我正在构建一个二进制表达式树(用于玩具脚本语言),到目前为止,我的算术运算正常(即4 * (5 + 6)
);现在我想添加对比较运算符的支持。使用0 < 1
这样的简单二进制比较很容易做到这一点,但是当我将它们链接在一起时,我遇到了问题。例如,这个表达式:
0 < 1 < 2
目前生成以下二进制表达式树:
<
/ \
< 2
/ \
0 1
我正在使用递归将树遍历到叶节点并返回值,因此首先处理0 < 1
,然后(正确地)返回True。问题是,下一级别是比较True < 2
,应该比较True && (1 < 2)
。
解决此问题的最佳方法是什么?我以为我最终可能不得不以不同的方式构建我的树。即。
&&
/ \
/ \
< <
/ \ / \
0 1 1 2
但我希望在我的野牛解析器解决方案中实现更优雅/稍微复杂一点的实现。
答案 0 :(得分:1)
本质上,一系列链式比较是单个运算符,而不是一系列二元运算符。将a < b < c
(a < b) && (b < c)
置于b
是不精确的,因为它会对T
进行两次评估。因此,如果你的AST允许的话,你可能只是将它变成一个n-ary运算符。
如果您有一个有区别的联合类型,也可以使它与一系列二元运算符一起使用。在这种情况下,一个非常简单的区分联合就足够了。
让false
成为值为false
或任何整数的类型。 (此处,0
与任何整数都是 distinct ,因此它与<
不同。)
现在,我们将integer a < integer b ==> T
if a is less than b, then b; otherwise false
T a < integer b ==> T
if a is false, then false; otherwise a < b (as above)
定义如下:
T
对于链式比较的中间结果的任何使用,必须将false
结果转换为布尔值;我们这样做是显而易见的:a < b == c < d # Chained comparison
映射到布尔值false,任何整数映射到布尔值true。
隐式转换为布尔值的结果是
(a < b) == (c < d) # Comparison of two booleans
与
不同{{1}}
这基本上是Python的语义,例如。 以上可以使用任何可订购类型替换整数。
为了实现链式比较,您需要在语法中正确管理带括号的比较。通常的简单AST构造只删除括号将无效。