Search code examples
yacclex

Simple calculator program in lex and yacc not giving output


I am trying to write a very simple calculator program using lex and yacc but getting stuck in printing the output. The files are:

calc.l:

%{
#include "y.tab.h"
extern int yylval;
%}

%%
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%

calc.y:

%{
#include <stdio.h>
void yyerror(char const *s) {
    fprintf(stderr, "%s\n", s);
}
%}

%token NAME NUMBER

%%
statement: NAME '=' expression
    | expression {printf(" =%d\n", $1);}
    ;

expression: expression '+' NUMBER {$$ = $1 + $3;}
    | expression '-' NUMBER {$$ = $1 - $3;}
    | NUMBER {$$ = $1;}
    ;

The commands I have used:

flex calc.l
bison calc.y -d
gcc lex.yy.c calc.tab.c -lfl
./a.out

After running the last command although the program takes input from the keyboard but does not print anything, simply terminates. I didn't get any warning or error while compiling but it doesn't give any output. Please help.


Solution

  • You have no definition of main, so the main function in -lfl will be used. That library is for flex programs, and its main function will call yylex -- the lexical scanner -- until it returns 0.

    You need to call the parser. Furthermore, you need to call it repeatedly, because your lexical scanner returns 0, indicating end of input, every time it reads a newline.

    So you might use something like this:

    int main(void) {
      do {
        yyparse();
      } while (!feof(stdin));
      return 0;
    }
    

    However, that will reveal some other problems. Most irritatingly, your grammar will not accept an empty input, so an empty line will trigger a syntax error. That will certainly happen at the end of the input, because the EOF will cause yylex to return 0 immediately, which is indistinguishable from an empty line.

    Also, any error encountered during the parse will cause the parse to terminate immediately, leaving the remainder of the input line unread.

    On the whole, it is often better for the scanner to return a newline token (or \n) for newline characters.


    Other than the main function which you don't require, the only thing in -lfl is a default definition of yywrap. You could just define this function yourself (it only needs to return 1), or you could avoid the need for the function by adding

    %option noyywrap
    

    to your flex file. In fact, I usually recommend

    %option noyywrap noinput nounput
    

    which will avoid the compiler warnings (which you didn't see because you didn't supply -Wall when you compiled the program, which you should do.)

    Another compiler warning will be avoided by adding a declaration of yylex to your bison input file before the definition of yyerror:

    int yylex(void);
    

    Finally, yylval is declared in y.tab.h, so there is no need for extern int yylval; in your flex file. In this case, it doesn't hurt, but if you change the type of the semantic value, which you will probably eventually want to do, this line will need to be changed as well. Better to just eliminate it.