0

我目前是第一次玩 Flex 和 Bison。我已经阅读了Bison 手册页上的上下文优先级。试图在不使用%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 { $$ = $1 + $3; eval = $$; }
        |   expr MINUS expr { $$ = $1 - $3; eval = $$; }
        |   expr MULTIPLY expr { $$ = $1 * $3; eval = $$; }
        |   MINUS expr { $$ = -$2; eval = $$; }
        |   INT
        ;

%%

主 cpp 文件

#include <iostream>

int eval = 0;
extern int yyparse();

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

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

谢谢

4

1 回答 1

2

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

在像这样的表达式的情况下-2-3,您会得到正确的解析,因为您已声明-为左关联,因此(-2)-3是首选的-(2-3),就像(1-2)-3会被首选的一样1-(2-3)

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

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

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

  • 您不关心获得正确的解析树。

这适用于*,但通常对 (integer)/和失败%

于 2015-06-26T06:32:25.600 回答