上 构建Lua解释器Part7:构建完整的语法分析器(11)


图15
图15的结果 , 就是代码片段5中 , 第365行代码执行的结果 , 在完成操作符识别以后 , 要识别和处理紧随操作符的token < , 100 > , 此时函数递归调用了自己 , 目的是识别和处理这个token , 并将其转化为一个结构 。得到图16的结果:
图16
我们可以观察到 , token指针又前进了一步 , 每个处理完以后 , 就会将当前token的值 , 设置为下一个token的 。再次回顾代码片段5 , 此时第370行要对unopr和变量 , 进行整合 , 于是得到图17的效果:
图17
我们可以观察到 , 实际上 , 这里是对常量进行处理 , 面对数值常量 , ’-‘运算符操作 , 是将结果直接算好 , 并存入结构的 , 读者可以将任何其他数值类型的值带入 , 也是这样的操作流程 。不过当token ‘-‘后面紧跟的token是类型的话 , 会怎么处理呢?首先 , 和刚刚讨论过的例子一样 , expr函数首先要识别的是unopr是否存在 , 如果存在 , 那么识别单目操作符后面的那个exp , 我们前面在讨论的时候也讨论过 , 对于expr函数处理类型的token , 最后生成的结构有几种形态 , 我们将其整理成表格如下所示:
e->k使用的字段说明
e->
表示值在栈中 , R(e->)

上  构建Lua解释器Part7:构建完整的语法分析器

文章插图
e->
表示值在中 , [e->]
e->u.ind.vt =
e->u.ind.t
e->u.ind.idx
表示值在[e->u.ind.t][RK(e->u.ind.idx)]
上面这个表格中 , 使用字段那一列 , 没有赋值运算的 , 代表值是可以变动的 , 有赋值运算的则代表值一定是固定的 。我们现在来看一下-a的例子 , 假设现在已经完成了操作符和操作符后面的exp识别 , 得到图18的情况:
图18
此时要将unopr和结构整合 , 那么就要生成指令了 , 在生成这个指令之前 , 首先要将如图18里 , 结构的 , 转化为指令 , 转换的流程 , 前面也已经讨论过 , 这里就是直接生成指令 , 生成结果如图19所示:
图19
我们可以看到 , 生成的指令过程中 , 将指令的A域赋值为原来指向的值 , 尔后自增1 , 然后改变对应的值 , 读者可以仔细查看图19 。现在我们要生成一个新的指令 , 这个指令的意思是 , 将目标对象的值取负 。我们此时要生成的指令为 , 其中A的值为上一条指令的A域 , 而B的值则由图19中的来指定 , 于是有:
图20
我们可以看到 , 当的类型为时 , e->指向刚刚生成那条指令的操作目标 。现在我们完成了UNM操作的论述了 , 后面我们将继续讨论其他单目运算操作 。
我们现在要论述的第二种情况 , 则是expr前面是’#‘的情况 , 一般来说 , 这个指令是用来计算字符串或者table的长度的 , 这些对象 , 首先要先被加载到栈中 , 也就是说 , 首先要生成创建指定对象、或者将指定对象加载到栈中的指令 , 此时我们也会得到一个类型为的结构 , 然后根据这个结构 , 生成指令 , 其中A的值由指定 , 而B的值则是e->(也就是上一条指令的操作目标) 。其实整个流程和前面讨论过的流程类似 , 读者可以自行将这个流程分析一次 。