RiscLua
History

RiscLua evolved over many years, starting in 2002, as an attempt to implement Lua for RISC OS with extra features that would mimic the facilities of BBC BASIC to call software interrupts with SYS. That implied that something to mimic DIM would also be needed, and the operators ! , ? and $ . These characters are not allowed in standard Lua, but I felt that their meaning would be so transparent to RISC OS users that it was worth modifying the Lua lexer. Other lexical changes introduced \ as a shorthand for function and => as a shorthand for return. Once, I accidentally introduced a hard space into a Lua program and had a hard time tracing down why Lua was throwing up a parsing error. So I decided to lex hard spaces as soft spaces to avoid such problems in the future.

Later on I introduced two features into RiscLua that are not in standard Lua: local variables from a table, and update operators. In RiscLua a statement like

local x, y, z in f(a)
is equivalent to

local t = f(a)
local x, y, z = t.x, t.y, t.z
Update operators in RiscLua are binary operators % , * , / , + , - , ^ , & , | , ~ followed by an equality sign. So

x + = 57
is equivalent to

x = x + 57
Note that a space between the operator and the equality sign is permitted, and is mandatory in the case

x ~ = 1  -- toggle least significant bit
to avoid confusion with the Boolean value

x ~= 1 -- x not equal to 1
Update operators should not be used in multiple assignments.
Lexical changes

RiscLua allows the characters

 @ !  $  ?  ` 
to be used in variable names. In the file c.type at line 25 replace

  0x0c,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,	/* 2. */
  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,	/* 3. */
  0x16,  0x16,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 4. */
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 5. */
  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x05,
  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 6. */
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 8. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 9. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* a. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* b. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* c. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* d. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* e. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* f. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
by

#ifdef RISCOS
  0x0c,  0x05,  0x04,  0x04,  0x05,  0x04,  0x04,  0x04,	/* 2. */
  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,	/* 3. */
  0x16,  0x16,  0x04,  0x04,  0x04,  0x04,  0x04,  0x05,
  0x05,  0x35,  0x35,  0x35,  0x35,  0x35,  0x35,  0x25,	/* 4. */
  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,
  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,  0x25,	/* 5. */
  0x25,  0x25,  0x25,  0x04,  0x04,  0x04,  0x04,  0x05,
  0x05,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 6. */
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 8. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 9. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x0c,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* a. */
#else
  0x0c,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,	/* 2. */
  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,	/* 3. */
  0x16,  0x16,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 4. */
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 5. */
  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x05,
  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 6. */
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 8. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 9. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* a. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* b. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* c. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* d. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* e. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* f. */
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
#endif
Soften hard spaces

In c.llex at line 468 insert

#ifdef RISCOS
    case 0xa0:
#endif
before the line

      case ' ': case '\f': case '\t': case '\v': }  /* spaces */
Syntactic sugar

In c.llex replace the lines

        if (check_next1(ls, '=')) return TK_EQ;
        else return '=';
by

   #ifdef RISCOS
        switch(ls->current) {
        case '=': next(ls); return TK_EQ; break;
        case '>': next(ls); return TK_RETURN; break;
        default: return '=';
        }
   #else
        if (check_next1(ls, '=')) return TK_EQ;
        else return '=';
   #endif
This makes => a synonym for return.

Insert the lines

   #ifdef RISCOS
      case '\\': {
       next(ls);
       return TK_FUNCTION;
       }
    #endif
before the line

      case '<': {
This makes \ a synonym for function.
Local variables from tables

RiscLua permits statements of the form

local x,y, .... in table_expression
This is got by making the following changes in c.lparser. At line 1441 replace

  /* stat -> LOCAL NAME {',' NAME} ['=' explist] */
by

  #ifdef RISCOS
   /* stat -> LOCAL NAME {`,' NAME} [ IN exp | `=' explist]*/
  #else
  /* stat -> LOCAL NAME {',' NAME} ['=' explist] */
  #endif
and a few lines further on, after the line

  } while (testnext(ls, ','));
insert

  #ifdef RISCOS
  int lastline = ls->lastline;
  if (testnext(ls, TK_IN)) {
    lu_byte from_var;
    int regs = ls->fs->freereg;
    int vars = ls->fs->nactvar;
    if (ls->linenumber != lastline)
      luaX_syntaxerror(ls,"ambiguous syntax"
       "(unpack declaration x lexical environment)");
    luaK_reserveregs(ls->fs, nvars);
    new_localvarliteral(ls, "(from)");
    expr(ls, &e);
    luaK_exp2nextreg(ls->fs, &e);
    adjustlocalvars(ls, nvars);
    from_var = ls->fs->nactvar;
    adjustlocalvars(ls, 1);
    luaK_setoneret(ls->fs, &e);  /* close last expression */
    for (nexps=0; nexps<nvars; nexps++) {
      expdesc v, key;
      init_exp(&e, VNONRELOC, ls->fs->freereg-1);
      codestring(ls, &key, localdebuginfo(ls->fs, vars+nexps)->varname);
      luaK_indexed(ls->fs, &e, &key);
      init_exp(&v, VLOCAL, regs+nexps);
      luaK_storevar(ls->fs, &v, &e);
    }
    removevars(ls->lfs, from_var);
    return;
  }
  #endif
Update operators

The following changes to c.lparser are needed:

Before the line

static void exprstat (LexState *ls) }
insert

#ifdef RISCOS
static void inc_assignment(LexState *ls, struct LHS_assign *lh) {
    int line;
    BinOpr op = getbinopr(ls->t.token);
    FuncState * fs=ls->fs;
    expdesc e, v2;
    /* reserve all registers needed by the lvalue */
    luaK_reserveregs(fs,fs->freereg-fs->nactvar);
    luaX_next(ls);
    checknext(ls, '=');
    line=ls->linenumber;
    enterlevel(ls);
    e = lh->v;
    luaK_infix(fs,op,&e);
    /* we only match one expr(), not a full explist(),
       so "a+=2,2" will be a parse error. */
    expr(ls,&v2);
    luaK_posfix(fs, op, &e, &v2, line);
    leavelevel(ls);
    luaK_exp2nextreg(fs,&e);
    luaK_setoneret(ls->fs, &e);
    luaK_storevar(ls->fs, &lh->v, &e);
}
#endif
A few lines on, after the line

 else {  /* stat -> func */
insert

 #ifdef RISCOS
  switch(ls->t.token) {
    case '%': case '*': case '/': case '+': case '-':
    case '^': case '&': case '|': case '~':
    case TK_CONCAT: case TK_IDIV:
    inc_assignment(ls, &v);
    return;
   }
 #endif