经过大量谷歌搜索后,我想出了这个解决方案来获取编译器和运行时错误消息以及重定向标准 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 中。