LL通常是一种比递归下降更有效的解析技术。实际上,在最坏的情况下,幼稚的递归下降解析器实际上将是O(k ^ n)(其中n是输入大小)。一些技术(例如备忘录)(产生Packrat解析器)可以改善这一点,并扩展解析器接受的语法类别,但是总会有空间的取舍。LL解析器(据我所知)始终是线性时间。
另一方面,您的直觉是正确的,即递归下降解析器比LL可以处理更大的语法类别。递归下降可以处理任何LL(*)语法(即无限前行)以及一小部分歧义语法。这是因为递归下降实际上是PEG或Parser Expression Grammar(s)的直接编码实现。具体来说,析取运算符(a | b
)不是可交换的,表示a | b
不等于b | a
。递归下降解析器将按顺序尝试每个替代方案。因此,如果a
输入相匹配,它甚至会succede是否b
会匹配的输入。这样可以实现经典的“最长匹配”歧义,例如晃来晃去else
简单地通过正确排序析取符即可解决该问题。
综上所述,可以使用递归下降实现LL(k)解析器,使其在线性时间内运行。这实际上是通过内联预测集来完成的,以便每个解析例程在恒定时间内确定给定输入的适当乘积。不幸的是,这种技术消除了整个语法类别的处理。一旦进入预测解析,悬空之else
类的问题就不再那么容易解决了。
至于为什么选择LL而不是递归下降,这主要是效率和可维护性的问题。递归下降解析器的实现明显更容易,但是它们通常更难维护,因为它们表示的语法不存在任何声明性形式。大多数非平凡的解析器用例都使用解析器生成器,例如ANTLR或Bison。有了这样的工具,算法是直接编码的递归下降还是表驱动的LL(k)确实无关紧要。
有兴趣的是,还值得研究recursive-ascent,它是一种以递归下降方式直接编码但可以处理任何LALR语法的解析算法。我还将研究解析器组合器,这是将递归下降解析器组合在一起的一种功能方式。