Next: , Previous: Example-Counting Words, Up: More Examples


7.2 Pascalのサブセット用の字句スキャナ

ここでは、 Pascalのような言語用の字句スキャナを作る方法を示します。 このスキャナ定義では、 個々のキーワードがルールとしてリストされています。 (一般的には、 すべてのキーワードをテーブルに格納してからテーブル検索を使う手法がよく見られますが、) ここでの方法は、 キーワードと識別子とを区別するための方法としては、 一般的に最も簡単なものです。 また、 識別子用にただ1つのルールがあるという点に注意してください。 多くの場合、 このルールはシンボル・テーブルを管理するためのサブルーチンを呼び出します。

もう1つ注意すべき点は、 ‘_FILE’と‘_BEGIN’が先頭にアンダースコアを持つという点です。 Flex、 またはCで定義済みの名前は、 追加的な工夫なしでは使えないということを示すために、 このようにしてあります。 これよりももっと一般的に使われる手法は、 すべてのトークンの先頭もしくは末尾に何らかの文字列を付加するというもので、 こうすることによって問題は発生しなくなります。 ‘TOK’や‘SYM’が一般的によく使われる拡張子です。

     
     
     
     
     /*
      * pascal.lex : PASCALスキャナの例
      */
     
     %{
     #include <stdio.h>
     #include "y.tab.h"
     int line_number = 0;
     void yyerror(char *message);
     
     %}
     
     %x COMMENT1 COMMENT2
     white_space       [ \t]*
     digit             [0-9]
     alpha             [A-Za-z_]
     alpha_num         ({alpha}|{digit})
     hex_digit         [0-9A-F]
     identifier        {alpha}{alpha_num}*
     unsigned_integer  {digit}+
     hex_integer       ${hex_digit}{hex_digit}*
     exponent          e[+-]?{digit}+
     i                 {unsigned_integer}
     real              ({i}\.{i}?|{i}?\.{i}){exponent}?
     string            \'([^'\n]|\'\')+\'
     bad_string        \'([^'\n]|\'\')+
     %%
     "{"                  BEGIN(COMMENT1);
     <COMMENT1>[^}\n]+
     <COMMENT1>\n            ++line_number;
     <COMMENT1><<EOF>>    yyerror("EOF in comment");
     <COMMENT1>"}"        BEGIN(INITIAL);
     "(*"                 BEGIN(COMMENT2);
     <COMMENT2>[^)*\n]+
     <COMMENT2>\n            ++line_number;
     <COMMENT2><<EOF>>    yyerror("EOF in comment");
     <COMMENT2>"*)"       BEGIN(INITIAL);
     <COMMENT2>[*)]
     
     
     
     
     
     
     
     /* FILEとBEGINは、FlexやCにおいては既に定義されているため
      * 使うことができない点に注意。これは、すべてのトークンの
      * 先頭にTOK_やその他の接頭辞を付加することによって、より
      * すっきりと克服することができる
      */
     
     and                  return(AND);
     array                return(ARRAY);
     begin                return(_BEGIN);
     case                 return(CASE);
     const                return(CONST);
     div                  return(DIV);
     do                   return(DO);
     downto               return(DOWNTO);
     else                 return(ELSE);
     end                  return(END);
     file                 return(_FILE);
     for                  return(FOR);
     function             return(FUNCTION);
     goto                 return(GOTO);
     if                   return(IF);
     in                   return(IN);
     label                return(LABEL);
     mod                  return(MOD);
     nil                  return(NIL);
     not                  return(NOT);
     of                   return(OF);
     packed               return(PACKED);
     procedure            return(PROCEDURE);
     program              return(PROGRAM);
     record               return(RECORD);
     repeat               return(REPEAT);
     set                  return(SET);
     then                 return(THEN);
     to                   return(TO);
     type                 return(TYPE);
     until                return(UNTIL);
     var                  return(VAR);
     while                return(WHILE);
     with                 return(WITH);
     
     "<="|"=<"            return(LEQ);
     "=>"|">="            return(GEQ);
     "<>"                 return(NEQ);
     "="                  return(EQ);
     
     ".."                 return(DOUBLEDOT);
     {unsigned_integer}   return(UNSIGNED_INTEGER);
     {real}               return(REAL);
     {hex_integer}        return(HEX_INTEGER);
     {string}             return{STRING};
     {bad_string}         yyerror("Unterminated string");
     {identifier}         return(IDENTIFIER);
     
     [*/+\-,^.;:()\[\]]   return(yytext[0]);
     
     
     {white_space}        /* 何もしない */
     \n                   line_number += 1;
     .                    yyerror("Illegal input");
     %%
     void yyerror(char *message)
     {
        fprintf(stderr,"Error: \"%s\" in line %d.  Token = %s\n",
                message,line_number,yytext);
        exit(1);
     }