看一下和函数相关的数据结构和方法。
数据结构
typedef struct LocVar
{
TaggedString *varname; /* NULL signals end of scope */
int line;
} LocVar;
局部变量描述信息,这个主要是调试时有用,也就是编译时打开了调试选项。
varname 局部变量的名字,如果为空,表示函数的局部变量结束。
line 局部变量开始定义的地方。
/*
** Function Headers*/
typedef struct TFunc
{
struct TFunc *next;
int marked;
int size;
Byte *code;
int lineDefined;
char *fileName;
LocVar *locvars;
} TFunc;
函数描述信息。
next : 下一个函数,所有有函数连成链表,以便垃圾回收。
marked : 垃圾回收标签。
size : 函数的大小。
code : 函数的字节码。
lineDefined : 定义函数行号。
fileName : 定义函数的文件名。
locvars : 函数的所有局部变量。
func.h 头文件中定义的几个对外接口,前四个函数简单的看一下。后面的四个都是和调试相关的,先放一放,留待以后再分析。
/*
** Initialize TFunc struct
*/
void luaI_initTFunc (TFunc *f)
{
f->next = NULL;
f->marked = 0;
f->size = 0;
f->code = NULL;
f->lineDefined = 0;
f->fileName = NULL;
f->locvars = NULL;
}
初始化函数的数据结构。
/*
** Insert function in list for GC
*/
void luaI_insertfunction (TFunc *f)
{
lua_pack();
f->next = function_root;
function_root = f;
f->marked = 0;
}
函数插入函数链表,以便进行垃圾回收。
/*
** Free function
*/
void luaI_freefunc (TFunc *f)
{
luaI_free (f->code);
luaI_free (f->locvars);
luaI_free (f);
}
释放函数内存空间。
/*
** Garbage collection function.
** This function traverse the function list freeing unindexed functions
*/
Long luaI_funccollector (void)
{
TFunc *curr = function_root;
TFunc *prev = NULL;
Long counter = 0;
while (curr)
{
TFunc *next = curr->next;
if (!curr->marked)
{
if (prev == NULL)
function_root = next;
else
prev->next = next;
luaI_freefunc (curr);
++counter;
}
else
{
curr->marked = 0;
prev = curr;
}
curr = next;
}
return counter;
}
垃圾回收。
遍历函数链表,释放没有 marked 的函数,同时调整链表指针。
这几个看到的代码都比较直接,后面的几个调试相关的代码相对来说复杂一点。
调试相关代码有一个比较好辨识的地方是,他们基本上都接在一个以 lua_debug 为条件的 if 判断里。
比如:
if (lua_debug)
luaI_registerlocalvar(name, lua_linenumber
还有我们之前看到的 luaI_codedebugline,记录下脚本代码的行号的。
可以看到,他在 lex.c 中的调用就也是这样:
if (lua_debug)
luaI_codedebugline(linelasttoken);
调试相关的信息还有的在执行时可以加回调的地方。
具体的描述可以参考下手册里的描述。
调试相关信息和程序的具体功能关系不大,暂时忽略它对程序具体功能分析并无影响。
----------------------------------------
到目前为止的问题:
> lua_parser 是什么? do_dump 方法里调的那几个方法又分别是干什么的?
----------------------------------------