flex代码:
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
野牛代码:
1 %{
2 #include "stdlib.h"
3 #include "stdio.h"
4 #include "stdarg.h"
5 void yyerror(char *s, ...);
6 #define YYDEBUG 1
7 int yydebug = 1;
8 %}
9
10 %union{
11 char *strval;
12 int intval;
13 }
14
15 %token <strval> ID
16 %token <intval> INT
17 %token CREATE
18 %token CMD
19
20 %type <strval> col_definition
21 %type <intval> create_type
22 %start stmt_list
23
24 %%
25 stmt_list:stmt ';'
26 | stmt_list stmt ';'
27 ;
28
29 stmt:create_cmd_stmt {/*printf("create cmd\n");*/}
30 ;
31
32 create_cmd_stmt:CREATE CMD ID'{'create_col_list'}' {printf("%s\n" , $3);}
33 ;
34 create_col_list:col_definition
35 | create_col_list col_definition
36 ;
37
38 col_definition:create_type ID ';' {printf("%d , %s\n" , $1, $2);}
39 ;
40
41 create_type:INT {$$ = $1;}
42 ;
43
44 %%
45 extern FILE *yyin;
46
47 void
48 yyerror(char *s, ...)
49 {
50 extern yylineno;
51 va_list ap;
52 va_start(ap, s);
53 fprintf(stderr, "%d: error: ", yylineno);
54 vfprintf(stderr, s, ap);
55 fprintf(stderr, "\n");
56 }
57
58 int main(int argc , char *argv[])
59 {
60 yyin = fopen(argv[1] , "r");
61 if(!yyin){
62 printf("open file %s failed\n" ,argv[1]);
63 return -1;
64 }
65
66 if(!yyparse()){
67 printf("parse work!\n");
68 }else{
69 printf("parse failed!\n");
70 }
71
72 fclose(yyin);
73 return 0;
74 }
75
测试输入文件:
create cmd keeplive
{
int a;
int b;
};
测试输出:
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 { int a; int b; “而不仅仅是”keeplive“?
答案 0 :(得分:6)
简短回答:
yylval.strval = yytext;
你不能那样使用yytext
。它指向的字符串对词法分析器是私有的,并且一旦flex动作结束就会改变。您需要执行以下操作:
yylval.strval = strdup(yytext);
然后你需要确保你之后释放内存。
更长的答案:
yytext
实际上是指向包含输入的缓冲区的指针。为了使yytext工作好像是一个以NUL结尾的字符串,flex
框架在执行操作之前用NUL
覆盖令牌后面的字符,然后替换原始字符。行动终止。因此strdup
在操作中可以正常工作,但在操作之外(在您的野牛代码中),您现在有一个指向缓冲区部分的指针。之后它会变得更糟,因为flex
会将源的下一部分读入同一个缓冲区,现在你的指针是随机垃圾。有几种可能的情况,取决于flex
选项,但它们都不漂亮。
因此黄金法则:yytext
仅在行动结束前有效。如果您想保留它,请将其复制,然后确保在不再需要时为该副本释放存储空间。
在我写的几乎所有词法分析器中,ID令牌实际上在符号表中找到了标识符(或将其放在那里)并将指针返回到符号表中,这简化了内存管理。但是,您仍然存在基本相同的内存管理问题,例如字符串文字。