LR(0)和SLR解析之间有什么区别?


80

我正在研究我的编译器概念,但我有些困惑……Google搜索使我无处获得确切的答案。

SLR和LR(0)解析器是否相同?如果没有,有什么区别?

Answers:


246

LR(0)和SLR(1)解析器都是自底向上的定向预测解析器。这意味着

  • 解析器尝试反向应用乘积,以将输入语句减少回起始符号(自下而上
  • 解析器从左到右(方向)扫描输入
  • 解析器尝试预测要应用的减少量,而不必看到所有输入(可预测

LR(0)和SLR(1)都是移位/减少解析器,这意味着它们通过将输入流的令牌放置在堆栈上来处理输入流的令牌,并且在每个点通过令牌推入堆栈或减少一些令牌来移位令牌栈顶上的终端和非终端的序列,返回到一些非终端符号。可以证明,可以使用shift / reduce解析器自底向上解析任何语法,但该解析器可能不是确定性的。也就是说,解析器可能不得不“猜测”是应用移位还是缩减,并且最终可能不得不回溯以意识到它做出了错误的选择。无论您构造的确定性移位/归约解析器多么强大,它都将永远无法解析所有语法。

当使用确定性的移位/归约解析器解析它无法处理的语法时,会导致移位/归纳冲突归约/归约冲突,解析器可能会进入无法告知要采取何种操作的状态。在移位/减少冲突中,它无法确定是应向堆栈中添加另一个符号还是对堆栈的顶部符号进行某种缩减。在reduce / reduce冲突中,解析器知道它需要用一些非终结符替换堆栈的顶部符号,但是它无法确定要使用哪种缩减。

对于这是一个冗长的阐述,我深表歉意,但是我们需要这样做才能解决LR(0)和SLR(1)解析之间的差异。LR(0)解析器是一种移位/减少解析器,它使用零提前标记来确定要采取的操作(因此为0)。这意味着在解析器的任何配置中,解析器都必须有明确的操作可供选择-移位特定符号或应用特定归约。如果有两个或多个选择,解析器将失败,我们说该语法不是LR(0)。

回想一下,两个可能的LR冲突是平移/减少和减少/减少。在这两种情况下,LR(0)自动机至少可以执行两个动作,并且无法区分要使用哪个动作。由于冲突操作中至少有一个是还原操作,因此合理的攻击方法是尝试使解析器在执行特定还原操作时更加小心。更具体地说,让我们假设允许解析器查看输入的下一个标记,以确定它是应该移位还是应减少。如果我们仅允许解析器在“有意义”的情况下进行缩减(对于“有意义”的某种定义),那么我们可以通过让自动机专门选择移动或缩减来消除冲突。特定步骤。

在SLR(1)(“简化的LR(1)”)中,允许解析器在确定是否应移动或缩小时查看先行标记。特别是,当解析器想要尝试简化形式A→w(对于非终结符A和字符串w)时,它将查看输入的下一个标记。如果在某些派生中该令牌可以合法地出现在非终端A之后,则解析器将减少。否则,事实并非如此。直觉是,在某些情况下,尝试进行减少是没有意义的,因为鉴于我们到目前为止已经看到的令牌以及即将到来的令牌,减少的方法永远不可能正确。

LR(0)和SLR(1)之间的唯一区别是,这种额外的功能可以帮助您确定在发生冲突时采取什么措施。因此,可以由SLR(1)解析器解析任何可以由LR(0)解析器解析的语法。但是,SLR(1)解析器比LR(0)可以解析更多的语法。

但是,实际上,SLR(1)仍然是一种较弱的解析方法。更常见的是,您会看到正在使用LALR(1)(“ Lookahead LR(1)”)解析器。它们也通过尝试解决LR(0)解析器中的冲突而起作用,但是用于解决冲突的规则比SLR(1)中使用的规则精确得多,因此LALR(1)的语法数量要大得多。比SLR(1)大。更具体地说,SLR(1)解析器尝试通过查看语法的结构来解决冲突,以了解有关何时转移和何时减少的更多信息。LALR(1)解析器同时查看语法和LR(0)解析器,以获取有关何时转移和何时减少的更具体的信息。因为LALR(1)可以查看LR(0)解析器的结构,所以它可以更精确地标识某些冲突是虚假的。yaccbison,默认情况下,产生LALR(1)解析器。

从历史上看,LALR(1)解析器通常通过依赖于功能更强大的LR(1)解析器的另一种方法构造,因此您经常会看到LALR(1)如此描述。为了理解这一点,我们需要谈论LR(1)解析器。在LR(0)解析器中,解析器通过跟踪生产环境中的位置来工作。一旦发现它已经达到生产的极限,它便知道要减少。但是,解析器可能无法分辨它是在一个生产的末尾还是在另一个生产的中间,这会导致移位/减少冲突,或者它已经到达了两个不同生产中的哪个(减少/减少冲突)。在LR(0)中,这立即导致冲突,并且解析器失败。在SLR(1)或LALR(1)中,

在LR(1)解析器中,解析器在运行时会跟踪其他信息。除了跟踪解析器认为正在使用的生产之外,它还跟踪生产完成后可能出现的令牌。因为解析器在每个步骤(不仅是在需要做出决定时)都会跟踪此信息,所以LR(1)解析器比LR(0),SLR(1)或到目前为止,我们已经讨论过LALR(1)解析器。LR(1)是一种非常强大的解析技术,可以使用一些棘手的数学运算来证明,可以由任何shift / reduce解析器确定性地解析的任何语言都具有可以用LR(1)自动机解析的语法。(请注意,这并不意味着所有语法可以确定地解析的是LR(1); 这仅表示可以确定性地解析的语言具有LR(1)语法)。但是,这种能力是有代价的,并且生成的LR(1)解析器可能需要太多信息才能进行操作,以至于无法在实践中使用。例如,用于实际编程语言的LR(1)解析器可能需要数十到数百兆字节的附加信息才能正确运行。因此,实际上通常不使用LR(1),而是使用较弱的解析器,例如LALR(1)或SLR(1)。

最近,一种称为GLR(0)(“ Generalized LR(0)”)的新解析算法已经普及。GLR(0)解析器通过尝试并行尝试所有可能的选项来工作,而不是尝试解决LR(0)解析器中出现的冲突。使用一些巧妙的技巧,可以使许多语法高效运行。而且,GLR(0)完全可以解析任何上下文无关的语法,甚至LR(k)解析器无法解析任何k的语法。其他解析器也可以执行此操作(例如,Earley解析器或CYK解析器),尽管在实践中GLR(0)往往会更快。

如果您有兴趣了解更多信息,那么今年夏天,我教了一个入门的编译器课程,并花了不到两周的时间讨论解析技术。如果您想更严格地介绍LR(0),SLR(1)和许多其他强大的解析技术,则可以喜欢我的演讲幻灯片和有关解析的家庭作业。所有课程材料都可以在我的个人网站上找到

希望这可以帮助!


23
这是一个很好的答案。以一种非常清晰和具有教育意义的方式准确地回答了这个问题。我在SO上遇到的最好的答案之一。
NealB 2011年

2
@templatetypedef:我认为您应该对L(AL)R(1)和SLR(1)之间的区别进行一些说明,这就是为什么SLR(1)作为有趣的选择而存在的原因。但是+1。
Ira Baxter

@Ira Baxter-我刚刚更新了讨论内容,以更多地谈论LALR(1)和LR(1)。您能仔细看一下,让我知道您是否应该添加任何内容吗?
templatetypedef

1
@newbie LR(0)解析器的确有一个ACTION表,但该动作仅取决于状态,而不取决于状态和下一个标记。
templatetypedef

1
@newbie您在上面提供的项目是减少项目。该状态的ACTION条目将减少。
templatetypedef

1

这是我学到的。通常,LR(0)解析器可能有歧义,即表的一个框(您派生用于创建解析器)可以具有多个值(或更好地表达):解析器会导致两个最终状态具有相同的输入。因此,创建SLR解析器以消除这种歧义。为了构造它可以找到导致goto状态的所有产生,在左侧找到生产符号的跟随,并且仅包括在跟随中出现的goto状态。这反过来意味着您不包含使用原始语法无法生成的结果(因为状态不在跟随集中)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.