cbisonarithmetic-expressions

Can't make arithmetic operator precedence with parenthesis in bison


I've currently building a Python parser and I'm at the definition of arithmetic expressions. The rules behind arithmetic expressions are working properly up until I add the parenthesis.

Here is the starting point:

%token TOKEN_ARITH_ADD TOKEN_ARITH_SUB
%token TOKEN_ARITH_MUL TOKEN_ARITH_DIV TOKEN_ARITH_MOD
%token TOKEN_ARITH_POWER
%token TOKEN_ASSIGN
%token TOKEN_PAREN_OPEN TOKEN_PAREN_CLOSE

and then:

arith_expr: factor
    | arith_expr TOKEN_ARITH_ADD factor { $$ = ast_init_arith_op($3, "+", $1); };
    | arith_expr TOKEN_ARITH_SUB factor { $$ = ast_init_arith_op($3, "-", $1); };
    | TOKEN_PAREN_OPEN arith_expr TOKEN_PAREN_CLOSE { $$ = $2; };
;

factor: power { $$ = ast_init_arith_op($1, NULL, NULL); };
    | factor TOKEN_ARITH_MUL power { $$ = ast_init_arith_op($3, "*", $1); };
    | factor TOKEN_ARITH_DIV power { $$ = ast_init_arith_op($3, "/", $1); };
    | factor TOKEN_ARITH_MOD power { $$ = ast_init_arith_op($3, "%", $1); };
;

power: term
    | power TOKEN_ARITH_POWER term { $$ = ast_init_arith_op($3, "**", $1); }

term: identifier;
    | literal_int;
    | literal_float;

The results is that if, for instance, I enter this :

myVar = (a + b) * 2

I get error: syntax error, unexpected TOKEN_ARITH_MUL, expecting TOKEN_EOL.

So I've tried to change the %token for %left for the first three ones, with the same problem.

I've also tried to change the %token for the assign to a %right, unfortunately I got an error at compile time (error: rule given for assign, which is a token) - in retrospect, make sense.

It looks like the TOKEN_PAREN_OPEN arith_expr TOKEN_PAREN_CLOSE collapse to a arith_expr and the assign kicks in right away. What am I doing wrong?


Solution

  • According to your grammar, a multiplication operator can appear only between a factor and a power. An expression enclosed in parentheses is neither and cannot be reduced to either. As far as the part of the grammar presented goes, it is an arith_expr.

    @n.m.'s comment is correct: you put the rule for a parenthesized expression in the wrong place. It should be a term, not an arith_expr. However, your followup comment suggests that you misunderstood. Do not change the production. Just move it, as is, to be one of the alternatives for term:

    term: identifier
        | literal_int
        | literal_float
        | TOKEN_PAREN_OPEN arith_expr TOKEN_PAREN_CLOSE
    ;
    

    That allows a parenthsized expression to appear as a complete expression itself or as an operand of any operator.