解决方案
有简单的设置一个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