4

私は単項マイナスオペランドを使用する非常に単純な文法を考案しています。ただし、シフト/削減の競合が発生します。Bison のマニュアルや他のどこを見ても、新しいトークンを定義し、バイナリ マイナス オペランドよりも優先順位を高くしてから、ルールで「%prec TOKEN」を使用する必要があると書かれています。

私はそれをしましたが、それでも警告が表示されます。なんで?

私は bison (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)UNARYT_MULUNARY

あなたの文法では、物事は非常に異なっています。非終端記号の任意のシーケンスがlineを構成し、非終端記号が行末で終わらなければならないsequenceということは何もありません。line実際、どの式もline. したがって、ここでは基本的に 2 つの解析方法がありますa - b。バイナリ マイナスを含む単一行として、または単項マイナスで始まる 2 つの「行」としてのいずれかです。これらのルールのどれが適用されるかを決定するものは何もないため、ルールベースの優先順位はまだここでは機能しません。

lineあなたの解決策は、すべてが実際に行末記号で終わるか、その後に続くことを要求することにより、行分割を修正することです。

行末に関して文法が示す動作が本当に必要な場合は、T_MINUS. これをツリーに伝播する必要があります。最初のlineものは単項マイナスで始まる場合がありますが、後続のものはそうではありません。括弧内では、マイナスから始めても問題ありません。

于 2012-07-20T13:53:25.540 に答える
4

expr ルールは問題ありません (%prec UNARY なし)。shift/reduce の競合は、次のルールに由来します。

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 に答える