名前 | 形式 | 機能説明 | オプション | オペランド | 出力 | 拡張機能説明 | 使用法 | 使用例 | 環境 | 終了ステータス | 属性 | 関連項目 | 注意事項
lex ユーティリティは、文字入力の字句解析に用いる C プログラムを生成します。このプログラムは、 yacc へのインタフェースとして使用できます。 lex ソースコードから生成された C プログラムは、 ISO C 標準に準拠しています。通常 lex ユーティリティは、生成したプログラムを lex.yy.c ファイルに書き出します。 lex の終了ステータスがゼロでない場合、このファイルの状態は不定です。 lex の入力言語に関する詳細は、「拡張機能説明」の項を 参照してください。
以下のオプションを使用できます。
C 言語の動作を示します。本指定がデフォルトです。
EUC 文字を扱えるプログラムを生成します。本オプションは -w と同時に指定することはできません。 yytext[ ] の型は unsigned char[ ] となります。
-v によって出力される合計情報の出力を抑止します。 lex ソースコード中にテーブルのサイズが指定されず、 -v オプションを省略した場合には、この -n が指定されたものと見なされます。
生成したプログラムを、 lex.yy.c ファイルではなく標準出力上に書き出します。
lex 合計情報を標準エラー出力に書き出します( 「 lex の定義」の項にある lex テーブルサイズの説明を参照してください)。 lex ソースコード中にテーブルサイズが指定されていて、 -n オプションが省略された場合、 -v オプションが有効となります。
EUC 文字を扱えるプログラムを生成します。本オプションは -e と同時に指定することはできません。 yytext[ ] の型は wchar_t[ ] となります。この点が -e 指定と異なります。
標準エラー出力上にバージョン情報を書き出します。
-Qy は、ファイル lex.yy.c にバージョン情報を書き出します。 -Qn はバージョン情報を出力しません。デフォルト指定は -Qn です。
以下のオペランドを指定できます。
入力ファイルのパス名。複数のファイルを指定すると、 それらすべてが連結されて 1 つの lex プログラムが生成されます。 このオペランドを 1 つも指定しない場合、およびオペランドとして - を指定した場合、標準入力が用いられます。
-t オプションが指定されると、 lex の C ソースコード出力のテキストファイルが標準出力に書き出されます。
-t オプションが指定されると、 lex ソースコード入力の内容に関する情報メッセージ、 エラーメッセージ、および警告メッセージが標準エラー出力に出力されます。
-t オプションが指定されなければ、次のようになります。
lex ソースコード入力の内容に関する情報メッセージ、 エラーメッセージ、および警告メッセージが 標準出力または標準エラー出力に書き出されます。
-v オプションが指定され、 -n オプションが指定されなかった場合は、 lex 統計情報が標準エラー出力に書き出されます。 -n オプションが指定されていない限り、 lex の定義の セクション (「拡張機能説明」を参照のこと) 内にテーブルサイズが % 演算子で指定された場合も、この統計情報が出力されます。
C ソースコードが入ったテキストファイルが lex.yy.c に、または -t オプションが指定された場合は標準出力に書き出されます。
各入力ファイルには lex ソースコードが入っています。これは、 C プログラムフラグメントの形式で対応するアクションを定義した 正規表現のテーブルです。
lex.yy.c がコンパイルされ lex ライブラリにリンクされると ( c89 または cc で -l l オペランドを使って)、 生成されたプログラムは標準入力から文字入力を読み込み、 与えられた式と一致する文字列に分割します。
式が一致すると、以下の処理が行われます。
一致した入力文字列は、 NULL で終わっている文字列として yytext に残されます。 yytext は、外部文字配列または文字列へのポインタのどちらかです。 lex の定義の セクション で説明するように、 %array または %pointer 宣言を使えば型を明示選択できますが、 デフォルトは %array です。
照合文字列の長さが外部変数 int yyleng に設定されます。
式に対応するプログラムフラグメントまたはアクションが実行されます。
パターン照合の間、 lex はパターンセットを検索し、一致するもっとも長い文字列を見つけ出します。 同じ文字数の一致する文字列が複数ある場合は、最初のパターンが選択されます。
lex ソースの一般形式は、次のとおりです。
最初の %% はルール (正規表現とアクション) の開始を示すために必要なもので、 2 番目の %% はユーザーサブルーチンが続く場合にのみ必要なものです。
lex の定義の セクション にある 空白文字で始まる 行は、 C プログラムフラグメントとみなされ、 lex.yy.c ファイルの外部定義域にコピーされます。同じく、 %{ と %} だけの区切り行に囲まれた部分もそのまま、 lex.yy.c ファイルの外部定義域にコピーされます。
他のルールが指定される前に、 「 lex の定義」の セクションの始めに、このような入力 (空白文字で始まる、 または %{ と %} だけの区切り行に囲まれる) があれば、 yylex 関数の変数宣言のあと、 yylex 内の最初のコード行の前に、 lex.yy.c に書き出されます。そのため yylex に入ったときに実行されるアプリケーションコードだけでなく、 yylex にローカルなユーザー変数をここで宣言できます。
いくつかのルールのあと、 Rules セクションに空白文字で始まる、または %{ と %} だけの区切り行に囲まれる入力があったときに lex が実行するアクションは、未定義です。このような入力があったとき、 yylex 関数の定義にエラーが生じることがあります。
lex 内の定義 は最初の %% 区切り行より前にあります。このセクション内で %{ と %} 区切り行に囲まれていない行で、しかも空白文字以外で始まっている行は、 lex 置換文字列を定義するものとみなされます。 これらの行の形式は、次のとおりです。
name substitute
ISO C 標準の識別子の条件を name が満たしていない場合、結果は未定義です。 substitute 文字列は、ルールとして使用されると文字列 { name } を置き換えます。この状況で name 文字列が認識されるのは、 中括弧が使用されていて、 大括弧や二重引用符で囲まれていないときだけです。
lex 内の定義 セクションでは、 % (パーセント記号) で始まりその後ろに s または S で始まる英数字語が続く行は、開始条件セットを定義します。 % (パーセント記号) で始まりその後ろに x または X で始まる英数字語が続く行は、排他的な開始条件セットを定義します。 生成されたスキャナが %s 状態のときは、状態が指定されていないパターンもアクティブになります。 %x 状態では、このようなパターンはアクティブになりません。 最初の語を除いた行の残りは、 空白文字で区切られた開始条件名とみなされます。 開始条件名は、定義名と同じ方法で作成されます。「 lex の正規表現」の項で説明するように、開始条件は、 正規表現の照合をいくつかの状態に制限するときに使用できます。
lex 内の定義 セクションで、次の排他的な宣言の 2 つのうちどちらかを使用します。
yytext の型を NULL で終わる文字配列と宣言します。
yytext の型を NULL で終わる文字配列へのポインタと宣言します。
yytext を変更するために、 %pointer オプションと同時に yyless 関数を使用することはできないので注意してください。
%array はデフォルトです。 %array が指定されている (または %array と %pointer の 2 つとも指定されていない) 場合に、外部参照先を yyext にするには以下のように書式を宣言します。
extern char yytext[ ]
%pointer が指定されている場合、 外部参照先の書式は以下の通りです。
extern char *yytext;
lex は、 特定の内部テーブルサイズを設定するため、 lex 内の定義 セクションで宣言することができます。次の表に、宣言を示します。
lex でのテーブルサイズ宣言
宣言 | 説明 | デフォルト |
%pn | ポジションの数 | 2500 |
%nn | 状態の数 | 500 |
%an | 遷移の数 | 2000 |
%en | 解析ツリーのノード数 | 1000 |
%kn | パック文字クラスの数 | 10000 |
%on | 出力配列のサイズ | 3000 |
lex により生成されたプログラムは、補助コードセットの EUC 文字を含む入力データを処理するため、 -e または -w のいずれかのオプションの指定を必要とします。 この両オプションがともに省略されると、 yytext の型は char[ ] となり、生成されたプログラムは ASCII 以外のコードセットを扱うことはできません。
-e オプションを使用すると、 yytext の型は unsigned char[ ] となり、 yyleng は一致した文字列のバイト数を示すことになります。マクロ input() 、 unput(c) 、および output(c) は、通常の ASCII lex と同様に、バイトを基準とした I/O を実行しなければなりません。 -e オプションで使用できる変数は他に 2 つあります。それは yywtext と yywleng で、それぞれ -w オプション指定時の yytext および yyleng と同じ動きをします。
-w オプションを指定すると、 yytext の型は wchar_t[ ] となり、 yyleng には一致した文字列の文字数が記録されます。 ユーザーがこのオプションを使って独自の input() 、 unput(c) 、または output(c) マクロを指定するのであれば、それらはワイド文字 (wchar_t) の形式で EUC 文字を返したり受け取ったりするよう設計しなければなりません。 これによって、ユーザーのプログラムと lex 内部との間に別のインタフェースを設け、 他のプログラムの処理速度を上げることが可能となります。
lex ソースファイル内のルールは、左のカラムには正規表現、 右のカラムにはその正規表現が認識されたときに実行されるアクション ( C プログラムフラグメント) が入ったテーブルです。
拡張正規表現 ( ERE ) 部分と action は、 1 つ以上の空白文字で区切られています。空白文字が入った正規表現は、 以下の条件の 1 つが満たされる場合に認識されます。
表現全体が二重引用符で囲まれている
二重引用符または大括弧内に空白文字がある
各空白文字の前にバックスラッシュがある
ユーザーサブルーチン内のものはすべて、 lex.yy.c の yylex のあとにコピーされます。
lex ユーティリティは、 regex(5) で記述されている拡張正規表現 (ERE) セットをサポートします。 ただし以下のように追加された構文と、例外となる構文があります。
二重引用符で囲まれた文字列は、二重引用符内の文字を表します。 ただしバックスラッシュエスケープの認識は除きます (次の表を参照してください)。バックスラッシュエスケープシーケンスは、 閉じる引用符で終端されます。たとえば " ¥ 01""1" は 8 進数の 1 と文字 1 からなる 1 個の文字列を表現します。
<state>r
正規表現 r が照合されるのは、プログラムが state 、 state1 、 state2 などによって示される開始条件の 1 つに合うときだけです。詳細については、「 lex 内のアクション」の項を参照してください (以降本書では、印刷上の規則の例外として、たとえば <state> はメタ変数を表さず、記号を囲むリテラル山括弧文字を表します)。 このように開始条件が認識されるのは、正規表現の始めだけです。
正規表現 r が照合されるのは、 r の後ろに正規表現 x が続いているときだけです。 yytext で戻されるトークンは、 r とだけ一致します。 r の末尾部分が x の先頭部分と一致する場合の結果は不定です。 r 式には末尾コンテキストや $ ( 行の終わり ) 演算子は含めることができません。 x には ^ (行の始まり) 演算子、末尾コンテキスト、 $ 演算子は含めることができません。つまり lex 正規表現には 1 つの末尾コンテキストしか含めず、 ^ 演算子が使用できるのはこのような式の始めだけです。 末尾コンテキスト演算子 / (スラッシュ) は、 括弧でグループ化できないよう制限されています。
name が Definitions セクションからの置換記号の 1 つなら、中括弧も含め、文字列は substitute 値で置き換えられます。 拡張正規表現内では、括弧で囲まれているものとして substitute 値が扱われます。 {name} が大括弧や二重引用符でかこまれている場合、 置換は行われません。
ERE 内では、バックスラッシュ文字 ( ¥¥, ¥ a, ¥ b, ¥ f, ¥ n, ¥ r, ¥ t, ¥ v) をエスケープシーケンスの始まりとみなします。 さらに以下のエスケープシーケンスが認識されます。
リテラル復帰改行文字 ( NEWLINE ) は、 ERE 内ではありえません。復帰改行文字を表現するには、エスケープシーケンス ¥ n が使用されます。復帰改行文字は、ピリオド演算子とは照合できません。
lex 内のエスケープシーケンス
エスケープ | 説明 | 意味 |
シーケンス | ||
¥ digits | バックスラッシュ文字とそのあとの 1 、 2 、または 3 桁の 8 進数の最長シーケンス ( 01234567 )。すべての桁が 0 なら (つまり NULL 文字なら)、動作は未定義 | エンコーディングが 1 、 2 、または 3 桁の 8 進整数を表す文字。システム上のバイトのサイズが 9 ビットよりも大きい場合、バイトを表現するために使用される 有効なエスケープシーケンスは、実装状態に依存する。 複数バイト文字には、バイトごとの先行 ¥ を含め、このタイプの複数の連結されたエスケープシーケンスが必要 |
¥ xdigits | バックスラッシュ文字とそのあとの 16 進文字の最長シーケンス ( 01234567abcdefABCDEF )。すべての桁が 0 なら (つまり NULL 文字なら)、動作は未定義 | エンコーディングが 16 進整数で表現される文字 |
¥ c | バックスラッシュ文字とそのあとに上記以外の文字があるもの ( ¥¥, ¥ a, ¥ b, ¥ f, ¥e n, ¥ r, ¥ t, ¥ v) | 文字 c、そのまま |
lex 用の拡張正規表現の優先順位は、下の表に示すとおりです。 優先度の高い順に並んでいます。
エスケープ文字エントリは、 これらが演算子であることを意味しませんが、真 の演算子との関係を示すため、表に組み込まれています。 この項で説明した配置方法の制限のため、開始条件、末尾コンテキスト、 およびアンカー指定は省略されています。これらは ERE の先頭または末尾にだけ指定できます。
lex 内での ERE 優先順位
照合関連の括弧記号 | [= =] [: :] [. .] |
エスケープ文字 | ¥<special character> |
大括弧表現 | [ ] |
引用 | ". . ." |
グループ化 | () |
定義 | {name} |
単一文字 RE 重複 | * + ? |
連結 | |
インターバル表現 | {m,n} |
択一 | | |
ERE アンカー演算子 ( ^ と $) は、表にはありません。 lex 正規表現では、これらの演算子の使用が次のように制限されています。 ^ 演算子は正規表現の始めにしか使用できず、 $ 演算子は最後にしか使用できません。 演算子は正規表現全体に適用されます。そのためたとえば、 (^abc)|(def$) などのパターンは未定義です。これは 2 つの別々のルールとして書くことができます。正規表現 ^abc と正規表現 def$ です。この 2 つは、特殊な | アクション ( 下記を参照のこと ) を介して共通なアクションを共有します。 パターンが ^abc|def$ と書かれたら、 abc または def だけの行と一致します。
一般の ERE ルールと異なり、従来のほとんどの lex の実装では組み込み型アンカーは許可されていません。 組み込み型アンカーの例としては、 foo が完全な語として存在するときに foo と照合させるための (^)foo($) などのパターン用があります。これは、以下の既存の lex 機能を使えば可能です。
なお $ も末尾コンテキストの形式であり ( /¥ n と等価)、その演算子の別のインスタンスを含む正規表現では 使用できません ( 上の末尾コンテキストの説明を参照してください ) 。
追加の正規表現末尾コンテキスト演算子 / (スラッシュ) は、二重引用符で囲む ( " / " ) 、前にバックスラッシュを付ける ( ¥ / ) 、または大括弧で囲めば ( [ / ]) 、通常の文字として使用できます。開始条件 < と > 演算子は、正規表現の始めの開始条件においてだけ特別とみなされます。 正規表現のその他の場所では、通常の文字として扱われます。
以下の例を見れば、 lex 正規表現と本書に出てくるその他の正規表現との違いがわかります。 r/x 形式の正規表現の場合、いつも r と一致する文字列 r が返されます。 x の先頭が r の末尾部分と一致する場合に混乱が生じることがあります。 たとえば、正規表現 a*b/cc と入力 aaabcc が与えられると、 yytext には aaab が入ります。しかし正規表現 x*/xy と入力 xxxy が与えられると、 xxx は x* に一致するため、 xx ではなく xxx が返されます。
ルール ab*/bc では、 r の最後の b* が末尾コンテキストの先頭の b までに一致するため 、結果は不定です。ただしこのルールが ab/bc なら、 テキスト ab にテキスト bc が続く場合に一致します。この場合 r は x の先頭の b までに一致しないので、結果は明確です。
ERE が一致したときに実行されるアクションは、 C プログラムフラグメントまたは以下に説明する特殊なアクションです。 プログラムフラグメントには 1 つ以上の C ステートメントと特殊なアクションが入っています。空の C ステートメント ; は、有効なアクションです。このようなルールのパターン部分に一致する lex.yy.c 入力内の文字列は、実際には無視またはスキップされます。 ただしアクションの不在は無効であり、このような状況で lex が実行するアクションは未定義です。
C ステートメントと特殊アクションも含め、アクションについての仕様は、 中括弧で囲まれていれば複数行にわたることができます。
ERE < 1 つ以上の空白文字 > { プログラムステートメント プログラムステートメント }
lex.yy.c プログラムへの入力内の文字列がどの表現とも一致しないときは、 デフォルトアクションとして、文字列が出力にコピーされます。 lex によって生成されるプログラムのデフォルトの動作は、 入力を読み込んで出力へコピーするだけなので、 %% だけの最小 lex ソースプログラムは、入力をそのまま出力へコピーするだけの C プログラムを生成します。
4 つの特殊アクションが使用可能です。
| ECHO; REJECT; BEGIN
アクション | は、次のルールのアクションが このルールのアクションであることを意味します。他の 3 つのアクションとは異なり、 | は中括弧で囲んだりセミコロンを付けたりできません。 | は単独で指定する必要があります。
文字列 yytext の内容を出力に書き出します。
1 つの式だけを入力内の文字列と一致させるのが普通です。 REJECT は「現在の入力と一致する次の式まで継続する」という意味で、 現在のルールが実行されたあと、 2 番目のルールが何であれ同じ入力に対して実行されます。そのため、 1 つの入力文字列または重なる入力文字列に対して複数のルールを 一致させて実行することができます。たとえば、正規表現 xyz 、正規表現 xy 、および入力 xyz が与えられると、通常は正規表現 xyz だけが一致します。次の照合は z のあとから開始されます。 xyz ルールの最後のアクションが REJECT なら、このルールと xy ルールの両方が実行されます。 yylex の別の部分への goto と同じように、制御の流れが継続しないような方法で、 REJECT アクションが実装されています。 REJECT を使用すると、スキャナはある程度大きくなり、実行が遅くなります。
BEGIN newstate;
このアクションは、状態 (開始条件) を newstate に切り替えます。文字列 newstate が lex 内の定義 セクションに開始条件として宣言されていないと、結果は不定です。 初期状態は、数字の 0 または INITIAL トークンで示されます。
以下に説明する関数やマクロは、 lex 入力内のユーザーコードをアクセスできます。 lex の C コード出力に示されるかどうか、および c89 や cc への -l l オペランドを通してだけアクセス可能かどうかは不定です ( lex ライブラリ ) 。
入力の字句を解析します。これは lex ユーティリティによって生成される主な関数です。 この関数は、入力の終わりに達するとゼロを返します。 その他の場合は、選択されたアクションによって決定された ゼロ以外の値 (トークン) を返します。
呼び出されると、次の入力文字列がいつ認識されるかを示します。 置き換えるのではなく、 yytext の現在の値に付加されます。これに合わせて yyleng の値が調整されます。
NULL で終わっている yytext 内の最初の n 文字を記憶し、残りの文字は読み取っていないものとします。これに合わせて yyleng の値が調整されます。
入力から次の文字を返します。ファイルが終わりのときはゼロを返します。 ストリームポインタ yyin から、おそらく中間バッファを介して入力を得ます。 そのためスキャニングの開始後に yyin の値を変更した場合の影響は未定義です。読み込まれた文字列は、 スキャナの入力ストリームからそのまま取り除かれます。
文字 c を入力に返します。次の式が一致するまで yytext と yyleng は未定義です。入力された文字より多い文字に対して unput を使用すると、結果は不定です。
以下の関数は -l l オペランドを通してアクセス可能な lex ライブラリ内にだけ出てきます。 そのためこれらの関数は移植性のあるアプリケーションによって再定義可能です。
ファイルの終わりで yylex によって呼び出されます。デフォルトの yywrap は 1 を返します。アプリケーションが yylex に別の入力ソースで処理を継続させたい場合、アプリケーションは関数 yywarp を組み込めます。 yywarp は別のファイルと外部変数 FILE *yyin を関連付け、ゼロの値を返します。
字句解析のために yylex を呼び出してから、終了します。 ユーザーコードにはアプリケーションに固有な動作を実行する main を組み込んだり、必要なら yylex を呼び出したりできます。
移植性のあるアプリケーションによって確実に再定義可能なのは libl.a の関数だけだという理由によって、上記の関数は 2 つのグループに分割されています。
lex によって生成される名前で、 input 、 unput 、 main を除くすべての外部およびスタティック名には、接頭辞 yy または YY が付きます。
lex 内のルール セクションではアクションのない ERE は受け付けられないことが、移植性のあるアプリケーションに警告されますが、 lex がエラーとして検出する必要はありません。 これはコンパイルまたは実行時エラーを引き起こすことがあります。
input の目的は、字句分析に関して、入力ストリームから文字を 取り出し破棄することです。コメントの先頭を検出したら、 コメント全体を破棄するという使い方が一般的です。
lex ユーティリティは、 lex ソースコードや生成された字句アナライザにおける 正規表現の扱いが完全には国際化されていません。 字句アナライザの実行時に、指定された環境に応じて lex ソース内の正規表現を解析することが理想とされますが、現在の lex テクノロジではこれは不可能です。さらに lex によって生成される字句アナライザの特徴は、 ロケール固有なことが多い入力言語の字句要件に 密接に結びついています ( たとえば、フランス語に使用するアナライザを作成しても、 自動的にその他の言語の処理に役立つことはありません ) 。
以下の例は、 Pascal に似た構文用の簡単なスキャナを実装する lex プログラムです。
%{ /* 以下の atof() を呼び出すのに必要 */ #include <math.h> /* 以下の printf()、fopen()、stdin を呼び出すのに必要 */ #include <stdio.h> %} DIGIT [0-9] ID [a-z][a-z0-9]* %% {DIGIT}+ { printf("An integer: %s (%d)¥n", yytext, atoi(yytext)); } {DIGIT}+"."{DIGIT}* { printf("A float: %s (%g)¥n", yytext, atof(yytext)); } if|then|begin|end|procedure|function { printf("A keyword: %s¥n", yytext); } {ID} printf("An identifier: %s¥n", yytext); "+"|"-"|"*"|"/" printf("An operator: %s¥n", yytext); "{"[^}¥n]*"}" /* 1 行コメントを飛ばす */ ¥t¥n]+ /* 空白を読み飛ばすspace */ . printf("Unrecognized character: %s¥n", yytext); %% int main(int argc, char *argv[ ]) { ++argv, --argc; /* プログラム名をスキップする */ if (argc > 0) yyin = fopen(argv[0], "r"); else yyin = stdin; yylex(); } |
lex の実行に影響を与える環境変数 LC_COLLATE、 LC_CTYPE、 LC_MESSAGES、 NLSPATH についての詳細は、 environ(5) を参照してください。
次の属性については attributes(5) のマニュアルページを参照してください。
属性タイプ | 属性値 |
使用条件 | SUNWbtool |
yacc(1), attributes(5), environ(5), regex(5)
.l ファイルの yyback()、 yywrap()、 yylock() などのルーチンが外部 C 関数となる場合には、 C++ プログラムをコンパイルするコマンド行で __EXTERN_C__ マクロを定義する必要があります。以下に例を示します。
example% CC -D__EXTERN_C__ . . . file
名前 | 形式 | 機能説明 | オプション | オペランド | 出力 | 拡張機能説明 | 使用法 | 使用例 | 環境 | 終了ステータス | 属性 | 関連項目 | 注意事項