野牛转移减少冲突 - 无法解决

时间:2012-10-04 04:19:52

标签: bison shift-reduce-conflict

语法如下:

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)

但我不知道如何解决这个冲突。等待答案。

4 个答案:

答案 0 :(得分:7)

您可能希望解决冲突,转而使用'else'。幸运的是,野牛已经自动为你做了这件事(但它仍然让你知道它。)

Bison手册的5.2部分正是关于这种转变/减少冲突。正如它所说的那样,如果你想要%expect声明,你可以消除警告信息。

这种特定的转移/减少冲突是原始yacc解析器生成器解决策略动机的很大一部分,如yacc或Dragon书中的历史文章所述,因为它是从语法中消除冲突令人难以置信。因此,这个问题的解决方案是一个很好的脑筋急转弯,但不应该在实践中部署。使用Bison的内置歧义消除更具可读性和可维护性,并且这样做没有任何不精确或羞耻。

如果我没记错的话,这个问题就是龙书中的练习之一。解决方案的基本概要如下:

  1. 如果statement中的if (expression) statement无法成为if声明,则不会出现问题。 else无法开始声明,因此前瞻中的if ( 0 ) break;无法缩小else。问题是if (0) if (0) break; else现在,是否应该移位(并因此附加到第二个if)或者是否应减少第二个if并使else移位是不明显的到第一个if。正常练习(和yacc的歧义解决算法)决定了第一个。

  2. 因此,让我们区分完整的if语句和不完整的if语句。现在我们可以说else不能立即跟一个不完整的if语句(一个没有else子句)。换句话说,完整的if语句不能将不完整的if语句作为其第一个封闭语句。

  3. 所以我们可以尝试类似的东西:

    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" _ ";"