野牛转移/减少与同一令牌的冲突出现在同一规则中

时间:2016-03-24 22:11:50

标签: bison reduce shift

鉴于以下野牛规则,我不明白为什么INTO令牌可以在相同的野牛状态中移位和减少,并导致1次移位/减少冲突。怎么解决?首都都是令牌。

select_condition: SELECT opt_select fields
                  FROM from_clause
                  opt_into_table
                  opt_into_graph
                  opt_where_expr

opt_into_table: { $$ = 0; }
              | INTO TABLE IDENTIFIER { $$ = 1; }

opt_into_graph: { $$ = 0; }
              | INTO GRAPH IDENTIFIER { $$ = 1; }

////// from the sqlparser.output //////////////////

INTO  shift, and go to state 66

INTO      [reduce using rule 31 (opt_into_table)]
$default  reduce using rule 31 (opt_into_table)

opt_into_table  go to state 67

1 个答案:

答案 0 :(得分:1)

这里的冲突是当解析器在INTO之后看到令牌from_clause时,有两种可能性:

  • 它是序列INTO TABLE IDENTIFIER中的第一个标记。在这种情况下,它应该被移位(在减少from_clause之后)。

  • 它是序列INTO GRAPH IDENTIFIER中的第一个标记。在这种情况下,在opt_into_table转移之前需要减少空INTO

因此存在转移/减少冲突,因为此时不知道是否需要减少空的opt_into_table非终端。再用一个前瞻符号,答案就很明确,所以写的语法是LR(2)。不幸的是,野牛不会产生LR(2)解析器。

在编写语义规则时(在两种情况下都忽略了IDENTIFIER的语义值),您可以使用一个简单的实用修复:将两个可选短语组合成一个非终端,这会创建一点掩码而不是两个单独的布尔值:

opt_intos: INTO TABLE IDENTIFIER { $$ = 1; }
         | INTO GRAPH IDENTIFIER { $$ = 2; }
         | INTO TABLE IDENTIFIER INTO GRAPH IDENTIFIER { $$ = 3; }

但这可能不是最好的解决方案,因为在某些时候你可能会关心IDENTIFIER

另一种(也有点丑陋)的可能性是通过创建将它们扩展为select_condition的四种不同作品来删除epsilon作品:

select_condition: SELECT opt_select fields
                  FROM from_clause
                  into_table
                  into_graph
                  opt_where_expr
                | SELECT opt_select fields
                  FROM from_clause
                  into_graph
                  opt_where_expr
                | SELECT opt_select fields
                  FROM from_clause
                  into_table
                  opt_where_expr
                | SELECT opt_select fields
                  FROM from_clause
                  opt_where_expr

into_table      : INTO TABLE IDENTIFIER { $$ = 1; }

into_graph      : INTO GRAPH IDENTIFIER { $$ = 1; }

另一种方法是将INTO TABLEINTO GRAPH合并到词法分析器中的单个标记中。 (对于类似SQL的语言,这可能不会起作用,因为关键字是上下文的。但在你的情况下它可能是可行的。)

或者您可以保留原语,并使用%glr-parser