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

<0 50 1 >表示设置到1~50的位置上 , 第二个指令则是<0 50 2 >表示设置到51~100的位置上 。
这里需要注意的是 , 在内 , 有赋值操作的域 , 是直接生成赋值指令 , 将对应的值设置到目标表里 , 其他的均是列表域 , 因此都需要通过压入栈 , 再使用指令 , 来将这些变量设置到table上 。
8、优先级处理
接下来我们要讨论的是 , 优先级处理的情况 。优先级的处理 , 主要有运算符优先级 , 还有就是表达式优先级 。我们先看一下运算符优先级的情况 , 实际上lua语言对运算符的优先级 , 有进行分级 , 其分级如下所示:
// luaparser.cstatic const struct {lu_byte left;// left priority for each binary operatorlu_byte right;// right priority} priority[] = {{10,10}, {10,10},// '+' and '-'{11,11}, {11,11}, {11,11}, {11, 11}, // '*', '/', '//' and '%'{14,13},// '^' right associative{6,6}, {4,4}, {5,5},// '&', '|' and '~'{7,7}, {7,7},// '<<' and '>>'{9,8},// '..' right associative{3,3}, {3,3}, {3,3}, {3,3}, {3,3}, {3,3}, // '>', '<', '>=', '<=', '==', '~=',{2,2}, {1,1},// 'and' and 'or'};
代码片段6
我们这里的运算符优先级 , 是双目运算符的优先级 , 一个双目运算符有两个操作数 , 分别是左操作数和右操作数 , 上面花括号内的数字 , 分别代表左操作数和右操作数的权重 , 比如下面一个例子:
a+b1010
到代码片段6中 , 查找加法运算符的权重 , 得到的值 , 附属到了变量a和b的下方 。如果出现一连串的算数运算 , 比如下面的例子:
1010a+b*c1111
代码上方的是加法运算的操作数权重 , 代码下方的是乘法运算的操作数权重 , 根据这个权重 , 我们就可以判定 , 权重高的运算符要先运算 。我们的编译器 , 怎么处理这样的流程的呢?通过图76来说明:
图76
图76展示了一个表达式 , 从例子中 , 我们可以看到 , ^运算符的优先级是最高的 , 然后是*运算符 , 最后是+运算符 。上面这个表达式 , 最终会经过expr函数 , 计算得到一个结构的结果 , 但是在这个expr函数内部 , 还是会将表达式分解成若干个表达式 , 并且通过递归的方式 , 调用expr函数来编译他们 , 整个分解过程 , 就是我们看到的图76的结果 。通过图76 , 我们可以得到几个结论 , 在一个包含运算符的表达式中 , 运算符的优先级越高 , 其层次越深 , 计算的次序越靠前 。我们可以通过先序遍历的方式 , 去遍历这个Parse Tree , 当操作符右边的节点 , 要退出的时候 , 操作运算才生效 。读者可以结合代码片段5和图76去体会一下 , lua编译器对于运算符优先级的处理逻辑 。
我们现在来看另一个例子 , 这个例子是表达式在括号内的情况 , 如图77所示:
图77
根据图77 , 我们可以看到 , expr处理带有双目操作符的时候 , 操作符左边的exp一定是一个 , 而本身就要处理括号内的表达式的情况 , 并且一定要优先处理 。这样做的好处是 , 不管操作符的优先级有多高 , 括号内的表达式要优先完成运算 。读者同样可以结合图77和代码片段5来感受这一点 。