Search code examples
compiler-constructionbisonflex-lexerbnf

Flex & Bison Simple BNF calculator constant output of zero


I am working through the O'Reilly Flex & Bison book by John Levine and I have encountered the following problem while attempting to compile and run the example for a simple BNF calculator

> ./fb1-5 
2 + 3 * 4
= 0
2 * 3 + 4 
= 0
c
Mystery Character c
error: syntax error

The program seems to recognize non-numerical input and exit accordingly, however any integer inputs with a mult/div/add/sub expression always result in the constant output of zero.

I have searched for similar questions on stack overflow as well as read through the chapter in O'Reilly multiple times. I am also in the process of mining through http://dinosaur.compilertools.net/bison/bison_5.html to try and find my mistake. Thanks for overlooking my bewilderment in the face of a seemingly elementary obstacle. I'm just getting started on my self journey through compilers. Any advice is appreciated.

flex (fb1-5.L):

%{
#include "fb1-5.tab.h" /*forward declaration - not yet compiled*/
%}

%%
"+" {return ADD;}
"-" {return SUB;}
"*" {return MUL;}
"/" {return DIV;}
[0-9]+ { yylval = atoi(yytext); return NUMBER;}
\n { return EOL;}
[ \t] { } /*ignore whitespace*/
.  { printf("Mystery Character %c\n", *yytext);}
%%

bison (fb1-5.y):

%{
#include <stdio.h>
%}

/*declare tokens*/
%token NUMBER
%token ADD
%token SUB
%token MUL
%token DIV
%token ABS
%token EOL

/*BNF tree*/
%%
calclist: /*nothing - matches at beginning of input*/
  | calclist exp EOL { printf("= %d\n", $1);}
  ;

exp: factor /*default $$ = $1*/
   |  exp ADD factor { $$ = $1 + $3;}
   |  exp SUB factor { $$ = $1 - $3;}
   ;

factor: term /*default $$=$1*/
    | factor MUL term { $$ = $1 * $3;}
    | factor DIV term { $$ = $1 / $3;}
    ;

term: NUMBER /*default $$=$1*/
    | ABS term { $$ = $2 >= 0 ? $2 : - $2;}
    ;
%%

int main(int argc, char **argv)
{
  yyparse();
  return 0;
}

yyerror(char *s)
{
  fprintf(stderr, "error: %s\n", s);
}

Makefile:

fb1-5: fb1-5.l fb1-5.y
    bison -d fb1-5.y
    flex fb1-5.l
    gcc -o $@ fb1-5.tab.c lex.yy.c -lfl

clean:
    rm -f core fb1-5.tab.h fb1-5.tab.c lex.yy.c fb1-5

Solution

  • printf("= %d\n", $1);
    

    Should be

    printf("= %d\n", $2);
    

    Since exp is the second thing on the right-hand side of that production.