マーク付けに使う文字の変更 #4

やっぱり関数yylexを手書きするのは面倒だ、という考えはあっても当然だろう。
だが前に述べたように固定パターンスキャナを作成するlex/flexで生成するのは難しそうだ。
と思ったが、とりあえず効率は無視して、変な方法を思いついた。
以下はお試しプログラム。

trch.l
%{
#define YY_INPUT(buf,result,max_size) \
    { \
        int i; \
        errno = 0; \
        while ((result = fread(buf, 1, max_size, yyin)) == 0 && ferror(yyin)) { \
            if (errno != EINTR) yy_fatal_error("input failed"); \
            errno = 0; \
            clearerr(yyin); \
        } \
        for (i = 0; i < result; i++) if (buf[i] == 'a') buf[i] = 'b'; \
    } \
\

#ifdef __STRICT_ANSI__
int fileno(FILE *);
#endif
%}

%option main noinput nounput

%%

見たとおり、定義部だけで規則部のないflex用コードであり、
YY_INPUTマクロの再定義が無ければ、生成される字句解析器は入力をそのまま出力するだけである。
この再定義したマクロの肝は、読み込んだ入力中の文字'a'を文字'b'に置換することである。

$ flex trch.l
$ gcc -std=c89 -pedantic -Wall -Wextra -o trch lex.yy.c -s
$ echo "abcabc aaa bbb ccc" | ./trch
bbcbbc bbb bbb ccc

となる。
要は、動的に指定されたメタ文字が入力中にあった場合、
それを特定の文字に置換してから字句解析器に渡してやろうということである。
固定パターンでマッチさせた後で置換した文字を元に戻してやれば、
flexで動的にメタ文字を検出するyylexを自動生成させることができそう、と思った次第。
もっとスマートな方法がありそうだとも思うが、この方針で書いてみよう。