BLex3 は、テキストファイルを解析して、さまざまなアクションを するときに使用します。 BLex3 は、エンジン、パーサ、アクター、カウンターから構成されています。 エンジン(BLex3_Engine クラス)は、パーサが字句解析をしやすくするために、 文字列ポインタのようなアクセス手段を提供します。 パーサ(BLex3_Parser クラス)は、テキストの字句を解析して トークン(句)を抽出します。 アクター(BLex3_Actor クラス)は、処理すべきトークンを 入力したときに、変換結果を出力するなどのアクションをします。
パーサ、アクターは、モジュール化できます。 BLex3 を使用するときは、既存のモジュールや、アプリケーション用に 作成したモジュールを登録してから実行します。(予定)
BLex3_BackMsg msg; c_try { BLex3_init( &lex, vprinter ); BLex3_addParser( &lex, BLexHtmlTag ); BLex3_addActor( &lex, BLexRec ); BLex3_addActor( &lex, TakeX_kword ); BLex3_addActor( &lex, RXML_actor ); for ( path;;) { msg = BLex3_assemble( &lex, path ); if ( msg & BLex3_BreakFileLoop ) break; } } c_finally { BLex3_printLastMsg( &lex ); BLex3_finish( &lex ); } c_end_finally; |
パスごとに assemble ループ パーサは、次のトークンの先頭アドレスを記憶しておき、途中ならパースしない アクターをコントロールするマスター マスターは、ファイルポインタを進める(ダイレクトorトークン指定)
エンジン(BLex3_Engine)は、パーサが字句解析をしやすくするために、
ファイルのデータに対して、文字列ポインタのようなアクセス手段を提供します。
ファイルポインタを進める BLex3_Engine_next 関数と、
現在のファイルポインタの位置に相当する char* 型変数を取得する
BLex3_Engine_getFilePtr 関数を主に使います。
取得したファイルポインタ fp は、
BLex3_Engine_getFilePtr 関数の引数 offsetMax に設定した
オフセットまで文字列としてアクセスが保証されています。
ただし、BLex3_Engine_next 関数を使うと、ファイルポインタが
内部バッファと合わなくなるため、再び BLex3_Engine_getFilePtr 関数を
呼び出さなければ、ファイルポインタのある位置にアクセスできません。
トークンが長いときは、offsetMax に 0 を指定して ファイルポインタを取得します。 0 を指定すると、内部バッファの最後までアクセスが 保証されます。 それ以上のオフセットにアクセスをするときは、 BLex3_Engine_nextBuf 関数を使ってから BLex3_Engine_getFilePtr を使います。
内部バッファにアクセスしても、
そこが、ファイルの末尾より後(EOF)に相当することがあります。
そのとき、内部バッファには '\0' が入っています。
BLex3_Engine_isPtrEOF 関数を使って EOF かどうか判定できます。
BLex3_Engine_getOverPtr 関数は、内部バッファの末尾の次、または
ファイルの末尾の次のアドレス(内部バッファのアドレス)の
どちらか小さい方を取得するので、そのアドレスの前まで、
自由にアクセスできます。
ワードや数値や CSV など、パーサがよく使うトークンを入力する ために、字句解析エンジン・ユーティリティ(BLex3_EngineU クラス)が あります。
エンジンは、内部でバイナリファイルの FILE* を持っています。 高速化のために、セクタサイズ単位のアクセスができるように、 内部バッファのサイズは、セクタサイズの倍数にします。 セクタサイズは、API の GetDiskFreeSpace から取得できます。 offsetMax がバッファを超えるときは、バッファの先頭に セクタのデータを移動します。この回数を減らすために、 バッファのサイズはなるべく大きくします。
パーサ(BLex3_Parser)は、テキストの字句を解析して トークン(句)タイプを抽出するインターフェイス・クラスです。
BLex3_Parser_parse 関数は、内部で BLex3_Engine クラスを使って入力ファイルの内容を解析します。
BLex3_Parser_parse 関数を呼び出すと、その解析によって ファイルポインタが移動する可能性があります。 同じファイルポインタの位置の、別の解析を行うときは、 BLex3_Engine_setPos 関数を使ってファイルポインタを戻します。 さらに、以前 BLex3_Engine_getFilePtr 関数から取得した ファイルポインタも、もう一度同関数を呼び出して更新する 必要があります。(同じファイルアドレスでも、 内部バッファの位置が変わる可能性があるためです)。
返されるトークン・タイプとすべきアクションは、 ファイルポインタの位置によって次のように分類されます。
ファイルポインタの位置 | トークン・タイプ定数 | アクション | 補足 |
---|---|---|---|
トークンの先頭 | (パーサ定義のトークンタイプ) | 一般に何らかのアクションが起きます | トークンタイプによって、アクターやマスターが何らかの処理をします。 |
トークンの途中 | BLex3_MiddleOfToken | アクションを起こす必要はありません。 | BLex3_Parser_getNextParsePos 関数が返したアドレスより前で BLex3_Parser_parse 関数を呼び出すとこれを返します。 |
トークンの最後の次 | (パーサ定義のトークンタイプ) | アクションを起こす必要があることがあります。 | トークンの先頭のトークン・タイプ定数と異なる定数を定義します。 アクションを起こす必要がなければ、BLex3_OutOfToken を返します。 |
ファイルの最後の次(EOF) | BLex3_EOF | 解析処理を終了します。 | ファイルアドレスが、ファイルの末尾の次(EOF)のときに、 「トークンの最後の次」のトークンタイプが返ることがあるので、 解析処理の終了は、すべてのトークンが EOF を返すようになったときにします。 |
その他のトークン | BLex3_OutOfToken | アクションを起こす必要はありません。 | パーサが、字句解析エンジンの内部バッファの 最後まで、解析すべきトークンが現れなかったときに返ります。 このとき、BLex3_Parser_getNextParsePos 関数は、 内部バッファ最後の次の位置のファイル・アドレスを返します。 |
BLex3_Parser_getNextParsePos 関数は、
次に BLex3_Parser_parse 関数を呼び出す必要がある
ファイル・アドレスを返します。
マスターは、全てのパーサの返すファイル・アドレスのうち、
もっとも近い位置にファイルポインタを移動させて、
すべての BLex3_Parser_parse 関数を呼び出します。
ファイルの一部を変更する処理では、
マスターがファイルポインタを移動をする際に、
入力ファイルのデータをそのまま出力ファイルに
出力する BLex3_Engine_copy 関数を使います。
BLex3_Parser_getTokenType 関数は、 現在のファイルポインタの位置にあるトークン・タイプを返します。 入力ファイルの行番号を数えたり、 括弧の深さを監視したりするカウンターも、 パーサと同じインターフェイスを持ちます。 ただし、BLex3_Parser_getTokenType 関数の返り値は、 BLex3_OutOfToken にします。 また、次に BLex3_Parser_parse 関数を呼び出す タイミングが存在しないので、 BLex3_Parser_getNextParsePos 関数によって 取得できるファイル・アドレスは、アドレスの最大値 (BLex3_PosForNoEvent)にします。
パーサには、HTML パーサ、KTML パーサ、行番号カウンタ、などがあります。
パーサとアクターを分けているのは、パーサが解析する字句を、 複数のアクターで参照するためです。
アクター(BLex3_Actor)は、処理すべきトークンを パーサから入力したときに、変換結果を出力するなどの アクションをするインターフェイス・クラスです。
アクターは、ファイル出力だけでなく次のようなものもあり、 アクターが別のアクターを参照することもあります。
字句解析のデバッグでポイントとなるのは、 調査したい入力ファイルの位置について、 プログラムがどう動くかについてです。 よって、ファイルアドレスを条件とした ブレークポイントを貼ることが重要です。 バイナリエディタを使ってファイルアドレスを調べ、 ブレークする条件を設定します。