我在使用flex和bison构建的编译器中使用char*
作为YYSTYPE
。这条线
#define YYSTYPE char*
位于我的语法文件的顶部。我的词法分析器中的一些标记需要将它们匹配的整个字符串传递给我的语法,而其他标记只需要传递它们的标记,所以这对我来说很有效。我在我的词法分析器中做了这样的事情:
[(foo|bar)] {yylval = *strdup(yytext); return FOOBAR;}
在我的语法中,我将它们与这样的作品一起使用:
fb:
FOOBAR
{
sprintf($$, "%s", &$1);
}
;
这会将$$
的值设置为原始匹配标记中的第一个字符。我(可能)理解为什么,因为取消引用char*
是char
,但我采取的修复措施导致了问题。例如,从&
行中删除sprintf()
会导致段错误。从赋值中删除*
会导致"从指针生成整数而不使用强制转换"。我该怎么办?我认为问题在于yylval
的分配。
答案 0 :(得分:4)
您正在做的事情有几个问题。首先,由于YYSTYPE
是一个char指针,实际上没有为字符串分配空间。因此,当您执行sprintf($$, "%s", &$1)
时,您尝试将字符串打印到未初始化的指针中($$
是指针,但未初始化为任何内容,因此它可以指向内存中的任何位置。)< / p>
另一个问题可能是您在&$1
中使用sprintf
。它获取指针的地址,而不是指针指向的实际字符串。
第三个问题是你在词法分析器中使用strdup
,它分配内存。但你永远不会把它释放到某处,造成内存泄漏。
第四个也是最后一个问题是为什么你只得到一个角色,而你实际上很幸运,因为当strdup(yytext)
返回一个字符串的副本时,它前面的星形返回取消引用的指针是一个char。因此,您将指针设置为单个字符。
编辑:我希望这一切都有道理,已经很晚了,我可能会喝一两杯葡萄酒......
答案 1 :(得分:4)
将作业更改回yylval = strdup(yytext)
,将sprintf(...)
更改为$$ = yylval
。确保在解析器(YYSTYPE
)文件中定义.y
,并创建该标头并将其导入到词法分析器(.l
)文件中。
我原本希望只使用YYSTYPE
,但我无法使用它,所以请使用%union{}
。
经过实验并稍微回过头来,我得到了它来处理这些变化:
在parser.y
:
%{
%}
%output "parser.c"
%defines "parser.h"
%union {
char *str;
}
%type <str> fb
%start fb
%token FOOBAR
%%
fb: FOOBAR { $$ = yylval.str; }
%%
在lexer.l
:
%{
#include <string.h>
#include "parser.h"
%}
%option outfile="lexer.c"
%option header-file="lexer.h"
%%
[(foo|bar)] { yylval.str = strdup(yytext); return FOOBAR; }
%%
注意:
yyerror
,yywrap
和main
。 free
字符串,您需要找出最适合的地方。答案 2 :(得分:3)
我用以下内容解决了这个问题(在.tab和.inc之前的.l和.y中):
#ifndef YYSTYPE
# define YYSTYPE char*
#endif