4

我收到以下错误:

Warning : *** Shift/Reduce conflict found in state #116
between Statement ::= Matched (*) 
and     Unmatched ::= IF LPAREN Condition RPAREN Matched (*) ELSE Unmatched 
and     Matched ::= IF LPAREN Condition RPAREN Matched (*) ELSE Matched 
under symbol ELSE
Resolved in favor of shifting.

现在,我知道悬空的 else 问题,并且我尝试使语法明确:

Statement ::= Matched | Unmatched ;


Matched ::= IF LPAREN Condition RPAREN Matched ELSE Matched
            |
            Others
             ;

Unmatched ::= IF  LPAREN Condition RPAREN Statement 
              | 
              IF  LPAREN Condition RPAREN Matched ELSE Unmatched
              ;

有没有办法在没有优先运算符的情况下解决这个问题,还是语法有其他问题?

4

1 回答 1

7

问题中提出的语法没有任何问题,所以我的猜测是移位/减少冲突是与另一个产品交互的结果。

将语句拆分为Matchedand的想法Unmatched

Statement ::= Matched | Unmatched ;

正是为了确保 anelse与最近的 unmatched 正确匹配ifMatched不能用 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:如果内部StatementUnmatched

例如,考虑

while (x) if (y) do_x_and_y;

由于上述不正确的While生产,这将减少如下:

   WHILE LPAREN Condition RPAREN Unmatched_If
-> WHILE LPAREN Condition RPAREN Statement
-> Matched

但这违反了Unmatched不能遵循的要求elseMatched后面可以跟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
            | ...
            ;
于 2015-12-13T20:39:32.837 回答