1

I've been trying to get a simple calculator in bison working but I get a reduce issue.

Could you tell me what I'm doing wrong.

%{
#include <cstdio>
#include <iostream>
using namespace std;

// stuff from flex that bison needs to know about:
extern "C" int yylex();
extern "C" int yyparse();
extern "C" FILE *yyin;

void yyerror(const char *s);
%}

// Bison fundamentally works by asking flex to get the next token, which it
// returns as an object of type "yystype".  But tokens could be of any
// arbitrary data type!  So we deal with that in Bison by defining a C union
// holding each of the types of tokens that Flex could return, and have Bison
// use that union instead of "int" for the definition of "yystype":
%union {
    int ival;
    float fval;
    char *sval;
}

// define the "terminal symbol" token types I'm going to use (in CAPS
// by convention), and associate each with a field of the union:
%token <fval> NUM
%token <sval> STRING

/* Define the type of node our nonterminal symbols represent.
   The types refer to the %union declaration above. Ex: when
   we call an ident (defined by union type ident) we are really
   calling an (NIdentifier*). It makes the compiler happy.
 */
%type <fval> statement
%type <fval> statements

/* Operator precedence for mathematical operators */
%left TPLUS TMINUS
%left TMUL TDIV
%left UMINUS
%right TEXP

/* The Start*/
%start program

%%
// this is the actual grammar that bison will parse, but for right now it's just
// something silly to echo to the screen what bison gets from flex.  We'll
// make a real one shortly:

program: statements
    ;

statements: statement
    | statements statement
    ;

statement: NUM { $$ = $1; }
    |   statement TPLUS statement { $$ = $1 + $3; }
    | statement TMINUS statement { $$ = $1 - $3; }
    | statement TMUL statement { $$ = $1 * $3; }
    | statement TDIV statement { $$ = $1 / $3; }
    | TMINUS statement %prec UMINUS { $$ = -$2; }
    | statement TEXP statement { $$ = pow($1, $3); }
    | '(' statement ')' { $$ = $2; }
    ;

%%

int main() {
    // open a file handle to a particular file:
    FILE *myfile = fopen("Program.gb", "r");
    // make sure it is valid:
    if (!myfile) {
        cout << "I can't open Program.gb" << endl;
        return -1;
    }
    // set flex to read from it instead of defaulting to STDIN:
    yyin = myfile;

    // parse through the input until there is no more:
    do {
        yyparse();
    } while (!feof(yyin));

    return 0;
}

void yyerror(const char *s) {
    cout << "EEK, parse error!  Message: " << s << endl;
    // might as well halt now:
    exit(-1);
}
James Campbell
  • 3,511
  • 4
  • 33
  • 50
  • Posting the exact text of the error you're getting, as well as the tool version would help pinpoint the problem. – Edward Aug 21 '14 at 20:30
  • parser.y: conflicts: 2 shift/reduce and it's Bison 2.3 – James Campbell Aug 21 '14 at 21:05
  • Is `2 - 3`: 1) an instance of `statements` containing the statement `2` followed by the statement `- 3` or 2) the statement `2 - 3`? Your grammar doesn't answer that question, so `bison` reports an ambiguity. – rici Aug 21 '14 at 21:38

1 Answers1

2

To convert @rici's comment into an answer, the problem is simply in the ambiguity of the grammar you've defined. One way to fix it would be to introduce an end-of-line marker. To make it somewhat C-style, you could do it like this:

statements: statement ';'
    | statements statement ';'
    ;

Obviously, you'll need to make the matching change to the lexer if it doesn't already pass back the semicolon character.

You may also find this question useful in explaining what a shift-reduce conflict is and why they occur.

Community
  • 1
  • 1
Edward
  • 6,964
  • 2
  • 29
  • 55