/*
** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/#define lcode_c#define LUA_CORE#include"lprefix.h"#include<math.h>#include<stdlib.h>#include"lua.h"#include"lcode.h"#include"ldebug.h"#include"ldo.h"#include"lgc.h"#include"llex.h"#include"lmem.h"#include"lobject.h"#include"lopcodes.h"#include"lparser.h"#include"lstring.h"#include"ltable.h"#include"lvm.h"/* Maximum number of registers in a Lua function (must fit in 8 bits) */#define MAXREGS 255#define hasjumps(e) ((e)->t != (e)->f)/*
** If expression is a numeric constant, fills 'v' with its value
** and returns 1. Otherwise, returns 0.
*/staticinttonumeral(const expdesc *e, TValue *v){if(hasjumps(e))return0;/* not a numeral */switch(e->k){case VKINT:if(v)setivalue(v, e->u.ival);return1;case VKFLT:if(v)setfltvalue(v, e->u.nval);return1;default:return0;}}/*
** Create a OP_LOADNIL instruction, but try to optimize: if the previous
** instruction is also OP_LOADNIL and ranges are compatible, adjust
** range of previous instruction instead of emitting a new one. (For
** instance, 'local a; local b' will generate a single opcode.)
*/void luaK_nil (FuncState *fs,int from,int n){
Instruction *previous;int l = from + n -1;/* last register to set nil */if(fs->pc > fs->lasttarget){/* no jumps to current position? */
previous =&fs->f->code[fs->pc-1];if(GET_OPCODE(*previous)== OP_LOADNIL){/* previous is LOADNIL? */int pfrom =GETARG_A(*previous);/* get previous range */int pl = pfrom +GETARG_B(*previous);if((pfrom <= from && from <= pl +1)||(from <= pfrom && pfrom <= l +1)){/* can connect both? */if(pfrom < from) from = pfrom;/* from = min(from, pfrom) */if(pl > l) l = pl;/* l = max(l, pl) */SETARG_A(*previous, from);SETARG_B(*previous, l - from);return;}}/* else go through */}luaK_codeABC(fs, OP_LOADNIL, from, n -1,0);/* else no optimization */}/*
** Gets the destination address of a jump instruction. Used to traverse
** a list of jumps.
*/staticint getjump (FuncState *fs,int pc){int offset =GETARG_sBx(fs->f->code[pc]);if(offset == NO_JUMP)/* point to itself represents end of list */return NO_JUMP;/* end of list */elsereturn(pc+1)+offset;/* turn offset into absolute position */}/*
** Fix jump instruction at position 'pc' to jump to 'dest'.
** (Jump addresses are relative in Lua)
*/staticvoid fixjump (FuncState *fs,int pc,int dest){
Instruction *jmp =&fs->f->code[pc];int offset = dest -(pc +1);lua_assert(dest != NO_JUMP);if(abs(offset)> MAXARG_sBx)luaX_syntaxerror(fs->ls,"control structure too long");SETARG_sBx(*jmp, offset);}/*
** Concatenate jump-list 'l2' into jump-list 'l1'
将跳转列表'l2'连接到跳转列表'l1'
*/void luaK_concat (FuncState *fs,int*l1,int l2){if(l2 == NO_JUMP)return;/* nothing to concatenate? */elseif(*l1 == NO_JUMP)/* no original list? */*l1 = l2;/* 'l1' points to 'l2' */else{int list =*l1;int next;while((next =getjump(fs, list))!= NO_JUMP)/* find last element */
list = next;fixjump(fs, list, l2);/* last element links to 'l2' */}}/*
** Create a jump instruction and return its position, so its destination
** can be fixed later (with 'fixjump'). If there are jumps to
** this position (kept in 'jpc'), link them all together so that
** 'patchlistaux' will fix all them directly to the final destination.
*/int luaK_jump (FuncState *fs){int jpc = fs->jpc;/* save list of jumps to here ,保存pc*/int j;
fs->jpc = NO_JUMP;/* no more jumps to here */
j =luaK_codeAsBx(fs, OP_JMP,0, NO_JUMP);luaK_concat(fs,&j, jpc);/* keep them on hold */return j;}/*
** Code a 'return' instruction
*/void luaK_ret (FuncState *fs,int first,int nret){luaK_codeABC(fs, OP_RETURN, first, nret+1,0);}/*
** Code a "conditional jump", that is, a test or comparison opcode
** followed by a jump. Return jump position.
*/staticint condjump (FuncState *fs, OpCode op,int A,int B,int C){luaK_codeABC(fs, op, A, B, C);returnluaK_jump(fs);}/*
** returns current 'pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
返回当前的pc和把它记录到下一个跳转的目标
*/int luaK_getlabel (FuncState *fs){
fs->lasttarget = fs->pc;return fs->pc;}/*
** Returns the position of the instruction "controlling" a given
** jump (that is, its condition), or the jump itself if it is
** unconditional.
*/static Instruction *getjumpcontrol (FuncState *fs,int pc){
Instruction *pi =&fs->f->code[pc];if(pc >=1&&testTMode(GET_OPCODE(*(pi-1))))return pi-1;elsereturn pi;}/*
** Patch destination register for a TESTSET instruction.
** If instruction in position 'node' is not a TESTSET, return 0 ("fails").
** Otherwise, if 'reg' is not 'NO_REG', set it as the destination
** register. Otherwise, change instruction to a simple 'TEST' (produces
** no register value)
*/staticint patchtestreg (FuncState *fs,int node,int reg){
Instruction *i =getjumpcontrol(fs, node);if(GET_OPCODE(*i)!= OP_TESTSET)return0;/* cannot patch other instructions */if(reg != NO_REG && reg !=GETARG_B(*i))SETARG_A(*i, reg);else{/* no register to put value or register already has the value;
change instruction to simple test */*i =CREATE_ABC(OP_TEST,GETARG_B(*i),0,GETARG_C(*i));}return1;}/*
** Traverse a list of tests ensuring no one produces a value
*/staticvoid removevalues (FuncState *fs,int list){for(; list != NO_JUMP; list =getjump(fs, list))patchtestreg(fs, list, NO_REG);}/*
** Traverse a list of tests, patching their destination address and
** registers: tests producing values jump to 'vtarget' (and put their
** values in 'reg'), other tests jump to 'dtarget'.
*/staticvoid patchlistaux (FuncState *fs,int list,int vtarget,int reg,int dtarget){while(list != NO_JUMP){int next =getjump(fs, list);if(patchtestreg(fs, list, reg))fixjump(fs, list, vtarget);elsefixjump(fs, list, dtarget);/* jump to default target */
list = next;}}/*
** Ensure all pending jumps to current position are fixed (jumping
** to current position with no values) and reset list of pending
** jumps
*/staticvoid dischargejpc (FuncState *fs){patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;}/*
** Add elements in 'list' to list of pending jumps to "here"
** (current position)
*/void luaK_patchtohere (FuncState *fs,int list){luaK_getlabel(fs);/* mark "here" as a jump target */luaK_concat(fs,&fs->jpc, list);}/*
** Path all jumps in 'list' to jump to 'target'.
** (The assert means that we cannot fix a jump to a forward address
** because we only know addresses once code is generated.)
*/void luaK_patchlist (FuncState *fs,int list,int target){if(target == fs->pc)/* 'target' is current position? */luaK_patchtohere(fs, list);/* add list to pending jumps */else{lua_assert(target < fs->pc);patchlistaux(fs, list, target, NO_REG, target);}}/*
** Path all jumps in 'list' to close upvalues up to given 'level'
** (The assertion checks that jumps either were closing nothing
** or were closing higher levels, from inner blocks.)
*/void luaK_patchclose (FuncState *fs,int list,int level){
level++;/* argument is +1 to reserve 0 as non-op */for(; list != NO_JUMP; list =getjump(fs, list)){lua_assert(GET_OPCODE(fs->f->code[list])== OP_JMP &&(GETARG_A(fs->f->code[list])==0||GETARG_A(fs->f->code[list])>= level));SETARG_A(fs->f->code[list], level);}}/*
** Emit instruction 'i', checking for array sizes and saving also its
** line information. Return 'i' position.
*/staticint luaK_code (FuncState *fs, Instruction i){
Proto *f = fs->f;dischargejpc(fs);/* 'pc' will change *//* put new instruction in code array */luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT,"opcodes");
f->code[fs->pc]= i;/* save corresponding line information */luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo,int,
MAX_INT,"opcodes");
f->lineinfo[fs->pc]= fs->ls->lastline;return fs->pc++;}/*
** Format and emit an 'iABC' instruction. (Assertions check consistency
** of parameters versus opcode.)
*/int luaK_codeABC (FuncState *fs, OpCode o,int a,int b,int c){lua_assert(getOpMode(o)== iABC);lua_assert(getBMode(o)!= OpArgN || b ==0);lua_assert(getCMode(o)!= OpArgN || c ==0);lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);returnluaK_code(fs,CREATE_ABC(o, a, b, c));}/*
** Format and emit an 'iABx' instruction.
*/int luaK_codeABx (FuncState *fs, OpCode o,int a,unsignedint bc){lua_assert(getOpMode(o)== iABx ||getOpMode(o)== iAsBx);lua_assert(getCMode(o)== OpArgN);lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);returnluaK_code(fs,CREATE_ABx(o, a, bc));}/*
** Emit an "extra argument" instruction (format 'iAx')
*/staticint codeextraarg (FuncState *fs,int a){lua_assert(a <= MAXARG_Ax);returnluaK_code(fs,CREATE_Ax(OP_EXTRAARG, a));}/*
** Emit a "load constant" instruction, using either 'OP_LOADK'
** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'
** instruction with "extra argument".
使用'OP_LOADK'(如果常量索引'k'适合18位)或带有“额外参数”的'OP_LOADKX'指令发出“加载常量”指令。
*/int luaK_codek (FuncState *fs,int reg,int k){if(k <= MAXARG_Bx)returnluaK_codeABx(fs, OP_LOADK, reg, k);else{int p =luaK_codeABx(fs, OP_LOADKX, reg,0);codeextraarg(fs, k);return p;}}/*
** Check register-stack level, keeping track of its maximum size
** in field 'maxstacksize'
*/void luaK_checkstack (FuncState *fs,int n){int newstack = fs->freereg + n;if(newstack > fs->f->maxstacksize){if(newstack >= MAXREGS)luaX_syntaxerror(fs->ls,"function or expression needs too many registers");
fs->f->maxstacksize =cast_byte(newstack);}}/*
** Reserve 'n' registers in register stack
*/void luaK_reserveregs (FuncState *fs,int n){luaK_checkstack(fs, n);
fs->freereg += n;}/*
** Free register 'reg', if it is neither a constant index nor
** a local variable.
)
*/staticvoid freereg (FuncState *fs,int reg){if(!ISK(reg)&& reg >= fs->nactvar){
fs->freereg--;lua_assert(reg == fs->freereg);}}/*
** Free register used by expression 'e' (if any)
*/staticvoid freeexp (FuncState *fs, expdesc *e){if(e->k == VNONRELOC)freereg(fs, e->u.info);}/*
** Free registers used by expressions 'e1' and 'e2' (if any) in proper
** order.
*/staticvoid freeexps (FuncState *fs, expdesc *e1, expdesc *e2){int r1 =(e1->k == VNONRELOC)? e1->u.info :-1;int r2 =(e2->k == VNONRELOC)? e2->u.info :-1;if(r1 > r2){freereg(fs, r1);freereg(fs, r2);}else{freereg(fs, r2);freereg(fs, r1);}}/*
** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list
** and try to reuse constants. Because some values should not be used
** as keys (nil cannot be a key, integer keys can collapse with float
** keys), the caller must provide a useful 'key' for indexing the cache.
*/staticint addk (FuncState *fs, TValue *key, TValue *v){
lua_State *L = fs->ls->L;
Proto *f = fs->f;
TValue *idx =luaH_set(L, fs->ls->h, key);/* index scanner table */int k, oldsize;if(ttisinteger(idx)){/* is there an index there? */
k =cast_int(ivalue(idx));/* correct value? (warning: must distinguish floats from integers!) */if(k < fs->nk &&ttype(&f->k[k])==ttype(v)&&luaV_rawequalobj(&f->k[k], v))return k;/* reuse index */}/* constant not found; create a new entry */
oldsize = f->sizek;
k = fs->nk;/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */setivalue(idx, k);luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax,"constants");while(oldsize < f->sizek)setnilvalue(&f->k[oldsize++]);setobj(L,&f->k[k], v);
fs->nk++;luaC_barrier(L, f, v);return k;}/*
** Add a string to list of constants and return its index.
*/int luaK_stringK (FuncState *fs, TString *s){
TValue o;setsvalue(fs->ls->L,&o, s);returnaddk(fs,&o,&o);/* use string itself as key */}/*
** Add an integer to list of constants and return its index.
** Integers use userdata as keys to avoid collision with floats with
** same value; conversion to 'void*' is used only for hashing, so there
** are no "precision" problems.
将一个整数添加到常量列表并返回其索引。
整数使用userdata作为键,以避免与浮动冲突相同的价值; 转换为'void *'仅用于散列,因此没有“精确”问题。
*/int luaK_intK (FuncState *fs, lua_Integer n){
TValue k, o;setpvalue(&k,cast(void*,cast(size_t, n)));setivalue(&o, n);returnaddk(fs,&k,&o);}/*
** Add a float to list of constants and return its index.
*/staticint luaK_numberK (FuncState *fs, lua_Number r){
TValue o;setfltvalue(&o, r);returnaddk(fs,&o,&o);/* use number itself as key */}/*
** Add a boolean to list of constants and return its index.
*/staticint boolK (FuncState *fs,int b){
TValue o;setbvalue(&o, b);returnaddk(fs,&o,&o);/* use boolean itself as key */}/*
** Add nil to list of constants and return its index.
*/staticint nilK (FuncState *fs){
TValue k, v;setnilvalue(&v);/* cannot use nil as key; instead use table itself to represent nil */sethvalue(fs->ls->L,&k, fs->ls->h);returnaddk(fs,&k,&v);}/*
** Fix an expression to return the number of results 'nresults'.
** Either 'e' is a multi-ret expression (function call or vararg)
** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
*/void luaK_setreturns (FuncState *fs, expdesc *e,int nresults){if(e->k == VCALL){/* expression is an open function call? */SETARG_C(getinstruction(fs, e), nresults +1);}elseif(e->k == VVARARG){
Instruction *pc =&getinstruction(fs, e);SETARG_B(*pc, nresults +1);SETARG_A(*pc, fs->freereg);luaK_reserveregs(fs,1);}elselua_assert(nresults == LUA_MULTRET);}/*
** Fix an expression to return one result.
** If expression is not a multi-ret expression (function call or
** vararg), it already returns one result, so nothing needs to be done.
** Function calls become VNONRELOC expressions (as its result comes
** fixed in the base register of the call), while vararg expressions
** become VRELOCABLE (as OP_VARARG puts its results where it wants).
** (Calls are created returning one result, so that does not need
** to be fixed.)
*/void luaK_setoneret (FuncState *fs, expdesc *e){if(e->k == VCALL){/* expression is an open function call? *//* already returns 1 value */lua_assert(GETARG_C(getinstruction(fs, e))==2);
e->k = VNONRELOC;/* result has fixed position */
e->u.info =GETARG_A(getinstruction(fs, e));}elseif(e->k == VVARARG){SETARG_B(getinstruction(fs, e),2);
e->k = VRELOCABLE;/* can relocate its simple result */}}/*
** Ensure that expression 'e' is not a variable.
*/void luaK_dischargevars (FuncState *fs, expdesc *e){switch(e->k){case VLOCAL:{/* already in a register */
e->k = VNONRELOC;/* becomes a non-relocatable value */break;}case VUPVAL:{/* move value to some (pending) register */
e->u.info =luaK_codeABC(fs, OP_GETUPVAL,0, e->u.info,0);
e->k = VRELOCABLE;break;}case VINDEXED:{
OpCode op;freereg(fs, e->u.ind.idx);if(e->u.ind.vt == VLOCAL){/* is 't' in a register? */freereg(fs, e->u.ind.t);
op = OP_GETTABLE;}else{lua_assert(e->u.ind.vt == VUPVAL);
op = OP_GETTABUP;/* 't' is in an upvalue */}
e->u.info =luaK_codeABC(fs, op,0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;break;}case VVARARG:case VCALL:{luaK_setoneret(fs, e);break;}default:break;/* there is one value available (somewhere) */}}/*
** Ensures expression value is in register 'reg' (and therefore
** 'e' will become a non-relocatable expression).
*/staticvoid discharge2reg (FuncState *fs, expdesc *e,int reg){luaK_dischargevars(fs, e);switch(e->k){case VNIL:{luaK_nil(fs, reg,1);break;}case VFALSE:case VTRUE:{luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE,0);break;}case VK:{luaK_codek(fs, reg, e->u.info);break;}case VKFLT:{luaK_codek(fs, reg,luaK_numberK(fs, e->u.nval));break;}case VKINT:{luaK_codek(fs, reg,luaK_intK(fs, e->u.ival));break;}case VRELOCABLE:{
Instruction *pc =&getinstruction(fs, e);SETARG_A(*pc, reg);/* instruction will put result in 'reg' */break;}case VNONRELOC:{if(reg != e->u.info)luaK_codeABC(fs, OP_MOVE, reg, e->u.info,0);break;}default:{lua_assert(e->k == VJMP);return;/* nothing to do... */}}
e->u.info = reg;
e->k = VNONRELOC;}/*
** Ensures expression value is in any register.
*/staticvoid discharge2anyreg (FuncState *fs, expdesc *e){if(e->k != VNONRELOC){/* no fixed register yet? */luaK_reserveregs(fs,1);/* get a register */discharge2reg(fs, e, fs->freereg-1);/* put value there */}}staticint code_loadbool (FuncState *fs,int A,int b,int jump){luaK_getlabel(fs);/* those instructions may be jump targets */returnluaK_codeABC(fs, OP_LOADBOOL, A, b, jump);}/*
** check whether list has any jump that do not produce a value
** or produce an inverted value
*/staticint need_value (FuncState *fs,int list){for(; list != NO_JUMP; list =getjump(fs, list)){
Instruction i =*getjumpcontrol(fs, list);if(GET_OPCODE(i)!= OP_TESTSET)return1;}return0;/* not found */}/*
** Ensures final expression result (including results from its jump
** lists) is in register 'reg'.
** If expression has jumps, need to patch these jumps either to
** its final position or to "load" instructions (for those tests
** that do not produce values).
*/staticvoid exp2reg (FuncState *fs, expdesc *e,int reg){discharge2reg(fs, e, reg);if(e->k == VJMP)/* expression itself is a test? */luaK_concat(fs,&e->t, e->u.info);/* put this jump in 't' list */if(hasjumps(e)){int final;/* position after whole expression */int p_f = NO_JUMP;/* position of an eventual LOAD false */int p_t = NO_JUMP;/* position of an eventual LOAD true */if(need_value(fs, e->t)||need_value(fs, e->f)){int fj =(e->k == VJMP)? NO_JUMP :luaK_jump(fs);
p_f =code_loadbool(fs, reg,0,1);
p_t =code_loadbool(fs, reg,1,0);luaK_patchtohere(fs, fj);}
final =luaK_getlabel(fs);patchlistaux(fs, e->f, final, reg, p_f);patchlistaux(fs, e->t, final, reg, p_t);}
e->f = e->t = NO_JUMP;
e->u.info = reg;
e->k = VNONRELOC;}/*
** Ensures final expression result (including results from its jump
** lists) is in next available register.
*/void luaK_exp2nextreg (FuncState *fs, expdesc *e){luaK_dischargevars(fs, e);freeexp(fs, e);luaK_reserveregs(fs,1);exp2reg(fs, e, fs->freereg -1);}/*
** Ensures final expression result (including results from its jump
** lists) is in some (any) register and return that register.
*/int luaK_exp2anyreg (FuncState *fs, expdesc *e){luaK_dischargevars(fs, e);if(e->k == VNONRELOC){/* expression already has a register? */if(!hasjumps(e))/* no jumps? */return e->u.info;/* result is already in a register */if(e->u.info >= fs->nactvar){/* reg. is not a local? */exp2reg(fs, e, e->u.info);/* put final result in it */return e->u.info;}}luaK_exp2nextreg(fs, e);/* otherwise, use next available register */return e->u.info;}/*
** Ensures final expression result is either in a register or in an
** upvalue.
*/void luaK_exp2anyregup (FuncState *fs, expdesc *e){if(e->k != VUPVAL ||hasjumps(e))luaK_exp2anyreg(fs, e);}/*
** Ensures final expression result is either in a register or it is
** a constant.
*/void luaK_exp2val (FuncState *fs, expdesc *e){if(hasjumps(e))luaK_exp2anyreg(fs, e);elseluaK_dischargevars(fs, e);}/*
** Ensures final expression result is in a valid R/K index
** (that is, it is either in a register or in 'k' with an index
** in the range of R/K indices).
** Returns R/K index.
*/int luaK_exp2RK (FuncState *fs, expdesc *e){luaK_exp2val(fs, e);switch(e->k){/* move constants to 'k' */case VTRUE: e->u.info =boolK(fs,1);goto vk;case VFALSE: e->u.info =boolK(fs,0);goto vk;case VNIL: e->u.info =nilK(fs);goto vk;case VKINT: e->u.info =luaK_intK(fs, e->u.ival);goto vk;case VKFLT: e->u.info =luaK_numberK(fs, e->u.nval);goto vk;case VK:
vk:
e->k = VK;if(e->u.info <= MAXINDEXRK)/* constant fits in 'argC'? */returnRKASK(e->u.info);elsebreak;default:break;}/* not a constant in the right range: put it in a register */returnluaK_exp2anyreg(fs, e);}/*
** Generate code to store result of expression 'ex' into variable 'var'.
*/void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex){switch(var->k){case VLOCAL:{freeexp(fs, ex);exp2reg(fs, ex, var->u.info);/* compute 'ex' into proper place */return;}case VUPVAL:{int e =luaK_exp2anyreg(fs, ex);luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info,0);break;}case VINDEXED:{
OpCode op =(var->u.ind.vt == VLOCAL)? OP_SETTABLE : OP_SETTABUP;int e =luaK_exp2RK(fs, ex);luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);break;}default:lua_assert(0);/* invalid var kind to store */}freeexp(fs, ex);}/*
** Emit SELF instruction (convert expression 'e' into 'e:key(e,').
*/void luaK_self (FuncState *fs, expdesc *e, expdesc *key){int ereg;luaK_exp2anyreg(fs, e);
ereg = e->u.info;/* register where 'e' was placed */freeexp(fs, e);
e->u.info = fs->freereg;/* base register for op_self */
e->k = VNONRELOC;/* self expression has a fixed register */luaK_reserveregs(fs,2);/* function and 'self' produced by op_self */luaK_codeABC(fs, OP_SELF, e->u.info, ereg,luaK_exp2RK(fs, key));freeexp(fs, key);}/*
** Negate condition 'e' (where 'e' is a comparison).
*/staticvoid negatecondition (FuncState *fs, expdesc *e){
Instruction *pc =getjumpcontrol(fs, e->u.info);lua_assert(testTMode(GET_OPCODE(*pc))&&GET_OPCODE(*pc)!= OP_TESTSET &&GET_OPCODE(*pc)!= OP_TEST);SETARG_A(*pc,!(GETARG_A(*pc)));}/*
** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'
** is true, code will jump if 'e' is true.) Return jump position.
** Optimize when 'e' is 'not' something, inverting the condition
** and removing the 'not'.
*/staticint jumponcond (FuncState *fs, expdesc *e,int cond){if(e->k == VRELOCABLE){
Instruction ie =getinstruction(fs, e);if(GET_OPCODE(ie)== OP_NOT){
fs->pc--;/* remove previous OP_NOT */returncondjump(fs, OP_TEST,GETARG_B(ie),0,!cond);}/* else go through */}discharge2anyreg(fs, e);freeexp(fs, e);returncondjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);}/*
** Emit code to go through if 'e' is true, jump otherwise.
*/void luaK_goiftrue (FuncState *fs, expdesc *e){int pc;/* pc of new jump */luaK_dischargevars(fs, e);switch(e->k){case VJMP:{/* condition? */negatecondition(fs, e);/* jump when it is false */
pc = e->u.info;/* save jump position */break;}case VK:case VKFLT:case VKINT:case VTRUE:{
pc = NO_JUMP;/* always true; do nothing */break;}default:{
pc =jumponcond(fs, e,0);/* jump when false */break;}}luaK_concat(fs,&e->f, pc);/* insert new jump in false list */luaK_patchtohere(fs, e->t);/* true list jumps to here (to go through) */
e->t = NO_JUMP;}/*
** Emit code to go through if 'e' is false, jump otherwise.
如果“e”为假则发出代码,否则跳转。
*/void luaK_goiffalse (FuncState *fs, expdesc *e){int pc;/* pc of new jump */luaK_dischargevars(fs, e);switch(e->k){case VJMP:{
pc = e->u.info;/* already jump if true */break;}case VNIL:case VFALSE:{
pc = NO_JUMP;/* always false; do nothing */break;}default:{
pc =jumponcond(fs, e,1);/* jump if true */break;}}luaK_concat(fs,&e->t, pc);/* insert new jump in 't' list */luaK_patchtohere(fs, e->f);/* false list jumps to here (to go through) */
e->f = NO_JUMP;}/*
** Code 'not e', doing constant folding.
*/staticvoid codenot (FuncState *fs, expdesc *e){luaK_dischargevars(fs, e);switch(e->k){case VNIL:case VFALSE:{
e->k = VTRUE;/* true == not nil == not false */break;}case VK:case VKFLT:case VKINT:case VTRUE:{
e->k = VFALSE;/* false == not "x" == not 0.5 == not 1 == not true */break;}case VJMP:{negatecondition(fs, e);break;}case VRELOCABLE:case VNONRELOC:{discharge2anyreg(fs, e);freeexp(fs, e);
e->u.info =luaK_codeABC(fs, OP_NOT,0, e->u.info,0);
e->k = VRELOCABLE;break;}default:lua_assert(0);/* cannot happen */}/* interchange true and false lists */{int temp = e->f; e->f = e->t; e->t = temp;}removevalues(fs, e->f);/* values are useless when negated */removevalues(fs, e->t);}/*
** Create expression 't[k]'. 't' must have its final result already in a
** register or upvalue.
*/void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k){lua_assert(!hasjumps(t)&&(vkisinreg(t->k)|| t->k == VUPVAL));
t->u.ind.t = t->u.info;/* register or upvalue index */
t->u.ind.idx =luaK_exp2RK(fs, k);/* R/K index for key */
t->u.ind.vt =(t->k == VUPVAL)? VUPVAL : VLOCAL;
t->k = VINDEXED;}/*
** Return false if folding can raise an error.
** Bitwise operations need operands convertible to integers; division
** operations cannot have 0 as divisor.
*/staticint validop (int op, TValue *v1, TValue *v2){switch(op){case LUA_OPBAND:case LUA_OPBOR:case LUA_OPBXOR:case LUA_OPSHL:case LUA_OPSHR:case LUA_OPBNOT:{/* conversion errors */
lua_Integer i;return(tointeger(v1,&i)&&tointeger(v2,&i));}case LUA_OPDIV:case LUA_OPIDIV:case LUA_OPMOD:/* division by 0 */return(nvalue(v2)!=0);default:return1;/* everything else is valid */}}/*
** Try to "constant-fold" an operation; return 1 iff successful.
** (In this case, 'e1' has the final result.)
*/staticint constfolding (FuncState *fs,int op, expdesc *e1,const expdesc *e2){
TValue v1, v2, res;if(!tonumeral(e1,&v1)||!tonumeral(e2,&v2)||!validop(op,&v1,&v2))return0;/* non-numeric operands or not safe to fold */luaO_arith(fs->ls->L, op,&v1,&v2,&res);/* does operation */if(ttisinteger(&res)){
e1->k = VKINT;
e1->u.ival =ivalue(&res);}else{/* folds neither NaN nor 0.0 (to avoid problems with -0.0) */
lua_Number n =fltvalue(&res);if(luai_numisnan(n)|| n ==0)return0;
e1->k = VKFLT;
e1->u.nval = n;}return1;}/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
** Expression to produce final result will be encoded in 'e'.
*/staticvoid codeunexpval (FuncState *fs, OpCode op, expdesc *e,int line){int r =luaK_exp2anyreg(fs, e);/* opcodes operate only on registers */freeexp(fs, e);
e->u.info =luaK_codeABC(fs, op,0, r,0);/* generate opcode */
e->k = VRELOCABLE;/* all those operations are relocatable */luaK_fixline(fs, line);}/*
** Emit code for binary expressions that "produce values"
** (everything but logical operators 'and'/'or' and comparison
** operators).
** Expression to produce final result will be encoded in 'e1'.
** Because 'luaK_exp2RK' can free registers, its calls must be
** in "stack order" (that is, first on 'e2', which may have more
** recent registers to be released).
*/staticvoid codebinexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2,int line){int rk2 =luaK_exp2RK(fs, e2);/* both operands are "RK" */int rk1 =luaK_exp2RK(fs, e1);freeexps(fs, e1, e2);
e1->u.info =luaK_codeABC(fs, op,0, rk1, rk2);/* generate opcode */
e1->k = VRELOCABLE;/* all those operations are relocatable */luaK_fixline(fs, line);}/*
** Emit code for comparisons.
** 'e1' was already put in R/K form by 'luaK_infix'.
*/staticvoid codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2){int rk1 =(e1->k == VK)?RKASK(e1->u.info):check_exp(e1->k == VNONRELOC, e1->u.info);int rk2 =luaK_exp2RK(fs, e2);freeexps(fs, e1, e2);switch(opr){case OPR_NE:{/* '(a ~= b)' ==> 'not (a == b)' */
e1->u.info =condjump(fs, OP_EQ,0, rk1, rk2);break;}case OPR_GT:case OPR_GE:{/* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
OpCode op =cast(OpCode,(opr - OPR_NE)+ OP_EQ);
e1->u.info =condjump(fs, op,1, rk2, rk1);/* invert operands */break;}default:{/* '==', '<', '<=' use their own opcodes */
OpCode op =cast(OpCode,(opr - OPR_EQ)+ OP_EQ);
e1->u.info =condjump(fs, op,1, rk1, rk2);break;}}
e1->k = VJMP;}/*
** Aplly prefix operation 'op' to expression 'e'.
*/void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e,int line){staticconst expdesc ef ={VKINT,{0}, NO_JUMP, NO_JUMP};switch(op){case OPR_MINUS:case OPR_BNOT:/* use 'ef' as fake 2nd operand */if(constfolding(fs, op + LUA_OPUNM, e,&ef))break;/* FALLTHROUGH */case OPR_LEN:codeunexpval(fs,cast(OpCode, op + OP_UNM), e, line);break;case OPR_NOT:codenot(fs, e);break;default:lua_assert(0);}}/*
** Process 1st operand 'v' of binary operation 'op' before reading
** 2nd operand.
*/void luaK_infix (FuncState *fs, BinOpr op, expdesc *v){switch(op){case OPR_AND:{luaK_goiftrue(fs, v);/* go ahead only if 'v' is true */break;}case OPR_OR:{luaK_goiffalse(fs, v);/* go ahead only if 'v' is false */break;}case OPR_CONCAT:{luaK_exp2nextreg(fs, v);/* operand must be on the 'stack' */break;}case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV:case OPR_IDIV:case OPR_MOD:case OPR_POW:case OPR_BAND:case OPR_BOR:case OPR_BXOR:case OPR_SHL:case OPR_SHR:{if(!tonumeral(v,NULL))luaK_exp2RK(fs, v);/* else keep numeral, which may be folded with 2nd operand */break;}default:{luaK_exp2RK(fs, v);break;}}}/*
** Finalize code for binary operation, after reading 2nd operand.
** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
** concatenation is right associative), merge second CONCAT into first
** one.
*/void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2,int line){switch(op){case OPR_AND:{lua_assert(e1->t == NO_JUMP);/* list closed by 'luK_infix' */luaK_dischargevars(fs, e2);luaK_concat(fs,&e2->f, e1->f);*e1 =*e2;break;}case OPR_OR:{lua_assert(e1->f == NO_JUMP);/* list closed by 'luK_infix' */luaK_dischargevars(fs, e2);luaK_concat(fs,&e2->t, e1->t);*e1 =*e2;break;}case OPR_CONCAT:{luaK_exp2val(fs, e2);if(e2->k == VRELOCABLE &&GET_OPCODE(getinstruction(fs, e2))== OP_CONCAT){lua_assert(e1->u.info ==GETARG_B(getinstruction(fs, e2))-1);freeexp(fs, e1);SETARG_B(getinstruction(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;}else{luaK_exp2nextreg(fs, e2);/* operand must be on the 'stack' */codebinexpval(fs, OP_CONCAT, e1, e2, line);}break;}case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV:case OPR_IDIV:case OPR_MOD:case OPR_POW:case OPR_BAND:case OPR_BOR:case OPR_BXOR:case OPR_SHL:case OPR_SHR:{if(!constfolding(fs, op + LUA_OPADD, e1, e2))codebinexpval(fs,cast(OpCode, op + OP_ADD), e1, e2, line);break;}case OPR_EQ:case OPR_LT:case OPR_LE:case OPR_NE:case OPR_GT:case OPR_GE:{codecomp(fs, op, e1, e2);break;}default:lua_assert(0);}}/*
** Change line information associated with current position.
*/void luaK_fixline (FuncState *fs,int line){
fs->f->lineinfo[fs->pc -1]= line;}/*
** Emit a SETLIST instruction.
** 'base' is register that keeps table;
** 'nelems' is #table plus those to be stored now;
** 'tostore' is number of values (in registers 'base + 1',...) to add to
** table (or LUA_MULTRET to add up to stack top).
*/void luaK_setlist (FuncState *fs,int base,int nelems,int tostore){int c =(nelems -1)/LFIELDS_PER_FLUSH +1;int b =(tostore == LUA_MULTRET)?0: tostore;lua_assert(tostore !=0&& tostore <= LFIELDS_PER_FLUSH);if(c <= MAXARG_C)luaK_codeABC(fs, OP_SETLIST, base, b, c);elseif(c <= MAXARG_Ax){luaK_codeABC(fs, OP_SETLIST, base, b,0);codeextraarg(fs, c);}elseluaX_syntaxerror(fs->ls,"constructor too long");
fs->freereg = base +1;/* free registers with list values */}
llex.c
/*
** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/#define llex_c#define LUA_CORE#include"lprefix.h"#include<locale.h>#include<string.h>#include"lua.h"#include"lctype.h"#include"ldebug.h"//#include "ldo.h"//#include "lgc.h"#include"llex.h"#include"lobject.h"#include"lparser.h"//state类型#include"lstate.h"//类型#include"lstring.h"//字符串处理函数#include"ltable.h"//luaH lua hash#include"lzio.h"//zio#define next(ls) (ls->current = zgetc(ls->z))#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')/* ORDER RESERVED */staticconstchar*const luaX_tokens []={"and","break","do","else","elseif","end","false","for","function","goto","if","in","local","nil","not","or","repeat","return","then","true","until","while","//","..","...","==",">=","<=","~=","<<",">>","::","<eof>","<number>","<integer>","<name>","<string>"};#define save_and_next(ls) (save(ls, ls->current), next(ls))static l_noret lexerror (LexState *ls,constchar*msg,int token);staticvoid save (LexState *ls,int c){
Mbuffer *b = ls->buff;if(luaZ_bufflen(b)+1>luaZ_sizebuffer(b)){
size_t newsize;if(luaZ_sizebuffer(b)>= MAX_SIZE/2)lexerror(ls,"lexical element too long",0);
newsize =luaZ_sizebuffer(b)*2;luaZ_resizebuffer(ls->L, b, newsize);}
b->buffer[luaZ_bufflen(b)++]=cast(char, c);}void luaX_init (lua_State *L){int i;
TString *e =luaS_newliteral(L, LUA_ENV);/* create env name *///luaC_fix(L, obj2gco(e)); /* never collect this name */for(i=0; i<NUM_RESERVED; i++){
TString *ts =luaS_new(L, luaX_tokens[i]);//luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */
ts->extra =cast_byte(i+1);/* reserved word */}}constchar*luaX_token2str (LexState *ls,int token){if(token < FIRST_RESERVED){/* single-byte symbols? */lua_assert(token ==cast_uchar(token));returnluaO_pushfstring(ls->L,"'%c'", token);}else{constchar*s = luaX_tokens[token - FIRST_RESERVED];if(token < TK_EOS)/* fixed format (symbols and reserved words)? */returnluaO_pushfstring(ls->L,"'%s'", s);else/* names, strings, and numerals */return s;}}staticconstchar*txtToken (LexState *ls,int token){switch(token){case TK_NAME:case TK_STRING:case TK_FLT:case TK_INT:save(ls,'\0');returnluaO_pushfstring(ls->L,"'%s'",luaZ_buffer(ls->buff));default:returnluaX_token2str(ls, token);}}static l_noret lexerror (LexState *ls,constchar*msg,int token){
msg =luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);if(token)luaO_pushfstring(ls->L,"%s near %s", msg,txtToken(ls, token));//luaD_throw(ls->L, LUA_ERRSYNTAX);}
l_noret luaX_syntaxerror (LexState *ls,constchar*msg){lexerror(ls, msg, ls->t.token);}/*
** creates a new string and anchors it in scanner's table so that
** it will not be collected until the end of the compilation
** (by that time it should be anchored somewhere)
*/
TString *luaX_newstring (LexState *ls,constchar*str, size_t l){
lua_State *L = ls->L;
TValue *o;/* entry for 'str' */
TString *ts =luaS_newlstr(L, str, l);/* create new string */setsvalue2s(L, L->top++, ts);/* temporarily anchor it in stack */
o =luaH_set(L, ls->h, L->top -1);if(ttisnil(o)){/* not in use yet? *//* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */setbvalue(o,1);/* t[string] = true *///luaC_checkGC(L);}else{/* string already present */
ts =tsvalue(keyfromval(o));/* re-use value previously stored */}
L->top--;/* remove string from stack */return ts;}/*
** increment line number and skips newline sequence (any of
** \n, \r, \n\r, or \r\n)
*/staticvoid inclinenumber (LexState *ls){int old = ls->current;lua_assert(currIsNewline(ls));next(ls);/* skip '\n' or '\r' */if(currIsNewline(ls)&& ls->current != old)next(ls);/* skip '\n\r' or '\r\n' */if(++ls->linenumber >= MAX_INT)lexerror(ls,"chunk has too many lines",0);}void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,int firstchar){
ls->t.token =0;
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS;/* no look-ahead token */
ls->z = z;
ls->fs =NULL;
ls->linenumber =1;
ls->lastline =1;
ls->source = source;
ls->envn =luaS_newliteral(L, LUA_ENV);/* get env name */luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);/* initialize buffer */}/*
** =======================================================
** LEXICAL ANALYZER
** =======================================================
*/staticint check_next1 (LexState *ls,int c){if(ls->current == c){next(ls);return1;}elsereturn0;}/*
** Check whether current char is in set 'set' (with two chars) and
** saves it
*/staticint check_next2 (LexState *ls,constchar*set){lua_assert(set[2]=='\0');if(ls->current == set[0]|| ls->current == set[1]){save_and_next(ls);return1;}elsereturn0;}/* LUA_NUMBER *//*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
** will reject ill-formed numerals.
*/staticint read_numeral (LexState *ls, SemInfo *seminfo){
TValue obj;constchar*expo ="Ee";int first = ls->current;lua_assert(lisdigit(ls->current));save_and_next(ls);if(first =='0'&&check_next2(ls,"xX"))/* hexadecimal? */
expo ="Pp";for(;;){if(check_next2(ls, expo))/* exponent part? */check_next2(ls,"-+");/* optional exponent sign */if(lisxdigit(ls->current))save_and_next(ls);elseif(ls->current =='.')save_and_next(ls);elsebreak;}save(ls,'\0');if(luaO_str2num(luaZ_buffer(ls->buff),&obj)==0)/* format error? */lexerror(ls,"malformed number", TK_FLT);if(ttisinteger(&obj)){
seminfo->i =ivalue(&obj);return TK_INT;}else{lua_assert(ttisfloat(&obj));
seminfo->r =fltvalue(&obj);return TK_FLT;}}/*
** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
** its number of '='s; otherwise, return a negative number (-1 iff there
** are no '='s after initial bracket)
*/staticint skip_sep (LexState *ls){int count =0;int s = ls->current;lua_assert(s =='['|| s ==']');save_and_next(ls);while(ls->current =='='){save_and_next(ls);
count++;}return(ls->current == s)? count :(-count)-1;}staticvoid read_long_string (LexState *ls, SemInfo *seminfo,int sep){int line = ls->linenumber;/* initial line (for error message) */save_and_next(ls);/* skip 2nd '[' */if(currIsNewline(ls))/* string starts with a newline? */inclinenumber(ls);/* skip it */for(;;){switch(ls->current){case EOZ:{/* error */constchar*what =(seminfo ?"string":"comment");constchar*msg =luaO_pushfstring(ls->L,"unfinished long %s (starting at line %d)", what, line);lexerror(ls, msg, TK_EOS);break;/* to avoid warnings */}case']':{if(skip_sep(ls)== sep){save_and_next(ls);/* skip 2nd ']' */goto endloop;}break;}case'\n':case'\r':{save(ls,'\n');inclinenumber(ls);if(!seminfo)luaZ_resetbuffer(ls->buff);/* avoid wasting space */break;}default:{if(seminfo)save_and_next(ls);elsenext(ls);}}} endloop:if(seminfo)
seminfo->ts =luaX_newstring(ls,luaZ_buffer(ls->buff)+(2+ sep),luaZ_bufflen(ls->buff)-2*(2+ sep));}staticvoid esccheck (LexState *ls,int c,constchar*msg){if(!c){if(ls->current != EOZ)save_and_next(ls);/* add current to buffer for error message */lexerror(ls, msg, TK_STRING);}}staticint gethexa (LexState *ls){save_and_next(ls);
esccheck (ls,lisxdigit(ls->current),"hexadecimal digit expected");returnluaO_hexavalue(ls->current);}staticint readhexaesc (LexState *ls){int r =gethexa(ls);
r =(r <<4)+gethexa(ls);luaZ_buffremove(ls->buff,2);/* remove saved chars from buffer */return r;}staticunsignedlong readutf8esc (LexState *ls){unsignedlong r;int i =4;/* chars to be removed: '\', 'u', '{', and first digit */save_and_next(ls);/* skip 'u' */esccheck(ls, ls->current =='{',"missing '{'");
r =gethexa(ls);/* must have at least one digit */while((save_and_next(ls),lisxdigit(ls->current))){
i++;
r =(r <<4)+luaO_hexavalue(ls->current);esccheck(ls, r <=0x10FFFF,"UTF-8 value too large");}esccheck(ls, ls->current =='}',"missing '}'");next(ls);/* skip '}' */luaZ_buffremove(ls->buff, i);/* remove saved chars from buffer */return r;}staticvoid utf8esc (LexState *ls){char buff[UTF8BUFFSZ];int n =luaO_utf8esc(buff,readutf8esc(ls));for(; n >0; n--)/* add 'buff' to string */save(ls, buff[UTF8BUFFSZ - n]);}staticint readdecesc (LexState *ls){int i;int r =0;/* result accumulator */for(i =0; i <3&&lisdigit(ls->current); i++){/* read up to 3 digits */
r =10*r + ls->current -'0';save_and_next(ls);}esccheck(ls, r <= UCHAR_MAX,"decimal escape too large");luaZ_buffremove(ls->buff, i);/* remove read digits from buffer */return r;}staticvoid read_string (LexState *ls,int del, SemInfo *seminfo){save_and_next(ls);/* keep delimiter (for error messages) */while(ls->current != del){switch(ls->current){case EOZ:lexerror(ls,"unfinished string", TK_EOS);break;/* to avoid warnings */case'\n':case'\r':lexerror(ls,"unfinished string", TK_STRING);break;/* to avoid warnings */case'\\':{/* escape sequences */int c;/* final character to be saved */save_and_next(ls);/* keep '\\' for error messages */switch(ls->current){case'a': c ='\a';goto read_save;case'b': c ='\b';goto read_save;case'f': c ='\f';goto read_save;case'n': c ='\n';goto read_save;case'r': c ='\r';goto read_save;case't': c ='\t';goto read_save;case'v': c ='\v';goto read_save;case'x': c =readhexaesc(ls);goto read_save;case'u':utf8esc(ls);goto no_save;case'\n':case'\r':inclinenumber(ls); c ='\n';goto only_save;case'\\':case'\"':case'\'':
c = ls->current;goto read_save;case EOZ:goto no_save;/* will raise an error next loop */case'z':{/* zap following span of spaces */luaZ_buffremove(ls->buff,1);/* remove '\\' */next(ls);/* skip the 'z' */while(lisspace(ls->current)){if(currIsNewline(ls))inclinenumber(ls);elsenext(ls);}goto no_save;}default:{esccheck(ls,lisdigit(ls->current),"invalid escape sequence");
c =readdecesc(ls);/* digital escape '\ddd' */goto only_save;}}
read_save:next(ls);/* go through */
only_save:luaZ_buffremove(ls->buff,1);/* remove '\\' */save(ls, c);/* go through */
no_save:break;}default:save_and_next(ls);}}save_and_next(ls);/* skip delimiter */
seminfo->ts =luaX_newstring(ls,luaZ_buffer(ls->buff)+1,luaZ_bufflen(ls->buff)-2);}staticint llex (LexState *ls, SemInfo *seminfo){luaZ_resetbuffer(ls->buff);for(;;){switch(ls->current){case'\n':case'\r':{/* line breaks */inclinenumber(ls);//如果是hang的结束位置就跳到下一行break;}case' ':case'\f':case'\t':case'\v':{/* spaces */next(ls);//如果是无意义的字符就跳过break;}case'-':{/* '-' or '--' (comment) */next(ls);//识别到-,处理注释。if(ls->current !='-')return'-';//如果不是注释就返回-/* else is a comment ,这是个注释字符串*/next(ls);//跳过第二个-if(ls->current =='['){/* long comment? 判断是不是长注释*/int sep =skip_sep(ls);//lua支持--[=== 123 ===],这里跳过并且获取等号的个数luaZ_resetbuffer(ls->buff);/* 'skip_sep' may dirty the buffer 重置一下buff,skip_sep有可能会污染buff*/if(sep >=0){read_long_string(ls,NULL, sep);/* skip long comment ,跳过长注释*/luaZ_resetbuffer(ls->buff);/* previous call may dirty the buff. 重置一下buff */break;}}/* else short comment */while(!currIsNewline(ls)&& ls->current != EOZ)//如果是短注释直接跳过当前行next(ls);/* skip until end of line (or end of file) */break;}case'[':{/* long string or simply '[' */int sep =skip_sep(ls);//跳过等号并返回等号个数if(sep >=0){read_long_string(ls, seminfo, sep);//读取长字符串并返回TK_STRING,告诉上一层这是一个字符串return TK_STRING;}elseif(sep !=-1)/* '[=...' missing second bracket ,如果下一个还是[则显示错误*/lexerror(ls,"invalid long string delimiter", TK_STRING);return'[';//返回[符号}case'=':{next(ls);if(check_next1(ls,'='))return TK_EQ;//判断下一个是不是等号,如果是的话就是判断elsereturn'=';//不是的话就是赋值}case'<':{next(ls);if(check_next1(ls,'='))return TK_LE;//判断下一个是不是等号,是的话就是小于或等于elseif(check_next1(ls,'<'))return TK_SHL;//判断下一个是不是<,是的话就是左移elsereturn'<';//都不是的话就是小于}case'>':{next(ls);if(check_next1(ls,'='))return TK_GE;//判断下一个是不是等号,是的话就是大于或等于elseif(check_next1(ls,'>'))return TK_SHR;//判断下一个是不是>,是的话就是右移elsereturn'>';}case'/':{next(ls);if(check_next1(ls,'/'))return TK_IDIV;//判断下一个是不是/,是的话就是idiv,LUA_OPIDIV: performs floor division (//)elsereturn'/';}case'~':{next(ls);if(check_next1(ls,'='))return TK_NE;//判断下一个是不是等号,是的话就是不等于elsereturn'~';//返回~}case':':{next(ls);if(check_next1(ls,':'))return TK_DBCOLON;//对于一个句柄的操作elsereturn':';}case'"':case'\'':{/* short literal strings 短字符串*/read_string(ls, ls->current, seminfo);//获取短字符串return TK_STRING;//返回这是字符串}case'.':{/* '.', '..', '...', or number 有可能是包的.,字符串连接符,不定参数和小数点*/save_and_next(ls);//保存并下一个if(check_next1(ls,'.')){//如果第二个是点,也就是这可能是字符串连接符或者是不定参数if(check_next1(ls,'.'))//如果第三个是点,这是不定参数return TK_DOTS;/* '...' 返回上层告诉这是不定参数*/elsereturn TK_CONCAT;/* '..' 返回上层告诉这是字符串连接符*/}elseif(!lisdigit(ls->current))return'.';//如果下一个不是数字,这是包操作点elsereturnread_numeral(ls, seminfo);//这是小数点,读取并解析返回后面的值}case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':{returnread_numeral(ls, seminfo);//读取到数字就读取并解析返回数值}case EOZ:{//如果这是文件的结尾return TK_EOS;//告诉上次层,解析结束}default:{if(lislalpha(ls->current)){/*lislalpha is lua is alphabetic,判断是不是字母 identifier or reserved word? 这是标识符还是保留字*/
TString *ts;do{save_and_next(ls);}while(lislalnum(ls->current));//lislalnum is lua is alphanumeric,判断是不是字母或数字
ts =luaX_newstring(ls,luaZ_buffer(ls->buff),luaZ_bufflen(ls->buff));//新建一个字符串
seminfo->ts = ts;if(isreserved(ts))/* reserved word? 这是保留字*/return ts->extra -1+ FIRST_RESERVED;//返回保留字else{return TK_NAME;//这是个标示符}}else{/* single-char tokens (+ - / ...) 这是简单的单词,例如+ - /等等*/int c = ls->current;next(ls);return c;//返回当前字符}}}}}void luaX_next (LexState *ls){
ls->lastline = ls->linenumber;if(ls->lookahead.token != TK_EOS){/* is there a look-ahead token? */
ls->t = ls->lookahead;/* use this one */
ls->lookahead.token = TK_EOS;/* and discharge it */}else
ls->t.token =llex(ls,&ls->t.seminfo);/* read next token */}int luaX_lookahead (LexState *ls){lua_assert(ls->lookahead.token == TK_EOS);
ls->lookahead.token =llex(ls,&ls->lookahead.seminfo);return ls->lookahead.token;}
lparser.c
/*
** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/#define lparser_c#define LUA_CORE#include"lprefix.h"#include<string.h>#include"lua.h"#include"lcode.h"#include"ldebug.h"#include"ldo.h"#include"lfunc.h"#include"llex.h"#include"lmem.h"#include"lobject.h"#include"lopcodes.h"#include"lparser.h"#include"lstate.h"#include"lstring.h"#include"ltable.h"/* maximum number of local variables per function (must be smaller
than 250, due to the bytecode format) */#define MAXVARS 200#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)/* because all strings are unified by the scanner, the parser
can use pointer equality for string equality */#define eqstr(a,b) ((a) == (b))/*
** nodes for block list (list of active blocks)
*/typedefstruct BlockCnt {struct BlockCnt *previous;/* chain */int firstlabel;/* index of first label in this block */int firstgoto;/* index of first pending goto in this block */
lu_byte nactvar;/* # active locals outside the block */
lu_byte upval;/* true if some variable in the block is an upvalue */
lu_byte isloop;/* true if 'block' is a loop */} BlockCnt;/*
** prototypes for recursive non-terminal functions
*/staticvoid statement (LexState *ls);staticvoid expr (LexState *ls, expdesc *v);/* semantic error */static l_noret semerror (LexState *ls,constchar*msg){
ls->t.token =0;/* remove "near <token>" from final message */luaX_syntaxerror(ls, msg);}static l_noret error_expected (LexState *ls,int token){luaX_syntaxerror(ls,luaO_pushfstring(ls->L,"%s expected",luaX_token2str(ls, token)));}static l_noret errorlimit (FuncState *fs,int limit,constchar*what){
lua_State *L = fs->ls->L;constchar*msg;int line = fs->f->linedefined;constchar*where =(line ==0)?"main function":luaO_pushfstring(L,"function at line %d", line);
msg =luaO_pushfstring(L,"too many %s (limit is %d) in %s",
what, limit, where);luaX_syntaxerror(fs->ls, msg);}staticvoid checklimit (FuncState *fs,int v,int l,constchar*what){if(v > l)errorlimit(fs, l, what);}staticint testnext (LexState *ls,int c){if(ls->t.token == c){luaX_next(ls);return1;}elsereturn0;}staticvoid check (LexState *ls,int c){if(ls->t.token != c)error_expected(ls, c);}staticvoid checknext (LexState *ls,int c){check(ls, c);luaX_next(ls);}#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); }staticvoid check_match (LexState *ls,int what,int who,int where){if(!testnext(ls, what)){if(where == ls->linenumber)error_expected(ls, what);else{luaX_syntaxerror(ls,luaO_pushfstring(ls->L,"%s expected (to close %s at line %d)",luaX_token2str(ls, what),luaX_token2str(ls, who), where));}}}static TString *str_checkname (LexState *ls){
TString *ts;check(ls, TK_NAME);
ts = ls->t.seminfo.ts;luaX_next(ls);return ts;}staticvoid init_exp (expdesc *e, expkind k,int i){
e->f = e->t = NO_JUMP;
e->k = k;
e->u.info = i;}staticvoid codestring (LexState *ls, expdesc *e, TString *s){init_exp(e, VK,luaK_stringK(ls->fs, s));}staticvoid checkname (LexState *ls, expdesc *e){codestring(ls, e,str_checkname(ls));}staticint registerlocalvar (LexState *ls, TString *varname){
FuncState *fs = ls->fs;
Proto *f = fs->f;int oldsize = f->sizelocvars;luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX,"local variables");while(oldsize < f->sizelocvars)
f->locvars[oldsize++].varname =NULL;
f->locvars[fs->nlocvars].varname = varname;luaC_objbarrier(ls->L, f, varname);return fs->nlocvars++;}staticvoid new_localvar (LexState *ls, TString *name){
FuncState *fs = ls->fs;
Dyndata *dyd = ls->dyd;int reg =registerlocalvar(ls, name);checklimit(fs, dyd->actvar.n +1- fs->firstlocal,
MAXVARS,"local variables");luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n +1,
dyd->actvar.size, Vardesc, MAX_INT,"local variables");
dyd->actvar.arr[dyd->actvar.n++].idx =cast(short, reg);}staticvoid new_localvarliteral_ (LexState *ls,constchar*name, size_t sz){new_localvar(ls,luaX_newstring(ls, name, sz));}#define new_localvarliteral(ls,v) \
new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)static LocVar *getlocvar (FuncState *fs,int i){int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;lua_assert(idx < fs->nlocvars);return&fs->f->locvars[idx];}//调整本地变量staticvoid adjustlocalvars (LexState *ls,int nvars){
FuncState *fs = ls->fs;
fs->nactvar =cast_byte(fs->nactvar + nvars);//转换字节,增加nvars个活动局部变量的数量for(; nvars; nvars--){getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;//nvars个变量的startpc地址为当前函数pc}}staticvoid removevars (FuncState *fs,int tolevel){
fs->ls->dyd->actvar.n -=(fs->nactvar - tolevel);while(fs->nactvar > tolevel)getlocvar(fs,--fs->nactvar)->endpc = fs->pc;}staticint searchupvalue (FuncState *fs, TString *name){int i;
Upvaldesc *up = fs->f->upvalues;for(i =0; i < fs->nups; i++){if(eqstr(up[i].name, name))return i;}return-1;/* not found */}staticint newupvalue (FuncState *fs, TString *name, expdesc *v){
Proto *f = fs->f;int oldsize = f->sizeupvalues;checklimit(fs, fs->nups +1, MAXUPVAL,"upvalues");luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL,"upvalues");while(oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name =NULL;
f->upvalues[fs->nups].instack =(v->k == VLOCAL);
f->upvalues[fs->nups].idx =cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;luaC_objbarrier(fs->ls->L, f, name);return fs->nups++;}staticint searchvar (FuncState *fs, TString *n){int i;for(i =cast_int(fs->nactvar)-1; i >=0; i--){if(eqstr(n,getlocvar(fs, i)->varname))return i;}return-1;/* not found */}/*
Mark block where variable at given level was defined
(to emit close instructions later).
*/staticvoid markupval (FuncState *fs,int level){
BlockCnt *bl = fs->bl;while(bl->nactvar > level)
bl = bl->previous;
bl->upval =1;}/*
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/staticvoid singlevaraux (FuncState *fs, TString *n, expdesc *var,int base){if(fs ==NULL)/* no more levels? */init_exp(var, VVOID,0);/* default is global */else{int v =searchvar(fs, n);/* look up locals at current level */if(v >=0){/* found? */init_exp(var, VLOCAL, v);/* variable is local */if(!base)markupval(fs, v);/* local will be used as an upval */}else{/* not found as local at current level; try upvalues */int idx =searchupvalue(fs, n);/* try existing upvalues */if(idx <0){/* not found? */singlevaraux(fs->prev, n, var,0);/* try upper levels */if(var->k == VVOID)/* not found? */return;/* it is a global *//* else was LOCAL or UPVAL */
idx =newupvalue(fs, n, var);/* will be a new upvalue */}init_exp(var, VUPVAL, idx);/* new or old upvalue */}}}staticvoid singlevar (LexState *ls, expdesc *var){
TString *varname =str_checkname(ls);
FuncState *fs = ls->fs;singlevaraux(fs, varname, var,1);if(var->k == VVOID){/* global name? */
expdesc key;singlevaraux(fs, ls->envn, var,1);/* get environment variable */lua_assert(var->k != VVOID);/* this one must exist */codestring(ls,&key, varname);/* key is variable name */luaK_indexed(fs, var,&key);/* env[varname] */}}staticvoid adjust_assign (LexState *ls,int nvars,int nexps, expdesc *e){
FuncState *fs = ls->fs;int extra = nvars - nexps;if(hasmultret(e->k)){
extra++;/* includes call itself */if(extra <0) extra =0;luaK_setreturns(fs, e, extra);/* last exp. provides the difference */if(extra >1)luaK_reserveregs(fs, extra-1);}else{if(e->k != VVOID)luaK_exp2nextreg(fs, e);/* close last expression */if(extra >0){int reg = fs->freereg;luaK_reserveregs(fs, extra);luaK_nil(fs, reg, extra);}}if(nexps > nvars)
ls->fs->freereg -= nexps - nvars;/* remove extra values */}staticvoid enterlevel (LexState *ls){//进入层
lua_State *L = ls->L;//进入这一层++L->nCcalls;//嵌套调用的数量加1checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS,"C levels");}#define leavelevel(ls) ((ls)->L->nCcalls--)staticvoid closegoto (LexState *ls,int g, Labeldesc *label){int i;
FuncState *fs = ls->fs;
Labellist *gl =&ls->dyd->gt;
Labeldesc *gt =&gl->arr[g];lua_assert(eqstr(gt->name, label->name));if(gt->nactvar < label->nactvar){
TString *vname =getlocvar(fs, gt->nactvar)->varname;constchar*msg =luaO_pushfstring(ls->L,"<goto %s> at line %d jumps into the scope of local '%s'",getstr(gt->name), gt->line,getstr(vname));semerror(ls, msg);}luaK_patchlist(fs, gt->pc, label->pc);/* remove goto from pending list */for(i = g; i < gl->n -1; i++)
gl->arr[i]= gl->arr[i +1];
gl->n--;}/*
** try to close a goto with existing labels; this solves backward jumps
*/staticint findlabel (LexState *ls,int g){int i;
BlockCnt *bl = ls->fs->bl;
Dyndata *dyd = ls->dyd;
Labeldesc *gt =&dyd->gt.arr[g];/* check labels in current block for a match */for(i = bl->firstlabel; i < dyd->label.n; i++){
Labeldesc *lb =&dyd->label.arr[i];if(eqstr(lb->name, gt->name)){/* correct label? */if(gt->nactvar > lb->nactvar &&(bl->upval || dyd->label.n > bl->firstlabel))luaK_patchclose(ls->fs, gt->pc, lb->nactvar);closegoto(ls, g, lb);/* close it */return1;}}return0;/* label not found; cannot close goto */}staticint newlabelentry (LexState *ls, Labellist *l, TString *name,int line,int pc){int n = l->n;luaM_growvector(ls->L, l->arr, n, l->size,
Labeldesc, SHRT_MAX,"labels/gotos");
l->arr[n].name = name;
l->arr[n].line = line;
l->arr[n].nactvar = ls->fs->nactvar;
l->arr[n].pc = pc;
l->n = n +1;return n;}/*
** check whether new label 'lb' matches any pending gotos in current
** block; solves forward jumps
*/staticvoid findgotos (LexState *ls, Labeldesc *lb){
Labellist *gl =&ls->dyd->gt;int i = ls->fs->bl->firstgoto;while(i < gl->n){if(eqstr(gl->arr[i].name, lb->name))closegoto(ls, i, lb);else
i++;}}/*
** export pending gotos to outer level, to check them against
** outer labels; if the block being exited has upvalues, and
** the goto exits the scope of any variable (which can be the
** upvalue), close those variables being exited.
*/staticvoid movegotosout (FuncState *fs, BlockCnt *bl){int i = bl->firstgoto;
Labellist *gl =&fs->ls->dyd->gt;/* correct pending gotos to current block and try to close it
with visible labels */while(i < gl->n){
Labeldesc *gt =&gl->arr[i];if(gt->nactvar > bl->nactvar){if(bl->upval)luaK_patchclose(fs, gt->pc, bl->nactvar);
gt->nactvar = bl->nactvar;}if(!findlabel(fs->ls, i))
i++;/* move to next one */}}staticvoid enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop){
bl->isloop = isloop;
bl->nactvar = fs->nactvar;
bl->firstlabel = fs->ls->dyd->label.n;
bl->firstgoto = fs->ls->dyd->gt.n;
bl->upval =0;
bl->previous = fs->bl;
fs->bl = bl;lua_assert(fs->freereg == fs->nactvar);}/*
** create a label named 'break' to resolve break statements
*/staticvoid breaklabel (LexState *ls){
TString *n =luaS_new(ls->L,"break");int l =newlabelentry(ls,&ls->dyd->label, n,0, ls->fs->pc);findgotos(ls,&ls->dyd->label.arr[l]);}/*
** generates an error for an undefined 'goto'; choose appropriate
** message when label name is a reserved word (which can only be 'break')
*/static l_noret undefgoto (LexState *ls, Labeldesc *gt){constchar*msg =isreserved(gt->name)?"<%s> at line %d not inside a loop":"no visible label '%s' for <goto> at line %d";
msg =luaO_pushfstring(ls->L, msg,getstr(gt->name), gt->line);semerror(ls, msg);}staticvoid leaveblock (FuncState *fs){
BlockCnt *bl = fs->bl;
LexState *ls = fs->ls;if(bl->previous && bl->upval){/* create a 'jump to here' to close upvalues */int j =luaK_jump(fs);luaK_patchclose(fs, j, bl->nactvar);luaK_patchtohere(fs, j);}if(bl->isloop)breaklabel(ls);/* close pending breaks */
fs->bl = bl->previous;removevars(fs, bl->nactvar);lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = fs->nactvar;/* free registers */
ls->dyd->label.n = bl->firstlabel;/* remove local labels */if(bl->previous)/* inner block? */movegotosout(fs, bl);/* update pending gotos to outer block */elseif(bl->firstgoto < ls->dyd->gt.n)/* pending gotos in outer block? */undefgoto(ls,&ls->dyd->gt.arr[bl->firstgoto]);/* error */}/*
** adds a new prototype into list of prototypes
*/static Proto *addprototype (LexState *ls){
Proto *clp;
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;/* prototype of current function */if(fs->np >= f->sizep){int oldsize = f->sizep;luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx,"functions");while(oldsize < f->sizep)
f->p[oldsize++]=NULL;}
f->p[fs->np++]= clp =luaF_newproto(L);luaC_objbarrier(L, f, clp);return clp;}/*
** codes instruction to create new closure in parent function.
** The OP_CLOSURE instruction must use the last available register,
** so that, if it invokes the GC, the GC knows which registers
** are in use at that time.
代码在父函数中创建新闭包的指令。
OP_CLOSURE指令必须使用最后一个可用的寄存器,
因此,如果它调用GC,则GC知道哪些寄存器当时正在使用。
*/staticvoid codeclosure (LexState *ls, expdesc *v){
FuncState *fs = ls->fs->prev;init_exp(v, VRELOCABLE,luaK_codeABx(fs, OP_CLOSURE,0, fs->np -1));luaK_exp2nextreg(fs, v);/* fix it at the last register */}staticvoid open_func (LexState *ls, FuncState *fs, BlockCnt *bl){
Proto *f;
fs->prev = ls->fs;/* linked list of funcstates */
fs->ls = ls;
ls->fs = fs;
fs->pc =0;
fs->lasttarget =0;
fs->jpc = NO_JUMP;
fs->freereg =0;
fs->nk =0;
fs->np =0;
fs->nups =0;
fs->nlocvars =0;
fs->nactvar =0;
fs->firstlocal = ls->dyd->actvar.n;
fs->bl =NULL;
f = fs->f;
f->source = ls->source;
f->maxstacksize =2;/* registers 0/1 are always valid */enterblock(fs, bl,0);}staticvoid close_func (LexState *ls){
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;luaK_ret(fs,0,0);/* final return */leaveblock(fs);luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc;luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc,int);
f->sizelineinfo = fs->pc;luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
f->sizek = fs->nk;luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
f->sizep = fs->np;luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
f->sizelocvars = fs->nlocvars;luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
f->sizeupvalues = fs->nups;lua_assert(fs->bl ==NULL);
ls->fs = fs->prev;luaC_checkGC(L);}/*============================================================*//* GRAMMAR RULES *//*============================================================*//*
** check whether current token is in the follow set of a block.
** 'until' closes syntactical blocks, but do not close scope,
** so it is handled in separate.
检查当前令牌是否在块的跟随集中。
'until'关闭语法块,但不关闭范围,
所以它是分开处理的。
*/staticint block_follow (LexState *ls,int withuntil){switch(ls->t.token){case TK_ELSE:case TK_ELSEIF:case TK_END:case TK_EOS:return1;case TK_UNTIL:return withuntil;default:return0;}}staticvoid statlist (LexState *ls){/* statlist -> { stat [';'] } */while(!block_follow(ls,1)){//检查当前令牌是否在块的跟随集的里面if(ls->t.token == TK_RETURN){//如果这是返回的单词statement(ls);return;/* 'return' must be last statement */}statement(ls);}}staticvoid fieldsel (LexState *ls, expdesc *v){/* fieldsel -> ['.' | ':'] NAME */
FuncState *fs = ls->fs;
expdesc key;luaK_exp2anyregup(fs, v);luaX_next(ls);/* skip the dot or colon */checkname(ls,&key);luaK_indexed(fs, v,&key);}staticvoid yindex (LexState *ls, expdesc *v){/* index -> '[' expr ']' */luaX_next(ls);/* skip the '[' */expr(ls, v);luaK_exp2val(ls->fs, v);checknext(ls,']');}/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/struct ConsControl {
expdesc v;/* last list item read */
expdesc *t;/* table descriptor */int nh;/* total number of 'record' elements */int na;/* total number of array elements */int tostore;/* number of array elements pending to be stored */};staticvoid recfield (LexState *ls,struct ConsControl *cc){//变量或者table赋值/* recfield -> (NAME | '['exp1']') = exp1 */
FuncState *fs = ls->fs;int reg = ls->fs->freereg;
expdesc key, val;int rkkey;if(ls->t.token == TK_NAME){checklimit(fs, cc->nh, MAX_INT,"items in a constructor");checkname(ls,&key);}else/* ls->t.token == '[' */yindex(ls,&key);
cc->nh++;checknext(ls,'=');
rkkey =luaK_exp2RK(fs,&key);expr(ls,&val);luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey,luaK_exp2RK(fs,&val));
fs->freereg = reg;/* free registers */}staticvoid 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_setlist(fs, cc->t->u.info, cc->na, cc->tostore);/* flush */
cc->tostore =0;/* no more items pending */}}staticvoid lastlistfield (FuncState *fs,struct ConsControl *cc){if(cc->tostore ==0)return;if(hasmultret(cc->v.k)){luaK_setmultret(fs,&cc->v);luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);
cc->na--;/* do not count last expression (unknown number of elements) */}else{if(cc->v.k != VVOID)luaK_exp2nextreg(fs,&cc->v);luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);}}staticvoid listfield (LexState *ls,struct ConsControl *cc){/* listfield -> exp */expr(ls,&cc->v);checklimit(ls->fs, cc->na, MAX_INT,"items in a constructor");
cc->na++;
cc->tostore++;}staticvoid field (LexState *ls,struct ConsControl *cc){//领域/* field -> listfield | recfield */switch(ls->t.token){case TK_NAME:{/* may be 'listfield' or 'recfield' 如果这是一个名字,这个很可能是一个列表领域或者rec领域(rec还不知道是什么)*/if(luaX_lookahead(ls)!='=')/* expression? 这是表达式?*/listfield(ls, cc);//列表领域elserecfield(ls, cc);//rec领域,rec还不知道是什么break;}case'[':{recfield(ls, cc);//rec领域,rec还不知道是什么break;}default:{listfield(ls, cc);//列表领域break;}}}staticvoid constructor (LexState *ls, expdesc *t){//构造函数,构造一个table/* constructor -> '{' [ field { sep field } [sep] ] '}'
sep -> ',' | ';' */
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 */checknext(ls,'{');do{lua_assert(cc.v.k == VVOID || cc.tostore >0);if(ls->t.token =='}')break;closelistfield(fs,&cc);field(ls,&cc);}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_int2fb(cc.nh));/* set initial table size */}/* }====================================================================== */staticvoid 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);
f->is_vararg =1;/* declared vararg 已声明的参数标志*/break;}default:luaX_syntaxerror(ls,"<name> or '...' expected");}}while(!f->is_vararg &&testnext(ls,','));//判断是不是下一个逗号,是的话,继续读取参数列表}adjustlocalvars(ls, nparams);//增加 nparams 个本地变量
f->numparams =cast_byte(fs->nactvar);//增加 nparams 个参数数量luaK_reserveregs(fs, fs->nactvar);/* reserve register for parameters 为参数保留寄存器*/}staticvoid body (LexState *ls, expdesc *e,int ismethod,int line){/* body -> '(' parlist ')' block END */
FuncState new_fs;
BlockCnt bl;
new_fs.f =addprototype(ls);//添加原型类型到原型列表里
new_fs.f->linedefined = line;open_func(ls,&new_fs,&bl);//初始化一个新的new_fs变量和进入下一块checknext(ls,'(');//检查下一个字符是不是(if(ismethod){//如果这是一个方法new_localvarliteral(ls,"self");/* create 'self' parameter 创建一个名字为self的参数*///通过字符串新建一个变量,new_localvar与new_localvarliteral的区别就是输入参数是lua_string类型
adjustlocalvars(ls,1);//添加一个本地变量}parlist(ls);//解析参数列表checknext(ls,')');//判断下一个字符是不是)statlist(ls);//递归处理函数体
new_fs.f->lastlinedefined = ls->linenumber;check_match(ls, TK_END, TK_FUNCTION, line);//匹配下一个单词是不是end,不是就报错codeclosure(ls, e);//闭包,代码在父函数中创建新闭包的指令。OP_CLOSURE指令必须使用最后一个可用的寄存器,因此,如果它调用GC,则GC知道哪些寄存器当时正在使用。close_func(ls);//关闭new_fs,离开这一个块和检查gc}staticint explist (LexState *ls, expdesc *v){/* explist -> 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;}staticvoid funcargs (LexState *ls, expdesc *f,int line){
FuncState *fs = ls->fs;
expdesc args;int base, nparams;switch(ls->t.token){case'(':{/* funcargs -> '(' [ explist ] ')' */luaX_next(ls);if(ls->t.token ==')')/* arg list is empty? */
args.k = VVOID;else{explist(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");}}lua_assert(f->k == VNONRELOC);
base = f->u.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));//初始化vcall变量,用于定义一次调用操作luaK_fixline(fs, line);
fs->freereg = base+1;/* call remove function and arguments and leaves
(unless changed) one result */}/*
** {======================================================================
** Expression parsing
** =======================================================================
*/staticvoid primaryexp (LexState *ls, expdesc *v){/* primaryexp -> 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");}}}staticvoid suffixedexp (LexState *ls, expdesc *v){/* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;int line = ls->linenumber;primaryexp(ls, v);for(;;){switch(ls->t.token){case'.':{/* fieldsel */fieldsel(ls, v);break;}case'[':{/* '[' exp1 ']' */
expdesc key;luaK_exp2anyregup(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, line);break;}case'(':case TK_STRING:case'{':{/* funcargs */luaK_exp2nextreg(fs, v);funcargs(ls, v, line);break;}default:return;}}}staticvoid simpleexp (LexState *ls, expdesc *v){/* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |
constructor | FUNCTION body | suffixedexp */switch(ls->t.token){case TK_FLT:{init_exp(v, VKFLT,0);
v->u.nval = ls->t.seminfo.r;break;}case TK_INT:{init_exp(v, VKINT,0);
v->u.ival = ls->t.seminfo.i;break;}case TK_STRING:{codestring(ls, v, ls->t.seminfo.ts);break;}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 '...' outside a vararg function");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:{suffixedexp(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_BNOT;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_MOD;case'^':return OPR_POW;case'/':return OPR_DIV;case TK_IDIV:return OPR_IDIV;case'&':return OPR_BAND;case'|':return OPR_BOR;case'~':return OPR_BXOR;case TK_SHL:return OPR_SHL;case TK_SHR:return OPR_SHR;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;}}staticconststruct{
lu_byte left;/* left priority for each binary operator */
lu_byte right;/* right priority */} priority[]={/* ORDER OPR */{10,10},{10,10},/* '+' '-' */{11,11},{11,11},/* '*' '%' */{14,13},/* '^' (right associative) */{11,11},{11,11},/* '/' '//' */{6,6},{4,4},{5,5},/* '&' '|' '~' */{7,7},{7,7},/* '<<' '>>' */{9,8},/* '..' (right associative) */{3,3},{3,3},{3,3},/* ==, <, <= */{3,3},{3,3},{3,3},/* ~=, >, >= */{2,2},{1,1}/* and, or */};#define UNARY_PRIORITY 12 /* 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,int limit){
BinOpr op;
UnOpr uop;enterlevel(ls);
uop =getunopr(ls->t.token);if(uop != OPR_NOUNOPR){int line = ls->linenumber;luaX_next(ls);subexpr(ls, v, UNARY_PRIORITY);luaK_prefix(ls->fs, uop, v, line);}elsesimpleexp(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;int line = ls->linenumber;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, line);
op = nextop;}leavelevel(ls);return op;/* return first untreated operator */}staticvoid expr (LexState *ls, expdesc *v){//读取条件subexpr(ls, v,0);}/* }==================================================================== *//*
** {======================================================================
** Rules for Statements
** =======================================================================
*///解析下一块staticvoid block (LexState *ls){/* block -> statlist */
FuncState *fs = ls->fs;
BlockCnt bl;enterblock(fs,&bl,0);statlist(ls);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 an upvalue/local variable, the
** upvalue/local variable is begin used in a previous assignment to a
** table. If so, save original upvalue/local value in a safe place and
** use this safe copy in the previous assignment.
*/staticvoid 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){/* check all previous assignments */if(lh->v.k == VINDEXED){/* assigning to a table? *//* table is the upvalue/local being assigned now? */if(lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info){
conflict =1;
lh->v.u.ind.vt = VLOCAL;
lh->v.u.ind.t = extra;/* previous assignment will use safe copy */}/* index is the local being assigned? (index cannot be upvalue) */if(v->k == VLOCAL && lh->v.u.ind.idx == v->u.info){
conflict =1;
lh->v.u.ind.idx = extra;/* previous assignment will use safe copy */}}}if(conflict){/* copy upvalue/local value to a temporary (in position 'extra') */
OpCode op =(v->k == VLOCAL)? OP_MOVE : OP_GETUPVAL;luaK_codeABC(fs, op, extra, v->u.info,0);luaK_reserveregs(fs,1);}}//进行赋值处理staticvoid assignment (LexState *ls,struct LHS_assign *lh,int nvars){
expdesc e;check_condition(ls,vkisvar(lh->v.k),"syntax error");//判断这是不是一个变量if(testnext(ls,',')){/* assignment -> ',' suffixedexp assignment 如果下一个字符是逗号,则是一个多变量同时赋值*/struct LHS_assign nv;
nv.prev = lh;suffixedexp(ls,&nv.v);if(nv.v.k != VINDEXED)check_conflict(ls, lh,&nv.v);checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,"C levels");assignment(ls,&nv, nvars+1);//递归处理}else{/* assignment -> '=' explist */int nexps;checknext(ls,'=');//检查下一个是不是等号,不是的话报错
nexps =explist(ls,&e);if(nexps != nvars)adjust_assign(ls, nvars, nexps,&e);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);}//执行条件判断staticint 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;}staticvoid gotostat (LexState *ls,int pc){int line = ls->linenumber;
TString *label;int g;if(testnext(ls, TK_GOTO))//如果下一个单词是goto
label =str_checkname(ls);//检查标签名else{luaX_next(ls);/* skip break ,跳过break*/
label =luaS_new(ls->L,"break");//新建一个名字为break的标签}
g =newlabelentry(ls,&ls->dyd->gt, label, line, pc);//一个新的标签findlabel(ls, g);/* close it if label already defined 如果这个标签已被定义就关闭它*/}/* check for repeated labels on the same block 检查同一个块里是否存在重复了的标签*/staticvoid checkrepeated (FuncState *fs, Labellist *ll, TString *label){int i;for(i = fs->bl->firstlabel; i < ll->n; i++){if(eqstr(label, ll->arr[i].name)){constchar*msg =luaO_pushfstring(fs->ls->L,"label '%s' already defined on line %d",getstr(label), ll->arr[i].line);semerror(fs->ls, msg);}}}/* skip no-op statements */staticvoid skipnoopstat (LexState *ls){while(ls->t.token ==';'|| ls->t.token == TK_DBCOLON)statement(ls);}staticvoid labelstat (LexState *ls, TString *label,int line){/* label -> '::' NAME '::' */
FuncState *fs = ls->fs;
Labellist *ll =&ls->dyd->label;int l;/* index of new label being created */checkrepeated(fs, ll, label);/* check for repeated labels 检查标签是否重复 */checknext(ls, TK_DBCOLON);/* skip double colon 检查是否双冒号并next*//* create new entry for this label 为此标签创建新条目*/
l =newlabelentry(ls, ll, label, line,luaK_getlabel(fs));skipnoopstat(ls);/* skip other no-op statements 跳过其他没有操作的声明*/if(block_follow(ls,0)){/* label is last no-op statement in the block? *//* assume that locals are already out of scope */
ll->arr[l].nactvar = fs->bl->nactvar;}findgotos(ls,&ll->arr[l]);//寻找goto}staticvoid 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);//记录当前pc为下一次跳转的目的地址,用于在循环尾部跳转,returns current 'pc' and marks it as a jump target (to avoid wrong optimizations with consecutive instructions not in the same basic block).
condexit =cond(ls);//获取条件enterblock(fs,&bl,1);//进入块checknext(ls, TK_DO);//检查下一个是不是do,如果不是就报错block(ls);//解析下一个块luaK_jumpto(fs, whileinit);//跳回while init的未知继续判断条件。check_match(ls, TK_END, TK_WHILE, line);//检查是不是到了endleaveblock(fs);//离开当前块回到上一块luaK_patchtohere(fs, condexit);/* false conditions finish the loop 结束这一个循环*/}staticvoid repeatstat (LexState *ls,int line){/* repeatstat -> REPEAT block UNTIL cond */int condexit;
FuncState *fs = ls->fs;int repeat_init =luaK_getlabel(fs);//返回当前的pc和把它记录到下一个跳转的目标,用于尾部判断hours跳转
BlockCnt bl1, bl2;enterblock(fs,&bl1,1);/* loop block 进入循环体*/enterblock(fs,&bl2,0);/* scope block 进入范围块*/luaX_next(ls);/* skip REPEAT 跳过repeat*/statlist(ls);//解析循环体check_match(ls, TK_UNTIL, TK_REPEAT, line);//检查下一个是不是until,如果不是就报错
condexit =cond(ls);/* read condition (inside scope block) 读取循环条件*/if(bl2.upval)/* upvalues? lua的闭包里的upvalues,检查范围是不是闭包*/luaK_patchclose(fs, condexit, bl2.nactvar);//闭包leaveblock(fs);/* finish scope 离开范围块*/luaK_patchlist(fs, condexit, repeat_init);/* close the loop 判断是否需要继续循环,是的话就跳转到repeat_init*/leaveblock(fs);/* finish loop 离开循环体*/}staticint exp1 (LexState *ls){
expdesc e;int reg;expr(ls,&e);luaK_exp2nextreg(ls->fs,&e);lua_assert(e.k == VNONRELOC);
reg = e.u.info;return reg;}staticvoid 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 调整控制变量,增加三个本地变量,并且把他们的startpc赋值成当前函数的pc*/checknext(ls, TK_DO);//检查下一个是不是do
prep = isnum ?luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP):luaK_jump(fs);//在fornum函数里isnum为1/*
指令 OP_FORPREP end_label:
从栈中得到循环变量 var1, $limit, $step//在fornum函数里isnum为1
比较: 如果 var1 > $limit 则 (注1)
从栈中移除 var1, $limit, $step 循环控制变量 (top -= 3)
跳转到 end_label
否则执行下一个指令, 也即循环体.(注1: 如果 $step 为负数, 则比较 var1 < $limit. 不影响我们语义理解的略去.)
*/enterblock(fs,&bl,0);/* scope for declared variables 已声明的变量的范围,进入循环体*/adjustlocalvars(ls, nvars);//增加一个本地变量,这里在for里nvars为1luaK_reserveregs(fs, nvars);//在寄存器对战中保留'nvars'寄存器,在for循环里nvars为1block(ls);//处理for循环体leaveblock(fs);/* end of scope for declared variables 已声明的变量的范围的尾部,离开循环体*/luaK_patchtohere(fs, prep);if(isnum)/* numeric for? 在for里isnum为1*/{
endfor =luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);//使用forloop指令/*
指令 OP_FORLOOP begin_label:
从栈中得到循环变量 var1, $limit, $step (并简单验证)
var1 += $step 增加循环变量值
如果 var1 > $limit 则
从栈中移除 var1, $limit, $step 循环控制变量
执行下一个代码, 即出了循环体.
否则
跳转到 begin_label 处执行, 即执行循环体.
根据上述描述, Lua 虚拟机使用了相比硬件指令而言, 更高级的虚拟指令
来支持实现 for 语句.
对 forlist 形式的支持有相似性, 也是使用了两种新的指令帮助实现,
OP_LFORPREP 和 OP_LFORLOOP, 因其实现原理的相似性, 即略去不详述了.
*/}else{/* generic for */luaK_codeABC(fs, OP_TFORCALL, base,0, nvars);//使用forcall指令来执行通用的luaK_fixline(fs, line);
endfor =luaK_codeAsBx(fs, OP_TFORLOOP, base +2, NO_JUMP);//使用forloop指令}luaK_patchlist(fs, endfor, prep +1);luaK_fixline(fs, line);}staticvoid 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)");new_localvarliteral(ls,"(for limit)");new_localvarliteral(ls,"(for step)");//通过字符串新建一个变量,new_localvar与new_localvarliteral的区别就是输入参数是lua_string类型new_localvar(ls, varname);//通过变量名新建一个本地变量checknext(ls,'=');//检查下一个是不是等号,不是就报错exp1(ls);/* initial value 执行初始化的语句*/checknext(ls,',');//检查下一个是不是逗号,不是就报错exp1(ls);/* limit 执行约束条件*/if(testnext(ls,','))//如果下一个是逗号,是的话就执行可选的步骤exp1(ls);/* optional step 执行可选步骤*/else{/* default step = 1 */luaK_codek(fs, fs->freereg,luaK_intK(fs,1));//将一个整数添加到常量列表并返回其索引,并且把常量加载到空闲的寄存器luaK_reserveregs(fs,1);//在寄存器堆栈中保留'1'寄存器}forbody(ls, base, line,1,1);//解析for的body部分}staticvoid forlist (LexState *ls, TString *indexname){/* forlist -> NAME {,NAME} IN explist forbody */
FuncState *fs = ls->fs;
expdesc e;int nvars =4;/* gen, state, control, plus at least one declared var */int line;int base = fs->freereg;/* create control variables */new_localvarliteral(ls,"(for generator)");new_localvarliteral(ls,"(for state)");new_localvarliteral(ls,"(for control)");//通过字符串新建一个变量,new_localvar与new_localvarliteral的区别就是输入参数是lua_string类型/* create declared variables */new_localvar(ls, indexname);//通过变量名新建一个本地变量while(testnext(ls,',')){//如果下一个是逗号,如果是就新建本地变量存放这些变量new_localvar(ls,str_checkname(ls));
nvars++;}checknext(ls, TK_IN);//检查下一个是不是in,不是的话报错
line = ls->linenumber;adjust_assign(ls,3,explist(ls,&e),&e);//调整分配luaK_checkstack(fs,3);/* extra space to call generator 检查对战,检查调用通用生成器的外部空间*/forbody(ls, base, line, nvars -3,0);//nvars是控制变量的数量}staticvoid 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' 跳过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;//如果是逗号或者in,使用forlist来解析,遍历循环default:luaX_syntaxerror(ls,"'=' or 'in' expected");}check_match(ls, TK_END, TK_FOR, line);//检查一下是不是end,防止出现语法错误,不是的话就报错leaveblock(fs);/* loop scope ('break' jumps to this point) 离开这一块,回到上一块*/}staticvoid test_then_block (LexState *ls,int*escapelist){/* test_then_block -> [IF | ELSEIF] cond THEN block */
BlockCnt bl;
FuncState *fs = ls->fs;
expdesc v;int jf;/* instruction to skip 'then' code (if condition is false) */luaX_next(ls);/* skip IF or ELSEIF 跳过if 或者else if*/expr(ls,&v);/* read condition 读取条件*/checknext(ls, TK_THEN);//检查下一个是不是then并且跳到下一个单词,如果不是就报错if(ls->t.token == TK_GOTO || ls->t.token == TK_BREAK){//下一个是goto或者break单词luaK_goiffalse(ls->fs,&v);/* will jump to label if condition is true ,当v条件成立时就跳转,这里只是压栈等操作,并不是直接跳转*/enterblock(fs,&bl,0);/* must enter block before 'goto' 必须在处理goto前先进入块*/gotostat(ls, v.t);/* handle goto/break 处理goto或者break,执行跳转*/while(testnext(ls,';')){}/* skip colons 跳过分号*/if(block_follow(ls,0)){/* 'goto' is the entire block? goto 是整个块?尾部,0是返回值*/leaveblock(fs);//如果这是块的尾部,退出块return;/* and that is it */}else/* must skip over 'then' part if condition is false 如果条件为假必须跳过then部分*/
jf =luaK_jump(fs);}else{/* regular case (not goto/break) 常规语句,没有goto和break */luaK_goiftrue(ls->fs,&v);/* skip over block if condition is false 如果条件为假,跳过块*/enterblock(fs,&bl,0);//进入块
jf = v.f;}statlist(ls);/* 'then' part 递归解析*/leaveblock(fs);//离开当前块if(ls->t.token == TK_ELSE ||
ls->t.token == TK_ELSEIF)/* followed by 'else'/'elseif'? */luaK_concat(fs, escapelist,luaK_jump(fs));/* must jump over it */luaK_patchtohere(fs, jf);}staticvoid ifstat (LexState *ls,int line){/* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
FuncState *fs = ls->fs;int escapelist = NO_JUMP;/* exit list for finished parts */test_then_block(ls,&escapelist);/* IF cond THEN block ,尝试是不是then语句,如果是解析if cond then语句*/while(ls->t.token == TK_ELSEIF)//循环处理elseif语句test_then_block(ls,&escapelist);/* ELSEIF cond THEN block */if(testnext(ls, TK_ELSE))//最后是否存在else语句block(ls);/* 'else' part 处理else语句*/check_match(ls, TK_END, TK_IF, line);//判断是结尾luaK_patchtohere(fs, escapelist);/* patch escape list to 'if' end 打包这里,将“list”中的元素添加到“here”的待处理跳转列表中*/}staticvoid localfunc (LexState *ls){
expdesc b;
FuncState *fs = ls->fs;new_localvar(ls,str_checkname(ls));/* new local variable,新建一个本地变量 */adjustlocalvars(ls,1);/* enter its scope 增加一个本地变量*/body(ls,&b,0, ls->linenumber);/* function created in next register 在下一个寄存器里创建一个函数,不是方法*//* debug information will only see the variable after this point! */getlocvar(fs, b.u.info)->startpc = fs->pc;}staticvoid localstat (LexState *ls){/* stat -> LOCAL NAME {',' NAME} ['=' explist] */int nvars =0;int nexps;
expdesc e;do{new_localvar(ls,str_checkname(ls));
nvars++;}while(testnext(ls,','));if(testnext(ls,'='))
nexps =explist(ls,&e);else{
e.k = VVOID;
nexps =0;}adjust_assign(ls, nvars, nexps,&e);adjustlocalvars(ls, nvars);}staticint funcname (LexState *ls, expdesc *v){/* funcname -> NAME {fieldsel} [':' NAME] */int ismethod =0;singlevar(ls, v);while(ls->t.token =='.')fieldsel(ls, v);if(ls->t.token ==':'){
ismethod =1;fieldsel(ls, v);}return ismethod;}staticvoid funcstat (LexState *ls,int line){/* funcstat -> FUNCTION funcname body */int ismethod;
expdesc v, b;luaX_next(ls);/* skip FUNCTION 跳过function单词*/
ismethod =funcname(ls,&v);//检查这是不是一个方法,并且检查是都存在对应的包body(ls,&b, ismethod, line);//进行函数的代码解析luaK_storevar(ls->fs,&v,&b);//恢复变量luaK_fixline(ls->fs, line);/* definition "happens" in the first line ,Change line information associated with current position.*/}staticvoid exprstat (LexState *ls){/* stat -> func | assignment */
FuncState *fs = ls->fs;struct LHS_assign v;/*
lua将表达式分为 主表达式 primaryexp 和 任意表达式 explist1。
主表达式必须可以作为左值存在,能够被赋值,比如"a.b=1+2",其中 "a.b"为主表达式,"1+2"不能为主表达式。
在exprstat里,等号'='左边为一个主表达式,用primaryexp解析,有4种表达形式:
exp; exp(exp); exp[exp]; exp.exp
比如: a; a(1+2); a["b"]; a.b
其他复杂形式为这4种形式的递归实现,如
a.b.c = a.exp1
exp1 = b.c
再比如
a(b.c).d() = exp1.exp2
exp1 = a(exp3)
exp2 = d()
exp3 = b.c
primaryexp先获取一个前缀表达式 prefixexp,如 "a()" 分解为"a" 和 "()",其中 "a" 即为前缀。
然后根据第2个token决定使用上面4种表达形式的哪一种,如"a()" 使用 exp(exp) 形式解析。
primaryexp解析完后,判断当前expr是否为函数调用,如:
"a()" 是函数调用
"a().b" 不是函数调用
"a().b()" 是函数调用
若为函数调用,exprstat使用 func 产生式,否则使用 assignment 产生式,作为赋值语句处理。
primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs }
对应上面的4种表达形式
prefixexp.NAME 用于table取key值,如 "a.b" 等同于"a['b']",这是lua的语法糖
prefixexp[exp] 用于table取key值,key可以为一个表达式
prefixexp:NAME() 用于table的成员函数调用,另一个语法糖,如 "a:b(c)" 等同于 "a.b(a,c)",自动将当前table对象作为第一个参数插入,类似c++的this指针
prefixexp() 用于函数调用,如 "a()"
prefixexp -> NAME | `(` expr `)`
前缀表达式可以为标识符,也可以一个表达式
如 "a()" ,prefixexp使用 NAME 产生式
如 "(a+1).d=1",prefixexp使用 expr 产生式
不要怀疑, "(a+1).d=1",在lua里可以这样写,比如a为table,table又可以定义元方法,重载+运算符返回一个新table就可以了。
*/suffixedexp(ls,&v.v);//参数解析if(ls->t.token =='='|| ls->t.token ==','){/* stat -> assignment ? 赋值语句*/
v.prev =NULL;assignment(ls,&v,1);}else{/* stat -> func 一个函数*/check_condition(ls, v.v.k == VCALL,"syntax error");//判断这是不是一个函数SETARG_C(getinstruction(fs,&v.v),1);/* call statement uses no results */}}staticvoid retstat (LexState *ls){/* stat -> RETURN [explist] [';'] */
FuncState *fs = ls->fs;
expdesc e;int first, nret;/* registers with returned values */if(block_follow(ls,1)|| ls->t.token ==';')
first = nret =0;/* return no values */else{
nret =explist(ls,&e);/* optional return values */if(hasmultret(e.k)){luaK_setmultret(fs,&e);if(e.k == VCALL && nret ==1){/* tail call? */SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);lua_assert(GETARG_A(getinstruction(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);testnext(ls,';');/* skip optional semicolon */}staticvoid statement (LexState *ls){//解析声明int line = ls->linenumber;/* may be needed for error messages */enterlevel(ls);//进入这一层,初始化当前luastateswitch(ls->t.token){case';':{/* stat -> ';' (empty statement) ;可以忽略*/luaX_next(ls);/* skip ';' */break;}case TK_IF:{/* stat -> ifstat 如果这是if判断语句*/ifstat(ls, line);break;}case TK_WHILE:{/* stat -> whilestat */whilestat(ls, line);break;}case TK_DO:{/* stat -> DO block END */luaX_next(ls);/* skip DO 跳过do*/block(ls);//解析下一块check_match(ls, TK_END, TK_DO, line);//检查是不是到了endbreak;}case TK_FOR:{/* stat -> forstat */forstat(ls, line);break;}/*
Lua 编程语言中 repeat...until 循环语句不同于 for 和 while循环,for 和 while 循环的条件语句在当前循环执行开始时判断,而 repeat...until 循环的条件语句在当前循环结束后判断。
语法
Lua 编程语言中 repeat...until 循环语法格式:
repeat
statements
until( condition )
*/case TK_REPEAT:{/* stat -> repeatstat */repeatstat(ls, line);break;}case TK_FUNCTION:{/* stat -> funcstat */funcstat(ls, line);break;}case TK_LOCAL:{/* stat -> localstat */luaX_next(ls);/* skip LOCAL 跳过local*/if(testnext(ls, TK_FUNCTION))/* local function? 下一个单词是function?这是一个local function?*/localfunc(ls);//本地函数elselocalstat(ls);//本地变量break;}case TK_DBCOLON:{/* stat -> label */luaX_next(ls);/* skip double colon 跳过两个冒号*/labelstat(ls,str_checkname(ls), line);//break;}case TK_RETURN:{/* stat -> retstat 这是一个返回*/luaX_next(ls);/* skip RETURN */retstat(ls);break;}case TK_BREAK:/* stat -> breakstat */case TK_GOTO:{/* stat -> 'goto' NAME */gotostat(ls,luaK_jump(ls->fs));break;}default:{/* stat -> func | assignment *//*
除去if、while、local、return等控制语句,exprstat表示一条执行语句,包含赋值和函数调用两类,如 "a=1" 和 "print()"
*/exprstat(ls);break;}}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);}/* }====================================================================== *//*
** compiles the main function, which is a regular vararg function with an
** upvalue named LUA_ENV
*/staticvoid mainfunc (LexState *ls, FuncState *fs){//编译主函数
BlockCnt bl;
expdesc v;open_func(ls, fs,&bl);
fs->f->is_vararg =1;/* main function is always declared vararg */init_exp(&v, VLOCAL,0);/* create and... */newupvalue(fs, ls->envn,&v);/* ...set environment upvalue */luaX_next(ls);/* read first token 读第一个单词,注意是单词不是字符*/statlist(ls);/* parse main body ,解析*/check(ls, TK_EOS);close_func(ls);}
LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd,constchar*name,int firstchar){
LexState lexstate;
FuncState funcstate;
LClosure *cl =luaF_newLclosure(L,1);/* create main closure */setclLvalue(L, L->top, cl);/* anchor it (to avoid being collected) */luaD_inctop(L);
lexstate.h =luaH_new(L);/* create table for scanner */sethvalue(L, L->top, lexstate.h);/* anchor it */luaD_inctop(L);
funcstate.f = cl->p =luaF_newproto(L);
funcstate.f->source =luaS_new(L, name);/* create and anchor TString */lua_assert(iswhite(funcstate.f));/* do not need barrier here */
lexstate.buff = buff;
lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n =0;luaX_setinput(L,&lexstate, z, funcstate.f->source, firstchar);mainfunc(&lexstate,&funcstate);lua_assert(!funcstate.prev && funcstate.nups ==1&&!lexstate.fs);/* all scopes should be correctly finished */lua_assert(dyd->actvar.n ==0&& dyd->gt.n ==0&& dyd->label.n ==0);
L->top--;/* remove scanner's table */return cl;/* closure is on the stack, too */}