我要先记录下在 lparser.h
的定义。
我现在做的主要是从 REPL 输入来看 Lua 的 parser,但是实际上区别不大,因为 Lua 在读入的时候抽象了一个 Zio 的结构,这个结构会处理不同的读入。所以无论怎么调用,入口都在 luaY_parser
方法上。
在这里,像 dyd 跟 buff 的初始化是在 ldo.c
里面的 luaD_protectedparser
做的。
并且是在 ldo.c
里面的 f_parser
方法调用 luaY_parser
,从这里进入 parse 的过程。f_parser
方法会判断从 Zio 读入的第一个字符,来确定是不是 Lua 的字节码,这个以后但是不知道是什么时候会讨论到。
对于 luaY_parser
来说,主要是一些初始化的内容,其中主要初始化 LexState lexstate
FuncState funcstate
,用来在 mainfunc
中使用。
mainfunc
我理解就是主函数的意思吧,是执行的最初的环境。
open_func
设置 FuncState *fs
的值,记录 ls->fs
到 fs->prev
并修改成当前的 fs
。
enterblock
方法设置 BlockCnt *bl
,而且把 bl->previous
设置成 fs->bl
并把 fs->bl
改成设置后的 bl
。
初始化 expdesc v
建立 _ENV
的 upvalue。
读入第一个 token。luaX_next
方法在 llex.c 里面。
这个方法是具体解析的过程了,statlist 我的理解就是 statement list。以为一开始设置了主函数是多返回值,所以这里是一个 list。具体 Lua 的语法可以参考这里 The Complete Syntax of Lua
block_follow
判断当前的 token 后面是否跟一个 block。
statement
应该算是核心的一个方法了,毕竟表达式都是从这里展开了,关于这点,我也是看了 Lua 的语法才了解到,不看 reference 的确踩了坑。我们接下来就顺着 statement 的方法体看吧。
为了方便我们知道 llex 读入的 token 是什么,我这里记录一下,token 的 int 值。
enterlevel
将 lua_State *L
的 nCcalls
的加 1。虽然看处理是记录增加了 C level 的 call,但是是为了什么,我还想明白。
如果 statement
遇到 TK_IF
,则执行 ifstat(ls, line)
在 test_then_block
方法里面,调用了 expr(ls, &v);
。这个地方是为了解析 if
后面的表达式。所以,我们要先看看 Lua 是怎么做表达式这部分的。
这个就是表达式的解析方法,其中还有 unop
跟 binop
,运算符的优先级跟结合性。这些都可以看下面。
不过里面有不少是 lcode.c
的方法调用,感觉应该可以先看那部分内容可能会更好,不过现在就暂时跳过吧,而且还有跳转的部分,现在也不是太懂。
以下是 whilestat
相关的代码。
以下是 forstat
的相关代码。
在 forstat
的执行里面,需要申请到一些变量,这就需要下面的代码了。
以下是 repeatstat
的相关代码。
以下是 funcstat
的相关代码。
以下是 localfunc
的相关代码。
以下是 localstat
的相关代码。
以下是 labelstat
和 gotostat
的相关代码。
以下是 retstat
的相关代码。
以下是 exprstat
的相关代码。