问题描述
我正在为一种名为 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
语句一样不匹配。这就是“匹配”的意思。
因此,您必须将迭代语句划分为 matched
和 unmatched
变体。 (这就是为什么大多数人使用优先级或期望声明来处理悬挂的 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 '}'