📄 lparser.c
字号:
static void closelistfield (FuncState *fs, struct ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */ cc->tostore = 0; /* no more items pending */ fs->freereg = cc->t->info + 1; /* free registers */ }}static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (cc->v.k == VCALL) { luaK_setcallreturns(fs, &cc->v, LUA_MULTRET); luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); } fs->freereg = cc->t->info + 1; /* free registers */}static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); cc->na++; cc->tostore++;}static void constructor (LexState *ls, expdesc *t) { /* constructor -> ?? */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ check(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); testnext(ls, ';'); /* compatibility only */ if (ls->t.token == '}') break; closelistfield(fs, &cc); switch(ls->t.token) { case TK_NAME: { /* may be listfields or recfields */ lookahead(ls); if (ls->lookahead.token != '=') /* expression? */ listfield(ls, &cc); else recfield(ls, &cc); break; } case '[': { /* constructor_item -> recfield */ recfield(ls, &cc); break; } default: { /* constructor_part -> listfield */ listfield(ls, &cc); break; } } } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */}/* }====================================================================== */static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ int nparams = 0; int dots = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { case TK_DOTS: dots = 1; next(ls); break; case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; default: luaX_syntaxerror(ls, "<name> or `...' expected"); } } while (!dots && testnext(ls, ',')); } code_params(ls, nparams, dots);}static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); new_fs.f->lineDefined = line; check(ls, '('); if (needself) create_local(ls, "self"); parlist(ls); check(ls, ')'); chunk(ls); check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e);}static int explist1 (LexState *ls, expdesc *v) { /* explist1 -> expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++; } return n;}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)"); next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); luaK_setcallreturns(fs, &args, LUA_MULTRET); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); return; } } lua_assert(f->k == VNONRELOC); base = f->info; /* base register for call */ if (args.k == VCALL) 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 */}/*** {======================================================================** Expression parsing** =======================================================================*/static void prefixexp (LexState *ls, expdesc *v) { /* prefixexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v, 1); return; }#ifdef LUA_COMPATUPSYNTAX case '%': { /* for compatibility only */ TString *varname; int line = ls->linenumber; next(ls); /* skip `%' */ varname = singlevar(ls, v, 1); if (v->k != VUPVAL) luaX_errorline(ls, "global upvalues are obsolete", getstr(varname), line); return; }#endif default: { luaX_syntaxerror(ls, "unexpected symbol"); return; } }}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 */ luaY_field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); luaY_index(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; 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; } }}static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); next(ls); /* must use `seminfo' before `next' */ break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); next(ls); /* must use `seminfo' before `next' */ break; } case TK_NIL: { init_exp(v, VNIL, 0); next(ls); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); next(ls); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); next(ls); break; } case '{': { /* constructor */ constructor(ls, v); break; } case TK_FUNCTION: { next(ls); body(ls, v, 0, ls->linenumber); break; } default: { primaryexp(ls, v); break; } }}static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; default: return OPR_NOUNOPR; }}static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MULT; case '/': return OPR_DIV; 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 */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */ {10, 9}, {5, 4}, /* power and concat (right associative) */ {3, 3}, {3, 3}, /* equality */ {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 -> (simplexep | unop subexpr) { binop subexpr }** where `binop' is any binary operator with a priority higher than `limit'*/static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { 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 && cast(int, priority[op].left) > limit) { expdesc v2; BinOpr nextop; next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, cast(int, priority[op].right)); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */}static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, -1);}/* }==================================================================== *//*** {======================================================================** Rules for Statements** =======================================================================*/static int block_follow (int token) { switch (token) { case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: case TK_EOS: return 1; default: return 0; }}static void block (LexState *ls) { /* block -> chunk */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); chunk(ls); lua_assert(bl.breaklist == NO_JUMP); leaveblock(fs);}/*** structure to chain all variables in the left-hand side of an** assignment*/struct LHS_assign { struct LHS_assign *prev; expdesc v; /* variable (global, local, upvalue, or indexed) */};/*** check whether, in an assignment to a local variable, the local variable** is needed in a previous assignment (to a table). If so, save original** local value in a safe place and use this safe copy in the previous** assignment.*/static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { if (lh->v.k == VINDEXED) { if (lh->v.info == v->info) { /* conflict? */ conflict = 1; lh->v.info = extra; /* previous assignment will use safe copy */ } if (lh->v.aux == v->info) { /* conflict? */ conflict = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -