2

フレックスコード:

  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!

2 つの質問があります。

1) 38 行目のアクションがトークン「;」を出力するのはなぜですか? たとえば、「20 、a;」および「20、b;」

2) 32 行目のアクションが単に「keeplive」ではなく「keeplive { int a; int b; }」を出力するのはなぜですか?

4

1 に答える 1

7

簡潔な答え:

yylval.strval = yytext;

そんな使い方はできませんyytext。それが指す文字列はレクサーにプライベートであり、flex アクションが終了するとすぐに変更されます。次のようなことをする必要があります:

yylval.strval = strdup(yytext);

その後、メモリを解放する必要があります。


より長い答え:

yytext実際には、入力を含むバッファーへのポインターです。yytext を NUL で終了する文字列であるかのように機能させるために、flexフレームワークはアクションを実行する前にトークンに続く文字を a で上書きしNUL、アクションの終了時に元の文字を置き換えます。したがってstrdup、アクション内では問題なく動作しますが、アクションの外 (bison コード内) では、トークンで始まるバッファーの部分へのポインターが得られます。flexソースの次の部分を同じバッファに読み込むため、後で悪化し、ポインタはランダムなガベージになります。オプションに応じて、いくつかのシナリオが考えられflexますが、どれもきれいではありません。

したがって、ゴールデン ルール:yytextはアクションが終了するまでのみ有効です。保持したい場合はコピーし、不要になったときにコピー用にストレージを解放してください。

私が書いたほとんどすべてのレクサーでは、ID トークンは実際にシンボル テーブルで識別子を見つけて (またはそこに置き)、ポインターをシンボル テーブルに返します。これにより、メモリ管理が簡素化されます。ただし、文字列リテラルなどのメモリ管理の問題は本質的に同じです。

于 2012-10-31T20:13:26.343 に答える