【发布时间】:2011-02-08 18:31:54
【问题描述】:
下面的语法有左递归
E= E+T|T
T= T*F|F
F= a|b|c
如何删除它?有什么通用的流程吗?
【问题讨论】:
标签: compiler-construction grammar
下面的语法有左递归
E= E+T|T
T= T*F|F
F= a|b|c
如何删除它?有什么通用的流程吗?
【问题讨论】:
标签: compiler-construction grammar
是的,有一个通用程序,参见例如wikipedia.
E = TE'
E'= (e) | +TE'
T = FT'
T'= (e) | *FT'
F = a | b | c
// (e) is "epsilon" which is defined as the empty string
应该提到的是,这会从左到右改变+ 和* 的关联性。也就是说,之前a + b + c被解析为(a + b) + c,现在被解析为a + (b + c)。
这不是加法和乘法的问题,但它会是例如减法和除法的问题。
维基百科文章有更多关于左递归删除过程及其复杂性的详细信息。
【讨论】:
e来改进。没有这个,对于那些还不熟悉解析器理论的人来说,它是非常不透明的。 (当然,您提供了一个维基百科页面的链接,但该页面以“这篇文章可能对大多数读者来说过于技术性而无法理解”开头,这对我来说当然是这样)。
生产
E = E+T
| T
T = T*F
| F
F = a|b|c
去
E= T ('+' T)*
T= F ('*' F)*
F= a|b|c
为了保持与A(E,T) 处理第一个 E 分离的相同处理。新版本使用:
ret = T1;
while(set.more()) ret = A(ret, set.pop_front().T);
【讨论】:
正如其他人所指出的,有一个用右递归替换左递归的通用过程。其他答案很好地展示了如何使用该通用过程来删除给定语法中的左递归。
这是一种以特定于该语法的方式重构给定语法的解决方案。
E= T+E|T
T= F*T|F
F= a|b|c
【讨论】:
例如,可以在Wikipedia 找到一般程序。我会为E = E+T|T演示:
E 是左递归非终结符。
+T 是非空序列 (alpha)。
T 是不以 E (beta) 开头的序列。
我们为“rest”创建一个新的非终结符,即。非空序列。这处理递归。
E' = epsilon|+TE'
我们修改了原来的规则,使用新的非终结符来处理递归。
E = TE'
【讨论】: