parsing - 为什么有 LR(0) 解析器而没有 LL(0) 解析器?

标签 parsing compiler-construction lr-grammar ll-grammar

我一直在维基百科上阅读这两个内容,并注意到虽然存在 LR(0) 解析器,但不存在 LL(0) 解析器之类的东西。

根据我的阅读,我了解到 LL(k)/LR(k) 中的 k 表示解析器可以看到超出当前正在处理的当前字符的数量。

所以我的问题是,尽管 LR(0) 存在,为什么没有 LL(0) 解析器这样的东西?

最佳答案

差异与 LR(k) 和 LL(k) 中 k 的含义有关。

在 LL(k) 中,解析器维护有关自上而下、从左到右解析的信息,该解析可追踪出最左推导。解析器的工作方式是重复查看当前非终结符,然后检查输入流的下一个 k 标记以确定应使用哪个产生式。因此,如果您有 LL(0) 解析器,则解析器必须纯粹根据当前非终结符来预测要使用哪个产生式。只有当每个非终结符只有一个与之关联的产生式时,这才是可能的,这意味着语法要么恰好产生一个字符串,要么根本不产生任何字符串(通过进入循环)。因此,虽然 LL(0) 解析在数学上有明确定义,但在实践中从未使用过。

在 LR(k) 中,解析器自下而上地工作。它维护一个符号堆栈以及当前的“状态”,然后不断决定是否执行移位(将另一个符号插入​​堆栈顶部)或减少>(从堆栈中弹出一定数量的符号并反向应用产生式)。 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)。

希望这有帮助!

关于parsing - 为什么有 LR(0) 解析器而没有 LL(0) 解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14674912/

相关文章:

abstract-syntax-tree - 如何将 LR(1) Parse 转换为抽象语法树?

parsing - 如何判断一个文法是LL(1)、LR(0)还是SLR(1)?

regex - 将字符串解析为哈希

python - 如何从嵌套数组中获取值? JSON

programming-languages - 我怎样才能写出一个又快又脏的解释器?

c++ - 使用 llvm 和局部值编号算法删除冗余表达式

compiler-construction - 除了 ANTLR,还有哪些工具可以帮助我创建针对 JVM 的小型语言?

parsing - LR(k) 到 LR(1) 语法转换

parsing - Attoparsec:跳过(但不包括)多字符分隔符

c - 为什么函数指针声明需要知道参数和返回值的类型?