C 言語で eval 風関数


はじめに

eval 関数とは文字列を式として評価する関数です。eval は C 言語などのコンパイラ言語にはほとんどないですが,JavaScript などのインタプリタ言語で一般的です。ここでは C 言語のための文字列を数式として処理する eval 風関数を作成します。ソースコードは GitHub にあげてあります。

主な仕様

eval は引数の数式を計算し,その結果を戻り値とする関数にします。eval では sin, exp, sqrt などの math.h にある関数が使えるようにします。関数を含めた数式の計算順は次のようになります。計算過程は全て文字列として処理を行います。

  1. 関数:sin, exp, sqrt など
  2. 括弧:(, )
  3. 乗法,除法:*, \
  4. 加法,減法:+, -

関数の計算を行う calcfunc ,四則演算を行う calc を作成します。括弧の処理には eval を使用します。プログラムの疑似コード(?)と共に説明します。実際のソースコードは長いので GitHub を参照してください。実装は基本的に単純で,上記の箇条書きの順番通りに計算するだけです。

double eval(char *str) {
    for ( 文字列先頭からループ ) {
        if ( 関数があった時 ) {
            str2 = 関数とその引数;
            str3 = num2str(calcfunc(str2));
            str = str2  str3 に置換;
        }
    }
    for ( 文字列先頭からループ ) {
        if ( 括弧があった時 ) {
            str2 = 括弧内の文字列;
            str3 = num2str(eval(str2));
            str = (str2)  str3 に置換;
        }
    }
    for ( 文字列先頭からループ ) {
        if ( *, / があった時 ) {
            str2 = 計算範囲;
            str3 = num2str(calc(str2));
            str = str2  str3 に置換;
        }
    }
    for ( 文字列先頭からループ ) {
        if ( +, - があった時 ) {
            str2 = 計算範囲;
            str3 = num2str(calc(str2));
            str = str2  str3 に置換;
        }
    }
    return atof(str);
}

処理の流れの例

引数に 3*sqrt(4)+(5-2) とした時を例にして説明します。まず都合が良くするために全体に (, ) を付けます。

次に計算の順番通りに関数を呼び出し計算します。

次に *, \ による計算を calc を用いて行います。最後に +, - による計算を行います。最終的に残った値を実数値として return します。

まとめ・今後

C 言語用の eval 風関数を作成しました。calc 等の関数について触れませんでしたが,説明を付け加えるかもしれません。ぜひ構文解析等の勉強に役立てばと思います。今後の課題としてメモリを多用する,処理速度が遅いなどが挙げられるので改善したいです。また,バグがあるかもしません。

文献

  1. ソースコード (GitHub)