如何存储解析的函数表达式多次插入?

时间:2011-12-25 01:39:16

标签: c++ parsing

正如主题所示,我的程序需要多次读取多个函数表达式和插入不同的变量。每次我需要插入一个新值时再次解析整个表达式肯定是太难看了,所以我需要一种方法来存储解析的表达式。

表达式可能看起来像2x + sin(tan(5x)) + x^2。哦,非常重要的一点 - 我正在使用C ++。

目前我有三个想法,但都不是很优雅:

  1. 将S表达式存储为树;通过重复评估它。有可能 是老派的办法来处理这个问题,但这很丑陋,我愿意 必须处理不同数量的参数(如+ vs.罪)。

  2. 使用boost::lambda撰写匿名函数。它可能很好用, 但我个人不喜欢提升。

  3. 编写一个小的python / lisp脚本,使用它的原生lambda 表达并用IPC调用......好吧,这很疯狂。

  4. 那么,有什么想法吗?

    更新

    我没有尝试仅使用一个参数来实现对括号和函数的支持,例如sin()

    我先尝试了第二种方式;但我没有使用boost::lambda,而是gcc的一个功能,它可用于创建我从here找到的(伪)匿名函数。生成的代码有340行,由于范围和堆栈的细微问题而无法正常工作。

    使用lambda无法使其变得更好;我不知道它是否可以正确处理范围。很抱歉没有测试boost :: lambda。

    将解析后的字符串存储为S表达式肯定会有效,但实现会更长 - 可能~500行?我的项目不是那种拥有成千上万行代码的巨大项目,所以投入如此多的精力来维护那种不经常使用的扭曲代码似乎不是一个好主意。

    所以最后我尝试了第三种方法 - 它太棒了! Python脚本只有50行,非常简洁易读。但是,另一方面,它也会使python成为我程序的先决条件。它在* nix机器上并没有那么糟糕,但在Windows上......我想非程序员安装Python会非常痛苦。 lisp也是如此。

    但是,我的最终解决方案是打开bc作为子流程。也许这对大多数情况来说都是一个糟糕的选择,但是,它很适合我。

    另一方面,对于仅在* nix下工作的项目或者已经将python作为先决条件,我个人推荐第三种方法,如果表达式足够简单,可以用手写解析器解析。如果它非常复杂,就像Hurkyl说的那样,你可以考虑创建一种迷你语言。

1 个答案:

答案 0 :(得分:3)

为什么不使用专为此目的而设计的脚本语言?有几种这样的语言漂浮在周围,但我的经验是与lua。

我使用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);
}