从lua_pcall(L,0,0,0)获取所有错误

时间:2014-08-13 10:00:02

标签: c++ lua lua-api

是否有可能从C / C ++获取lua堆栈中的所有错误?这是我尝试过的事情

C ++

int main()
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    if (luaL_loadfile(L, "LuaBridgeScript.lua"))
    {
        throw std::runtime_error("Unable to find lua file");
    }

    int error = lua_pcall(L, 0, 0, 0);
    while (error && lua_gettop(L))
    {
        std::cout << "stack = " << lua_gettop(L) << "\n";
        std::cout << "error = " << error << "\n";
        std::cout << "message = " << lua_tostring(L, -1) << "\n";
        lua_pop(L, 1);
        error = lua_pcall(L, 0, 0, 0);
    }
}

LUA:

printMessage("hi")
printMessage2("hi2")

输出:

stack = 1
error = 2
message = LuaBridgeScript.lua:1: attempt to call global 'printMessage' <a nil value>

即使堆栈大小为0或为负,我也尝试循环,但我不明白堆栈是如何为负,并且程序在几次尝试后崩溃。

2 个答案:

答案 0 :(得分:4)

将我的评论总结为答案:

根据lua_pcall上的Lua docs,pcall返回成功(块结束)或第一个错误抛出。所以在后一种情况下,它会将只有一条消息推送到堆栈。在第一次错误之后它永远不会继续执行。

您要实现的目标是检查文件中是否存在错误。在像C这样的静态类型语言中,每个变量都必须在编译时定义,因此编译器可以发现调用非现有函数的实例。

然而,Lua是一种动态类型语言,其中变量没有类型,而是值(具有类型)的占位符。这意味着,Lua无法事先告诉printMessage是函数,字符串,值还是不存在(nil)。只有在运行时才会调用Lua检查其类型的变量。

因此无法实现您想要的那种方式。运行代码超出第一个未处理的错误也是没有意义的,因为错误可能会使后续片段中的假设无效(例如关于非现有函数应该设置的全局变量) - 这将是一团糟。

对于语法错误,通常在编译源文件时捕获这些错误,即加载时。但是,Lua解析器在第一次遇到语法错误时停止。这是因为在一个地方多次出现语法错误会使其后面的所有内容无效。正如Etan在他的评论中指出的那样,许多解析器报告一旦你修复了它们之前的错误,后续错误就会消失或改变。对于像MSVS那样的重量级解析器也是如此。

答案 1 :(得分:1)

(按照您在评论中澄清的问题)无法报告多个语法错误(仅报告第一个语法错误);所以在下面的片段中只报告了第1行的第一个错误:

if true the --<-- first syntax error
end
if false the --<-- second syntax error
end

然而,您可以编写自己的解析器(或修改现有的Lua解析器之一),即使在找到错误之后也会继续处理。例如,您可以查看David Manura loose parser的工作原理。

无法报告多个运行时错误(仅报告第一个错误);所以在下面的片段中,pcall只报告第一个错误:

pcall(function()
  nonExistingFunction1() --<-- only this error will be reported
  nonExistingFunction2()
end)