【问题标题】:Difference to remove left recursion for + and - or * or /?删除 + 和 - 或 * 或 / 的左递归的区别?
【发布时间】:2015-10-25 18:23:06
【问题描述】:

去除左递归

E->E+T|E-T|T
T->T*F|T/F|F

对于+和*,我确定应该是

E->TE'
E'->+TE'|(e) (e) is empty string
T->FT'
T'->*FT'|(e)

但是对于-或/,我不知道怎么去掉左递归,我想出了下面的,对-和/合适吗?举个例子,对于加号,a+b = b+a,但对于减号,a - b != b -a。所以如果我们使用下面的右递归,我们会遇到像 a-b 这样的问题吗?

E->TE'
E'->+TE'|-TE'|(e) 
T->FT'
T'->*FT'|/FT'|(e)

有人知道编译器向我解释吗?提前谢谢。

【问题讨论】:

  • 4-3 是什么意思?你有解释这个语法的解释器吗?它返回-1 而不是1?问题可能不是语法的一部分,而是解释器的一部分。如果是这样,那么您应该提供有关解析器生成器和解释器代码的更多信息。
  • 我想你的意思是T->T*F|T/F|F(而不是E/T
  • @rici 是的,我就是这个意思
  • @CoronA 这与解释器无关。我编辑了我的问题。
  • 不清楚您的问题是什么——是的,您展示的最终语法是初始语法的正确左分解。它可以解析+-*/,就像原始语法一样,并识别完全相同的语言。显然,任何给定输入的解析树都会有所不同。

标签: compiler-construction grammar left-recursion


【解决方案1】:

左递归消除允许 LL 解析器正确识别一种语言,但生成的解析器不会生成正确的解析树。特别是,它通过右关联解析更改了 -/ 等运算符的左关联解析。

为了使用解析来实际解释已解析的字符串,您需要通过反转左关联运算符的关联性来有效地恢复正确的解析树。

或者,您可以只使用自下而上的解析器,例如由 yacc/bison 生成的 LALR(1) 解析器。或者您可以编写或修改运算符优先级算法(请参阅“Shunting Yard”)。

如果您要在递归下降解析器中使用 LL 语法,则可以避免该问题,因为递归下降解析器通常具有显式循环而不是右递归产生式的递归(在伪代码中) :

parse_term(): 
  f = parse_factor()
  while peek() is in ('*', '/'):
    op = token()
    f2 = parse_factor()
    f = apply_operator(op, f, f2)
  return f

【讨论】:

  • 感谢您的回复,我编辑了我的问题。原本很混乱。
  • @David:我认为我的回答仍然是正确的。基本上:是的,解析树不正确是个问题,但可以处理;答案尝试了一些关于如何做的建议。
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-24
相关资源
最近更新 更多