/* ** $Id: lparser.c,v 1.32 1999/05/06 14:41:41 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ #include #include #include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "lua.h" #include "luadebug.h" #include "lzio.h" /* for limit numbers in error messages */ #define MES_LIM(x) "(limit=" x ")" /* size of a "normal" jump instruction: OpCode + 1 byte */ #define JMPSIZE 2 /* maximum number of local variables */ #define MAXLOCALS 32 #define SMAXLOCALS "32" /* maximum number of upvalues */ #define MAXUPVALUES 16 #define SMAXUPVALUES "16" /* ** Variable descriptor: ** must include a "exp" option because LL(1) cannot distinguish ** between variables, upvalues and function calls on first sight. ** VGLOBAL: info is constant index of global name ** VLOCAL: info is stack index ** VDOT: info is constant index of index name ** VEXP: info is pc index of "nparam" of function call (or 0 if exp is closed) */ typedef enum {VGLOBAL, VLOCAL, VDOT, VINDEXED, VEXP} varkind; typedef struct vardesc { varkind k; int info; } vardesc; /* ** Expression List descriptor: ** tells number of expressions in the list, ** and, if last expression is open (a function call), ** where is its pc index of "nparam" */ typedef struct listdesc { int n; int pc; /* 0 if last expression is closed */ } listdesc; /* ** Constructors descriptor: ** "n" indicates number of elements, and "k" signals whether ** it is a list constructor (k = 0) or a record constructor (k = 1) ** or empty (k = ';' or '}') */ typedef struct constdesc { int n; int k; } constdesc; /* state needed to generate code for a given function */ typedef struct FuncState { TProtoFunc *f; /* current function header */ struct FuncState *prev; /* enclosuring function */ int pc; /* next position to code */ int stacksize; /* number of values on activation register */ int maxstacksize; /* maximum number of values on activation register */ int nlocalvar; /* number of active local variables */ int nupvalues; /* number of upvalues */ int nvars; /* number of entries in f->locvars (-1 if no debug information) */ int lastsetline; /* line where last SETLINE was issued */ vardesc upvalues[MAXUPVALUES]; /* upvalues */ TaggedString *localvar[MAXLOCALS]; /* store local variable names */ } FuncState; /* ** prototypes for non-terminal functions */ static int assignment (LexState *ls, vardesc *v, int nvars); static int cond (LexState *ls); static int funcname (LexState *ls, vardesc *v); static int funcparams (LexState *ls, int slf); static int listfields (LexState *ls); static int localnamelist (LexState *ls); static int optional (LexState *ls, int c); static int recfields (LexState *ls); static int stat (LexState *ls); static void block (LexState *ls); static void body (LexState *ls, int needself, int line); static void chunk (LexState *ls); static void constructor (LexState *ls); static void decinit (LexState *ls, listdesc *d); static void exp0 (LexState *ls, vardesc *v); static void exp1 (LexState *ls); static void exp2 (LexState *ls, vardesc *v); static void explist (LexState *ls, listdesc *e); static void explist1 (LexState *ls, listdesc *e); static void ifpart (LexState *ls, int line); static void parlist (LexState *ls); static void part (LexState *ls, constdesc *cd); static void recfield (LexState *ls); static void ret (LexState *ls); static void statlist (LexState *ls); static void var_or_func (LexState *ls, vardesc *v); static void var_or_func_tail (LexState *ls, vardesc *v); static void check_pc (FuncState *fs, int n) { luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT); } static void code_byte (FuncState *fs, Byte c) { check_pc(fs, 1); fs->f->code[fs->pc++] = c; } static void deltastack (LexState *ls, int delta) { FuncState *fs = ls->fs; fs->stacksize += delta; if (fs->stacksize > fs->maxstacksize) { if (fs->stacksize > MAX_BYTE) luaX_error(ls, "function/expression too complex"); fs->maxstacksize = fs->stacksize; } } static void code_oparg_at (LexState *ls, int pc, OpCode op, int arg, int delta) { Byte *code = ls->fs->f->code; deltastack(ls, delta); if (arg <= MAX_BYTE) { code[pc] = (Byte)op; code[pc+1] = (Byte)arg; } else if (arg > MAX_ARG) luaX_error(ls, "code too long"); else { /* MAX_BYTE < arg < MAX_ARG */ if (arg > MAX_WORD) { code[pc] = (Byte)LONGARG; code[pc+1] = (Byte)(arg>>16); pc += 2; } code[pc] = (Byte)(op-1); /* opcode for word argument */ code[pc+1] = (Byte)((arg&0xFFFF)>>8); code[pc+2] = (Byte)(arg&0xFF); } } static int codesize (int arg) { if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ } static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { int tomove = codesize(arg)-2; if (tomove > 0) { /* need to open space? */ FuncState *fs = ls->fs; TProtoFunc *f = fs->f; check_pc(fs, tomove); luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); fs->pc += tomove; } code_oparg_at(ls, pc, op, arg, 0); return tomove; } static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { int size = codesize(arg); check_pc(ls->fs, size); code_oparg_at(ls, ls->fs->pc, op, arg, delta); ls->fs->pc += size; } static void code_opcode (LexState *ls, OpCode op, int delta) { deltastack(ls, delta); code_byte(ls->fs, (Byte)op); } static void code_constant (LexState *ls, int c) { code_oparg(ls, PUSHCONSTANT, c, 1); } static int next_constant (FuncState *fs) { TProtoFunc *f = fs->f; luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG); return f->nconsts++; } static int string_constant (FuncState *fs, TaggedString *s) { TProtoFunc *f = fs->f; int c = s->constindex; if (!(c < f->nconsts && ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { c = next_constant(fs); ttype(&f->consts[c]) = LUA_T_STRING; tsvalue(&f->consts[c]) = s; s->constindex = c; /* hint for next time */ } return c; } static void code_string (LexState *ls, TaggedString *s) { code_constant(ls, string_constant(ls->fs, s)); } #define LIM 20 static int real_constant (FuncState *fs, real r) { /* check whether 'r' has appeared within the last LIM entries */ TObject *cnt = fs->f->consts; int c = fs->f->nconsts; int lim = c < LIM ? 0 : c-LIM; while (--c >= lim) { if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) return c; } /* not found; create a new entry */ c = next_constant(fs); cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */ ttype(&cnt[c]) = LUA_T_NUMBER; nvalue(&cnt[c]) = r; return c; } static void code_number (LexState *ls, real f) { real af = (f<0) ? -f : f; if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { /* abs(f) has a short integer value */ code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1); } else code_constant(ls, real_constant(ls->fs, f)); } static void flush_record (LexState *ls, int n) { if (n > 0) code_oparg(ls, SETMAP, n-1, -2*n); } static void flush_list (LexState *ls, int m, int n) { if (n > 0) { code_oparg(ls, SETLIST, m, -n); code_byte(ls->fs, (Byte)n); } } static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, int line) { if (fs->nvars != -1) { /* debug information? */ TProtoFunc *f = fs->f; luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); f->locvars[fs->nvars].varname = varname; f->locvars[fs->nvars].line = line; fs->nvars++; } } static void luaI_unregisterlocalvar (FuncState *fs, int line) { luaI_registerlocalvar(fs, NULL, line); } static void store_localvar (LexState *ls, TaggedString *name, int n) { FuncState *fs = ls->fs; if (fs->nlocalvar+n >= MAXLOCALS) luaX_error(ls, "too many local variables " MES_LIM(SMAXLOCALS)); fs->localvar[fs->nlocalvar+n] = name; luaI_registerlocalvar(fs, name, ls->linenumber); } static void add_localvar (LexState *ls, TaggedString *name) { store_localvar(ls, name, 0); ls->fs->nlocalvar++; } static void correctvarlines (LexState *ls, int nvars) { FuncState *fs = ls->fs; if (fs->nvars != -1) { /* debug information? */ for (; nvars; nvars--) { /* correct line information */ fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline; } } } static int aux_localname (FuncState *fs, TaggedString *n) { int i; for (i=fs->nlocalvar-1; i >= 0; i--) if (n == fs->localvar[i]) return i; /* local var index */ return -1; /* not found */ } static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { FuncState *fs = prev ? ls->fs->prev : ls->fs; int i = aux_localname(fs, n); if (i >= 0) { /* local value? */ var->k = VLOCAL; var->info = i; } else { FuncState *level = fs; while ((level = level->prev) != NULL) /* check shadowing */ if (aux_localname(level, n) >= 0) luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); var->k = VGLOBAL; var->info = string_constant(fs, n); } } static int indexupvalue (LexState *ls, TaggedString *n) { FuncState *fs = ls->fs; vardesc v; int i; singlevar(ls, n, &v, 1); for (i=0; inupvalues; i++) { if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) return i; } /* new one */ if (++(fs->nupvalues) > MAXUPVALUES) luaX_error(ls, "too many upvalues in a single function " MES_LIM(SMAXUPVALUES)); fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ return i; } static void pushupvalue (LexState *ls, TaggedString *n) { if (ls->fs->prev == NULL) luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); if (aux_localname(ls->fs, n) >= 0) luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); } static void check_debugline (LexState *ls) { if (L->debug && ls->linenumber != ls->fs->lastsetline) { code_oparg(ls, SETLINE, ls->linenumber, 0); ls->fs->lastsetline = ls->linenumber; } } static void adjuststack (LexState *ls, int n) { if (n > 0) code_oparg(ls, POP, n, -n); else if (n < 0) code_oparg(ls, PUSHNIL, (-n)-1, -n); } static void close_exp (LexState *ls, int pc, int nresults) { if (pc > 0) { /* expression is an open function call? */ Byte *code = ls->fs->f->code; code[pc-1] = (Byte)nresults; /* set nresults */ /* push results, pop params (at code[pc]) and function */ deltastack(ls, nresults-(code[pc]+1)); } #ifdef DEBUG code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0); #endif } static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { int diff = d->n - nvars; if (d->pc == 0) { /* list is closed */ /* push or pop eventual difference between list lengths */ adjuststack(ls, diff); } else { /* must correct function call */ diff--; /* do not count function call itself */ if (diff <= 0) { /* more variables than values? */ /* function call must provide extra values */ close_exp(ls, d->pc, -diff); } else { /* more values than variables */ close_exp(ls, d->pc, 0); /* call should provide no value */ adjuststack(ls, diff); /* pop eventual extra values */ } } } static void code_args (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; fs->nlocalvar += nparams; /* "self" may already be there */ nparams = fs->nlocalvar; if (!dots) { fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ deltastack(ls, nparams); } else { fs->f->code[1] = (Byte)(nparams+ZEROVARARG); deltastack(ls, nparams+1); add_localvar(ls, luaS_new("arg")); } } static void unloaddot (LexState *ls, vardesc *v) { /* dotted variables must be stored like regular indexed vars */ if (v->k == VDOT) { code_constant(ls, v->info); v->k = VINDEXED; } } static void lua_pushvar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: code_oparg(ls, PUSHLOCAL, var->info, 1); break; case VGLOBAL: code_oparg(ls, GETGLOBAL, var->info, 1); break; case VDOT: code_oparg(ls, GETDOTTED, var->info, 0); break; case VINDEXED: code_opcode(ls, GETTABLE, -1); break; case VEXP: close_exp(ls, var->info, 1); /* function must return 1 value */ break; } var->k = VEXP; var->info = 0; /* now this is a closed expression */ } static void storevar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: code_oparg(ls, SETLOCAL, var->info, -1); break; case VGLOBAL: code_oparg(ls, SETGLOBAL, var->info, -1); break; case VINDEXED: code_opcode(ls, SETTABLEPOP, -3); break; default: LUA_INTERNALERROR("invalid var kind to store"); } } static int fix_jump (LexState *ls, int pc, OpCode op, int n) { /* jump is relative to position following jump instruction */ return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); } static void fix_upjmp (LexState *ls, OpCode op, int pos) { int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ code_oparg(ls, op, delta+(codesize(delta)-2), 0); } static void codeIf (LexState *ls, int thenAdd, int elseAdd) { FuncState *fs = ls->fs; int elseinit = elseAdd+JMPSIZE; if (fs->pc == elseinit) { /* no else part? */ fs->pc -= JMPSIZE; elseinit = fs->pc; } else elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); fix_jump(ls, thenAdd, IFFJMP, elseinit); } static void func_onstack (LexState *ls, FuncState *func) { FuncState *fs = ls->fs; int i; int c = next_constant(fs); ttype(&fs->f->consts[c]) = LUA_T_PROTO; fs->f->consts[c].value.tf = func->f; if (func->nupvalues == 0) code_constant(ls, c); else { for (i=0; inupvalues; i++) lua_pushvar(ls, &func->upvalues[i]); code_oparg(ls, CLOSURE, c, -func->nupvalues+1); code_byte(fs, (Byte)func->nupvalues); } } static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { TProtoFunc *f = luaF_newproto(); fs->prev = ls->fs; /* linked list of funcstates */ ls->fs = fs; fs->stacksize = 0; fs->maxstacksize = 0; fs->nlocalvar = 0; fs->nupvalues = 0; fs->lastsetline = 0; fs->f = f; f->source = source; fs->pc = 0; f->code = NULL; fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ code_byte(fs, 0); /* to be filled with maxstacksize */ code_byte(fs, 0); /* to be filled with arg information */ /* push function (to avoid GC) */ tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO; incr_top; } static void close_func (LexState *ls) { FuncState *fs = ls->fs; TProtoFunc *f = fs->f; code_opcode(ls, ENDCODE, 0); f->code[0] = (Byte)fs->maxstacksize; luaM_reallocvector(f->code, fs->pc, Byte); luaM_reallocvector(f->consts, f->nconsts, TObject); if (fs->nvars != -1) { /* debug information? */ luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ luaM_reallocvector(f->locvars, fs->nvars, LocVar); } ls->fs = fs->prev; L->stack.top--; /* pop function */ } static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; static int is_in (int tok, int *toks) { int *t; for (t=toks; *t; t++) if (*t == tok) return t-toks; return -1; } static void next (LexState *ls) { ls->token = luaX_lex(ls); } static void error_expected (LexState *ls, int token) { char buff[100], t[TOKEN_LEN]; luaX_token2str(token, t); sprintf(buff, "`%s' expected", t); luaX_error(ls, buff); } static void error_unexpected (LexState *ls) { luaX_error(ls, "unexpected token"); } static void error_unmatched (LexState *ls, int what, int who, int where) { if (where == ls->linenumber) error_expected(ls, what); else { char buff[100]; char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; luaX_token2str(what, t_what); luaX_token2str(who, t_who); sprintf(buff, "`%s' expected (to close `%s' at line %d)", t_what, t_who, where); luaX_error(ls, buff); } } static void check (LexState *ls, int c) { if (ls->token != c) error_expected(ls, c); next(ls); } static void check_match (LexState *ls, int what, int who, int where) { if (ls->token != what) error_unmatched(ls, what, who, where); check_debugline(ls); /* to 'mark' the 'what' */ next(ls); } static int checkname (LexState *ls) { int sc; if (ls->token != NAME) luaX_error(ls, "`NAME' expected"); sc = string_constant(ls->fs, ls->seminfo.ts); next(ls); return sc; } static TaggedString *str_checkname (LexState *ls) { return tsvalue(&ls->fs->f->consts[checkname(ls)]); } static int optional (LexState *ls, int c) { if (ls->token == c) { next(ls); return 1; } else return 0; } TProtoFunc *luaY_parser (ZIO *z) { struct LexState lexstate; struct FuncState funcstate; luaX_setinput(&lexstate, z); init_state(&lexstate, &funcstate, luaS_new(zname(z))); next(&lexstate); /* read first token */ chunk(&lexstate); if (lexstate.token != EOS) luaX_error(&lexstate, " expected"); close_func(&lexstate); return funcstate.f; } /*============================================================*/ /* GRAMAR RULES */ /*============================================================*/ static void chunk (LexState *ls) { /* chunk -> statlist ret */ statlist(ls); ret(ls); } static void statlist (LexState *ls) { /* statlist -> { stat [;] } */ while (stat(ls)) { LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar, "stack size != # local vars"); optional(ls, ';'); } } static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ FuncState *fs = ls->fs; switch (ls->token) { case IF: /* stat -> IF ifpart END */ ifpart(ls, line); return 1; case WHILE: { /* stat -> WHILE cond DO block END */ TProtoFunc *f = fs->f; int while_init = fs->pc; int cond_end, cond_size; next(ls); cond_end = cond(ls); check(ls, DO); block(ls); check_match(ls, END, WHILE, line); cond_size = cond_end-while_init; check_pc(fs, cond_size); memcpy(f->code+fs->pc, f->code+while_init, cond_size); luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); fix_upjmp(ls, IFTUPJMP, while_init); return 1; } case DO: { /* stat -> DO block END */ next(ls); block(ls); check_match(ls, END, DO, line); return 1; } case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */ int repeat_init = fs->pc; next(ls); block(ls); check_match(ls, UNTIL, REPEAT, line); exp1(ls); fix_upjmp(ls, IFFUPJMP, repeat_init); deltastack(ls, -1); /* pops condition */ return 1; } case FUNCTION: { /* stat -> FUNCTION funcname body */ int needself; vardesc v; if (ls->fs->prev) /* inside other function? */ return 0; check_debugline(ls); next(ls); needself = funcname(ls, &v); body(ls, needself, line); storevar(ls, &v); return 1; } case LOCAL: { /* stat -> LOCAL localnamelist decinit */ listdesc d; int nvars; check_debugline(ls); next(ls); nvars = localnamelist(ls); decinit(ls, &d); fs->nlocalvar += nvars; correctvarlines(ls, nvars); /* vars will be alive only after decinit */ adjust_mult_assign(ls, nvars, &d); return 1; } case NAME: case '%': { /* stat -> func | ['%'] NAME assignment */ vardesc v; check_debugline(ls); var_or_func(ls, &v); if (v.k == VEXP) { /* stat -> func */ if (v.info == 0) /* is just an upper value? */ luaX_error(ls, "syntax error"); close_exp(ls, v.info, 0); } else { /* stat -> ['%'] NAME assignment */ int left = assignment(ls, &v, 1); adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ } return 1; } case RETURN: case ';': case ELSE: case ELSEIF: case END: case UNTIL: case EOS: /* 'stat' follow */ return 0; default: error_unexpected(ls); return 0; /* to avoid warnings */ } } static int SaveWord (LexState *ls) { int res = ls->fs->pc; check_pc(ls->fs, JMPSIZE); ls->fs->pc += JMPSIZE; /* open space */ return res; } static int SaveWordPop (LexState *ls) { deltastack(ls, -1); /* pop condition */ return SaveWord(ls); } static int cond (LexState *ls) { /* cond -> exp1 */ exp1(ls); return SaveWordPop(ls); } static void block (LexState *ls) { /* block -> chunk */ FuncState *fs = ls->fs; int nlocalvar = fs->nlocalvar; chunk(ls); adjuststack(ls, fs->nlocalvar - nlocalvar); for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) luaI_unregisterlocalvar(fs, fs->lastsetline); } static int funcname (LexState *ls, vardesc *v) { /* funcname -> NAME [':' NAME | '.' NAME] */ int needself = 0; singlevar(ls, str_checkname(ls), v, 0); if (ls->token == ':' || ls->token == '.') { needself = (ls->token == ':'); next(ls); lua_pushvar(ls, v); code_constant(ls, checkname(ls)); v->k = VINDEXED; } return needself; } static void body (LexState *ls, int needself, int line) { /* body -> '(' parlist ')' chunk END */ FuncState newfs; init_state(ls, &newfs, ls->fs->f->source); newfs.f->lineDefined = line; check(ls, '('); if (needself) add_localvar(ls, luaS_new("self")); parlist(ls); check(ls, ')'); chunk(ls); check_match(ls, END, FUNCTION, line); close_func(ls); func_onstack(ls, &newfs); } static void ifpart (LexState *ls, int line) { /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ int c; int e; next(ls); /* skip IF or ELSEIF */ c = cond(ls); check(ls, THEN); block(ls); e = SaveWord(ls); if (ls->token == ELSEIF) ifpart(ls, line); else { if (optional(ls, ELSE)) block(ls); check_match(ls, END, IF, line); } codeIf(ls, c, e); } static void ret (LexState *ls) { /* ret -> [RETURN explist sc] */ if (optional(ls, RETURN)) { listdesc e; check_debugline(ls); explist(ls, &e); if (e.pc > 0) { /* expression is an open function call? */ Byte *code = ls->fs->f->code; code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ code[e.pc-1] = (Byte)ls->fs->nlocalvar; } else code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ optional(ls, ';'); } } /* ** For parsing expressions, we use a classic stack with priorities. ** Each binary operator is represented by its index in "binop" + FIRSTBIN ** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. */ #define INDNOT 0 #define INDMINUS 1 /* code of first binary operator */ #define FIRSTBIN 2 /* code for power operator (last operator) ** '^' needs special treatment because it is right associative */ #define POW 13 static int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, '+', '-', '*', '/', '^', 0}; static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP, LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; #define MAXOPS 20 /* op's stack size */ typedef struct stack_op { int ops[MAXOPS]; int top; } stack_op; static void exp1 (LexState *ls) { vardesc v; exp0(ls, &v); lua_pushvar(ls, &v); if (is_in(ls->token, expfollow) < 0) luaX_error(ls, "ill-formed expression"); } static void exp0 (LexState *ls, vardesc *v) { /* exp0 -> exp2 {(AND | OR) exp2} */ exp2(ls, v); while (ls->token == AND || ls->token == OR) { int op = (ls->token == AND) ? ONFJMP : ONTJMP; int pc; lua_pushvar(ls, v); next(ls); pc = SaveWordPop(ls); exp2(ls, v); lua_pushvar(ls, v); fix_jump(ls, pc, op, ls->fs->pc); } } static void push (LexState *ls, stack_op *s, int op) { if (s->top >= MAXOPS) luaX_error(ls, "expression too complex"); s->ops[s->top++] = op; } static void pop_to (LexState *ls, stack_op *s, int prio) { int op; while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { code_opcode(ls, opcodes[op], optop--; } } static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { check_debugline(ls); switch (ls->token) { case NUMBER: { /* simpleexp -> NUMBER */ real r = ls->seminfo.r; next(ls); /* dirty trick: check whether it is a -NUMBER not followed by '^' */ /* (because the priority of '^' is closer than '-'...) */ if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { s->top--; /* remove '-' from stack */ r = -r; } code_number(ls, r); break; } case STRING: /* simpleexp -> STRING */ code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); break; case NIL: /* simpleexp -> NIL */ adjuststack(ls, -1); next(ls); break; case '{': /* simpleexp -> constructor */ constructor(ls); break; case FUNCTION: /* simpleexp -> FUNCTION body */ next(ls); body(ls, 0, ls->linenumber); break; case '(': /* simpleexp -> '(' exp0 ')' */ next(ls); exp0(ls, v); check(ls, ')'); return; case NAME: case '%': var_or_func(ls, v); return; default: luaX_error(ls, " expected"); return; } v->k = VEXP; v->info = 0; } static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { /* prefixexp -> {NOT | '-'} simpleexp */ while (ls->token == NOT || ls->token == '-') { push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); next(ls); } simpleexp(ls, v, s); } static void exp2 (LexState *ls, vardesc *v) { stack_op s; int op; s.top = 0; prefixexp(ls, v, &s); while ((op = is_in(ls->token, binop)) >= 0) { op += FIRSTBIN; lua_pushvar(ls, v); /* '^' is right associative, so must 'simulate' a higher priority */ pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); push(ls, &s, op); next(ls); prefixexp(ls, v, &s); lua_pushvar(ls, v); } if (s.top > 0) { lua_pushvar(ls, v); pop_to(ls, &s, 0); } } static void var_or_func (LexState *ls, vardesc *v) { /* var_or_func -> ['%'] NAME var_or_func_tail */ if (optional(ls, '%')) { /* upvalue? */ pushupvalue(ls, str_checkname(ls)); v->k = VEXP; v->info = 0; /* closed expression */ } else /* variable name */ singlevar(ls, str_checkname(ls), v, 0); var_or_func_tail(ls, v); } static void var_or_func_tail (LexState *ls, vardesc *v) { for (;;) { switch (ls->token) { case '.': /* var_or_func_tail -> '.' NAME */ next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ v->k = VDOT; v->info = checkname(ls); break; case '[': /* var_or_func_tail -> '[' exp1 ']' */ next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ exp1(ls); check(ls, ']'); v->k = VINDEXED; break; case ':': /* var_or_func_tail -> ':' NAME funcparams */ next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ code_oparg(ls, PUSHSELF, checkname(ls), 1); v->k = VEXP; v->info = funcparams(ls, 1); break; case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ lua_pushvar(ls, v); /* 'v' must be on stack */ v->k = VEXP; v->info = funcparams(ls, 0); break; default: return; /* should be follow... */ } } } static int funcparams (LexState *ls, int slf) { FuncState *fs = ls->fs; int nparams = 1; /* in cases STRING and constructor */ switch (ls->token) { case '(': { /* funcparams -> '(' explist ')' */ int line = ls->linenumber; listdesc e; next(ls); explist(ls, &e); check_match(ls, ')', '(', line); close_exp(ls, e.pc, 1); nparams = e.n; break; } case '{': /* funcparams -> constructor */ constructor(ls); break; case STRING: /* funcparams -> STRING */ code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); break; default: luaX_error(ls, "function arguments expected"); break; } code_byte(fs, CALL); code_byte(fs, 0); /* save space for nresult */ code_byte(fs, (Byte)(nparams+slf)); return fs->pc-1; } static void explist (LexState *ls, listdesc *d) { switch (ls->token) { case ELSE: case ELSEIF: case END: case UNTIL: case EOS: case ';': case ')': d->pc = 0; d->n = 0; break; default: explist1(ls, d); } } static void explist1 (LexState *ls, listdesc *d) { vardesc v; exp0(ls, &v); d->n = 1; while (ls->token == ',') { d->n++; lua_pushvar(ls, &v); next(ls); exp0(ls, &v); } if (v.k == VEXP) d->pc = v.info; else { lua_pushvar(ls, &v); d->pc = 0; } } static void parlist (LexState *ls) { int nparams = 0; int dots = 0; switch (ls->token) { case DOTS: /* parlist -> DOTS */ next(ls); dots = 1; break; case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ init: store_localvar(ls, str_checkname(ls), nparams++); if (ls->token == ',') { next(ls); switch (ls->token) { case DOTS: /* tailparlist -> DOTS */ next(ls); dots = 1; break; case NAME: /* tailparlist -> NAME [',' tailparlist] */ goto init; default: luaX_error(ls, "NAME or `...' expected"); } } break; case ')': break; /* parlist -> empty */ default: luaX_error(ls, "NAME or `...' expected"); } code_args(ls, nparams, dots); } static int localnamelist (LexState *ls) { /* localnamelist -> NAME {',' NAME} */ int i = 1; store_localvar(ls, str_checkname(ls), 0); while (ls->token == ',') { next(ls); store_localvar(ls, str_checkname(ls), i++); } return i; } static void decinit (LexState *ls, listdesc *d) { /* decinit -> ['=' explist1] */ if (ls->token == '=') { next(ls); explist1(ls, d); } else { d->n = 0; d->pc = 0; } } static int assignment (LexState *ls, vardesc *v, int nvars) { int left = 0; unloaddot(ls, v); if (ls->token == ',') { /* assignment -> ',' NAME assignment */ vardesc nv; next(ls); var_or_func(ls, &nv); if (nv.k == VEXP) luaX_error(ls, "syntax error"); left = assignment(ls, &nv, nvars+1); } else { /* assignment -> '=' explist1 */ listdesc d; check(ls, '='); explist1(ls, &d); adjust_mult_assign(ls, nvars, &d); } if (v->k != VINDEXED || left+(nvars-1) == 0) { /* global/local var or indexed var without values in between */ storevar(ls, v); } else { /* indexed var with values in between*/ code_oparg(ls, SETTABLE, left+(nvars-1), -1); left += 2; /* table&index are not popped, because they aren't on top */ } return left; } static void constructor (LexState *ls) { /* constructor -> '{' part [';' part] '}' */ int line = ls->linenumber; int pc = SaveWord(ls); int nelems; constdesc cd; deltastack(ls, 1); check(ls, '{'); part(ls, &cd); nelems = cd.n; if (ls->token == ';') { constdesc other_cd; next(ls); part(ls, &other_cd); if (cd.k == other_cd.k) /* repeated parts? */ luaX_error(ls, "invalid constructor syntax"); nelems += other_cd.n; } check_match(ls, '}', '{', line); fix_opcode(ls, pc, CREATEARRAY, nelems); } static void part (LexState *ls, constdesc *cd) { switch (ls->token) { case ';': case '}': /* part -> empty */ cd->n = 0; cd->k = ls->token; return; case NAME: { vardesc v; exp0(ls, &v); if (ls->token == '=') { switch (v.k) { case VGLOBAL: code_constant(ls, v.info); break; case VLOCAL: code_string(ls, ls->fs->localvar[v.info]); break; default: error_unexpected(ls); } next(ls); exp1(ls); cd->n = recfields(ls); cd->k = 1; /* record */ } else { lua_pushvar(ls, &v); cd->n = listfields(ls); cd->k = 0; /* list */ } break; } case '[': /* part -> recfield recfields */ recfield(ls); cd->n = recfields(ls); cd->k = 1; /* record */ break; default: /* part -> exp1 listfields */ exp1(ls); cd->n = listfields(ls); cd->k = 0; /* list */ break; } } static int recfields (LexState *ls) { /* recfields -> { ',' recfield } [','] */ int n = 1; /* one has been read before */ while (ls->token == ',') { next(ls); if (ls->token == ';' || ls->token == '}') break; recfield(ls); n++; if (n%RFIELDS_PER_FLUSH == 0) flush_record(ls, RFIELDS_PER_FLUSH); } flush_record(ls, n%RFIELDS_PER_FLUSH); return n; } static int listfields (LexState *ls) { /* listfields -> { ',' exp1 } [','] */ int n = 1; /* one has been read before */ while (ls->token == ',') { next(ls); if (ls->token == ';' || ls->token == '}') break; exp1(ls); n++; if (n%LFIELDS_PER_FLUSH == 0) flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); } flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); return n; } static void recfield (LexState *ls) { /* recfield -> (NAME | '['exp1']') = exp1 */ switch (ls->token) { case NAME: code_constant(ls, checkname(ls)); break; case '[': next(ls); exp1(ls); check(ls, ']'); break; default: luaX_error(ls, "NAME or `[' expected"); } check(ls, '='); exp1(ls); }