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)
。
那么什么时候不需要声明一元减号的优先级?如果
唯一既是前缀又是中缀的运算符是-
优先级高于(二进制)的每个运算符 ⊕ −, −(a⊕b)=( −a)⊕b;
你不关心得到一个正确的解析树。
这适用于 *,但通常无法用于(整数)/ 和 % .
我目前是第一次玩 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)
。
那么什么时候不需要声明一元减号的优先级?如果
唯一既是前缀又是中缀的运算符是-
优先级高于(二进制)的每个运算符 ⊕ −, −(a⊕b)=( −a)⊕b;
你不关心得到一个正确的解析树。
这适用于 *,但通常无法用于(整数)/ 和 % .