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


接下来 , 看一下or逻辑的情况 , 如果or操作符前面的exp , 经过expr函数处理后 , 得到的结构是VNIL或的类型时 , 它可以被忽略 , 如图48的情况:
图48
我们可以看到 , 除了最后一个exp是false或者nil , 其他在or前面的exp , 凡是这两个类型 , 都可以被忽略 , 因为在or逻辑处理中 , 只要exp的值是false就会进入下一个or操作的测试之中 。去除了这些常量 , 我们就可以将余下的内容 , 套用到前面讨论过的流程之中了 。
关于逻辑运算的处理 , 我们还有最后一种情况没有讨论 , 就是and和or结合的例子 , 我们现在来看一组例子 , 如下所示:
a and b and c or d
面对这样的情况 , 我们可以接着图40的情况 , 往下讨论 , 假设现在我们已经处理了a and b and c的流程 , 现在我们将c变量的信息 , 装填到结构中 , 得到图49的结果:
图49
此时我们获得了操作符or , 进入中序处理流程(调用函数) , 这里首先将e中的信息 , 转化为虚拟机指令 , 于是得到图50的结果:
图50
尔后 , 我们需要生成的是指令和指令 , 得到图51的结果:
图51
我们可以看到 , e中原来代表false列表的字段就不使用了 , 取而代之的是e->t , 这个表示为true时的列表 , 也就是说当变量值为true的时候 , 直接跳过所有测试 。原来的false列表 , 并未被立即消费 , 而是转移到结构的jpc变量来暂存 。此时 , 函数的处理就结束了 , 接下来使用函数 , 来获得下一个token < , d > , 此时需要把d的内容 , 装填到新的结构中 , 得到图52的结果:
图52
接下来就进入到函数的处理之中了 , 在这种情况下 , 就是将e和e2的信息整合在一起 , 其实就是将t的值赋值给e2->t , 最后用e2的值覆盖e的值 , 得到图53的结果:
图53
到了这一步 , 我们的expr函数的处理就成就算结束了 。但是为了完整性 , 我们需要对中的信息 , 转化为指令 , 在赋值语句中 , 或者在、、等的部分 , 我们需要将e转化为指令 , 于是得到图54的结果:
图54
从图54中的内容 , 我们可以看到 , jpc所指向的jump指令列表的跳转索引 , 被改变了 , 直接指向了获取变量d到栈中的指令<0 0 259 > , 这表示 , 当a、b的值为false时 , 直接跳转到d这里 , 以d的值作为表达式的结果 。而e->t指向的JUMP指令 , 则指向了下下个指令 , 因为如果c为true , 则不用理会d的具体值了 。
这里展示了and和or的逻辑运算 , 至于or和and的结合 , 就留给读者自己去推导了 , 到目前为止 , 逻辑运算相关的论述就结束了 , 接下来我们将进入到比较运算的讨论之中 。
5、比较运算
现在我们将进入比较运算的探索之中了 , 我们的比较运算包括了>、=、 , 此时我们需要一个新的结构 , e2 , 并将b的信息装填到里面 , 于是得到图57的结果:
图57
此时我们获得了e和e2 , 接下来 , 就是要进行真正的比较指令生成了 , 这个操作是交给函数来执行 。首先要将e2的信息 , 转化为指令 , 于是得到图58的效果: