这个 yacc 语法中的 shift/reduce 冲突在哪里?

问题描述

我正在为一种名为 C- 的语言编写解析器。我必须编写语法,所以它不会有歧义,而且我不能在 Bison 中使用任何 %prec 语句。除了 1 个班次/减少冲突之外,我已经更正了所有内容,但我无法弄清楚它在哪里。有任何想法吗?我的 .output 文件提供了有关其发生位置的以下信息:

State 163

   44 matched: IF '(' simpleExp ')' matched . ELSE matched
   46 unmatched: IF '(' simpleExp ')' matched .
   48          | IF '(' simpleExp ')' matched . ELSE unmatched

    ELSE  shift,and go to state 169

    ELSE      [reduce using rule 46 (unmatched)]
    $default  reduce using rule 46 (unmatched)

语法:

stmt                : selectStmt
                    ;

expStmt             : exp ';'
                    | ';'

compoundStmt        : '{' localDecls stmtList '}'
                    ;  

stmtList            : stmtList stmt
                    |
                    ;

otherStmt           : compoundStmt
                    | expStmt
                    | iterStmt
                    | returnStmt
                    | breakStmt
                    ;     

localDecls          : localDecls scopedVarDecl
                    |
                    ;

selectStmt          : matched
                    | unmatched
                    ;
                
matched             : IF '(' simpleExp ')' matched ELSE matched
                    | otherStmt
                    ;

unmatched           : IF '(' simpleExp ')' matched
                    | IF '(' simpleExp ')' unmatched
                    | IF '(' simpleExp ')' matched ELSE unmatched
                    ;
                    
iterStmt            : WHILE simpleExp DO selectStmt
                    | FOR ID '=' iterRange DO selectStmt
                    ;

iterRange           : simpleExp
                    | simpleExp TO simpleExp
                    | simpleExp TO simpleExp BY simpleExp
                    ;

returnStmt          : RETURN ';'
                    | RETURN exp ';'
                    ;

breakStmt           : BREAK ';'
                    ;

解决方法

问题在于,不仅可以“匹配”if 语句。以不匹配语句结尾的迭代语句与以不匹配语句结尾的 if 语句一样不匹配。这就是“匹配”的意思。

因此,您必须将迭代语句划分为 matchedunmatched 变体。 (这就是为什么大多数人使用优先级或期望声明来处理悬挂的 else。)

这是一个简单的例子,以备将来有用。 (很多非终结符没有改变,所以省略了它们的定义。我也扩展了很多缩写。)

statement: matched
         | unmatched
/* Statements which could have been extended with an else clause,* but haven't been. An unmatched statement can be the body of an
 * unmatched compound statement,which includes an `if` statement
 * whose `else` clause is unmatched. Unmatched also includes `if`
 * statements without an `else` clause.
 */
unmatched: "if" '(' simpleExp ')' statement
         | "if" '(' simpleExp ')' matched "else" unmatched
         | "while" '(' simpleExp ')' "do" unmatched
         | "for" IDENT '=' iterRange "do" unmatched
/* Statements which cannot be extended with an else clause.
 * In other words,in a `matched` every `else` matches some `if`.
 * Only `matched` statements can come between `if` and `else`,because
 * an unmatched statement would grab the `else` for itself.
 */
matched  : "if" '(' simpleExp ')' matched "else" matched
         | "while" '(' simpleExp ')' "do" matched
         | "for" IDENT '=' iterRange "do" matched
         | expStatement
         | returnStatement
         | breakStatement
         | '{' localDeclarations statementList '}'