0

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

Marek Milkovič
  • 464
  • 1
  • 8
  • 20
  • It doesn't give the correct answer for `-2+3`. – user207421 Jun 27 '15 at 04:09
  • It does and I don't see any reason it shouldn't. As rici said, it does not produce the correct parse tree, however, it gives right answer. And based on the fact that - and + have same priorities and are left associative, this one even produces right parse tree. – Marek Milkovič Jun 28 '15 at 11:12

1 Answers1

2

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 over 1-(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) −, −(ab)=(−a)⊕b;

  • You don't care about getting a correct parse tree.

This works for *, but generally fails for (integer) / and %.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Thank you for explanation. I somehow didn't think of a wrong derivation tree. I also found a way how to turn bison into debug mode and after I see everything what is going on on the stack, I see the difference. I will try to use it to see how `%prec` works. – Marek Milkovič Jun 26 '15 at 09:08