Parsing 删除左递归会导致歧义吗?

Parsing 删除左递归会导致歧义吗?,parsing,compiler-construction,context-free-grammar,ll,Parsing,Compiler Construction,Context Free Grammar,Ll,假设我们有以下CFG G: A -> A b A A -> a 哪个应该产生字符串 a,aba,ababa,ababababa,等等。现在我想删除左递归,使其适合于预测性解析。龙之书给出了以下规则来删除立即左递归。 给定 重写为 A -> b A' A' -> a A' | ε 如果我们简单地将规则应用于上面的语法,我们得到语法G': A -> a A' A' -> b A A' | ε 在我看来这很好,但显然这个语法不是LL(1),

假设我们有以下CFG G:

A -> A b A
A -> a
哪个应该产生字符串
a
aba
ababa
ababababa
,等等。现在我想删除左递归,使其适合于预测性解析。龙之书给出了以下规则来删除立即左递归。 给定

重写为

A  -> b A'
A' -> a A'
    | ε
如果我们简单地将规则应用于上面的语法,我们得到语法G':

A  -> a A'
A' -> b A A'
    | ε
在我看来这很好,但显然这个语法不是LL(1),因为有些歧义。我得到了以下第一套/第二套:

First(A) = { "a" }
First(A') = { ε, "b" }
Follow(A) = { $, "b" }
Follow(A') = { $, "b" }
我从中构造解析表

    |   a          |   b            |  $           |
----------------------------------------------------
A   | A -> a A'    |                |              |
A'  |              | A' -> b A A'   | A' -> ε      |
    |              | A' -> ε        |              |
T[a',b]
中存在冲突,因此语法不是LL(1),尽管不再有左递归,也没有公共的生产前缀,因此需要左分解

我不完全确定这种模糊性是从哪里来的。我猜在解析堆栈的过程中会填充
S'
。如果不再需要的话,基本上可以删除它(减少到epsilon)。我认为如果堆栈下面有另一个
S'
,情况就是这样

我认为我试图从原始语法中得到的LL(1)语法G''应该是:

A  -> a A'
A' -> b A
    | ε
我错过什么了吗?我做错什么了吗

是否有一个更通用的过程来删除考虑此边情况的左递归?如果我想自动删除左递归,我应该能够处理它,对吗


对于某些k>1的语法来说,第二种语法是G'a LL(k)语法吗?

原始语法是不明确的,因此新语法也是不明确的就不足为奇了

考虑字符串
aba
。我们可以从原始语法中通过两种方式得出:

A ⇒ A b A
  ⇒ A b a
  ⇒ A b A b a
  ⇒ A b a b a
  ⇒ a b a b a

A ⇒ A b A
  ⇒ A b A b A
  ⇒ A b A b a
  ⇒ A b a b a
  ⇒ a b a b a
当然,明确的语法是可能的。以下是右递归版本和左递归版本:

A ⇒ a              A ⇒ a
A ⇒ a b A          A ⇒ A b a

(尽管它们代表同一种语言,但它们有不同的解析:右递归版本关联到右,而左递归版本关联到左。)

删除左递归不会产生歧义。这种转换保留了模糊性。如果CFG已经不明确,结果也将不明确,如果原始CFG不明确,则结果也不明确

A ⇒ a              A ⇒ a
A ⇒ a b A          A ⇒ A b a