我的基于bison的解析器开始被我最近生成的一些中等大小的文件阻塞。
它抛出了一个关于"内存耗尽"的异常
野牛手册页说,这可能是由于使用了右手递归。在不试图重写语法的情况下(我的最后期限很紧),我只想增加堆栈,让解析器解析这个文件。我试图遵循野牛手册页,并将#define YYMAXDEPTH定义为大于默认10000的某个数字,但没有成功。当我查看bison的输出时,似乎只有在定义了YYSTACK_RELOCATE时才有条件地使用YYMAXDEPTH,并且只有在这种情况下才定义了YY斯塔克_RELOCATE:
#if (! defined yyoverflow
&& (! defined __cplusplus
|| (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
&& defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
由于我是用C++编译的,所以上面的#ifdef失败了,因此没有定义YYSTACK_RELOCATE。
这是bug还是功能?有人知道增加堆栈大小的正确方法是什么吗?
顺便说一句,这是野牛生成的代码片段,堆栈溢出:
....
....
if (yyss + yystacksize - 1 <= yyssp)
{
/* Get the current used size of the three stacks, in elements. */
YYSIZE_T yysize = yyssp - yyss + 1;
#ifdef yyoverflow
{
/* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
yytype_int16 *yyss1 = yyss;
YYLTYPE *yyls1 = yyls;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
&yyls1, yysize * sizeof (*yylsp),
&yystacksize);
yyls = yyls1;
yyss = yyss1;
yyvs = yyvs1;
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
goto yyexhaustedlab; // <====== Overflows and throws exception here
# else
......
......
通常,与C数据类型不同的C++对象不能由memcpy
重新定位。因此,bison拒绝重新定位其堆栈,除非它不知何故知道堆栈对象是"琐碎的",并且如果对象是C++对象,它会假设它们不是。
YYMAXDEPTH
是解析器将分配的最大堆栈,但初始堆栈大小为YYINITDEPTH
。由于C++堆栈无法重新定位,因此初始大小必须足够大,以用于任何输入,因此需要增加YYINITDEPTH
,而不是YYMAXDEPTH
。
或者,你可以想办法告诉bison C++堆栈对象是可重定位的(如果是的话),或者你可以尝试更新版本的bison:据称,v3更愿意让你自焚,但我自己还没有尝试过。最后,您可以定义yyoverflow
来提供自己的堆栈重新定位机制:不幸的是,这是未记录的,而且不必要地复杂。