基本字句解析 ver.3 [BLex3]

目次

1. 概要

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トークン指定)


2. エンジンBLex3_Engine クラス

エンジン(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 クラス)が あります。

2-1. 内部メモ

エンジンは、内部でバイナリファイルの FILE* を持っています。 高速化のために、セクタサイズ単位のアクセスができるように、 内部バッファのサイズは、セクタサイズの倍数にします。 セクタサイズは、API の GetDiskFreeSpace から取得できます。 offsetMax がバッファを超えるときは、バッファの先頭に セクタのデータを移動します。この回数を減らすために、 バッファのサイズはなるべく大きくします。


3. パーサBLex3_Parser クラス

パーサ(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 パーサ、行番号カウンタ、などがあります。

パーサアクターを分けているのは、パーサが解析する字句を、 複数のアクターで参照するためです。


4. アクターBLex3_Actor クラス

アクター(BLex3_Actor)は、処理すべきトークンを パーサから入力したときに、変換結果を出力するなどの アクションをするインターフェイス・クラスです。

アクターは、ファイル出力だけでなく次のようなものもあり、 アクターが別のアクターを参照することもあります。


5. 字句解析のデバッグ

字句解析のデバッグでポイントとなるのは、 調査したい入力ファイルの位置について、 プログラムがどう動くかについてです。 よって、ファイルアドレスを条件とした ブレークポイントを貼ることが重要です。 バイナリエディタを使ってファイルアドレスを調べ、 ブレークする条件を設定します。


written by T's-Neko from Jul.16.2000.