【问题标题】:How to replace Lua default error print?如何替换 Lua 默认错误打印?
【发布时间】:2013-12-09 07:59:58
【问题描述】:

我正在将 Lua 作为一种脚本语言实现到 Windows 应用程序中。由于应用程序的结构,打印输出不使用流式 io,例如 stdoutstderror

我已经设法覆盖 Lua print 以适应我的结构...

lua_register(L,"print", cs_print);

...但是如何在不使用流的情况下覆盖所有错误和调试打印输出?我需要在一个函数中处理这个问题(类似于print)。

【问题讨论】:

    标签: c++ lua win32gui


    【解决方案1】:

    Lua 写入stderr 的唯一地方是luaL_newstate 安装的恐慌函数。如果您将 Lua 嵌入到您的应用程序中,请确保从受保护的调用中启动 Lua,这样就不会发生恐慌。有关想法,请参阅 http://www.lua.org/source/5.2/lua.c.html#main

    【讨论】:

    • 问题不在于我想隐藏错误消息,我想在特定的窗口控件中显示它们。所以我需要在一个函数中捕获所有与错误相关的消息,以便我可以在正确的窗口中打印它们。如上所述,这不是嵌入应用程序,而是 Win32 GUI 应用程序。
    • @MaxKielland,当您使用受保护的调用启动 Lua 时,错误消息会留在 Lua 堆栈中。
    • 是的,经过一天的谷歌,我发现我可能需要使用 lua_pcall() 而不是 luaL_dostring() 来获取编译器错误。
    • @MaxKielland, luaL_dostring 工作正常:它调用lua_pcall。见lua.org/manual/5.2/manual.html#luaL_dostring
    【解决方案2】:

    经过大量谷歌搜索后,我想出了这个解决方案来获取编译器和运行时错误消息以及重定向标准 Lua 打印函数。

    我使用 C++ Builder,但我认为它对寻找相同答案的任何人都有用。 该脚本在 TScriptLua 对象实例中运行并将 Lua 状态映射到正确的脚本实例,我使用 std::map 列表查找对象指针。

    // list for mapping Lua state with object pointers.
    static std::map<lua_State*,TScriptLua*> LuaObjMap;
    

    Next 是一个内联函数,用于从 Lua 状态指针中获取对象指针。

    extern "C" {
    
       // Inline to map Lua state pointer to object pointer
       static inline TScriptLua* GetScriptObject(lua_State* L) {
         return LuaObjMap.find(L)->second;
       }
    

    此函数将取代标准 Lua 打印函数。对象指针 (f) 在其基类中有一个名为 Out() 的成员函数,它将在关联的窗口控件中输出一个字符缓冲区。

       // New Lua print function
       static int cs_print (lua_State *L) {
    
         // Map Lua state to object
         TScriptLua* f = GetScriptObject(L);
    
         if (f) {
           int count = lua_gettop(L);
           for (int i=1; i <= count; ++i) {
             const char *str = lua_tostring(L, i); // Get string
             size_t len = lua_rawlen(L,i);         // Get string length
    
             // Output string.
             f->Out(str,len);
           }
         }
    
         return 0;
       }
    

    这是我的错误打印例程,将显示编译器/运行时错误。至于Lua的打印功能,再次使用f->Out来打印错误信息。

       // Error print routine
       static int cs_error(lua_State *L, char *msg) {
    
         // Map Lua state to object
         TScriptLua* f = GetScriptObject(L);
    
         // Get error message
         AnsiString m = String(msg) + " " + String(lua_tostring(L, -1));
    
         // "print" error message
         f->Out(m.c_str(),m.Length());
    
         // Clenaup Lua stack
         lua_pop(L, 1);
    
         return 0;
       }
    
     } // <--- End extern C
    

    这是实际的加载和运行成员。创建新的 Lua 状态后,它与映射列表中的该对象相关联。然后它使用 luaL_loadbuffer() 从富编辑控件加载脚本,检查编译器错误并使用 lua_pcall() 运行编译后的脚本。

    void __fastcall TScriptLua::Compile(void) {
    
       // Create new Lua state
       lua_State *L = luaL_newstate();
    
       // Store mapping Lua state --> object
       LuaObjMap.insert( std::pair<lua_State*,TScriptLua*>(L,this) );
    
       // Override Lua Print
       lua_register(L,"print",  cs_print);
    
       // Load and compile script
       AnsiString script(Frame->Script_RichEdit->Text);
       if (luaL_loadbuffer(L,script.c_str(),script.Length(),AnsiString(Name).c_str()) == 0) {
         if (lua_pcall(L, 0, 0, 0))        // Run loaded Lua script
           cs_error(L, "Runtime error: "); // Print runtime error
       } else {
         cs_error(L, "Compiler error: ");  // Print compiler error
       }
    
       // Close Lua state
       lua_close(L);
    
       // Remove Lua --> object mapping
       LuaObjMap.erase( LuaObjMap.find(L) );
    
     }
    

    这不是我的最终解决方案,但到目前为止它可以解决问题。我认为最好的办法是将流处理写入 TScriptLua 对象,这样我就可以将它直接注册到 Lua 中。

    【讨论】:

      猜你喜欢
      • 2017-10-17
      • 2017-07-07
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 2011-02-03
      相关资源
      最近更新 更多