2011-12-25 2 views
1

トピックが示しているように、私のプログラムはいくつかの関数式を読み込み、さまざまな変数を何度もプラグインする必要があります。新しい値をプラグインする必要があるたびに、式全体を再度解析するのは間違いですが、あまりにも醜いので、解析された式を格納する方法が必要です。プラグインされた関数式を何度も格納する方法は?

2x + sin(tan(5x)) + x^2のように表示される場合があります。ああ、そして非常に重要なポイント - 私はC + +を使用しています。

は現在、私は3つのそれにアイデアが、すべての非常にエレガントではない持っている:ツリーとしてS式を保存

  1. を。それを定期的に評価する。 これを処理する古い学校の方法かもしれませんが、それは醜いです、私は (+対sinのような)異なる数のパラメータで処理する必要があります。

  2. boost::lambdaでの匿名機能の作成。それは良い、 が動作するかもしれませんが、個人的に私はブーストが好きではありません。

  3. 小さなpython/lispスクリプトを書いて、そのネイティブラムダ という表現を使って、IPCと呼んでください...まあ、これは狂っています。

どのようなアイデアですか?

UPDATE:

私はsin()のように、一つのパラメータのみでカッコや機能のサポートを実装しようとしませんでした。

私は最初に2番目の方法を試しました。私はboost::lambdaを使用しませんでしたが、gccの機能は、hereから見つかった偽の匿名関数を作成するために使用できます。結果のコードには340行があり、スコープとスタックの微妙な問題のため正しく動作しません。

ラムダを使用するとそれが改善されませんでした。スコープで正しく処理できるかどうかわかりません。 boost :: lambdaのテストをしていないのは残念です。

S式として解析された文字列を格納することは間違いなく機能しますが、実装はさらに長くなります。私のプロジェクトは何万行もの巨大なプロジェクトではないので、あまり使われないようなひねったコードを維持することに多くの力を注いでいるのは良い考えではないようです。

最後に私は3番目の方法を試しました - それは素晴らしいです! Pythonスクリプトには、わずか50行しかありません。読みやすくてすっきりしています。しかし、それはまた、私のプログラムの前提条件としてpythonを作ることにもなります。 * nixマシンではそれほど悪いことではありませんが、Windowsでは...プログラマー以外の人がPythonをインストールするのは非常に辛いでしょう。リスプもそうです。

しかし、私の最終的な解決策は、サブプロセスとしてbcを開きます。たぶんそれはほとんどの状況にとって悪い選択ですが、それは私によく合います。

一方、* nixの下でのみ動作するプロジェクトや、すでにPythonを前提条件として使用している場合は、手書きパーザで解析できるほどシンプルであれば、3番目の方法をお勧めします。 Hurkyl氏のように、非常に複雑な場合は、ミニ言語の作成を検討することができます。

+1

実行時に次の表現を読んでいますか?もしそうなら、私は 'boost :: lambda'がコンパイル時にすべての作業を行うのと同様に、どのように役立つのか見当たりません。 –

+1

木は何が問題なのですか?あなたが直線的なプログラムを主張するなら、あなたはいつもミニインタープリタ言語とミニコンパイラを使って式をあなたの言語に変換して実行できると思うが、それはオーバーエンジニアリングのようだ。 – Hurkyl

+0

@DavidBrown http://pastie.org/3069270 – wecing

答えて

3

このような目的のために設計されたスクリプト言語を使用してみませんか?そのような言語がいくつか浮遊していますが、私の経験はルアです。

私はこの種のことを「すべての時間」行うためにluaを使用します。そのような式を埋め込んで解析するコードは非常に小さいです。

std::string my_expression = "2*x + math.sin(math.tan(x)) + x * x"; 

//Initialise lua and load the basic math library. 
lua_State * L = lua_open(); 
lua_openmath(L); 

//Create your function and load it into lua 
std::string fn = "function myfunction(x) return "+my_expression+"end"; 
luaL_dostring(L, fn.c_str(), fn.size()); 

//Use your function 

for(int i=0; i<10; ++i) 
{ 
    // add the function to the stack 
    lua_getfield(L, LUA_GLOBALSINDEX, "myfunction"); 
    // add the argument to the stack 
    lua_pushnumber(L, i); 
    // Make the call, using one argument and expecting one result. 
    // stack looks like this : FN ARG 
    lua_pcall(L,1,1) 
    // stack looks like this now : RESULT 
    // so get the result and print it 
    double result = lua_getnumber(L,-1); 
    std::cout<<i<<" : "<<result<<std::endl; 
    // The result is still on the stack, so clean it up. 
    lua_pop(L,1); 
} 
+0

クール!それはBCよりも良いようです。私はそれを試してみます。ありがとう! – wecing

関連する問題