c++ lua lua-table

¿Iterando a través de una tabla Lua de C++?



lua-table (3)

Estoy tratando de cargar tablas desde Lua a C ++ pero tengo problemas para hacerlo bien. Estoy superando la primera iteración, pero luego, en la segunda llamada a lua_next, se bloquea. ¿Algunas ideas?

Archivo lua:

level = { 1, 2, 3, }

Archivo C ++ - Primero hice esto:

lua_getglobal( L, "level" ); for( lua_pushnil( L ); lua_next( L, 1 ); lua_pop( L, -2 ) ) { if( lua_isnumber( L, -1 ) ) { int i = (int)lua_tonumber( L, -1 ); //use number } } lua_pop( L, 1 );

Entonces probé desde el manual de referencia :

lua_getglobal( L, "level" ); int t = 1; lua_pushnil( L ); while( lua_next( L, t ) ) { printf( "%s - %s", lua_typename( L, lua_type( L, -2 ) ), lua_typename( L, lua_type( L, -1 ) ) ); lua_pop( L, 1 ); } lua_pop( L, 1 );

Y finalmente esto:

lua_getglobal( L, "level" ); lua_pushnil( L ); lua_next( L, 1 ); if( lua_isnumber( L, -1 ) ) { int i = (int)lua_tonumber( L, -1 ); //use number fine } lua_pop( L, 1 ); lua_next( L, 1 ); //crashes etc...

Naturalmente, L es un estado_lua * y lo estoy inicializando y analizando bien el archivo.

Edit: En respuesta a la respuesta de Jesse Beder, probé este código con un registrador, pero todavía no puedo hacerlo funcionar.

Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) ); lua_getglobal(L, "level"); if( lua_istable( L, -1 ) ) Log::Get().Write( "engine", "-1 is a table" ); lua_pushnil(L); if( lua_isnil( L, -1 ) ) Log::Get().Write( "engine", "-1 is now nil" ); if( lua_istable( L, -2 ) ) Log::Get().Write( "engine", "-2 is now table" ); int pred = lua_next( L, -2 ); Log::Get().Write( "engine", "pred: %i", pred ); while( pred ) { Log::Get().Write( "engine", "loop stuff" ); if( lua_isnumber( L, -1 ) ) { int i = (int)lua_tonumber( L, -1 ); //use number Log::Get().Write( "engine", "num: %i", i ); } Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) ); if( lua_istable( L, -3 ) ) Log::Get().Write( "engine", "-3 is now table" ); lua_pop( L, 1 ); Log::Get().Write( "engine", "stack size: %i", lua_gettop( L ) ); if( lua_istable( L, -2 ) ) Log::Get().Write( "engine", "-2 is now table" ); pred = lua_next( L, -2 ); Log::Get().Write( "engine", "pred: %i", pred ); } lua_pop( L, 1 );

Lo que dio esta salida:

stack size: 0 -1 is a table -1 is now nil -2 is now table pred: 1 loop stuff num: 1 stack size: 3 -3 is now table stack size: 2 -2 is now table

Todo lo que dijiste, Jesse, parece ser cierto. Pero todavía no pasa a la siguiente iteración.

Edit2: traté de copiar el código exacto en un nuevo proyecto, saltándome todas las clases y cosas que no me molesté en incluir aquí y allá, funciona. Pero aquí no, y solo sobrevivirá una llamada al lua_next.

Edit3: Lo he reducido un poco más ahora. Estoy usando hge como mi motor 2D. Pongo todo el código anterior en la prueba de función:

test(); //works if( hge->System_Initiate() ) { test(); //fails hge->System_Start(); }

Según tengo entendido, Hge no hace nada con lua. Here está el código fuente de una pequeña prueba que hice. La fuente para hge 1.81 está here .

Edit4: El tamaño de la pregunta se está saliendo de control pero no se puede evitar. Este es el código más pequeño al que he podido reducirlo.

extern "C" { #include <lua/lua.h> #include <lua/lualib.h> #include <lua/lauxlib.h> } #include <hge/hge.h> bool frame_func() { return true; } bool render_func() { return false; } void test() { lua_State *L = lua_open(); luaL_openlibs( L ); if( luaL_dofile( L, "levels.lua" ) ) { lua_pop( L, -1 ); return; } lua_getglobal(L, "level"); lua_pushnil(L); while( lua_next( L, -2 ) ) { if( lua_isnumber( L, -1 ) ) { int i = (int)lua_tonumber( L, -1 ); //use number } lua_pop( L, 1 ); } lua_pop( L, 1 ); lua_close( L ); } int main() { HGE *hge = hgeCreate( HGE_VERSION ); hge->System_SetState( HGE_FRAMEFUNC, frame_func ); hge->System_SetState( HGE_RENDERFUNC, render_func ); hge->System_SetState( HGE_WINDOWED, true ); hge->System_SetState( HGE_SCREENWIDTH, 800 ); hge->System_SetState( HGE_SCREENHEIGHT, 600 ); hge->System_SetState( HGE_SCREENBPP, 32 ); //test(); //works if( hge->System_Initiate() ) { test(); //fails hge->System_Start(); } hge->Release(); return 0; }


¿Por qué haces el lua_pop(L, 1) extra lua_pop(L, 1) al final de la versión del manual de referencia? Puedo ver cómo eso podría ser un problema, ya que estás saltando más allá de la profundidad de la pila.


Al leer el manual de LUA lua_next encontrará que pueden surgir problemas al usar lua_tostring en una clave directamente, es decir, debe verificar el valor de la clave y luego decidir usar lua_tostring o lua_tonumber. Así que puedes probar este código:

std::string key while(lua_next(L, -2) != 0){ // in your case index may not be -2, check // uses ''key'' (at index -2) and ''value'' (at index -1) if (lua_type(L, -2)==LUA_TSTRING){ // check if key is a string // you may use key.assign(lua_tostring(L,-2)); } else if (lua_type(L, -2)==LUA_TNUMBER){ //or if it is a number // this is likely to be your case since you table level = { 1, 2, 3, } // don''t declare field ID''s // try: // sprintf(buf,"%g",lua_tonumber(L,-2)); // key.assign(buf); } else{ // do some other stuff } key.clear(); lua_pop(L,1) }

Espero eso ayude.


Cuando llama a lua_next , el segundo argumento debe ser el índice de la tabla. Ya que solo estas empujando la mesa en la pila con

lua_getglobal(L, "level");

después de esa llamada su pila se verá como

-1: table "level"

(No +1 , ya que la pila se lee bajando). Entonces llamas

lua_pushnil(L);

entonces tu pila será

-1: key (nil) -2: table "level"

Su tabla está en -2 , así que cuando llame a lua_next , debe usar el índice -2 . Finalmente, después de cada iteración, tu pila debe verse como:

-1: value -2: key -3: table "level"

Por lo tanto, desea leer el valor (en -1 ) y luego lua_next (solo lua_next una vez), y luego llamar a lua_next para obtener la siguiente clave. Así que algo como esto debería funcionar:

lua_getglobal(L, "level"); lua_pushnil(L); while(lua_next(L, -2)) { // <== here is your mistake if(lua_isnumber(L, -1)) { int i = (int)lua_tonumber(L, -1); //use number } lua_pop(L, 1); } lua_pop(L, 1);

Edición basada en tu segunda edición

Ya que funciona cuando eliminas cosas externas, pero no cuando lo vuelves a agregar, mi mejor conjetura es que estás corrompiendo la pila de alguna manera (ya sea la pila C ++ o la pila lua). Mire con mucho cuidado sus punteros, especialmente cuando manipula el estado lua.