Bison阵列改变了冲突

时间:2015-11-29 20:24:58

标签: arrays bison shift-reduce-conflict

我是Bison的新手,我一直在尝试创建一个阵列和连接规则以及更长时间,并且无法弄清楚为什么我在这里减少了一个班次以及如何解决它:

arr:
  T_OPEN expr       {$$ = (void *)(new vector<int>());((vector<int>*)$$)->push_back($2);}
| arr ',' expr      {((vector<int>*)($1))->push_back($3);}
| arr T_CLOSE       {}
| arr '@' arr       {/*will add it later*/}

T_OPEN是&#34; [&#34;和T_CLOSE是&#34;]&#34;。 @应该连接两个数组。 arr的类型为void *。部分:

arr '@' arr

导致班次减少冲突。任何解决方案都将非常感激

1 个答案:

答案 0 :(得分:3)

这样的制作
arr: arr '@' arr;

总会产生shift-reduce冲突,因为它们不明确。假设您在源中有两个@运算符:

...1 @ ...2 @ ...3

这应该被解析为:

arr1: ...1 @ ...2
arr2: ...3
arr3: arr1 @ arr2

arr1: ...1
arr2: ...2 @ ...3
arr3: arr1 @ arr2

换句话说,@是左侧还是右侧?语法没有指定,因此不明确。

解决这个问题的常用方法是使用优先级声明(请参阅bash手册),但可以直接在语法中编写(参见下文)。

但是,即使将@操作员放在一边,你的语法也不能真正做到你想要的。首先,您可能希望基本数组文字符合此语法:[注1]

arr: '[' expr_list ']'    { $$ = $2; }
   | '[' ']'              { $$ = new std::vector<int>; }
expr_list
   : expr                 { $$ = new std::vector<int>; $$->push_back($1); }
   | expr_list ',' expr   { $1->push_back($3); }

然后你可以定义连接表达式:

arr_concat
   : arr
   | arr_concat '@' arr   { std::copy($3->begin(), $3->end,
                                      std::back_inserter(*$1));
                            delete $3; // Note 2
                          }

请注意,上述作品明确指出了@的相关性。没有歧义是可能的。

注意:

  1. 这里我假设您已经声明了一个语义联合,其中一个类型为std::vector<int>*,因为所有这些void*强制转换都是丑陋且不安全的。它会是这样的:

    %union {
       std::vector<int>*   array_pointer;
       // ...
    }
    %type <array_pointer> arr expr_list arr_concat
    %%
    
  2. delete是避免内存泄漏的必要条件,但您执行此操作取决于您的内存管理方法。不幸的是,一旦你决定保留指向矢量而不是实际矢量的指针(在这种情况下你几乎没有选择,因为每次减少复制矢量都是荒谬的),你就会负责内存管理。一旦将语义值合并到其他语义值中,就删除语义值是一个简单的解决方案,但这意味着您必须小心指向分配对象的指针的其他副本。如果你小心只有一个指向每个分配对象的指针,那么立即delete就可以了。否则,您可能需要某种垃圾收集,可能基于引用计数。