Как отфильтровать пользовательские глобалы в Lua из C ++?

Рассмотрим небольшой тестовый скрипт Lua.

g1 = "Global 1"g2 = "Global 2"
function test ()
local l1
print(g1,g2,l1)
end

test()

Предположим, вы приостановили выполнение при печати (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

Решение

Я вижу два пути. Во-первых, вы записываете имена всех глобальных переменных перед загрузкой пользовательских скриптов:

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") только один раз, перед обходом, и индексируйте его повторно в цикле.

5

Другие решения

Мое решение состояло в том, чтобы создать хеш-таблицу глобальной среды до того, как я загрузил основной скрипт. Когда мне нужно получить определяемые пользователем глобальные переменные, я отображаю только глобальные переменные, которых нет в хеш-таблице. Таким образом, скрипт может работать на полной скорости, не отслеживая глобальные переменные во время выполнения.

Пример моего решения (это краткая версия моей реализации):

// 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 рутина)

4

По вопросам рекламы [email protected]