是否可以为在 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 规则,但实际上并不比为每个运算符使用单独的规则更简单。