rlm@1: /* rlm@1: ** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ rlm@1: ** Lua Parser rlm@1: ** See Copyright Notice in lua.h rlm@1: */ rlm@1: rlm@1: rlm@1: #include rlm@1: rlm@1: #define lparser_c rlm@1: #define LUA_CORE rlm@1: rlm@1: #include "lua.h" rlm@1: rlm@1: #include "lcode.h" rlm@1: #include "ldebug.h" rlm@1: #include "ldo.h" rlm@1: #include "lfunc.h" rlm@1: #include "llex.h" rlm@1: #include "lmem.h" rlm@1: #include "lobject.h" rlm@1: #include "lopcodes.h" rlm@1: #include "lparser.h" rlm@1: #include "lstate.h" rlm@1: #include "lstring.h" rlm@1: #include "ltable.h" rlm@1: rlm@1: rlm@1: rlm@1: #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) rlm@1: rlm@1: #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) rlm@1: rlm@1: #define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) rlm@1: rlm@1: rlm@1: /* rlm@1: ** nodes for block list (list of active blocks) rlm@1: */ rlm@1: typedef struct BlockCnt { rlm@1: struct BlockCnt *previous; /* chain */ rlm@1: int breaklist; /* list of jumps out of this loop */ rlm@1: lu_byte nactvar; /* # active locals outside the breakable structure */ rlm@1: lu_byte upval; /* true if some variable in the block is an upvalue */ rlm@1: lu_byte isbreakable; /* true if `block' is a loop */ rlm@1: } BlockCnt; rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** prototypes for recursive non-terminal functions rlm@1: */ rlm@1: static void chunk (LexState *ls); rlm@1: static void expr (LexState *ls, expdesc *v); rlm@1: rlm@1: rlm@1: static void anchor_token (LexState *ls) { rlm@1: if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { rlm@1: TString *ts = ls->t.seminfo.ts; rlm@1: luaX_newstring(ls, getstr(ts), ts->tsv.len); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void error_expected (LexState *ls, int token) { rlm@1: luaX_syntaxerror(ls, rlm@1: luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); rlm@1: } rlm@1: rlm@1: rlm@1: static void errorlimit (FuncState *fs, int limit, const char *what) { rlm@1: const char *msg = (fs->f->linedefined == 0) ? rlm@1: luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : rlm@1: luaO_pushfstring(fs->L, "function at line %d has more than %d %s", rlm@1: fs->f->linedefined, limit, what); rlm@1: luaX_lexerror(fs->ls, msg, 0); rlm@1: } rlm@1: rlm@1: rlm@1: static int testnext (LexState *ls, int c) { rlm@1: if (ls->t.token == c) { rlm@1: luaX_next(ls); rlm@1: return 1; rlm@1: } rlm@1: else return 0; rlm@1: } rlm@1: rlm@1: rlm@1: static void check (LexState *ls, int c) { rlm@1: if (ls->t.token != c) rlm@1: error_expected(ls, c); rlm@1: } rlm@1: rlm@1: static void checknext (LexState *ls, int c) { rlm@1: check(ls, c); rlm@1: luaX_next(ls); rlm@1: } rlm@1: rlm@1: rlm@1: #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } rlm@1: rlm@1: rlm@1: rlm@1: static void check_match (LexState *ls, int what, int who, int where) { rlm@1: if (!testnext(ls, what)) { rlm@1: if (where == ls->linenumber) rlm@1: error_expected(ls, what); rlm@1: else { rlm@1: luaX_syntaxerror(ls, luaO_pushfstring(ls->L, rlm@1: LUA_QS " expected (to close " LUA_QS " at line %d)", rlm@1: luaX_token2str(ls, what), luaX_token2str(ls, who), where)); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static TString *str_checkname (LexState *ls) { rlm@1: TString *ts; rlm@1: check(ls, TK_NAME); rlm@1: ts = ls->t.seminfo.ts; rlm@1: luaX_next(ls); rlm@1: return ts; rlm@1: } rlm@1: rlm@1: rlm@1: static void init_exp (expdesc *e, expkind k, int i) { rlm@1: e->f = e->t = NO_JUMP; rlm@1: e->k = k; rlm@1: e->u.s.info = i; rlm@1: } rlm@1: rlm@1: rlm@1: static void codestring (LexState *ls, expdesc *e, TString *s) { rlm@1: init_exp(e, VK, luaK_stringK(ls->fs, s)); rlm@1: } rlm@1: rlm@1: rlm@1: static void checkname(LexState *ls, expdesc *e) { rlm@1: codestring(ls, e, str_checkname(ls)); rlm@1: } rlm@1: rlm@1: rlm@1: static int registerlocalvar (LexState *ls, TString *varname) { rlm@1: FuncState *fs = ls->fs; rlm@1: Proto *f = fs->f; rlm@1: int oldsize = f->sizelocvars; rlm@1: luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, rlm@1: LocVar, SHRT_MAX, "too many local variables"); rlm@1: while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; rlm@1: f->locvars[fs->nlocvars].varname = varname; rlm@1: luaC_objbarrier(ls->L, f, varname); rlm@1: return fs->nlocvars++; rlm@1: } rlm@1: rlm@1: rlm@1: #define new_localvarliteral(ls,v,n) \ rlm@1: new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) rlm@1: rlm@1: rlm@1: static void new_localvar (LexState *ls, TString *name, int n) { rlm@1: FuncState *fs = ls->fs; rlm@1: luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); rlm@1: fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); rlm@1: } rlm@1: rlm@1: rlm@1: static void adjustlocalvars (LexState *ls, int nvars) { rlm@1: FuncState *fs = ls->fs; rlm@1: fs->nactvar = cast_byte(fs->nactvar + nvars); rlm@1: for (; nvars; nvars--) { rlm@1: getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void removevars (LexState *ls, int tolevel) { rlm@1: FuncState *fs = ls->fs; rlm@1: while (fs->nactvar > tolevel) rlm@1: getlocvar(fs, --fs->nactvar).endpc = fs->pc; rlm@1: } rlm@1: rlm@1: rlm@1: static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { rlm@1: int i; rlm@1: Proto *f = fs->f; rlm@1: int oldsize = f->sizeupvalues; rlm@1: for (i=0; inups; i++) { rlm@1: if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { rlm@1: lua_assert(f->upvalues[i] == name); rlm@1: return i; rlm@1: } rlm@1: } rlm@1: /* new one */ rlm@1: luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); rlm@1: luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, rlm@1: TString *, MAX_INT, ""); rlm@1: while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; rlm@1: f->upvalues[f->nups] = name; rlm@1: luaC_objbarrier(fs->L, f, name); rlm@1: lua_assert(v->k == VLOCAL || v->k == VUPVAL); rlm@1: fs->upvalues[f->nups].k = cast_byte(v->k); rlm@1: fs->upvalues[f->nups].info = cast_byte(v->u.s.info); rlm@1: return f->nups++; rlm@1: } rlm@1: rlm@1: rlm@1: static int searchvar (FuncState *fs, TString *n) { rlm@1: int i; rlm@1: for (i=fs->nactvar-1; i >= 0; i--) { rlm@1: if (n == getlocvar(fs, i).varname) rlm@1: return i; rlm@1: } rlm@1: return -1; /* not found */ rlm@1: } rlm@1: rlm@1: rlm@1: static void markupval (FuncState *fs, int level) { rlm@1: BlockCnt *bl = fs->bl; rlm@1: while (bl && bl->nactvar > level) bl = bl->previous; rlm@1: if (bl) bl->upval = 1; rlm@1: } rlm@1: rlm@1: rlm@1: static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { rlm@1: if (fs == NULL) { /* no more levels? */ rlm@1: init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ rlm@1: return VGLOBAL; rlm@1: } rlm@1: else { rlm@1: int v = searchvar(fs, n); /* look up at current level */ rlm@1: if (v >= 0) { rlm@1: init_exp(var, VLOCAL, v); rlm@1: if (!base) rlm@1: markupval(fs, v); /* local will be used as an upval */ rlm@1: return VLOCAL; rlm@1: } rlm@1: else { /* not found at current level; try upper one */ rlm@1: if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) rlm@1: return VGLOBAL; rlm@1: var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ rlm@1: var->k = VUPVAL; /* upvalue in this level */ rlm@1: return VUPVAL; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void singlevar (LexState *ls, expdesc *var) { rlm@1: TString *varname = str_checkname(ls); rlm@1: FuncState *fs = ls->fs; rlm@1: if (singlevaraux(fs, varname, var, 1) == VGLOBAL) rlm@1: var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ rlm@1: } rlm@1: rlm@1: rlm@1: static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { rlm@1: FuncState *fs = ls->fs; rlm@1: int extra = nvars - nexps; rlm@1: if (hasmultret(e->k)) { rlm@1: extra++; /* includes call itself */ rlm@1: if (extra < 0) extra = 0; rlm@1: luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ rlm@1: if (extra > 1) luaK_reserveregs(fs, extra-1); rlm@1: } rlm@1: else { rlm@1: if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ rlm@1: if (extra > 0) { rlm@1: int reg = fs->freereg; rlm@1: luaK_reserveregs(fs, extra); rlm@1: luaK_nil(fs, reg, extra); rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void enterlevel (LexState *ls) { rlm@1: if (++ls->L->nCcalls > LUAI_MAXCCALLS) rlm@1: luaX_lexerror(ls, "chunk has too many syntax levels", 0); rlm@1: } rlm@1: rlm@1: rlm@1: #define leavelevel(ls) ((ls)->L->nCcalls--) rlm@1: rlm@1: rlm@1: static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { rlm@1: bl->breaklist = NO_JUMP; rlm@1: bl->isbreakable = isbreakable; rlm@1: bl->nactvar = fs->nactvar; rlm@1: bl->upval = 0; rlm@1: bl->previous = fs->bl; rlm@1: fs->bl = bl; rlm@1: lua_assert(fs->freereg == fs->nactvar); rlm@1: } rlm@1: rlm@1: rlm@1: static void leaveblock (FuncState *fs) { rlm@1: BlockCnt *bl = fs->bl; rlm@1: fs->bl = bl->previous; rlm@1: removevars(fs->ls, bl->nactvar); rlm@1: if (bl->upval) rlm@1: luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); rlm@1: /* a block either controls scope or breaks (never both) */ rlm@1: lua_assert(!bl->isbreakable || !bl->upval); rlm@1: lua_assert(bl->nactvar == fs->nactvar); rlm@1: fs->freereg = fs->nactvar; /* free registers */ rlm@1: luaK_patchtohere(fs, bl->breaklist); rlm@1: } rlm@1: rlm@1: rlm@1: static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { rlm@1: FuncState *fs = ls->fs; rlm@1: Proto *f = fs->f; rlm@1: int oldsize = f->sizep; rlm@1: int i; rlm@1: luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, rlm@1: MAXARG_Bx, "constant table overflow"); rlm@1: while (oldsize < f->sizep) f->p[oldsize++] = NULL; rlm@1: f->p[fs->np++] = func->f; rlm@1: luaC_objbarrier(ls->L, f, func->f); rlm@1: init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); rlm@1: for (i=0; if->nups; i++) { rlm@1: OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; rlm@1: luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void open_func (LexState *ls, FuncState *fs) { rlm@1: lua_State *L = ls->L; rlm@1: Proto *f = luaF_newproto(L); rlm@1: fs->f = f; rlm@1: fs->prev = ls->fs; /* linked list of funcstates */ rlm@1: fs->ls = ls; rlm@1: fs->L = L; rlm@1: ls->fs = fs; rlm@1: fs->pc = 0; rlm@1: fs->lasttarget = -1; rlm@1: fs->jpc = NO_JUMP; rlm@1: fs->freereg = 0; rlm@1: fs->nk = 0; rlm@1: fs->np = 0; rlm@1: fs->nlocvars = 0; rlm@1: fs->nactvar = 0; rlm@1: fs->bl = NULL; rlm@1: f->source = ls->source; rlm@1: f->maxstacksize = 2; /* registers 0/1 are always valid */ rlm@1: fs->h = luaH_new(L, 0, 0); rlm@1: /* anchor table of constants and prototype (to avoid being collected) */ rlm@1: sethvalue2s(L, L->top, fs->h); rlm@1: incr_top(L); rlm@1: setptvalue2s(L, L->top, f); rlm@1: incr_top(L); rlm@1: } rlm@1: rlm@1: rlm@1: static void close_func (LexState *ls) { rlm@1: lua_State *L = ls->L; rlm@1: FuncState *fs = ls->fs; rlm@1: Proto *f = fs->f; rlm@1: removevars(ls, 0); rlm@1: luaK_ret(fs, 0, 0); /* final return */ rlm@1: luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); rlm@1: f->sizecode = fs->pc; rlm@1: luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); rlm@1: f->sizelineinfo = fs->pc; rlm@1: luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); rlm@1: f->sizek = fs->nk; rlm@1: luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); rlm@1: f->sizep = fs->np; rlm@1: luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); rlm@1: f->sizelocvars = fs->nlocvars; rlm@1: luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); rlm@1: f->sizeupvalues = f->nups; rlm@1: lua_assert(luaG_checkcode(f)); rlm@1: lua_assert(fs->bl == NULL); rlm@1: ls->fs = fs->prev; rlm@1: L->top -= 2; /* remove table and prototype from the stack */ rlm@1: /* last token read was anchored in defunct function; must reanchor it */ rlm@1: if (fs) anchor_token(ls); rlm@1: } rlm@1: rlm@1: rlm@1: Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { rlm@1: struct LexState lexstate; rlm@1: struct FuncState funcstate; rlm@1: lexstate.buff = buff; rlm@1: luaX_setinput(L, &lexstate, z, luaS_new(L, name)); rlm@1: open_func(&lexstate, &funcstate); rlm@1: funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ rlm@1: luaX_next(&lexstate); /* read first token */ rlm@1: chunk(&lexstate); rlm@1: check(&lexstate, TK_EOS); rlm@1: close_func(&lexstate); rlm@1: lua_assert(funcstate.prev == NULL); rlm@1: lua_assert(funcstate.f->nups == 0); rlm@1: lua_assert(lexstate.fs == NULL); rlm@1: return funcstate.f; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: /*============================================================*/ rlm@1: /* GRAMMAR RULES */ rlm@1: /*============================================================*/ rlm@1: rlm@1: rlm@1: static void field (LexState *ls, expdesc *v) { rlm@1: /* field -> ['.' | ':'] NAME */ rlm@1: FuncState *fs = ls->fs; rlm@1: expdesc key; rlm@1: luaK_exp2anyreg(fs, v); rlm@1: luaX_next(ls); /* skip the dot or colon */ rlm@1: checkname(ls, &key); rlm@1: luaK_indexed(fs, v, &key); rlm@1: } rlm@1: rlm@1: rlm@1: static void yindex (LexState *ls, expdesc *v) { rlm@1: /* index -> '[' expr ']' */ rlm@1: luaX_next(ls); /* skip the '[' */ rlm@1: expr(ls, v); rlm@1: luaK_exp2val(ls->fs, v); rlm@1: checknext(ls, ']'); rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================================== rlm@1: ** Rules for Constructors rlm@1: ** ======================================================================= rlm@1: */ rlm@1: rlm@1: rlm@1: struct ConsControl { rlm@1: expdesc v; /* last list item read */ rlm@1: expdesc *t; /* table descriptor */ rlm@1: int nh; /* total number of `record' elements */ rlm@1: int na; /* total number of array elements */ rlm@1: int tostore; /* number of array elements pending to be stored */ rlm@1: }; rlm@1: rlm@1: rlm@1: static void recfield (LexState *ls, struct ConsControl *cc) { rlm@1: /* recfield -> (NAME | `['exp1`]') = exp1 */ rlm@1: FuncState *fs = ls->fs; rlm@1: int reg = ls->fs->freereg; rlm@1: expdesc key, val; rlm@1: int rkkey; rlm@1: if (ls->t.token == TK_NAME) { rlm@1: luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); rlm@1: checkname(ls, &key); rlm@1: } rlm@1: else /* ls->t.token == '[' */ rlm@1: yindex(ls, &key); rlm@1: cc->nh++; rlm@1: checknext(ls, '='); rlm@1: rkkey = luaK_exp2RK(fs, &key); rlm@1: expr(ls, &val); rlm@1: luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); rlm@1: fs->freereg = reg; /* free registers */ rlm@1: } rlm@1: rlm@1: rlm@1: static void closelistfield (FuncState *fs, struct ConsControl *cc) { rlm@1: if (cc->v.k == VVOID) return; /* there is no list item */ rlm@1: luaK_exp2nextreg(fs, &cc->v); rlm@1: cc->v.k = VVOID; rlm@1: if (cc->tostore == LFIELDS_PER_FLUSH) { rlm@1: luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ rlm@1: cc->tostore = 0; /* no more items pending */ rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void lastlistfield (FuncState *fs, struct ConsControl *cc) { rlm@1: if (cc->tostore == 0) return; rlm@1: if (hasmultret(cc->v.k)) { rlm@1: luaK_setmultret(fs, &cc->v); rlm@1: luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); rlm@1: cc->na--; /* do not count last expression (unknown number of elements) */ rlm@1: } rlm@1: else { rlm@1: if (cc->v.k != VVOID) rlm@1: luaK_exp2nextreg(fs, &cc->v); rlm@1: luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void listfield (LexState *ls, struct ConsControl *cc) { rlm@1: expr(ls, &cc->v); rlm@1: luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); rlm@1: cc->na++; rlm@1: cc->tostore++; rlm@1: } rlm@1: rlm@1: rlm@1: static void constructor (LexState *ls, expdesc *t) { rlm@1: /* constructor -> ?? */ rlm@1: FuncState *fs = ls->fs; rlm@1: int line = ls->linenumber; rlm@1: int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); rlm@1: struct ConsControl cc; rlm@1: cc.na = cc.nh = cc.tostore = 0; rlm@1: cc.t = t; rlm@1: init_exp(t, VRELOCABLE, pc); rlm@1: init_exp(&cc.v, VVOID, 0); /* no value (yet) */ rlm@1: luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ rlm@1: checknext(ls, '{'); rlm@1: do { rlm@1: lua_assert(cc.v.k == VVOID || cc.tostore > 0); rlm@1: if (ls->t.token == '}') break; rlm@1: closelistfield(fs, &cc); rlm@1: switch(ls->t.token) { rlm@1: case TK_NAME: { /* may be listfields or recfields */ rlm@1: luaX_lookahead(ls); rlm@1: if (ls->lookahead.token != '=') /* expression? */ rlm@1: listfield(ls, &cc); rlm@1: else rlm@1: recfield(ls, &cc); rlm@1: break; rlm@1: } rlm@1: case '[': { /* constructor_item -> recfield */ rlm@1: recfield(ls, &cc); rlm@1: break; rlm@1: } rlm@1: default: { /* constructor_part -> listfield */ rlm@1: listfield(ls, &cc); rlm@1: break; rlm@1: } rlm@1: } rlm@1: } while (testnext(ls, ',') || testnext(ls, ';')); rlm@1: check_match(ls, '}', '{', line); rlm@1: lastlistfield(fs, &cc); rlm@1: SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ rlm@1: SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ rlm@1: } rlm@1: rlm@1: /* }====================================================================== */ rlm@1: rlm@1: rlm@1: rlm@1: static void parlist (LexState *ls) { rlm@1: /* parlist -> [ param { `,' param } ] */ rlm@1: FuncState *fs = ls->fs; rlm@1: Proto *f = fs->f; rlm@1: int nparams = 0; rlm@1: f->is_vararg = 0; rlm@1: if (ls->t.token != ')') { /* is `parlist' not empty? */ rlm@1: do { rlm@1: switch (ls->t.token) { rlm@1: case TK_NAME: { /* param -> NAME */ rlm@1: new_localvar(ls, str_checkname(ls), nparams++); rlm@1: break; rlm@1: } rlm@1: case TK_DOTS: { /* param -> `...' */ rlm@1: luaX_next(ls); rlm@1: #if defined(LUA_COMPAT_VARARG) rlm@1: /* use `arg' as default name */ rlm@1: new_localvarliteral(ls, "arg", nparams++); rlm@1: f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; rlm@1: #endif rlm@1: f->is_vararg |= VARARG_ISVARARG; rlm@1: break; rlm@1: } rlm@1: default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); rlm@1: } rlm@1: } while (!f->is_vararg && testnext(ls, ',')); rlm@1: } rlm@1: adjustlocalvars(ls, nparams); rlm@1: f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); rlm@1: luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ rlm@1: } rlm@1: rlm@1: rlm@1: static void body (LexState *ls, expdesc *e, int needself, int line) { rlm@1: /* body -> `(' parlist `)' chunk END */ rlm@1: FuncState new_fs; rlm@1: open_func(ls, &new_fs); rlm@1: new_fs.f->linedefined = line; rlm@1: checknext(ls, '('); rlm@1: if (needself) { rlm@1: new_localvarliteral(ls, "self", 0); rlm@1: adjustlocalvars(ls, 1); rlm@1: } rlm@1: parlist(ls); rlm@1: checknext(ls, ')'); rlm@1: chunk(ls); rlm@1: new_fs.f->lastlinedefined = ls->linenumber; rlm@1: check_match(ls, TK_END, TK_FUNCTION, line); rlm@1: close_func(ls); rlm@1: pushclosure(ls, &new_fs, e); rlm@1: } rlm@1: rlm@1: rlm@1: static int explist1 (LexState *ls, expdesc *v) { rlm@1: /* explist1 -> expr { `,' expr } */ rlm@1: int n = 1; /* at least one expression */ rlm@1: expr(ls, v); rlm@1: while (testnext(ls, ',')) { rlm@1: luaK_exp2nextreg(ls->fs, v); rlm@1: expr(ls, v); rlm@1: n++; rlm@1: } rlm@1: return n; rlm@1: } rlm@1: rlm@1: rlm@1: static void funcargs (LexState *ls, expdesc *f) { rlm@1: FuncState *fs = ls->fs; rlm@1: expdesc args; rlm@1: int base, nparams; rlm@1: int line = ls->linenumber; rlm@1: switch (ls->t.token) { rlm@1: case '(': { /* funcargs -> `(' [ explist1 ] `)' */ rlm@1: if (line != ls->lastline) rlm@1: luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); rlm@1: luaX_next(ls); rlm@1: if (ls->t.token == ')') /* arg list is empty? */ rlm@1: args.k = VVOID; rlm@1: else { rlm@1: explist1(ls, &args); rlm@1: luaK_setmultret(fs, &args); rlm@1: } rlm@1: check_match(ls, ')', '(', line); rlm@1: break; rlm@1: } rlm@1: case '{': { /* funcargs -> constructor */ rlm@1: constructor(ls, &args); rlm@1: break; rlm@1: } rlm@1: case TK_STRING: { /* funcargs -> STRING */ rlm@1: codestring(ls, &args, ls->t.seminfo.ts); rlm@1: luaX_next(ls); /* must use `seminfo' before `next' */ rlm@1: break; rlm@1: } rlm@1: default: { rlm@1: luaX_syntaxerror(ls, "function arguments expected"); rlm@1: return; rlm@1: } rlm@1: } rlm@1: lua_assert(f->k == VNONRELOC); rlm@1: base = f->u.s.info; /* base register for call */ rlm@1: if (hasmultret(args.k)) rlm@1: nparams = LUA_MULTRET; /* open call */ rlm@1: else { rlm@1: if (args.k != VVOID) rlm@1: luaK_exp2nextreg(fs, &args); /* close last argument */ rlm@1: nparams = fs->freereg - (base+1); rlm@1: } rlm@1: init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); rlm@1: luaK_fixline(fs, line); rlm@1: fs->freereg = base+1; /* call remove function and arguments and leaves rlm@1: (unless changed) one result */ rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================================== rlm@1: ** Expression parsing rlm@1: ** ======================================================================= rlm@1: */ rlm@1: rlm@1: rlm@1: static void prefixexp (LexState *ls, expdesc *v) { rlm@1: /* prefixexp -> NAME | '(' expr ')' */ rlm@1: switch (ls->t.token) { rlm@1: case '(': { rlm@1: int line = ls->linenumber; rlm@1: luaX_next(ls); rlm@1: expr(ls, v); rlm@1: check_match(ls, ')', '(', line); rlm@1: luaK_dischargevars(ls->fs, v); rlm@1: return; rlm@1: } rlm@1: case TK_NAME: { rlm@1: singlevar(ls, v); rlm@1: return; rlm@1: } rlm@1: default: { rlm@1: luaX_syntaxerror(ls, "unexpected symbol"); rlm@1: return; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void primaryexp (LexState *ls, expdesc *v) { rlm@1: /* primaryexp -> rlm@1: prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ rlm@1: FuncState *fs = ls->fs; rlm@1: prefixexp(ls, v); rlm@1: for (;;) { rlm@1: switch (ls->t.token) { rlm@1: case '.': { /* field */ rlm@1: field(ls, v); rlm@1: break; rlm@1: } rlm@1: case '[': { /* `[' exp1 `]' */ rlm@1: expdesc key; rlm@1: luaK_exp2anyreg(fs, v); rlm@1: yindex(ls, &key); rlm@1: luaK_indexed(fs, v, &key); rlm@1: break; rlm@1: } rlm@1: case ':': { /* `:' NAME funcargs */ rlm@1: expdesc key; rlm@1: luaX_next(ls); rlm@1: checkname(ls, &key); rlm@1: luaK_self(fs, v, &key); rlm@1: funcargs(ls, v); rlm@1: break; rlm@1: } rlm@1: case '(': case TK_STRING: case '{': { /* funcargs */ rlm@1: luaK_exp2nextreg(fs, v); rlm@1: funcargs(ls, v); rlm@1: break; rlm@1: } rlm@1: default: return; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void simpleexp (LexState *ls, expdesc *v) { rlm@1: /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | rlm@1: constructor | FUNCTION body | primaryexp */ rlm@1: switch (ls->t.token) { rlm@1: case TK_NUMBER: { rlm@1: init_exp(v, VKNUM, 0); rlm@1: v->u.nval = ls->t.seminfo.r; rlm@1: break; rlm@1: } rlm@1: case TK_STRING: { rlm@1: codestring(ls, v, ls->t.seminfo.ts); rlm@1: break; rlm@1: } rlm@1: case TK_NIL: { rlm@1: init_exp(v, VNIL, 0); rlm@1: break; rlm@1: } rlm@1: case TK_TRUE: { rlm@1: init_exp(v, VTRUE, 0); rlm@1: break; rlm@1: } rlm@1: case TK_FALSE: { rlm@1: init_exp(v, VFALSE, 0); rlm@1: break; rlm@1: } rlm@1: case TK_DOTS: { /* vararg */ rlm@1: FuncState *fs = ls->fs; rlm@1: check_condition(ls, fs->f->is_vararg, rlm@1: "cannot use " LUA_QL("...") " outside a vararg function"); rlm@1: fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ rlm@1: init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); rlm@1: break; rlm@1: } rlm@1: case '{': { /* constructor */ rlm@1: constructor(ls, v); rlm@1: return; rlm@1: } rlm@1: case TK_FUNCTION: { rlm@1: luaX_next(ls); rlm@1: body(ls, v, 0, ls->linenumber); rlm@1: return; rlm@1: } rlm@1: default: { rlm@1: primaryexp(ls, v); rlm@1: return; rlm@1: } rlm@1: } rlm@1: luaX_next(ls); rlm@1: } rlm@1: rlm@1: rlm@1: static UnOpr getunopr (int op) { rlm@1: switch (op) { rlm@1: case TK_NOT: return OPR_NOT; rlm@1: case '-': return OPR_MINUS; rlm@1: case '#': return OPR_LEN; rlm@1: default: return OPR_NOUNOPR; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static BinOpr getbinopr (int op) { rlm@1: switch (op) { rlm@1: case '+': return OPR_ADD; rlm@1: case '-': return OPR_SUB; rlm@1: case '*': return OPR_MUL; rlm@1: case '/': return OPR_DIV; rlm@1: case '%': return OPR_MOD; rlm@1: case '^': return OPR_POW; rlm@1: case TK_CONCAT: return OPR_CONCAT; rlm@1: case TK_NE: return OPR_NE; rlm@1: case TK_EQ: return OPR_EQ; rlm@1: case '<': return OPR_LT; rlm@1: case TK_LE: return OPR_LE; rlm@1: case '>': return OPR_GT; rlm@1: case TK_GE: return OPR_GE; rlm@1: case TK_AND: return OPR_AND; rlm@1: case TK_OR: return OPR_OR; rlm@1: default: return OPR_NOBINOPR; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static const struct { rlm@1: lu_byte left; /* left priority for each binary operator */ rlm@1: lu_byte right; /* right priority */ rlm@1: } priority[] = { /* ORDER OPR */ rlm@1: {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ rlm@1: {10, 9}, {5, 4}, /* power and concat (right associative) */ rlm@1: {3, 3}, {3, 3}, /* equality and inequality */ rlm@1: {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ rlm@1: {2, 2}, {1, 1} /* logical (and/or) */ rlm@1: }; rlm@1: rlm@1: #define UNARY_PRIORITY 8 /* priority for unary operators */ rlm@1: rlm@1: rlm@1: /* rlm@1: ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } rlm@1: ** where `binop' is any binary operator with a priority higher than `limit' rlm@1: */ rlm@1: static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { rlm@1: BinOpr op; rlm@1: UnOpr uop; rlm@1: enterlevel(ls); rlm@1: uop = getunopr(ls->t.token); rlm@1: if (uop != OPR_NOUNOPR) { rlm@1: luaX_next(ls); rlm@1: subexpr(ls, v, UNARY_PRIORITY); rlm@1: luaK_prefix(ls->fs, uop, v); rlm@1: } rlm@1: else simpleexp(ls, v); rlm@1: /* expand while operators have priorities higher than `limit' */ rlm@1: op = getbinopr(ls->t.token); rlm@1: while (op != OPR_NOBINOPR && priority[op].left > limit) { rlm@1: expdesc v2; rlm@1: BinOpr nextop; rlm@1: luaX_next(ls); rlm@1: luaK_infix(ls->fs, op, v); rlm@1: /* read sub-expression with higher priority */ rlm@1: nextop = subexpr(ls, &v2, priority[op].right); rlm@1: luaK_posfix(ls->fs, op, v, &v2); rlm@1: op = nextop; rlm@1: } rlm@1: leavelevel(ls); rlm@1: return op; /* return first untreated operator */ rlm@1: } rlm@1: rlm@1: rlm@1: static void expr (LexState *ls, expdesc *v) { rlm@1: subexpr(ls, v, 0); rlm@1: } rlm@1: rlm@1: /* }==================================================================== */ rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================================== rlm@1: ** Rules for Statements rlm@1: ** ======================================================================= rlm@1: */ rlm@1: rlm@1: rlm@1: static int block_follow (int token) { rlm@1: switch (token) { rlm@1: case TK_ELSE: case TK_ELSEIF: case TK_END: rlm@1: case TK_UNTIL: case TK_EOS: rlm@1: return 1; rlm@1: default: return 0; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void block (LexState *ls) { rlm@1: /* block -> chunk */ rlm@1: FuncState *fs = ls->fs; rlm@1: BlockCnt bl; rlm@1: enterblock(fs, &bl, 0); rlm@1: chunk(ls); rlm@1: lua_assert(bl.breaklist == NO_JUMP); rlm@1: leaveblock(fs); rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** structure to chain all variables in the left-hand side of an rlm@1: ** assignment rlm@1: */ rlm@1: struct LHS_assign { rlm@1: struct LHS_assign *prev; rlm@1: expdesc v; /* variable (global, local, upvalue, or indexed) */ rlm@1: }; rlm@1: rlm@1: rlm@1: /* rlm@1: ** check whether, in an assignment to a local variable, the local variable rlm@1: ** is needed in a previous assignment (to a table). If so, save original rlm@1: ** local value in a safe place and use this safe copy in the previous rlm@1: ** assignment. rlm@1: */ rlm@1: static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { rlm@1: FuncState *fs = ls->fs; rlm@1: int extra = fs->freereg; /* eventual position to save local variable */ rlm@1: int conflict = 0; rlm@1: for (; lh; lh = lh->prev) { rlm@1: if (lh->v.k == VINDEXED) { rlm@1: if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ rlm@1: conflict = 1; rlm@1: lh->v.u.s.info = extra; /* previous assignment will use safe copy */ rlm@1: } rlm@1: if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ rlm@1: conflict = 1; rlm@1: lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ rlm@1: } rlm@1: } rlm@1: } rlm@1: if (conflict) { rlm@1: luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ rlm@1: luaK_reserveregs(fs, 1); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { rlm@1: expdesc e; rlm@1: check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, rlm@1: "syntax error"); rlm@1: if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ rlm@1: struct LHS_assign nv; rlm@1: nv.prev = lh; rlm@1: primaryexp(ls, &nv.v); rlm@1: if (nv.v.k == VLOCAL) rlm@1: check_conflict(ls, lh, &nv.v); rlm@1: luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, rlm@1: "variables in assignment"); rlm@1: assignment(ls, &nv, nvars+1); rlm@1: } rlm@1: else { /* assignment -> `=' explist1 */ rlm@1: int nexps; rlm@1: checknext(ls, '='); rlm@1: nexps = explist1(ls, &e); rlm@1: if (nexps != nvars) { rlm@1: adjust_assign(ls, nvars, nexps, &e); rlm@1: if (nexps > nvars) rlm@1: ls->fs->freereg -= nexps - nvars; /* remove extra values */ rlm@1: } rlm@1: else { rlm@1: luaK_setoneret(ls->fs, &e); /* close last expression */ rlm@1: luaK_storevar(ls->fs, &lh->v, &e); rlm@1: return; /* avoid default */ rlm@1: } rlm@1: } rlm@1: init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ rlm@1: luaK_storevar(ls->fs, &lh->v, &e); rlm@1: } rlm@1: rlm@1: rlm@1: static int cond (LexState *ls) { rlm@1: /* cond -> exp */ rlm@1: expdesc v; rlm@1: expr(ls, &v); /* read condition */ rlm@1: if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ rlm@1: luaK_goiftrue(ls->fs, &v); rlm@1: return v.f; rlm@1: } rlm@1: rlm@1: rlm@1: static void breakstat (LexState *ls) { rlm@1: FuncState *fs = ls->fs; rlm@1: BlockCnt *bl = fs->bl; rlm@1: int upval = 0; rlm@1: while (bl && !bl->isbreakable) { rlm@1: upval |= bl->upval; rlm@1: bl = bl->previous; rlm@1: } rlm@1: if (!bl) rlm@1: luaX_syntaxerror(ls, "no loop to break"); rlm@1: if (upval) rlm@1: luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); rlm@1: luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); rlm@1: } rlm@1: rlm@1: rlm@1: static void whilestat (LexState *ls, int line) { rlm@1: /* whilestat -> WHILE cond DO block END */ rlm@1: FuncState *fs = ls->fs; rlm@1: int whileinit; rlm@1: int condexit; rlm@1: BlockCnt bl; rlm@1: luaX_next(ls); /* skip WHILE */ rlm@1: whileinit = luaK_getlabel(fs); rlm@1: condexit = cond(ls); rlm@1: enterblock(fs, &bl, 1); rlm@1: checknext(ls, TK_DO); rlm@1: block(ls); rlm@1: luaK_patchlist(fs, luaK_jump(fs), whileinit); rlm@1: check_match(ls, TK_END, TK_WHILE, line); rlm@1: leaveblock(fs); rlm@1: luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ rlm@1: } rlm@1: rlm@1: rlm@1: static void repeatstat (LexState *ls, int line) { rlm@1: /* repeatstat -> REPEAT block UNTIL cond */ rlm@1: int condexit; rlm@1: FuncState *fs = ls->fs; rlm@1: int repeat_init = luaK_getlabel(fs); rlm@1: BlockCnt bl1, bl2; rlm@1: enterblock(fs, &bl1, 1); /* loop block */ rlm@1: enterblock(fs, &bl2, 0); /* scope block */ rlm@1: luaX_next(ls); /* skip REPEAT */ rlm@1: chunk(ls); rlm@1: check_match(ls, TK_UNTIL, TK_REPEAT, line); rlm@1: condexit = cond(ls); /* read condition (inside scope block) */ rlm@1: if (!bl2.upval) { /* no upvalues? */ rlm@1: leaveblock(fs); /* finish scope */ rlm@1: luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ rlm@1: } rlm@1: else { /* complete semantics when there are upvalues */ rlm@1: breakstat(ls); /* if condition then break */ rlm@1: luaK_patchtohere(ls->fs, condexit); /* else... */ rlm@1: leaveblock(fs); /* finish scope... */ rlm@1: luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ rlm@1: } rlm@1: leaveblock(fs); /* finish loop */ rlm@1: } rlm@1: rlm@1: rlm@1: static int exp1 (LexState *ls) { rlm@1: expdesc e; rlm@1: int k; rlm@1: expr(ls, &e); rlm@1: k = e.k; rlm@1: luaK_exp2nextreg(ls->fs, &e); rlm@1: return k; rlm@1: } rlm@1: rlm@1: rlm@1: static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { rlm@1: /* forbody -> DO block */ rlm@1: BlockCnt bl; rlm@1: FuncState *fs = ls->fs; rlm@1: int prep, endfor; rlm@1: adjustlocalvars(ls, 3); /* control variables */ rlm@1: checknext(ls, TK_DO); rlm@1: prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); rlm@1: enterblock(fs, &bl, 0); /* scope for declared variables */ rlm@1: adjustlocalvars(ls, nvars); rlm@1: luaK_reserveregs(fs, nvars); rlm@1: block(ls); rlm@1: leaveblock(fs); /* end of scope for declared variables */ rlm@1: luaK_patchtohere(fs, prep); rlm@1: endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : rlm@1: luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); rlm@1: luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ rlm@1: luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); rlm@1: } rlm@1: rlm@1: rlm@1: static void fornum (LexState *ls, TString *varname, int line) { rlm@1: /* fornum -> NAME = exp1,exp1[,exp1] forbody */ rlm@1: FuncState *fs = ls->fs; rlm@1: int base = fs->freereg; rlm@1: new_localvarliteral(ls, "(for index)", 0); rlm@1: new_localvarliteral(ls, "(for limit)", 1); rlm@1: new_localvarliteral(ls, "(for step)", 2); rlm@1: new_localvar(ls, varname, 3); rlm@1: checknext(ls, '='); rlm@1: exp1(ls); /* initial value */ rlm@1: checknext(ls, ','); rlm@1: exp1(ls); /* limit */ rlm@1: if (testnext(ls, ',')) rlm@1: exp1(ls); /* optional step */ rlm@1: else { /* default step = 1 */ rlm@1: luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); rlm@1: luaK_reserveregs(fs, 1); rlm@1: } rlm@1: forbody(ls, base, line, 1, 1); rlm@1: } rlm@1: rlm@1: rlm@1: static void forlist (LexState *ls, TString *indexname) { rlm@1: /* forlist -> NAME {,NAME} IN explist1 forbody */ rlm@1: FuncState *fs = ls->fs; rlm@1: expdesc e; rlm@1: int nvars = 0; rlm@1: int line; rlm@1: int base = fs->freereg; rlm@1: /* create control variables */ rlm@1: new_localvarliteral(ls, "(for generator)", nvars++); rlm@1: new_localvarliteral(ls, "(for state)", nvars++); rlm@1: new_localvarliteral(ls, "(for control)", nvars++); rlm@1: /* create declared variables */ rlm@1: new_localvar(ls, indexname, nvars++); rlm@1: while (testnext(ls, ',')) rlm@1: new_localvar(ls, str_checkname(ls), nvars++); rlm@1: checknext(ls, TK_IN); rlm@1: line = ls->linenumber; rlm@1: adjust_assign(ls, 3, explist1(ls, &e), &e); rlm@1: luaK_checkstack(fs, 3); /* extra space to call generator */ rlm@1: forbody(ls, base, line, nvars - 3, 0); rlm@1: } rlm@1: rlm@1: rlm@1: static void forstat (LexState *ls, int line) { rlm@1: /* forstat -> FOR (fornum | forlist) END */ rlm@1: FuncState *fs = ls->fs; rlm@1: TString *varname; rlm@1: BlockCnt bl; rlm@1: enterblock(fs, &bl, 1); /* scope for loop and control variables */ rlm@1: luaX_next(ls); /* skip `for' */ rlm@1: varname = str_checkname(ls); /* first variable name */ rlm@1: switch (ls->t.token) { rlm@1: case '=': fornum(ls, varname, line); break; rlm@1: case ',': case TK_IN: forlist(ls, varname); break; rlm@1: default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); rlm@1: } rlm@1: check_match(ls, TK_END, TK_FOR, line); rlm@1: leaveblock(fs); /* loop scope (`break' jumps to this point) */ rlm@1: } rlm@1: rlm@1: rlm@1: static int test_then_block (LexState *ls) { rlm@1: /* test_then_block -> [IF | ELSEIF] cond THEN block */ rlm@1: int condexit; rlm@1: luaX_next(ls); /* skip IF or ELSEIF */ rlm@1: condexit = cond(ls); rlm@1: checknext(ls, TK_THEN); rlm@1: block(ls); /* `then' part */ rlm@1: return condexit; rlm@1: } rlm@1: rlm@1: rlm@1: static void ifstat (LexState *ls, int line) { rlm@1: /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ rlm@1: FuncState *fs = ls->fs; rlm@1: int flist; rlm@1: int escapelist = NO_JUMP; rlm@1: flist = test_then_block(ls); /* IF cond THEN block */ rlm@1: while (ls->t.token == TK_ELSEIF) { rlm@1: luaK_concat(fs, &escapelist, luaK_jump(fs)); rlm@1: luaK_patchtohere(fs, flist); rlm@1: flist = test_then_block(ls); /* ELSEIF cond THEN block */ rlm@1: } rlm@1: if (ls->t.token == TK_ELSE) { rlm@1: luaK_concat(fs, &escapelist, luaK_jump(fs)); rlm@1: luaK_patchtohere(fs, flist); rlm@1: luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ rlm@1: block(ls); /* `else' part */ rlm@1: } rlm@1: else rlm@1: luaK_concat(fs, &escapelist, flist); rlm@1: luaK_patchtohere(fs, escapelist); rlm@1: check_match(ls, TK_END, TK_IF, line); rlm@1: } rlm@1: rlm@1: rlm@1: static void localfunc (LexState *ls) { rlm@1: expdesc v, b; rlm@1: FuncState *fs = ls->fs; rlm@1: new_localvar(ls, str_checkname(ls), 0); rlm@1: init_exp(&v, VLOCAL, fs->freereg); rlm@1: luaK_reserveregs(fs, 1); rlm@1: adjustlocalvars(ls, 1); rlm@1: body(ls, &b, 0, ls->linenumber); rlm@1: luaK_storevar(fs, &v, &b); rlm@1: /* debug information will only see the variable after this point! */ rlm@1: getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; rlm@1: } rlm@1: rlm@1: rlm@1: static void localstat (LexState *ls) { rlm@1: /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ rlm@1: int nvars = 0; rlm@1: int nexps; rlm@1: expdesc e; rlm@1: do { rlm@1: new_localvar(ls, str_checkname(ls), nvars++); rlm@1: } while (testnext(ls, ',')); rlm@1: if (testnext(ls, '=')) rlm@1: nexps = explist1(ls, &e); rlm@1: else { rlm@1: e.k = VVOID; rlm@1: nexps = 0; rlm@1: } rlm@1: adjust_assign(ls, nvars, nexps, &e); rlm@1: adjustlocalvars(ls, nvars); rlm@1: } rlm@1: rlm@1: rlm@1: static int funcname (LexState *ls, expdesc *v) { rlm@1: /* funcname -> NAME {field} [`:' NAME] */ rlm@1: int needself = 0; rlm@1: singlevar(ls, v); rlm@1: while (ls->t.token == '.') rlm@1: field(ls, v); rlm@1: if (ls->t.token == ':') { rlm@1: needself = 1; rlm@1: field(ls, v); rlm@1: } rlm@1: return needself; rlm@1: } rlm@1: rlm@1: rlm@1: static void funcstat (LexState *ls, int line) { rlm@1: /* funcstat -> FUNCTION funcname body */ rlm@1: int needself; rlm@1: expdesc v, b; rlm@1: luaX_next(ls); /* skip FUNCTION */ rlm@1: needself = funcname(ls, &v); rlm@1: body(ls, &b, needself, line); rlm@1: luaK_storevar(ls->fs, &v, &b); rlm@1: luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ rlm@1: } rlm@1: rlm@1: rlm@1: static void exprstat (LexState *ls) { rlm@1: /* stat -> func | assignment */ rlm@1: FuncState *fs = ls->fs; rlm@1: struct LHS_assign v; rlm@1: primaryexp(ls, &v.v); rlm@1: if (v.v.k == VCALL) /* stat -> func */ rlm@1: SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ rlm@1: else { /* stat -> assignment */ rlm@1: v.prev = NULL; rlm@1: assignment(ls, &v, 1); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void retstat (LexState *ls) { rlm@1: /* stat -> RETURN explist */ rlm@1: FuncState *fs = ls->fs; rlm@1: expdesc e; rlm@1: int first, nret; /* registers with returned values */ rlm@1: luaX_next(ls); /* skip RETURN */ rlm@1: if (block_follow(ls->t.token) || ls->t.token == ';') rlm@1: first = nret = 0; /* return no values */ rlm@1: else { rlm@1: nret = explist1(ls, &e); /* optional return values */ rlm@1: if (hasmultret(e.k)) { rlm@1: luaK_setmultret(fs, &e); rlm@1: if (e.k == VCALL && nret == 1) { /* tail call? */ rlm@1: SET_OPCODE(getcode(fs,&e), OP_TAILCALL); rlm@1: lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); rlm@1: } rlm@1: first = fs->nactvar; rlm@1: nret = LUA_MULTRET; /* return all values */ rlm@1: } rlm@1: else { rlm@1: if (nret == 1) /* only one single value? */ rlm@1: first = luaK_exp2anyreg(fs, &e); rlm@1: else { rlm@1: luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ rlm@1: first = fs->nactvar; /* return all `active' values */ rlm@1: lua_assert(nret == fs->freereg - first); rlm@1: } rlm@1: } rlm@1: } rlm@1: luaK_ret(fs, first, nret); rlm@1: } rlm@1: rlm@1: rlm@1: static int statement (LexState *ls) { rlm@1: int line = ls->linenumber; /* may be needed for error messages */ rlm@1: switch (ls->t.token) { rlm@1: case TK_IF: { /* stat -> ifstat */ rlm@1: ifstat(ls, line); rlm@1: return 0; rlm@1: } rlm@1: case TK_WHILE: { /* stat -> whilestat */ rlm@1: whilestat(ls, line); rlm@1: return 0; rlm@1: } rlm@1: case TK_DO: { /* stat -> DO block END */ rlm@1: luaX_next(ls); /* skip DO */ rlm@1: block(ls); rlm@1: check_match(ls, TK_END, TK_DO, line); rlm@1: return 0; rlm@1: } rlm@1: case TK_FOR: { /* stat -> forstat */ rlm@1: forstat(ls, line); rlm@1: return 0; rlm@1: } rlm@1: case TK_REPEAT: { /* stat -> repeatstat */ rlm@1: repeatstat(ls, line); rlm@1: return 0; rlm@1: } rlm@1: case TK_FUNCTION: { rlm@1: funcstat(ls, line); /* stat -> funcstat */ rlm@1: return 0; rlm@1: } rlm@1: case TK_LOCAL: { /* stat -> localstat */ rlm@1: luaX_next(ls); /* skip LOCAL */ rlm@1: if (testnext(ls, TK_FUNCTION)) /* local function? */ rlm@1: localfunc(ls); rlm@1: else rlm@1: localstat(ls); rlm@1: return 0; rlm@1: } rlm@1: case TK_RETURN: { /* stat -> retstat */ rlm@1: retstat(ls); rlm@1: return 1; /* must be last statement */ rlm@1: } rlm@1: case TK_BREAK: { /* stat -> breakstat */ rlm@1: luaX_next(ls); /* skip BREAK */ rlm@1: breakstat(ls); rlm@1: return 1; /* must be last statement */ rlm@1: } rlm@1: default: { rlm@1: exprstat(ls); rlm@1: return 0; /* to avoid warnings */ rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void chunk (LexState *ls) { rlm@1: /* chunk -> { stat [`;'] } */ rlm@1: int islast = 0; rlm@1: enterlevel(ls); rlm@1: while (!islast && !block_follow(ls->t.token)) { rlm@1: islast = statement(ls); rlm@1: testnext(ls, ';'); rlm@1: lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && rlm@1: ls->fs->freereg >= ls->fs->nactvar); rlm@1: ls->fs->freereg = ls->fs->nactvar; /* free registers */ rlm@1: } rlm@1: leavelevel(ls); rlm@1: } rlm@1: rlm@1: /* }====================================================================== */