本文转自:http://www.cnblogs.com/zxh1210603696/p/4458473.html
#include "lua.hpp"#include <iostream> using namespace std;#pragma comment(lib, "lua5.1.lib")struct lua_guard{lua_State *pL;lua_guard(lua_State *s) :pL(s){}~lua_guard(){ lua_close(pL); } };int main(){lua_guard g(lua_open());luaL_openlibs(g.pL);int err;if ((err = luaL_dofile(g.pL, "mylua.lua") != 0)){throw runtime_error("open lua file error");}system("pause");return 0; }
首先利用lua提供的函数luaL_dofile来执行一个lua脚本。
可以看到有两个过程,首先luaL_loadfile函数将lua文件加载进来然后进行词法语法语义分析,得到一个closure函数放入栈中,接着调用lua_pcall函数来执行栈顶的closure。
我们先来看看第一个过程:
首先在luaL_loadfile中真正加载lua文件的是lua_load函数
在lua_load中调用了luaD_protectedparser来进行parse过程
在luaD_protectedparser中又调用了f_parser
在f_parser中根据一些选择来分别处理不同的情况,我们示例中会跑到luaY_parser函数中去,在luaY_parser中会调用luaX_next进行分析,这个函数会首先读取源文件中的第一个token
最后在luaX_next中调用了llex,llex是真正切出token的例程
在读取了第一个token后luaX_next返回,相关的词法信息保存在了lexstate中,接着luaY_parser调用chunk函数来递归的生成一个chunk块
在chunk中循环读取下一个token并根据token的类型一层一层的递归的生成chunk,将chunks根据层次组合成tree,位于root的是最外层chunk
在分析完lua脚本后会返回到f_parser,在f_parser中接着调用luaF_newLclosure来将分析结果包裹成一个closure然后push到lua栈中
接下来分析第二个过程:
当第一个过程完成后lua栈顶存放着一个closure,luaL_dofile中调用lua_pcall让其来调用这个closure:
在lua_pcall中调用了f_call
f_call中又接着调用了luaD_call,传入了被调用的closure和参数个数
最后在luaD_call中调用了luaV_execute来执行closure中的opcode
luaV_execute既是lua虚拟机执行opcode的函数,其中可以看到一个无限循环,利用switch (GET_OPCODE(i))来根据不同的opcode进行不同的过程
void luaV_execute (lua_State *L, int nexeccalls) {LClosure *cl;StkId base;TValue *k;const Instruction *pc;reentry: /* entry point */lua_assert(isLua(L->ci));pc = L->savedpc;cl = &clvalue(L->ci->func)->l;base = L->base;k = cl->p->k;/* main loop of interpreter */for (;;) {const Instruction i = *pc++;StkId ra;if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc);if (L->status == LUA_YIELD) { /* did hook yield? */L->savedpc = pc - 1;return;}base = L->base;}/* warning!! several calls may realloc the stack and invalidate `ra' */ra = RA(i);lua_assert(base == L->base && L->base == L->ci->base);lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);lua_assert(L->top == L->ci->top || luaG_checkopenop(i));switch (GET_OPCODE(i)) {case OP_MOVE: {setobjs2s(L, ra, RB(i));continue;}case OP_LOADK: {setobj2s(L, ra, KBx(i));continue;}case OP_LOADBOOL: {setbvalue(ra, GETARG_B(i));if (GETARG_C(i)) pc++; /* skip next instruction (if C) */continue;}case OP_LOADNIL: {TValue *rb = RB(i);do {setnilvalue(rb--);} while (rb >= ra);continue;}case OP_GETUPVAL: {int b = GETARG_B(i);setobj2s(L, ra, cl->upvals[b]->v);continue;}case OP_GETGLOBAL: {TValue g;TValue *rb = KBx(i);sethvalue(L, &g, cl->env);lua_assert(ttisstring(rb));Protect(luaV_gettable(L, &g, rb, ra));continue;}case OP_GETTABLE: {Protect(luaV_gettable(L, RB(i), RKC(i), ra));continue;}case OP_SETGLOBAL: {TValue g;sethvalue(L, &g, cl->env);lua_assert(ttisstring(KBx(i)));Protect(luaV_settable(L, &g, KBx(i), ra));continue;}case OP_SETUPVAL: {UpVal *uv = cl->upvals[GETARG_B(i)];setobj(L, uv->v, ra);luaC_barrier(L, uv, ra);continue;}case OP_SETTABLE: {Protect(luaV_settable(L, ra, RKB(i), RKC(i)));continue;}case OP_NEWTABLE: {int b = GETARG_B(i);int c = GETARG_C(i);sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));Protect(luaC_checkGC(L));continue;}case OP_SELF: {StkId rb = RB(i);setobjs2s(L, ra+1, rb);Protect(luaV_gettable(L, rb, RKC(i), ra));continue;}case OP_ADD: {arith_op(luai_numadd, TM_ADD);continue;}case OP_SUB: {arith_op(luai_numsub, TM_SUB);continue;}case OP_MUL: {arith_op(luai_nummul, TM_MUL);continue;}case OP_DIV: {arith_op(luai_numdiv, TM_DIV);continue;}case OP_MOD: {arith_op(luai_nummod, TM_MOD);continue;}case OP_POW: {arith_op(luai_numpow, TM_POW);continue;}case OP_UNM: {TValue *rb = RB(i);if (ttisnumber(rb)) {lua_Number nb = nvalue(rb);setnvalue(ra, luai_numunm(nb));}else {Protect(Arith(L, ra, rb, rb, TM_UNM));}continue;}case OP_NOT: {int res = l_isfalse(RB(i)); /* next assignment may change this value */setbvalue(ra, res);continue;}case OP_LEN: {const TValue *rb = RB(i);switch (ttype(rb)) {case LUA_TTABLE: {setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));break;}case LUA_TSTRING: {setnvalue(ra, cast_num(tsvalue(rb)->len));break;}default: { /* try metamethod */Protect(if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))luaG_typeerror(L, rb, "get length of");)}}continue;}case OP_CONCAT: {int b = GETARG_B(i);int c = GETARG_C(i);Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));setobjs2s(L, RA(i), base+b);continue;}case OP_JMP: {dojump(L, pc, GETARG_sBx(i));continue;}case OP_EQ: {TValue *rb = RKB(i);TValue *rc = RKC(i);Protect(if (equalobj(L, rb, rc) == GETARG_A(i))dojump(L, pc, GETARG_sBx(*pc));)pc++;continue;}case OP_LT: {Protect(if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))dojump(L, pc, GETARG_sBx(*pc));)pc++;continue;}case OP_LE: {Protect(if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))dojump(L, pc, GETARG_sBx(*pc));)pc++;continue;}case OP_TEST: {if (l_isfalse(ra) != GETARG_C(i))dojump(L, pc, GETARG_sBx(*pc));pc++;continue;}case OP_TESTSET: {TValue *rb = RB(i);if (l_isfalse(rb) != GETARG_C(i)) {setobjs2s(L, ra, rb);dojump(L, pc, GETARG_sBx(*pc));}pc++;continue;}case OP_CALL: {int b = GETARG_B(i);int nresults = GETARG_C(i) - 1;if (b != 0) L->top = ra+b; /* else previous instruction set top */L->savedpc = pc;switch (luaD_precall(L, ra, nresults)) {case PCRLUA: {nexeccalls++;goto reentry; /* restart luaV_execute over new Lua function */}case PCRC: {/* it was a C function (`precall' called it); adjust results */if (nresults >= 0) L->top = L->ci->top;base = L->base;continue;}default: {return; /* yield */}}}case OP_TAILCALL: {int b = GETARG_B(i);if (b != 0) L->top = ra+b; /* else previous instruction set top */L->savedpc = pc;lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);switch (luaD_precall(L, ra, LUA_MULTRET)) {case PCRLUA: {/* tail call: put new frame in place of previous one */CallInfo *ci = L->ci - 1; /* previous frame */int aux;StkId func = ci->func;StkId pfunc = (ci+1)->func; /* previous function index */if (L->openupval) luaF_close(L, ci->base);L->base = ci->base = ci->func + ((ci+1)->base - pfunc);for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */setobjs2s(L, func+aux, pfunc+aux);ci->top = L->top = func+aux; /* correct top */lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);ci->savedpc = L->savedpc;ci->tailcalls++; /* one more call lost */L->ci--; /* remove new frame */ goto reentry;}case PCRC: { /* it was a C function (`precall' called it) */base = L->base;continue;}default: {return; /* yield */}}}case OP_RETURN: {int b = GETARG_B(i);if (b != 0) L->top = ra+b-1;if (L->openupval) luaF_close(L, base);L->savedpc = pc;b = luaD_poscall(L, ra);if (--nexeccalls == 0) /* was previous function running `here'? */return; /* no: return */else { /* yes: continue its execution */if (b) L->top = L->ci->top;lua_assert(isLua(L->ci));lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);goto reentry;}}case OP_FORLOOP: {lua_Number step = nvalue(ra+2);lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */lua_Number limit = nvalue(ra+1);if (luai_numlt(0, step) ? luai_numle(idx, limit): luai_numle(limit, idx)) {dojump(L, pc, GETARG_sBx(i)); /* jump back */setnvalue(ra, idx); /* update internal index... */setnvalue(ra+3, idx); /* ...and external index */}continue;}case OP_FORPREP: {const TValue *init = ra;const TValue *plimit = ra+1;const TValue *pstep = ra+2;L->savedpc = pc; /* next steps may throw errors */if (!tonumber(init, ra))luaG_runerror(L, LUA_QL("for") " initial value must be a number");else if (!tonumber(plimit, ra+1))luaG_runerror(L, LUA_QL("for") " limit must be a number");else if (!tonumber(pstep, ra+2))luaG_runerror(L, LUA_QL("for") " step must be a number");setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));dojump(L, pc, GETARG_sBx(i));continue;}case OP_TFORLOOP: {StkId cb = ra + 3; /* call base */setobjs2s(L, cb+2, ra+2);setobjs2s(L, cb+1, ra+1);setobjs2s(L, cb, ra);L->top = cb+3; /* func. + 2 args (state and index) */Protect(luaD_call(L, cb, GETARG_C(i)));L->top = L->ci->top;cb = RA(i) + 3; /* previous call may change the stack */if (!ttisnil(cb)) { /* continue loop? */setobjs2s(L, cb-1, cb); /* save control variable */dojump(L, pc, GETARG_sBx(*pc)); /* jump back */}pc++;continue;}case OP_SETLIST: {int n = GETARG_B(i);int c = GETARG_C(i);int last;Table *h;if (n == 0) {n = cast_int(L->top - ra) - 1;L->top = L->ci->top;}if (c == 0) c = cast_int(*pc++);runtime_check(L, ttistable(ra));h = hvalue(ra);last = ((c-1)*LFIELDS_PER_FLUSH) + n;if (last > h->sizearray) /* needs more space? */luaH_resizearray(L, h, last); /* pre-alloc it at once */for (; n > 0; n--) {TValue *val = ra+n;setobj2t(L, luaH_setnum(L, h, last--), val); luaC_barriert(L, h, val);}continue;}case OP_CLOSE: {luaF_close(L, ra);continue;}case OP_CLOSURE: {Proto *p;Closure *ncl;int nup, j;p = cl->p->p[GETARG_Bx(i)];nup = p->nups;ncl = luaF_newLclosure(L, nup, cl->env);ncl->l.p = p;for (j=0; j<nup; j++, pc++) {if (GET_OPCODE(*pc) == OP_GETUPVAL)ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];else {lua_assert(GET_OPCODE(*pc) == OP_MOVE);ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));}}setclvalue(L, ra, ncl);Protect(luaC_checkGC(L));continue;}case OP_VARARG: {int b = GETARG_B(i) - 1;int j;CallInfo *ci = L->ci;int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1;if (b == LUA_MULTRET) {Protect(luaD_checkstack(L, n));ra = RA(i); /* previous call may change the stack */b = n;L->top = ra + n;}for (j = 0; j < b; j++) {if (j < n) {setobjs2s(L, ra + j, ci->base - n + j);}else {setnilvalue(ra + j);}}continue;}}} }