我正在尝试了解 shift-reduce 解析。假设我们有以下语法,使用强制操作顺序的递归规则,受ANSI C Yacc 语法的启发:
S: A;
P
: NUMBER
| '(' S ')'
;
M
: P
| M '*' P
| M '/' P
;
A
: M
| A '+' M
| A '-' M
;
我们想使用 shift-reduce 解析来解析 1+2。首先,将 1 作为数字移动。我的问题是,它是否会被简化为 P,然后是 M,然后是 A,最后是 S?它怎么知道在哪里停下来?
假设它确实一直减少到 S,然后移动“+”。我们现在有一个堆栈,其中包含:
S '+'
如果我们移动'2',减少可能是:
S '+' NUMBER
S '+' P
S '+' M
S '+' A
S '+' S
现在,在最后一行的任一侧,S 可以是 P、M、A 或 NUMBER,并且它仍然有效,因为任何组合都是文本的正确表示。解析器如何“知道”它
A '+' M
这样它就可以将整个表达式简化为A,然后S?换句话说,它如何知道在移动下一个令牌之前停止减少?这是 LR 解析器生成的关键难点吗?
编辑:对问题的补充如下。
现在假设我们解析1+2*3
. 一些移位/减少操作如下:
Stack | Input | Operation
---------+-------+----------------------------------------------
| 1+2*3 |
NUMBER | +2*3 | Shift
A | +2*3 | Reduce (looking ahead, we know to stop at A)
A+ | 2*3 | Shift
A+NUMBER | *3 | Shift (looking ahead, we know to stop at M)
A+M | *3 | Reduce (looking ahead, we know to stop at M)
这是正确的(当然,它还没有完全解析)?此外,1 符号前瞻是否也告诉我们不要减少A+M
到A
,因为这样做会导致读取后不可避免的语法错误*3
?