【问题标题】:Limitations of LL vs LR parsers?LL 与 LR 解析器的局限性?
【发布时间】:2011-03-29 02:30:11
【问题描述】:

我知道 LL 与 LR 解析器的基本区别。我也知道 GLR、SLR 和 LALR 都是 LR 解析器的扩展。所以我更详细的问题是......

给定一个 LL(*) 解析器和一个 LR 解析器的任何变体,是否有任何语言可以用一种语言而不是另一种语言来描述?或者更简单地说,是否有任何特性或属性都无法表达?

作为一个具体的例子。如果我要使用 LL(*) 解析器创建一种语言,我是否会遇到想要添加到我的语言中的所需功能/属性,而这只有通过 LR 解析器才能实现(反之亦然)?

【问题讨论】:

    标签: programming-languages parser-generator ll lr


    【解决方案1】:

    这里有几个观点,你可以认为它们是对立的:

    【讨论】:

    • 我不太关心人们对解析器的看法,但我很关心每个人的理论局限性。
    【解决方案2】:

    当然。 LL 解析器不能处理任何带有左递归的文法。固定 k 的 L(AL)R(k) 解析器将无法解析 LL(*) 解析器可以处理的某些内容,因为 k

    【讨论】:

    • 你不能重写你的规则来移除左递归吗?我注意到 LL 解析器的 wiki 页面提到了删除左冲突。
    • 您是否声称不能为 LL* 重写任何具有左递归的语法,从而消除左递归?
    • LL 解析器不能处理左递归语法有关系吗?我有一个模糊的记忆,任何可以用左递归表达的语言也可以用右递归表达。 IOW:在使用 LL 解析器和 LR 解析器时,您可能必须以不同的方式考虑您的语法,但问题不在于您是否需要重写语法,而在于是否存在一种语言可以可以被 LL 解析器识别,但不能被 LR 解析器识别,反之亦然。
    • 如果你愿意重写语法,你可以让大多数解析器“解析”真正语言​​的超集';然后,您可以编写额外的测试来删除无关的部分。问题是,你愿意做多少工作? OP 最初的问题是关于 LL(*) 与 LALR(k) 的强度。
    • 嗯,早期的算法很久以前就解决了上下文无关解析的问题,只是在实践中效率不高。 GLR 很久以前就在实际意义上解决了这个问题。 (我有一个巨大的工具包,可以使用 GLR 解析包括 C++11 在内的各种东西,请参阅我的简历)。 GLL 是最近一个有趣的竞争者,我没有进行太多调查。 ...您认为它与 GLR 相比有哪些具体优势?
    【解决方案3】:

    您可能会在 Wikipedia 中发现这一段很有趣,它说 LL(*) 语法是 LR(k) 语法的子集: http://en.wikipedia.org/wiki/Context-free_grammar#Restrictions 所以你可以使用LR解析方法来解析更多的语言。

    【讨论】:

    • 我希望该段引用了它的来源;那将是一个很好的阅读。这似乎与 Ira 的回答相矛盾(我现在已经接受了)。
    【解决方案4】:

    有些语法不能被“重写”以被 LL 解析器解析,而可以被 LR 解析器解析。一个例子:给定一个用减法构造术语的简单语法:

    S -> S - S | num
    

    你显然在这里有左递归,这是 LL 解析器无法处理的。为了使这个语法可以被 LL 解析,你必须消除左递归:

    S -> num S'
    
    S' -> - num S' | epsilon
    

    现在你的 LL 解析器可以处理这个语法了。但是在为 4 - 2 -1 之类的术语构建语法树时,在树上操作的深度优先搜索会给你 4 - (2 - 1) = 3 而不是 (4 - 2) - 1 = 3如你所料。

    这样做的原因是,您必须在语法中使用左递归规则来处理左关联运算符(如减法)。但是左递归规则不能被 LL 解析器处理。

    所以这里有一类语言不能被 LL 处理。

    【讨论】:

    • 当我的问题更侧重于 LL 与 LR 时,您只在这里谈论 LL。虽然每个都有限制,但是 LL 的限制是否也有 LR 的等价限制?
    • 突出这一点很好。但是您的“在这里,您有一类语言无法由 LL 处理”不是正确的教训。该语言是一组字符串,此处预期的语言确实包含字符串“4-2-1”并被解析器接受。教训是,如果您想要对该字符串进行左关联解释,则必须在如何处理解析器的输出方面做更多的工作。
    • 还值得明确指出,如果我们用括号扩展您的语法,LL 解析器不会4-2-14-(2-1) 相同的AST,所以这些字符串可以被赋予不同的解释。正确的是 4-2-1 的 AST 结构将具有 [- 4 [- 2 1]] 的形状。因此,正如我所说,需要做一些工作来给出所需的左联想解释。
    • @dubiousjim,我想解析器的目的是解析一个字符串,而不是“接受”它。
    【解决方案5】:

    LR 解析器可以接受比 LL 更大的语言类别。在 LL(k) 和 LR(k) 中,k 表示它需要知道的前瞻符号的数量,以便它可以应用适当的产生/减少。 k 越大,解析表越大。所以 k 不仅限制了 LR 解析器,它也限制了 LL 解析器。 LR 解析器可以接受更大类语言的原因是因为左递归在使用 LL 解析器时会出现问题。但这并不完全正确,因为直接递归是可解的,这意味着您可以将文法重写为 LL 文法。直接递归类似于 A -> Abc。当你有间接递归时,你现在可能知道它的样子,那么你就有问题了。 LR 解析器可以解决这个问题,因为它们以自下而上的方式生成解析树。您将不得不更深入地研究 LR 解析,以了解为什么会这样。但是,LR 解析器也不是很强大,它们也有局限性。有些语法很难消化,k 因子也无济于事。对于这种语法,需要 GLR 解析器,它实际上模拟 LR(k) 解析器,但在产生/归约歧义发生时使用回溯来分析整个解析空间。

    【讨论】:

      【解决方案6】:

      LR (1) 解析器比 LL (1) 识别更多语法,因为它不需要我们重写语法来移除左递归和公因数。

      但是,给定一个明确的语法,我们总是可以去除左递归和公因数,因此最终它们都可以解析相同的语言

      如果有人对此有疑问,我挑战你给出一个 LL(1) 无法解析而 LR(1) 可以解析的明确语法,也就是说,不能重写以删除左递归和常见因素

      【讨论】:

        【解决方案7】:

        LL 解析理论上是 O(n^4),或者非常慢。 LR 解析更快,O(n^3),或者相当慢。 https://en.wikipedia.org/wiki/Top-down_parsing

        虽然我很想看到这方面的证据。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-23
          • 2012-08-23
          • 2021-01-03
          • 1970-01-01
          相关资源
          最近更新 更多