ccompiler-constructionbisonflex-lexer

flex and bison behave unexpectedly towards my input


I was trying to write a logical expression evaluation tool with flex and bison. I've gone over the code many times but when I run the executable it just ignores my input and prints Syntax error after several inputs. My flex file lexer.l is

%{
#include "parser.tab.h"
%}


%%

"&&"        { return AND; }
"||"        { return OR; }
"!"         { return NOT; }
"=="        { return EQ; }
"!="        { return NEQ; }
"<="        { return LEQ; }
">="        { return GEQ; }
"<"         { return LT; }
">"         { return GT; }
"("         { return LPAREN; }
")"         { return RPAREN; }
[0-9]+      { yylval = atoi(yytext); return NUM; }
"true"      { return TRUE; }
"false"     { return FALSE; }
[ \t\n]+    { /* Skip whitespace */ }
.           { return yytext[0]; }

%%

int yywrap() {
    return 1;
}


And my bison file parser.y is

%{
#include <stdio.h>

int comparisons = 0;
int actual_comparisons = 0;

void yyerror(const char *s);
int yylex(void);
%}

%token AND OR NOT EQ NEQ LEQ GEQ LT GT LPAREN RPAREN NUM TRUE FALSE

%left OR
%left AND
%right NOT
%nonassoc EQ NEQ LEQ LT GT GEQ

%%

input: input expr '\n' { printf("%s, %d, %d", $2 ? "TRUE" : "FALSE", comparisons, actual_comparisons);}
    | /* empty */      { /*empty*/ }
    ;

expr: expr OR expr       { $$ = $1 || $3; comparisons += 1; actual_comparisons += ($1 ? 0 : 1); }
    | expr AND expr      { $$ = $1 && $3; comparisons += 1; actual_comparisons += ($1 ? 1 : 0); }
    | NOT expr           { $$ = !$2; }
    | expr EQ expr       { $$ = $1 == $3; comparisons += 1; actual_comparisons += 1; }
    | expr NEQ expr      { $$ = $1 != $3; comparisons += 1; actual_comparisons += 1; }
    | expr LEQ expr      { $$ = $1 <= $3; comparisons += 1; actual_comparisons += 1; }
    | expr GEQ expr      { $$ = $1 >= $3; comparisons += 1; actual_comparisons += 1; }
    | expr LT expr       { $$ = $1 < $3; comparisons += 1; actual_comparisons += 1; }
    | expr GT expr       { $$ = $1 > $3; comparisons += 1; actual_comparisons += 1; }
    | LPAREN expr RPAREN { $$ = $2; }
    | NUM                { $$ = $1; }
    | TRUE               { $$ = 1; }  
    | FALSE              { $$ = 0; }  
    ;

%%

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

int main(void) {
    return yyparse();
}


%%


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

int main() {
    return yyparse();
}

I then did

bison -d parser.y
flex lexer.l
gcc parser.tab.c lex.yy.c -o logic_eval -lm
./logic_eval

But the executable doesn't print any information after \n.

I have examined the operator priority, associativity and the productions over and over, but did not find anything suspicious. Any help would be appreciated!


Solution

  • The most obvious problem is that your parser is expecting newline ('\n') tokens, but your lexer never generates them -- it treats a newline as whitespace and skips it.

    Remove \n from your whitespace lexer rule and add an explicit newline rule:

    [ \t\r]+    { /* Skip whitespace */ }
    [\n]        { return *yytext; }
    

    Adding CR to your whitespace rule will also skip that, so your parser can handle DOS formatted files transparently.