Home / 字句解析もどき

字句解析もどき

コンパイラ屋ではないので字句解析する必要は滅多にないが、アプリケーションの設定ファイルなんかで「こんな風に書けたらなぁ」と思う時がある。
Windows であれば .ini の読み書きが備わっているけど標準ではキーに対して単一の数値か文字列しか書けない。

例えば x と y の組を幾つか表すのに↓風に書けたら良さそう。

"(10,3)  (257,93)  (155,437)"

原始的、力技で字句解析

ベタな C で読み取ろうとすると色々間違い易いので、余り書かない遷移図なんかを描いてみると...

lexana

ふぅ、書いている間にロジックは固まって来るのだけれど、完全でない上、如何せん面倒。
図を描くだけなら 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;
}

Home / 字句解析もどき
http://usskim.web.fc2.com/
inserted by FC2 system