经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Lua » 查看文章
lua函数定义
来源:cnblogs  作者:bytemode  时间:2018/12/17 9:42:57  对本文有异议

FuncState

proto结构数组保存函数原型信息;prev保存父函数体指针;actvar保存定义的局部变量;upvalues保存upvalue

Lua源码中,专门有一个结构体FuncState用来保存函数相关的信息.其实,即使没有创建任何函数,对于Lua而言也有一个最外层的FuncState数据.这个结构体的定义:

  1. typedef struct FuncState {
  2. Proto *f; /* current function header */
  3. Table *h; /* table to find (and reuse) elements in */
  4. struct FuncState *prev; /* enclosing function */
  5. struct LexState *ls; /* lexical state */
  6. struct lua_State *L; /* copy of the Lua state */
  7. struct BlockCnt *bl; /* chain of current blocks */
  8. int pc; /* next position to code (equivalent to `ncode') */
  9. int lasttarget; /* `pc' of last `jump target' */
  10. int jpc; /* list of pending jumps to `pc' */
  11. int freereg; /* first free register */
  12. int nk; /* number of elements in `k' */
  13. int np; /* number of elements in `p' */
  14. short nlocvars; /* number of elements in `locvars' */
  15. lu_byte nactvar; /* number of active local variables */
  16. upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */
  17. unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */
  18. } FuncState;

其中的Proto结构体数组用于保存函数原型信息,包括函数体代码(opcode),之所以使用数组,是因为在某个函数内,可能存在多个局部函数.而prev指针就是指向这个函数的”父函数体”的指针.

比如以下代码:

  1. function fun()
  2. function test()
  3. end
  4. end

那么,在保存test函数原型的Proto数据就存放在保存fun函数的FuncState结构体的p数组中,反之,保存test函数的FuncState.prev指针就指向保存func函数的FuncState指针.

接着看Funcstate结构体的成员,actvar数组用于保存局部变量,比如函数的参数就是保存在这里.另外还有一个存放upval值的upvalues数组.这里有两种不同的处理.如果这个upval是父函数内的局部变量,则生成的是MOVE指令用于赋值;如果对于父函数而言也是它的upval,则生成GET_UPVAL指令用于赋值.

当开始处理一个函数的定义时,首先调用open_func函数,创建一个新的Proto结构体用于保存函数原型信息,接着将该函数的FuncState的prev指针指向父函数.
最后当函数处理完毕时,调用pushclosure函数将这个新的函数的信息push到父函数的Proto数组中.

函数也是第一类值 可以存在变量里

最后,由于函数在Lua中是所谓的”first class type”,所以其实以下两段Lua代码是等价的:

  1. local function test()
  2. -- 可以test
  3. end
  4. --以上相当于 local test test = function() ... end
  5. local test = function ()
  6. --不可以调用test 以为第一类之定义完成之后才可以使用
  7. end

也就是说,其实是生成一段代码,用于保存函数test的相关信息,之后再将这些信息赋值给变量test,这里的test可以是local,也可以是global的,这一点跟一般的变量无异.

函数定义词法分析

所以在与函数定义相关的词法分析代码中:

  1. static void funcstat (LexState *ls, int line) {
  2. /* funcstat -> FUNCTION funcname body */
  3. int needself;
  4. expdesc v, b;
  5. luaX_next(ls); /* skip FUNCTION */
  6. needself = funcname(ls, &v);
  7. body(ls, &b, needself, line);
  8. luaK_storevar(ls->fs, &v, &b);
  9. luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
  10. }

上面的变量v首先在funcname函数中获得该函数的函数名,变量b在进入函数body之后可以得到函数体相关的内容.在这之后的luaK_storevar调用,就是把b的值赋值给v,也就是前面提到的函数体赋值给函数名.

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号