2009-09-17 24 views
19

Estoy tratando de cargar tablas de Lua a C++ pero estoy teniendo problemas para hacerlo bien. Estoy repasando la primera iteración, pero luego en la segunda llamada al lua_next falla. ¿Algunas ideas? archivoIterar a través de una tabla Lua de C++?

Lua:

archivo
level = { 1, 2, 3, } 

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); 

Luego he intentado desde el reference manual:

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... 

Naturally L es un lua_State * y lo estoy inicializando y analizando bien el archivo.

Editar: En respuesta a la respuesta Jesse Beder yo probamos este código, con un registrador, pero todavía no puede conseguir que funcione.

Que dio este resultado:

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 dijo, Jesse, parece ser verdad. Pero aún no pasa a la siguiente iteración.

Edit2: He intentado copiar el código exacto en un nuevo proyecto, saltándose todas las clases de los alrededores y cosas que no se molestan en incluir aquí y allí funciona. Pero aquí no es así, y sobrevivirá a una llamada al lua_next.

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

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

Por lo que yo entiendo hge no hace nada con lua. Here es el código fuente de una pequeña prueba que realicé. La fuente de hge 1.81 es here.

Edit4: tamaño 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; 
} 
+0

¿Entonces la segunda llamada a 'lua_next' se bloquea? Esto es raro ... ¿tienes alguna información de depuración en el bloqueo (como donde se bloquea exactamente)? Además, para asegurarse de que las cosas funcionen correctamente, debe registrar la clave en cada paso (también debe ser un número) y editar esta respuesta –

+0

Agregué el valor de retorno de lua_next. No tengo ninguna información de depuración y tampoco sé cómo agregarlo ... – Jonas

+0

Esa segunda edición es una pista: revisa la edición en mi respuesta –

Respuesta

0

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

+0

Estoy eliminando la tabla de la pila, en el manual solo aparece el índice de una tabla, pero usted tiene para empujar y estallar en algún lugar también. – Jonas

27

Cuando llame al lua_next, el segundo argumento debe ser el índice de la tabla.Puesto que usted está simplemente empujando la mesa en la pila con

lua_getglobal(L, "level"); 

después de que llame a su pila se verá como

 
-1: table "level" 

(no +1, ya que la pila se lee va hacia abajo). Posteriormente, se llama

lua_pushnil(L); 

por lo que su pila habrá

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

Su mesa está en -2, por lo que cuando se llama a lua_next, se debe utilizar el índice -2. Finalmente, después de cada iteración, su pila debe verse como:

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

Así que quieres leer el valor (en -1) y luego el pop (lo que acaba de hacer estallar una vez), y luego llamar a lua_next para obtener la clave siguiente . 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); 

Editar basado en su segunda edición

Desde funciona cuando se quita la materia externa, pero no cuando se agrega de nuevo, mi mejor conjetura es que está corrompiendo la pila de alguna manera (ya sea la pila C++ o la pila lua). Mire realmente con cuidado en sus punteros, especialmente cuando manipula el estado lua.

+0

No lo hice funcionar - ver mi edición para obtener información. – Jonas

+0

Lo reduje aún más, hay otra edición para ti. – Jonas

1

Leyendo LUA manual lua_next encuentra que pueden surgir problemas al usar lua_tostring en una clave directamente, es decir, tiene que verificar el valor de la clave y luego decide usar lua_tostring o lua_tonumber. Para que pueda 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 que ayude.

Cuestiones relacionadas