Provided by:
manpages-ja_0.5.0.0.20080615-1_all 
YACCス
flex の主な使用方法の一つは、 yacc
パーサジェネレータと共に使用することです。 yacc パーサは yylex()
と言う名前のルーチンを呼び、次の入力トークンを見付けるものとしています。
このルーチンは、次のトークンの型を返し、 関連する値をグローバルの
yylval に格納するものとされています。 flex を yacc と共に使うには、
yacc に -d オプションを指定して、 yacc の入力に現れる全ての %tokens
の定義を含む y.tab.h ファイルを生成させます。 このファイルは flex ス-
ャナにインクルードされます。 例えばトークンの一つが "TOK_NUMBER"
である場合、 スゥ礇覆琉貮分は次のようになっています:
%{
#include "y.tab.h"
%}
%%
[0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
ン
flex には以下のようなオプションがあります:
-b バックアップ情報を lex.backup に出力します。
このファイルには、ス-
ャナのバックアップ(backing-up)を必要とする状態と
それに対応する入力文字の一覧がリストされます。
ルールを追加することでバックアップ状態を取り除くこと がで-
ます。バックアップ状態が _-Cf または -CF
を指定すると、生成されたスゥ礇覆亮孫埖度が向上します( -p
フラグを見て下さい)。 ス-
ャナをぎりぎりまで最適化しようとしてるユーザのみが
このオプションに関係あります。 (後述の税輯慙△寮瓩鮓て下さい。)
-c 何もしません。POSIX 互換のために用意されています。
-d 生成されたスゥ礇覆 _yy_flex_debug が非ゼロの場合(デフォルト)、
パターンが認識されるたびに、スゥ礇覆麓,里茲Δ淵瓮奪察璽犬
_-f _-Cfr
と同等です (以下を参照)。
-h flex のオプションの要約からなる "ヘルプ" を _-? と --help とは -h と同じです。
-i _flex
の入力パターンに与えられる文字が大文字であるか小文字であるかは区別されず、
スゥ礇覆貌力される文字列は大文字小文字に関係なくマッチします。
マッチしたテゥ好 yytext では入力時の大文字小文字が保存されます
(大文字を小文字に変換したりしません)。
-l AT&T の lex の実装に対して最大限の互換世鮖たせます。これは
_-+, -f, -F, -Cf, -CF
と同時に使用でい泙擦鵝詳しくは、 後述の "Lex および POSIX
との非互換" の節を御覧下さい。 またこのオプションを使用すると、
YY_FLEX_LEX_COMPAT が生成されたスゥ礇覆量樵阿 #define
されます。
-n 何もしません。POSIX 互換のためにだけ用意されたオプションです。
-p 税従霾鵑鯢現爛┘蕁悉侘呂暴侘呂靴泙后 flex 入力ファイルの-
述のうち、 生成されるスゥ礇覆寮-
能低下の深刻な原因となる部分について、 コメントされます。
オプションを2回指定すると、より細かな税縦祺爾砲弔い討
コメントが出力されます。
REJECT ・ %option yylineno
・可変長右文脈(欠陥/バグの節で後述)は多大なる税修悗琉-
影響があります; yymore() の使用・ ^ オペレータ・ -I
フラグは小さな税修琉影響があります。
-s __
に出力する) が抑制されます。ルールにマッチしない入力が表れたと-
、スゥ礇覆 エラーで異常終了します。 ス-
ャナのルールの組に抜けが無いかを確認する場合に邑です。
-t lex.yy.c ではなく、標準出力にスゥ礇覆鮟颪出します。
-v 生成するスゥ礇覆瞭団Г陵很鵑 _flex に指示します。 ほとんどの特徴は通常の flex
ユーザには意味がありませんが、最初の行は flex
のバージョンを表示し( -V
で表示されるもと同じです)、次の行はデフォルトを含むス-
ャナ生成時のフラグです。
-w 警告メッセージを抑制します。
-B _-I の項を参照) ではなく _flex に指示します。 通常 -B
を使用するのは、スゥ礇覆鯊佻壇に使用しないことが _
時であり、 _-Cf もしくは -CF オプションを使用すべ-
です(後述)。 -B を自動的に設定します。
-F _(-f) とほぼ同じぐらい高速で、
ある種のパターンに対してはかなり小さく (ある種に対しては大い)
なります。 通常、次のように、パターンの組が "keywords"
とその対応 および "identifier" ルールからなる場合:
"case" return TOK_CASE;
"switch" return TOK_SWITCH;
...
"default" return TOK_DEFAULT;
[a-z]+ return TOK_ID;
この場合、完全テーブル表現を使用する方が良いです。 もし
"identifier" ルールからのみ表現され、 -
ーワードを検知するためにハッシュ表等を使用する場合は、 -F
を使用する方が良いです。
このオプションは -CFr と等価です (以下を参照)。 これは -+
オプションとは同時に指定でい泙擦鵝
-I flex に __
トークンを入力するまでそれは改行として認識されません。
大概の場合、次の行全体を入力することになります。
flex のスゥ礇覆離妊侫ルトは _-Cf や -CF
といったテーブル圧縮オプション(後述)使用時です。 高-
能追求時にはこれらのオプションを使用しているべい任垢里如
これらのオプションを使用していない場合には、 flex は実行時-
能を少し犠牲にして直観的な対話的な振舞いを取っているものとします。
-I オプションを -Cf や -CF と共に _
ことにも注意して下さい。 実際はこのオプションは不要です;
許される場合、デフォルトで邑になっています。
isatty() がスゥ礇覆瞭力に対して偽を返す場合、 -I
が指定されていた場合でも、flex はバッチモードへ戻ります。
なにがあっても対話モードを強制するには、 %option always-
interactive (後述のオプションを参照) を使用します。
スゥ礇覆鯊佻壇で _-B
(先述)を使用します。
-L flex に #line ディレクティブを lex.yy.c
中に生成しないように指示します。 デフォルトではこの #line
ディレクティブを生成するので、
アクションにおけるエラーメッセージは、オリジナルの flex
入力ファイル(
エラーが入力ファイルのコードに起因する場合)もしくは ファイル
lex.yy.c ( flex の誤り --
以下の電子メールアドレスに報告して下さい)
における正しい位置を与えます。
-T flex を __
に多量のメッセージを出力します。 このオプションは主に flex
をメンテナンスするために使われます。
-V バージョン番号を _--version は -V
と同じです。
-7 7 ビットのスゥ礇覆鮴言します。 すなわち、入力に 7
ビットの文字のみを使用することを意味します。 -7
を指定する利点は、 -8
オプション(後述)を指定して生成するテーブルの半分まで小さくなりうることです。
欠点は、入力に 8 ビット文字が含まれている時に、 ス-
ャナがハングもしくはクラッシュすることです。
しかしながら、 -Cf や -CF
といったテーブル圧縮オプション使用時にはテーブル圧縮の効果は少なく、
移植世著しく低下することに注意して下さい。 flex
のデフォルトの動作では、 -Cf や -CF, を指定しない限り 8
ビットスゥ礇覆鮴言します。 指定時には、 あなたのサイトが常に 8
ビットスゥ礇覆鮴言するように (USA
以外のサイトでは良くあります)していない場合には、 7 ビットス-
ャナを生成します。 flex が 7 ビットもしくは 8
ビットのいずれのスゥ礇覆鮴言するのかを 知りたい場合には、上述の
-v の出力のフラグの要約を調べて下さい。
-Cfe もしくは -CFe
(これらのテーブル圧縮オプションおよび等価クラスは後述)
を使用しても、flex はデフォルトで 8 ビットス-
ャナを生成することに 注意して下さい。 なぜなら、完全な 8
ビットテーブルは 7 ビットテーブルと比べても
たいして高価にはならないからです。
-8 8 ビットのスゥ礇覆鮴言するように flex に指示します。すなわち 8
ビット文字を解釈します。 圧縮オプション -Cf と -CF
使用時にのみ必要です。 なぜなら flex はデフォルトでは 8
ビットスゥ礇覆鮴言するからです。
flex のデフォルト動作と 7 ビットおよび 8 ビットスゥ礇覆
トレードオフに関しては、上 -7 の議論を見て下さい。
-+ C++ のスゥ礇淵ラスを生成します。 詳しくは C++ ス-
ャナの生成で後述します。
-C[aefFmr]
テーブル圧縮の程度と、 より一般的には小さいスゥ礇覆塙眤なス-
ャナとのトレードオフを指定します。
-Ca ("アライン") 生成されるスゥ礇覆離董璽屮襪蓮
メモリアクセスおよび計算のためにアラインされるため、より大-
なものになります。 RISC アー-
テクチャではロングワードのフェッチおよび操作は
ショートワードといったより小さな大-
さのものに対するものより効率的です。 場合によってはス-
ャナのテーブルサイズが通常の 2倍になることもあります。
-Ce _flex 入力中に数字が現れるのが文字クラス "[0-9]"
のみの場合、 数字 '0', '1', ..., '9'
は全て同じ等価クラスになります)。
多くの場合、等価クラスを用いることで最終的なテーブル/
オブジェクトファイルのサイズを劇的(平均して
1/2-1/5)に減らすことが出来ます。 また、その際の-
能コストは非常に低く抑えられます ( 1文字スゥ礇鵑垢襪瓦箸
1回の配列検索を行うだけです)。
-Cf _full) スゥ礇淵董璽屮襪鮴言することを指示します - flex
は、別の状態に関する類似した遷移関数をうまく利用するという、
テーブル圧縮手法を用いません。
-CF 別の高速スゥ礇壁集( -F フラグにて-
述)を用いることを指定します。 このオプションは -+
と同時に使用でい泙擦鵝
-Cm flex に _-Cr 生成されたス-
ャナは入力に対しては標準入出力ライブラリ(標準入出力)を _
します。 スゥ礇覆蓮 fread() や getc() ではなく、 read()
システムコールを使用します。 税讐善結果はシステムに依存します。
オプション -Cf もしくは -CF を使用していない場合には、
一般にこのオプションは税修鬚△泙蟆善しません。 -Cr
を指定すると、例えばスゥ礇覆鮴瀋蠅垢訌阿防現狷出力を使用して
yyin を読み取る等した場合奇妙な動作となり得ます
(標準入出力の入力バッファに以前読み込んだものを、ス-
ャナは読めません)。
-Cr は YY_INPUT を定義した場合意味がありません
(前述の生成されたスゥ礇覆鮖仮)。 ス-
ャナの呼出に先だって標準入力を使って yyin から読みだしていると-
には、予想外の振る舞いをすることがあります。
-C のみを指定したとい砲蓮▲好ャナはテーブル圧縮は行いますが、
等価クラスもメタ等価クラスも使いません。
オプション -Cf と -CF はオプション -Cm
を同時に指定しても意味をなしません -
なぜなら、テーブル圧縮が行われないとぅ瓮薪価クラス
は現れないからです。
それ以外のオプションは自由に組み合わせることが出来ます。
デフォルトの設定は -Cem です。このと flex
は等価クラスとメタ等価クラスを生成します。
この設定は最も高いテーブル圧縮を行います。 テーブルサイズの大-
さと実行の高速世魯肇譟璽疋フの関係にあり、 一般に
遅いが 小さい
-Cem
-Cm
-Ce
-C
-C{f,F}e
-C{f,F}
-C{f,F}a
速いが 大い
となります。 小さいテーブルのス-
ャナは通常生成もコンパイルも高速であるため、
通常の開発時は最大の圧縮を行うでしょう。
製品のスゥ礇覆任蓮 -Cfe が速度と大い気領匹ぅ丱薀鵐垢任后
-ooutput
lex.yy.c ではなくファイル output にスゥ礇覆鮟颪ように flex
に指示します。 -o と -t オプションを組み合わせると、 スゥ礇覆
_#line ディレクティブ( -L
にて上述)はファイル output を参照します。
-Pprefix
flex の使うデフォルトのプレフィックス yy の代わりに prefix
を使います。これはグローバル変数とファイル名に影響します。
例えば -Pfoo とすると、 yytext の名前は footext となります。
またデフォルトの出力ファイル名を lex.yy.c から lex.foo.c
に変えます。 影響を受ける名前の一覧です:
yy_create_buffer
yy_delete_buffer
yy_flex_debug
yy_init_buffer
yy_flush_buffer
yy_load_buffer_state
yy_switch_to_buffer
yyin
yyleng
yylex
yylineno
yyout
yyrestart
yytext
yywrap
(C++ スゥ礇併藩兒には yywrap と yyFlexLexer
だけが影響を受けます。) ス-
ャナの中では、グローバル変数および関数を
どちらの名前ででも参照でい泙;
外部的には修正した名前のみ持ちます。
このオプションを使用することにより、複数の flex
プログラムを同一の実行形式に容易にリンクすることが出来ます。
しかし、このオプションは yywrap() の名前をも変えますので、
独自の(適切に名前を付けた)ルーチンをスゥ礇覆里燭瓩僕儖佞垢襪、
%option noyywrap を使用して -ll とリンクする _
どれもデフォルトでは提供されません。
-Sskeleton_file
flex がスゥ礇覆鮃獣曚垢襪里忙箸Ε妊侫ルトの
スケルトンファイルに優先します。 flex
のメンテナンスや開発をする場合以外、このオプションは必要ありません。
flex は、flex のコマンドラインではなく、 スゥ礇併斗裕-
述中からオプションを制御する機構を提供します。 これはス-
ャナの最初の部分に %option ディレクティブを含めることで実現でい泙后
単一の %option ディレクティブにおいて複数のオプションを指定でぁ
また複数のディレクティブを flex
入力ファイルの最初の部分に置くことが出来ます。
ほとんどのオプションが単純な名前であり、 オプションとして前に "no"
という語(空白をはさみません)を付けて 意味を反転でい泙后 数値は flex
のフラグやその反転と等価です。
7bit -7 オプション
8bit -8 オプション
align -Ca オプション
backup -b オプション
batch -B オプション
c++ -+ オプション
caseful または
case-sensitive -i オプションの逆(デフォルト)
case-insensitive または
caseless -i オプション
debug -d オプション
default -s オプションの逆
ecs -Ce オプション
fast -F オプション
full -f オプション
interactive -I オプション
lex-compat -l オプション
meta-ecs -Cm オプション
perf-report -p オプション
read -Cr オプション
stdout -t オプション
verbose -v オプション
warn -w オプションの逆
(-w オプションには "%option nowarn" を使用して下さい)
array "%array" と等価
pointer "%pointer" と等価(デフォルト)
%option には、他では利用でい覆さ’修鯆鷆,垢襪發里發△蠅泙:
always-interactive
入力を常に "対話的" に扱うスゥ礇覆鮴言するように flex
に指示します。 通常、新たな入力ファイル毎にスゥ礇覆 isatty()
を呼び出し、スゥ礇覆瞭力元が対話的であり 1 度に 1
文字ずつ読むべい どうか判定しようとします。
一方このオプションを使用するとこの様な呼び出しは行いません。
main スゥ礇覆紡个掘 yylex() を呼び出すだけのデフォルトの main()
プログラムを提供するように指示します。 このオプションは noyywrap
(後述)も暗黙的に指示します。
never-interactive
入力を "対話的" とはしないスゥ礇覆鮴言するように flex
に指示します (これもまた isatty() を呼び出しません)。 これは
always-interactive の逆です。
stack 開始条件スタックの使用を邑にします(前述の開始条件を参照)。
stdinit
設定されている場合 (すなわち %option stdinit) yyin および yyout
を、 デフォルトの nil ではなく、 __
に設定します。 既存の lex プログラムには、 ANSI C
互換ではないものの、この動作に依存しているものがあります。 ANSI
C では __
がコンパイル時の定数である必要はありません。
yylineno
入力から読み取った現在の行番号をグローバル変数 yylineno
に保持するスゥ礇覆鮴言するように、 flex に指示します。
このオプションは %option lex-compat から暗黙的に指定されます。
yywrap セットされていない場合 (すなわち %option noyywrap) 、ス-
ャナはファイルの終りに際し yywrap() を呼ばず単にスゥ礇鵑垢戮-
ファイルがもう無いものとするようになります( ユーザが yyin
を新しいファイルを指すようにし、再度 yylex()
を呼び出すまでです)。
flex はルールアクションをスゥ礇鵑掘 REJECT と yymore()
の機能が使われているかどうかを調べます。 reject と yymore
のオプションを使用すると、
オプションで指定した通りにこの判定に優先します。
オプションの指定は、セットして機能を使用していることを示す(例えば
%option reject)
、もしくはアンセットして機能を使用していないことを示す(例えば %option
noyymore) ものとします。
次のオプションは文字列の値を取り、'=' で区切ります:
%option outfile="ABC"
これは -oABC と同じであり、
%option prefix="XYZ"
は -PXYZ と同じです。 最後に、
%option yyclass="foo"
は C++ スゥ礇弊言時のみ邑( -+ オプション)です。これは flex に対して、
foo が yyFlexLexer のサブクラスであることを知らせますので、 flex
はアクションを yyFlexLexer::yylex() ではなく foo::yylex()
のメンバ関数とします。 また、( yyFlexLexer::LexerError()
を起動することにより)呼び出すと実行時エラーを除去する
yyFlexLexer::yylex() メンバ関数を生成します。 詳細は後述の C++ ス-
ャナの生成を見て下さい。
生成されたスゥ礇覆ら不要なルーチンを除い燭 lint 純正主義者のために
多くのオプションが用意されています。 以下をアンセットすると(例えば
%option nounput )、対応するルーチンは生成されるスゥ礇覆ら除かれます:
input, unput
yy_push_state, yy_pop_state, yy_top_state
yy_scan_buffer, yy_scan_bytes, yy_scan_string
( yy_push_state() 等は %option stack を使用しない場合には現れません)。
連
flex の主なデザインゴールは高税修淵好ャナを生成することです。
多くのルールセットを良く扱うことで最適化されます。 既に概説した -C
オプション使用によるテーブル圧縮に起因する速度への影響の他に、 税修魄-
化させる多くのオプション/アクションがあります。
それらを高価なものから安価なものへと並べます:
REJECT
%option yylineno
自由長の右文脈(trailing context)
バックアップが必要なパターンの組
%array
%option interactive
%option always-interactive
'^' 行頭オペレータ
yymore()
最初の 3 つは非常に高価であり、最後の 2 つは非常に安価です。 unput()
は潜在的に非常に大-
な仕事をするルーチン呼び出しとして実装されているのに対し、 yyless()
は非常に安価なマクロです; ですからスゥ礇鵑靴人省なテ-
ストを戻すだけの場合には yyless() を使って下さい。
税修重要な場合には、出来うる限りの努力でもって REJECT を避けて下さい。
これは特に高価なオプションです。
バックアップを取り除くと、乱雑になり、 ひどく苦労して複雑なス-
ャナを作ることになります。 実際的には -b フラグを指定して lex.backup
ファイルを生成することから始めます。例えば、入力
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
に対しては、ファイルは次のようになります:
State #6 is non-accepting -
associated rule line numbers:
2 3
out-transitions: [ o ]
jam-transitions: EOF [ \001-n p-\177 ]
State #8 is non-accepting -
associated rule line numbers:
3
out-transitions: [ a ]
jam-transitions: EOF [ \001-` b-\177 ]
State #9 is non-accepting -
associated rule line numbers:
3
out-transitions: [ r ]
jam-transitions: EOF [ \001-q s-\177 ]
Compressed tables always back up.
最初の数行は、 'o' に遷移でい襪他の文字には遷移でい覆ぞ態があり、
その状態では現在スゥ礇鵑気譴織謄ストは他のルールにはマッチしないことを
表します。 この状態が発生したのは、 入力ファイルの行 2, 3
のルールにマッチしようとした時です。 スゥ礇覆この様な状態にあり 'o'
以外の文字を読んだ場合には、
マッチするルールを探すためのバックアップが必要となります。
少し考えれば、これは "fo"
を見た時にある状態に違いないことが分かるでしょう。 この様な時、'o'
以外のものが現れると、 スゥ礇覆蓮単に 'f'
にマッチする(デフォルトルール)ところまで 戻り(バックアップし)ます。
状態 #8 に関係するコメントは、 "foob" がス-
ャンされた時に問題があることを表しています。 実際、'a'
以外の文字に出会うと、スゥ礇覆 "foo" を受理するところまで戻ります。
同様に状態 #9 に関係するコメントは、 "fooba" がスゥ礇鵑気 'r'
が続かない場合に関係します。
最後のコメントが通知するのは、 -Cf や -CF を使っているのでなければ
バックアップを取り除こうと努力することは無意味であることです。
なぜなら、圧縮されたスゥ礇覆紡个靴討修里茲Δ覆海箸鬚靴討癲 -
能上の利益は無いからです。
バックアップを取り除くためには "エラー" ルールを追加します:
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
fooba |
foob |
fo {
/* false alarm, not really a keyword */
return TOK_ID;
}
ァ璽錙璽匹離螢好箸らバックアップを取り除くには、"全てを捕まえる"
ルールを使用することが出来ます:
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
[a-z]+ return TOK_ID;
通常、適切な時にはこれは一番良い解決策です。
バックアップメッセージはカスケードすることが多いです。
複雑なルールの組では、数百ものメッセージを得るのは普通のことです。
しかし、これを解析すれば、バックアップを除去するためには
大抵の場合数ダースのルールにだけ関係あることが分かるでしょう
(しかし、間違えることが多く、誤ったルールが偶然-
効なトークンにマッチし得ます。 祥茲 flex の機能では、
自動的にバックアップを除去するルールを追加するようになるかも知れません)。
バックアップを除去することにより利益があるのは、 _
バックアップを除去した時だけということを覚えておくことは重要です。
たった一つを残しても何も得ることが出来ません。
_REJECT
とほぼ同じだけの(すなわち相当の)税塾化となります。
そのため次のようなルール:
%%
mouse|rat/(cat|dog) run();
は次のように書くか:
%%
mouse/cat|dog run();
rat/cat|dog run();
次のように書いた方が良いです:
%%
mouse|rat/cat run();
mouse|rat/dog run();
特別な '|' アクションは助けにはなり _yytext)
をほとんどしないからです。 C コメントのスゥ礇覆鮖廚そ个靴泙靴腓:
%x comment
%%
int line_num = 1;
"/*" BEGIN(comment);
<comment>[^*\n]*
<comment>"*"+[^*/\n]*
<comment>\n ++line_num;
<comment>"*"+"/" BEGIN(INITIAL);
次のように書くと高速になります:
%x comment
%%
int line_num = 1;
"/*" BEGIN(comment);
<comment>[^*\n]*
<comment>[^*\n]*\n ++line_num;
<comment>"*"+[^*/\n]*
<comment>"*"+[^*/\n]*\n ++line_num;
<comment>"*"+"/" BEGIN(INITIAL);
今度は、改行毎に別のアクションの処理を行うのではなく、
改行認識はルール間で "分散" され、 可能な限り長いテ-
ストにマッチするようになっています。 ルールの ___
入力ストリームはレターと改行だけであることを知っていますが、 flex
はこれが分からないため、 トークン "auto" などをス-
ャンした次の文字が改行でもレターでもない場合には
バックアップが必要であると考えます。 以前は "auto"
ルールに適合しそれで終りでしたが、 今は "auto" ルールは無く、"auto\n"
ルールだけがあります。 バックアップの可能世鮟去するためには、
最後の改行以外のルールを二重化するか、
そのような入力に出くわさないので分類は不要と分かっているため、
改行を導入しないもう一つの全てを捕まえるルールを導入することが出来ます:
%%
asm\n |
auto\n |
break\n |
... etc ...
volatile\n |
while\n /* it's a keyword */
[a-z]+\n |
[a-z]+ |
.|\n /* it's not a keyword */
-Cf を付けてコンパイルすると、実際問題上 flex
で得られるほぼ最速になります。
最後の注意事項: flex は NUL にマッチする時には遅く、トークンが複数の
NUL を含む時には特に遅いです。 テゥ好箸しばしば NUL
を含むものと予想される場合には、テゥ好箸 _
部分とマッチするようにルールを書くべい任后
もう一つの税修亡悗垢觝能注意事項:
入力のマッチ方法の節で既に示したように、 大い淵函璽ンを納めるために
yytext のサイズを動的に変更すると処理が遅くなります。
なぜなら、(巨大な)トークンを再度先頭からス-
ャンしなおさねばならないからです。 税修重要な場合、 テゥ好箸 "大い"
部分にマッチさせるべい任垢 "巨大な" 部分にマッチさせる べ-
ではありません。 両者の堺目は 8K 文字/トークンです。
C++成
flex は 2 通りの C++ スゥ礇弊言方法を提供します。 最初の方法は flex
が生成したスゥ礇覆鮹韻 C コンパイラではなく C++ コンパイラで
コンパイルするというものです。
この場合コンパイルエラーには出会わないはずです
(見付けた場合には作者の節で後述する電子メールアドレスに報告して下さい)。
この場合ルールにおいて C コードではなく C++
コードを書くことが出来ます。 スゥ礇覆離妊侫ルトの入力元は yyin
のままであり、 デフォルトのエコー先は yyout
のままであることに注意して下さい。 どちらも FILE *
変数のままであり、C++ streams ではないです。
flex に C++ スゥ礇淵ラスを生成させることも出来ます。 -+
オプションを指定する(もしくは等価的に %option c++
を使う)とこのように実行され、 flex の実行形式名が '+'
で終っている場合には自動的に指定されます。 このオプションを指定すると
flex が生成するスゥ礇覆離妊侫ルトはファイル lex.yy.cc となり lex.yy.c
ではありません。 生成されたスゥ礇覆 2 つの C++
クラスとのインタフェースを定義するヘッダファイル FlexLexer.h
をインクルードします。
最初のクラス FlexLexer は一般的なス-
ャナクラスを定義する抽象基盤クラスを提供します。
以下のメンバ関数を提供します:
const char* YYText()
最後にマッチしたテゥ好箸鯤屬靴泙后 yytext と等価です。
int YYLeng()
最後にマッチしたトークンの長さを返します。 yyleng と等価です。
int lineno() const
現在の入力の行番号( %option yylineno 参照)もしくは %option
yylineno を使用していない場合には 1 を返します。
void set_debug( int flag )
スゥ礇覆離妊丱奪哀侫薀阿鬟札奪箸靴泙后 yy_flex_debug
に代入するのと同じです(オプションの節で前述)。 スゥ礇聞獣杙に
%option debug
を使用してデバッグ情報を組み込む必要があることに注意して下さい。
int debug() const
現在のデバッグフラグの設定を返します。
また次のものと等価なメンバ関数も提供されます yy_switch_to_buffer(),
yy_create_buffer() (最初の引数は istream* オブジェクトポインタであり
FILE* ではありません), yy_flush_buffer(), yy_delete_buffer(),
yyrestart() (これもまた最初の引数は istream*
オブジェクトポインタです)。
2 番目のクラスは FlexLexer.h で定義される yyFlexLexer であり、
FlexLexer から導出したものです。 以下の追加のメンバ関数を定義します:
yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
与えられた入出力ストリームを使う yyFlexLexer
オブジェクトを構築します。
指定しない場合にはそれぞれストリームのデフォルト cin と cout
になります。
virtual int yylex()
これは yylex() が通常の flex ス-
ャナに対して行ったのと同様の役割を担います:
ルールのアクションが値を返すまで、 入力ストリームをス-
ャンし、トークンを消費します。 yyFlexLexer からサブクラス S
を導出し yylex() から S
のメンバ関数および変数をアクセスしたい場合、 %option yyclass="S"
を指定して yyFlexLexer ではなくサブクラスを使用することを flex
に知らせる必要があります。 この場合 yyFlexLexer::yylex()
を生成するのではなく、 flex は S::yylex()
(および呼び出されたなら yyFlexLexer::LexerError()
を呼び出すダミーの yyFlexLexer::yylex() も)を生成します。
virtual void switch_streams(istream* new_in = 0,
ostream* new_out = 0) yyin を new_in (非ニルの場合) に再割当し、
yyout を new_out (同様)に再割当します。 yyin
が再割当された場合には以前の入力バッファは消去されます。
int yylex( istream* new_in, ostream* new_out = 0 )
まず入力ストリームを switch_streams( new_in, new_out )
を使用して切り替え、 yylex() の値を返します。
さらに、 yyFlexLexer は次のプロテクトされた仮想関数を定義します。 ス-
ャナにあわせてこれらを導出クラスにおいて再定義出来ます:
virtual int LexerInput( char* buf, int max_size )
最大 max_size 文字を buf に読み込み、読めた文字数を返します。
入力の終りを示すには 0 文字を返します。"対話的" スゥ礇( -B と
-I フラグを参照)はマクロ YY_INTERACTIVE
を定義することに注意して下さい。 LexerInput() を再定義し、
対話的な入力元をスゥ礇鵑垢覯椎柔があるかどうかに依存して
異なるアクションが必要となる場合、
この名前が存在するかどうかのテストは #ifdef にて可能です。
virtual void LexerOutput( const char* buf, int size )
size 文字をバッファ buf から書そ个靴泙后 スゥ礇覆離襦璽襪 NUL
を含むテゥ好箸縫泪奪漸椎修幣豺隋 NUL
終端されているこのバッファは "内部に" NUL
を含んでいても構いません。
virtual void LexerError( const char* msg )
致命的なエラーメッセージを報告します。
デフォルトのこの関数はメッセージをストリーム cerr に書-
、終了します。
yyFlexLexer オブジェクトは _yyFlexLexer
クラスの複数のインスタンスを具体化可能であり、 複数の C++ ス-
ャナクラスを組み合わせ上 -P
オプションを使用することで同一のプログラムで使用可能です。
最後に %array 機能は C++ スゥ礇淵ラスでは使用で-
ないことに注意して下さい; %pointer
を使用しなければなりません(デフォルト)。
単純な C++ スゥ礇覆領磴魄焚爾房┐靴泙:
// An example of using the flex C++ scanner class.
%{
int mylineno = 0;
%}
string \"[^\n"]+\"
ws [ \t]+
alpha [A-Za-z]
dig [0-9]
name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
number {num1}|{num2}
%%
{ws} /* skip blanks and tabs */
"/*" {
int c;
while((c = yyinput()) != 0)
{
if(c == '\n')
++mylineno;
else if(c == '*')
{
if((c = yyinput()) == '/')
break;
else
unput(c);
}
}
}
{number} cout << "number " << YYText() << '\n';
\n mylineno++;
{name} cout << "name " << YYText() << '\n';
{string} cout << "string " << YYText() << '\n';
%%
int main( int /* argc */, char** /* argv */ )
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
複数の(異なった)字句解析クラスを生成したい場合、 -P フラグ (もしくは
prefix= オプション) を使用して各 yyFlexLexer を xxFlexLexer
等の別の名前にします。 次に字句解析クラスのソースごとに <FlexLexer.h>
をインクルードします。 以下のように yyFlexLexer をリネームします:
#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#include <FlexLexer.h>
#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#include <FlexLexer.h>
これはあるスゥ礇覆紡个 %option prefix="xx" を使用しもう一方に対し
%option prefix="zz" を使用した場合です。
重要: 現在のスゥ礇鵐ラスの形式は _
であり、メジャーリリースが変わると大い変更される可能世あります。
LEX POSIX浩
flex は AT&T Unix の lex ツールのリライトですが(2
つの実装はいかなるコードも共佑靴泙擦)、 いくばくかの拡張と非互換-
を持っており、 どちらの実装でも受理可能なスゥ礇覆鮟颪たい方は
これを意識しなければなりません。 flex は POSIX lex
仕様に完全合致しますが、例外は %pointer (デフォルト)使用と unput()
呼び出しにより yytext の内容を破壊することであり、これは POSIX
仕様に反します。
この節では、 flex と AT&T lex と POSIX 仕様との間の全ての既知の非互換-
を扱います。
flex の -l オプションはオリジナルの AT&T lex 実装との最大の互換世鰺-
効にしますが、 生成されたスゥ礇覆寮能は大い低下します。 -l
オプションを使用しても発生しうる非互換世聾紊能劼戮泙后
flex は以下の例外を除 lex と完全互換です:
- ドゥ絅瓮鵐箸傍載されていない lex スゥ礇米睇瑤諒竸 yylineno は
-l もしくは %option yylineno を使用しないとサポートされません。
yylineno はス-
ャナ毎(単一のグローバル変数)ではなく、バッファ毎に管理されるべ-
です。
yylineno は POSIX 仕様ではありません。
- input() ルーチンは再定義でい泙擦鵑、
ルールにマッチしたものに後続する文字を読むために呼ばれえます。
input() がファイルの終りに到達すると、通常の yywrap()
処理は終了します。``実際の'' ファイルの終りは EOF
として返されます。
実際には入力は YY_INPUT マクロを定義することにより制御されます。
input() を再定義でい覆い箸い flex の制限は、最初に yyin
を設定する以外のスゥ礇米力制御方法を単に規定していないという、
POSIX 仕様と合致します。
- unput() ルーチンは再定義でい泙擦鵝この制限は POSIX
に合致しています。
- flex スゥ礇覆 lex ス-
ャナとは異なりリエントラントではありません。 実際、対話的なス-
ャナにおいて、 割り込みハンドラにてロングジャンプを用いてス-
ャナから脱出し、 その後ス-
ャナを再度呼び出す場合、以下のメッセージを得るでしょう:
fatal flex scanner internal error--end of buffer missed
スゥ礇覆忘禿抛るためには、まず以下のようにして下さい
yyrestart( yyin );
この呼び出しにより入力バッファは捨てられることに注意して下さい;
通常これは対話的スゥ礇覆任鰐簑蠅任呂△蠅泙擦鵝
また、C++ スゥ礇淵ラスはリエントラント _output() はサポートされていません。 ECHO
マクロからの出力はファイルポインタ yyout (デフォルトでは
_output() は POSIX 仕様にはありません。
- lex は排他的開始条件 (%x) をサポートしませんが、これは POSIX
仕様にあります。
- 定義を展開する時、 flex では括弧で括ります。 lex では以下は:
NAME [A-Z][A-Z0-9]*
%%
foo{NAME}? printf( "Found it\n" );
%%
文字列 "foo" にはマッチしません。
なぜなら展開されたマクロはルール "foo[A-Z][A-Z0-9]*?"
と等価になり、 優先度にて `?' は "[A-Z0-9]*" と結び付い泙后
flex ではルールが展開されると "foo([A-Z][A-Z0-9]*)?" となり、
文字列 "foo" がマッチします。
^ で始まるか $ で終る定義は、展開時に括弧で括らず、
これらのオペレータが定義において特別な意味を失わないようにすることに
注意して下さい。 しかし <s>, /, <<EOF>> オペレータは flex
の定義では使用でい泙擦鵝
-l を使用すると、 lex の振舞いと同じく定義を括弧で括りません。
POSIX 仕様では、定義を括弧で括ります。
- lex の実装によっては、 ルールのパターンの右側に空白がある場合、
ルールのアクションを別の行から始めることを許します:
%%
foo|bar<space here>
{ foobar_action(); }
flex はこの機能をサポートしません。
- lex の %r (Ratfor ス-
ャナの生成)オプションはサポートされていません。 これは POSIX
仕様には含まれません。
- スゥ礇覆 %array を使用して構築したのではない限り、 unput()
呼び出し後には、次のトークンにマッチするまで yytext
は未定義です。 これは lex にも POSIX 仕様にも当てはまりません。
-l オプションを指定するとこの非互換世鮗茲蟒い泙后
- {} (数値範囲)オペレータの優先度が異なります。 lex は "abc{1,3}"
を "1 度か 2 度か 3 度の 'abc' にマッチ" と解釈しますが、 flex
は "'ab' に 1 度か 2 度か 3 度の 'c' が続くものにマッチ"
と解釈します。 後者が POSIX 仕様に合致します。
- ^ オペレータの優先度が異なります。 lex は "^foo|bar" を "行頭の
'foo' か任意位置の 'bar' にマッチ" と解釈しますが、 flex は
"行頭の 'foo' か 'bar' にマッチ" と解釈します。 後者が POSIX
仕様に合致します。
- lex でサポートされている %a 等の特別なテーブルサイズの宣言は
flex スゥ礇覆任鷲塒廚任; flex はこれらを無視します。
- flex と lex のどちらでもスゥ礇覆鮖藩儔椎修暴颪韻襪茲Δ法
FLEX_SCANNER という名前を定義します。 スゥ礇覆鮴言した flex
のバージョンを表す YY_FLEX_MAJOR_VERSION と
YY_FLEX_MINOR_VERSION を、スゥ礇覆牢泙澆泙 (例えば 2.5
リリースではこれらはそれぞれ 2 と 5 になります)。
以下の flex の機能は lex および POSIX 仕様には含まれません:
C++ スゥ礇
%option
開始条件スコープ
開始条件スタック
対話的/非対話的スゥ礇
yy_scan_string() 等
yyterminate()
yy_set_interactive()
yy_set_bol()
YY_AT_BOL()
<<EOF>>
<*>
YY_DECL
YY_START
YY_USER_ACTION
YY_USER_INIT
#line ディレクティブ
アクションの周りの %{}
単一行における複数のアクション
さらにほぼ全ての flex フラグです。 リストの最後の機能の意味は、 flex
では複数のアクションをセミコロンで区切って同一行に欺匆椎修任垢、 lex
では次の
foo handle_foo(); ++num_foos_seen;
は (驚くべい海箸) 次のように切り詰められるということです。
foo handle_foo();
flex はアクションを切り詰めません。
ブレースで括られないアクションは単純に行末で終了します。
断
warning, rule cannot be matched 常に同じテ-
ストにマッチするルールが前にあるので、
与えられたルールがマッチしません。 例えば以下の "foo" は
"全てを捕まえる" ルールの後ろにありますので 決してマッチしません:
[a-z]+ got_identifier();
foo got_foo();
スゥ礇蔽罎 REJECT を使用するとこの警告を抑制します。
warning, -s option given but default rule can be matched
(おそらくある特定の開始条件のもとでは) デフォルトルール
(任意の一文字にマッチする) しか特定の入力に
対してはマッチしないことがあります。 -s
を指定しているので、おそらくそうなりません。
reject_used_but_not_detected undefined あるいは
yymore_used_but_not_detected undefined - これらのエラーは
コンパイル時に起い泙后スゥ礇覆 REJECT もしくは yymore()
を使っていますが flex がそのことに気づかなかったということです。
つまり、 flex は最初の 2 つの部分を探しても
これらのアクションの出現を見つけられなかったのですが、
実際には何らかの方法 (例えば #include ファイルを介して)でこれらが-
述されていた、ということです。 %option reject か %option yymore
を使用して、flex にこれらの機能を実際に使用していることを教えて下さい。
flex scanner jammed - -s でコンパイルされたス-
ャナが、どのルールにもマッチしない 入力文字列に遭遇しました。
内部的な問題に起因してこのエラーが起こることもあります。
token too large, exceeds YYLMAX - スゥ礇覆 %array
を使っている場合に、あるルールが定数 YYLMAX (デフォルトで 8K バイト)
より大い癖源列とマッチしました。 flex の入力ファイルの定義部で YYLMAX
を #define することで値を大いでい泙后
scanner requires -8 flag to use the character 'x' - スゥ礇覆竜述に 8
ビットの文字 'x' を識別する部分があり、 -Cf もしくは -CF
のテーブル圧縮オプションのためにデフォルトの 7 ビットになっている
にもかかわらず、 -8 オプションをつけていないということです。 詳細は -7
フラグのオプションの議論を参照して下さい。
flex scanner push-back overflow - unput() でテ-
ストを戻しすぎたため、スゥ礇覆離丱奪侫, 戻したテゥ好箸噺愁函璽ンを
yytext に保てません。 この場合、理想的にはスゥ礇覆動的にバッファの大-
さを変えるべい任垢、 現在のところそうなってはいません。
input buffer overflow, can't enlarge buffer because scanner uses REJECT
- スゥ礇覆枠鷯錣紡腓なトークンのマッチを調べていて、入力バッファを
拡張する必要が起い泙靴拭しかしながら、バッファの拡張は REJECT
を使うスゥ礇覆任脇い泙擦鵝
fatal flex scanner internal error--end of buffer missed - ス-
ャナが使用しているフレームから(を越えて)ロングジャンプした後、 再度ス-
ャナに入った場合に起こります。 再度スゥ礇覆貌る前に:
yyrestart( yyin );
を使うか、前述のように C++ スゥ礇淵ラスを使用するようにして下さい。
too many start conditions in <> construct! -
存在するより多くの開始条件を <> 中に戯椶靴泙靴 (少なくとも一つを二度-
載しました)。
ル
-ll スゥ礇覆リンクしなければならないライブラリ。
lex.yy.c
生成されたスゥ礇(システムによっては lexyy.c
という名前になります)。
lex.yy.cc
-+ を使った時に作成された C++ スゥ礇淵ラス。
<FlexLexer.h>
C++ スゥ礇淵戞璽好ラス FlexLexer とその導出クラス yyFlexLexer
を定義するヘッダファイル。
flex.skl
スケルトンスゥ礇福 このファイルは flex の実行時ではなく、flex
を構築する時のみ利用されます。
lex.backup
-b フラグ用のバックアップ情報(システムによっては lex.bck
という名前になります)。
/グ
右文脈(trailing context)パターンの中には、正しくマッチせず
警告メッセージ ("dangerous trailing context") を出すものがあります。
これらのパターンは、 ルールの最初の部分が
2番目の頭の部分とマッチするようなものです。 例えば "zx*/xy*"
の場合、'x*' は右文脈の頭の 'x' とマッチします。 (POSIX
ドラフトではそのようなパターンにマッチするテゥ好箸
未定義であると述べていることに注意して下さい。)
右文脈の中には、実際には固定長であるのにそうとは解釈されないものがあり、
上に述べた税修猟祺爾起こります。 特に、 '|' や {n} (例えば "foo{3}")
は常に可変長であると解釈されます。
右文脈と特別なアクション '|' を組み合わせると _
右文脈がよりコストのかかる _
右文脈となります。例えば、次のようなものです:
%%
abc |
xyz/def
%array もしくは -l オプションを指定しない場合、 unput() を使うと yytext
と yyleng を破壊します。
NUL のパターンマッチングは他の文字の比較よりかなり遅くなっています。
入力バッファの動的な大い気虜督汗阿六間がかかります。これは現トークン
(一般に巨大)までのマッチした全テゥ好箸虜謄好ャンを伴うためです。
入力のバッファリングと先読みのため、 <stdio.h> ルーチンと
混合して使うことが出来ません。例えば、 getchar() と flex
のルールはうまく行い泙擦鵝B紊錣蠅 input() を使って下さい。
-v オプションで表示される全テーブルエントリには、
どのルールがマッチしたのかを決定するのに必要なテーブルエントリ数が
含まれていません。エントリの数はスゥ礇覆 REJECT を使っていないとい砲
DFA 状態数に等しく、 使っているとい砲 DFA 状態数よりいくらか大-
くなります。
REJECT がオプション -f もしくは -F とともに使えません。
flex の内部アルゴリズムについてのドゥ絅瓮鵐箸必要です。
目
lex(1), yacc(1), sed(1), awk(1)
John Levine, Tony Mason, and Doug Brown, Lex & Yacc, O'Reilly and
Associates. 第 2 版を入手すること。
M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator
Alfred Aho, Ravi Sethi and Jeffrey Ullman, Compilers: Principles,
Techniques and Tools, Addison-Wesley (1986). flex
で使用しているパターンマッチング技法を解説している(決定瀬ートマトン)。
者
Vern Paxson が多くのアイディアとインスピレーションを得る助けを Van
Jacobson から受けました。 オリジナルバージョンは Jef Poskanzer
が作成しました。 高速テーブル表現は Van Jacobson
のデザインの部分実装です。 この実装は Kevin Gong と Vern Paxson
が行いました。
多くの flex ベータテスタ、フィードバッカ、コントリビュータ、特に
Francois Pinard, Casey Leedom, Robert Abramovitz, Stan Adermann, Terry
Allen, David Barker-Plummer, John Basrai, Neal Becker, Nelson H.F.
Beebe, benson@odi.com, Karl Berry, Peter A. Bigot, Simon Blanchard,
Keith Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher,
Brian Clapper, J.T. Conklin, Jason Coughlin, Bill Cox, Nick Cropper,
Dave Curtis, Scott David Daniels, Chris G. Demetriou, Theo Deraadt,
Mike Donahue, Chuck Doucette, Tom Epperly, Leo Eskin, Chris Faylor,
Chris Flatters, Jon Forrest, Jeffrey Friedl, Joe Gayda, Kaveh R. Ghazi,
Wolfgang Glunz, Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer
Griebel, Jan Hajic, Charles Hemphill, NORO Hideo, Jarkko Hietaniemi,
Scott Hofmann, Jeff Honig, Dana Hudes, Eric Hughes, John Interrante,
Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,
Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane, Amir
Katz, ken@ken.hilco.com, Kevin B. Kenny, Steve Kirsch, Winfried Koenig,
Marq Kole, Ronald Lamprecht, Greg Lee, Rohan Lenard, Craig Leres, John
Levine, Steve Liddle, David Loffredo, Mike Long, Mohamed el Lozy, Brian
Madsen, Malte, Joe Marshall, Bengt Martensson, Chris Metcalf, Luke
Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum, G.T. Nicol,
Landon Noll, James Nordby, Marc Nozell, Richard Ohnemus, Karsten
Pahnke, Sven Panne, Roland Pesch, Walter Pelissero, Gaumond Pierre,
Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha, Frederic
Raimbault, Pat Rankin, Rick Richardson, Kevin Rodgers, Kai Uwe Rommel,
Jim Roskind, Alberto Santini, Andreas Scherer, Darrell Schiebel, Raf
Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas Schwab, Larry
Schwimmer, Alex Siegel, Eckehard Stolz, Jan-Erik Strvmquist, Mike
Stump, Paul Stuart, Dave Tallman, Ian Lance Taylor, Chris Thewalt,
Richard M. Timoney, Jodi Tsai, Paul Tuinenga, Gary Weik, Frank Whaley,
Gerhard Wilhelms, Kent Williams, Ken Yap, Ron Zellar, Nathan Zelle,
David Zuhn, および私の最低のメールアーカイブ能力から滑り落ちた方々、
それらの方々の協力にも同様に感謝します。
Keith Bostic, Jon Forrest, Noah Friedman, John Gilmore, Craig Leres,
John Levine, Bob Mulcahy, G.T. Nicol, Francois Pinard, Rich Salz,
Richard Stallman には多くの悩みの分散に関して感謝します。
Esmond Pitt と Earle Horton には 8 ビット文字サポートに関して; Benson
Margulies と Fred Burke には C++ サポートに関して; Kent Williams と Tom
Epperly には C++ クラスサポートに関して; Ove Ewerlid には NUL
のサポートに関して; Eric Hughes
には複数バッファのサポートに関して、それぞれ感謝します。
この作品は当初、私が CA Berkeley の Lawrence Berkeley Laboratory
における Real Time Systems Group にいた時に作成されました。
私に協力してくれた方々に感謝します。
コメントは vern@ee.lbl.gov に送って下さい。