考虑这个小的Lua测试脚本。
g1 = "Global 1"
g2 = "Global 2"
function test ()
local l1
print(g1,g2,l1)
end
test()
假设您暂停执行print(g1,g2,l1)并从C ++获取具有此C代码的所有全局变量:
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) {
const char* name = lua_tostring(L,-2);
// How do I tell a user defined
// global variable (now in name)
// from all other environment variables?
lua_pop(L,1);
}
lua_pop(L,1); // global table
当我得到全局条目的name
时,如何判断这是否是用户在脚本中定义的全局变量,如g1和g2?
由于用户可以自由编写脚本,我无法搜索特定的全局,我需要以某种方式区分它们。
答案 0 :(得分:5)
我看到两种方式。在第一个中,您在加载用户脚本之前记录所有全局变量的名称:
local S={}
_G["system variables"]=S
for k in pairs(_G) do S[k]=true end
然后在您的C代码中,遍历全局变量并仅过滤其名称在表"system variables"
中的变量。使用lua_getglobal(L,"system variables")
获取此表。
在第二种方式中,您在加载系统变量后跟踪全局变量的定义。您可以在加载用户脚本之前运行此脚本来设置它:
local U={}
_G["user variables"]=U
local function trace(t,k,v)
U[k]=true
rawset(t,k,v)
end
setmetatable(_G,{ __newindex = trace })
然后在您的C代码中,遍历全局变量并仅过滤那些名称不在表"user variables"
中的变量。使用lua_getglobal(L,"user variables")
获取此表。
在这两种情况下,都不要将_G
中的键转换为字符串:使用原始键直接索引特殊表。
请注意,您可以在遍历之前调用lua_getglobal(L,"system variables")
或lua_getglobal(L,"user variables")
一次,并在循环内重复索引。
答案 1 :(得分:4)
我的解决方案是在加载主脚本之前构建全局环境的哈希表。当我需要获取用户定义的全局变量时,我只显示散列表中不存在的全局变量。通过这种方式,脚本可以全速运行,而无需在运行时跟踪全局变量。
我的解决方案示例(这是我的实施的简短版本):
// The hash table storing global names
std::set<unsigned int> Blacklist;
// Create hash table "Blacklist"
void BlacklistSnapshot(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
Blacklist.insert(HashName(lua_tostring(L,-2))); // insert to hash table
lua_pop(L,1); // remove value
}
lua_pop(L,1); // Remove global table
}
// Display user defined globals only
void PrintGlobals(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
// Check if the global is present in our blacklist
if (Blacklist.find(HashName(lua_tostring(L,-2))) == Blacklist.end()) {
// Not present, print it...
PrintFormattedVariable(lua_type(L,-1),lua_tostring(L,-2));
}
lua_pop(L,1); // remove value
}
lua_pop(L,1); // remove global table
}
void RunScript(void) {
// Create new Lua state
L = luaL_newstate();
// Load all Lua libraries
luaL_openlibs(L);
// Create co-routine
CO = lua_newthread(L);
BlacklistSnapshot(CO);
// Load and compile script
AnsiString script(Frame->Script_Edit->Text);
if (luaL_loadbuffer(CO,script.c_str(),script.Length(),"Test") == LUA_OK) {
lua_resume(CO,NULL,0);
} else {
cs_error(CO, "Compiler error: "); // Print compiler error
}
}
函数HashName
接受一个字符串并将其作为unsigned int
的哈希键返回,使用您喜欢的任何哈希算法...
当您需要显示全局变量时,请调用PrintGlobals()
(我是从hook
例程执行此操作)