C言語でeval風関数

はじめに

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

主な仕様

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

  1. 関数sinexpsqrtなど
  2. 括弧()
  3. 乗法除法*\
  4. 加法減法+-

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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)
  2. C言語でeval風関数(Qiita)