开始解释器篇。
解释器部分会写几节还说不准,因为,不少相关内容在之前的版本中是有覆盖到的。
同样,还是从解释器入口的 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 是如何区分脚本文件和编译过的二进制文件的呢?
----------------------------------------