前: Another Example of Flex and Bison, 上: Interfacing to Flex


4.6 FlexとC++(Flex 2.5の補足情報)

4.7 FlexとC++(Flex 2.5の補足情報)

Flex 2.5では、 Flexに対するC++インターフェイスが提供されています。

FlexのC++インターフェイスを使うためには、 Flex実行時に`-+'オプションを指定するか、 スキャナ定義ファイルの中で`%option c++'を指定する必要があります。 これにより、 C++のスキャナ・クラスを実装するlex.yy.ccというファイルが生成されます。

lex.yy.ccは、 Flexが提供するFlexLexer.hをインクルードします。 このFlexLexer.hの中に、 C++スキャナ・クラスの実装に利用される2つのC++クラス (FlexLexeryyFlexLexer) が定義されています。


FlexLexerは、 C++スキャナ・クラスが実装すべきインターフェイスを構成する抽象仮想関数を定義するクラスです。

FlexLexerの持つメンバを以下に示します。

次に、 FlexLexerの持つメンバ関数のうち、 抽象仮想関数ではないものを以下に示します。

次に、 FlexLexerの持つ抽象仮想メンバ関数を列挙します。

     void yy_switch_to_buffer(struct yy_buffer_state* new_buffer)
     struct yy_buffer_state* yy_create_buffer(istream* s, int size)
     void yy_delete_buffer(struct yy_buffer_state* b)
     void yyrestart(istream* s)
     int yylex()
     void switch_streams(istream* new_in = 0, ostream* new_out = 0)

最初の5つのメンバ関数は、 FlexのCインターフェイスにおける同名の関数と同等の機能を実現します。 Cインターフェイスでは、 FILE*となっていた引数の型が、 istream*となっている点に注意してください。 最後のswitch_streams()は、 入出力ストリームの切り替えを行います。 これらの抽象仮想メンバ関数の定義は、 サブクラスyyFlexLexerにおいて与えられ、 そのコードはlex.yy.ccの中に生成されます。


yyFlexLexerは、 FlexLexerのサブクラスです。 デフォルトの状態では、 yyFlexLexerのインスタンスを生成して、 yylex()メンバ関数を呼び出すことによって、 スキャナの処理が実行されます。 以下に例を示します。

     int main( int /* argc */, char** /* argv */ )
         {
         FlexLexer* lexer = new yyFlexLexer;
         while(lexer->yylex() != 0)
             ;
         return 0;
         }

これは、 Cインターフェイスにおける、 以下のコードに対応します。

     int main( int /* argc */, char** /* argv */ )
         {
         yylex();
         return 0;
         }

スキャナ定義ファイルの中に`%option yyclass="classname"'を指定すると、 lex.yy.ccclassname::yylex()が生成されます。 クラスclassnameyyFlexLexerのサブクラスとして定義することによって、 classnameのインスタンスを使ってスキャン処理を実行することができます。 クラスclassnameを定義する際、 以下に示す、 yyFlexLexerの持つprotectedメンバ関数を再定義することによって、 スキャナの振る舞いを変更することができます。


スキャン処理に関わるすべてのコンテキスト情報は、 yyFlexLexerのインスタンスの内部に閉じています。 このことは、 C++スキャナ・クラスを使うことによって、 再入可能なスキャナを生成することが可能であることを意味しています。

複数のC++スキャナ・クラスを生成して、 1つの実行プログラムにリンクすることも可能です。 これを行うには、 Flex起動時に`-Pprefix'オプションを指定するか、 スキャナ定義ファイルの中に`%option prefix="prefix"'を指定することによって、 yyFlexLexerの名前を`prefixFlexLexer'に変更します。 prefixFlexLexerクラスを使うソース・ファイルの中では、 以下のようにしてFlexLexer.hをインクルードすることによって、 prefixFlexLexer (実際にはyyFlexLexer) の定義を参照する必要があります。

     #undef yyFlexLexer
     #define yyFlexLexer prefixFlexLexer
     #include <FlexLexer.h>