文字列を一連のパターンと照合するためのライブラリを作成しました。これで、レキシカル スキャナーを C プログラムに簡単に埋め込むことができるようになりました。
レキシカルスキャナーを作成するために利用できる確立されたツールがたくさんあることを私は知っています(頭に浮かぶ最初の2つに名前を付けると、lexとre2c)。レクサーの例は、一般的な問題の具体的なケースにすぎません。
考えられる解決策は 2 つあります。
- 埋め込まれた字句解析器を含むソース ファイルをプレーンな C ファイルに変換するプリプロセッサを作成し、場合によっては、コンパイルで使用される他のファイルのセットに変換します。
- より読みやすい形式でレクサーを表す一連の C マクロを作成します。
私はすでに両方を行っていますが、質問は次のとおりです。
- 読みやすさ。レクサーのロジックは明確で理解しやすいものにする必要があります
- 保守性。バグを見つけて修正するのは悪夢ではありません。
- ビルド プロセスの干渉。プリプロセッサは、ビルド プロセスで追加の手順を必要とし、プリプロセッサはパス内に存在する必要があります。
言い換えれば、2 つのアプローチのいずれかを使用するソフトウェアを保守または作成する必要がある場合、失望が少ないのはどちらでしょうか?
例として、次の問題のレクサーを次に示します。
- すべての数値を合計します (1.3E-4.2 のような指数を含む 10 進数形式にすることができます)
- スキップ文字列 (二重引用符と一重引用符)
- スキップ リスト (LISP リストと同様: (3 4 (0 1)() 3) )
- 単語 end (大文字と小文字は区別されません) に遭遇するか、バッファの最後で停止します
2つのスタイルで。
/**** SCANNER STYLE 1 (preprocessor) ****/
#include "pmx.h"
t = buffer
while (*t) {
switch pmx(t) { /* the preprocessor will handle this */
case "&q" : /* skip strings */
break;
case "&f<?=eE>&F" : /* sum numbers */
sum += atof(pmx(Start,0));
break;
case "&b()": /* skip lists */
break;
case "&iend" : /* stop processing */
t = "";
break;
case "<.>": /* skip a char and proceed */
break;
}
}
/**** SCANNER STYLE 2 (macros) ****/
#include "pmx.h"
/* There can be up to 128 tokens per scanner with id x80 to xFF */
#define TOK_STRING x81
#define TOK_NUMBER x82
#define TOK_LIST x83
#define TOK_END x84
#define TOK_CHAR x85
pmxScanner( /* pmxScanner() is a pretty complex macro */
buffer
,
pmxTokSet("&q" , TOK_STRING)
pmxTokSet("&f<?=eE>&F" , TOK_NUMBER)
pmxTokSet("&b()" , TOK_LIST)
pmxTokSet("&iend" , TOK_END)
pmxTokSet("<.>" , TOK_CHAR)
,
pmxTokCase(TOK_STRING) : /* skip strings */
continue;
pmxTokCase(TOK_NUMBER) : /* sum numbers */
sum += atof(pmxTokStart(0));
continue;
pmxTokCase(TOK_LIST): /* skip lists */
continue;
pmxTokCase(TOK_END) : /* stop processing */
break;
pmxTokCase(TOK_CHAR) : /* skip a char and proceed */
continue;
);
現在の実装に興味がある方は、コードはhttp://sites.google.com/site/clibutlにあります。