【问题标题】:Why can't a LL grammar be left-recursive?为什么LL语法不能是左递归的?
【发布时间】:2013-04-16 10:21:43
【问题描述】:

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

当且仅当对于任何产生式A -> a|b,满足以下两个条件时,语法才是 LL。

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

  2. 如果b可以派生EMPTY,那么a不能派生任何以FOLLOW(A)开头的字符串,即FIRST(a)FOLLOW(A)必须是不相交的。

    李>

而且我知道 LL 语法不能递归,但形式上的原因是什么?我猜左递归语法会与规则 2 相矛盾,对吧?例如,我写了以下语法:

S->SA|empty
A->a

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

【问题讨论】:

  • FIRST[1](SA){a}
  • 理论上的问题是LA(S->SA)LA(S->e)都包含a。请参阅我的答案以获得更直观的解释。

标签: grammar ll left-recursion


【解决方案1】:

直观地说,因为您不能对左递归语法执行递归下降。

考虑 A -> Ab。我们不能进行递归下降,因为它会导致无限递归:

def A():
    A() # infinite recursion!
    expect('b')

【讨论】:

    【解决方案2】:

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

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

    aaaaaaa...
    

    解析器无法通过查看前面的k 符号来决定它是否应该应用S->SAS->empty,因为该决定取决于之前选择了多少次S->SA,这就是解析器的信息不具有。

    解析器必须选择 S->SA 恰好是 n 次和 S->empty 一次,并且不可能通过查看输入流中的第一个 k 符号来确定哪个是正确的。

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

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

    【讨论】:

      【解决方案3】:

      好的,我想通了,如果一个语法包含左递归产生式,比如:

      S->SA
      

      然后它必须以某种方式包含另一个产生式以“完成”递归,例如:

      S->B
      

      而且由于FIRST(B)是FIRST(SA)的一个子集,所以它们是联合的,这违反了条件1,在填充FIRST(B)和FIRST(SA中的终端对应的解析表条目时一定会发生冲突)。总而言之,左递归语法可能导致 FIRST 集的两个或多个产生式具有公共终结符,从而违反条件 1。

      【讨论】:

        【解决方案4】:

        考虑你的语法:

        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 有两种不同的规则。我们应该使用哪一个?

        【讨论】:

        • 感谢您的回复,但请理解我的要求,是的,我们无法决定 S 使用哪个规则,因为 FIRST(SA) 和 FOLLOW(S) 是联合的,我的问题是: 是左递归使 FIRST(SA) 和 FOLLOW(S) 联合吗?谢谢。
        • @wangshuaijie 您的问题是针对S->SX|e 表单的,答案是。在更一般的情况下,如果存在S->SX,则S 的不同规则的前瞻(LA) 集之间会有交集。 LA 集合中相同非终结符号的交集意味着无法对某些输入做出正确规则的确定性决定。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多