Parsing 为什么可以';左递归、非确定性或歧义语法是否为LL(1)?

Parsing 为什么可以';左递归、非确定性或歧义语法是否为LL(1)?,parsing,compiler-construction,grammar,ll,language-theory,Parsing,Compiler Construction,Grammar,Ll,Language Theory,我从几个来源了解到,LL(1)语法是: 毫不含糊 不是左递归的 以及确定性(左因式分解) 我不能完全理解的是,为什么上述内容适用于任何LL(1)语法。我知道LL(1)解析表在某些单元格中将有多个条目,但我真正想得到的是以下命题的正式和一般性(不是示例)证明: 左递归(1)、非确定性(2)或歧义(3)语法不是LL(1)。我做了更多的研究,我想我已经找到了第一个和第二个问题的解决方案,至于第三个问题,我在这里找到了一个现有的解决方案,因此对于它,验证尝试写在下面: 我们首先编写LL(1)语法定义的三

我从几个来源了解到,LL(1)语法是:

  • 毫不含糊
  • 不是左递归的
  • 以及确定性(左因式分解)
  • 我不能完全理解的是,为什么上述内容适用于任何LL(1)语法。我知道LL(1)解析表在某些单元格中将有多个条目,但我真正想得到的是以下命题的正式和一般性(不是示例)证明:


    左递归(1)、非确定性(2)或歧义(3)语法不是LL(1)。

    我做了更多的研究,我想我已经找到了第一个和第二个问题的解决方案,至于第三个问题,我在这里找到了一个现有的解决方案,因此对于它,验证尝试写在下面:

    我们首先编写LL(1)语法定义的三条规则:

    对于每个生产
    A->α|β
    α≠ β

  • FIRST(α)∩ 第一(β)=Ø
  • 如果
    β=>*ε
    那么
    首先(α)∩ 遵循(A)=Ø
    (同样,如果
    α=>*ε
    首先(β)∩ 遵循(A)=Ø
  • 在规则(1)中包括
    ε
    ,意味着
    α
    β
    中最多有一个可以导出
    ε
  • 命题1:无因素语法不是LL(1)

    证明:

    如果语法G是非因数的,则G中存在一个形式为:

    A -> ωα1 | ωα2 | ... | ωαn
    
    S -> Sα | β
    
    (其中
    αi
    i-thα
    ,而不是符号
    α
    i
    ),带有
    α1≠ α2 ≠ ... ≠ αn
    。我们可以很容易地证明:

    ∩(i=1,..,n) FIRST(ωαi) ≠ Ø
    
    这和定义中的规则(1)相矛盾,所以,非因数语法不是LL(1)。∎

    命题2:左递归语法不是LL(1)

    证明:

    如果语法是左递归的,则存在一个G形式的生成:

    A -> ωα1 | ωα2 | ... | ωαn
    
    S -> Sα | β
    
    这里有三种情况:

  • 如果<代码>第一个(β)≠ {ε}
  • 然后:

    第一(β)⊆ 首先

    =>第一(β)∩ 第一(Sα)≠ Ø

    这与定义中的规则(1)相矛盾

  • 如果
    第一个(β)={ε}
    则:

    2.1。如果<代码>ε∈ 首先(α)
  • 然后:

    ε∈ 第一(Sα)

    这与定义的第(3)条相矛盾

    2.2。如果<代码>ε∉ 首先(α)然后:

    FIRST(α)⊆ 第一个(S)
    (因为
    β=>*ε

    =>第一(α)⊆ 第一(Sα)。。。。。。。。(一) 

    我们还知道:

    FIRST(α)⊆ 跟随。。。。。。。。(二) 

    通过
    (I)
    (II)
    ,我们已经:

    第一(Sα)∩ 跟进(S)≠ Ø

    由于
    β=>*ε
    ,这与定义的规则(2)相矛盾

    在每种情况下,我们都会得出一个矛盾,因此,左递归语法不是LL(1)。∎

    命题3:歧义语法不是LL(1)

    证明:

    虽然上述证据是我的,但这一个不是,我从他的答案中得到的证据如下:


    这些问题的答案(它们对LL(k)对任何有限k都有效)与解析堆栈在LL解析器中的工作方式有关

    在语法中,当一个标记位于非终结符的开头时,解析器必须通过只向前看k(LL(1)中的1)个大小写标记来确定是将特定规则推送到堆栈上,还是使用其他规则解析文本。那么,让我们看看这些案例中的每一个,看看它是如何影响决策的

  • 左递归。有两种左递归情况

    a。左递归在递归之后没有标记。一条规则,比如:

  • 非术语:非术语

    这样的规则没有任何效果,并且无论递归多少,都不会改变正在解析的内容

    b. The left-recursion has tokens in it after the recursion.  A rules something like:
    
    非术语:非术语“X”

    在这个规则中,您需要将非术语规则推送到堆栈上,使非术语后面的X尽可能多。您无法确定只有k个前瞻标记的X的数量。如果你猜得太少,你会得到剩下的Xs,对于任何猜测,在语言中都会有一个例子,其中包含了超过那么多的X标记。如果您猜得太大,那么最终会在堆栈上出现外部非术语规则。你不必移除它们。无论哪种情况,你都是错的

  • 不确定性。非确定性语法与左递归语法具有相同的特征。你是否应该推是不确定的。回文语言是典型的非确定性例子,但不是唯一的例子。在回文语言中,您不知道是应该将另一个非终结符推送到堆栈上,还是使用看到的标记来帮助您从堆栈中弹出。如果你做了错误的选择,你又一次错估了输入

  • 模棱两可。同样,问题也是类似的。在本例中,有两种可能的解析。一个推送一个非终结符并成功解析输入的解析,另一个不推送的解析(可能是现在或以后在解析中推送另一个非终结符)。任何一个都将产生正确的解析。现在,在不明确的情况下,推送非终结符不一定会导致解析错误,您只需选择一个可能的解析,而忽略另一个。如果语义要求选择另一个解析,那么问题将在稍后出现。当然,请注意,最模糊的语法也是不确定的

  • 现在,如果您查看这些情况,您可以看到,如果您能够以某种方式将非终结符推送和不推送到堆栈上,那么您可以使用语法解析输入。在不明确的情况下,生成一组解析