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