Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shift/reduce conflicts in bison

I'm new to Bison and I'm having trouble with shift/reduce conflicts... I'm trying to load from file to array data[]:

struct  _data
{
  char name[50]; 
  char surname[50]; 
  int year;
} data[1000];

Here is part of my bison code:

%token ID NUM NL EOF 

%%

File   : List EOF
       ;
List   : Record
       | List Record
       ;
Record : Name Surname Year NL  { count++; }
       | NL                    { count++; }
       | /*empty*/
       ;
Name   : ID                    { strcpy(data[count].name, yytext); }
       ;
Surname: ID                    { strcpy(data[count].surname, yytext); }
       ;
Year   : NUM                   { data[count].year= atoi(yytext); }
       ;

%%            

I get this error:

conflicts: 5 shift/reduce

Any idea where I went wrong?

like image 886
Zrinka Avatar asked Jul 11 '13 09:07

Zrinka


People also ask

What is a shift-reduce conflict?

The Shift-Reduce Conflict is the most common type of conflict found in grammars. It is caused when the grammar allows a rule to be reduced for particular token, but, at the same time, allowing another rule to be shifted for that same token.

How do you identify a shift-reduce conflict?

In a shift-reduce conflict, the default is to shift. In a reduce-reduce conflict, the default is to reduce by the earlier grammar rule (in the yacc specification). Rule 1 implies that reductions are deferred in favor of shifts when there is a choice.

What is shift reduce parser explain the conflicts that may occur during shift-reduce parsing?

Shift Reduce Parser is a type of Bottom-Up Parser. It generates the Parse Tree from Leaves to the Root. In Shift Reduce Parser, the input string will be reduced to the starting symbol. This reduction can be produced by handling the rightmost derivation in reverse, i.e., from starting symbol to the input string.


1 Answers

You can use the -v option to get bison to produce an .output file containing a lot more information which can help you diagnose shift/reduce conflicts. In particular, it will show you every parser state, including the list of items, and also indicate which states have conflicts.

But in this case, the problem is pretty simple. Stripped to its essentials you have:

List  : Record

Record: Something
      | /* Nothing */

Ignoring what the definition of Something is, the problem is that a List can consist of any number of Records, one after another, and a Record can be empty. That means that nothing can be parsed as any number of empty Records, which is totally ambiguous. Any two consecutive Somethings in the input could be separated by 0, 1, 2, 42, or 273 empty Records. Since the parser can't know whether to start parsing a new Something (shift) or to emit an empty Record (reduce), it complains that there is a shift/reduce conflict.

The solution is also pretty simple. We can see that a non-empty Something must end with a NL; presumably the intent was that the File consists of any number of Records, each on its own line. So we can rewrite:

List  : Record
      | List NL Record

Record: Name Surname Year
      | %empty

Now a Record, empty or not, must be followed by either a NL or whatever can follow List (in this case the end-of-input indicator, although you normally don't need to add such a rule explicitly). It cannot be directly followed by another Record.

like image 164
rici Avatar answered Sep 20 '22 14:09

rici