【问题标题】:Solving reduce/reduce and shift/reduce conflicts in bison grammar解决野牛语法中的reduce/reduce和shift/reduce冲突
【发布时间】:2017-11-12 05:12:14
【问题描述】:

我正在尝试解决以下野牛语法中的 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 :  '+'  
      |  '*'
%%

【问题讨论】:

  • 不是答案,但您的一些代码操作不正确。没有理由销毁 ],或将二元运算符作为参数提供给 adopt()
  • 感谢您的反馈。我的后一个问题的答案就足够了。

标签: compiler-construction bison


【解决方案1】:

此回复是针对您的 UPDATE 部分的,因为这是问题的核心。

TL;DR 的答案是优先级和关联性声明 %left '+'%left '*' 在解析 BINOP 时适用,但在解析 expr 时不适用,所以它们为时过早(他们对此无能为力点)并且在需要的时候消失了。


我修改了您的示例,以便 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

(如果你每次选择“shift”而不是“reduce”得到的解析树),或者:

    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 语法中,如果您对每个运算符都有一个单独的规则,那么您会为每个运算符获得一个单独的状态,这允许单独的 shift-or-reduce 决策。

$ cat expr-repaired.y
%token TOK_INTCON
%left '+'
%left '*'

%%
expr : expr '+' expr
     | expr '*' expr
     | TOK_INTCON 
%%
$ bison -v expr-repaired.y
$ 

有趣的是,状态总数保持不变(expr.outputexpr-repaired.output 都显示七个状态)。但是,状态的含义是不同的。处理旧的BINOP 非终端的几个状态已经消失;取而代之的是多个状态,用于正确处理左关联、不同优先级运算符,同时根据我们如何决定减少 first expr 来决定是否减少 expr &lt;some-op&gt; 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-from-reduction)之前处理expr * expr并减少它。

【讨论】:

  • 好的,所以我的理解是,bison 可以识别 '"*" 和 "+" 的优先级,但不能识别 BINOP 的优先级
  • 这不太对:问题是BINOP 没有优先级。实际上,您可以通过在规则中使用%prec 来给它一个...但这只是一个,而不是两个不同,具体取决于它具有的运算符匹配。
  • 我明白了,谢谢。我发布了另一个问题stackoverflow.com/questions/47254910/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多