【问题标题】:Get all errors from lua_pcall(L, 0, 0, 0)从 lua_pcall(L, 0, 0, 0) 获取所有错误
【发布时间】:2014-10-06 15:27:03
【问题描述】:

是否可以从 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);
    }
}

卢阿:

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

输出:

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

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

【问题讨论】:

  • 我不确定我是否遵循。 lua_pcall 将在捕获第一个错误后立即返回。它将在printMessage 处停止,并且不会继续执行该块。你从哪里得到堆栈上会有更多错误的想法? Docs 清楚地说明了这一点。
  • 顺便说一句,你为什么在 main 中抛出错误?
  • 我认为既然 lua_pcall 将函数从堆栈中弹出,它将在整个文件中继续执行,我想这不正确?你知道我该怎么做吗?至于抛出,我只是从一个函数中复制并粘贴它,并将其包装在 main 中。
  • 你想达到什么目的?检查源文件是否有任何错误?
  • 是的,我希望能够检查 lua 文件是否有错误,例如调用未定义的函数,或者忘记在函数后加上“结束”。

标签: c++ lua lua-api


【解决方案1】:

将我的 cmets 总结为一个答案:

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

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

然而,Lua 是一种动态类型语言,其中变量没有类型,而是值的占位符(确实有类型)。这意味着,Lua 无法提前判断 printMessage 是函数、字符串、值还是不存在(nil)。只有在运行时变量即将被调用时,Lua 才会检查它的类型。

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

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

【讨论】:

    【解决方案2】:

    (根据您在 cmets 中澄清的问题)无法报告多个语法错误(仅报告第一个);所以在下面的片段中只报告了第 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)
    

    【讨论】:

    • 感谢您的链接,我需要对此进行更多研究。
    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 2016-12-12
    相关资源
    最近更新 更多