Как хранить разобранные выражения функций для подключения много раз? - PullRequest
1 голос
/ 25 декабря 2011

Как видно из темы, моей программе необходимо прочитать несколько выражений функций и подключить различные переменные много раз. Повторный анализ всего выражения каждый раз, когда мне нужно подключить новое значение, определенно слишком уродлив, поэтому мне нужен способ сохранить проанализированное выражение.

Выражение может выглядеть как 2x + sin(tan(5x)) + x^2. Ох, и очень важный момент - я использую C ++.

В настоящее время у меня есть три идеи, но все они не очень изящны:

  1. Сохранение S-выражения в виде дерева; оцените это повторением. Это может быть старой школы способ справиться с этим, но это уродливо, и я бы приходится обрабатывать с различным количеством параметров (например, + против греха).

  2. Составление анонимных функций с помощью boost::lambda. Это может хорошо работать, но лично я не люблю повышение.

  3. Написание небольшого скрипта на python / lisp, используйте его родную лямбду выражение и назвать его с IPC ... Ну, это безумие.

Итак, есть идеи?

UPDATE:

Я не пытался реализовать поддержку скобок и функций только с одним параметром, например sin().

Сначала я попробовал второй способ; но я не использовал boost::lambda, но особенность gcc, которую можно использовать для создания (подделки) анонимных функций, я нашел из здесь . Результирующий код содержит 340 строк, и он не работает правильно из-за области видимости и небольшой проблемы со стеком.

Использование лямбды не могло сделать его лучше; и я не знаю, сможет ли он справиться с областью видимости правильно. Извините, что не тестируете boost :: lambda.

Сохранение проанализированной строки в виде S-выражений определенно сработает, но реализация будет еще длиннее - возможно, ~ 500 строк? Мой проект - не такой гигантский проект с десятками тысяч строк кода, поэтому уделять столько энергии поддержанию такого вида искаженного кода, который не будет использоваться очень часто, кажется не очень хорошей идеей.

Итак, наконец-то я попробовал третий способ - он потрясающий! Скрипт Python имеет всего 50 строк, довольно аккуратный и удобный для чтения. Но, с другой стороны, это также сделает Python обязательным условием моей программы. Это не так плохо на машинах * nix, но на Windows ... Я думаю, что непрограммистам было бы очень больно устанавливать Python. Так и есть.

Однако, мое окончательное решение - открытие bc в качестве подпроцесса . Возможно, это плохой выбор для большинства ситуаций, однако, он мне подходит.

С другой стороны, для проектов, работающих только под * nix или уже имеющих python в качестве предварительного условия, лично я рекомендую третий способ, если выражение достаточно простое, чтобы его можно было проанализировать с помощью рукописного анализатора. Если это очень сложно, как сказал Хюркил, вы можете подумать о создании мини-языка.

1 Ответ

3 голосов
/ 27 декабря 2011

Почему бы не использовать язык сценариев, предназначенный именно для таких целей?Есть несколько таких языков, но мой опыт с 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...