从字符串中执行 Lua 函数

我需要执行一个 Lua 函数,该函数是 XML 文件的一部分。我将解析 XML 并将整个函数作为字符串加载。

当我尝试执行 lua_pcall 时,它给出 attempt to call a nil value 错误。但是,当我尝试删除函数部分并仅使用内部逻辑时,它对我有效。我需要理解是否需要执行任何其他步骤以执行为函数。

初始化:

/* Lua 解释器 */
lua_State *luaState;
// 初始化 Lua
luaState = luaL_newstate();
lua_register(luaState, "getValue", get_value);
lua_register(luaState, "setValue", set_value);
// 载入 Lua 基础库
luaL_openlibs(luaState);

_工作流程_: XML

-- 由该算法执行的 Lua 脚本
-- 使用下列 API 调用来获取和设置功能块数据
-- local IN1 = getValue("IN1")
-- setValue("OUT1", value)
 setValue("RequestAccepted", "true");

-- lua 脚本

C++ 代码:

TAlgoTable::iterator iter = algoTable.find("RequestAccepted");
if (luaL_dostring(luaState, iter->second.c_str()))
{
    printf("Failure at Algorithm : 'RequestAccepted' Reason : %s", lua_tostring(luaState, -1));
}

不工作:

 -- 由该算法执行的 Lua 脚本
function RequestAccepted()
 -- 使用下列 API 调用来获取和设置功能块数据
 -- local IN1 = getValue("IN1")
 -- setValue("OUT1", value)
 setValue("RequestAccepted", "true");

end -- lua 脚本

C++ 代码:

lua_getglobal(luaState, "RequestAccepted"); // 要调用的函数
if (lua_pcall(luaState, 0, 0, 0)) {
    printf("Failure at Algorithm : 'RequestAccepted' Reason : %s", lua_tostring(luaState, -1));
}
点赞
用户2896993
用户2896993

我发现并理解了我需要将函数加载到缓冲区中。 以下链接帮助我解决了问题 http://gouthamanbalaraman.com/blog/minimal-example-lua-function-cpp.html

2016-05-12 02:37:16
用户6301420
用户6301420

在我的一个项目中,我是通过创建一个 Lua 引用来实现的(请原谅格式,复制粘贴):

int SParamSchemaNode::parseScript(lua_State* L,
                                  const char* arglist,
                                  const char* body)
{
std::ostringstream bufToParse;

// 保存旧栈顶,这样如果第二个 try 成功,我们就可以清理第一个 try 的错误
int oldStackTop = lua_gettop(L);
bufToParse << "return function(" << arglist << ") return ("
           << body << ") end";
if (luaL_dostring(L, bufToParse.str().c_str()))
{
    int parseError1_pos = lua_gettop(L);
    bufToParse.str(std::string());  // 重置 bufToParse 字符串为空
    bufToParse << "return function(" << arglist << ") "
               << body << " end";
    if (luaL_dostring(L, bufToParse.str().c_str()))
    {
        // 由于错误消息包括我们正在尝试解析的脚本,因此结果具有无限长度;因此使用另一个 ostringstream 来保存错误消息
        std::ostringstream errmsg;
        errmsg << "Errors parsing the following script:" << std::endl;
        errmsg << body << std::endl << std::endl;
        errmsg << "Parser error when interpreting as an expression:" << std::endl;
        errmsg << lua_tostring(L, parseError1_pos) << std::endl << std::endl;
        errmsg << "Parser error when interpreting as a function body:" << std::endl;
        errmsg << lua_tostring(L, -1);
        ERROR_ReportError(errmsg.str().c_str());
    }
}
if (DEBUG)
{
    std::cout << "Successfully loaded chunk: " << bufToParse.str() << std::endl;
}
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_settop(L, oldStackTop);
return ref;
}

然后我将其存储在(例如)SParameterDefinition::m_applicableScriptRef 成员中,并使用以下代码调用:

bool SParameterDefinition::isApplicable(SAbstractComponent* cmpt, int index)
{
if (m_applicableScriptRef == LUA_NOREF)
{
    return true;
}

lua_State* L = schema()->luaState();
// 从注册表中获取要调用的函数
lua_rawgeti(L, LUA_REGISTRYINDEX, m_applicableScriptRef);
// 推动 "cmpt" 参数
SWIG_UC_push_SAbstractComponent(L, cmpt);
int nargs = 1;
if (m_isInstanced)
{
    lua_pushnumber(L, index);
    nargs++;
}
// 函数的受保护调用(nargs 个参数,1 个结果,没有特殊的错误处理程序函数)
int script_result = lua_pcall(L, nargs, 1, 0);
if (script_result != 0)
{
    std::ostringstream errmsgBuf;
    errmsgBuf << "Error while calling applicable script for "
              << "parameter " << m_name << ":\n";
    errmsgBuf << lua_tostring(L, -1);
    ERROR_ReportError(errmsgBuf.str().c_str());
}
if (! lua_isboolean(L, -1))
{
    report_type_error("Applicable",
                      m_name.c_str(), "boolean",
                      luaL_typename(L, -1));
}
bool result = (lua_toboolean(L, -1) != 0);
lua_pop(L, 1);
return result;
}

您可能不需要这里的全部复杂性,但基本要点是将函数主体包装在 return function() ... end 中,使用 luaL_dostring 对其进行评估,然后使用 luaL_ref(L, LUA_REGISTRYINDEX) 存储该脚本的结果。

2016-05-12 02:44:25