I am currently playing with Flex and Bison for a first time. I have read about contextual precedence on Bison manual page. Tried to build a minimal example without using %prec
directive as I am not that familiar with what it really does. Here is my minimal example.
Flex file
%option noyywrap
%{
#include <iostream>
#include "parser.h"
int lineNum = 1;
%}
%%
[ \t]+ ;
\n { lineNum++; }
\/\/(.*) ;
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY; }
[0-9]+ {
yylval.int_val = atoi(yytext);
return INT;
}
. { std::cout << "Unknown token " << yytext << " at line " << lineNum << std::endl; yyterminate(); }
%%
Bison file
%{
#include <iostream>
#include <string>
extern int lineNum;
extern int yylex();
void yyerror(const char* e) { std::cerr << "ERROR ON LINE " << lineNum << ": " << e << std::endl; }
extern int eval;
%}
%union
{
int int_val;
}
%define parse.error verbose
%token <int_val> INT PLUS MINUS MULTIPLY
%type <int_val> expr
%left PLUS MINUS
%left MULTIPLY
%start expr
%%
expr : expr PLUS expr { $$ = $1 + $3; eval = $$; }
| expr MINUS expr { $$ = $1 - $3; eval = $$; }
| expr MULTIPLY expr { $$ = $1 * $3; eval = $$; }
| MINUS expr { $$ = -$2; eval = $$; }
| INT
;
%%
Main cpp file
#include <iostream>
int eval = 0;
extern int yyparse();
int main()
{
yyparse();
std::cout << eval << std::endl;
return 0;
}
I have not done deep testing but for every single combination using unary minus I could come up with, I got the right result. Am I just that lucky, or the %prec
directive is only needed in some special cases? Also I would appreciate example when the directive is needed so I can evaluate shifts and reduces on the stack by myself.
Thanks
Your code produces the wrong parse but the correct result, because the unary minus operator is equivalent to multiplying by -1, and multiplication is associative. So even though it is parsing
-2*3
as-(2*3)
instead of(-2)*3
, the resulting value is the same.In the case of expressions like
-2-3
, you get the correct parse because you've declared-
as being left-associative, so(-2)-3
is preferred over-(2-3)
, just like(1-2)-3
would be preferred over1-(2-3)
.So when don't you need to declare precedence for unary minus? If
The only operator which is both prefix and infix is −
Every operator ⊕ with higher precedence than (binary) −, −(a⊕b)=(−a)⊕b;
You don't care about getting a correct parse tree.
This works for *, but generally fails for (integer) / and %.