首页 > 其他 > 详细

《lua设计与实现》第6章 指令的解析与执行--6.4 函数相关的操作指令

时间:2021-05-16 18:46:50      阅读:18      评论:0      收藏:0      [点我收藏+]

    在下面的示例中,(3)的prev成员(2),(2)的prev成员(1),(1)的prev成为NULL。

g = 10              -- (1) 全局环境的 FuncState: 其 prev 为 NULL
function fun ()     -- (2) fun  的 FuncState: 其 prev 指向(1)
    local a = 2
    function test() -- (3) test 的 FuncState: 其 prev 指向(2)
        local b = 1
        -- g -> test -> fun -> 全局环境 -> VGLOBAL
        -- b -> test ->VLOCAL
        -- a -> test -> fun -> VUPVAL
        print(a,b,g)
    end
    test()
end
fun()

    Lua解释器在解析完某个环境(比如全局环境)中定义的函数之后,生成的 Proto 结构体数据必然也会存放在该环境的 Proto结构体数组中,最后一并返回。测试代码:

function test()
end

     ChunkSpy编译出来的指令如下。第一层函数即全局环境,这一层的第一条指令是一个closure语句,用于定义函数;紧跟着是一条setglobal指令,用于将函数体的信息、赋值给第二层的函数test。

; function [0] definition (level 1)
; 0 upvalues, 0 params, 2 stacks
.function  0 0 2 2
.const  "test"  ; 0

; function [0] definition (level 2)
; 0 upvalues, 0 params, 2 stacks
.function  0 0 0 2
[1] return     0   1      
; end of function

[1] closure    0   0        ; 0 upvalues
[2] setglobal  0   0        ; test
[3] return     0   1      
; end of function

    函数定义相关指令 OP_CLOSURE 格式如下:

typedef enum {
/*A: 存放函数的寄存器  B: Proto数组的索引  C: 无 */
// ......
OP_CLOSURE,/*A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))*/
// ......
} OpCode;

      解释器会依次走过以下函数(箭头左方),右边是其对应的EBNF表示

chunk    -> {stat [;]}
stat     -> funcstat
funcstat -> FUNCTION funcname body

      函数调用堆栈,funcstat处理函数的定义,即如何把函数体信息和变量结合在一起;body处理函数体的解析。

int dofile(const char *filename, const char *cmd);
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename);
LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname);
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef);
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
static void f_parser (lua_State *L, void *ud);
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name);
// EBNF 对应函数
static void chunk (LexState *ls);
static int statement (LexState *ls);
static void body (LexState *ls, expdesc *e, int needself, int line);
static void funcstat (LexState *ls, int line);

     主要函数body

static void body (LexState *ls, expdesc *e, int needself, int line) {
  /* body ->  `(‘ parlist `)‘ chunk END */
  FuncState new_fs;
  open_func(ls, &new_fs); //主要用于初始化 new_fs

  //完成函数体的解析,解析结果保存在局部变量 new_fs 的 Proto *f 中 。
  new_fs.f->linedefined = line;
  checknext(ls, ();
  if (needself) {
    new_localvarliteral(ls, "self", 0);
    adjustlocalvars(ls, 1);
  }
  parlist(ls);
  checknext(ls, ));
  chunk(ls);
  new_fs.f->lastlinedefined = ls->linenumber;
  check_match(ls, TK_END, TK_FUNCTION, line);

  //将最后分析的结果保存到 new_fs 的 Proto 中
  close_func(ls);
  // 主要功能是把 new_fs 的 Proto 指针保存到父函数 FuncState 的 Proto指针的 p 数组中
  pushclosure(ls, &new_fs, e);
}

 

    用于存放函数信息的结构体是Closure

#define ClosureHeader \
    CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist;     struct Table *env

typedef struct CClosure {
  ClosureHeader;
  lua_CFunction f;
  TValue upvalue[1];
} CClosure;


typedef struct LClosure {
  ClosureHeader;
  struct Proto *p;  //用于存放解析函数体代码之后的指令
  UpVal *upvals[1]; //用于保存外部引用的局部变量
} LClosure;


typedef union Closure {
  CClosure c;
  LClosure l;
} Closure;

 

    funcstat 函数 

 

《lua设计与实现》第6章 指令的解析与执行--6.4 函数相关的操作指令

原文:https://www.cnblogs.com/yyqng/p/14773866.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!