【发布时间】:2013-02-03 17:04:58
【问题描述】:
我一直在 Wikipedia 上阅读这两个内容,并注意到虽然存在 LR(0) 解析器,但没有 LL(0) 解析器之类的东西。
根据我的阅读,我了解到 LL(k)/LR(k) 中的 k 表示解析器可以看到超出当前正在处理的当前字符的字符数。 p>
所以我的问题是,为什么没有 LL(0) 解析器之类的东西,即使 LR(0) 存在?
【问题讨论】:
标签: parsing compiler-construction lr ll
我一直在 Wikipedia 上阅读这两个内容,并注意到虽然存在 LR(0) 解析器,但没有 LL(0) 解析器之类的东西。
根据我的阅读,我了解到 LL(k)/LR(k) 中的 k 表示解析器可以看到超出当前正在处理的当前字符的字符数。 p>
所以我的问题是,为什么没有 LL(0) 解析器之类的东西,即使 LR(0) 存在?
【问题讨论】:
标签: parsing compiler-construction lr ll
区别在于 LR(k) 与 LL(k) 中 k 的含义。
在 LL(k) 中,解析器维护有关自上而下、从左到右的解析的信息,该解析追踪最左边的推导。解析器通过反复查看当前的非终结符来工作,然后检查输入流的下 k 个标记以确定应该使用哪个产生式。因此,如果您有一个 LL(0) 解析器,则解析器必须完全根据当前的非终结符来预测要使用的产生式。这只有在每个非终结符只有一个与之关联的产生式时才有可能,这意味着语法要么只产生一个字符串,要么根本不产生字符串(通过进入循环)。因此,虽然它在数学上是明确定义的,但 LL(0) 解析在实践中从未使用过。
在 LR(k) 中,解析器自底向上工作。它维护一堆符号以及当前的“状态”,然后不断地决定是执行 shift(将另一个符号推到堆栈顶部)还是 reduce(从堆栈中弹出一些符号并反向应用产生式)。 LL(k) 和 LR(k) 解析器之间的一个关键区别是 LR(k) 解析器如何决定执行哪个操作。在 LR(k) 解析器中,接下来要做什么的决定 s 基于前瞻的下 k 个标记和 解析器的当前状态。 结果,一个 LR(0)即使解析器看不到任何前瞻标记,解析器仍然可以对要执行的操作做出一些明智的决定,因为解析器的当前状态可以编码大量关于解析器在生产中的位置以及它可以实际期望的信息视为输入的下一个标记(即使解析器不能直接查看这些标记)。
简而言之,LL(0) 非常弱,因为解析器必须完全根据当前的非终结符做出决定,这意味着它不能根据可能使用的产生式采取许多不同的操作之一。 LR(0) 解析器非常强大,因为解析器根据其内部状态进行选择,内部状态通常足够详细,可以让解析器就下一步做什么做出明智的决定。
还有另一个原因 LL(0) 很弱,而 LR(0) 相当强大。在 LL(0) 解析器中,解析器必须立即决定应该执行哪些产生式,这意味着解析器必须完全盲目地猜测产生式。在 LR(0) 解析器中,解析器可以在决定减少时间之前移动多个符号。因此,解析器可以在没有任何前瞻的情况下推迟决定使用哪种归约,直到它看到足够的输入标记以了解字符串的结构。这是任何 LL(k) 文法自动成为 LR(k) 的更普遍事实的特例。
希望这会有所帮助!
【讨论】: