问题中提出的语法没有任何问题,所以我的猜测是移位/减少冲突是与另一个产品交互的结果。
将语句拆分为Matched
and的想法Unmatched
:
Statement ::= Matched | Unmatched ;
正是为了确保 anelse与最近的 unmatched 正确匹配if。Matched
不能用 else 子句扩展语句;Unmatched
可能是一个声明。所以我们要求else语法中的标记不能跟在Unmatched
语句之后,从而避免过早地减少可能已经用else
子句扩展的语句。
所以在If
语句里面,else只能跟在Matched
语句后面。如果语句本身Unmatched
没有else
子句,或者else
子句本身是Unmatched
. 因此,我们有三个产品:
Unmatched_If ::= IF LPAREN Condition RPAREN Statement
| IF LPAREN Condition RPAREN Matched ELSE Unmatched ;
Matched_If ::= IF LPAREN Condition RPAREN Matched ELSE Matched ;
但这还不是全部,因为还有其他可能的复合语句。例如,考虑一个while
语句。如果语言有这样的结构,语法可能包括这样的东西:
While ::= WHILE LPAREN Condition RPAREN Statement ; /* Wrong! */
那是行不通的,因为while
语句也可以是Unmatched
,就像语句可以是完全相同的方式if...else
:如果内部Statement
是Unmatched
。
例如,考虑
while (x) if (y) do_x_and_y;
由于上述不正确的While
生产,这将减少如下:
WHILE LPAREN Condition RPAREN Unmatched_If
-> WHILE LPAREN Condition RPAREN Statement
-> Matched
但这违反了Unmatched
不能遵循的要求else。Matched
后面可以跟else,但在这种情况下以 .Matched
结尾Unmatched_If
。因此,我们有一个移位/减少冲突:
if (w)
while (x) if (y) do_this;
else do_that;
这可以解析为
IF ( Condition:[w] ) Matched:[while(x)if(y)do_this;] ELSE Statement:[do_that;]
但这实际上不是预期的解析。(缩进可能会让我们认为这是程序员的意图,但它不是语言设计者的意图。)else应该匹配第二个if,而不是第一个,导致:
if (w)
while (x)
if (y) do_this; else do_that;
所以我们需要区分匹配和不匹配的While
语句,而不仅仅是匹配和不匹配的If
语句:
Unmatched_While ::= WHILE LPAREN Condition RPAREN Unmatched ;
Matched_While ::= WHILE LPAREN Condition RPAREN Matched ;
这样,while (x) if (y) do_x_and_y;
将被解析为Unmatched_While
,因此它不再是开始的产品的一部分IF LPAREN Condition RPAREN Matched ELSE...
当然,其他复合语句也需要这样做,例如for
语句。
所以最终的结果将是这样的:
Matched ::= Matched_If
| Matched_While
| Matched_For
| ...
| Simple_Statement
;
Unmatched ::= Unmatched_If
| Unmatched_While
| Unmatched_For
| ...
;