我正在设计一个非常简单的语法,我使用一元减操作数。但是,我遇到了转变/减少冲突。在 Bison 手册以及我查看的其他任何地方,它都说我应该定义一个新标记并赋予它比二进制减操作数更高的优先级,然后在规则中使用“%prec TOKEN”。
我已经这样做了,但我仍然收到警告。为什么?
我正在使用野牛(GNU Bison)2.4.1。语法如下所示:
%{
#include <string>
extern "C" int yylex(void);
%}
%union {
std::string token;
}
%token <token> T_IDENTIFIER T_NUMBER
%token T_EQUAL T_LPAREN T_RPAREN
%right T_EQUAL
%left T_PLUS T_MINUS
%left T_MUL T_DIV
%left UNARY
%start program
%%
program : statements expr
;
statements : '\n'
| statements line
;
line : assignment
| expr
;
assignment : T_IDENTIFIER T_EQUAL expr
;
expr : T_NUMBER
| T_IDENTIFIER
| expr T_PLUS expr
| expr T_MINUS expr
| expr T_MUL expr
| expr T_DIV expr
| T_MINUS expr %prec UNARY
| T_LPAREN expr T_RPAREN
;
最佳答案
%prec
并没有你所希望的那样做。它告诉 Bison,在您有 - a * b
的情况下,您希望将其解析为 (- a) * b
而不是 - (a * b)
。换句话说,这里它更喜欢 UNARY
规则而不是 T_MUL
规则。在任何一种情况下,您都可以确定 UNARY
规则最终会得到应用,这只是输入减少到一元参数的顺序问题。
在你的语法中,事情非常不同。 line
非终结符的任何序列都将构成 sequence
,并且没有说 line
非终结符必须在行尾结束。事实上,任何表达式都可以是 line
。所以这里基本上有两种解析 a - b
的方法:作为带有二进制减号的单行,或者作为两个“行”,第二行以一元减号开头。没有什么可以决定哪些规则将适用,因此基于规则的优先级在这里还不起作用。
您的解决方案是通过要求每个 line
实际上以行尾符号结尾或后跟行尾符号来纠正行拆分。
如果你真的想要你的语法关于行尾的行为,你需要两个单独的非终结符来表达可以和不能以 T_MINUS
开头的表达式。您必须将其向上传播:第一个 line
可能以一元减号开头,但后续的不能。在括号内,以减号开头也可以。
关于grammar - 在 Bison 中使用一元减号的优先级并不能解决移位/减少冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10772504/