这是一个粗心的问题。没有理由先验为什么 ETF 语法需要对应于任何特定的 AST。确实,基于 EFT 语法的解析器最容易构建具有常规优先级规则的 AST。而且,像这样的左递归语法也确实使得在 AST 中实现左关联操作变得最容易。
但这些是问题应该明确说明的重大假设。要完全说明问题,您需要提供一个生成 AST 的属性语法,而不仅仅是一个简单的语法。
属性语法将指定如何构建 AST 节点:
E_a -> E_b + T { E_a.ast = makeNode('+', E_b.ast, T.ast) }
E -> T { E.ast = T.ast }
...
F -> i { F.ast = makeLeaf(i) }
因此,如果我们假设一个典型的属性文法,那么 EFT 文法的结构就隐含了操作的优先级。
语法“顶部”的运算符 - 直接从开始符号派生 - 对应于最低优先级。你可以这样想:
E -> E + T | T
扩展为由+ 运算符分隔的一个或多个Terms 的列表。
E -> T + ... + T
这意味着属性语法构造了一个左倾斜的术语树(Ts)。 “在Ts 内”发生的所有事情都具有更高的优先级。这些东西是“绑定在一起”的,不考虑周围的+。
对应的 AST 如下所示:
+
| \
+ T
| \
+ T
|
.
.
.
+
| \
T T
换句话说,表达式是前面项(根下的左子树)与最后一项(右子树)相加的总和。连续的加法从左到右发生。这称为左关联操作。某些运算(例如典型的幂运算)会使树以另一种方式倾斜,因此运算是从右到左进行评估的。 2^3^2 表示“2 的 9 次方”= 512 而不是“8 平方”= 64。
现在您可以扩展条款。在您的示例中,第一个术语最终扩展为 a。第二个扩展为F / F,最后扩展为b / c。 (这假定* 规则也适用于/。)第三项扩展为d。所以你最终得到了
+
| \
+ T
| \
T T
这就变成了
+__
| \
+ d
| \
a /
|\
b c
操作b/c 的优先级高于+,因为它更接近树的叶子。
括号覆盖此自然优先级。表达式
(a + b) / c
最初只有一个词!
E -> T
-> T / F
-> F / F
第二个因素是c。所以直观地说,树的形式是:
/
| \
F c
现在扩展F的关键属性语法规则是
F -> ( E ) { F.ast = E.ast }
所以我们真的有
/_______
| \
( E ) c
现在 ( E ) 会扩展为 a + b 的 AST
/_______
| \
+ c
| \
a b
注意+ 是如何靠近树叶的。括号赋予它比 /! 更高的优先级!