当我突然开始获得SEGFAULT时,我正在构建一个非常简单的解析器的解析器。我已经将我的代码剥离到最小的地方:
这是我的test.flex文件:
%{
#include "test.tab.h"
#include <iostream>
using namespace std;
%}
%option noyywrap
%%
model { yylval.a = new double(); return IDENTIFIER; }
. { cerr << "Unrecognized token!" << endl; exit(1); }
%%
这是我的test.y文件:
%{
#include <iostream>
using namespace std;
int yylex();
int yyerror(const char *p) { cerr << "Error" << endl; }
%}
%union YYSTYPE {
double* a;
int* b;
};
%token <a> IDENTIFIER
%type <b> expression
%%
expression : IDENTIFIER { cout << "got here! " << $1 << "|" << $$ << endl; };
%%
int main()
{
yyparse();
cout << "Success!" << endl;
return 0;
}
我们的联盟由两个指针a和b组成。 $ 1和$$是不同类型的(分别为a和b)。
在输入“model”上,输出“到达这里!0x372a28 | 0x372a28”(和第二行的“Success!”),这意味着$ 1和$$指向相同的内存位置!这当然会导致各种不好的事情发生。
要显示错误,需要在词法分析器中对yylval.a进行分配。
我使用Bison 2.4.1和Flex 2.5.4,两者都用于Windows(使用GnuWin32)。难道我做错了什么?这是一个(已知的)错误吗?
编辑: 如果我将联合更改为:
%union YYSTYPE {
int a;
int b;
};
和
的规则expression : IDENTIFIER { cout << "got here! " << &$1 << "|" << &$$ << endl; };
(并删除词法分析器中的赋值)描述的结果内存位置不同,这使我相信如果没有使用指针,变量本身的内存位置会有所不同。但是,如果我使用指针就是这种情况,则赋值为“yylval.a = new double();”应该只改变$ 1并保持$$不受影响。
答案 0 :(得分:1)
这不是Bison中的一个错误,这就是Bison的工作方式。它使用一个堆栈来处理中间解析结果,并且在你的规则中有一个令牌要从堆栈中移出而另一个要添加,因此要弹出的项目和要推送的项目显然位于同一个记忆位置。
因为你在这里做类型强制(?),我想你在行动中应该拥有的是
double *a = $1;
$$ = new int((int)(*a));
delete a;
请注意,一旦你写入$$,就不能再读取1美元,因为你现在已经占用了曾经是1美元的堆栈槽。
答案 1 :(得分:0)
表达式只有一个组件,因此它的左侧和右侧完全相同。我不确定你为什么觉得这很令人惊讶。
我想我可能知道你的困惑在哪里:
expression : IDENTIFIER
这表示expression
的一个有效表单是IDENTIFIER
。因此,任何有效的IDENTIFIER
也是有效的expression
。