static void funcargs (LexState *ls, expdesc *f) { FuncState *fs = ls->fs; expdesc args; int base, nparams; int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ if (line != ls->lastline) luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); return; } } lua_assert(f->k == VNONRELOC); base = f->u.s.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ }
static TString* str_checkname(LexState* ls) { TString* ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; luaX_next(ls); return ts; }
static void yindex(LexState* ls, expdesc* v) { /* index -> '[' expr ']' */ luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); }
static int testnext(LexState* ls, int c) { if (ls->t.token == c) { luaX_next(ls); return 1; } else return 0; }
static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); }
static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ int condexit; luaX_next(ls); /* skip IF or ELSEIF */ condexit = cond(ls); checknext(ls, TK_THEN); block(ls); /* `then' part */ return condexit; }
static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); body(ls, &b, needself, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ }
static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = GetCurrentFuncState( ls ); expdesc e; int first, nret; /* registers with returned values */ luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') { first = nret = 0; /* return no values */ } else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ { first = luaK_exp2anyreg(fs, &e); } else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); }
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; TString *inputNameString = luaS_new(L, name); try { luaX_setinput(L, &lexstate, z, inputNameString ); open_func(&lexstate, &funcstate); try { funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); } catch( ... ) { close_func(&lexstate); // We do not need the proto anymore. funcstate.f->DereferenceGC( L ); throw; } close_func(&lexstate); // The result is funcstate.f, which is a referenced proto. } catch( ... ) { // When done parsing, we should clear up the string. inputNameString->DereferenceGC( L ); throw; } inputNameString->DereferenceGC( L ); lua_assert(funcstate.next == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fsList.IsEmpty() == true); return funcstate.f; }
static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; expdesc e; int first, nret; /* registers with returned values */ int ret_in_try = 0; luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } /* before return, we should exit all try-catch blocks */ while (bl) { if (bl->isbreakable == 2) { if (ret_in_try) luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); else { ret_in_try = 1; luaK_codeABC(fs, OP_EXITTRY, first, nret+1, 1); /* here we will save all return values */ } } else if (bl->isbreakable == 3) luaX_syntaxerror(ls, "can't return in _finally_ clause"); bl = bl->previous; } luaK_codeABC(fs, OP_RETURN, first, nret+1, ret_in_try); }
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; }
static void forstat (LexState *ls, int line) { /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope (`break' jumps to this point) */ }
static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_patchlist(fs, luaK_jump(fs), whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ }
static void dostrip(LexState *X) { int ln=1; int lt=0; for (;;) { int t; luaX_next(X); t=X->t.token; if (preserve) { if (X->linenumber!=ln) { if (preserve>1) while (X->linenumber!=ln++) printf("\n"); else if (lt!=0) printf("\n"); ln=X->linenumber; lt=0; } } if (space(lt,t)) printf(" "); switch (t) { case TK_EOS: return; case TK_STRING: quote(X->t.seminfo.ts); break; case TK_NAME: printf("%s",getstr(X->t.seminfo.ts)); break; case TK_NUMBER: printf("%s",X->buff->buffer); break; default: if (t<FIRST_RESERVED) printf("%c",t); else printf("%s",luaX_tokens[t-FIRST_RESERVED]); break; } lt=t; if (preserve>2) printf("\n"); } }
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars, BinOpr *opr) { expdesc e; check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); assignment(ls, &nv, nvars+1, opr); } else { /* assignment -> `=' explist1 */ int nexps; *opr = OPR_NOBINOPR; switch(ls->t.token) { case '=': break; case TK_CONCATASSIGN: *opr = OPR_CONCAT; break; case TK_ADDASSIGN: *opr = OPR_ADD; break; case TK_SUBASSIGN: *opr = OPR_SUB; break; case TK_MULASSIGN: *opr = OPR_MUL; break; case TK_DIVASSIGN: *opr = OPR_DIV; break; case TK_POWASSIGN: *opr = OPR_POW; break; case TK_MODASSIGN: *opr = OPR_MOD; break; default: luaX_syntaxerror(ls, "unexpected symbol"); break; }; luaX_next(ls); nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e, *opr); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e, *opr); }
static void compound (LexState *ls, struct LHS_assign *lh) { expdesc rh; int nexps; BinOpr op; check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, "syntax error"); /* parse Compound operation. */ op = getcompopr(ls->t.token); luaX_next(ls); /* parse right-hand expression */ nexps = explist1(ls, &rh); check_condition(ls, nexps == 1, "syntax error"); luaK_posfix(ls->fs, op, &(lh->v), &rh); }
static void primaryexp(LexState* ls, expdesc* v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState* fs = ls->fs; prefixexp(ls, v); for (;;) { switch (ls->t.token) { case '.': /* field */ { field(ls, v); break; } case '[': /* `[' exp1 `]' */ { expdesc key; luaK_exp2anyreg(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': /* `:' NAME funcargs */ { expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); break; } case '(': case TK_STRING: case '{': /* funcargs */ { luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } }
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState *pfuncstate = (struct FuncState*)malloc(sizeof(struct FuncState)); Proto *res; lexstate.buff = buff; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, pfuncstate); pfuncstate->f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(pfuncstate->prev == NULL); lua_assert(pfuncstate->f->nups == 0); lua_assert(lexstate.fs == NULL); res = pfuncstate->f; free(pfuncstate); return res; }
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; TString *tname = luaS_new(L, name); setsvalue2s(L, L->top, tname); /* protect name */ incr_top(L); lexstate.buff = buff; luaX_setinput(L, &lexstate, z, tname); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); L->top--; /* remove 'name' from stack */ lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; }
static void inc_assignment(LexState *ls, struct LHS_assign *lh) { 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, '='); 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); leavelevel(ls); luaK_exp2nextreg(fs,&e); luaK_setoneret(ls->fs, &e); luaK_storevar(ls->fs, &lh->v, &e); }
static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ FuncState *fs = GetCurrentFuncState( ls ); Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls), nparams++); break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); f->is_vararg |= VARARG_ISVARARG; break; } default: { luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected"); break; } } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte( fs->nactvar - (f->is_vararg & VARARG_HASARG) ); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ }
static void prefixexp (LexState *ls, expdesc *v) { /* prefixexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v); return; } default: { luaX_syntaxerror(ls, "unexpected symbol"); return; } } }
static void parlist(LexState* ls) { /* parlist -> [ param { `,' param } ] */ FuncState* fs = ls->fs; Proto* f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') /* is `parlist' not empty? */ { do { switch (ls->t.token) { case TK_NAME: /* param -> NAME */ { new_localvar(ls, str_checkname(ls), nparams++); break; } case TK_DOTS: /* param -> `...' */ { luaX_next(ls); #if defined(LUA_COMPAT_VARARG) /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; #endif f->is_vararg |= VARARG_ISVARARG; break; } default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected"); } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ }
static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int flist; int escapelist = NO_JUMP; flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); }
static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); #if LUA_EXT_CONTINUE if (bl2.continuelist != NO_JUMP) { int oldprohibition = fs->prohibitedloc; luaK_patchtohere(fs, bl2.continuelist); fs->prohibitedloc = bl2.continuepos; condexit = cond(ls); /* read condition (inside scope block) */ fs->prohibitedloc = oldprohibition; bl2.continuelist = NO_JUMP; } else { condexit = cond(ls); /* read condition (inside scope block) */ } #else condexit = cond(ls); /* read condition (inside scope block) */ #endif /* LUA_EXT_CONTINUE */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ }
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, "variables in assignment"); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ int nexps; #if LUA_MUTATION_OPERATORS luaX_next(ls); /* consume `=' token. */ #else checknext(ls, '='); #endif /* LUA_MUTATION_OPERATORS */ nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e); }
static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ }
static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); }
static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; prefixexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* field */ field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); break; } #if LUA_WIDESTRING case '(': case TK_STRING: case TK_WSTRING: case '{': { /* funcargs */ #else case '(': case TK_STRING: case '{': { /* funcargs */ #endif /* LUA_WIDESTRING */ luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { #if LUA_WIDESTRING /* simpleexp -> NUMBER | STRING | WSTRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ #else /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ #endif /* LUA_WIDESTRING */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } #if LUA_WIDESTRING case TK_WSTRING: { codewstring(ls, v, ls->t.seminfo.ts); break; } #endif /* LUA_WIDESTRING */ case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { primaryexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; #if LUA_BITFIELD_OPS case '&': return OPR_BAND; case '|': return OPR_BOR; case TK_XOR: return OPR_BXOR; case TK_SHL: return OPR_BSHL; case TK_SHR: return OPR_BSHR; #endif /* LUA_BITFIELD_OPS */ case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ #if LUA_BITFIELD_OPS {8, 8}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, /* bitwise operators */ #endif /* LUA_BITFIELD_OPS */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ }
static int statement(LexState* ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { case TK_IF: /* stat -> ifstat */ { ifstat(ls, line); return 0; } case TK_WHILE: /* stat -> whilestat */ { whilestat(ls, line); return 0; } case TK_DO: /* stat -> DO block END */ { luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); return 0; } case TK_FOR: /* stat -> forstat */ { forstat(ls, line); return 0; } case TK_REPEAT: /* stat -> repeatstat */ { repeatstat(ls, line); return 0; } case TK_FUNCTION: { funcstat(ls, line); /* stat -> funcstat */ return 0; } case TK_LOCAL: /* stat -> localstat */ { luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else localstat(ls); return 0; } case TK_RETURN: /* stat -> retstat */ { retstat(ls); return 1; /* must be last statement */ } case TK_BREAK: /* stat -> breakstat */ { luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } case TK_CONTINUE: /* stat -> continuestat */ { luaX_next(ls); /* skip CONTINUE */ continuestat(ls); return 1; /* must be last statement */ } default: { exprstat(ls); return 0; /* to avoid warnings */ } } }