1
votes

My objective is to create a parser for a small language. It is currently giving me one shift/reduce error.

My CFG is ambiguous somewhere, but I can't figure out where

prog:    PROGRAM beg                   {$$ = "program" $2;}
    |   PROGRAM stmt beg               {$$ = "program" $2 $3;}

beg:    BEG stmt END                   {$$ = "begin" $2 "end";}
    | BEG END                      {$$ = "begin" "end";}


stmt:   beg             {$$ = $1;}
    | if_stmt                   {$$ = $1;}/*
    | IF expr THEN stmt                 {$$ = $1 $2 $3 $4;}*/
    | WHILE expr beg                    {$$ = "while" $2 $3;}
    | VAR COLEQUALS arithexpr SEMI      {$$ = $1 ":=" $3 ";";}
    | VAR COLON INTEGER SEMI            {$$ = $1 ":" "integer" ";";} /*Declaring an integer */
    | VAR COLON REAL SEMI               {$$ $1 ":" "real" ";";}   /*declaring a real */

if_stmt:  IF expr THEN stmt            {$$ = "if" $2 "then" $4;}
    | IF expr THEN stmt ELSE stmt      {$$ = "if" $2 "then" $4 "else" $6;}

expr:   NOT VAR                        {$$ = "!" $2;}
| VAR GREATERTHAN arithexpr        {$$ = $1 ">" $3;}
    | VAR LESSTHAN arithexpr           {$$ = $1 "<" $3;}
    | VAR GREATERTHANEQUALTO arithexpr {$$ = $1 ">=" $3;}
    | VAR LESSTHANEQUALTO arithexpr    {$$ = $1 "<=" $3;}
    | VAR EQUALS arithexpr             {$$ = $1 "==" $3;}
    | VAR NOTEQUALS arithexpr          {$$ = $1 "!=" $3;}
    | arithexpr AND arithexpr          {$$ = $1 "&&" $3;}
    | arithexpr OR arithexpr           {$$ = $1 "||" $3;}


arithexpr:  arithexpr PLUS term            {$$ = $1 + $3;}
    |  arithexpr MINUS term            {$$ = $1 - $3;}
    |   term                   {$$ = $1;}

term:   term TIMES factor          {$$ = $1 * $3;}
    | term DIVIDE factor           {$$ = $1 / $3;}
    | factor               {$$ = $1;}

factor:   VAL                              {$$ = $1;}
1
Doesn't Bison give you any clues in the error message as to where the conflict is?500 - Internal Server Error
It only tells you how many conflicts you have, not where they are. Errors on the other hand are given to youChristopher Shifflett
Use the -v option to get a .output file showing where and what the conflicts are...Chris Dodd

1 Answers

1
votes

The "error" comes from the ambiguity in the if_stmt's else part: stmt can be an if_stmt, and it's not clear to which if a else-part belongs, e.g. if you write:

if y1 then if y2 then x=1 else x=2

Then the else-part could either belong to the first if or the second one.

This question has been asked in variations many times, just search for if then else shift reduce

For diagnosis (to find out that you are also a victim of that if then else shift reduce problem) you can tell bison to produce an output-file with

bison -r all  myparser.y

which will produce a file myparser.output, in which you can find for your case:

State 50 conflicts: 1 shift/reduce
....
state 50

   11 if_stmt: IF expr THEN stmt .  [ELSE, BEG, END]
   12        | IF expr THEN stmt . ELSE stmt

    ELSE  shift, and go to state 60

    ELSE      [reduce using rule 11 (if_stmt)]
    $default  reduce using rule 11 (if_stmt)


state 51
...

One solution for this would be to introduce a block-statement and only alow these as statements in the if and else part:

stmt: ...
    | blk_stmt
blk_stmt: BEGIN stmt END
if_stmt:  IF expr THEN blk_stmt
    | IF expr THEN blk_stmt ELSE blk_stmt

Which would for a modified c-language mean that only

if x1 then {if x2 then {y=1}} else {y=2}

be possible (with { representing the BEGIN-token and }representing the END-token) thus resolving the ambiguity.