これは、Ubuntu Online、Fedora Online、Windows オンライン エミュレーター、MAC OS オンライン エミュレーターなど、複数の無料オンライン ワークステーションのいずれかを使用して、OnWorks 無料ホスティング プロバイダーで実行できるコマンド freebsd-lex です。
プログラム:
NAME
flex, lex - 高速字句解析ジェネレータ
SYNOPSIS
フレックス [-bcdfhillnpstvwBFILTV78+? -C[aefFmr] -o出力 -プレフィックス 【スケルトン】 [ - ヘルプ - バージョン]
[ファイル名 ...]
概要
このマニュアルでは、 フレックス、 パターンマッチングを行うプログラムを生成するツール
テキスト上。 このマニュアルには、チュートリアルと参照セクションの両方が含まれています。
詳細説明
ツールの概要
簡単な例
入力ファイルのフォーマット
パターン
flex で使用される拡張正規表現
入力の一致方法
一致したものを決定するためのルール
パターンが一致したときに何をするかを指定する方法
生成されたスキャナー
flex が生成するスキャナーに関する詳細。
入力ソースの制御方法
開始条件
スキャナーにコンテキストを導入する
「ミニスキャナー」の管理
複数の入力バッファ
複数の入力ソースを操作する方法。 方法
ファイルではなく文字列からスキャンする
ファイルの終わりの規則
入力の終わりを一致させるための特別な規則
その他のマクロ
アクションで使用できるマクロの概要
ユーザーが利用できる値
アクションで使用できる値の要約
Yacc とのインターフェース
フレックススキャナーを yacc パーサーと一緒に接続する
オプション
flex コマンドライン オプション、および「%option」
指令
パフォーマンスに関する考慮事項
スキャナーをできるだけ速くする方法
C++ スキャナーの生成
C++ を生成するための (実験的な) 機能
スキャナ クラス
Lex および POSIX との非互換性
flex と AT&T lex および POSIX lex との違い
標準
診断法
flex (またはスキャナー) によって生成されるエラー メッセージ
その意味が明らかではない可能性があります)
flex が使用するファイル
欠陥/バグ
フレックスの既知の問題
も参照してください
その他のドキュメント、関連ツール
著者
連絡先情報が含まれています
DESCRIPTION
フレックス 生成するためのツールです スキャナー: テキストの字句パターンを認識するプログラム。
フレックス 指定された入力ファイル、またはファイル名が指定されていない場合はその標準入力を読み取ります
生成するスキャナーの説明。 説明は、通常のペアの形式です
と呼ばれる式と C コード ルール。 フレックス 出力として C ソース ファイルを生成し、 lex.yy.c、
ルーチンを定義する yylex()。 このファイルはコンパイルされ、 -NS ライブラリから
実行可能ファイルを生成します。 実行可能ファイルが実行されると、その入力の出現箇所が分析されます
正規表現の。 それが見つかると、対応する C コードが実行されます。
一部 SIMPLE 例
最初に、使用方法の趣向を理解するためのいくつかの簡単な例を示します フレックス。 以下 フレックス
入力は、文字列「username」に遭遇するたびに置き換えるスキャナーを指定します
ユーザーのログイン名でそれを:
%%
ユーザー名 printf( "%s", getlogin() );
デフォルトでは、 フレックス スキャナーは出力にコピーされるため、ネット
このスキャナーの効果は、入力ファイルを出力にコピーすることです。
「ユーザー名」が展開されました。 この入力では、ルールは XNUMX つだけです。 「ユーザー名」は パターン
そして「printf」は をご利用ください。 「%%」はルールの始まりを示します。
別の簡単な例を次に示します。
%{
int num_lines = 0、num_chars = 0;
%}
%%
\n ++num_lines; ++num_chars;
。 ++num_chars;
%%
メイン()
{
yylex();
printf( "行数 = %d、文字数 = %d\n",
num_lines、num_chars );
}
このスキャナは、入力の文字数と行数をカウントします (
カウントに関する最終レポート以外の出力は生成されません)。 最初の行は宣言します
XNUMX つのグローバル "num_lines" と "num_chars" は、内部の両方にアクセスできます。 yylex() または
メイン() XNUMX 番目の "%%" の後にルーチンが宣言されています。 XNUMX つのルールがあり、XNUMX つは一致します。
改行 ("\n") を追加し、行数と文字数の両方をインクリメントします。
改行以外の任意の文字に一致します (「.」正規表現で示されます)。
やや複雑な例:
/* おもちゃの Pascal に似た言語のスキャナー */
%{
/* 以下の atof() の呼び出しにこれが必要です */
#include
%}
数字 [0-9]
ID [az][a-z0-9]*
%%
{桁}+ {
printf( "整数: %s (%d)\n", yytext,
atoi( yytext ) );
}
{DIGIT}+"."{DIGIT}* {
printf( "フロート: %s (%g)\n", yytext,
atof( yytext ) );
}
if|then|begin|end|procedure|function {
printf( "キーワード: %s\n", yytext );
}
{ID} printf( "識別子: %s\n", yytext );
"+"|"-"|"*"|"/" printf( "演算子: %s\n", yytext );
"{"[^}\n]*"}" /* XNUMX 行のコメントを使い切る */
[ \t\n]+ /* 空白を使い切る */
. printf( "認識できない文字: %s\n", yytext );
%%
main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* プログラム名をスキップします */
もし (引数 > 0 )
yyin = fopen( argv[0], "r" );
ほかに
yyin = 標準入力;
yylex();
}
これは、Pascal のような言語用の単純なスキャナーの始まりです。 それは識別します
異なるタイプの トークン そして見たことを報告します。
この例の詳細については、以降のセクションで説明します。
FORMAT OF 、 入力 FILE
当学校区の フレックス 入力ファイルは、次の行で区切られた XNUMX つのセクションで構成されます。 %% 初期化:
定義
%%
ルール
%%
ユーザーコード
当学校区の 定義 セクションには単純な宣言が含まれています 名 を簡素化するための定義
スキャナの仕様、および宣言 start 条件は、 で説明されています
後のセクション。
名前の定義の形式は次のとおりです。
名前定義
「名前」は、文字またはアンダースコア ('_') で始まり、その後にゼロまたはゼロが続く単語です。
さらに文字、数字、「_」、または「-」(ダッシュ)。 定義は最初から始まると見なされます
名前に続き、行末まで続く非空白文字。 の
定義は、その後「{name}」を使用して参照できます。
"(意味)"。 例えば、
数字 [0-9]
ID [az][a-z0-9]*
"DIGIT" を XNUMX 桁の数字に一致する正規表現、"ID" を
文字の後に XNUMX 個以上の文字または数字が続く正規表現。 あ
その後の参照
{桁}+"."{桁}*
と同じです
([0-9])+"."([0-9])*
XNUMX つ以上の数字の後に「.」が続くものと一致します。 その後に XNUMX 個以上の数字が続きます。
当学校区の ルール のセクション フレックス 入力には、次の形式の一連の規則が含まれます。
パターンアクション
パターンはインデントされていない必要があり、アクションは同じ行で開始する必要があります。
パターンとアクションの詳細については、以下を参照してください。
最後に、ユーザー コード セクションは単純に次の場所にコピーされます。 lex.yy.c 逐語的に。 それはのために使用されます
スキャナを呼び出す、またはスキャナによって呼び出されるコンパニオン ルーチン。 このセクションの存在
オプションです。 欠落している場合は、XNUMX 番目の %% 入力ファイルの もスキップされる可能性があります。
定義とルールのセクションでは、 インデント テキストまたはで囲まれたテキスト %{ %} is
逐語的に出力にコピーしました (%{} は削除されています)。 %{} はインデントされていない必要があります
自分でオンラインで。
ルール セクションでは、最初のルールの前に表示されるインデントされたテキストまたは %{} テキストを使用できます
スキャン ルーチンに対してローカルな変数を宣言し、(宣言の後)
スキャンルーチンに入るたびに実行されるコード。 その他のインデントまたは
ルール セクションの %{} テキストは引き続き出力にコピーされますが、その意味は適切ではありません-
定義されており、コンパイル時のエラーが発生する可能性があります (この機能は、 POSIX
コンプライアンス; その他の機能については、以下を参照してください)。
定義セクション (ルール セクションではない) では、インデントされていないコメント (つまり、
"/*" で始まる行) も、次の "*/" までそのまま出力にコピーされます。
パターン
入力のパターンは、正規表現の拡張セットを使用して記述されます。 これらは
には次の値があります:
x 文字「x」に一致
. 改行を除く任意の文字 (バイト)
[xyz] 「文字クラス」; この場合、パターン
「x」、「y」、または「z」のいずれかに一致します
[abj-oZ] 範囲を持つ「文字クラス」。 マッチ
「a」、「b」、「j」から「o」までの任意の文字、
または「Z」
[^AZ] 「否定された文字クラス」、つまり任意の文字
でもクラスの人。 この場合、任意の
大文字以外の文字。
[^AZ\n] 大文字または
改行
r* XNUMX 個以上の r (r は任意の正規表現)
r+ XNUMX つ以上の r
? XNUMX 個または XNUMX 個の r (つまり、「オプションの r」)
r{2,5} XNUMX ~ XNUMX 個の r
r{2,} XNUMX つ以上の r
r{4} ちょうど 4 個の r
{name} 「名前」定義の展開
(上記を参照)
"[xyz]\"foo"
リテラル文字列: [xyz]"foo
\X X が 'a'、'b'、'f'、'n'、'r'、't'、または 'v' の場合、
次に \x の ANSI-C 解釈。
それ以外の場合は、リテラル 'X' (エスケープに使用
'*' などの演算子)
\0 NUL 文字 (ASCII コード 0)
\123 123 進値 XNUMX の文字
\x2a 2 進値 XNUMXa の文字
(r) r に一致します。 括弧は上書きするために使用されます
優先順位 (下記参照)
rs 正規表現 r の後に
正規表現; 「連結」と呼ばれる
r|s r または s のいずれか
r/s は r ですが、その後に s が続く場合に限ります。 の
s に一致するテキストは、決定時に含まれます
このルールが「最長一致」かどうか、
しかし、その後、前に入力に返されます
アクションが実行されます。 だからアクションだけ
r にマッチしたテキストを見る。 このタイプ
のパターンは、後続コンテキストと呼ばれます。」
(柔軟な r/s の組み合わせがいくつかあります。
正しく一致できません。 の注を参照してください
以下の欠陥/バグセクション
「危険な後続コンテキスト」。)
^r と r ですが、行頭のみです (つまり、
スキャンを開始した直後、または
改行がスキャンされました)。
r$ と r ですが、行末のみです (つまり、ちょうど
改行の前)。 「r/\n」と同等。
flex の「改行」の概念は正確に
C コンパイラが flex のコンパイルに使用したもの
'\n' を次のように解釈します。 特に、一部の DOS では
システムでは、\r をフィルターで除外する必要があります。
自分で入力するか、「r$」に r/\r\n を明示的に使用します。
r と r ですが、開始条件 s のみ (参照
開始条件については後述)
r
同じですが、開始条件 s1 のいずれかで、
s2、またはs3
<*>r は、排他的なものであっても、任意の開始条件で r です。
< > ファイルの終わり
< >
開始条件 s1 または s2 の場合のファイルの終わり
文字クラス内では、すべての正規表現演算子が特殊文字を失うことに注意してください。
エスケープ ('\') と文字クラス演算子、'-'、']'、および
クラスの先頭、'^'。
上記の正規表現は、優先度の高いものから順にグループ化されています。
上が優先順位、下が最低優先順位です。 グループ化されたものは等しい
優先。 例えば、
フー|バー*
と同じです。
(foo)|(ba(r*))
「*」演算子は連結よりも優先順位が高く、連結の方が優先されるため
代替 ('|') よりも。 したがって、このパターンは一致します どちら 文字列「フー」 or
文字列 "ba" の後に XNUMX 個以上の r が続きます。 「foo」または XNUMX 個以上の「bar」に一致させるには、次を使用します。
foo|(バー)*
XNUMX 個以上の "foo" または "bar" に一致するには:
(foo|バー)*
文字と文字の範囲に加えて、文字クラスには次のものも含めることができます
キャラクタークラス 式。 これらは中に囲まれた式です [: :] 区切り文字
(それ自体は、文字クラスの '[' と ']' の間に表示される必要があります。
要素は、文字クラス内でも発生する可能性があります)。 有効な式は次のとおりです。
[:alnum:] [:alpha:] [:blank:]
[:cntrl:] [:桁:] [:グラフ:]
[: lower:] [:print:] [:punct:]
[:space:] [:upper:] [:xdigit:]
これらの式はすべて、対応する文字セットと同等のものを指定します。
標準C はXXXです 関数。 例えば、 [:alnum:] これらの文字を指定します
isalnum() true を返します。つまり、任意のアルファベットまたは数字です。 一部のシステムは提供していません
isblank()、 したがって、フレックスは定義します [:空欄:] 空白またはタブとして。
たとえば、次の文字クラスはすべて同等です。
[[:alnum:]]
[[:アルファ:][:数字:]]
[[:アルファ:]0-9]
[a-zA-Z0-9]
スキャナが大文字と小文字を区別しない場合 ( -i フラグ)、その後 [:アッパー:] [:低い:]
に相当 [:アルファ:]。
パターンに関する注意事項:
- 上記の「[^AZ]」の例のような否定された文字クラス 意志 match a 改行
"\n" (または同等のエスケープ シーケンス) が明示的に文字の XNUMX つでない限り
否定された文字クラス (例: "[^AZ\n]") に存在します。 これは幾らとは違う
他の正規表現ツールは否定文字クラスを扱いますが、残念ながら
矛盾は歴史的に定着しています。 一致する改行は、
[^"]* のようなパターンは、別の引用符が含まれていない限り、入力全体に一致できます。
入力。
- ルールは、末尾のコンテキスト ('/' 演算子または
'$' 演算子)。 開始条件、'^'、および "< >" パターンは
パターンの先頭であり、'/' や '$' と同様に、グループ化することはできません
括弧内。 ルールの先頭にない「^」または「$」
ルールの最後に発生しないものは、その特別なプロパティを失い、
普通のキャラ扱い。
以下は違法です。
フー/バー $
ふーバー
これらの最初のものは、「foo/bar\n」と書くことができることに注意してください。
次の例では、'$' または '^' が通常の文字として扱われます。
foo|(bar$)
foo|^バー
必要なものが「foo」または改行が続くバーである場合、次のようになります
使用されます (特別な '|' アクションについては以下で説明します):
ふー |
bar$ /* ここにアクションが入ります */
同様のトリックは、foo または行頭のバーのマッチングにも機能します。
HOW 、 入力 IS 一致
生成されたスキャナーが実行されると、入力を分析して一致する文字列を探します
そのパターンのいずれか。 複数の一致が見つかった場合は、最も一致するものを取得します
テキスト (末尾のコンテキスト ルールの場合、これには末尾部分の長さが含まれます。
ただし、その後は入力に返されます)。 の一致が XNUMX つ以上見つかった場合、
同じ長さ、最初にリストされているルール フレックス 入力ファイルが選択されます。
一致が決定されると、一致に対応するテキスト ( トークン) is
グローバル文字ポインタで利用可能に yytext、 およびそのグローバルでの長さ
整数 イレン。 当学校区の アクション 一致したパターンに対応するが実行されます (さらに
アクションの詳細な説明が続きます)、その後、残りの入力がスキャンされます。
別の試合。
一致するものが見つからない場合、 デフォルト ルール が実行されます: 入力の次の文字
一致したと見なされ、標準出力にコピーされます。 したがって、最も単純な法律 フレックス
入力は次のとおりです。
%%
これは、入力 (一度に XNUMX 文字) を単純にコピーするスキャナーを生成します。
出力。
注意してください yyテキスト XNUMX つの異なる方法で定義できます: 文字として ポインタ またはとして
キャラクター アレイ。 どの定義を制御できるか フレックス のいずれかを含めて使用します。
特別指令 %ポインタ or %配列 フレックスの最初の(定義)セクションで
入力。 デフォルトは %ポインタ、 を使用しない限り、 -l lex 互換性オプション。
場合 yyテキスト 配列になります。 使用する利点 %ポインタ は大幅に高速です
非常に大きなトークンに一致する場合のスキャンとバッファオーバーフローなし(不足しない限り)
動的メモリ)。 欠点は、自分の行動が制限されることです。
修正する yyテキスト (次のセクションを参照)、および 入力() 関数は
現在の内容 yytext、 これは、移動時にかなりの移植の頭痛の種になる可能性があります
異なる間で LEX バージョン。
の利点 %配列 変更できるということです yyテキスト 心ゆくまで、そして
への呼び出し 入力() 破壊しないでください yyテキスト (下記参照)。 さらに、既存の LEX プログラム
時々アクセス yyテキスト 次の形式の宣言を外部的に使用します。
extern char yytext[];
で使用すると、この定義は誤りです。 %ポインタ、 しかし正しい %配列。
%配列 定義 yyテキスト の配列になる イルマックス 文字、デフォルトはかなり
大きな値。 #define するだけでサイズを変更できます イルマックス 異なる値に
あなたの最初のセクション フレックス 入力。 上記のように、 %ポインタ yytext が大きくなる
大きなトークンに対応するために動的に。 これはあなたの %ポインタ スキャナー缶
非常に大きなトークンに対応する (コメントのブロック全体を一致させるなど)、覚えておいてください
スキャナーのサイズを変更する必要があるたびに yyテキスト また、トークン全体を再スキャンする必要があります。
そのため、このようなトークンの照合は遅くなる可能性があります。 yyテキスト 現在している
への呼び出しの場合、動的に成長します 入力() あまりにも多くのテキストが押し戻されます。 代わりは、
実行時エラーが発生します。
また、ご利用いただけませんのでご了承ください。 %配列 C++ スキャナー クラス ( C ++ オプション; 下記参照)。
ACTIONS
ルール内の各パターンには対応するアクションがあり、これは任意の C ステートメントにすることができます。
パターンは、エスケープされていない最初の空白文字で終了します。 行の残り
その行動です。 アクションが空の場合、パターンが一致すると入力トークン
単に破棄されます。 たとえば、これは削除するプログラムの仕様です
その入力からの「zap me」のすべての出現:
%%
「ザップミー」
(入力内の他のすべての文字が一致するため、出力にコピーされます
デフォルトのルールで。)
以下は、複数の空白とタブを単一の空白に圧縮するプログラムです。
行末にある空白を破棄します。
%%
[ \t]+ putchar( ' ' );
[ \t]+$ /* このトークンを無視します */
アクションに '{' が含まれている場合、アクションはバランシング '}' が見つかるまで続きます。
アクションは複数の行にまたがる場合があります。 フレックス C の文字列とコメントを知っていて、そうではない
それらの中にある中括弧にだまされますが、アクションを開始することもできます %{ そして、なります
アクションを次までのすべてのテキストと見なす %} (通常のブレースに関係なく
アクション内)。
縦棒 ('|') だけで構成されるアクションは、「次のアクションと同じ」を意味します。
ルール。" 図については、以下を参照してください。
アクションには、次のような任意の C コードを含めることができます。 return 値を返すステートメント
どんなルーチンが呼び出されても yylex()。 毎回 yylex() と呼ばれ、処理を続行します
ファイルの最後に到達するか、実行されるまで、最後に中断した場所からのトークン
リターン。
アクションは自由に変更可能 yyテキスト それを長くすることを除いて(その
end--これらは、入力ストリーム内の後の文字を上書きします)。 ただし、これはそうではありません
使用時に適用 %配列 (上記を参照); その場合、 yyテキスト 任意に自由に変更できます
ウェイ
アクションは自由に変更可能 イレン ただし、アクションに含まれる場合はそうすべきではありません
使用 yymore() (下記参照)。
アクション内に含めることができる特別なディレクティブがいくつかあります。
- エコー スキャナの出力に yytext をコピーします。
- ベギン 開始条件の名前が続くと、スキャナが
対応する開始条件 (以下を参照)。
- 拒否 一致した「次善の」ルールに進むようにスキャナに指示します
入力 (または入力のプレフィックス)。 ルールは、上で説明したように選択されます。
「入力の一致方法」、および yyテキスト イレン 適切に設定します。 かもしれない
最初に選択されたルールと同じくらい多くのテキストに一致したが、
後で フレックス 入力ファイル、または一致するテキストが少ないファイル。 たとえば、
以下は、入力内の単語をカウントし、ルーチン special() を呼び出します。
「フロブ」が見られるときはいつでも:
int word_count = 0;
%%
フロブスペシャル(); 拒絶;
[^ \t\n]+ ++word_count;
なし 拒否する、 入力内の「フロブ」は単語としてカウントされません。
スキャナーは通常、トークンごとに XNUMX つのアクションのみを実行します。 多数 REJECTの
許可され、それぞれが現在アクティブなルールの次善の選択肢を見つけます。 為に
たとえば、次のスキャナーがトークン「abcd」をスキャンすると、次のように書き込まれます。
出力への「abcdabcaba」:
%%
|
ab |
ABC |
abcdエコー; 拒絶;
.|\n /* 一致しない文字を食べ尽くす */
(最初の XNUMX つのルールは、特殊な「|」を使用するため、XNUMX 番目のアクションを共有します。
アクション。) 拒否 スキャナの点で特に高価な機能です
パフォーマンス; で使用する場合 どれか スキャナーのアクションの速度が低下します を of
スキャナのマッチング。 さらに、 拒否 と一緒に使用することはできません -参照 or -CF
オプション (以下を参照)。
また、他の特殊アクションとは異なり、 拒否 支店; コード
アクションでその直後に続く 実行されます。
- yymore() 次にルールに一致するとき、対応する
トークンは 添付 の現在の値に yyテキスト 交換するのではなく。
たとえば、入力が「mega-kludge」の場合、次のように書くと「mega-mega-
kludge" を出力に:
%%
メガエコー; yymore();
クラッジエコー;
最初の「mega-」が一致し、出力にエコーされます。 すると「kludge」がマッチしますが、
以前の「メガ」はまだ冒頭にぶら下がっています yyテキスト そう エコー
"kludge" ルールは実際には "mega-kludge" と書きます。
の使用に関するXNUMXつの注意事項 yymore()。 まず、 yymore() の値に依存します イレン
現在のトークンのサイズを正しく反映しているため、変更しないでください イレン あなたの場合
使っている yymore()。 第二に、の存在 yymore() スキャナーのアクションでは、
スキャナーのマッチング速度のわずかなパフォーマンスの低下。
- yyless(n) 最初を除くすべてを返します n 現在のトークンの文字を
入力ストリーム。スキャナが次を探すときに再スキャンされます
一致しています。 yyテキスト イレン 適切に調整されます(例: イレン になります
に等しい n )。 たとえば、入力「foobar」では、次のように書き出されます
"フーバーバー":
%%
フーバーエコー; いいえ(3);
[az]+エコー;
0 ~ の引数 いいえ 現在の入力文字列全体がスキャンされます
また。 スキャナがその後入力を処理する方法を変更していない限り
(使用 始める、 例)、これは無限ループになります。
注意してください いいえ はマクロであり、フレックス入力ファイルでのみ使用でき、他のファイルからは使用できません
ソースファイル。
- 入力(c) 文字を入れます c 入力ストリームに戻ります。 それは次になります
文字がスキャンされました。 次のアクションは現在のトークンを取得し、それを引き起こします
かっこで囲まれて再スキャンされます。
{
int i;
/* unput() は yytext を破棄するため、yytext をコピーします */
char *yycopy = strdup( yytext );
unput( ')' );
for ( i = yyleng - 1; i >= 0; --i )
unput( yycopy[i] );
unput( '(' );
無料 ( yycopy );
}
それぞれの 入力() 指定された文字を元に戻します 初め
入力ストリームでは、文字列の押し戻しは後ろから前に行う必要があります。
使用時の重要な潜在的な問題 入力() それはあなたが使用している場合です %ポインタ (
デフォルト)、への呼び出し 入力() 破壊する の内容 yytext、 一番右から
文字を呼び出し、各呼び出しで左に XNUMX 文字をむさぼり食う。 値が必要な場合
への呼び出し後に保持される yytext の 入力() (上記の例のように)、次のいずれかを行う必要があります
最初に別の場所にコピーするか、次を使用してスキャナーを構築します %配列 代わりに (入力方法を参照してください
一致した)。
最後に、元に戻すことはできません。 EOF 入力ストリームを
ファイルの終わり。
- 入力() 入力ストリームから次の文字を読み取ります。 たとえば、次の
は、C のコメントを使い果たす XNUMX つの方法です。
%%
"/*" {
int c;
為に ( ; ; )
{
while ( (c = 入力()) != '*' &&
c != EOF )
; /* コメントのテキストを食べ尽くす */
もし ( c == '*' )
{
while ( (c = 入力()) == '*' )
;
もし ( c == '/' )
壊す; /* 最後を見つけた */
}
もし ( c == EOF )
{
error( "コメントの EOF" );
破る;
}
}
}
(スキャナーが次を使用してコンパイルされている場合は、 C ++、 その後 入力() 代わりに参照されます
として yyinput()、 との名前の衝突を避けるために C + + の名前でストリーミング
入力。)
- YY_FLUSH_BUFFER スキャナの内部バッファをフラッシュして、次回
スキャナがトークンの照合を試みると、最初に次を使用してバッファを補充します YY_INPUT
(以下の生成されたスキャナーを参照してください)。 このアクションは、more の特殊なケースです。
一般的な yy_flush_buffer() 関数、以下の複数入力セクションで説明
バッファ。
- yyterminate() アクションの return ステートメントの代わりに使用できます。 これ
スキャナーを終了し、スキャナーの呼び出し元に 0 を返します。
デフォルトでは、 yyterminate() ファイルの終わりのときにも呼び出されます
遭遇した。 これはマクロであり、再定義できます。
、 生成された スキャナー
の出力 フレックス ファイルです lex.yy.c、 スキャンルーチンを含む yylex()、 a
トークンの照合に使用されるテーブルの数、および補助ルーチンの数と
マクロ。 デフォルトでは、 yylex() は次のように宣言されます。
int yylex()
{
... さまざまな定義とここでのアクション ...
}
(お使いの環境が関数プロトタイプをサポートしている場合、"int yylex( void )" になります。)
この定義は、「YY_DECL」マクロを定義することで変更できます。 たとえば、次のことができます。
使用します。
#define YY_DECL float lexscan( a, b ) float a, b;
スキャンルーチンに名前を付ける レスキャン、 float を返し、XNUMX つの float を
引数。 K&R スタイル/非
プロトタイプ関数宣言では、セミコロン (;) で定義を終了する必要があります。
都度 yylex() が呼び出されると、グローバル入力ファイルからトークンをスキャンします イーイン (これは
デフォルトは stdin です)。 ファイルの終わりに達するまで続きます (その時点で)
値 0 を返す) またはそのアクションの XNUMX つが return 声明。
スキャナーがファイルの終わりに達した場合、後続の呼び出しは未定義です。 イーイン
新しい入力ファイルを指している (この場合、スキャンはそのファイルから続行されます)、または
yyrestart() が呼び出されます。 yyrestart() XNUMX つの引数を取ります。 FILE * ポインター (
nil、設定した場合 YY_INPUT 以外のソースからスキャンする yyin)、 そして初期化します
イーイン そのファイルからスキャンするため。 本質的に違いはありません
割り当て イーイン 新しい入力ファイルに、または使用して yyrestart() そうするために; 後者は利用可能です
の以前のバージョンとの互換性のため フレックス、 切り替えて使えるから
スキャンの途中でファイルを入力します。 電流を捨てるためにも使用できます
の引数で呼び出すことにより、入力バッファ イーイン。 しかし、より良いのは使用することです YY_FLUSH_BUFFER
(上記を参照)。 ご了承ください yyrestart() ありません 開始条件をにリセットします 初期 (参照してください
以下の開始条件)。
If yylex() を実行したため、スキャンを停止します return アクションの XNUMX つのステートメント、
その後、scanner を再度呼び出すことができ、中断したところからスキャンを再開します。
デフォルトでは (効率を高めるために)、スキャナはブロック読み取りを使用します。
シンプルな getc() 文字を読み取るための呼び出し 陰。 入力を取得する方法の性質により、
を定義することによって制御されます。 YY_INPUT 大きい。 YY_INPUT の呼び出しシーケンスは
"YY_INPUT(buf,result,max_size)". そのアクションは、 最大サイズ の文字
文字配列 BUF そして整数変数に戻ります 結果 の数のいずれか
読み込まれた文字または定数 YY_NULL (Unix システムでは 0) で EOF を示します。 デフォルト
YY_INPUT は、グローバル ファイル ポインタ "yyin" から読み取ります。
YY_INPUT のサンプル定義 (入力ファイルの定義セクション内):
%{
#define YY_INPUT(buf,result,max_size) \
{\
int c = getchar(); \
結果 = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
}
%}
この定義により、入力処理が一度に XNUMX 文字ずつ発生するように変更されます。
スキャナが YY_INPUT からファイルの終わりの指示を受け取ると、スキャナは
yywrap() 関数。 もしも yywrap() false (ゼロ) を返す場合、関数が
先に進んで設定しました イーイン 別の入力ファイルを指定すると、スキャンが続行されます。 もしも
true (ゼロ以外) を返した後、スキャナーは終了し、呼び出し元に 0 を返します。 ノート
どちらの場合も、開始条件は変更されません。 します 戻る イニシャル。
独自のバージョンの yywrap()、 次に、次のいずれかを使用する必要があります %オプション
ノイラップ (この場合、スキャナは次のように動作します。 yywrap() 返される 1)、またはする必要があります
とのリンク -NS 常に 1 を返すルーチンのデフォルト バージョンを取得します。
ファイルではなくメモリ内バッファからのスキャンには、次の XNUMX つのルーチンを使用できます。
yy_scan_string()、 yy_scan_bytes()、 yy_scan_buffer()。 以下のそれらの議論を参照してください
複数の入力バッファのセクションで。
スキャナはその エコー に出力 yout グローバル (デフォルト、stdout)。
ユーザーが他のものに割り当てるだけで再定義 FILE ポインター。
開始 条件
フレックス ルールを条件付きでアクティブ化するメカニズムを提供します。 パターンが
接頭辞 " " は、スキャナが次の名前の開始条件にある場合にのみアクティブになります
「sc」。 例えば、
[^"]* { /* 文字列本体を食べ尽くす ... */
...
}
スキャナが「STRING」開始状態にある場合にのみアクティブになります。
\. { /* エスケープ処理 ... */
...
}
現在の開始条件が「INITIAL」、「STRING」、または
"見積もり"。
開始条件は、入力の定義 (最初の) セクションで次を使用して宣言されます。
いずれかで始まるインデントされていない行 %s or %x 名前のリストが続きます。 前者
宣言してい 含む 開始条件、後者 排他的な 開始条件。 スタート
条件は、 ベギン アクション。 次まで ベギン アクションが実行され、
指定された開始条件を持つルールがアクティブになり、他の開始条件を持つルールがアクティブになります
非アクティブになります。 開始条件が 包括的、 その後、開始のないルール
条件もまったくアクティブになります。 もしそれが 排他的、 その後 の 修飾されたルール
開始条件がアクティブになります。 同じ排他的開始を条件とする一連のルール
条件は、他のルールから独立したスキャナーを記述します。 フレックス
入力。 このため、専用の起動条件で「ミニ」を簡単に指定できます。
スキャナ」は、残りとは構文的に異なる入力の部分をスキャンします
(コメントなど)。
包括的および排他的な開始条件の違いがまだ少しある場合
漠然としていますが、XNUMX つの関係を示す簡単な例を次に示します。 のセット
ルール:
%s の例
%%
foo do_something();
バー something_else();
に相当します
%x の例
%%
foo do_something();
bar something_else();
なし 修飾子、 バー XNUMX番目の例のパターンはそうではありません
開始状態のときにアクティブ (つまり、一致できませんでした) 例。 ちょうど使用した場合
資格を得る バー、 ただし、それはでのみアクティブになります 例 ではなく イニシャル、 while
最初の例では、両方でアクティブです。最初の例では、 例 start
状態は 含む (%NS) 開始条件。
また、特別な開始条件指定子 <*> すべての開始条件に一致します。
したがって、上記の例も書くことができます。
%x の例
%%
foo do_something();
<*>bar something_else();
デフォルトのルール ( エコー 一致しない文字) は、開始条件でアクティブなままになります。 これ
以下と同等です。
<*>.|\n エコー;
ベギン(0) 開始条件のないルールだけが存在する元の状態に戻る
アクティブ。 この状態を開始条件「INITIAL」と呼ぶこともできるので、
BEGIN(イニシャル) に相当します ベギンとします。 (開始条件を囲む括弧
名前は必須ではありませんが、良いスタイルと見なされます。)
ベギン アクションは、ルール セクションの先頭にインデントされたコードとして指定することもできます。
たとえば、次の場合、スキャナは「SPECIAL」開始条件に入ります。
たびに yylex() が呼び出され、グローバル変数 Enter_special は本当です:
int enter_special;
%x スペシャル
%%
場合 (enter_special)
開始 (特別);
何とか何とか何とか
...さらにルールが続きます...
開始条件の使用法を説明するために、XNUMX つの異なる条件を提供するスキャナーを次に示します。
「123.456」のような文字列の解釈。 デフォルトでは、それを XNUMX つのトークンとして扱います。
整数「123」、ドット ('.')、および整数「456」。 しかし、文字列が前にある場合
文字列「expect-floats」の前の行で、それを単一のトークンとして扱います。
浮動小数点数 123.456:
%{
#include
%}
%s 期待
%%
期待フロート BEGIN(期待);
[0-9]+"."[0-9]+ {
printf( "float が見つかりました。= %f\n",
atof( yytext ) );
}
\n{
/* これが行末なので、
* 別の「expect-number」が必要です
* これ以上認識する前に
* 数字
*/
BEGIN(初期);
}
[0-9]+{
printf( "整数が見つかりました、= %d\n",
atoi( yytext ) );
}
「。」 printf( "ドットが見つかりました\n" );
これは、カウントを維持しながら C コメントを認識 (および破棄) するスキャナーです。
現在の入力行。
%x コメント
%%
int line_num = 1;
"/*" BEGIN(コメント);
[^*\n]* /* '*' 以外のものは何でも食べる */
"*"+[^*/\n]* /* '*' の後に '/' が続かない */
\n ++line_num;
"*"+"/" BEGIN(頭文字);
このスキャナーは、各ルールにできるだけ多くのテキストを一致させるために少し手間がかかります。
一般に、高速スキャナを書き込もうとするときは、可能な限り一致させようとします。
それは大きな勝利なので、各ルール。
開始条件名は実際には整数値であり、そのように保存できることに注意してください。
したがって、上記は次のように拡張できます。
%x コメント foo
%%
int line_num = 1;
int comment_caller;
"/*" {
comment_caller = 初期;
BEGIN(コメント);
}
...
"/*" {
コメント呼び出し者 = foo;
BEGIN(コメント);
}
[^*\n]* /* '*' 以外のものは何でも食べる */
"*"+[^*/\n]* /* '*' の後に '/' が続かない */
\n ++line_num;
"*"+"/" BEGIN(comment_caller);
さらに、整数値を使用して現在の開始条件にアクセスできます。 YY_START
大きい。 たとえば、上記の割り当ては コメント発信者 代わりに書くことができます
コメント発信者 = YY_START;
Flex が提供する YY州 エイリアスとして YY_START (これは AT&T で使用されているためです。 レックス)。
開始条件には独自の名前空間がないことに注意してください。 %s と %x の宣言名
#define と同じ方法で。
最後に、exclusive start を使用して C スタイルの引用符で囲まれた文字列を一致させる方法の例を次に示します。
拡張されたエスケープ シーケンスを含む条件 (文字列のチェックは含まない)
それは長すぎます):
%x 文字列
%%
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
\" string_buf_ptr = string_buf; BEGIN(str);
\" { /* 最後の引用を見ました - すべて完了 */
BEGIN(初期);
*string_buf_ptr = '\0';
/* 文字列定数のトークン タイプを返し、
* パーサーへの値
*/
}
\n{
/* エラー - 終了していない文字列定数 */
/* エラーメッセージを生成します */
}
\\[0-7]{1,3} {
/* XNUMX 進エスケープ シーケンス */
int 結果;
(void) sscanf( yytext + 1, "%o", &result );
もし (結果 > 0xff )
/* エラー、定数が範囲外です */
*string_buf_ptr++ = 結果;
}
\\[0-9]+ {
/* エラーを生成 - 不適切なエスケープ シーケンス。 なにか
* '\48' や '\0777777' のように
*/
}
\\n *string_buf_ptr++ = '\n';
\\t *string_buf_ptr++ = '\t';
\\r *string_buf_ptr++ = '\r';
\\b *string_buf_ptr++ = '\b';
\\f *string_buf_ptr++ = '\f';
\\(.|\n) *string_buf_ptr++ = yytext[1];
[^\\\n\"]+ {
char *yptr = yytext;
ながら ( *yptr )
*string_buf_ptr++ = *yptr++;
}
多くの場合、上記の例のように、大量のルールを作成することになります。
すべて同じ開始条件が先行します。 Flex を使用すると、これが少し簡単かつクリーンになります
開始条件の概念を導入することにより 範囲。 開始条件スコープは次で始まります。
{
コラボレー SC XNUMX つ以上の開始条件のリストです。 開始条件スコープ内で、
すべてのルールには自動的に接頭辞があります 適用されるまで、 '}' 一致するもの
初期 「{」。 たとえば、
{
"\\n" return '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" は '\0' を返します。
}
以下と同等です。
"\\n" return '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" は '\0' を返します。
開始条件スコープは入れ子にすることができます。
開始条件のスタックを操作するために、XNUMX つのルーチンを使用できます。
ボイド yy_push_state(int 新しい状態)
現在の開始条件を開始条件スタックの一番上にプッシュし、
に切り替える 新しい状態 まるであなたが使ったかのように ベギン 新しい状態 (その始まりを思い出してください
条件名も整数です)。
ボイド yy_pop_state()
スタックの一番上をポップし、経由してそれに切り替えます 始める。
int型 yy_top_state()
スタックの内容を変更せずにスタックの一番上を返します。
開始条件スタックは動的に拡大するため、組み込みのサイズ制限はありません。 もしも
メモリが使い果たされ、プログラムの実行が中止されます。
開始条件スタックを使用するには、スキャナーに %オプション スタック ディレクティブ (参照
以下のオプション)。
複数 入力 バッファ
一部のスキャナ (「インクルード」ファイルをサポートするスキャナなど) は、複数のスキャナから読み取る必要があります。
入力ストリーム。 として フレックス スキャナーは大量のバッファリングを行い、どこで制御することはできません
次の入力は、次のように書くだけで読み取られます。 YY_INPUT に敏感です
スキャン コンテキスト。 YY_INPUT スキャナがバッファの最後に到達したときにのみ呼び出されます。
これは、必要な「include」などのステートメントをスキャンした後、長い時間がかかる場合があります
入力ソースを切り替えます。
こういった問題を解決するには、 フレックス 作成および切り替えのメカニズムを提供します
複数の入力バッファ間。 入力バッファーは、以下を使用して作成されます。
YY_BUFFER_STATE yy_create_buffer( FILE *ファイル, int サイズ)
これは FILE ポインタとサイズを指定し、指定されたファイルに関連付けられたバッファを作成します
そして十分な大きさ サイズ 文字(疑わしい場合は、使用してください YY_BUF_SIZE サイズに関して)。
それは YY_BUFFER_STATE このハンドルは、他のルーチンに渡すことができます (参照
未満)。 NS YY_BUFFER_STATE type は opaque へのポインタです 構造 yy_buffer_state
構造であるため、YY_BUFFER_STATE 変数を安全に初期化できます。 ((YY_BUFFER_STATE) 0)
必要に応じて、入力を正しく宣言するために不透明な構造も参照してください
スキャナ以外のソース ファイルのバッファ。 注意してください FILE ポインター
への呼び出し yy_create_buffer の値としてのみ使用されます。 イーイン から見た YY_INPUT; あなたの場合
再定義する YY_INPUT だから使わなくなった 陰、 その後、安全に nil を渡すことができます FILE ポインタ
〜へ yy_create_buffer。 以下を使用して、スキャンする特定のバッファーを選択します。
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
スキャナの入力バッファを切り替えて、後続のトークンが次の場所から来るようにします 新しいバッファ。 注意
それ yy_switch_to_buffer() yywrap() で使用して、継続するための設定を行うことができます
新しいファイルを開いてポイントする代わりに、スキャンします イーイン それで。 切り替えにも注意
入力ソース yy_switch_to_buffer() or yywrap() ありません スタートを変える
条件。
void yy_delete_buffer( YY_BUFFER_STATE バッファ )
バッファに関連付けられたストレージを再利用するために使用されます。 ( バッファ nil にすることができます。
この場合、ルーチンは何もしません。) バッファの現在の内容をクリアすることもできます
を使用して:
void yy_flush_buffer( YY_BUFFER_STATE バッファ )
この関数はバッファの内容を破棄します。
バッファからのトークンに一致する場合、最初に次を使用してバッファを新たに埋めます YY_INPUT。
yy_new_buffer() のエイリアスです yy_create_buffer()、 との互換性のために提供されます。
C++ の使用 NEW 削除 動的オブジェクトの作成と破棄。
最後に、 YY_CURRENT_BUFFER マクロは YY_BUFFER_STATE 現在のハンドル
バッファ。
これらの機能を使用して展開するスキャナーを作成する例を次に示します。
ファイル ( < > 機能については以下で説明します):
/* "incl" 状態は名前の取得に使用されます
* インクルードファイルの
*/
%x 含む
%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
BEGIN(含む)を含めます。
[az]+エコー;
[^az\n]*\n? エコー;
[ \t]* /* 空白を食べる */
[^ \t\n]+ { /* インクルードファイル名を取得 */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "ネストが深すぎます" );
終了 ( 1 );
}
include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;
yyin = fopen( yytext, "r" );
もし ( ! yyin )
エラー( ... );
yy_switch_to_buffer(
yy_create_buffer( yyin, YY_BUF_SIZE ) );
BEGIN(初期);
}
< > {
if ( --include_stack_ptr < 0 )
{
yyterminate();
}
ほかに
{
yy_delete_buffer( YY_CURRENT_BUFFER );
yy_switch_to_buffer(
include_stack[include_stack_ptr] );
}
}
メモリ内文字列をスキャンするための入力バッファを設定するために、XNUMX つのルーチンを使用できます。
ファイルの代わりに。 それらはすべて、文字列をスキャンするための新しい入力バッファを作成し、
対応する YY_BUFFER_STATE ハンドル(削除する必要があります
yy_delete_buffer() それが終わったら)。 また、次を使用して新しいバッファに切り替えます
yy_switch_to_buffer()、 そのため、次の呼び出し yylex() 文字列のスキャンを開始します。
yy_scan_string(const チャリオット *str)
NUL で終わる文字列をスキャンします。
yy_scan_bytes(定数 チャリオット *バイト、 int型 レン)
スキャン LEN location から始まるバイト (場合によっては NUL を含む) バイト
これらの関数は両方とも、 copy 文字列またはバイトの。 (これ
が望ましい場合があります。 yylex() スキャンしているバッファの内容を変更します。)
以下を使用してコピーを回避できます。
yy_scan_buffer(文字 *ベース、 yy_size_t サイズ)
で始まるバッファをその場でスキャンします ベース、 からなる サイズ バイト、
最後の XNUMX バイト しなければなりません be YY_END_OF_BUFFER_CHAR (ASCII NUL)。 この最後のXNUMXつ
バイトはスキャンされません。 したがって、スキャンは次のもので構成されます ベース[0] ベース[サイズ-2]、
包括的です。
設定に失敗した場合 ベース この方法で(つまり、最後のXNUMXつを忘れて
YY_END_OF_BUFFER_CHAR バイト)、その後 yy_scan_buffer() 代わりに nil ポインタを返します
新しい入力バッファの作成。
タイプ yy_size_t 整数式をキャストできる整数型です
バッファのサイズを反映しています。
ファイルの終わり RULES
特別ルール「< >" は、ファイルの終わりが発生したときに実行されるアクションを示します。
yywrap() はゼロ以外を返します (つまり、これ以上処理するファイルがないことを示します)。
アクションは、次の XNUMX つのいずれかを実行して終了する必要があります。
- 割り当て イーイン 新しい入力ファイルに (以前のバージョンの flex では、
特別なアクションを呼び出さなければならなかった割り当て YY_NEW_FILE; これはもうありません
必要);
- を実行する return 声明;
- スペシャルの実行 yyterminate() アクション;
- または、を使用して新しいバッファに切り替えます yy_switch_to_buffer() 例に示すように
上記。
< > ルールは他のパターンでは使用できません。 それらはリストでのみ修飾できます
開始条件の。 修飾されていない < > ルールが与えられ、適用される を start
< をまだ持っていない条件> アクション。 < を指定するには> のみのルール
初期開始条件、使用
< >
これらのルールは、閉じられていないコメントなどをキャッチするのに役立ちます。 例:
%x 引用
%%
...引用符を扱うためのその他のルール...
< > {
error( "終了していない引用符" );
yyterminate();
}
< > {
if ( *++ファイルリスト )
yyin = fopen( *filelist, "r" );
ほかに
yyterminate();
}
雑則 マクロス
マクロ YY_USER_ACTION 常に実行されるアクションを提供するように定義できます
一致したルールのアクションの前。 たとえば、ルーチンを呼び出すために #define することができます
yytext を小文字に変換します。 いつ YY_USER_ACTION が呼び出され、変数 yy_act
一致したルールの番号を示します (ルールには 1 から始まる番号が付けられます)。 あなたが
各ルールが一致する頻度をプロファイリングしたいと考えています。 以下は
騙す:
#define YY_USER_ACTION ++ctr[yy_act]
コラボレー ctr 異なるルールのカウントを保持する配列です。 マクロに注意してください
YY_NUM_RULES ルールの総数を示します(デフォルトのルールを使用した場合でも、
-s)、 したがって、正しい宣言 ctr 次のとおりです。
int ctr[YY_NUM_RULES];
マクロ YY_USER_INIT 常に前に実行されるアクションを提供するように定義できます
最初のスキャン (およびスキャナの内部初期化が完了する前)。 例えば、
ルーチンを呼び出してデータ テーブルを読み取ったり、ログ ファイルを開いたりするために使用できます。
マクロ yy_set_interactive(is_interactive) を制御するために使用できます。
バッファが考慮されます インタラクティブ。 対話型バッファの処理は遅くなりますが、
スキャナーの入力ソースが実際に対話型である場合は、問題を回避するために使用する必要があります。
バッファがいっぱいになるのを待っています(の説明を参照してください -I 下のフラグ)。 ゼロ以外の値
マクロ呼び出しはバッファを対話型としてマークし、ゼロの値は非対話型としてマークします。
このマクロの使用は上書きされることに注意してください %オプション 相互作用的 , %オプション 常にインタラクティブ or
%オプション インタラクティブでない (以下のオプションを参照)。 yy_set_interactive() 事前に呼び出す必要があります
インタラクティブと見なされる (またはされない) バッファーのスキャンを開始します。
マクロ yy_set_bol(at_bol) 現在のバッファのスキャンが終了するかどうかを制御するために使用できます
次のトークン一致のコンテキストは、行の先頭であるかのように行われます。 非ゼロ
マクロ引数はルールを固定します
マクロ YY_AT_BOL() 現在のバッファからスキャンされた次のトークンが
'^' ルールを有効にし、それ以外の場合は false。
生成されたスキャナーでは、すべてのアクションが XNUMX つの大きな switch ステートメントにまとめられ、
を使用して区切られた YY_BREAK、 これは再定義される可能性があります。 デフォルトでは、これは単なる「休憩」です。
各ルールのアクションを次のルールのアクションから分離します。 再定義 YY_BREAK 許可する
たとえば、C++ ユーザーは何もしないように #define YY_BREAK する必要があります (すべての
ルールは「break」または「return」で終了します!) 到達不能なステートメントに苦しむのを避けるために
ルールのアクションが「return」で終わるため、 YY_BREAK アクセスできません。
VALUES AVAILABLE に 、 USER
このセクションでは、ルール アクションでユーザーが使用できるさまざまな値をまとめます。
- チャリオット * yytext 現在のトークンのテキストを保持します。 変更される可能性がありますが、変更されません
長くなります (最後に文字を追加することはできません)。
特別指令の場合 %配列 スキャナの最初のセクションに表示されます
説明、その後 yyテキスト 代わりに宣言されています チャリオット yyテキスト[YYLMAX]、 コラボレー イルマックス
気に入らない場合は、最初のセクションで再定義できるマクロ定義
デフォルト値 (通常は 8KB)。 使用する %配列 その結果、スキャナーがやや遅くなり、
しかし、の値 yyテキスト への呼び出しに対して免疫になります 入力() 入力()、 which
潜在的にその価値を破壊する yyテキスト 文字ポインタです。 の反対
%配列 is %ポインタ、 これがデフォルトです。
使用できません %配列 C++ スキャナー クラスを生成するとき ( -+ 国旗)。
- int型 イレン 現在のトークンの長さを保持します。
- FILE *イーイン デフォルトで フレックス から読み取ります。 再定義されるかもしれませんが、
そうすることは、スキャンが開始される前、またはEOFが行われた後にのみ意味があります
遭遇した。 スキャン中に変更すると、予期しない結果が生じる場合があります
から フレックス その入力をバッファリングします。 使用する yyrestart() 代わりは。 スキャンが終了したら
ファイルの終わりが見られたので、割り当てることができます イーイン 新しい入力ファイルで
その後、スキャナーを再度呼び出してスキャンを続行します。
- ボイド yyrestart( FILE *新しいファイル ) 指さすように呼ばれるかもしれません イーイン 新しい入力ファイルで。
新しいファイルへの切り替えは即座に行われます (以前にバッファリングされた入力はすべて
失った)。 呼び出すことに注意してください yyrestart() イーイン したがって、引数として
現在の入力バッファをスキャンし、同じ入力ファイルのスキャンを続行します。
- FILE *yout が対象のファイルです エコー アクションが行われます。 によって再割り当てできます。
ユーザー。
- YY_CURRENT_BUFFER を返す YY_BUFFER_STATE 現在のバッファへのハンドル。
- YY_START 現在の開始条件に対応する整数値を返します。
その後、この値を次のように使用できます。 ベギン その開始状態に戻ります。
インターフェース WITH YACC
の主な用途のXNUMXつ フレックス の仲間として ヤック パーサージェネレーター。 ヤック パーサー
という名前のルーチンを呼び出すことを期待しています yylex() 次の入力トークンを見つけます。 ルーチンは
次のトークンのタイプを返すだけでなく、関連する値を入れることになっています
グローバル yylval。 使用するには フレックス yacc、 XNUMXつは -d オプション ヤック 指示します
ファイルを生成する yタブh すべての定義を含む %トークン に登場
ヤック 入力。 このファイルは、 フレックス スキャナー。 たとえば、
tokens は「TOK_NUMBER」で、スキャナーの一部は次のようになります。
%{
#include "y.tab.h"
%}
%%
[0-9]+ yylval = atoi( yytext ); TOK_NUMBER を返します。
OPTIONS
フレックス 次のオプションがあります。
-NS、 - バックアップ
へのバックアップ情報を生成します lex.バックアップ。 これはスキャナーの状態のリストです
バックアップと、バックアップを行う入力文字が必要です。 追加することで
バックアップ状態を削除できるルール。 もしも を バックアップ状態が解消されます
-参照 or -CF を使用すると、生成されたスキャナーはより高速に実行されます ( -p 国旗)。
スキャナーからすべての最後のサイクルを絞り出したいユーザーだけが心配する必要があります
このオプションについて。 (以下のパフォーマンスに関する考慮事項のセクションを参照してください。)
-c は、POSIX 準拠のために含まれている、何もしない非推奨のオプションです。
-NS、 - デバッグ
生成されたスキャナーを実行します debug モード。 パターンが認識されるたびに
そして世界 yy_flex_debug ゼロ以外 (デフォルト) の場合、スキャナーは
に書きます stderr 次の形式の行:
-- 53 行目でルールを受け入れます (「一致したテキスト」)。
行番号は、スキャナーを定義するファイル内のルールの場所を示します
(つまり、flex に供給されたファイル)。 メッセージは、
スキャナーはバックアップし、デフォルトのルールを受け入れ、入力バッファーの最後に到達します (または
NUL に遭遇しました。 この時点で、スキャナの限り、XNUMX つは同じように見えます。
か、またはファイルの終わりに到達します。
-NS、 - 満杯
指定する 速いです スキャナ。 テーブルの圧縮は行われず、stdio はバイパスされます。 の
結果は大きいですが高速です。 このオプションは、 -参照 (下記参照)。
-NS、 - 助けて
の「ヘルプ」要約を生成します フレックス オプション (Linuxで言うところのstdout) その後、終了します。 -?
- 助けて の同義語です -h。
-私、 - 大文字小文字を区別しません
指示する フレックス を生成する 大文字小文字を区別しません スキャナー。 与えられた手紙の場合
会場は フレックス 入力パターンは無視され、入力内のトークンが一致します
場合を問わず。 で指定された一致したテキスト yyテキスト 保存ケースをお付けします
(つまり、折りたたまれません)。
-l、 --lex-compat
元の AT&T との最大限の互換性をオンにします LEX 実装。 ノート
これは意味がないこと 全体像を 互換性。 このオプションを使用すると、
かなりの量のパフォーマンスであり、 -+、 -NS、 -NS、 -Cf、
or -CF オプション。 提供される互換性の詳細については、セクションを参照してください。
以下の「Lex および POSIX との非互換性」。 このオプションは、名前にもなります
YY_FLEX_LEX_COMPAT 生成されたスキャナーで #define されています。
-n POSIX 準拠のためだけに含まれている、もう XNUMX つの何もしない非推奨のオプションです。
-NS、 --perf-レポート
stderr にパフォーマンス レポートを生成します。 レポートはコメントで構成されています
の特徴について フレックス 重大な損失を引き起こす入力ファイル
得られたスキャナーのパフォーマンス。 フラグを XNUMX 回渡すと、
軽微なパフォーマンスの低下につながる機能に関するコメントを取得します。
の使用に注意してください 拒否する、 %オプション yylineno、 および変数の末尾のコンテキスト (を参照)
以下の欠陥/バグのセクション) は、実質的なパフォーマンスの低下を伴います。
使用 yymore()、 ^ オペレーターと、 -I 旗は軽微なパフォーマンスを伴います
罰則。
-s、 --no-デフォルト
を引き起こす デフォルト ルール (一致しないスキャナ入力がエコーされます 標準出力) ようにするには
抑圧した。 スキャナがどのルールにも一致しない入力に遭遇した場合、
エラーで中止されます。 このオプションは、スキャナの穴を見つけるのに役立ちます
ルールセット。
-NS、 --stdout
指示する フレックス 代わりに、生成したスキャナーを標準出力に書き込みます。
lex.yy.c.
-v、 -詳細
を指定します フレックス に書くべきです stderr に関する統計の要約
それが生成するスキャナー。 統計のほとんどは、カジュアルには無意味です フレックス
ユーザーですが、最初の行はのバージョンを識別します フレックス (報告と同じ -V)、
次の行には、スキャナーを生成するときに使用されるフラグが含まれます。
デフォルトでオンになっています。
-w、 --nowarn
警告メッセージを抑制します。
-NS、 - バッチ
指示する フレックス を生成する バッチ スキャナ、反対 相互作用的 スキャナ
によって生成されます -I (下記参照)。 一般的には、 -B あなたがいるとき 一定 あなたの
スキャナーが対話的に使用されることはなく、 少し よ
それからのパフォーマンス。 あなたの目標が代わりに絞り出すことである場合 たくさん よ
を使用する必要があります。 -参照 or -CF オプション (以下で説明)。
オンにする -B とにかく自動的に。
-NS、 - 速い
は、 速いです スキャナ テーブル表現を使用する必要があります (および stdio
バイパスされます)。 この表現は、完全なテーブル表現とほぼ同じくらい高速です
(-f)、 一部のパターンのセットでは、かなり小さくなります (他のセットでは、
大きい)。 一般に、パターン セットに「キーワード」とキャッチオールの両方が含まれている場合、
次のような「識別子」ルール:
「ケース」はTOK_CASEを返します。
"スイッチ" return TOK_SWITCH;
...
「デフォルト」はTOK_DEFAULTを返します。
[az]+ TOK_ID を返します。
その場合は、完全なテーブル表現を使用することをお勧めします。 もしも
「識別子」ルールが存在し、ハッシュテーブルなどを使用して検出します
キーワード、あなたは使用する方が良いです -NS。
このオプションは以下と同等です -CFr (下記参照)。 とは併用できません -+。
-私、 - 相互の作用
指示する フレックス を生成する 相互作用的 スキャナー。 対話型スキャナーはその XNUMX つです。
絶対に必要な場合にのみ、どのトークンが一致したかを判断するために先を見越します。
スキャナが
現在のトークンのあいまいさを解消するのに十分なテキストが既に表示されているため、
必要なときだけ前を見る。 しかし、常に先を見据えるスキャナーは、
恐ろしいインタラクティブなパフォーマンス。 たとえば、ユーザーが改行を入力すると、
入力するまで改行トークンとして認識されない 別の トークンは、多くの場合、
別の行全体を入力します。
硬さ(フレックス Flex) スキャナのデフォルト 相互作用的 を使用しない限り、 -参照 or -CF テーブル-
圧縮オプション (以下を参照)。 それは、あなたが高いものを探しているなら、
これらのオプションのいずれかを使用する必要があります。 フレックス
直感的な操作のために実行時のパフォーマンスを少し犠牲にすることを前提としています
インタラクティブな動作。 あなたにも注意してください つかいます -I と一緒に -参照 or
-CF。 したがって、このオプションは実際には必要ありません。 それらすべてに対してデフォルトでオンになっています
許されるケース。
もし isatty() スキャナー入力に対して false を返し、flex はに戻ります
バッチモード -I が指定されました。 何があってもインタラクティブモードを強制するには、
つかいます %オプション 常にインタラクティブ (以下のオプションを参照)。
スキャナに強制的に を使用してインタラクティブにする -B (上記を参照)。
-L、 --ノリン
指示する フレックス 生成しない #ライン ディレクティブ。 このオプションがないと、 フレックス ピーマン
#line ディレクティブを使用して生成されたスキャナーなので、アクションのエラー メッセージは
元の フレックス 入力ファイル (
エラーは入力ファイルのコードによるものです)、または lex.yy.c (エラーが フレックス
エラー -- この種のエラーは、以下に示す電子メール アドレスに報告する必要があります)。
-NS、 - 痕跡
MAKES フレックス 駆け込む トレース モード。 に多くのメッセージを生成します。 stderr
入力の形式と結果の非決定論的および
決定論的有限オートマトン。 このオプションは主にメンテナンスに使用されます フレックス。
-V、 - バージョン
バージョン番号をに出力します (Linuxで言うところのstdout) 終了します。 - バージョン の同義語です -V。
-7、 --7ビット
指示する フレックス 7 ビット スキャナ、つまり認識のみ可能なスキャナを生成します。
入力の 7 ビット文字。 使用する利点 -7 それはスキャナーの
テーブルは、 -8 オプション(を参照)
未満)。 不利な点は、そのようなスキャナーは、入力時にハングまたはクラッシュすることが多いことです。
8 ビット文字が含まれています。
ただし、 -参照 or -CF テーブル
圧縮オプション、使用 -7 少量のテーブルスペースしか節約できません。
スキャナーの携帯性が大幅に低下します。 フレックスさん デフォルトの動作は
を使用しない限り、8 ビット スキャナを生成します。 -参照 or -CF、 その場合 フレックス
サイトが常に構成されていない限り、デフォルトで7ビットスキャナーを生成します
8 ビット スキャナを生成します (米国以外のサイトではよくあることです)。 あなたはできる
フラグを調べて、flex が 7 ビットまたは 8 ビットのスキャナを生成したかどうかを判断します
の要約 -v 上記のように出力します。
使用する場合は注意してください -Cfe or -CFe (これらのテーブル圧縮オプションだけでなく、
以下で説明する等価クラス)、flex は依然としてデフォルトで
通常、これらの圧縮オプションを使用すると、完全な 8 ビット テーブルが
7 ビット テーブルよりもそれほど高価ではありません。
-8、 --8ビット
指示する フレックス 8ビットスキャナー、つまり8ビットを認識できるスキャナーを生成する
文字。 このフラグは、次を使用して生成されたスキャナーにのみ必要です。 -参照 or -CF、 as
それ以外の場合、flex はデフォルトで 8 ビット スキャナを生成します。
のディスカッションを参照してください -7 上記の flex のデフォルトの動作とトレードオフ
7 ビット スキャナと 8 ビット スキャナの間。
-+、 --c++
flex が C++ スキャナ クラスを生成することを指定します。 のセクションを参照してください。
詳細については、以下の C++ スキャナーの生成を参照してください。
-C[aefFmr]
テーブル圧縮の程度を制御し、より一般的には、
小型スキャナーと高速スキャナー。
-Ca、 --整列 ("align") 生成されたテーブルでより大きなテーブルをトレードオフするように flex に指示します。
テーブルの要素が優れているため、スキャナーのパフォーマンスが向上します
メモリアクセスと計算のために整列されます。 一部の RISC アーキテクチャでは、フェッチ
ロングワードの操作は、次のような小さなサイズのユニットよりも効率的です。
略語。 このオプションは、スキャナーが使用するテーブルのサイズを XNUMX 倍にすることができます。
-Ce、 --ecs 指示する フレックス 構築する 同値 クラス、 つまり、文字のセット
同一の字句特性を持つ (たとえば、
の数字 フレックス 入力は文字クラス「[0-9]」で、数字「0」、
'1'、...、'9' はすべて同じ等価クラスに入れられます)。 等価クラス
通常、最終的なテーブル/オブジェクト ファイルのサイズが大幅に削減されます (通常、
2 ~ 5 の係数) であり、パフォーマンスの面ではかなり安価です (XNUMX 回の配列ルックアップあたり XNUMX 回)
文字がスキャンされます)。
-参照 は、 全体像を スキャナ テーブルを生成する必要があります - フレックス いけません
同様の遷移関数を利用してテーブルを圧縮する
さまざまな状態。
-CF 代替の高速スキャナー表現 (上記で説明) を指定します。
下 -F フラグ) を使用する必要があります。 このオプションは使用できません -+。
-Cm、 --meta-ecs 指示する フレックス 構築する メタ等価 クラス、 セットです
等価クラス (または等価クラスが使用されていない場合は文字) の
一緒に使うのが一般的です。 メタ等価クラスは、多くの場合、大きな勝利を収めます。
圧縮されたテーブルを使用しますが、パフォーマンスに中程度の影響があります (XNUMX つまたは XNUMX つ)
「if」テストと、スキャンされた文字ごとに XNUMX つの配列ルックアップ)。
-Cr、 - 読んだ 生成されたスキャナーが 標準 I/O ライブラリの使用
(stdio) 入力用。 呼び出す代わりに fread() or getc()、 スキャナーは
読んだ() システムコールにより、システムごとに異なるパフォーマンスが向上します
システムですが、一般的には、使用していない限り、おそらく無視できます -参照 or -CF。
使い方 -Cr たとえば、から読み取ると、奇妙な動作が発生する可能性があります イーイン
スキャナを呼び出す前に stdio (スキャナはテキストを見逃すため)
以前の読み取りは stdio 入力バッファーに残っています)。
-Cr 定義した場合、効果はありません YY_INPUT (上記の生成されたスキャナーを参照してください)。
孤独 -C スキャナ テーブルを圧縮する必要があることを指定しますが、どちらも圧縮しません
等価クラスもメタ等価クラスも使用しないでください。
オプション -参照 or -CF -CM 一緒に意味をなさない - 機会がない
テーブルが圧縮されていない場合のメタ等価クラス。 そうでなければ、
オプションは自由に組み合わせることができ、累積されます。
デフォルト設定は次のとおりです。 -セム、 それを指定するもの フレックス 同等性を生成する必要があります
クラスとメタ等価クラス。 この設定により、最高度の
テーブル圧縮。 実行速度の速いスキャナーは、以下の代償を払ってトレードオフできます。
より大きなテーブルで、次のことが一般的に当てはまります。
最も遅く最小
-セム
-CM
-これ
-C
-C{f,F}e
-C{f,F}
-C{f,F}a
最速&最大
通常、最小のテーブルを持つスキャナーが生成され、コンパイルされることに注意してください。
そのため、開発中は通常、デフォルトの最大値を使用することをお勧めします
圧縮。
-Cfe 多くの場合、プロダクション スキャナーの速度とサイズの間の適切な妥協点です。
-出力、 --outputfile=ファイル
スキャナをファイルに書き込むように flex に指示します 出力 lex.yy.c. もしあなた
組み合わせる -o -t オプションの場合、スキャナが書き込まれます (Linuxで言うところのstdout) しかし、その #ライン
ディレクティブ ( -L 上記のオプション) ファイルを参照 出力。
-プレフィックス、 --prefix=STRING
デフォルトを変更します yy によって使用されるプレフィックス フレックス すべてのグローバルに表示される変数と
代わりに関数名 接頭辞。 たとえば、 -ふー の名前を変更します yyテキスト
〜へ フットテキスト。 また、デフォルトの出力ファイルの名前を 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
イーイン
イレン
イレックス
イリネノ
yout
yy再起動
yyテキスト
yywrap
(C++ スキャナーを使用している場合は、 yywrap yyフレックスレクサー 影響を受けます。)
スキャナー自体の内部では、引き続きグローバル変数を参照できます。
いずれかのバージョンの名前を使用する関数。 しかし、外部的には、彼らは
変更された名前。
このオプションを使用すると、複数の フレックス プログラムを同じに
実行可能。 ただし、このオプションを使用すると名前も変更されることに注意してください。 yywrap()、 だからあなたは今
しなければなりません ルーチンの独自の (適切な名前の) バージョンを提供します。
スキャナ、または使用 %オプション ノイラップ、 とリンクするように -NS もう提供しません
デフォルトであなた。
-スケルトン_ファイル、 --skel=ファイル
デフォルトのスケルトン ファイルをオーバーライドします。 フレックス スキャナーを構築します。
あなたがしていない限り、このオプションは決して必要ありません フレックス メンテナンスまたは開発。
-NS、 --posix-compat
POSIX lex との最大限の互換性。
--yylineno
yylineno で行数を追跡します。
--yyclass=名前
C++ クラスの名前。
--header-file=ファイル
スキャナーに加えて C ヘッダー ファイルを作成します。
--テーブルファイル[=FILE]
テーブルを FILE に書き込みます。
-Dマクロ[=定義]
#define マクロ defn (デフォルトの defn は '1')。
-NS、 --再入可能
リエントラント C スキャナを生成する
--バイソンブリッジ
bison 純粋なパーサー用のスキャナー。
--バイソンの場所
yylloc サポートを含めます。
--stdinit
yyin/yyout を stdin/stdout に初期化します。
--noansi-定義 古いスタイル function 定義。
--noansi-プロトタイプ
プロトタイプの空のパラメータ リスト。
--nounistd
含まない.
--noFUNCTION
特定の FUNCTION を生成しないでください。
フレックス スキャナ仕様内のオプションを制御するためのメカニズムも提供します
flex コマンドラインからではなく、それ自体。 これは、含めることによって行われます %オプション
スキャナ仕様の最初のセクションのディレクティブ。 複数指定できます
単一のオプション %オプション ディレクティブ、および最初のセクションの複数のディレクティブ
フレックス入力ファイル。
ほとんどのオプションは単に名前として与えられ、必要に応じて "no" という単語を前に付けます (no
介在する空白) を使用して、その意味を無効にします。 数字はフレックスフラグまたは
それらの否定:
7bit -7 オプション
8bit -8 オプション
align -Ca オプション
バックアップ -b オプション
バッチ -B オプション
c++ -+ オプション
ケースフルまたは
大文字と小文字を区別 -i の反対 (デフォルト)
大文字と小文字を区別しないまたは
ケースレス -i オプション
デバッグ -d オプション
-s オプションのデフォルトの反対
ecs -Ce オプション
高速 -F オプション
フル -f オプション
インタラクティブ -I オプション
lex-compat -l オプション
meta-ecs -Cm オプション
perf-report -p オプション
-Cr オプションを読む
stdout -t オプション
詳細 -v オプション
-w オプションの反対を警告する
(-w には "%option noarn" を使用)
「%array」に相当する配列
"%pointer" に相当するポインタ (デフォルト)
一部 %オプション 他の方法では利用できない機能を提供します:
常にインタラクティブ
常にその入力を考慮するスキャナーを生成するように flex に指示します
"相互の作用"。 通常、スキャナーが呼び出す新しい入力ファイルごとに isatty() で
スキャナの入力ソースがインタラクティブかどうかを判断しようとするため、
一度に XNUMX 文字ずつ読み取る必要があります。 ただし、このオプションを使用すると、
このような呼び出しが行われます。
メイン デフォルトを提供するように flex に指示します メイン() スキャナー用のプログラム。
呼び出し yylex()。 このオプションは、 ノイラップ (下記参照)。
インタラクティブでない
入力を「インタラクティブ」と見なさないスキャナーを生成するように flex に指示します。
(繰り返しますが、呼び出しは行われません isatty())。 これはその逆です 常にインタラクティブ。
スタック 開始条件スタックの使用を有効にします (上記の開始条件を参照)。
標準単位
設定されている場合 (つまり、 %オプション 標準単位) 初期化する イーイン yout 〜へ stdin 標準出力、
デフォルトの代わりに なし。 一部既存 LEX プログラムはこの動作に依存し、
ANSI C には準拠していませんが、 stdin
(Linuxで言うところのstdout) コンパイル時定数であること。
イリネノ
指示する フレックス 現在の行の番号を維持するスキャナーを生成する
グローバル変数の入力から読み取る yylineno。 このオプションは、
%オプション レックス互換。
yywrap 設定されていない場合 (つまり、 %オプション noyywrap)、 スキャナーが呼び出されないようにする yywrap() 終わりに—
of-file ですが、スキャンするファイルがこれ以上ないと仮定します (ユーザーが
ポイント イーイン 新しいファイルと呼び出しで yylex() 再び)。
フレックス ルール アクションをスキャンして、 拒否 or yymore() 機能。
当学校区の 拒否する イモレ オプションを使用して、使用するかどうかに関する決定をオーバーライドすることができます
オプションを設定します (例: %オプション 拒絶) 機能が
実際に使用されているか、実際には使用されていないことを示すためにそれらを設定解除します (例: %オプション
うるさい)。
XNUMX つのオプションは文字列で区切られた値を取り、「=」でオフセットします。
%option outfile="ABC"
に相当します -oABC、
%option prefix="XYZ"
に相当します -PXYZ。 最後に、
%option yyclass="foo"
C++ スキャナーを生成する場合にのみ適用されます ( -+ オプション)。 それは知らせる フレックス あなたは持っている
派生 foo のサブクラスとして yyFlexLexer、 so フレックス あなたのアクションをメンバーに配置します
function foo::yylex() yyFlexLexer::yylex()。 また、
yyFlexLexer::yylex() 実行時エラーを発行するメンバー関数 (呼び出しによる)
yyFlexLexer::LexerError()) 呼び出された場合。 詳細については、以下の C++ スキャナーの生成を参照してください。
情報を表示します。
糸くずの出現を抑えたい純粋主義者のために、多くのオプションが用意されています。
生成されたスキャナーの不要なルーチン。 設定されていない場合は、次のそれぞれ (例:
%オプション 入力なし )、対応するルーチンが生成された
スキャナー:
入力、出力
yy_push_state、yy_pop_state、yy_top_state
yy_scan_buffer、yy_scan_bytes、yy_scan_string
(しかし yy_push_state() 使用しない限り、とにかく友達は表示されません %オプション スタック)。
パフォーマンスとは 考慮事項
の主な設計目標 フレックス 高性能スキャナーを生成することです。 それはそうだった
ルールの大規模なセットを適切に処理するために最適化されています。 スキャナーへの影響は別として
テーブル圧縮の速度 -C 上記で概説したオプションがいくつかあります
パフォーマンスを低下させるオプション/アクション。 これらは、最も高価なものから最も安価なものまでです。
拒否
%オプションyylineno
任意の後続コンテキスト
バックアップが必要なパターン セット
%配列
%option インタラクティブ
%option 常にインタラクティブ
'^' 行頭演算子
yymore()
最初の XNUMX つはすべて非常に高価で、最後の XNUMX つは非常に安価です。 ノート
それも 入力() 潜在的にかなりのことを行うルーチン呼び出しとして実装されています
仕事しながら yyless() 非常に安価なマクロです。 余分なテキストを元に戻すだけなら
スキャンして使う yyless()。
拒否 パフォーマンスが重要な場合は、絶対に避ける必要があります。 それは特に
高価なオプション。
バックアップをなくすのは面倒で、多くの場合、膨大な量の作業になる可能性があります。
複雑なスキャナー。 原則として、人は -b を生成するフラグ
lex.バックアップ ファイル。 たとえば、入力では
%%
foo は TOK_KEYWORD を返します;
foobar return TOK_KEYWORD;
ファイルは次のようになります:
状態 #6 は受け入れられません -
関連するルールの行番号:
2 3
アウトトランジション: [ o ]
ジャムトランジション: EOF [ \001-n p-\177 ]
状態 #8 は受け入れられません -
関連するルールの行番号:
3
アウトトランジション: [ a ]
ジャムトランジション: EOF [ \001-` b-\177 ]
状態 #9 は受け入れられません -
関連するルールの行番号:
3
アウトトランジション: [ r ]
ジャムトランジション: EOF [ \001-q s-\177 ]
圧縮されたテーブルは常にバックアップされます。
最初の数行は、遷移可能なスキャナー状態があることを示しています。
'o' ではなく、他の文字ではなく、その状態で現在スキャンされている
テキストはどのルールとも一致しません。 で見つかったルールに一致させようとすると、状態が発生します。
入力ファイルの 2 行目と 3 行目。 スキャナがその状態にあり、何かを読み取った場合
「o」以外の場合、一致するルールを見つけるためにバックアップする必要があります。 少しで
頭を悩ませていると、これが「fo」を見たときの状態に違いないことがわかります。
これが発生した場合、別の「o」以外のものが見られる場合、スキャナーは
単純に「f」に一致するようにバックアップします (デフォルト ルールによる)。
State #8 に関するコメントは、「foob」がスキャンされたときに問題があることを示しています。
実際、「a」以外の文字では、スキャナは受け入れるためにバックアップする必要があります
「ふー」。 同様に、State #9 のコメントは、"fooba" がスキャンされ、
'r' は続きません。
最後のコメントは、削除するのに苦労しても意味がないことを思い出させてくれます
使用していない限り、ルールからバックアップします -参照 or -CF、 パフォーマンスが上がらないので
圧縮スキャナーでそうします。
バックアップを削除する方法は、「エラー」ルールを追加することです。
%%
foo は TOK_KEYWORD を返します;
foobar return TOK_KEYWORD;
フーバ |
フーブ |
フォ{
/* 誤った警告、実際にはキーワードではありません */
TOK_ID を返します。
}
キーワードのリスト間でのバックアップをなくすには、「キャッチオール」ルールを使用することもできます。
%%
foo は TOK_KEYWORD を返します;
foobar return TOK_KEYWORD;
[az]+ TOK_ID を返します。
これは通常、適切な場合に最適なソリューションです。
メッセージのバックアップはカスケードする傾向があります。 複雑な一連のルールを使用することは珍しくありません
何百ものメッセージを受け取ります。 ただし、それらを解読できれば、多くの場合、XNUMXダースしかかかりません
またはバックアップを排除するためのルール (ただし、間違いを犯しやすく、
エラー ルールが誤って有効なトークンと一致しました。 あり得る未来 フレックス 機能は
自動的にルールを追加してバックアップを排除します)。
バックアップのみを排除することでメリットが得られることを覚えておくことが重要です。
排除すれば あらゆる バックアップのインスタンス。 XNUMXつだけ残すということは、何も得られないということです。
変数 後続のコンテキスト (先行部分と後続部分の両方が固定されていない場合)
長さ) は、ほぼ同じパフォーマンス損失を伴います。 拒否 (すなわち、実質的)。 そうするとき
次のような規則が考えられます。
%%
マウス|ラット/(猫|犬) run();
より良く書かれています:
%%
マウス/猫|犬の実行();
ラット/猫|ドッグラン();
またはとして
%%
マウス|ラット/猫の実行();
マウス|ラット/犬の実行();
ここで特別な「|」に注意してくださいアクションは あらゆる節約を提供し、
さらに悪いこと (以下の欠陥/バグを参照)。
ユーザーがスキャナーのパフォーマンスを向上できる別の領域 (およびより簡単に
実装) は、トークンが一致する時間が長いほど、スキャナーが高速になるという事実から生じます。
実行されます。 これは、長いトークンを使用すると、ほとんどの入力文字の処理に時間がかかるためです。
(短い)内側のスキャンループに配置され、多くの場合、ループを通過する必要はありません
スキャン環境を設定する追加作業 (例: yyテキスト) アクションのために。
C コメントのスキャナーを思い出してください。
%x コメント
%%
int line_num = 1;
"/*" BEGIN(コメント);
[^*\n]*
"*"+[^*/\n]*
\n ++line_num;
"*"+"/" BEGIN(頭文字);
これは、次のように書くことで高速化できます。
%x コメント
%%
int line_num = 1;
"/*" BEGIN(コメント);
[^*\n]*
[^*\n]*\n ++line_num;
"*"+[^*/\n]*
"*"+[^*/\n]*\n ++line_num;
"*"+"/" BEGIN(頭文字);
各改行が別のアクションの処理を必要とする代わりに、
改行は、一致したテキストを保持するために、他のルールに「分散」されます。
可能。 ご了承ください 追加 ルールは スキャナーの速度を落としてください! の速度
スキャナーは、ルールの数または (モジュールで与えられた考慮事項による) とは無関係です。
このセクションの冒頭) などの演算子に関してルールがどれほど複雑か
「*」と「|」。
スキャナーを高速化する最後の例: ファイルをスキャンしたいとします。
識別子とキーワードを XNUMX 行に XNUMX つずつ含み、その他の余分な文字を含まない、
すべてのキーワードを認識します。 自然な最初のアプローチは次のとおりです。
%%
アスム |
自動 |
休憩 |
...など..。
揮発性 |
while /* キーワードです */
.|\n /* キーワードではありません */
バックトラッキングをなくすには、キャッチオール ルールを導入します。
%%
アスム |
自動 |
休憩 |
...など..。
揮発性 |
while /* キーワードです */
[az]+ |
.|\n /* キーワードではありません */
ここで、XNUMX 行に XNUMX つの単語が含まれていることが保証されている場合は、
改行の認識を
他のトークン:
%%
asm\n |
自動\n |
休憩\n |
...など..。
揮発性\n |
while\n /* キーワードです */
[az]+\n |
.|\n /* キーワードではありません */
スキャナへのバックアップを再導入したため、ここでは注意が必要です。 の
特に、 we 入力ストリームに文字が存在しないことを知っている
文字または改行以外の、 フレックス これを理解することはできません。
「auto」のようなトークンをスキャンしたときにバックアップする必要があり、次の文字が
改行または文字以外のもの。 以前は、
「auto」ルールで実行されますが、現在は「auto」ルールがなく、「auto\n」ルールのみです。 に
バックアップの可能性を排除するには、すべてのルールを複製することもできますが、
最後の改行、または、そのような入力に遭遇することは決してないため、
それがどのように分類されるか、もう XNUMX つのキャッチオール ルールを導入できます。
改行を含める:
%%
asm\n |
自動\n |
休憩\n |
...など..。
揮発性\n |
while\n /* キーワードです */
[az]+\n |
[az]+ |
.|\n /* キーワードではありません */
でコンパイルされました -Cf、 これは、人が得ることができるのとほぼ同じ速さです フレックス これに行くスキャナー
特定の問題。
最後のメモ: フレックス NUL に一致する場合、特にトークンに
複数の NUL。 一致するルールを書くのが最善です 短い ある場合のテキストの量
多くの場合、テキストには NUL が含まれることが予想されます。
パフォーマンスに関するもう XNUMX つの最後の注意事項: 上記の「入力方法」セクションで説明したように
is Matched、動的にサイズ変更 yyテキスト 巨大なトークンに対応するのは遅いプロセスです
現在、(巨大な)トークンを最初から再スキャンする必要があるためです。 したがって
パフォーマンスが重要な場合は、「大量の」テキストの一致を試みる必要がありますが、そうではありません。
8 つの間のカットオフが約 XNUMXK 文字/トークンである「巨大な」量。
生成 C + + スキャナー
フレックス C++ で使用するスキャナーを生成する XNUMX つの異なる方法を提供します。 最初の方法は
によって生成されたスキャナーを単純にコンパイルするには フレックス C の代わりに C++ コンパイラを使用する
コンパイラ。 コンパイル エラーが発生することはありません (見つかった場合は報告してください)。
以下の著者セクションに記載されている電子メールアドレス)。 その後、C++ コードを
C コードの代わりにルール アクション。 スキャナのデフォルトの入力ソースは
残っている 陰、 デフォルトのエコーは引き続き行われます うん。 これはどちらも残る FILE *
変数であり、C++ ではありません ストリーム。
使用することもできます フレックス を使用して、C++ スキャナー クラスを生成します。 -+ オプション (または、
同等に、 %オプション c++)、 フレックスの名前の場合に自動的に指定されます
実行可能ファイルは「+」で終わります。 フレックス++. このオプションを使用する場合、flex のデフォルトは
スキャナーをファイルに生成する lex.yy.cc lex.yy.c. 生成されたスキャナー
ヘッダファイルを含む FlexLexer.h、 これは、XNUMX つの C++ クラスへのインターフェイスを定義します。
ファーストクラス、 フレックスレクサー、 一般的なスキャナを定義する抽象基本クラスを提供します
クラス インターフェイス。 次のメンバー関数を提供します。
定数 char * YYText()
最後に一致したトークンのテキストを返します。 yyテキスト。
int型 YYLeng()
最後に一致したトークンの長さを返します。 イレン。
int型 ライン番号() 定数
現在の入力行番号を返します (を参照してください %オプション yylineno)、 or 1 if %オプション
イリネノ 使用されませんでした。
ボイド set_debug( int型 フラグ )
スキャナのデバッグ フラグを設定します。 yy_flex_debug
(上記のオプションセクションを参照してください)。 を使用してスキャナーを構築する必要があることに注意してください
%オプション debug デバッグ情報を含めることができます。
int型 デバッグ() 定数
デバッグフラグの現在の設定を返します。
と同等のメンバー関数も提供されます。 yy_switch_to_buffer()、 yy_create_buffer()
(ただし、最初の引数は std::istream* オブジェクトポインタであり、 ファイル*)、
yy_flush_buffer()、 yy_delete_buffer()、 yyrestart() (繰り返しますが、最初の引数は
std::istream* オブジェクト ポインター)。
で定義された XNUMX 番目のクラス FlexLexer.h is yyFlexLexer、 から派生しています フレックスレクサー。
次の追加メンバー関数を定義します。
yyFlexLexer( std::istream* arg_yyin = 0, std::ostream* arg_yyout = 0 )
を構築します yyフレックスレクサー 入力と出力に指定されたストリームを使用するオブジェクト。 もしも
指定されていない場合、ストリームはデフォルトで CIN カウト、 。
バーチャル int型 yylex()
と同じ役割を果たします yylex() 通常の flex スキャナの場合:
ルールのアクションが値を返すまで、トークンを消費する入力ストリーム。 もし、あんたが
サブクラスを派生させる S from yyフレックスレクサー メンバー関数にアクセスしたい
の変数 S 内部 yylex()、 それなら使う必要があります %オプション yyclass="S" 通知する
フレックス 代わりにそのサブクラスを使用すること yyFlexLexer。 この場合、
生成するのではなく yyFlexLexer::yylex()、 フレックス 生成 S::yylex() (そしてまた
ダミーを生成する yyFlexLexer::yylex() それは呼び出す yyFlexLexer::LexerError() if
と呼ばれます)。
バーチャル ボイド switch_streams(std::istream* new_in = 0,
std::ostream* 新しい出力 = 0) 再割り当てする イーイン 〜へ new_in (非 nil の場合) および yout 〜へ
新しい出力 (同上)、前の入力バッファを削除する場合 イーイン 再割り当てされます。
int型 イレックス( std::istream* new_in、 std::ostream* 新しい出力 = 0 )
最初に入力ストリームを切り替えます switch_streams( new_in、 新しい出力 ) その後
の値を返します yylex()。
加えて、 yyフレックスレクサー 次の保護された仮想機能を定義します。
スキャナーを調整するために派生クラスで再定義します。
バーチャル int型 レクサー入力( char * バフ、 int型 最大サイズ )
まで読みます 最大サイズ 文字をに BUF 読み取った文字数を返します。
入力の終わりを示すには、0 文字を返します。 「インタラクティブな」スキャナーに注意してください
(参照 -B -I flags) マクロを定義する YY_INTERACTIVE。 再定義すると
LexerInput() かどうかに応じて、さまざまなアクションを実行する必要があります。
スキャナーがインタラクティブな入力ソースをスキャンしている可能性がある場合は、
この名前の存在 #ifdef。
バーチャル ボイド レクサー出力( 定数 char * バフ、 int型 サイズ )
書き出す サイズ バッファからの文字 バフ、 これは、NUL で終了している間、
スキャナのルールがテキストを NUL と一致させることができる場合、「内部」NUL も含みます。
それら。
バーチャル ボイド レクサーエラー( 定数 char * MSG )
致命的なエラー メッセージを報告します。 この関数のデフォルト バージョンは、
ストリームへのメッセージ CERR 終了します。
そのAに注意してください。 yyフレックスレクサー オブジェクトにはその 全体 スキャン状態。 したがって、そのようなものを使用できます
オブジェクトを使用してリエントラント スキャナーを作成します。 同じものの複数のインスタンスをインスタンス化できます
yyフレックスレクサー クラスで、複数の C++ スキャナー クラスを組み合わせることもできます。
を使用した同じプログラム -P 上で説明したオプション。
最後に、注意してください %配列 この機能は C++ スキャナー クラスでは使用できません。 絶対です
つかいます %ポインタ (デフォルト)。
以下は、単純な C++ スキャナーの例です。
// Flex C++ スキャナ クラスの使用例。
%{
int mylineno = 0;
%}
文字列 \"[^\n"]+\"
ws [\t]+
アルファ [A-Za-z]
[0-9] を掘る
名前 ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
数 {num1}|{num2}
%%
{ws} /* 空白とタブをスキップします */
"/*" {
int c;
while((c = yyinput()) != 0)
{
if(c == '\n')
++ミリネノ;
それ以外の場合 (c == '*')
{
if((c = yyinput()) == '/')
破る;
ほかに
入力(c);
}
}
}
{数値} cout << "数値" << YYText() << '\n';
\n mylineno++;
{名前} cout << "名前" << YYText() << '\n';
{string} cout << "string " << YYText() << '\n';
%%
int main( int /* argc */, char** /* argv */ )
{
FlexLexer* lexer = 新しい yyFlexLexer;
while(lexer->yylex() != 0)
;
0リターン;
}
複数の (異なる) レクサー クラスを作成する場合は、 -P フラグ (または
接頭語= オプション) それぞれの名前を変更します yyフレックスレクサー 他の人に xxフレックスレクサー。 その後、次のことができます
include レクサークラスごとにXNUMX回、他のソースで、最初に名前を変更します
yyフレックスレクサー 次のように:
#undef yyFlexLexer
#定義 yyFlexLexer xxFlexLexer
#含む
#undef yyFlexLexer
#定義 yyFlexLexer zzFlexLexer
#含む
たとえば、使用した場合 %オプション 接頭辞="xx" スキャナの XNUMX つと %オプション
接頭辞="zz" 他のために。
重要: 現在のスキャニング クラスの形式は次のとおりです。 実験的 および変更される場合があります
メジャーリリース間でかなり。
非互換性 WITH LEX そして POSIX
フレックス AT&T Unix の書き直しです。 LEX ツール (XNUMX つの実装は、
コード、ただし)、いくつかの拡張機能と非互換性があり、どちらも懸念事項です
どちらの実装でも受け入れられるスキャナを書きたい人。 フレックスは完全に
POSIXに準拠 LEX 仕様、使用時以外 %ポインタ (デフォルト)、
への電話 入力() の内容を破壊します yytext、 これはPOSIXに反しています
仕様。
このセクションでは、flex と AT&T の間の既知の非互換性について説明します。
lex、および POSIX 仕様。
フレックス -l オプションは、元の AT&T との最大限の互換性を有効にします LEX 実装、
生成されたスキャナーのパフォーマンスが大幅に低下します。 以下に注意してください
非互換性は、 -l オプションを選択します。
フレックス 完全に互換性があります LEX 以下の例外があります。
- 文書化されていない LEX スキャナ内部変数 イリネノ ない限りサポートされません。 -l
or %オプション イリネノ 使用されている。
イリネノ スキャナーごとではなく、バッファーごとに維持する必要があります
(単一のグローバル変数)ベース。
イリネノ POSIX 仕様の一部ではありません。
- 入力() ルーチンは再定義できませんが、文字を読み取るために呼び出すことはできます
ルールによって一致したものすべてに従います。 もしも 入力() 終わりに遭遇する
通常のファイル yywrap() 処理が行われます。 「本当の」ファイルの終わりが返されます
入力() as 終了後。
入力は代わりに、 YY_INPUT マクロ。
当学校区の フレックス という制限 入力() 再定義することはできません
POSIX 仕様。
への初期割り当てを行う以外のスキャナーの入力 陰。
- 入力() ルーチンは再定義できません。 この制限は、
POSIX。
- フレックス スキャナーは再入可能ではありません LEX スキャナー。 特に、
対話型スキャナーと、スキャナーからロングジャンプする割り込みハンドラー、
その後、スキャナーが再度呼び出されると、次のメッセージが表示される場合があります。
致命的な flex スキャナの内部エラー -- バッファの終わりがありません
スキャナーに再度入るには、最初に使用します
yyrestart( yyin );
この呼び出しは、バッファリングされた入力を破棄することに注意してください。 通常、これは
対話型スキャナの問題。
また、フレックス C++ スキャナー クラスにも注意してください。 再入可能であるため、C++ の使用がオプションである場合
代わりにそれらを使用する必要があります。 詳しくは、上記の「C++ スキャナーの生成」を参照してください。
詳細。
- 出力() はサポートされていません。 からの出力 エコー マクロはファイルポインタに対して実行されます
yout (デフォルト stdout)。
出力() POSIX 仕様の一部ではありません。
- LEX 排他的開始条件 (%x) はサポートしていませんが、POSIX にはあります。
仕様。
- 定義を展開すると、 フレックス それらを括弧で囲みます。 レックスでは、
次のとおりです。
名前 [AZ][A-Z0-9]*
%%
フー{名前}? printf( "見つかりました\n" );
%%
マクロが展開されるとルールが
「foo[AZ][A-Z0-9]*?」と同等優先順位は「?」 は
「[A-Z0-9]*」に関連付けられています。 と フレックス、 ルールは "foo([AZ][A-
Z0-9]*)?" であるため、文字列 "foo" が一致します。
定義が ^ またはで終わります $ それは 拡大
括弧を使用して、これらの演算子を失わずに定義に表示できるようにします
それらの特別な意味。 しかし 、 /, < > 演算子は使用できません
フレックス 定義。
使い方 -l 結果は LEX 定義の周りに括弧がない場合の動作。
POSIX 仕様では、定義を括弧で囲む必要があります。
- いくつかの実装 LEX ルールのアクションを別の行で開始できるようにします。
ルールのパターンには末尾の空白があります:
%%
フー|バー
{ foobar_action(); }
フレックス この機能はサポートしていません。
- LEX %r (Ratfor スキャナーを生成する) オプションはサポートされていません。 一部ではありません
POSIX 仕様。
- 電話をかけた後 入力()、 yyテキスト 次のトークンが一致するまで未定義です。
スキャナが以下を使用して構築されていない限り %配列。 これは当てはまりません LEX または
POSIX 仕様。 の -l オプションは、この非互換性を排除します。
- の優先順位 {} (数値範囲)演算子が異なります。 LEX 解釈する
"abc{1,3}" は "'abc' の XNUMX、XNUMX、または XNUMX 回の出現に一致する" として、 フレックス
は、「'ab' の後に XNUMX 回、XNUMX 回、または XNUMX 回の 'c' が続く」と解釈します。
後者は POSIX 仕様に準拠しています。
- の優先順位 ^ オペレーターが違います。 LEX "^foo|bar" を "マッチ" と解釈します
行頭の 'foo' または任意の場所の 'bar' のいずれか" フレックス
'foo' または 'bar' のいずれかに一致すると解釈します。
行」。後者は POSIX 仕様に準拠しています。
- 次のような特別なテーブルサイズ宣言 %a による支援 LEX によって必要とされない
フレックス スキャナー; フレックス それらを無視します。
- 名前 FLEX_SCANNER #define されているため、スキャナーはどちらでも使用できるように作成できます
フレックス or lex。 スキャナーには以下も含まれます YY_FLEX_MAJOR_VERSION YY_FLEX_MINOR_VERSION
どのバージョンの フレックス スキャナーを生成しました (たとえば、2.5
リリースでは、これらの定義はそれぞれ 2 と 5 になります)。
以下 フレックス 機能は含まれていません LEX またはPOSIX仕様:
C++ スキャナー
%オプション
開始条件スコープ
開始条件スタック
インタラクティブ/非インタラクティブ スキャナー
yy_scan_string() と仲間たち
yyterminate()
yy_set_interactive()
yy_set_bol()
YY_AT_BOL()
< >
<*>
YY_DECL
YY_START
YY_USER_ACTION
YY_USER_INIT
#line ディレクティブ
%{} の周りのアクション
XNUMX 行で複数のアクション
加えて、ほとんどすべてのフレックスフラグ。 リストの最後の機能は、
フレックス セミコロンで区切って同じ行に複数のアクションを入れることができます。
lex、 次
foo ハンドル_foo(); ++num_foos_seen;
(かなり驚くべきことに) に切り捨てられます
foo ハンドル_foo();
フレックス アクションを切り捨てません。 中括弧で囲まれていないアクションは単純に
行の最後で終了します。
診断
警告、 ルール be マッチ 指定されたルールが一致しないことを示します。
常に同じテキストに一致する他のルールに従います。 たとえば、
次の「foo」は、識別子「catch-all」ルールの後にあるため、一致できません。
[az]+ got_identifier();
foo got_foo();
使い方 拒否 スキャナーでは、この警告を抑制します。
警告、 -s オプション 与えられた 焙煎が極度に未発達や過発達のコーヒーにて、クロロゲン酸の味わいへの影響は強くなり、金属を思わせる味わいと乾いたマウスフィールを感じさせます。 デフォルト ルール できる be マッチ 可能であることを意味します
(おそらく特定の開始条件でのみ)デフォルトのルール(任意の単一の条件に一致)
character) は、特定の入力に一致する唯一のものです。 以来 -s 与えられた、
おそらくこれは意図したものではありません。
使用済みだが検出されないことを拒否 未定義 or yymore_used_not_detected 未定義 - ボーマン
コンパイル時にエラーが発生する可能性があります。 それらは、スキャナーが使用することを示します 拒否 or yymore()
でもあの フレックス その事実に気付かなかった、つまり フレックス 最初の XNUMX つのセクションをスキャンしました
これらのアクションの発生を探して何も見つかりませんでしたが、どういうわけかあなたはこっそり
いくつか (たとえば、#include ファイルを介して)。 使用 %オプション 拒否する or %オプション イモレ 〜へ
これらの機能を実際に使用していることを flex に示します。
フレックス スキャナー 詰まった - でコンパイルされたスキャナ -s 入力文字列に遭遇しました
どのルールにも一致しませんでした。 このエラーは、内部の問題が原因で発生することもあります。
トークン あまりに 大、 超え イルマックス - スキャナーが使用する %配列 そのルールの XNUMX つが
よりも長い文字列 イルマックス 定数 (デフォルトで 8K バイト)。 値を増やすことができます
#定義することによって イルマックス あなたの定義セクションで フレックス 入力。
スキャナー 必要 -8 フラグ 〜へ つかいます 文字 'バツ' - スキャナの仕様には次のものが含まれます
8ビット文字の認識 'バツ' -8 フラグを指定しておらず、スキャナ
を使用したため、デフォルトで 7 ビットに設定されています。 -参照 or -CF テーブル圧縮オプション。 を参照してください
の議論 -7 詳細については、フラグをご覧ください。
フレックス スキャナー プッシュバック オーバーフロー - 使いました 入力() 非常に多くのテキストを押し戻すため、
スキャナーのバッファーは、プッシュバックされたテキストと現在のトークンの両方を保持できませんでした yyテキスト。
この場合、スキャナはバッファのサイズを動的に変更する必要がありますが、現時点では
ではない。
バッファ オーバーフロー、 することはできません 大きくする バッファ なぜなら スキャナー 使用されます 拒否 - スキャナーは
非常に大きなトークンの照合に取り組んでおり、入力バッファを拡張する必要がありました。 この
を使用するスキャナーでは機能しません。 拒絶。
致命的な フレックス スキャナー 内部 エラー -- 終了 of バッファ 逃した - これはスキャナで発生する可能性があります
ロングジャンプがスキャナーのアクティベーションを飛び越えた(または飛び越えた)後に再入力されます
フレーム。 スキャナーに再度入る前に、次を使用します。
yyrestart( yyin );
または、前述のように、C++ スキャナー クラスの使用に切り替えます。
あまりに 多くの start 条件 in <> 構築してください! - <> に開始条件を追加しました
存在するよりも構成します (したがって、それらの少なくとも XNUMX つを XNUMX 回リストする必要があります)。
onworks.net サービスを使用して freebsd-lex をオンラインで使用する