递归上升解析器如何工作?我自己编写了一个递归的 descent 解析器,但我并不了解LR解析器。我found on Wikipedia只会增加我的困惑。
另一个问题是为什么递归上升解析器的使用不比它们基于表的对应物更多。似乎递归上升解析器总体上具有更高的性能。
答案 0 :(得分:7)
clasical dragon book很好地解释了LR解析器的工作原理。如果我记得很清楚,还有Parsing Techniques. A Practical Guide.你可以在那里阅读它们。维基百科上的文章(至少是介绍)是不对的。它们是由Donald Knuth创建的,他在他的“计算机编程艺术第5卷”中对它们进行了解释。如果您了解西班牙语,我会发布完整的书籍列表here。并非所有的书籍都是西班牙语。
在了解它们的工作原理之前,你必须先了解一些概念,如第一,后续和前瞻。另外,我真的建议你在尝试理解LR(上升)解析器之前理解LL(后代)解析器背后的概念。
有一系列解析器LR,特别是LR(K),SLR(K)和LALR(K),其中K是他们需要工作的前瞻。 Yacc支持LALR(1)解析器,但你可以进行调整,而不是基于理论,使其适用于更强大的语法。
关于表现,它取决于所分析的语法。它们以线性时间执行,但是它们需要多少空间取决于您为最终解析器构建的状态数。
答案 1 :(得分:6)
我个人很难理解函数调用如何更快 - 比表查找更“明显更快”。而且我怀疑,与词法分析器/解析器必须做的其他事情(主要是读取和标记文件)相比,即使“明显更快”也是微不足道的。我看了维基百科页面,但没有按照参考文献;作者是否真的描述了一个完整的词法分析器/解析器?
对我来说更有趣的是表驱动解析器在递归下降方面的下降。我来自C背景,其中yacc(或等效的)是首选的解析器生成器。当我转移到Java时,我发现了一个表驱动实现(JavaCup)和几个递归下降实现(JavaCC,ANTLR)。
我怀疑答案类似于“为什么选择Java而不是C”的答案:执行速度并不像开发速度那么重要。正如维基百科文章所述,表格驱动的解析器几乎不可能从代码中理解(当我使用它们时,我可以遵循他们的行为,但永远无法从解析器重构语法)。相比之下,递归下降非常直观(毫无疑问,为什么它早于桌面驱动约20年)。
答案 2 :(得分:2)
关于递归上升解析的维基百科文章引用了关于该主题的原始论文(“Very Fast LR Parsing”)。略读那篇论文为我清除了一些东西。我注意到的事情:
本文讨论了生成汇编代码。我想知道如果你生成C或Java代码,你是否可以做同样的事情;请参见第4节和第5节“错误恢复”和“堆栈溢出检查”。 (我不是想尝试他们的技术 - 它可能会很好 - 只是说在提交之前你可能想要查看它。)
他们将递归上升工具与自己的表驱动解析器进行比较。从结果部分的描述看,它们的表驱动解析器是“完全解释”的;它不需要任何自定义生成的代码。我想知道是否有一个中间地带,整体结构仍然是由表驱动的,但是你为某些动作生成自定义代码以加快速度。
维基百科页面引用的论文:
关于使用代码生成而不是表解释的另一篇论文:
另请注意,递归下降解析不是解析基于LL语法的语言的最快方法: