在我的前面的问题我一直在寻找evaulating在C复合数学表达式的一种方式,最的建议需要执行某种类型的解析器。

然而一个答案时,建议使用的Lua用于评估表达。我感兴趣的这种做法,但我不知道任何事情的Lua。

能否有人在Lua的经验提供一些线索?

具体想什么,我知道的是 哪些API如有不Lua中提供可评估传过来的字符串数学表达式?如果没有API做这样的事情,可能有些人能摆脱对链接的答案,因为它的一些光似乎是个好办法:)

由于

我想评估表达式的类型被给予某些用户输入,例如

Y = X ^ 2 + 1 / X - COS(x)的

计算y为x的范围值的

有帮助吗?

解决方案

有简单的设置一个Lua解释实例,并把它传递表达式进行评估,取回一个函数调用,用于评估表达。你甚至可以让用户有变量...

下面是我做起来,编辑成我的其他答案示例代码。它可能是更好放置在任何情况下标记Lua中的一个问题,所以我在这里添加它。我编这一点,并尝试了一些案件,但它肯定不应该在生产代码是可信的,而不注意一些错误处理等等。所有常见的警告适用于这里。

我编译和使用的Lua从的Lua 5.1.4用于Windows 测试此在Windows。在其它平台上,你必须去找Lua从你平时的来源,或者从www.lua.org。

<强>更新:此示例使用简单和直接的技术来隐藏后面尽可能简单的接口的Lua API的全功率和复杂性。这是因为,可能是有用的,但在许多方面可以改进。

我会鼓励读者寻找到了更多的生产就绪的代码AE 库由 LHF ,是以API的优势,避免了一些快速和肮脏的字符串操作我用。他的图书馆还促进了数学库到全局命名空间,以便用户可以说sin(x)2 * pi不必说math.sin等等。

公共接口到LE

下面是文件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);

使用LE示例代码

下面是文件叔le.c,表明一个简单的采用该库。它采取它的单个命令行参数,加载它作为表达,并且与全局变量评估其中的x 11个步骤从0.0变化到1.0:

#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);
    }
}

下面是从叔乐一些输出:

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的实施

下面是le.c,实施lua的表达评估器:

#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行代码总的,包括的注释,空行溅射,和显示。不坏,知道如何评价一个变量的合理任意表达式,并具有的丰富的标准数学函数库的在其使唤。

您拥有这一切之下的图灵完备的语言,这将是一个很容易的扩展,允许用户定义完整的功能以及评估简单表达式。

其他提示

既然你是懒惰的,最喜欢的程序员,这里有一个简单的例子,一个链接,你可以用它来分析一些的 使用任意代码的Lua 。从那里,它应该是简单的创建表达式分析器。

这是针对正在寻找一个Lua等效的“EVAL”的Lua用户。

魔语用来被加载链,但它现在是,由于的Lua 5.2,的升级版的负载

 i=0
 f = load("i = i + 1") -- f is a function
 f() ; print(i) -- will produce 1
 f() ; print(i) -- will produce 2

又如,,提供了一个值:

f=load('return 2+3')
print(f()) -- print 5

作为一个快速和肮脏的方式做,你可以考虑的eval(S),其中S是一个字符串,以评估以下等价的:

load(s)()

和往常一样,应在可能的情况,因为它们是昂贵的并且产生难以读取的代码避免EVAL机制。 我个人使用这个机制LuaTEX等程序/ LuaLatex进行数学运算中的乳胶。

在的Lua文档包含标题中的应用程序编程接口一个部其中介绍了如何在C程序中调用Lua。为lua的文档是非常好,你甚至可以找到你想在那里做什么的例子。

这是在有一个大的世界,所以无论你选择自己的解析方案或嵌入式翻译像Lua中,你将有一些工作要做!

function calc(operation)
    return load("return " .. operation)()
end
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top