Bison - 一元运算符什么时候真正需要 %prec?

Bison - when is %prec really needed for unary operators?

我目前是第一次玩 Flex 和 Bison。我已经阅读了 Bison manual page 上的上下文优先级。尝试在不使用 %prec 指令的情况下构建一个最小示例,因为我不太熟悉它的实际作用。这是我的最小示例。

弹性文件

%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(); }

%%

野牛档案

%{
#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 { $$ =  + ; eval = $$; }
        |   expr MINUS expr { $$ =  - ; eval = $$; }
        |   expr MULTIPLY expr { $$ =  * ; eval = $$; }
        |   MINUS expr { $$ = -; eval = $$; }
        |   INT
        ;

%%

主cpp文件

#include <iostream>

int eval = 0;
extern int yyparse();

int main()
{
    yyparse();
    std::cout << eval << std::endl;
    return 0;
}

我没有进行深入测试,但对于我能想到的每一个使用一元负号的组合,我都得到了正确的结果。我只是那么幸运,还是仅在某些特殊情况下才需要 %prec 指令?当需要指令时,我也会很感激示例,这样我就可以自己评估堆栈上的移位和减少。

谢谢

您的代码产生了错误的解析但产生了正确的结果,因为一元减号运算符等效于乘以 -1,而乘法是结合的。因此,即使将 -2*3 解析为 -(2*3) 而不是 (-2)*3,结果值也是相同的。

对于像 -2-3 这样的表达式,您得到了正确的解析,因为您已将 - 声明为左结合的,因此 (-2)-3 优于 [=16] =],就像 (1-2)-3 优于 1-(2-3)

那么什么时候不需要声明一元减号的优先级?如果

  • 唯一既是前缀又是中缀的运算符是-

  • 优先级高于(二进制)的每个运算符 ⊕ −, −(ab)=( −a)⊕b;

  • 你不关心得到一个正确的解析树。

这适用于 *,但通常无法用于(整数)/% .