是否可以为在 Bison 中定义为非终端的运算符定义运算符优先级?
Is it possible to define operator precedence for operators who are defined as a non-terminal in Bison?
我无法找到一个解决方案来为我当前的语法规则应用运算符优先级。这些是关于一元和二元运算符,如 +、-、* 等。然后将这些运算视为表达式。
我的grammar/precedence规则如下(以大写单词作为记号):
%left PLUS MINUS
%left MUL DIV
%left UMINUS NOT
expr : expr binop expr {$$ = new BinOpExpression(, , );}
| NOT expr {$$ = new UnaryBooleanNegationExpression();}
| MINUS expr %prec UMINUS {$$ = new UnaryNumericNegationExpression();}
| LPAREN expr RPAREN {$$ = ;}
;
binop
: PLUS { $$ = new Add(); }
| MINUS { $$ = new Sub(); }
| MUL { $$ = new Mul(); }
| DIV { $$ = new Div(); }
| GT { $$ = new GreaterThan(); }
| GE { $$ = new GreaterOrEqual(); }
| ...
;
问题在于优先级规则仅适用于一元减号运算符。例如,我的编译器为表达式“1+-2*3-8”返回的解是 11 而不是 -13。表达式被评估为(前缀表示法):
+(
1,
*(
-2,
-(3, 8)
)
)
这表明运算符是按照它们被发现的顺序应用的。为了解决这个问题,我为每个运算符(如下所示)添加了一条新规则来解决问题:
expr : expr PLUS expr {$$ = new BinOpExpression(, , new Add());}
| expr MINUS expr {$$ = new BinOpExpression(, , new Sub());}
| expr MUL expr {$$ = new BinOpExpression(, , new Mul());}
| expr DIV expr {$$ = new BinOpExpression(, , new Div());}
| ...
;
但我想避免这种情况,因为我必须将 1 条规则(例如 expr binop expr
)转换为 19 条不同的规则(每个规则对应一元、二元和赋值运算)只是为了添加正确的运算符优先级.有没有办法避免这种情况,但仍能获得正确的运算符优先级?
您看到的基本问题是每条规则只能有一个优先级,那么规则 expr: expr binop expr
的优先级应该是多少?因此,您需要为每个优先级别至少制定一个规则。你可以这样做:
expr : expr addop expr %prec PLUS
| expr mulop expr %prec MUL
...
addop : PLUS | MINUS
mulop : MUL | DIV
不需要那么多的 expr 规则,但实际上并不比为每个运算符使用单独的规则更简单。
我无法找到一个解决方案来为我当前的语法规则应用运算符优先级。这些是关于一元和二元运算符,如 +、-、* 等。然后将这些运算视为表达式。
我的grammar/precedence规则如下(以大写单词作为记号):
%left PLUS MINUS
%left MUL DIV
%left UMINUS NOT
expr : expr binop expr {$$ = new BinOpExpression(, , );}
| NOT expr {$$ = new UnaryBooleanNegationExpression();}
| MINUS expr %prec UMINUS {$$ = new UnaryNumericNegationExpression();}
| LPAREN expr RPAREN {$$ = ;}
;
binop
: PLUS { $$ = new Add(); }
| MINUS { $$ = new Sub(); }
| MUL { $$ = new Mul(); }
| DIV { $$ = new Div(); }
| GT { $$ = new GreaterThan(); }
| GE { $$ = new GreaterOrEqual(); }
| ...
;
问题在于优先级规则仅适用于一元减号运算符。例如,我的编译器为表达式“1+-2*3-8”返回的解是 11 而不是 -13。表达式被评估为(前缀表示法):
+(
1,
*(
-2,
-(3, 8)
)
)
这表明运算符是按照它们被发现的顺序应用的。为了解决这个问题,我为每个运算符(如下所示)添加了一条新规则来解决问题:
expr : expr PLUS expr {$$ = new BinOpExpression(, , new Add());}
| expr MINUS expr {$$ = new BinOpExpression(, , new Sub());}
| expr MUL expr {$$ = new BinOpExpression(, , new Mul());}
| expr DIV expr {$$ = new BinOpExpression(, , new Div());}
| ...
;
但我想避免这种情况,因为我必须将 1 条规则(例如 expr binop expr
)转换为 19 条不同的规则(每个规则对应一元、二元和赋值运算)只是为了添加正确的运算符优先级.有没有办法避免这种情况,但仍能获得正确的运算符优先级?
您看到的基本问题是每条规则只能有一个优先级,那么规则 expr: expr binop expr
的优先级应该是多少?因此,您需要为每个优先级别至少制定一个规则。你可以这样做:
expr : expr addop expr %prec PLUS
| expr mulop expr %prec MUL
...
addop : PLUS | MINUS
mulop : MUL | DIV
不需要那么多的 expr 规则,但实际上并不比为每个运算符使用单独的规则更简单。