在flex/bison中将Char*作为YYSTYPE返回时,与strdup()一起在词法分析器中使用时,仅返回标记中的第一个字符。

3

我在使用flex和bison构建的编译器中,将char*作为YYSTYPE使用。以下是相关代码:

#define YYSTYPE char*

这个语法文件的顶部有一个“is”。我的词法分析器中的一些标记需要将它们匹配的整个字符串传递给我的语法分析器,而其他标记只需要传递它们的标记,因此这对我很有用。我在我的词法分析器中做了这样的事情:

[(foo|bar)]    {yylval = *strdup(yytext); return FOOBAR;}

在我的语法中,我使用它们来进行这样的产生:

fb:
    FOOBAR
    {
        sprintf($$, "%s", &$1);
    }
    ;

这将$$的值设置为原始匹配令牌中的第一个字符。我(可能)明白为什么,因为解引用的char*char,但我采取的修复步骤导致问题。例如,从sprintf()行中删除&会导致段错误。从赋值中删除*会导致“使指针转换为整数”。我该怎么办?我认为问题在于对yylval的赋值。

3个回答

4
你所做的事情存在几个问题。首先,由于 YYSTYPE 是一个char指针,实际上并没有为字符串分配空间。因此,当你执行sprintf($$, "%s", &$1)时,你尝试将一个字符串打印到未初始化的指针中($$是一个指针,但没有初始化为任何内容,所以它可以指向内存中的任何位置)。
另一个问题可能是你在sprintf中使用了&$1。它获取指针的地址,而不是指针实际指向的字符串。
第三个问题是你在词法分析器中使用了strdup,它会分配内存。但你从未释放它,造成了内存泄漏。
第四个问题是为什么你只得到一个字符,而且你其实很幸运能得到那个字符,这是因为strdup(yytext)返回字符串的副本,星号则是返回解引用的指针,其类型是char。所以你将指针设置为了一个单独的字符。 编辑:希望一切都说得清楚,现在很晚了,我可能喝了一两杯酒……

是的。我实际上正在使用asprintf(),它会分配更多的内存并导致另一个内存泄漏。此外,我在其他地方进行了内存释放。很抱歉没有包含那个,不想倾泻一堵墙的文字。问题是最后一件事...但我仍然收到那个警告。如何解决“使整数从指针转换而来而没有强制转换”的问题? - uristmcinternet

4
将分配更改回yylval = strdup(yytext),将sprintf(...)更改为$$ = yylval。确保在您的解析器(.y)文件中定义了YYSTYPE,并且该头文件已创建并导入到您的词法分析器(.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; }
%%

注意:

  1. 你需要在某处定义yyerror, yywrap, 和 main
  2. 目前它没有释放字符串,你需要想办法在何处最好释放。

它实际上可以使用char*,我刚刚试过了。但还是谢谢,这个方法也可以。 - uristmcinternet
不错的例子,但仅仅为了一个字符串使用联合有点臃肿。 - ceving

3

我用以下方法解决了这个问题(在.tab.h #include之前的.l和.y文件中都要加上):

#ifndef YYSTYPE
# define YYSTYPE char*
#endif

似乎正则表达式不起作用。 错误:error: request for member ‘string’ in something not a structure or union 例如:[a-zA-Z][a-zA-Z0-9]* { yylval.string = strdup(yytext); return(ID); }[1-9][0-9]*|\.[0-9]*|[1-9][0-9]\.|[1-9][0-9]*\.[0-9]* { yylval.string = strdup(yytext); return(NUMBER); }\'(\\.|[^\\'\n])*\' { yylval.string = strdup(yytext); return(STRING); } - Max Base

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接