【问题标题】:Resolving PREDICT/PREDICT conflicts in LL(1)解决 LL(1) 中的 PREDICT/PREDICT 冲突
【发布时间】:2015-04-02 23:22:40
【问题描述】:

我正在开发一个简单的 LL(1) 解析器生成器,但在给定某些输入语法的情况下,我遇到了 PREDICT/PREDICT 冲突的问题。例如,给定如下输入语法:

E  → E + E
   | P

P  → 1

我可以从E中去掉左递归,用大致等效的右递归规则替换它,从而得出语法:

E  → P E'

E' → + E E'
   | ε

P  → 1

接下来,我可以计算语法的相关 FIRST 和 FOLLOW 集,最终得到以下结果:

FIRST(E)  = { 1 }
FIRST(E') = { +, ε }
FIRST(P)  = { 1 }

FOLLOW(E)  = { +, EOF }
FOLLOW(E') = { +, EOF }
FOLLOW(P)  = { +, EOF }

最后,使用PREDICT(A → α) = { FIRST(α) - ε } ∪ (FOLLOW(A) if ε ∈ FIRST(α) else ∅)为语法构造PREDICT集合,得到的集合如下。

PREDICT(1. E  → P E')   = { 1 }
PREDICT(2. E' → + E E') = { +, EOF }
PREDICT(3. E' → ε)      = { +, EOF }
PREDICT(4. P  → 1)      = { 1 }

所以这是我遇到PREDICT(2) = PREDICT(3) 冲突的地方,因此,我无法生成解析表,因为语法不是 LL(1),因为解析器无法选择应该应用哪个规则.

我真正想知道的是,是否有可能解决冲突或考虑语法以避免冲突,并产生合法的 LL(1) 语法,而无需直接修改原始输入语法。

【问题讨论】:

    标签: algorithm parsing grammar ll


    【解决方案1】:

    这里的问题是你原来的语法是模棱两可的。

    E → E + E
    E → P
    

    表示P + P + P 可以解析为(P + P) + PP + (P + P)。消除左递归并不能解决歧义,因此修改后的语法也是歧义的。并且模棱两可的文法不能是 LL(k)(或者,就此而言,是 LR(k))。

    所以你需要使语法明确:

    E → E + P
    E → P
    

    (这是常见的左关联版本。)一旦消除左递归,您最终会得到:

    E  → P E'
    E' → + P E'
       | ε
    

    现在+ 不在 FOLLOW(E') 中。

    (该示例直接来自 Dragon 书,但经过简化;它是我拥有的相当破旧的旧副本中的示例 4.8。)

    值得注意的是,这里使用的转换保留了由语法派生的字符串集,而不是派生。修改后的语法产生的解析树实际上是右关联的,因此需要对其进行重新处理以恢复所需的解析。龙书作者相当简短地提到了这一事实:

    虽然左递归消除和左因式分解很容易做到,但它们使生成的语法难以阅读并且难以用于翻译目的。 (我的重点)

    他们继续建议运算符优先级解析可用于表达式,然后提到如果 LR 解析器生成器可用,则不再需要将语法划分为预测部分和运算符优先级部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      • 2017-07-31
      • 2015-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多