可以删除左递归引入歧义吗?

时间:2015-06-22 12:09:49

标签: parsing compiler-construction context-free-grammar ll

假设我们有以下CFG G:

A -> A b A
A -> a

哪个应该产生字符串 aabaababaabababa等。现在我想删除左递归,使其适合预测解析。龙书提供了以下规则来删除立即左递归。 给定

A -> Aa | b

重写为

A  -> b A'
A' -> a A'
    | ε

如果我们只是将规则应用于上面的语法,我们就会得到语法G':

A  -> a A'
A' -> b A A'
    | ε

这对我来说很好看,但显然这个语法不是LL(1),因为有些含糊不清。我得到以下First / Follow集:

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
    | ε

我错过了什么吗?我做错了吗?

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

第二个语法是G'某些k的LL(k)语法> 1?

2 个答案:

答案 0 :(得分:3)

原始语法含糊不清,所以新语法也不明确也就不足为奇了。

考虑字符串a b a b a。我们可以从原始语法中以两种方式推导出这个:

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

(虽然它们代表相同的语言,但它们有不同的解析:右递归版本与右侧相关联,而左递归版本与左侧相关联。)

答案 1 :(得分:0)

删除左递归不会引入歧义。这种转变保留了模糊性。如果CFG已经模糊不清,结果也会模棱两可,如果原始不是,则结果也不明确。

相关问题