如何理解LALR移位/减少算法

时间:2011-03-29 03:10:39

标签: parsing compiler-construction lalr

我正在尝试阅读Niklaus Wirth的Compiler Construction。在第23页,他开始描述LALR如何解析表达式x*(y+z)给出以下语法:

E  = T  | E "+" T. expression 
T  = F  | T "*" F. term 
F  = id | "(" E ")". factor

他接着将减少表示为:

     Action   Stack     Remaining
1             x         * (y + z) 
2    S        x         * (y + z) 
3    R        F         * (y + z) 
4    R        T         * (y + z) 
6    S        T*          (y + z) 
7    S        T*(          y + z) 
8    S        T*(y           + z) 
9    R        T*(F           + z) 
10   R        T*(T           + z) 
11   R        T*(E           + z) 
12   S        T*(E+            z) 
13   S        T*(E + z          ) 
14   R        T*(E + F          ) 
15   R        T*(E + T          ) 
16   R        T*(E              ) 
17   S        T*(E) 
18   R        T*F 
19   R        T 
20   R        E

如果动作是S(换挡)或R(换挡......为了清晰起见,我添加了行号)。所以我想我理解如何从步骤1到4以及从4到20,但我不明白4本身。例如,步骤1将x推入堆栈。 x表示规则'F'的RHS,因此发生减少 - > F.F代表规则'T'的第一个“OR”,因此可以发生另一个减少 - > T.如果这是正确的(我不确定它是什么?),那么为什么不用T代替T,因为T代表规则'E'的RHS的第一个“OR”。是因为规则E有一个暗示的“EOF”可以这么说(因为我们还没有达到EOF它不能减少)?或者是因为它在这一点上是模糊的(T也代表规则T的RHS的第二个“OR”的第一部分...即T“*”F)?或者它完全是另一回事?

谢谢!

1 个答案:

答案 0 :(得分:5)

解析器使用两个标准来决定接下来要采取的操作(轮班或减少)。第一种是当堆栈上的令牌与生产的右侧匹配时。在步骤4之后,堆栈上的T与E = T生成匹配,因此如果这是标准,则可以在该点减少。但是,解析器也在查看前瞻(即“剩余”中的第一个令牌)以决定要采取的操作。没有规则将E“*”作为前缀,因此减少无效,唯一的操作是转移。在步骤20之后,E = T生产 是有效的,因为(正如您猜测的那样)前瞻标记实际上有一个EOF,它确实匹配。

请注意,一些不明确的语法可能导致shift和reduce操作有效。在这些情况下,Bison决定支持“转变”。有关详细信息,请参阅Bison docs。但是,上面给出的语法并不含糊不清;一个先行的标记就足以使它明确无误。