2015-06-19 2 views
4

У меня есть небольшое замешательство в том, как lua_next действительно работает. Пользователь определяет таблицу:Lua C++ Table Iteration

a={["a1"]=20,["a2"]=30} 

Я хочу напечатать эту таблицу с кодом C++:

inline int lua_print(lua_State* L) 
{ 
wxString wxReturnStr=wxEmptyString; 
wxString tempString=wxEmptyString; 
int nargs = lua_gettop(L); 

for (int i=1; i <= nargs; i++) 
{ 
    int type = lua_type(L, i); 
    switch (type) 
    { 

    case LUA_TNIL: 
     break; 

    case LUA_TBOOLEAN: 
     tempString<<(lua_toboolean(L, i) ? "true" : "false"); 
     break; 

    case LUA_TNUMBER: 
     tempString<<lua_tonumber(L, i); 
     break; 

     case LUA_TSTRING: 
      tempString<<lua_tostring(L, i); 
     break; 
     case LUA_TTABLE: 
     { 
      lua_pushnil(L); 
      while(lua_next(L,-2)) 
      { 
       const char* key=lua_tostring(L,-2); 
       double val=lua_tonumber(L,-1); 
       lua_pop(L,1); 
       tempString<<key<<"="<<val<<"\t"; 
      } 

      break; 
     } 

     default: 
      tempString<<lua_typename(L, type); 
     break; 
    } 

    wxReturnStr=wxReturnStr+tempString+"\n"; 
    tempString=wxEmptyString; 

} 

lua_pop(L,nargs); 

Этот код работает очень хорошо, когда я звоню из Lua:

print(a) -- Works well 

Однако, представьте себе, что у меня есть стол в Луа:

b={["b1"]=10, ["b2"]=15} 

, если я позвоню код как:

print(a,b) -- Twice prints only contents of b 

Моего понимание с тем, как lua_next работы на следующий рисунке: enter image description here [версия # 1]

Где эта ошибка?

+0

Как вы назначаете 'a' и' b'? – Kyle

ответ

2

Ошибка в строке lua_next(L, -2), потому что -2 относится к вершине стека минус один, что здесь является последним аргументом print.

Используйте вместо этого lua_next(L, i).

Upd: Lua индексы стека могут плавать при перемещении кода вокруг на стадии разработки, так что общий совет приколоть индексы с SML int t = lua_gettop(L) только после получения/толкания/с учетом значения и использовать это t вместо -n (хотя этот конкретный случай кажется своего рода ошибкой нажатия клавиши.)

+0

Ваше предложение 'lua_next (L, i)' работает. Однако я теперь смущен ... Когда я использую 'lua_next (L, 1)' для i = 1, это относится к нижней части стека, как я понимаю. Однако, когда я говорю 'lua_pop (L, 1)' это выскакивает из верхней части стека. Я не уверен, как он работает ... – macroland

+0

@macroland Некоторые функции принимают * стековые индексы * (1..top/-top ..- 1) в качестве аргументов, другие принимают * count *. lua_next(), lua_tostring(), lua_getfield() принимают индексы стека. lua_pop(), lua_concat() принимают * число значений * для удаления/конкатенации в верхней части стека. Вы просто не можете выскочить из середины стека, поэтому lua_remove() существует. Если есть сомнения, обратитесь к документации конкретной функции. – user3125367

+0

Спасибо!Когда мы говорим 'lua_next (L, i)' для i = 1, то это относится к нижней части стека, элемент с абсолютным индексом 1. Однако, когда мы выходим из стека, единственный способ, которым мы можем поп, - это наверху наверняка. Теперь, если у меня есть две таблицы в стеке (таблица a по индексу 1, таблица b в индексе 2), когда мы запускаем 'lua_next (L, 1)', код ссылается на таблицу a. Это «принимает» значения из таблицы a и нажимает на стек. Теперь использование idx = -1 для значения и idx = -2 для ключа имеет смысл. Я понимаю, что lua_next внутренне делает что-то, чтобы удалить таблицу a (с индексом 1) из стека. – macroland

0

Вы забыли lua_pop после обработки таблицы.

lua_pushnil(L); 
     while(lua_next(L,-2)) 
     { 
      const char* key=lua_tostring(L,-2); 
      double val=lua_tonumber(L,-1); 
      lua_pop(L,1); 
      tempString<<key<<"="<<val<<"\t"; 
     } 
lua_pop(L, 1); // THE FIX, pops the nil on the stack used to process the table 

Это означает, что дополнительный ноль остается в стеке, поэтому во второй итерации

case LUA_TNIL: 
    break; 

просто ничего не печатает.

О вашем графическом представлении стека. Команда под каждым изображением представляет состояние после, вызвав команду. Таким образом, в последнем изображении отсутствует элемент [Key = a2] в стеке.

+0

OPs while loop не оставляет нулевого в стеке, потому что lua_next потребляет начальное значение nil и ничего не толкает при возврате 0. – user3125367

+0

Ваше предложение использовать 'lua_pop (L, 1)' в конце блока, который я действительно пробовал перед публикацией здесь не работает. Например, для 'print (a, b)' он только печатает первый аргумент, а второй аргумент выставляется перед его печатью. – macroland