字句解析プログラムによって実行されるアクション

字句解析プログラムは、仕様ファイルの規則のセクションの拡張正規表現の 1 つを突き合わせる場合、拡張正規表現に対応するアクション を実行します。 入力ストリーム内のすべての文字列を突き合わせるだけの十分な規則がない場合、 字句解析プログラムは入力を標準出力へコピーします。 したがって、入力を出力へコピーするだけの規則は、作成しないでください。 デフォルト出力は、規則の食い違いを検出するのに役立つ場合があります。

lex コマンドを使用して、yacc コマンドが作成するパーサーへの入力を処理する場合は、すべての入力文字列を突き合わせる規則を提供します。 その規則は、 yacc コマンドが解釈できる出力を生成するものでなければなりません。

null アクション

拡張正規表現と関連した入力を無視するには、; (C 言語の null ステートメント) を使用します。 次の例では、3 つのスペーシング文字 (ブランク、タブ、および改行) が無視されています。

[ ¥t¥n] ;

次のアクションと同じ

同じアクションを繰り返し作成するのを避けるためには、| (パイプ記号) を使用します。 この文字は、この規則のアクションが次の規則のアクションと同じであることを示しています。 例えば、ブランク、タブ、および改行の文字を無視する前の例は、次のように書くこともできます。
" "                     |
"¥t"                    |
"¥n"                    ;

¥n¥t の前後の引用符は必須ではありません。

一致した文字列の出力

どのテキストが仕様ファイルの規則セクションの式と一致したかを判別するために、その式のアクションの 1 つとして C 言語の printf サブルーチン呼び出しを組み込むことができます。 字句解析プログラムは、入力ストリームで一致した文字列を見つけると、 その文字列を外部文字 (char) 配列とワイド文字 (wchar_t) 配列 (それぞれ、 yytext および yywtext と呼ばれる) に書き込みます。 例えば、次の規則を使用して一致した文字列を印刷することができます。

[a-z]+            printf("%s",yytext);

C 言語の printf サブルーチンは、 フォーマット引数と印刷するデータを受け入れます。 この例では、printf サブルーチンに対する引数の意味は、次のとおりです。

%s
印刷の前にデータをタイプ文字列に変換する記号
%S
印刷の前にデータをワイド文字列 (wchar_t) に変換する記号
yytext
印刷するデータの入った配列の名前
yywtext
印刷するマルチバイト・タイプ (wchar_t) データが入っている配列の名前
lex コマンドは、ECHO; を、yytext の内容を印刷する特殊なアクションと定義します。 例えば、次の 2 つの規則は同等です。
[a-z]+       ECHO;
[a-z]+       printf("%s",yytext);
次のように、%array または %pointer のいずれかを lex 仕様ファイルの定義セクションで使用することによって、yytext の表記を変更することができます。
%array
yytext を null 終了文字配列として定義します。 これは、デフォルトのアクションです。
%pointer
yytext を null 終了文字列を指すポインターとして定義します。

一致した文字列の長さの検出

特定の拡張正規表現に関して、 字句解析プログラムが突き合わせた文字数を検索するには、yyleng または yywleng 外部変数を使用します。
yyleng
一致したバイト数をトラッキングします。
yywleng
一致した文字列内のワイド文字の数をトラッキングします。 マルチバイト文字は、長さが 1 を超えています。
入力の中のワード数とワードの中の文字数の両方をカウントするには、 次のアクションを使用します。
[a-zA-Z]+       {words++;chars += yyleng;}

このアクションは、一致したワードの中の文字数を合計して、 その数を chars に書き込みます。

次の式は、一致した文字列の最後の文字を検索します。
yytext[yyleng-1]

文字列内の文字列の突き合わせ

lex コマンドは、入力ストリームを分割するので、 それぞれの式のすべての可能な突き合わせを行っているわけではありません。 それぞれの文字は、1 回だけ計算されます。 この選択を指定変更して、互いに重なり合ったり包含したりしている項目を検索するには、REJECT アクションを使用します。 例えば、shehe のすべてのインスタンスを、 she の中に組み込まれている he も含めてカウントするには、次のアクションを使用します。
she              {s++; REJECT;}
he               {h++}
¥n               |
.                ;

she のオカレンスをカウントした後で、 lex コマンドは入力文字列を拒否して、 he のオカレンスをカウントします。 he には she は組み込まれていないので、REJECT アクションは he には不要です。

yytext 配列への結果の追加

通常は、yytext 配列の中の現行項目は、入力ストリームのその次の文字列によって上書きされます。 yymore サブルーチンを使用した場合、 入力ストリームからの次の文字列は、yytext 配列の現行配列の最後に追加されます。

例えば、次の字句解析プログラムは複数の文字列を検索します。

%s instring
%%
<INITIAL>¥"     {  /* start of string */
         BEGIN instring;
         yymore();
        }
<instring>¥"    {  /* end of string */
         printf("matched %s¥n", yytext);
         BEGIN INITIAL;
        }
<instring>.     {
         yymore();
        }
<instring>¥n    {
         printf("Error, new line in string¥n");
         BEGIN INITIAL;
        }

複数の規則を突き合わせれば文字列は認識されるかもしれないけれども、 yymore サブルーチンを繰り返し呼び出せば、yytext 配列に確実に文字列全体を組み入れることができます。

入力ストリームへの文字の戻り

文字を入力ストリームに戻すには、次の呼び出しを使用します。

yyless(n)

ここで、n は保持すべき現在の文字列の文字数です。 文字列の中のこの文字数を超える部分の文字は、入力ストリームに戻されます。 yyless サブルーチンにも、 / (スラッシュ) 演算子が使用するのと同じタイプの先読み関数が用意されていますが、 こちらのほうがその使用法をさらに詳細に制御することができます。

テキストを複数回使用する場合は、yyless サブルーチンを使用してください。 例えば、C 言語プログラムを構文解析している場合、x=-a のような式は理解が困難です。 x is equal to minus a (x は -a と等しい) を意味するのか、 または x -= a の古い表現で、decrease x by the value of a (x を a の値だけ減らす) ということを意味するのでしょうか。 この式を x is equal to minus a として扱い、 警告メッセージを印刷する場合は、次のような規則を使用します。
=-[a-zA-Z]      {
                printf("Operator (=-) ambiguous¥n");
                yyless(yyleng-1);
                ... action for = ...
                }

入出力サブルーチン

lex プログラムを使用すると、 プログラムが次の入出力 (I/O) サブルーチンを使用できるようになります。
input()
次の入力文字を戻す
output(c)
出力上に文字 C を書き込む
unput(c)
文字 c を、後で input サブルーチンで読むように、 元の入力ストリームにプッシュする
winput()
次のマルチバイト入力文字を戻す
woutput(C)
マルチバイト文字 C を、元の出力ストリームに書き出す
wunput(C)
マルチバイト文字 C を、後で winput サブルーチンで読むように、 元の入力ストリームにプッシュする

lex プログラムは、これらのサブルーチンをマクロ定義の形で提供します。 サブルーチンは、lex.yy.c ファイルの中にコーディングされています。 これらを変更して、他のバージョンを提供することができます。

winputwunput、 および woutput マクロは、 yywinputyywunput、 および yywoutput サブルーチンを使用するように定義されています。 互換性のために、yy サブルーチンは後に inputunput、および output サブルーチンを使用して必要なバイト数を完全なマルチバイト文字で読み取り、置き換え、 および書き込みをします。

これらのサブルーチンは、外部ファイルと内部文字の間の関係を定義します。 サブルーチンを変更する場合は、すべてのサブルーチンを同じように変更してください。 これらのサブルーチンは、以下の規則に従う必要があります。
  • すべてのサブルーチンが同じ文字セットを使用する必要がある。
  • input サブルーチンはファイルの終わりを示すために 0 の値を戻す必要がある。
  • input サブルーチンに対する unput サブルーチンの関係は変更しない。変更すると、先読み関数が作動しなくなる。

lex.yy.c ファイルによって、 字句解析プログラムは最大 200 文字をバックアップすることができます。

ヌルの入ったファイルを読むには、 異なるバージョンの input サブルーチンを作成する必要があります。 通常バージョンの input サブルーチンでは、 戻された値の 0 (null 文字から) は、ファイルの終わりと入力の終わりを示しています。

文字セット

lex コマンドが生成する字句解析プログラムは、 input、output、および unput サブルーチンを使用して文字入出力を処理します。 したがって、yytext サブルーチンで値を戻すために、lex コマンドは、これらのサブルーチンが使用する文字表現を使用しています。 しかし内部では、 lex コマンドはそれぞれの文字を短整数で表しています。 標準ライブラリーを使用している場合、 この整数はコンピューターが文字の表現に使用するビット・パターンです。 通常、文字 a は、文字定数 a と同じ形式で表されます。各種の入出力サブルーチンでこの解釈を変更する場合は、仕様ファイルの定義セクションに変換テーブルを書き込んでください。 変換テーブルは、 次のエントリーだけの入った行で始まり、同じ行で終わります。
%T
変換テーブルには、それぞれの文字と関連した値を示す追加行が入っています。 例:

%T
{integer}       {character string}
{integer}       {character string}
{integer}       {character string}
%T

ファイルの終わり処理

字句解析プログラムは、ファイルの終わりに達すると、yywrap ライブラリー・サブルーチンを呼び出します。このサブルーチンは、入力の終わりで通常の折り返しを継続することを字句解析プログラムに示す、1 の値を戻します。

ただし、字句解析プログラムが複数のソースから入力を受け取った場合は、yywrap サブルーチンを変更します。 新しい関数は、 新しい入力を取得してから 0 の値を字句解析プログラムへ戻す必要があります。 0 の戻り値は、プログラムが処理を継続する必要があることを示します。

新バージョンの yywrap サブルーチンで字句解析プログラムが 終了したときに、要約レポートとテーブルを印刷するコードを組み込むこともできます。 yywrap サブルーチンは、yylex サブルーチンに強制的に入力の終了を認識させる唯一の方法です。