bbg*_*bbg 2 c bison flex-lexer
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
Run Code Online (Sandbox Code Playgroud)
野牛代码:
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
Run Code Online (Sandbox Code Playgroud)
测试输入文件:
create cmd keeplive
{
int a;
int b;
};
Run Code Online (Sandbox Code Playgroud)
测试输出:
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!
Run Code Online (Sandbox Code Playgroud)
我有两个问题:
1)为什么第38行的动作打印了令牌';'?例如,"20,a;" 和"20,b;"
2)为什么第32行的动作打印"keeplive {int a; int b;}"而不是简单地"keeplive"?
简短回答:
yylval.strval = yytext;
Run Code Online (Sandbox Code Playgroud)
你不能那样用yytext.它指向的字符串对词法分析器是私有的,并且一旦flex动作结束就会改变.你需要做一些事情:
yylval.strval = strdup(yytext);
Run Code Online (Sandbox Code Playgroud)
然后你需要确保你之后释放内存.
更长的回答:
yytext实际上是一个指向包含输入的缓冲区的指针.为了使yytext工作好像是一个以NUL结尾的字符串,flex框架NUL会在执行操作之前覆盖令牌后面的字符,然后在操作终止时替换原始字符.因此,strdup在动作中可以正常工作,但在动作之外(在你的野牛代码中),你现在有一个指向缓冲区部分的指针.之后会变得更糟,因为flex将源的下一部分读入同一个缓冲区,现在你的指针是随机垃圾.有几种可能的情况,取决于flex选项,但它们都不漂亮.
所以黄金法则:yytext只有在行动结束时才有效.如果要保留它,请将其复制,然后确保在不再需要时为该副本释放存储空间.
在我编写的几乎所有词法分析器中,ID令牌实际上在符号表中找到标识符(或将其放在那里)并将指针返回到符号表中,这简化了内存管理.但是,您仍然存在基本相同的内存管理问题,例如字符串文字.