我一直在维基百科上阅读,并注意到虽然存在LR(0)解析器,但是没有LL(0)解析器。
根据我的阅读,我理解LL(k)/ LR(k)中的k表示解析器可以看到超出当前正在处理的当前字符的字符数。
所以我的问题是,为什么即使LR(0)存在,也没有LL(0)解析器这样的东西?
答案 0 :(得分:26)
差异与LR(k)与LL(k)中k的含义有关。
在LL(k)中,解析器维护有关从上到下,从左到右解析的信息,该解析描绘出最左边的推导。解析器通过重复查看当前的非终结符号,然后检查输入流的下一个k标记来确定应该使用哪个生产。因此,如果您有一个LL(0)解析器,解析器必须完全基于当前的非终结符来预测要使用的生产。这只有在每个非终结符只有一个与之关联的生成时才有可能,这意味着语法要么只生成一个字符串,要么根本不生成任何字符串(通过进入循环)。因此,虽然在数学上定义良好,但LL(0)解析在实践中从未使用过。
在LR(k)中,解析器自下而上工作。它保持一堆符号,以及当前的状态,"然后不断决定是否执行 shift (在堆栈顶部推送另一个符号)或 reduce (从堆栈中弹出一些符号并应用生产相反)。 LL(k)和LR(k)解析器之间的一个关键区别是LR(k)解析器如何决定执行哪个动作。在LR(k)解析器中,根据前瞻的下一个k标记和解析器的当前状态决定下一步做什么。结果,LR(0)即使解析器看不到任何前瞻标记,解析器仍然可以做出一些关于要执行哪些操作的智能决策,因为解析器的当前状态可以编码大量关于解析器在生产中的位置的信息。实际上可以期待看到的是下一个输入标记(即使解析器不能直接查看这些标记)。
简而言之,LL(0)非常弱,因为解析器必须纯粹基于当前的非终结符决定,这意味着它不能根据可能使用的生产采取许多不同的动作之一。 LR(0)解析器非常强大,因为解析器的选择基于其内部状态,这通常足够详细,让解析器做出关于下一步该做什么的明智决定。
另一个原因是LL(0)弱,而LR(0)相当强大。在LL(0)解析器中,解析器必须立即决定应该执行哪些生成,这意味着解析器必须完全盲目地猜测生成。在LR(0)解析器中,解析器可以在决定是否需要缩减之前移位多个符号。因此,解析器没有任何前瞻,可以推迟决定使用哪个减少直到它已经看到足够的输入令牌才能理解字符串的结构。这是一个更普遍的事实的特殊情况,即任何LL(k)语法都是自动LR(k)。
希望这有帮助!