我是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
导致班次减少冲突。任何解决方案都将非常感激
答案 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
}
请注意,上述作品明确指出了@
的相关性。没有歧义是可能的。
这里我假设您已经声明了一个语义联合,其中一个类型为std::vector<int>*
,因为所有这些void*
强制转换都是丑陋且不安全的。它会是这样的:
%union {
std::vector<int>* array_pointer;
// ...
}
%type <array_pointer> arr expr_list arr_concat
%%
delete
是避免内存泄漏的必要条件,但您执行此操作取决于您的内存管理方法。不幸的是,一旦你决定保留指向矢量而不是实际矢量的指针(在这种情况下你几乎没有选择,因为每次减少复制矢量都是荒谬的),你就会负责内存管理。一旦将语义值合并到其他语义值中,就删除语义值是一个简单的解决方案,但这意味着您必须小心指向分配对象的指针的其他副本。如果你小心只有一个指向每个分配对象的指针,那么立即delete
就可以了。否则,您可能需要某种垃圾收集,可能基于引用计数。