2012-10-31 80 views
1

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; 
}; 

測試輸出:

[email protected]:~/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一個; INT B; }」,而不是簡單的 「keeplive」?

回答

5

簡短的回答:

yylval.strval = yytext; 

不能使用yytext這樣。它指向的字符串對詞法分析器來說是私有的,並且只要flex動作完成就會改變。您需要執行以下操作:

yylval.strval = strdup(yytext); 

然後您需要確保在事後釋放內存。


較長答案:

yytext實際上是一個指針到含有輸入緩衝器。爲了使yytext像NUL終止的字符串一樣工作,flex框架在執行動作之前用NUL覆蓋該令牌後面的字符,然後在動作終止時替換原始字符。所以strdup可以在動作內部正常工作,但是在動作之外(在你的野牛代碼中),你現在有一個指向緩衝區以令牌開始的部分。後來情況變得更糟,因爲flex會將源代碼的下一部分讀入同一緩衝區,現在您的指針指向隨機垃圾。有幾種可能的情況,取決於flex選項,但沒有一個是漂亮的。

所以黃金法則:yytext是唯一有效的,直到行動結束。如果您想保留它,請將其複製,然後確保在不再需要時爲該副本釋放存儲空間。

在我編寫的幾乎所有詞法分析器中,ID標記實際上在符號表中找到標識符(或放在那裏)並返回一個指向符號表的指針,這簡化了內存管理。但是,對於例如字符串文字,您仍然具有基本相同的內存管理問題。

相關問題