LL通常比递归下降更有效的解析技术。事实上,天真的递归下降解析器在最坏情况下实际上是O(k^n)(其中n是输入大小)。一些技术,如备忘录(产生Packrat解析器),可以改善此问题,并扩展解析器接受的语法类别,但总会有一些空间折衷。LL解析器始终是线性时间(据我所知)。
另一方面,您的直觉是正确的,递归下降解析器可以处理比LL更广泛的语法类别。递归下降可以处理任何LL(*)文法(也就是说,无限先见之后和一个小的二义性文法集合)。这是因为递归下降实际上是PEGs或解析器表达式语法的直接编码实现。具体来说,分支运算符(a | b
)不是交换的,意味着a | b
不等于b | a
。递归下降解析器将按顺序尝试每个替代。因此,如果a
匹配输入,即使b
将匹配输入,它也将成功。这样,可处理经典的“最长匹配”歧义,例如悬空的else
问题只需要正确排序分支。
尽管如此,可以使用递归下降实现LL(k)解析器以在线性时间内运行。这是通过基本上内联预测集来实现的,这样每个解析例程就能在常数时间内确定给定输入的适当产生式。不幸的是,这种技术消除了一个可以处理的语法类别。一旦涉及到预测解析,像悬挂的else
这样的问题就不再容易解决了。
关于为什么选择LL算法而不是递归下降算法,主要是考虑效率和可维护性。递归下降解析器的实现相对容易,但通常难以维护,因为它们表示的语法在任何声明形式中都不存在。大多数非平凡的解析器用例都使用解析器生成器,例如ANTLR或Bison。对于这样的工具,无论算法是直接编码的递归下降还是表驱动的LL(k),都不会有太大区别。
值得一提的是,还可以研究递归上升,它是按照递归下降方式直接编码的解析算法,但能够处理任何LALR语法。此外,还有解析器组合子,它是一种将递归下降解析器以函数式方式组合在一起的方法。