Next: , Previous: The Database Language, Up: Another Example of Flex and Bison


4.5.2 実装:コマンド文パーサ

上の節で、 小規模な言語について説明しました。 次にそれを実装してみることにしましょう。 以下のファイルがこれを実現します。

注:これはあくまでも1つの例として見てください。 特に文法の部分は、 英語のパース処理としてはあまり良い例ではありません。

以下はBisonのファイルです。 %unionの部分、 および、 yylvalにアクセスするために$$$nを使う方法に注目してください。

     
     /* Cコードはファイルの先頭で提供する */
     
     %{
     
     #include <stdio.h>
     #include <string.h>
     
     
     
     extern int  yylexlinenum;  /* lex.yy.cに存在する */
     extern char *yytext;       /* カレント・トークン */
     
     %}
     
     /* キーワードと予約語がここから始まる */
     
     
     
     %union{                    /* これはデータの共用体 */
         char   name[128];      /* 名前                 */
     }
     
     /*------------- 予約語 ------------------*/
     
     %token PERIOD
     %token NEWLINE
     %token POSITIONAL
     %token VERB
     %token ADVERB
     %token PROPER_NOUN
     %token NOUN
     %token DECLARATIVE
     %token CONDITIONAL
     
     %type  <name> declarative
     %type  <name> verb_phrase
     %type  <name> noun_phrase
     %type  <name> position_phrase
     %type  <name> adverb
     %type  <name> POSITIONAL VERB ADVERB PROPER_NOUN
     %type  <name> NOUN DECLARATIVE CONDITIONAL
     
     %%
     sentence_list : sentence
                   | sentence_list NEWLINE sentence
                   ;
     
     sentence : verb_phrase noun_phrase position_phrase
                adverb period
                {
                  printf("I understand that sentence.\n");
                  printf("VP = %s \n",$1);
                  printf("NP = %s \n",$2);
                  printf("PP = %s \n",$3);
                  printf("AD = %s \n",$4);
                }
              | { yyerror("That's a strange sentence!");  }
              ;
     position_phrase : POSITIONAL  declarative PROPER_NOUN
                       {
                         sprintf($$,"%s %s %s",$1,$2,$3);
                       }
     
                     | /* 空 */ { strcpy($$,""); }
                     ;
     
     verb_phrase : VERB { strcpy($$,$1); strcat($$," "); }
                 | adverb VERB
                   {
                     sprintf($$,"%s %s",$1,$2);
                   }
                 ;
     adverb : ADVERB      { strcpy($$,$1); }
     
            | /* 空 */    { strcpy($$,""); }
            ;
     noun_phrase : DECLARATIVE NOUN
                   {
                     sprintf($$,"%s %s",$1,$2);
                   }
                 | CONDITIONAL declarative NOUN
                   {
                     sprintf($$,"%s %s %s",$1,$2,$3);
                   }
                 | NOUN { strcpy($$,$1); strcat($$," "); }
                 ;
     declarative : DECLARATIVE { strcpy($$,$1); }
     
                 | /* 空 */    { strcpy($$,""); }
                 ;
     
     period : /* 空 */
            | PERIOD
            ;
     
     %%
     
     /* main()およびyyerror()関数を提供する */
     
     void main(int argc, char **argv)
     {
     
       yyparse();       /* ファイルをパースする */
     }
     int yyerror(char *message)
     {
       extern FILE *yyout;
     
       fprintf(yyout,"\nError at line %5d.  (%s) \n",
                          yylexlinenum,message);
     }

以下はFlexのファイルです。 文字列が渡される方法に注意してください。 これは最適化された方法ではありませんが、 最も理解しやすい方法です。

     %{
     #include <stdio.h>
     #include <string.h>
     
     #include "y.tab.h"      /* これはBisonにより生成される */
     #define TRUE  1
     #define FALSE 0
     #define copy_and_return(token_type) \
              { \
                  strcpy(yylval.name,yytext);\
                  return(token_type); \
              }
     
     
     int yylexlinenum = 0;  /* 行数カウント用 */
     %}
     %%
     
        /* 字句解析ルールがここから始まる */
     
     MEN|WOMEN|STOCKS|TREES      copy_and_return(NOUN)
     MISTAKES|GNUS|EMPLOYEES     copy_and_return(NOUN)
     LOSERS|USERS|CARS|WINDOWS   copy_and_return(NOUN)
     DATABASE|NETWORK|FSF|GNU    copy_and_return(PROPER_NOUN)
     COMPANY|HOUSE|OFFICE|LPF    copy_and_return(PROPER_NOUN)
     THE|THIS|THAT|THOSE         copy_and_return(DECLARATIVE)
     
     ALL|FIRST|LAST              copy_and_return(CONDITIONAL)
     FIND|SEARCH|SORT|ERASE|KILL copy_and_return(VERB)
     ADD|REMOVE|DELETE|PRINT     copy_and_return(VERB)
     
     QUICKLY|SLOWLY|CAREFULLY    copy_and_return(ADVERB)
     IN|AT|ON|AROUND|INSIDE|ON   copy_and_return(POSITIONAL)
     
     "."                         return(PERIOD);
     "\n"                        yylexlinenum++; return(NEWLINE);
     .
     %%

これらのファイルは、 以下を実行することでコンパイルできます。

     % bison -d front.y
     % flex -I front.lex
     % cc -o front alloca.c front.tab.c lex.yy.c

または、 この例のソースが手元にあれば、 examplesサブディレクトリにおいて‘make front’を実行することでもコンパイルできます。

注:Bisonパーサはalloca.cというファイルを必要とします。 このファイルはexamplesサブディレクトリにあります。 Bisonの代わりにyaccを使うのであれば、 このファイルは必要ありません。