lparser.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,338 行 · 第 1/3 页
CPP
1,338 行
** 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.u.s.info == v->u.s.info) { /* conflict? */
conflict = 1;
lh->v.u.s.info = extra; /* previous assignment will use safe copy */
}
if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */
conflict = 1;
lh->v.u.s.aux = extra; /* previous assignment will use safe copy */
}
}
}
if (conflict) {
luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */
luaK_reserveregs(fs, 1);
}
}
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);
assignment(ls, &nv, nvars+1);
}
else { /* assignment -> `=' explist1 */
int nexps;
checknext(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);
return; /* avoid default */
}
}
init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
luaK_storevar(ls->fs, &lh->v, &e);
}
static int cond (LexState *ls) {
/* cond -> exp */
expdesc v;
expr(ls, &v); /* read condition */
if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */
luaK_goiftrue(ls->fs, &v);
return v.f;
}
static void breakstat (LexState *ls) {
FuncState *fs = ls->fs;
BlockCnt *bl = fs->bl;
int upval = 0;
while (bl && !bl->isbreakable) {
upval |= bl->upval;
bl = bl->previous;
}
if (!bl)
luaX_syntaxerror(ls, "no loop to break");
if (upval)
luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
}
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 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 int exp1 (LexState *ls) {
expdesc e;
int k;
expr(ls, &e);
k = e.k;
luaK_exp2nextreg(ls->fs, &e);
return k;
}
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
/* forbody -> DO block */
BlockCnt bl;
FuncState *fs = ls->fs;
int prep, endfor;
adjustlocalvars(ls, 3); /* control variables */
checknext(ls, TK_DO);
prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
enterblock(fs, &bl, 0); /* scope for declared variables */
adjustlocalvars(ls, nvars);
luaK_reserveregs(fs, nvars);
block(ls);
leaveblock(fs); /* end of scope for declared variables */
luaK_patchtohere(fs, prep);
endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
}
static void fornum (LexState *ls, TString *varname, int line) {
/* fornum -> NAME = exp1,exp1[,exp1] forbody */
FuncState *fs = ls->fs;
int base = fs->freereg;
new_localvarliteral(ls, "(for index)", 0);
new_localvarliteral(ls, "(for limit)", 1);
new_localvarliteral(ls, "(for step)", 2);
new_localvar(ls, varname, 3);
checknext(ls, '=');
exp1(ls); /* initial value */
checknext(ls, ',');
exp1(ls); /* limit */
if (testnext(ls, ','))
exp1(ls); /* optional step */
else { /* default step = 1 */
luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
luaK_reserveregs(fs, 1);
}
forbody(ls, base, line, 1, 1);
}
static void forlist (LexState *ls, TString *indexname) {
/* forlist -> NAME {,NAME} IN explist1 forbody */
FuncState *fs = ls->fs;
expdesc e;
int nvars = 0;
int line;
int base = fs->freereg;
/* create control variables */
new_localvarliteral(ls, "(for generator)", nvars++);
new_localvarliteral(ls, "(for state)", nvars++);
new_localvarliteral(ls, "(for control)", nvars++);
/* create declared variables */
new_localvar(ls, indexname, nvars++);
while (testnext(ls, ','))
new_localvar(ls, str_checkname(ls), nvars++);
checknext(ls, TK_IN);
line = ls->linenumber;
adjust_assign(ls, 3, explist1(ls, &e), &e);
luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base, line, nvars - 3, 0);
}
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 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 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 localfunc (LexState *ls) {
expdesc v, b;
FuncState *fs = ls->fs;
new_localvar(ls, str_checkname(ls), 0);
init_exp(&v, VLOCAL, fs->freereg);
luaK_reserveregs(fs, 1);
adjustlocalvars(ls, 1);
body(ls, &b, 0, ls->linenumber);
luaK_storevar(fs, &v, &b);
/* debug information will only see the variable after this point! */
getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
}
static void localstat (LexState *ls) {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
int nexps;
expdesc e;
do {
new_localvar(ls, str_checkname(ls), nvars++);
} while (testnext(ls, ','));
if (testnext(ls, '='))
nexps = explist1(ls, &e);
else {
e.k = VVOID;
nexps = 0;
}
adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}
static int funcname (LexState *ls, expdesc *v) {
/* funcname -> NAME {field} [`:' NAME] */
int needself = 0;
singlevar(ls, v);
while (ls->t.token == '.')
field(ls, v);
if (ls->t.token == ':') {
needself = 1;
field(ls, v);
}
return needself;
}
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 exprstat (LexState *ls) {
/* stat -> func | assignment */
FuncState *fs = ls->fs;
struct LHS_assign v;
primaryexp(ls, &v.v);
if (v.v.k == VCALL) /* stat -> func */
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
else { /* stat -> assignment */
v.prev = NULL;
assignment(ls, &v, 1);
}
}
static void retstat (LexState *ls) {
/* stat -> RETURN explist */
FuncState *fs = ls->fs;
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);
}
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 */
}
default: {
exprstat(ls);
return 0; /* to avoid warnings */
}
}
}
static void chunk (LexState *ls) {
/* chunk -> { stat [`;'] } */
int islast = 0;
enterlevel(ls);
while (!islast && !block_follow(ls->t.token)) {
islast = statement(ls);
testnext(ls, ';');
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
}
leavelevel(ls);
}
/* }====================================================================== */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?