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?
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.