使用bison和flex实现解析字符串的函数
我使用bison和flex实现了一个解析器和扫描器。起初它从stdin读取输入,后来我修改为从字符串读取。关于这个主题,有几篇关于stackoverflow的文章。具体地说,at描述了多个缓冲区的使用以及内存中字符串而不是文件作为输入的使用 因此,我让解析器/词法分析器为单个字符串工作,如下所示:使用bison和flex实现解析字符串的函数,bison,flex-lexer,yacc,lex,Bison,Flex Lexer,Yacc,Lex,我使用bison和flex实现了一个解析器和扫描器。起初它从stdin读取输入,后来我修改为从字符串读取。关于这个主题,有几篇关于stackoverflow的文章。具体地说,at描述了多个缓冲区的使用以及内存中字符串而不是文件作为输入的使用 因此,我让解析器/词法分析器为单个字符串工作,如下所示: %{ //Bunch of includes, typedefs, etc.. extern char * yytext; void yyerror(char *); int yylex(); typ
%{
//Bunch of includes, typedefs, etc..
extern char * yytext;
void yyerror(char *);
int yylex();
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern int yylex_destroy(void);
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);
...
%%
int main(int argc, char **argv) {
char *string = "abcd\n\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yyparse();
}
这是最简单的部分。这里的语法/lex规则有点冗长。
我想实现一个函数,该函数将使用字符串参数重复调用。因为语法/lex规则可以处理输出,所以我可以处理它。问题是要有一种机制来实现一个经典函数,并将一个字符串传递给该函数进行解析和分析。所以,我试着用这个来测试
int main(int argc, char **argv) {
int i=10;
char *string;
string = malloc(16);
while (1) {
sprintf(string, "someString to be parsed...%d\n\0", i++);
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
yyparse();
yylex_destroy();
printf("%d\n", i);
}
}
大约10000次后,它失败,出现以下错误:
fatal flex scanner internal error--end of buffer missed
我不是在看任何多线程环境。它将是一个单线程进程,其中包含来自要解析的套接字的字符串。当字符串到达时,我调用一个函数来解析它。
我找不到任何关于使用Bison和Flex实现此类功能的参考资料
我尝试了不同的方法,但没有成功。有什么简单的方法来处理这个问题吗
string = malloc(16);
考虑到你将要写:
sprintf(string, "someString to be parsed...%d\n\0", ++i);
如果i
为单个数字,则至少为28个字节;如果i
达到10000,则至少为32个字节。(这可能不是巧合。)
帮自己一个忙,如果可以的话,使用asprintf
。如果它不可用,那么使用snprintf
编写它就很容易了,或者您可以使用带有更大缓冲区的snprintf
。(在这种情况下不需要动态分配。)
请注意,格式字符串末尾的\0
完全没有意义。我猜想您的意图是保证有两个NUL终止符,正如yy_scan\u buffer
所要求的那样,但是\0
不会被复制到sprintf
的输出中,因为它的作用是终止格式字符串。(请记住,C字符串以NUL字符结尾。)
还要注意sizeof(string)
在yy_扫描_缓冲区(string,sizeof(string))
是sizeof(char*)
,因为string
是char*
。现在很可能是8,但如果您使用的是32位环境,则可能是4。在任何情况下,它都与sprintf
写入的字符数无关。您可以使用strlen
来计算string
的长度,但是利用sprintf
返回它写入的字节数这一事实会更有效
说到返回值,您不会检查yy_scan_buffer
中的返回值,这可能是为了告诉您错误:
如果无法以这种方式设置base(即,忘记最后两个YY_END_的_BUFFER_CHAR字节),则YY_scan_BUFFER()
返回空指针,而不是创建新的输入缓冲区
考虑到你将要写:
sprintf(string, "someString to be parsed...%d\n\0", ++i);
如果i
为单个数字,则至少为28个字节;如果i
达到10000,则至少为32个字节。(这可能不是巧合。)
帮自己一个忙,如果可以的话,使用asprintf
。如果它不可用,那么使用snprintf
编写它就很容易了,或者您可以使用带有更大缓冲区的snprintf
。(在这种情况下不需要动态分配。)
请注意,格式字符串末尾的\0
完全没有意义。我猜想您的意图是保证有两个NUL终止符,正如yy_scan\u buffer
所要求的那样,但是\0
不会被复制到sprintf
的输出中,因为它的作用是终止格式字符串。(请记住,C字符串以NUL字符结尾。)
还要注意sizeof(string)
在yy_扫描_缓冲区(string,sizeof(string))
是sizeof(char*)
,因为string
是char*
。现在很可能是8,但如果您使用的是32位环境,则可能是4。在任何情况下,它都与sprintf
写入的字符数无关。您可以使用strlen
来计算string
的长度,但是利用sprintf
返回它写入的字节数这一事实会更有效
说到返回值,您不会检查yy_scan_buffer
中的返回值,这可能是为了告诉您错误:
如果无法以这种方式设置base(即,忘记最后两个YY_END_的_BUFFER_CHAR字节),则YY_scan_BUFFER()
返回空指针,而不是创建新的输入缓冲区
我不知道这是否是你需要的,但无论如何,这是我在《野牛》中写的
int calc(char str[])
{
YY_BUFFER_STATE buffer = yy_scan_string(str);
yyparse();
yy_delete_buffer(buffer);
return 0;
}
我不知道这是否是你需要的,但无论如何,这是我在《野牛》中写的
int calc(char str[])
{
YY_BUFFER_STATE buffer = yy_scan_string(str);
yyparse();
yy_delete_buffer(buffer);
return 0;
}
您的代码中可能存在缓冲区溢出,这通常不是问题,但偶尔会破坏某些东西,从而导致以后出现此错误。尝试运行,看看它是否告诉您任何有用的信息。您的代码中可能存在缓冲区溢出,这通常不是问题,但偶尔会破坏某些内容,从而导致以后出现此错误。试着运行,看看它是否告诉你什么有用的东西。关键问题是“还要注意yy_scan_buffer(string,sizeof(string))中的sizeof(string))是sizeof(char*),因为string是char*”。有趣的是,引用来自这个stackoverflow[link]()-塞夫科的答案-直到你指出,我才意识到显而易见的问题。有趣的是,你编辑了这个答案,但没有注意到这一点-:)@asinix:sevko的代码是正确的<代码>stri