English 中文(简体)
How to find shift/reduce conflict in this yacc file?
原标题:
  • 时间:2009-11-15 12:48:46
  •  标签:
  • yacc

When I try to use yacc on the following file I get the error conflicts: 1 shift/reduce How can I find and fix the conflict?

/* C-Minus BNF Grammar */

%token ELSE
%token IF
%token INT
%token RETURN
%token VOID
%token WHILE

%token ID
%token NUM

%token LTE
%token GTE
%token EQUAL
%token NOTEQUAL
%%

program : declaration_list ;

declaration_list : declaration_list declaration | declaration ;

declaration : var_declaration | fun_declaration ;

var_declaration : type_specifier ID  ; 
                | type_specifier ID  [  NUM  ]   ;  ;

type_specifier : INT | VOID ;

fun_declaration : type_specifier ID  (  params  )  compound_stmt ;

params : param_list | VOID ;

param_list : param_list  ,  param
           | param ;

param : type_specifier ID | type_specifier ID  [   ]  ;

compound_stmt :  {  local_declarations statement_list  }  ;

local_declarations : local_declarations var_declaration
                   | /* empty */ ;

statement_list : statement_list statement
               | /* empty */ ;

statement : expression_stmt
          | compound_stmt
          | selection_stmt
          | iteration_stmt
          | return_stmt ;

expression_stmt : expression  ; 
                |  ;  ;

selection_stmt : IF  (  expression  )  statement
               | IF  (  expression  )  statement ELSE statement ;

iteration_stmt : WHILE  (  expression  )  statement ;

return_stmt : RETURN  ;  | RETURN expression  ;  ;

expression : var  =  expression | simple_expression ;

var : ID | ID  [  expression  ]  ;

simple_expression : additive_expression relop additive_expression
                  | additive_expression ;

relop : LTE |  <  |  >  | GTE | EQUAL | NOTEQUAL ;

additive_expression : additive_expression addop term | term ;

addop :  +  |  -  ;

term : term mulop factor | factor ;

mulop :  *  |  /  ;

factor :  (  expression  )  | var | call | NUM ;

call : ID  (  args  )  ;

args : arg_list | /* empty */ ;

arg_list : arg_list  ,  expression | expression ;
最佳回答

As mientefuego pointed out you grammar has the classic "dangling else" problem. You could beat the problem by assigning precedence to the rules that causes conflict.

The rule causing conflict is:

selection_stmt : IF  (  expression  )  statement
               | IF  (  expression  )  statement ELSE statement ;

First start by making ELSE and LOWER_THAN_ELSE ( a pseudo-token ) non associative:

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

This gives ELSE more precedence over LOWER_THAN_ELSE simply because LOWER_THAN_ELSE is declared first.

Then in the conflicting rule you have to assign a precedence to either the shift or reduce action:

selection_stmt : IF  (  expression  )  statement    %prec LOWER_THAN_ELSE ;
               | IF  (  expression  )  statement ELSE statement ;

Here, higher precedence is given to shifting. I have incorporated the above mentioned corrections and listed the complete grammar below:

/* C-Minus BNF Grammar */

%token ELSE
%token IF
%token INT
%token RETURN
%token VOID
%token WHILE

%token ID
%token NUM

%token LTE
%token GTE
%token EQUAL
%token NOTEQUAL

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
%%

program : declaration_list ;

declaration_list : declaration_list declaration | declaration ;

declaration : var_declaration | fun_declaration ;

var_declaration : type_specifier ID  ; 
                | type_specifier ID  [  NUM  ]   ;  ;

type_specifier : INT | VOID ;

fun_declaration : type_specifier ID  (  params  )  compound_stmt ;

params : param_list | VOID ;

param_list : param_list  ,  param
           | param ;

param : type_specifier ID | type_specifier ID  [   ]  ;

compound_stmt :  {  local_declarations statement_list  }  ;

local_declarations : local_declarations var_declaration
                   | /* empty */ ;

statement_list : statement_list statement
               | /* empty */ ;

statement : expression_stmt
          | compound_stmt
          | selection_stmt
          | iteration_stmt
          | return_stmt ;

expression_stmt : expression  ; 
                |  ;  ;

selection_stmt : IF  (  expression  )  statement    %prec LOWER_THAN_ELSE ;
               | IF  (  expression  )  statement ELSE statement ;

iteration_stmt : WHILE  (  expression  )  statement ;

return_stmt : RETURN  ;  | RETURN expression  ;  ;

expression : var  =  expression | simple_expression ;

var : ID | ID  [  expression  ]  ;

simple_expression : additive_expression relop additive_expression
                  | additive_expression ;

relop : LTE |  <  |  >  | GTE | EQUAL | NOTEQUAL ;

additive_expression : additive_expression addop term | term ;

addop :  +  |  -  ;

term : term mulop factor | factor ;

mulop :  *  |  /  ;

factor :  (  expression  )  | var | call | NUM ;

call : ID  (  args  )  ;

args : arg_list | /* empty */ ;

arg_list : arg_list  ,  expression | expression ;
问题回答

maybe you should try a yacc -v <filename>, it generates an output of the details.

I tested here, and your grammar description fails in the classic "dangling else" problem.

Take a look at this Wikipedia article.

Ahem, the correct answer to this problem is usually: do nothing.

Shift/reduce conflicts are expected with ambiguous grammars. They are not errors, they are conflicts.

The conflict will be resolved by preferring shift over reduce, which just happens to solve the canonical dangling else problem.

And bison even has an %expect n statement so that you don t get a S/R conflict warning when there are exactly n conflicts.

First, get a state machine output from yacc. A state which can be either shifted or reduced represents a shift/reduce conflict. Find one, and then solve the conflict by rewriting the grammar.





相关问题
How to turn this into a parser

If I just add on to the following yacc file, will it turn into a parser? /* C-Minus BNF Grammar */ %token ELSE %token IF %token INT %token RETURN %token VOID %token WHILE %token ID %token NUM %...

Bison/Yacc, make literal token return its own value?

Below is my rule, when i replace $2 with = my code works. I know by default all literal tokens uses their ascii value (hence why multi character token require a definition) The below doesnt work. ...

What s wrong with this yacc file?

When I run yacc -d parser.y on the following file I get the following errors: parser.y:23.3-24.4: warning: unused value: $4 15 rules never reduced parser.y: warning: 7 useless nonterminals and 15 ...

How to find shift/reduce conflict in this yacc file?

When I try to use yacc on the following file I get the error conflicts: 1 shift/reduce How can I find and fix the conflict? /* C-Minus BNF Grammar */ %token ELSE %token IF %token INT %token RETURN %...

Deriving a state machine from a BNF grammar

I am trying to put together a proof of concept of an XSS-safe string interpolation scheme. Given a string with substitutions, "Hello <b>$planetoid</b>!" I want break it into literal ...

热门标签