Parsing LALR和LR解析之间的区别是什么?

Parsing LALR和LR解析之间的区别是什么?,parsing,compiler-construction,context-free-grammar,lalr,lr,Parsing,Compiler Construction,Context Free Grammar,Lalr,Lr,我知道LR和LALR都是自底向上的解析算法,但两者之间有什么区别 LR(0)、LALR(1)和LR(1)解析之间有什么区别?如何判断语法是LR(0)、LALR(1)还是LR(1)?在较高的层次上,LR(0)、LALR(1)和LR(1)之间的区别如下: LALR(1)解析器是LR(0)解析器的“升级”版本,它跟踪更精确的信息以消除语法歧义。LR(1)解析器比LALR(1)解析器功能更强大,可以跟踪更精确的信息 LALR(1)解析器是比LR(0)解析器大的常数因子,并且LR(1)解析器通常比LAL

我知道LR和LALR都是自底向上的解析算法,但两者之间有什么区别


LR(0)、LALR(1)和LR(1)解析之间有什么区别?如何判断语法是LR(0)、LALR(1)还是LR(1)?

在较高的层次上,LR(0)、LALR(1)和LR(1)之间的区别如下:

  • LALR(1)解析器是LR(0)解析器的“升级”版本,它跟踪更精确的信息以消除语法歧义。LR(1)解析器比LALR(1)解析器功能更强大,可以跟踪更精确的信息

  • LALR(1)解析器是比LR(0)解析器大的常数因子,并且LR(1)解析器通常比LALR(1)解析器大指数

  • 任何可以用LR(0)解析器解析的语法都可以用LALR(1)解析器解析,任何可以用LALR(1)解析器解析的语法都可以用LR(1)解析器解析。有些语法是LALR(1)但不是LR(0)和LR(1)但不是LALR(1)

更正式地说,LR(k)解析器是一种自底向上的解析器,它通过维护终端和非终端堆栈来工作。解析器由一个有限自动机控制,该自动机根据解析器的当前状态和输入的下一个k个令牌来确定是将新令牌转移到堆栈上,还是通过反向应用产生来减少堆栈的顶部符号

为了跟踪足够的信息以确定是移位还是缩减,LR(k)解析器将每个状态对应于一个“配置集”,即一组带有以下信息注释的产品:

  • 到目前为止,已经看到了多少生产,以及
  • 生产完成后预期的代币(前瞻)
这些信息中的第一条用于确定解析器是否需要进行缩减——如果当前状态下的所有生成都未完成,则没有理由进行缩减。这些信息中的第二条在执行缩减时用于确定是否应执行缩减。在决定是否减少时,LR(k)解析器查看输入流的下一个k标记。如果它们与前瞻标记匹配,解析器将减少,否则解析器什么也不做

当LR(k)解析器在给定状态下应该做什么发生冲突时,就会出现问题。当解析器处于生产已完成的状态时,会出现一种类型的冲突,即shift/reduce冲突,但该状态下的另一个未完成生产也会使用该生产冲突的先行符号。这意味着解析器无法判断是否执行缩减。第二种类型的冲突是reduce/reduce冲突,解析器知道它必须进行一次缩减,但是两次或更多的缩减是可能的,并且它无法判断该做什么

直观地说,随着k变得越来越大,解析器可以获得越来越精确的信息来确定何时移动和何时减少。例如,如果语法不是LR(0),那么解析器可能会有一种状态,在这种状态下,它根本无法确定是移位还是缩减。然而,该语法可能仍然是LR(1),因为给定了一个额外的前瞻标记,它可能能够识别出它应该肯定地移位而不是减少,或者肯定地减少而不是移位

LR(k)解析器的问题是,随着k变大,状态的数量可能会呈指数增长。LR(k)解析器中的前瞻是通过在解析器中构建越来越多的状态来处理的,以对应于产品和Lookahead的不同组合,因此,随着可能的Lookahead的数量增加,状态的数量也会增加。因此,LR(1)解析器通常太大而不实用,而LR(2)或更大的解析器在实践中几乎闻所未闻

LALR(1)是作为LR(0)解析器的空间效率和LR(1)解析器的表达能力之间的折衷而发明的。有几种方法可以考虑什么是LALR(1)解析器。最初,LALR(1)解析器被指定为将LR(1)自动机转换为更小自动机的转换。尽管LR(1)解析器可能比LR(0)自动机具有更多的状态,但唯一的区别是LR(1)解析器可能在LR(0)自动机中具有任何特定状态的多个副本,每个副本都带有不同的前瞻信息。可以从LR(1)解析器开始,将具有相同“核心”的所有状态(产品集及其位置)组合在一起,然后将所有前瞻信息聚合在一起,从而形成LALR(1)解析器。这导致解析器的状态数与LR(0)解析器的状态数相同,但保留了一些关于lookaheads的信息,以帮助避免LR冲突

LALR(1)语法的另一个视图使用“LALRbySLR”方法。可以从语法的LR(0)解析器开始,然后为该语言创建一个新的语法来构造LALR(1)解析器,该语言使用LR(0)解析器中的哪些状态对应的信息来注释非终结符。有关该语法中非终结符的FOLLOW集合的信息可以用于在LR(0)解析器中计算lookaheads

最终的结果是

  • LR(0)解析器很小,但表达能力不强
  • LALR(1)解析器由于具有前瞻性信息而稍大一些,但非常有表现力
  • LR(1)解析器非常庞大,但表达能力非常强
至于第二个问题——如何确定语法是LR(1)还是LALR(1)——标准方法是尝试为LR(1)解析器和LALR(1)解析器构建解析自动机,并检查冲突。要构建LR(1)解析器,您需要构建LR(1)配置集,然后检查是否有