【问题标题】:On complexity of recursive descent parsers关于递归下降解析器的复杂性
【发布时间】:2013-06-01 05:33:17
【问题描述】:

众所周知,递归下降解析器在某些情况下可能需要指数时间;任何人都可以指出我的样本,这发生在哪里?对 PEG 的案例特别感兴趣(即有优先选择)。

【问题讨论】:

  • 只有当他们回溯时。如果他们以真正的LL(1) 风格继续从左到右,他们应该是O(N)
  • @EJP,很明显。但在大多数情况下,即使回溯也不会引入指数复杂性。我正在努力弄清楚在什么情况下会发生这种情况。
  • 并非所有递归下降解析器都能表现出指数行为。例如,ANTLR 4 生成具有 [半] 优先选择的递归下降解析器,但最坏的情况是 O(n⁴)(证明是我目前正在研究的论文的一部分)。

标签: algorithm parsing language-agnostic


【解决方案1】:

如果输入和语法的组合需要大量回溯,则任何自上而下的解析器(包括递归下降)理论上都可以变成指数型。如果语法使得决定性选择放在长序列的末尾,就会发生这种情况。例如,如果你有一个类似 & 的符号,意思是“所有以前的减号实际上都是加号”,然后有类似“((((a - b) - c) - d) - e &)”的数据,那么解析器必须去倒退并将所有优点变为缺点。如果您开始按照这些思路创建嵌套表达式,您可以创建一个有效的非终止输入集。

你必须意识到你在这里介入了一个政治问题,因为现实情况是大多数正常的语法和数据集都不是这样的,但是,有很多人系统地骂递归下降,因为它并不容易自动进行RD。所有早期的解析器都是 LALR,因为它们比 RD 更容易自动生成。所以发生的事情是每个人都只写了 LALR 和 RD,因为在过去,制作 RD 的唯一方法是手动编码。比如你看龙书你会发现Aho & Ullman在RD上只写了一段,基本上就是在意识形态上说“RD不好,别做”。

当然,如果您开始手动编码 RD(就像我一样),您会发现由于各种原因它们比 LALR 好得多。在过去,您总是可以告诉编译器具有手动编码的 RD,因为它具有位置准确的有意义的错误消息,而具有 LALR 的编译器会显示错误发生在距离实际位置 50 行的地方。与过去相比,情况发生了很大变化,但您应该意识到,当您开始阅读有关 RD 的 FUD 时,它来自于“某些圈子”中口头诋毁 RD 的长期传统。

【讨论】:

    【解决方案2】:

    这是因为您最终可以在不同的递归分支中多次解析相同的内容(检查相同位置的相同规则)。这有点像使用递归计算第 n 个斐波那契数。

    Grammar:
    
    A -> xA | xB | x
    B -> yA | xA | y | A
    S -> A
    
    Input:
    xxyxyy
    
    Parsing:
    xA(xxyxyy)
        xA(xyxyy)
            xA(yxyy) fail
            xB(yxyy) fail
            x(yxyy) fail
        xB(xyxyy)
            yA(yxyy)
                xA(xyy)
                    xA(yy) fail
                    xB(yy) fail
                    x(yy) fail
                xB(xyy)
                    yA(yy)
                        xA(y) fail
                        xB(y) fail
                        x(y) fail
                    xA(yy) fail *
                x(xyy) fail
            xA(yxyy) fail *
            y(yxyy) fail
            A(yxyy)
                xA(yxyy) fail *
                xB(yxyy) fail *
                x(yxyy) fail *
        x(xyxyy) fail
    xB(xxyxyy)
        yA(xyxyy) fail
        xA(xyxyy) *
            xA(yxyy) fail *
            xB(yxyy) fail *
            ...
    

    * - 我们在相同的位置解析规则,而我们已经在不同的分支中解析了它。如果我们保存了结果——哪些规则在哪些位置失败——我们会知道 xA(xyxyy) 第二次失败,我们不会再遍历它的整个子树。我不想写出整个事情,但你可以看到它会重复相同的子树很多次。

    何时发生 - 当您有许多重叠的转换时。优先选择不会改变事情 - 如果最低优先级规则最终成为唯一正确的规则(或没有一个是正确的),那么无论如何您都必须检查所有规则。

    【讨论】:

      猜你喜欢
      • 2015-08-07
      • 1970-01-01
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多