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


图23
在完成了两个exp的装载之后 , 就要执行运算处理了 , 在expr函数中 , 这个处理我们称之为后序处理 , 就是要将e和e2进行运算处理 , 这里相当于将e和e2两个参数先入栈 , 再压入运算符 。总之这个处理是在函数内实现的 。在本例中 , 因为e和e2都是常量 , 因此直接计算两个常量的结果 , 并将结果存入e中 , 这个e其实就是expr函数处理的结果 , 一直遵循我们前面讨论过的规则:
tokens => expr function => expdesc
此时 , 我们得到图24的结果:
图24
我们现在接下来看一下第二种情况 , 一个常量与一个变量相加的情况:
1+a
我们先将操作符左边的exp转化成 , 得到图25的结果:
图25
此时我们获得操作符 , token ‘+‘ , 然后此时进入到“中序处理”流程之中 , 因为1这个exp是个数值类型 , 因此不需要做任何处理 , 此时获取下一个token < , a > , 根据前面已经讨论过的内容 , 我们的变量a直接转化为结构 , 最终的结果如图26所示:
图26
接着我们要用函数来处理e和e2了 , 因为他们不全是常量 , 因此两个参数都要先生成入栈指令 , 如图27所示:
图27
最后 , 需要将e和e2进行双目运算操作 , 生成相关的指令 , 如图28所示 , 这里要注意e和的变化:
图28
操作指令的操作结果 , 会存入寄存器R(0) , 所有的参数入栈 , 最终的结果都是为了生成一个值 , 则被复位到R(1)的位置 , 这里需要注意的是 , 永远指向刚刚生成的那条指令 , A域所对的R(A)寄存器的下一个寄存器 。
现在我们来看一下 , 算术运算的最后一种讨论情况 , 两个变量操作的情况 , 我们现在来看一下下面一个例子:
a + b
首先 , 我们进入到expr函数以后 , 首先会通过函数 , 来处理变量a , 得到图29的效果:
图29
此时 , 我们遇到操作符 , 执行操作 , 因为e不是数值类型 , 因此要生成入栈指令 , 得到图30的结果:
图30
此时 , 进入到操作符右边的token的识别流程之中了 , 识别之后 , 直接装载到新的结构中 , 得到图31的结果:
图31
两个参数都被识别和装载之后 , 就进入到了的执行流程了 , 此时会生成将第二个参数都入栈的指令 , 图32展示了这个结果:
图32
最后 , 生成对两个参数进行运算的指令 , 这里是指令 , 得到图33的结果:
图33
我们可以用任何一个双目算术运算符 , 代替上面几个例子中的加法运算符 , 操作流程都是一致的 。而拼接字符串的操作 , 可以结合第三种情况去分析 , 这个留给读者自己去推导流程 。
4、逻辑运算
我们的逻辑运算 , 本质是and和or运算符执行逻辑运算 , 我们接下来通过几个例子来看 。首先是一个and和or只有变量参与的例子 , 然后我们再参入常量 , 最后让and和or结合 。我们首先来看第一个例子:
a and b and c
进入到expr函数以后 , 我们首先对token < , a >进行处理 , 处理它的是函数 , 对应代码片段5的第372行 。执行完以后 , 我们将该token的信息 , 装载到中 , 得到图34的结果: