开始解释器篇。
解释器部分会写几节还说不准,因为,不少相关内容在之前的版本中是有覆盖到的。
同样,还是从解释器入口的 main 函数说起。
int main (int argc, char *argv[]) { int i; int result = 0; iolib_open (); strlib_open (); mathlib_open (); lua_register("argv", lua_getargv); if (argc < 2) manual_input(); else { for (i=1; i<argc; i++) if (strcmp(argv[i], "--") == 0) { lua_argc = argc-i-1; lua_argv = argv+i; break; } for (i=1; i<argc; i++) { if (strcmp(argv[i], "--") == 0) break; else if (strcmp(argv[i], "-") == 0) manual_input(); else if (strcmp(argv[i], "-v") == 0) printf("%s %s\n(written by %s)\n\n", LUA_VERSION, LUA_COPYRIGHT, LUA_AUTHORS); else { result = lua_dofile (argv[i]); if (result) fprintf(stderr, "lua: error trying to run file %s\n", argv[i]); } } } return result; }
程序上来先定义一个程序的返回值。按 C 语言惯例,程序返回 0 表示成功,非 0 表示失败。
打开几个库,io 库,字符串库,数学库。打开库的过程就是把库函数注册到全局符号表中去。
注册一个 argv 函数以在 Lua 脚本里取得命令行中给 Lua 脚本的参数。这些参数是保存在了 C 的执行环境中。注册函数用的是 lua_register 宏,上面的程序内置库的注册用的也是这个宏。
如果无参,则表示程序执行在交互模式。就是把命令行里的用户手动输入的内容做为 Lua 脚本程序来执行。
static void manual_input (void) { if (isatty(0)) { char buffer[250]; while (fgets(buffer, sizeof(buffer), stdin) != 0) lua_dostring(buffer); } else lua_dofile(NULL); /* executes stdin as a file */ }
isatty 是检查设备是否是某种终端类型,它定义在 POSIX 里的。
这里是在 windows 里分析的,所以用一个宏代替它,就是把标准输入当做一个 tty。
因此在 windows 里,isatty(0) 永远为真,也就是手动输入 manual_input 里是按行执行输入脚本代码的,通过 lua_dostring 执行。
回到 main 函数。
接着开解释命令行的参数。
第一个 for 循环是为了解析出 Lua 脚本的输入参数的位置和个数,就是从两个减号 "--" 开始的参数是 Lua 脚本的参数。
for (i=1; i<argc; i++) if (strcmp(argv[i], "--") == 0) { lua_argc = argc-i-1; lua_argv = argv+i; break; }
第二个 for 循环也是解析命令行输入的。
如果是两个减号"--",表示是 Lua 脚本的参数开始了,就停止。
如果是一个减号 "-",表示是交互模式,这个和无参时情况类似,调用的也是 manual_input 来执行用户的手动输入内容。
如果是 "-v",打印程序的版本,版权,作者信息。
否则,就是脚本文件的解释执行了。调用 lua_dofile 解释脚本文件。
如果执行脚本文件结果出错(就是 result 非 0 的情况),打印出错信息。
这一版本,新增了外部编译器,Lua 可以直接解释编译器编译过的 luac.out 格式的二进制文件, Lua 是如何区分脚本文件和编译过的二进制文件的呢?
----------------------------------------
到目前为止的问题:
> Lua 是如何区分脚本文件和编译过的二进制文件的呢?
----------------------------------------