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


图34
在完成了第一个exp的识别之后 , 调用函数获得下一个token , 我们获得操作符 , token  , 此时要进入“中序处理流程” , 也就是代码片段5中的第380行代码函数的执行 。函数在这种情况下会做什么呢?其运作流程如下所示:
结合图34的情况 , 现在将结构转化为指令 , 就得到了图35的情况:
图35
完成入栈指令生成之后 , 现在要生成的指令和指令 , 得到图36的效果:
图36
图36的信息量很大 , 首先我们生成了指令 , 目前的A域并不是最终值 , 在最后一个指令被处理完以后 , 它会被重置 。这个指令的作用是判断R(B)和C是否相等 , 如果相等 , 则令R(A)=R(B) , 否则PC++ 。PC++的含义是 , 跳过下一个指令 , 在图36的例子中 , 如果R(B)的值(也就是a的值)不与C值0相等 , 那么将R(A)赋值为a , 此时下一条指令为 。如果R(A)的值和C不相等 , 那么下一条指令 , 则是的下一条指令 , 也就是跳过了指令 。含义就是如果a的值为false , 后面的判断都不用做了 , 因为一定是false , 我们直接把a所代表的false值记录下来就行了 。第二个要注意的点是 , 结构的f值 , 指向了我们刚生成的指令 , 记录了这个位置 , 并且的参数为-1 , 这个值后续还要进行处理 。
在完成了第一个and的处理之后 , 编译器通过函数 , 获取下一个token < , b > , 此时 , 将变量b装载到新的结构e2中 , 于是得到图37的结果:
图37
此时进入到了第二个and的处理流程 , 和前面的处理流程一样 , 首先e2的信息要转化为指令 , 然后生成和指令 , 得到图38的结果:
图38
对b的处理 , 和对a是基本相似的 , 但是有一点需要注意的是 , 第一个指令 , 的-1值变为了2 , 我们前面已经知道了 , e->f指向了第一个指令 , 这个f其实是一个false列表的意思 , 意思就是and逻辑运算中 , 有一个参数为false , 那么就进入这个jump流程之中 。在图38中 , 我们可以看到第一个JMP指令 , 的sBx的值为2 , 那么它的下一个JMP指令则是sBx+1 。在完成这个处理之后 , 需要将e和e2合并 , 其实就是将e2中 , 除了f以外的值赋值给e 。在完成了第二个and的处理流程之后 , 我们调用函数 , 获得下一个token < , c > , 得到图39的结果:
图39
此时经过函数 , 将e和e2合并 , 得到图40的结果:
图40
其实到目前为止 , 我们的expr函数的处理就结束了 , 就是输入一些token , 经过expr函数处理 , 输出一个结构 。但是为了本次讨论的完整性 , 我需要最后将结构转化为指令 , 实际上这一步可能是在的赋值操作开始之前 , 或者在、、等中的部分结束分析时进行处理的 。那么 , 接下来 , 我们首先要将e中的信息 , 转化为指令得到图41的结果:
图41
在完成这些处理之后 , 我们要根据e->f取得false列表 , 从第一个指令开始 , 修改它的参数 , 使其跳转到指令列表的第8个位置的那个指令 。同时将指令的A域 , 设置为-1的值 , 得到图42的结果: