我正在尝试解决以下野牛语法中的r / r和s / r冲突
%right TOK_IF TOK_ELSE
%right '='
%left TOK_EQ TOK_NE '<' TOK_LE '>' TOK_GE
%left '+' '-'
%left '*' '/' '%'
%right TOK_POS TOK_NEG '!' TOK_NEW
%left TOK_BLK '.' TOK_CALL
%precedence TOK_PARENT
%start start
expr : expr BINOP expr {$$=$2->adopt($1,$2);}
| UNOP {$$ = $1;}
| allocator {$$ = $1;}
| call {$$ = $1;}
| expr '[' expr ']' %prec TOK_BLK {
destroy($4);
$$ = $2->adopt($1,$3);}
| '(' expr ')' %prec TOK_PARENT {$$ = $2;}
| expr '.' expr {$$ = $2->adopt($1,$3);}
| variable {$$= $1;}
| constant {$$ = $1;}
;
BINOP : TOK_IF {$$ = $1;}
| TOK_ELSE {$$ = $1;}
| '=' {$$ = $1;}
| TOK_EQ {$$ = $1;}
| TOK_NE {$$ = $1;}
| '<' {$$ = $1;}
| TOK_LE {$$ = $1;}
| '>' {$$ = $1;}
| TOK_GE {$$ = $1;}
| '+' {$$ = $1;}
| '-' {$$ = $1;}
| '*' {$$ = $1;}
| '/' {$$ = $1;}
| '%' {$$ = $1;}
;
UNOP : '+' expr %prec TOK_POS {
$1->swap_token_code(TOK_POS);
$$ = $1->adopt($2);
}
| '-' expr %prec TOK_NEG{
$1->swap_token_code(TOK_NEG);
$$ = $1->adopt($2);
}
| '!' expr {$$ = $1->adopt($2);}
;
allocator : TOK_NEW TOK_IDENT '('')' {
destroy($3);
$2->swap_token_code(TOK_TYPEID);
$$ = $1->adopt($2);
}
| TOK_NEW TOK_STRING '(' expr ')'{
}
| TOK_NEW basetype '[' expr ']'{
destroy($3);destroy($5);
$1->swap_token_code(TOK_NEWARRAY);
$$ = $1->adopt($2,$4);
}
;
call : TOK_IDENT '(' exprs ')' %prec TOK_CALL{
destroy($4);
$2->swap_token_code(TOK_CALL);
$$ = ($2->adopt($1))->cannibalize($3);
}
;
exprs : exprs expr {$$ = $1->adopt($2);}
| {$$ = new astree ('{',{0,0,0}, "}");}
;
variable : TOK_IDENT {$$ = $1;}
| expr '[' expr ']'{
destroy($4);
$$ = $2->adopt($1,$3);
}
| expr '.' TOK_IDENT {$$ = $2->adopt($1,$3);}
;
constant :TOK_INTCON {$$ = $1;}
|TOK_CHARCON {$$ = $1;}
|TOK_STRINGCON {$$ = $1;}
|TOK_NULL {$$ = $1;}
;
%%
我认为问题是规则expr:expr BINOP expr,因为当我摆脱它时,它会停止显示这些冲突。我已经声明了上面的优先规则以避免转换/减少冲突,但看起来它不起作用。有人可以在调试模糊语法时给我快捷方式吗?忽略语义规则。
parser.y: warning: 24 shift/reduce conflicts [-Wconflicts-sr]
parser.y: warning: 56 reduce/reduce conflicts [-Wconflicts-rr]
parser.y:140.14-143.12: warning: rule useless in parser due to conflicts [-Wother]
| expr '[' expr ']'{
^^^^^^^^^^^
parser.y:144.14-56: warning: rule useless in parser due to conflicts [-Wother]
| expr '.' TOK_IDENT {$$ = $2->adopt($1,$3);}
更新:我在理解中发现了一个问题
虽然我得到了正确的结果,但我的编译器一直在告诉下面的语法中存在转换/减少冲突。我认为不应该有冲突,因为我正确地指定了优先级和关联性。
%left '+'
%left '*'
%%
expr : expr BINOP expr
| TOK_INTCON
BINOP : '+'
| '*'
%%
答案 0 :(得分:1)
这个回复是你的更新部分,因为这是问题的核心。
TL; DR答案是优先级和关联性声明%left '+'
和%left '*'
在解析BINOP
时适用,但在解析expr
时不适用,因此他们&#39太早了(他们此时什么都不做)并且在他们需要的时候已经消失了。
我修改了你的例子,以便Bison可以处理它:
$ cat expr.y
%token TOK_INTCON
%left '+'
%left '*'
%%
expr : expr BINOP expr
| TOK_INTCON
BINOP : '+'
| '*'
%%
$ bison -v expr.y
expr.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
此处-v
的要点是写expr.output
,其中显示了Bison如何解释您的语法。您可以仔细阅读此内容以确切了解移位/减少冲突发生的位置 - 但简而言之,它在输入包含时发生,例如,
1 op 2 op 3
语法允许将其解析为:
op
/ \
1 op
/ \
2 3
(如果你选择&#34,那就是你得到的解析树;转移&#34;而不是&#34;每次减少&#34;或者:
op
/ \
op 3
/ \
1 2
%left
,%right
和%nonassoc
所做的是为特定令牌指定优先级。现在,正如the Bison documentation section on how precedence works中所述,优先级会流向规则,但至关重要的是,不是非终端:它们仅适用于非终端内的单个规则。它们用于决定是转换到新状态还是通过规则减少,并且一旦发生转移或减少,就已做出决定。 (This is natural since the token or nonterminal is recognized by the shifting or reduction, which gives you either a new node for your parse tree, or a partial parse tree.)
通过将所有二元运算符减少到binop
非终结符,可以抢占解析器以区分每个不同的二元运算符。在Bison将生成的LALR语法中,如果每个运算符都有一个单独的规则,则每个运算符都有一个单独的状态,这允许单独的移位或减少决策。
$ cat expr-repaired.y
%token TOK_INTCON
%left '+'
%left '*'
%%
expr : expr '+' expr
| expr '*' expr
| TOK_INTCON
%%
$ bison -v expr-repaired.y
$
有趣的是,州的总数保持不变(expr.output
和expr-repaired.output
都显示七个州)。但是,状态的含义是不同的。处理旧BINOP
非终结符的几个州已经消失;在他们的位置有多个状态,用于正确处理左关联,不同优先级运算符,同时决定是否减少expr <some-op> expr
,具体取决于我们决定如何减少第一个 expr
。仔细观察新的州6,例如:
State 6
1 expr: expr . '+' expr
1 | expr '+' expr .
2 | expr . '*' expr
'*' shift, and go to state 5
$default reduce using rule 1 (expr)
如果我们处于此状态且下一个标记为*
,我们会移动,以便我们在减少expr * expr
之前处理expr + (expr-from-reduction)
并减少它。