从 lua.c 的 main 函数开始,看看在代码执行过程中中发生了什么?
1
2
3
4
5
|
if (argc < 2) { puts ( "usage: lua filename [functionnames]" ); return ; } |
Lua1.0 执行时至少要有一个参数,否则直接退出。
接着是三个 lua_register 。
1
2
3
|
lua_register ( "callfunc" , callfunc); lua_register ( "execstr" , execstr); lua_register ( "test" , test); |
来看看 lua_register 是干什么的? 可以看到 lua_register 是一个宏,定义在 lua.h 中:
1
|
#define lua_register(n,f) (lua_pushcfunction(f), lua_storeglobal(n)) |
再分别看下 lua_pushcfunction,和 lua_storeglobal,
opcode.c 文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/* ** Push an object (tag=cfunction) to stack. Return 0 on success or 1 on error. */ int lua_pushcfunction (lua_CFunction fn) { if ((top-stack) >= MAXSTACK-1) { lua_error ( "stack overflow" ); return 1; } tag(top) = T_CFUNCTION; fvalue(top++) = fn; return 0; } |
lua_pushcfunction 的参数是一个函数指针,调用结束时,栈顶的 Object 类型被置为 T_CFUNCTION, 值被设置为传入的函数指针实际参数 fn 。 这里说的这个栈是 lua 和 c 相互调用的一个纽带,如同这里用 c 代码实现的一个方法,被转化成 T_CFUNCTION 类型的 Object.
opcode.c 文件
1
2
3
4
5
6
7
8
9
10
11
12
|
/* ** Store top of the stack at a global variable array field. ** Return 1 on error, 0 on success. */ int lua_storeglobal ( char *name) { int n = lua_findsymbol (name); if (n < 0) return 1; if (tag(top-1) == T_MARK) return 1; s_object(n) = *(--top); return 0; } |
table.c 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/* ** Given a name, search it at symbol table and return its index. If not ** found, allocate at end of table, checking oveflow and return its index. ** On error, return -1. */ int lua_findsymbol ( char *s) { int i; for (i=0; i<lua_ntable; i++) if (streq(s,s_name(i))) return i; if (lua_ntable >= MAXSYMBOL-1) { lua_error ( "symbol table overflow" ); return -1; } s_name(lua_ntable) = strdup(s); if (s_name(lua_ntable) == NULL) { lua_error ( "not enough memory" ); return -1; } s_tag(lua_ntable++) = T_NIL; return (lua_ntable-1); } |
lua_storeglobal 的作用是把全局变量存入符号表里。参数是一个字符串,就是全局变量的名字,lua_findsymbol 在符号表中查找由参数指定的字符串,如果找到,返回它在符号表中的 index, 否则,在表尾新建一个符号,返回它在表中的 index。
符号表: table.c 文件中
1
2
3
4
5
6
7
|
static Symbol tablebuffer[MAXSYMBOL] = { { "type" ,{T_CFUNCTION,{lua_type}}}, { "tonumber" ,{T_CFUNCTION,{lua_obj2number}}}, { "next" ,{T_CFUNCTION,{lua_next}}}, { "nextvar" ,{T_CFUNCTION,{lua_nextvar}}}, { "print" ,{T_CFUNCTION,{lua_print}}} }; |
我们看下符号的定义:
1
2
3
4
5
|
typedef struct { char *name; Object object; } Symbol; |
其包括一个符号的名字和一个对应的 Object 类型。
lua_storeglobal 在 lua_findsymbol 返回后,利用返回的 index 找到相应的符号,设置其 Obejct 字段。 到此,方法注册 lua_register ("callfunc", callfunc); 调用完成。 所以, lua_register ("callfunc", callfunc); 的作用就是在全局符号表里注册名为 "callfunc" 的函数, 当在 Lua 脚本里调用时,调的是 callfunc 这个 C 函数。 其它的函数注册与之相同。
函数库的注册:
1
2
3
|
iolib_open (); strlib_open (); mathlib_open (); |
可以看到,库函数的注册也是用上面说的 lua_register 宏。 调用结束后,所有的系统自带的函数已经注册完毕。
到此,环境准备完毕,开始干活:
1
|
lua_dofile (argv[1]); |
后面的代码是把从命令行第二个参数开始的参数都做为无参函数调用来处理了。