コンパイラ屋ではないので字句解析する必要は滅多にないが、アプリケーションの設定ファイルなんかで「こんな風に書けたらなぁ」と思う時がある。
Windows であれば .ini の読み書きが備わっているけど標準ではキーに対して単一の数値か文字列しか書けない。
例えば x と y の組を幾つか表すのに↓風に書けたら良さそう。
"(10,3) (257,93) (155,437)"
ベタな C で読み取ろうとすると色々間違い易いので、余り書かない遷移図なんかを描いてみると...
ふぅ、書いている間にロジックは固まって来るのだけれど、完全でない上、如何せん面倒。
図を描くだけなら Graphviz という便利なのがあるらしいが、この場は考えながら描く事に意義があるので、そちらは別の機会に…
さて実装は...まず空白をスキップする関数を用意する。こう言う字句解析では次の文字を読んでおくのがコツらしい。
const char * skip(const char * p)
{
while (isspace(*p)) p++;
return p;
}
次に解析の本体をシコシコと書く。数値部は手前の空白を無視し、非数値な位置で停止してくれる strtol がぴったり。
const char * scan_point_pair_core(const char * str, int * err)
{
const char * p = str;
p = skip(p);
if (*p++ != '(')
{
*err = 1;
return p;
}
p = skip(p);
char * ex = NULL;
long x = strtol(p, &ex, 10);
if (ex == p)
{
*err = 2;
return p;
}
TRACE("x = %ld\n", x);
p = ex;
p = skip(p);
if (*p++ != ',')
{
*err = 3;
return p;
}
p = skip(p);
char * ey = NULL;
long y = strtol(p, &ey, 10);
if (ey == p)
{
*err = 4;
return p;
}
TRACE("y = %ld\n", y);
p = ey;
p = skip(p);
if (*p++ != ')')
{
*err = 5;
return p;
}
return p;
}
最後に、繰り返し呼んで終わり。途中でエラーが起きたら以降も読めないかも知れない…
int scan_point_pair(const char * str)
{
int err = 0;
while (*str != '\0')
str = scan_point_pair_core(str, &err);
return err;
}