Lua源码解析之一:lexical

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Lunar_lty/article/details/50196069

我们知道,任何高级一点的编译器,在解析源代码时,都需要进行词法分析。而词法分析的过程就是先识别token的一个过程,总体来说,lua里面的token大致分为:

1. 数字和字符串

2. 特殊字符:包括运算符和括号

3. 关键词

对于每一类token lua都有唯一的id与之对应,此id用int来表示,对于第2种类型,直接用该字符的ASCII码来表示,对于1,3两类,则定义一组枚举,为了与第2种区别开,枚举从257开始。比如关键字break 对应 TK_BREAK,do 对应 TK_DO。


先来看看luaX_next,它用来识别下一个token,会调用 llex 函数,返回token type和seminfo。有了token,接下来就会分析一条条的语句。

一个statementlist 的 production为: statlist -> { stat [`;'] } ,下面先将一个statement的grammer production列出:

stat = { ifstat | dostat | whilestat | functionstat | localstat | retstat | forstat | repeatestat | goto | breakstat  | exprstat }


以ifstat为例:

ifstat -> IF exprstat THEN statlist END

exprstat -> subexpr

subexpr ->(simpleexp | unop subexpr) { binop subexpr }

simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | suffixedexp */


关键词以大写表示,在读完IF token之后,接着读exprstat,exprstat继续向下分解为subexpr,接着是simpleexp,直至基础数据NUMBER为止。这实际上就是所谓的自顶向下分析法。


说到这里,似乎词法分析很简单,单论词法分析,lua确实很简单,但lua是解释型的脚本语言,实际在是一边做词法分析,一边再做语义分析,同时根据语义分析结果,生成lua指令。也就是说,在词法分析的同时,干了很多事情。


具体来看看lua指令,一个lua指令用一个32位的整数来表示。其中6bit用于表示指令码,8bit表示操作数A,9bit表示B,9bit表示C(这种做法在逻辑上有点类似汇编),操作数一般来说分几种类型:

1) R(x): 表示该操作数在寄存器中

2) Kst(x):表示该操作数在常量表中

3) RK(x):表示该操作数如果是常量的话,则表示2),否则表示1)

举例:指令OP_MOVE,看代码注释为R(A) := R(B),这就表示将寄存器B的值赋值给寄存器A。

到这里不禁要问,lua寄存器是个什么概念?我们知道,对汇编来说,具体的寄存器是使用具体寄存器名字来指定的,例如mov ax, bx ...,而lua则由下标来指向寄存器。实质上R(x) = [base+x] ,其中base表示当前函数调用的一个基地址。


lua解析是以function为单位来进行的,加载一个文件,可以看作是在一个全局的大函数里面对文件进行解析。那么,最终生成的指令都会放在归属函数Proto的opcodes数组里面。执行一个函数的时候,VM直接取指令分析操作数,接着往下执行就可以了。


在下一篇中我将重点表述语法分析,以及生成具体指令的这么一个过程。



猜你喜欢

转载自blog.csdn.net/Lunar_lty/article/details/50196069