C 为什么这个bison代码会产生意外的输出?
弹性代码:C 为什么这个bison代码会产生意外的输出?,c,bison,flex-lexer,C,Bison,Flex Lexer,弹性代码: 1 %option noyywrap nodefault yylineno case-insensitive 2 %{ 3 #include "stdio.h" 4 #include "tp.tab.h" 5 %} 6 7 %% 8 "{" {return '{';} 9 "}" {return '}';} 10 ";" {return ';';} 11 "create"
1 %option noyywrap nodefault yylineno case-insensitive
2 %{
3 #include "stdio.h"
4 #include "tp.tab.h"
5 %}
6
7 %%
8 "{" {return '{';}
9 "}" {return '}';}
10 ";" {return ';';}
11 "create" {return CREATE;}
12 "cmd" {return CMD;}
13 "int" {yylval.intval = 20;return INT;}
14 [a-zA-Z]+ {yylval.strval = yytext;printf("id:%s\n" , yylval.strval);return ID;}
15 [ \t\n]
16 <<EOF>> {return 0;}
17 . {printf("mistery char\n");}
18
测试输出:
root@VM-Ubuntu203001:~/test/tpp# ./a.out t1.tp
id:keeplive
id:a
20 , a;
id:b
20 , b;
keeplive
{
int a;
int b;
}
parse work!
我有两个问题:
1) 为什么第38行的操作会打印标记“;”?例如,“20,a;”和“20,b;”
2) 为什么第32行的操作会打印“keeplive”
{
INTA;
int b;
}“而不是简单的“保持活力”?简短回答:
yylval.strval = yytext;
你不能那样使用yytext
。它指向的字符串对于lexer是私有的,并且将在flex操作完成后立即更改。您需要执行以下操作:
yylval.strval = strdup(yytext);
然后,您需要确保在之后释放内存
详细回答:
yytext
实际上是指向包含输入的缓冲区的指针。为了使yytext像以NUL结尾的字符串一样工作,flex
框架在执行操作之前用NUL
覆盖标记后面的字符,然后在操作终止时替换原始字符。因此,strdup
在操作内部可以正常工作,但在操作外部(在bison代码中),您现在有一个指针指向以令牌开头的缓冲区部分。之后情况会变得更糟,因为flex
会将源代码的下一部分读入同一个缓冲区,现在指针指向随机垃圾。根据flex
选项的不同,有几种可能的场景,但没有一种是漂亮的
所以黄金法则:yytext
只在操作结束前有效。如果您想保留它,请复制它,然后确保在不再需要它时为该副本释放存储空间
在我编写的几乎所有lexer中,ID令牌实际上在符号表中找到标识符(或将其放在符号表中),并将指针返回到符号表中,这简化了内存管理。但是,对于例如字符串文本,您仍然存在基本相同的内存管理问题
yylval.strval = yytext;
yylval.strval = strdup(yytext);