4

我正在设计一个非常简单的语法,我使用一元减操作数。但是,我遇到了转变/减少冲突。在 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
;
4

2 回答 2

8

%prec没有你希望的那么多。它告诉 Bison,在- a * b您想要将其解析为(- a) * b而不是- (a * b). 换句话说,在这里它将更喜欢UNARY规则而不是T_MUL规则。无论哪种情况,您都可以确定该UNARY规则最终会得到应用,这只是输入减少为一元参数的顺序问题。

在您的语法中,情况大不相同。任何line非终结符序列都将组成 a sequence,并且没有什么可以说line非终结符必须在行尾结束。事实上,任何表达式都可以是line. 所以这里基本上有两种解析方法a - b:或者作为带有二进制减号的单行,或者作为两个“行”,第二种以一元减号开头。没有什么可以决定哪些规则将适用,因此基于规则的优先级在这里还不起作用。

line您的解决方案是通过要求每个实际以行尾符号结束或后跟一个行尾符号来纠正您的行拆分。

If you really want the behaviour your grammar indicates with respect to line endings, you'd need two separate non-terminals for expressions which can and which cannot start with a T_MINUS. You'd have to propagate this up the tree: the first line may start with a unary minus, but subsequent ones must not. Inside a parenthesis, starting with a minus would be all right again.

于 2012-07-20T13:53:25.540 回答
4

expr 规则没问题(没有 %prec UNARY)。您的班次/减少冲突来自规则:

statements : '\n'
           | statements line
;

规则不是你想的那样。例如你可以写:

a + b c + d

我认为这不应该是有效的输入。

但程序规则也不是很健全:

program : statements expr
;

规则应该是这样的:

program: lines;

lines: line | lines line;

line: statement "\n" | "\n";

statement: assignment | expr;
于 2012-06-01T13:43:28.660 回答