ここで非常に簡単にではありますが、 FlexとLexの両方を概観してみます。 Flex、Lexそれぞれの性能と、 Lexのようなユーティリティに関するPOSIX標準への準拠度についても、 いくつか一般的なコメントを示します。
Flexは、 Lexのより優れた再実装であり、 Lexと同様、 パターンとアクションの記述情報を入力として受け取って、 そのパターンにマッチする能力を持つCのスキャナに変換するものです。 しかしながら、 Flexはより少ない時間でテーブルを生成しますし、 Flexにより生成されるテーブルは、 Lexにより生成されるテーブルと比較して、 はるかに効率的なものです。 (Flexが正確には何を生成するのかという説明については、 このマニュアルの冒頭で言及した書籍を参照してください。)
Flexは、 LexおよびPOSIXと十分に互換性があり、 それ独自の特別な機能もいくつか追加しています。
Flexは、 大体のところLexおよびPOSIXの両方と互換性があります。 将来は (Flex、POSIXのどちらかが変わることによって)、 さらにPOSIXとの互換性を高めていくでしょう。 しかし、 Flex、Lex、POSIXには、 異なる部分もいくつかあります。 それを以下に示します。
input()
input()
は再定義可能ではありません。
Flexで入力を制御するためには、
input()
を再定義する代わりに、
YY_INPUT
という拡張機能を使います
(これは現在のところPOSIXではサポートされていません)。
また、
Lexとは異なり、
Flexのinput()
はyytext
の値を変更するという点に注意してください。
output()
output()
ルーチンをサポートしていません。
ECHO
の出力はyyout
経由で行われます。
このyyout
のデフォルトはstdout
です。
これを使うようにoutput()
を書くことも可能ですが、
現在のPOSIXのドラフト仕様は、
output()
が正確には何をすべきなのかを示していません。
%r
)をサポートしていません。
yylineno
yywrap()
yywrap()
はマクロです。
POSIXのドラフト仕様では、
これは関数であるべきとされていますので、
おそらく将来は変更されることになるでしょう。(18)
unput()
unput()
はyytext
とyyleng
の値を破壊しますが、
次のトークンがマッチされるまでは、
これは不当です。
LexとPOSIXでは、
yytext
とyyleng
はunput()
の影響を受けません。(19)
ab
の後ろに1個、2個、または3個のc
が続くもの」
にマッチすべきとなっています。
Flexはこのとおりに動きますが、
Lexはこれを
「1個、2個、または3個のabc
」
と解釈します。
yytext
yytext
の正しい定義は`extern char *yytext'ですが、
Lexでは`extern char yytext[]'です。(20)
配列によるアクセス方法は、
性能にかなりの影響を及ぼすので、
Flexでは`extern char *yytext'を使い続けるでしょう。
最新のPOSIXドラフト仕様は、
`%array'と`%pointer'を導入することによって、
両方の方法をサポートしています。
これは、
FlexとLexのいずれにもまだ組み込まれていません。(21)
%p
、%a
等)がありますが、
Flexでは必要ありません。
互換性のために認識はされますが、
無視されるだけです。
FLEX_SCANNER
FLEX_SCANNER
が#define
によって定義されています。
{...}
を使うことなく、
単一行において複数の文を置くことができます。
これに対してLexは、
そのような行を単一文に切り詰めてしまいます。
yyterminate()
、yyrestart()
、<<EOF>>
、YY_DECL
、#line
指示子
#line
指示子の説明に関しては、
Flex コマンドライン・オプションの要約を参照してください。
Flex 2.5でサポートされている新しい機能のうち、 POSIXの仕様(および、Lex)に存在しないものを以下に列挙します。
C++スキャナ %option指示子 スタート状態スコープ スタート状態スタック yy_scan_string()、yy_scan_bytes()、yy_scan_buffer() yy_set_interactive() yy_set_bol() YY_AT_BOL() <*> YY_START
Lexはスキャナを作成するための標準的なUnixユーティリティであり、 長い歴史を持っています。 LexはFlexと非常によく似ていますが、 スキャナを生成するのにより多くの時間がかかりますし、 Lexの生成するスキャナはFlexの生成するスキャナよりも通常は遅いものです。 Lexは、 特に多くのPOSIX機能を提供していないという理由から、 置き換える必要が大いにあります。 FlexはこうしたPOSIX機能を提供しています。 より多くのコンピュータ・システムがPOSIX互換になるにつれて、 Flexの提供する多くの機能をサポートしなければならなくなり、 このために、 おそらくはFlexがLexの代わりにインストールされるようになるでしょう (例えば、 4.4 BSDリリースはFlexを使うことになります)。 しかし、 Lexがインストールされている少数のシステムがあるために、 しばらくの間はLexの存在は確実に維持されるでしょう。
FlexとLexの大きな違いは、 Flexが性能を考慮して書かれたという点にあります。 一般的には、 Flexを持っているのであればそれを使うべきです。 両者の性能差は、 無視するにはあまりにも大きすぎます。 しかし、 移植性が最も重要なのであれば、 スキャナ定義は可能な限りLexのものに近づけるべきです。 というのは、 Lexは事実上すべてのUnixマシンに入っていることが保証されていますが、 Flexは入っていない可能性があるからです (しかし、 Flexのインストールは通常は取るに足りない作業です)。 このような場合に残念なのは、 FlexとPOSIXが持っている排他的スタート状態のような、 より便利な拡張機能を使うことができなくなるということです。
この問題を回避するためのもう1つの方法は、 Flexでスキャナを作成して、 作成されたスキャナを配布することです。 スキャナというものは一度書かれるとほとんど変更されることがないので、 多くの場合この方法は実行可能です。 仮に変更が必要になったとしても、 プログラムの他の部分も相当変更しなければならない可能性があり、 よってプログラムを更新するための努力全体から見れば、 Flexをインストールすることなどはほんの些細なものでしょう。