lex コマンド

目的

入力ストリームの簡単な字句解析のために、パターン・マッチングを行う C または C++ 言語プログラムを作成します。

構文

lex [ -C ] [ -t ] [ -v| -n ] [ File ... ]

説明

lex コマンドは File または標準入力を読み取り、C 言語プログラムを生成し、それを lex.yy.c という名前のファイルに書き込みます。 このファイル lex.yy.c は C 言語プログラムと互換性があります。 C++ コンパイラーでも、lex コマンドの出力をコンパイルすることができます。 -C フラグを指定すると、出力ファイル名が C++ コンパイラー用の lex.yy.C に変更されます。

lex コマンドで生成される C++ プログラムでは、STDIO または IOSTREAMS のどちらかを使用することができます。 C++ コンパイル処理中に define _CPP_IOSTREAMS が真であれば、プログラムはすべての入出力に IOSTREAMS を使用します。 それ以外の場合は、STDIO が使用されます。

lex コマンドは File に入っている規則やアクションを使って、プログラム lex.yy.c を生成します。 このプログラムは cc コマンドでコンパイルすることができます。 コンパイルされた lex.yy.c は次に入力を受け取り、その入力を File 内の規則で定義された論理部分に分解し、File 内のアクションに含まれるプログラムの一部分を実行します。

生成されたプログラムは、yylex と呼ばれる C 言語関数です。 lex コマンドは yylex 関数を lex.yy.c という名前のファイルに保管します。 yylex 関数を単独で使うことによって単純な 1 ワードの入力を認識することや、他の C 言語プログラムと共に使うことによってさらに難しい入力分析関数を実行することもできます。 例えば、lex コマンドを使ってプログラムを生成し、そのプログラムを使って入力ストリームを簡易化した後、 入力ストリームを yacc コマンドが生成した構文解析プログラムに送らせるようにすることができます。

yylex 関数は有限状態マシンと呼ばれるプログラム構造によって入力ストリームを分析します。 この構造により、プログラムが一度にとることができる状態 (または条件) は 1 つだけとなります。 許可される状態数は有限です。 File 内にあるこの規則は、プログラムがある状態から別の状態にどのように移るかを決定します。

File を指定しないと、lex コマンドは標準入力を読み取ります。 複数のファイルは単一のファイルとして扱われます。

注: lex コマンドは中間ファイルと出力ファイルに対して固定名を使うので、与えられたディレクトリー内では lex によって生成されたプログラムは 1 つしか存在することができません。

lex 仕様ファイル

入力ファイルには、定義セクション規則セクションユーザー・サブルーチン・セクション のセクションがあります。 各セクションは、区切り文字 %% (パーセント記号 2 つ) しか含まれない行によって、他のセクションと区切らなければなりません。 フォーマットは次のとおりです。

次の各セクションではセクションの目的とフォーマットについて説明します。

定義

規則内で変数を使いたいときは、それらの変数はこのセクションで定義しなければなりません。 これらの変数は左の欄に、その定義は右の欄にまとめられます。 例えば、D を数字として定義したいときは、次のように書きます。


D   [0-9]

変数名を {} (中括弧) で囲むことによって、定義された変数を規則セクションで使うことができます。 次に例を示します。


{D}

ブランクで始まる定義セクションまたは %{, %} 区切り行で囲まれている定義セクション内の行は、lex.yy.c ファイルにコピーされます。 この構成を使用すると、lex のアクション内で使用する C 言語変数を宣言するか、または次のようにヘッダー・ファイルを組み込むことができます。

%{
#include <math.h>
int count;
%}

また、このような行は、最初の %% 区切り記号の直後の規則セクションの先頭にも置くことができますが、規則セクションの他の場所では使用できません。 この行が File の定義セクションに含まれていると、lex コマンドはこの行を lex.yy.c ファイルの外部宣言セクションにコピーします。 この行が規則セクションの最初の規則の前に含まれていると、lex コマンドは lex.yy.c 内の yylex サブルーチンのローカル宣言セクションにコピーします。 この行が最初の規則の後に置かれないようにしてください。

lex 外部のタイプである yytext は、定義セクションで次のどちらかを指定して、ヌル終了文字配列 (デフォルト) またはヌル終了文字列へのポインターに設定することもできます。


%array    (default)
%pointer

定義セクションでは、結果として生じる有限状態マシンのためにテーブルのサイズを設定することができます。 デフォルトのサイズは、小さなプログラムに十分な大きさです。 さらに複雑なプログラムのためにもっと大きなサイズを設定することもできます。

項目 説明
%an 移行の数は n です (デフォルトは 5000)
%en 構文解析ツリー・ノードの数は n です (デフォルトは 2000)
%hn マルチバイト文字の出力スロット数 (デフォルトは 0)
%kn パックされた文字クラスの数 (デフォルトは 1000)
%mn マルチバイト「文字クラス」文字の出力スロット数 (デフォルトは 0)
%nn 状態の数は n です (デフォルトは 2500)
%on 出力スロットの数 (デフォルトは 5000、最小 257)
%pn 位置の数は n です (デフォルトは 5000)
%vp %h%m によって制御されたハッシュ・テーブル内の空きスロットの割合 (デフォルトは 20、範囲 0 <= P < 100)
%zn マルチバイト文字クラスの出力スロット数 (デフォルトは 0)

マルチバイト文字が拡張正規表現の文字列内にあると、%o 引数を使用して出力配列サイズを (ほぼ 10,000 から 20,000 の配列サイズに) 再設定しなければならないことがあります。 この再設定は、1 バイト文字の数と比較するとかなり多い数の文字に影響します。

マルチバイト文字が拡張正規表現で表示される場合、%h%m の引数を使って、マルチバイト・ハッシュ・テーブルのサイズを、lex ファイルに含まれるマルチバイト文字数の合計より大きいサイズに設定しなければなりません。

マルチバイト文字が拡張正規表現でなくても、 「.」を使用マルチバイト文字に一致させたい場合は、%z をゼロよりも大きい値に設定しなければなりません。 また、反転文字クラス ([^abc] など) でマルチバイト文字を一致させる場合は、%h および %m の両方をゼロよりも大きい値に設定しなければなりません。

マルチバイト文字を使用する場合は、-qmbcs コンパイラー・オプションを使用して、lex.yy.c ファイルをコンパイルしなければなりません。

規則

一度用語を定義すると、規則セクションを書くことができます。 このセクションには yylex サブルーチンで照合される文字列と式、および照合時に実行される C コマンドが入っています。 このセクションは必須で、定義セクションのあるなしにかかわらず、区切り文字 %% (2 つのパーセント記号) が先になければなりません。 この区切り文字がないと、lex コマンドは規則を認識しません。

このセクションでは、左の欄にパターンが拡張正規表現の形式で記述され、yylex サブルーチンへの入力ファイル内で認識されます。 右の欄には、パターンが認識されるとき実行される C プログラムの一部 (アクション と呼ばれる) が記述されます。

字句解析プログラムは一致する拡張正規表現を見つけると、その拡張正規表現に関連付けられるアクションを実行します。

パターンには拡張文字を入れることができます。 マルチバイト・ロケールが運用システムにインストールされている場合は、インストールされたコード・セットの一部であるマルチバイト文字も、パターンに入れることができます。

欄はタブまたは空白によって区切られます。 例えば、ファイル内でキーワード KEY を検索するには、次のように書くことができます。

(KEY) printf ("found KEY");

この規則を File に入れると、字句解析プログラム yylex はパターン KEY に一致し、printf サブルーチンを実行します。

各パターンは対応するアクション、つまり、パターンが一致する場合に実行する C コマンドを持つことができます。 各ステートメントは ; (セミコロン) で終わらなければなりません。 1 つのアクションで複数のステートメントを使うときは、それらのすべてのステートメントを { } (中括弧) で囲まなければなりません。 ユーザー・サブルーチン・セクションがあるときは、2 番目の区切り文字 %% は規則セクションの後に付けなければなりません。 パターンが一致する場合に指定されたアクションがないと、字句解析プログラムは入力パターンを変更せずに出力にコピーします。

yylex 字句解析プログラムは、入力ストリーム内で文字列を照合すると、一致した文字列を外部文字配列 (または文字列を指すポインター) yytext にコピーしてから、規則セクションにあるコマンドを実行します。 同様に、外部 int 型 yyleng は、一致した文字列の長さがバイト数で設定されます (したがって、マルチバイト文字のサイズは 1 よりも大きくなります)。

ユーザー・サブルーチン

lex ライブラリーには、lex 仕様ファイルの規則セクション使用できるマクロとして次のようなサブルーチンが定義されています。

項目 説明
input 1 バイトを yyin から読み取ります。
unput 読み取られた 1 バイトを置き換えます。
output 出力バイトを yyout に書き込みます。
winput yyin からマルチバイト文字を読み取ります。
wunput 読み取られたマルチバイト文字を置き換えます。
woutput マルチバイト出力文字を yyout に書き込みます。
yysetlocale 現行ロケールを決定するサブルーチン setlocale (LC_ALL,""); を呼び出します。

winputwunput、および woutput マクロは、lex.yy.c ファイルでコード化された yywinputyywunputyywoutput サブルーチンを使用するために定義されています。 互換性のため、これらの yy サブルーチンは、完全なマルチバイト文字で必要なバイト数の読み取り、置換、書き込みを行うために、続けて inputunputoutput サブルーチンを使用します。

これらのマクロは、これらのルーチンに対するユーザーの独自のコードをユーザー・サブルーチン・セクションに書き込むことによって、オーバーライドすることができます。 しかし、ユーザー独自のコードを書く場合は、次のようにこれらのマクロを定義セクションで未定義にしなければなりません。

%{
#undef input
#undef unput
#undef output
#undef winput
#undef wunput
#undef woutput
#undef yysetlocale
%}

lex ライブラリーには、yylex 字句解析プログラムを呼び出す main サブルーチンだけでなく、File の終わりに yylex() によって呼び出しされる yywrap サブルーチンが含まれているので、lex.yy.c には main サブルーチンはありません。 したがって、 ユーザー・サブルーチン・セクションに main( )yywrap( )、 またはその両方が含まれていない場合は、 lex.yy.c をコンパイルする時に cclex.yy.c-ll を入力しなければなりません。 この場合、lllex ライブラリーを呼び出します。

lex コマンドで生成される外部名はすべて、yyinyyoutyylex、および yytext のように yy で始まります。

有限状態マシン

有限状態マシンのデフォルトの骨組みは、/usr/ccs/lib/lex/ncform に定義されています。 環境変数 LEXER=PATH を設定することによって、ユーザー自身が設定した有限状態マシンを使用することもできます。 PATH 変数は、ユーザー定義による有限状態マシンのパスとファイル名を指定します。 lex コマンドは環境のこの変数を確認し、この変数が設定されていれば、与えられたパスを使用します。

式にブランクを入れる

通常、規則の終わりにはブランクまたはタブが付くので、規則を定義している式はブランクまたはタブで終了します。 しかし、ブランクやタブ文字を " " (引用符) で囲んで式に入れることができます。 [ ] (大括弧) 内に入っていない式では、ブランクはすべて引用符で囲みます。

その他の特殊文字

lex プログラムは多数の通常の C 言語特殊文字を認識します。 これらの文字シーケンスは次のとおりです。

シーケンス 意味
¥a アラート
¥b バックスペース
¥f 用紙送り
¥n 改行文字 (式では実際の改行文字を使用してはなりません)
¥r リターン
¥t タブ
¥v 垂直タブ
¥¥ 円記号
¥digits digits で指定した 1 桁、2 桁、3 桁の 8 進整数で表されるエンコード文字。
¥xdigits digits で指定した 16 進文字シーケンスで表されるエンコード文字。
¥c c が上記以外の文字であれば、文字 c が変更されないことを示します。

注: lex の規則セクションには ¥0¥x0 を使用しないでください。

これらの特殊文字を式で使用する場合、引用符で囲む必要はありません。 これらの特殊文字と演算子記号を除き、すべての文字は常にテキスト文字です。

突き合わせ規則

複数の式が現行入力と一致する場合、lex コマンドは最初に最も長い一致を選択します。 複数の規則が同数の文字と一致する場合、lex コマンドは最初に発生する規則を選択します。 例えば、次の規則がこの順序で指定されます。

integer    keyword action...;
[a-z]+       identifier action...;

integers が入力語であるものと仮定した場合、lex は入力を ID と一致させます。 その理由は、integer が 7 文字としか一致しないのに対して、[a-z]+ は 8 文字と一致するからです。 ただし、入力が integer であれば、どちらの規則も 7 文字と一致します。 keyword 規則が先に発生するため、lex はこちらを選択します。 int のように短い入力は式 integer に一致せず、lex は identifier 規則を選択します。

ワイルドカードを使った文字列の一致

lex は最長の一致を最初に選ぶので、.* のような式を含んでいる規則は使用しないでください。 以下に例を示します。

'.*'

上記の例は、単一引用符内の文字列を認識する良い方法のように見えるかもしれません。 しかし、字句解析プログラムは長い照合を完了するために、離れた所にある単一引用符を探してさらに先を読み取ります。 このような規則を持った字句解析プログラムが、次のように入力します。

'first' quoted string here, 'second' here

これは次のストリングに一致します。

'first' quoted string here, 'second'

もっと短い文字列 firstsecond を見つけるには、 次の規則を使います。

'[^'¥n]*'

この規則は 'first' の後で止まります。

この種のエラーは、. (ピリオド) 演算子が改行文字に一致しないので、後で影響することはありません。 したがって、.* (ピリオド、アスタリスク) などの式の効果の効果は現在の行で止まります。 [.¥n]+ などの式でこれを無効にしようとしないでください。 字句解析プログラムが入力ファイル全体を読み取ろうとすると、内部バッファー・オーバーフローが発生します。

文字列の中での文字列の検索

lex プログラムは入力ストリームを区分し、各式の可能な一致をすべて検索することはしません。 各文字は一度だけ計算されます。 例えば、 shehe の両方が入力テキストに現れる回数を数えるには、 次の規則を試してください。

she         s++
he          h++
¥n          |.           ;

ここで、最後の 2 つの規則は heshe 以外のすべてのものを無視します。 しかし、shehe を含むので、lexheshe に含まれるインスタンスを認識しません

この選択をオーバーライドするには、アクション REJECT を使います。 このディレクティブは、lex が次の規則に進むように命令します。 そこで lex は入力ポインターの位置を調整して、最初の規則が実行される前の場所に置き、次の選択の規則を実行します。 例えば、he が含まれる場合を数えるには、次の規則を使います。

she                 {s++;REJECT;}
he                  {h++;REJECT;}
¥n                  |.                   ;

she が現れる回数を数えると、lex は入力ストリームを拒否し、次に he が現れる回数を数えます。 この場合、shehe を含みますが、その逆はないので、he について REJECT アクションを省略することができます。 その他の場合、どの入力文字が両方のクラスにあるかを確認するのは難しいかもしれません。

一般に REJECT は、lex を入力ストリームを区分するためではなく、入力内のある項目のすべての例を検出するために使うと便利で、これらの項目の例は互いに重なり合っていたり含んでいたりすることがあります。

フラグ

項目 説明
-C C++ コンパイラーで使用できるように、lex.yy.c の代わりに lex.yy.C ファイルを作成します。 入出力ストリーム・ライブラリーを取り出すには、マクロ _CPP_IOSTREAMS も使用します。
-n 統計情報の要約情報の出力を抑制します。 有限状態マシンに対してユーザー独自のテーブル・サイズを設定する場合、このフラグを選択しなければ、lex コマンドは自動的にこの要約情報を作成します。
-t lex.yy.c をファイルの代わりに標準出力に書き出します。
-v 生成した有限状態マシンの統計情報 1 行の要約を提供します。

終了状況

このコマンドは次の終了値を戻します。

項目 説明
0 正常終了。
>0 エラーが発生しました。

  1. lex 命令をファイル lexcommands から抽出して、出力を lex.yy.c に配置するには、次のコマンドを使用します。
    lex lexcommands
  2. 大文字を小文字に変換し、行末ブランクを取り除き、複数のブランクを単一のブランクに置き換える lex プログラムを作成するには、lex コマンド・ファイルに次のように指定します。
    %%
    [A-Z]   putchar(yytext[0]+ 'a'-'A');
    [ ]+$ ;
    [ ]+    putchar(' '); 

ファイル

項目 説明
/usr/ccs/lib/libl.a 実行時ライブラリーが入っています。
/usr/ccs/lib/lex/ncform 有限状態マシンを定義します。