这里根据 luac.c 里的函数调用顺序,依次展开相关的代码。首先要看的就是 lua_openfile,该函数定义于 inout.c 中:
数据结构
/* ** Function to open a file to be input unit. ** Return the file. */ FILE *lua_openfile (char *fn) { lua_setinput (fileinput); if (fn == NULL) { fp = stdin; fn = "(stdin)"; } else fp = fopen (fn, "r"); if (fp == NULL) return NULL; lua_linenumber = 1; lua_parsedfile = luaI_createfixedstring(fn)->str; return fp; }
函数一开始调用 lua_setinput,传给它一个函数指针。
lua_setinput 定义于 lex.c 中,给词法分析器一个函数指针,之后词法分析程序须要从该函数指针中获得一个个的输入字符。
这里 lua_setinput 的实际输入参数是 fileinput,fileinput 定义以下:
模块化
/* ** Function to get the next character from the input file */ static int fileinput (void) { return fgetc (fp); }
能够看出,这个函数的做用就是每次调用它时从文件中取得一个字符。
回到 lua_openfile ,若是传入的文件名为空,则程序认为从标准输入读入内容。设置文件描述符为标准输入 stdin,设置它的文件名为 “(stdin)”。
若是传入正常的文件名,则打开它。若是打开失败,返回 NULL。
设置当前的行号为 1。
设置当前的要分析的文件为当前打开的文件。luaI_createfixedstring 函数是在 Lua 的字符串存储空间中生成一个不可回收的字符串,这个方法之后会提到。
最后,函数返回文件描述符 fp;
lua_openfile 分析完了。
再看看相应的 lua_closefile
函数
/* ** Function to close an opened file */ void lua_closefile (void) { if (fp != NULL && fp != stdin) { fclose (fp); fp = NULL; } }
这个函数就是关闭由 lua_openfile 打开的文件。
lua_openstring, lua_closestring 和上面的打开关闭文件的操做相似,就再也不重复了。
注意,lua_openstring 时,给它设置的文件名为 "(string)", 这个格式和上面的以标准输入为输入文件的文件名格式相同。
这样是为了程序上的统一,就是看到文件是一个括号里有一个字符串,就知道文件并不是真正的文件,而只是为了维持写程序时概念上的统一。
这也是写程序中比较经常使用的技巧,就是把特例转化为某种特殊的通常状况。
到这里,和编译器相关的 inout.c 中的内容已经说完了。这里能够回答在编译器那里提出的 compile 里打开关闭文件相关的问题了。
那里提出的为何要调用 lua_openfile 这样的问题,这里解答一下,把输入输出这样的放到一块是出于设计上的考量,程序结构很清晰。
再夸一句,Lua 的设计作的很好,模块化作得很漂亮,代码质量也很高。
luac.c 里提到和打开关闭文件相关的问题已经解答了。不过,在上面的看代码的过程当中又发现一些新的问题,列在下面:
> lua_setinput 在词法分析里的做用?相关的词法分析内容又是什么?
> luaI_createfixedstring 是什么? 那个 TaggedString 是个什么数据结构?
记点题外话,其实也不算是偏题太远。目前计划的是 Lua2.4 先跟编译器这条线儿,这条线儿结束了,再看看解释器那条。只看代码,写代码相关的东西,原理性的东西,不影响解释的状况下,尽可能少说。由于原理性的东西,网上仍是比较多的,相关的书籍也有不少。这里说的原理性的东西主要是指编译原理相关的。
----------------------------------------
记一下到目前为止的问题:
inout.c
> lua_setinput 在词法分析里的做用?相关的词法分析内容又是什么?
> luaI_createfixedstring 是什么? 那个 TaggedString 是个什么数据结构?
luac.c
> do_compile 里的 TFunc 是什么?那个初始化 luaI_initTFunc 是什么?
> lua_parser 是什么? do_dump 方法里调的那几个方法又分别是干什么的?
----------------------------------------
lua