为什么LL语法不能左递归?

时间:2013-04-23 09:08:02

标签: grammar ll left-recursion

dragon book 中,LL语法定义如下:

当且仅当对于任何作品A -> a|b时,语法为LL,以下两个条件适用。

  1. FIRST(a)FIRST(b)不相交。这意味着它们不能同时派生EMPTY

  2. 如果b可以派生EMPTY,则a无法派生任何以FOLLOW(A)开头的字符串,即FIRST(a)和{{1}必须是不相交的。

  3. 我知道LL语法不能递归,但正式的原因是什么?我猜左递归语法会违反规则2,对吧?例如,我写了以下语法:

    FOLLOW(A)

    因为S->SA|empty A->a FIRST(SA) = {a, empty}FOLLOW(S) ={$, a}FIRST(SA)不是不相交的,所以这个语法不是LL。但是我不知道左递归是否使FOLLOW(S)FIRST(SA)不相交,还是有其他原因?换句话说,每个左递归语法都会产生违反LL语法条件2的产品吗?

3 个答案:

答案 0 :(得分:14)

好吧,我弄清楚,如果语法包含左递归生成,例如:

S->SA

然后它必须包含另一个产品来“完成”递归,比如说:

S->B

由于FIRST(B)是FIRST(SA)的子集,因此它们是联合的,这违反了条件1,在FIRST(B)和FIRST(SA)中填写与终端相对应的解析表条目时必定存在冲突)。总而言之,左递归语法可能导致两个或多个产品的FIRST集合具有公共终端,从而违反条件1.

答案 1 :(得分:11)

考虑你的语法:

S->SA|empty
A->a

这是三条规则的简写:

S -> SA
S -> empty
A -> a

现在考虑字符串aaa。它是如何产生的?如果你没有预测,你一次只能读一个字符,所以你就这样开始(你有S作为开始符号):

S -> SA
S -> empty
A -> a

很好,你已经制作了第一个a。但现在你不能再申请任何规则,因为没有更多的非终端。你被困住了!

你应该做的是:

S -> SA
S -> SA
S -> SA
S -> empty
A -> a
A -> a
A -> a

但是如果不阅读整个字符串,你就不知道这一点。你需要无限量的前瞻。

在一般意义上,,每个左递归语法都可以有不明确的字符串而没有无限的前瞻。再看一下这个例子:S有两种不同的规则。我们应该使用哪一个?

答案 2 :(得分:9)

LL(k)语法是允许构造仅具有前瞻k符号的确定性下降解析器的语法。左递归的问题在于,在检查完整的输入字符串之前,无法确定应用哪个规则,这使得所需的k可能无限。

使用您的示例,选择k,并为解析器提供长度为n >= k的输入序列:

aaaaaaa...

解析器无法通过查看前面的S->SA符号来决定它是应该应用S->empty还是k,因为决定将取决于已选择S->SA次的次数之前,这是解析器没有的信息。

解析器必须选择S->SA完全n次和S->empty一次,并且通过查看第一个k符号无法确定哪个是正确的输入流。

要知道,解析器必须同时检查完整的输入序列,并记录已选择S->SA的次数,但这样的解析器将超出LL(k)的定义

请注意,无限前瞻不是解决方案,因为解析器在有限的资源上运行,因此总会有一个有限的输入序列,其长度足以使解析器在生成任何输出之前崩溃。