为什么自下而上的解析比自上而下的解析更常见?

时间:2010-11-30 17:05:52

标签: parsing context-free-grammar

似乎递归下降解析器不仅是最简单的解释,而且也是最简单的设计和维护。它们不仅限于LALR(1)语法,并且代码本身可以被凡人理解。相比之下,自下而上的解析器对它们能够识别的语法有限制,并且需要通过特殊工具生成(因为驱动它们的表几乎不可能手动生成)。

为什么然后,自下而上(即shift-reduce)解析比自上而下(即递归下降)解析更常见?

6 个答案:

答案 0 :(得分:15)

如果您选择功能强大的解析器生成器,则可以编写语法代码而无需担心特殊属性。 (洛杉矶)LR意味着你不必担心左递归,更少担心头痛。 GLR意味着您不必担心本地模糊或前瞻。

自下而上的解析器往往效率很高。因此,一旦你付出了一些复杂机器的价格,就可以更容易地编写语法并且解析器表现良好。

如果通常会出现一些编程结构,你应该会看到这种选择:如果它更容易指定,并且表现相当好,即使机器很复杂,复杂的机器也会获胜。另一个例子是,数据库世界已经转向关系工具,尽管您可以自己手工构建索引文件。它更容易编写数据模式,更容易指定索引,并且后面有足够复杂的机器(你不必看齿轮,只需使用它们),它们可以非常快速地完成任务。原因相同。

答案 1 :(得分:7)

它源于几个不同的东西。

BNF(以及语法等理论)来自计算语言学:人们研究自然语言解析。 BNF是一种非常有吸引力的描述语法的方式,因此想要使用这些符号来生成解析器是很自然的。

不幸的是,自上而下的解析技术在应用于此类符号时往往会失败,因为它们无法处理许多常见情况(例如,左递归)。这样你就可以使用LR系列,它可以很好地处理语法,并且因为它们是由机器生成的,它关心的是代码的样子?

你说得对:自上而下的解析器更“直观”工作,因此它们更易于调试和维护,一旦你进行了一些练习,它们就像工具生成的一样容易编写。 (特别是当你进入转移/减少冲突地狱时。)许多答案谈论解析性能,但实际上,自上而下的解析器通常可以优化为与机器生成的解析器一样快。

这就是为什么许多生产编译器使用手写的词法分析器和解析器。

答案 2 :(得分:6)

递归下降解析器试图假设输入字符串的一般结构,这意味着在字符串结束之前会发生大量的反复试验。这使得它们比自下而上的解析器效率低,后者不需要这样的推理引擎。

随着语法复杂性的增加,性能差异会变得更大。

答案 3 :(得分:2)

要添加其他答案,重要的是要意识到除了效率之外,自下而上的解析器可以接受明显更多的语法而不是递归下降解析器。自上而下的解析器 - 无论是预测的还是非 - 只能有1个先行令牌,如果当前令牌和紧跟令牌之后的任何内容可以使用两个不同的规则导出,则会失败。当然,您可以实现解析器以获得更多的前瞻(例如LL(3)),但是在它变得像自下而上的解析器一样复杂之前,您愿意推动它多远?另一方面,自下而上的解析器(特别是LALR)维护firstsfollows的列表,并且可以处理自上而下解析器无法解决的情况。

当然,计算机科学是一种权衡取舍。如果你的语法足够简单,那么编写一个自上而下的解析器是有意义的。如果它很复杂(例如大多数编程语言的语法),那么您可能必须使用自下而上的解析器来成功接受输入。

答案 4 :(得分:1)

我有两个猜测,但我怀疑是否完全解释了它:

  1. 自上而下的解析可能很慢。递归下降解析器可能需要指数时间才能完成其工作。这会严重限制使用自上而下解析器的编译器的可伸缩性。

  2. 更好的工具。如果您可以在EBNF的某些变体中表达语言,那么Lex / Yacc很可能会通过大量繁琐的代码。似乎没有多少工具可以帮助自动完成将自上而下的解析器组合在一起的任务。让我们面对现实,研究解析器代码并不是玩弄语言的有趣部分。

答案 5 :(得分:1)

我从未在top-down和shift-reduce解析器之间看到真正的比较:

只有2个小程序在同一时间并排运行,一个使用自上而下的方法,一个使用自下而上的方法,每个大约200行代码,

能够解析任何类型的自定义二元运算符和数学表达式,两者共享相同的语法声明格式,然后可能添加变量声明和影响以显示' hacks' (无上下文)可以实现。

那么,如何诚实地说出我们从未做过的事情:严格比较两种方法?