语法如下:
1. program -> declaration-list
2. declaration-list -> declaration-list declaration | declaration
3. declaration -> var-declaration | fun-declaration
4. var-declaration -> type-specifier ID ; | type-specifier ID [ NUM ] ;
5. type-specifier -> int | void
6. fun-declaration -> type-specifier ID ( params ) compound-stmt
7. params -> param-list | void
8. param-list -> param-list , param | param
9. param -> type-specifier ID | type-specifier ID [ ]
10. compound-stmt -> { local-declarations statement-list }
11. local-declarations -> local-declarations var-declarations | empty
12. statement-list -> statement-list statement | empty
13. statement -> expression-stmt | compound-stmt | selection-stmt |
iteration-stmt | return-stmt
14. expression-stmt -> expression ; | ;
15. selection-stmt -> if ( expression ) statement |
if ( expression ) statement else statement
16. iteration-stmt -> while ( expression ) statement
17. return-stmt -> return ; | return expression ;
18. expression -> var = expression | simple-expression
19. var -> ID | ID [ expression ]
20. simple-expression -> additive-expression relop additive-expression |
additive-expression
21. relop -> <= | < | > | >= | == | !=
22. additive-expression -> additive-expression addop term | term
23. addop -> + | -
24. term -> term mulop factor | factor
25. mulop -> * | /
26. factor -> ( expression ) | var | call | NUM
27. call -> ID ( args )
28. args -> arg-list | empty
29. arg-list -> arg-list , expression | expression
通过bison -d -v xyz.l获得的转移减少冲突处于状态97
state 97
29 selection-stmt: IF LFT_BRKT expression RGT_BRKT statement .
30 | IF LFT_BRKT expression RGT_BRKT statement . ELSE statement
ELSE shift, and go to state 100
ELSE [reduce using rule 29 (selection-stmt)]
$default reduce using rule 29 (selection-stmt)
但我不知道如何解决这个冲突。等待答案。
答案 0 :(得分:7)
您可能希望解决冲突,转而使用'else'。幸运的是,野牛已经自动为你做了这件事(但它仍然让你知道它。)
Bison手册的5.2部分正是关于这种转变/减少冲突。正如它所说的那样,如果你想要%expect
声明,你可以消除警告信息。
这种特定的转移/减少冲突是原始yacc
解析器生成器解决策略动机的很大一部分,如yacc或Dragon书中的历史文章所述,因为它是从语法中消除冲突令人难以置信。因此,这个问题的解决方案是一个很好的脑筋急转弯,但不应该在实践中部署。使用Bison的内置歧义消除更具可读性和可维护性,并且这样做没有任何不精确或羞耻。
如果我没记错的话,这个问题就是龙书中的练习之一。解决方案的基本概要如下:
如果statement
中的if (expression) statement
无法成为if
声明,则不会出现问题。 else
无法开始声明,因此前瞻中的if ( 0 ) break;
无法缩小else
。问题是if (0) if (0) break; else
现在,是否应该移位(并因此附加到第二个if)或者是否应减少第二个if
并使else
移位是不明显的到第一个if
。正常练习(和yacc的歧义解决算法)决定了第一个。
因此,让我们区分完整的if语句和不完整的if语句。现在我们可以说else
不能立即跟一个不完整的if语句(一个没有else子句)。换句话说,完整的if语句不能将不完整的if语句作为其第一个封闭语句。
所以我们可以尝试类似的东西:
conditional : complete_conditional
| incomplete_conditional
;
complete_conditional : IF ( expression ) statement_other_than_conditional ELSE statement
| IF ( expression ) complete_conditional ELSE statement
;
incomplete_conditional : IF ( expression ) statement
;
现在我们需要:
statement : statement_other_than_conditional
| incomplete_conditional
| complete_conditional
;
答案 1 :(得分:3)
请在此处查看我的回答:Reforming the grammar to remove shift reduce conflict in if-then-else。根据我的经验,你永远不应该留下“已知冲突”,解决它们。使用%expect N和N!= 0是不安全的,恕我直言(当然GLR除外)。
答案 2 :(得分:2)
我试过了@rici的答案(接受的答案),失败。
statement: conditional | statement_other_than_conditional;
conditional: complete_conditional | incomplete_conditional;
complete_conditional: L_IF '(' expression ')' statement_other_than_conditional L_ELSE statement
| L_IF '(' expression ')' complete_conditional L_ELSE statement;
incomplete_conditional: L_IF '(' expression ')' statement;
statement_other_than_conditional: ';';
expression: IDENTIFIER;
$ bison --report=all rrr.y
rrr.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
State 14 conflicts: 1 shift/reduce
State 15 conflicts: 1 shift/reduce
State 14
3 conditional: complete_conditional . [$end, L_ELSE]
6 complete_conditional: L_IF '(' expression ')' complete_conditional . L_ELSE statement
L_ELSE shift, and go to state 16
L_ELSE [reduce using rule 3 (conditional)]
$default reduce using rule 3 (conditional)
State 15
2 statement: statement_other_than_conditional . [$end, L_ELSE]
5 complete_conditional: L_IF '(' expression ')' statement_other_than_conditional . L_ELSE statement
L_ELSE shift, and go to state 17
L_ELSE [reduce using rule 2 (statement)]
$default reduce using rule 2 (statement)
Chris Dodd's answer(至少似乎是)好。有点适应:
statement: if_statement | noif_statement;
if_statement:
IF '(' expression ')' statement
| IF '(' expression ')' noif_statement ELSE if_statement
;
noif_statement:
IF '(' expression ')' noif_statement ELSE noif_statement
| RETURN ';'
;
expression: IDENTIFIER;
如果您还有语句规则:如果正确递归(不以statement
结尾),则只需添加 noif_statement < / em>(如RETURN ';'
)。
否则,例如
statement: blah '(' blah ')' statement ;
复制它:
| blah '(' blah ')' if_statement
| blah '(' blah ')' noif_statement
将第一个变体添加到 if_statement ,第二个变量添加到 noif_statement 。
答案 3 :(得分:0)
另一种可行的策略(@rici接受的答案不起作用,@ RaqaouPi归功于Chris Dodd的答案)是将代码视为一系列if-else / for / while前缀,也许后跟一个单个悬挂if或最后一个简单语句。此示例改编自this Nearley grammar for a C-like language。
Statement -> StatementPrefix:* (StatementEnd | DanglingIf)
StatementNoDangle -> StatementPrefix:* StatementEnd
StatementPrefix -> "if" _ "(" _ Expression _ ")" _ StatementNoDangle _ "else" _
| "while" _ "(" _ Expression _ ")" _
DanglingIf -> "if" _ "(" _ Expression _ ")" _ Statement
StatementEnd -> Simple _ ";"
| "return" (_ Expression):? _ ";"
| BlockStatement
| "break" _ ";"
| "continue" _ ";"