如何从C ++中过滤掉Lua中用户定义的全局变量?

时间:2013-12-11 18:57:38

标签: c++ lua global-variables lua-5.2

考虑这个小的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?

由于用户可以自由编写脚本,我无法搜索特定的全局,我需要以某种方式区分它们。

2 个答案:

答案 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例程执行此操作)