Доберитесь valgrind. дают ему Вашу программу для выполнения, и это скажет Вам много о своем использовании памяти.
Это применялось бы только для случая программы, которая работает в течение некоторого времени и остановки. Я не знаю, может ли valgrind достать уже рабочий процесс или процессы должен-остановки, такие как демоны.
Альтернативой реализации вашего собственного синтаксического анализатора и оценщика выражений было бы связывание с библиотекой, которая предоставляет один для вас. Интересным выбором был бы легко встраиваемый язык сценариев, такой как Lua .
Просто настроить экземпляр интерпретатора Lua и передать ему выражения для оценки, возвращая функцию для вызова, которая оценивает выражение. Вы даже можете позволить пользователю иметь переменные ...
Вот схематическая реализация простого оценщика выражений, основанного на интерпретаторе Lua. Я скомпилировал это и попробовал это в нескольких случаях, но, конечно, нельзя доверять производственному коду без некоторого внимания к обработке ошибок и так далее. Здесь действуют все обычные предостережения.
Я скомпилировал и протестировал это в Windows, используя Lua 5.1.4 из Lua для Windows . На других платформах вам нужно будет найти Lua из обычного источника или с www.lua.org.
Вот файл le.h
:
/* Public API for the LE library.
*/
int le_init();
int le_loadexpr(char *expr, char **pmsg);
double le_eval(int cookie, char **pmsg);
void le_unref(int cookie);
void le_setvar(char *name, double value);
double le_getvar(char *name);
Вот файл t-le.c, демонстрирующий простое использование этой библиотеки. Он берет свой единственный аргумент командной строки, загружает его как выражение и оценивает его с изменением глобальной переменной x от 0,0 до 1,0 за 11 шагов:
#include <stdio.h>
#include "le.h"
int main(int argc, char **argv)
{
int cookie;
int i;
char *msg = NULL;
if (!le_init()) {
printf("can't init LE\n");
return 1;
}
if (argc<2) {
printf("Usage: t-le \"expression\"\n");
return 1;
}
cookie = le_loadexpr(argv[1], &msg);
if (msg) {
printf("can't load: %s\n", msg);
free(msg);
return 1;
}
printf(" x %s\n"
"------ --------\n", argv[1]);
for (i=0; i<11; ++i) {
double x = i/10.;
double y;
le_setvar("x",x);
y = le_eval(cookie, &msg);
if (msg) {
printf("can't eval: %s\n", msg);
free(msg);
return 1;
}
printf("%6.2f %.3f\n", x,y);
}
}
Вот некоторые выходные данные t-le:
E:...>t-le "math.sin(math.pi * x)" x math.sin(math.pi * x) ------ -------- 0.00 0.000 0.10 0.309 0.20 0.588 0.30 0.809 0.40 0.951 0.50 1.000 0.60 0.951 0.70 0.809 0.80 0.588 0.90 0.309 1.00 0.000 E:...>
Вот le.c
, реализующий оценщик Lua Expression:
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <string.h>
static lua_State *L = NULL;
/* Initialize the LE library by creating a Lua state.
*
* The new Lua interpreter state has the "usual" standard libraries
* open.
*/
int le_init()
{
L = luaL_newstate();
if (L)
luaL_openlibs(L);
return !!L;
}
/* Load an expression, returning a cookie that can be used later to
* select this expression for evaluation by le_eval(). Note that
* le_unref() must eventually be called to free the expression.
*
* The cookie is a lua_ref() reference to a function that evaluates the
* expression when called. Any variables in the expression are assumed
* to refer to the global environment, which is _G in the interpreter.
* A refinement might be to isolate the function envioronment from the
* globals.
*
* The implementation rewrites the expr as "return "..expr so that the
* anonymous function actually produced by lua_load() looks like:
*
* function() return expr end
*
*
* If there is an error and the pmsg parameter is non-NULL, the char *
* it points to is filled with an error message. The message is
* allocated by strdup() so the caller is responsible for freeing the
* storage.
*
* Returns a valid cookie or the constant LUA_NOREF (-2).
*/
int le_loadexpr(char *expr, char **pmsg)
{
int err;
char *buf;
if (!L) {
if (pmsg)
*pmsg = strdup("LE library not initialized");
return LUA_NOREF;
}
buf = malloc(strlen(expr)+8);
if (!buf) {
if (pmsg)
*pmsg = strdup("Insufficient memory");
return LUA_NOREF;
}
strcpy(buf, "return ");
strcat(buf, expr);
err = luaL_loadstring(L,buf);
free(buf);
if (err) {
if (pmsg)
*pmsg = strdup(lua_tostring(L,-1));
lua_pop(L,1);
return LUA_NOREF;
}
if (pmsg)
*pmsg = NULL;
return luaL_ref(L, LUA_REGISTRYINDEX);
}
/* Evaluate the loaded expression.
*
* If there is an error and the pmsg parameter is non-NULL, the char *
* it points to is filled with an error message. The message is
* allocated by strdup() so the caller is responsible for freeing the
* storage.
*
* Returns the result or 0 on error.
*/
double le_eval(int cookie, char **pmsg)
{
int err;
double ret;
if (!L) {
if (pmsg)
*pmsg = strdup("LE library not initialized");
return 0;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, cookie);
err = lua_pcall(L,0,1,0);
if (err) {
if (pmsg)
*pmsg = strdup(lua_tostring(L,-1));
lua_pop(L,1);
return 0;
}
if (pmsg)
*pmsg = NULL;
ret = (double)lua_tonumber(L,-1);
lua_pop(L,1);
return ret;
}
/* Free the loaded expression.
*/
void le_unref(int cookie)
{
if (!L)
return;
luaL_unref(L, LUA_REGISTRYINDEX, cookie);
}
/* Set a variable for use in an expression.
*/
void le_setvar(char *name, double value)
{
if (!L)
return;
lua_pushnumber(L,value);
lua_setglobal(L,name);
}
/* Retrieve the current value of a variable.
*/
double le_getvar(char *name)
{
double ret;
if (!L)
return 0;
lua_getglobal(L,name);
ret = (double)lua_tonumber(L,-1);
lua_pop(L,1);
return ret;
}
Приведенный выше образец состоит из 189 строк всего кода, включая разбросанные комментарии, пустые строки и демонстрация.
Здесь вам нужен алгоритм Shunting Yard Algorithm .
Он позволяет преобразовать выражение in-fix в обратную польскую нотацию , который довольно просто оценить программно.
Алгоритм маневровой верфи довольно сложен, но мой опыт показывает, что вы можете закодировать его так, как он написан, и все это работает - вам не нужно беспокоиться о анализируя его.
Вы можете использовать Алгоритм маневрового двора , он отлично работает и позволяет вам легко разбирать функции и т. Д. На самом деле он не вычисляет его, но преобразует выражение в ONP, которое можно очень легко вычислить.
Я попросил у Google "синтаксический анализатор выражений рекурсивного спуска" (я не виню вас в том, что вы не знаете, что искать) и нашел Анализ выражений с помощью рекурсивного спуска , который обеспечивает введение в некоторые полезные методы синтаксического анализа.
Кроме того, статья в Википедии о парсере рекурсивного спуска включает довольно полный пример на C.