解决LL(1)中的PREDICT / PREDICT冲突

时间:2015-04-02 23:22:41

标签: algorithm parsing grammar ll

我正在研究一个简单的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)语法,而不必直接修改原始输入语法。 / p>

1 个答案:

答案 0 :(得分: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')。

(这个例子直接来自龙书,但是已经简化了;它的例子是我在相当破旧的旧版本中的例子4.8。)

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

  

尽管左递归消除和左分解很容易,但它们使得结果语法难以阅读且难以用于翻译目的。 (我的重点)

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