I'm implementing a simple calculator with flex and bison.
I'd like the following input to give -4 and not 4:
-2^2
In order to achieve -4, I had to declare the priority of ^ operator to be higher than the priority of the unary minus operator, but it doesn't work.
This is the bison code:
%{
#include <iostream>
#include <math.h>
using namespace std;
void yyerror(const char *s);
int yylex();
%}
%union {
int int_val;
char* string_val;
double double_val;
}
%token INTEGER
%left '+' '-'
%left '*' '/' '%'
%left UMINUS UPLUS
%right '^'
%type <int_val> expr_int INTEGER
%%
program: line '\n'
| '\n' { return 0; }
;
line: expr_int { cout<<$1<<endl; return 0; }
;
expr_int: expr_int '+' expr_int { $$ = $1 + $3; }
| expr_int '-' expr_int { $$ = $1 - $3; }
| expr_int '*' expr_int { $$ = $1 * $3; }
| expr_int '^' expr_int { $$ = pow($1,$3); }
| '-' INTEGER %prec UMINUS { $$ = -$2; }
| '+' INTEGER %prec UPLUS { $$ = $2; }
| INTEGER
;
%%
void yyerror(const char *s) {
printf("error");
}
int main(void) {
while(yyparse()==0);
return 0;
}
And this is the flex code:
%{
#include <iostream>
#include "calc.tab.h"
using namespace std;
void yyerror(const char *s);
%}
INTEGER [1-9][0-9]*|0
UNARY [+|\-]
BINARY [+|\-|*|^|]
WS [ \t]+
%%
{INTEGER} { yylval.int_val=atoi(yytext); return INTEGER; }
{UNARY}|{BINARY}|\n { return *yytext; }
{WS} {}
. {}
%%
//////////////////////////////////////////////////
int yywrap(void) { return 1; } // Callback at end of file
Why doesn't bison first handle 2^2 and then adds the unary minus, like I defined?
It keeps printing 4 instead...
Thanks a lot for the helpers.
Your syntax for unary minus:
'-' INTEGER %prec UMINUS
does not allow its argument to be an expression. So it unambiguously grabs the following INTEGER
and the %prec
rule is never needed.
<personal_opinion>
The problem with %prec
is that yacc/bison does not complain if the rule is not needed. So you never really know if it does anything or not. IMHO it's really better to just write an unambiguous grammar.