关于数据结构:使用链接比较运算符评估二进制表达式树

Evaluating a binary expression tree with chaining comparison operators

我正在构建一个二进制表达式树(用于玩具脚本语言),到目前为止,我的算术运算工作正常(即4 * (5 + 6));现在,我想添加对比较运算符的支持。使用像0 < 1这样的简单二进制比较,这很容易做到,但是当我将它们链接在一起时,我遇到了问题。例如,此表达式:

1
0 < 1 < 2

当前产生以下二进制表达式树:

1
2
3
4
5
    <
   / \\
  <   2
 / \\
0   1

我正在使用递归将树向下遍历到叶节点并返回值,因此0 < 1首先得到处理,(正确地)返回True。问题在于,下一个升级应该是比较True < 2,而应该比较True && (1 < 2)

解决此问题的最佳方法是什么?我以为我可能最终不得不以不同的方式建造我的树。即

1
2
3
4
5
6
       &&
      /  \\
     /    \\
    <      <
   / \\    / \\
  0   1  1   2

但是我希望能在我的野牛解析器解决方案中实现更优雅/更简单的实现。


本质上,一系列链接比较是单个运算符,而不是一系列二进制运算符。将a < b < c解糖到(a < b) && (b < c)是不精确的,因为它对b进行两次评估。因此,如果您的AST允许,您可以将其解糖为n元运算符。

如果您具有区分的联合类型,则还可以使其与一系列二进制运算符一起使用。在这种情况下,非常简单的已区分联合就足够了。

T是其值为false或任何整数的类型。 (此处,false与任何整数都不同,因此它与0不同。)

现在,我们定义<如下:

1
2
3
4
5
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映射到布尔值false,任何整数都映射到布尔值true。

隐式转换为布尔值的结果是

1
a < b == c < d      # Chained comparison

不同

1
(a < b) == (c < d)  # Comparison of two booleans

例如,这基本上是Python的语义。
上面的方法可以用任何可排序的类型替换整数。

为了实现链式比较,您需要在语法中正确管理带括号的比较。通常只删除括号的朴素AST结构将无法正常工作。