2009-09-17 7 views
19

J'essaye de charger des tables de Lua au C++ mais j'ai du mal à le faire correctement. Je passe à travers la première itération très bien, mais au deuxième appel à lua_next il se bloque. Des idées?itération à travers une table Lua à partir de C++?

fichier Lua:

level = { 1, 2, 3, } 

fichier C++ - D'abord, je l'ai fait:

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

Alors j'ai essayé de la 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); 

Et enfin ceci:

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

Naturellement, L est un lua_State * et je l'initialise et je l'analyse correctement.

Edit: En réponse à Jesse Beder réponse J'ai essayé ce code, avec un enregistreur, mais je ne peux toujours pas à travailler.

qui a donné cette sortie:

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 

Tout ce que vous avez dit, Jesse, semble vrai. Mais il échoue toujours à aller à l'itération suivante.

Edit2: J'ai essayé de copier le code exact dans un nouveau projet, en sautant toutes les classes environnantes et des choses que je ne l'ai pas pris la peine d'inclure ici et là cela fonctionne. Mais ici, il ne le fait pas, et il survivra juste un appel le lua_next.

Édition3: Je l'ai réduit un peu plus loin maintenant. J'utilise hge comme moteur 2D. Je mets tout le code précédent dans le test de fonctionnement:

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

Pour autant que je comprends HGE ne fait rien avec lua. Here est le code source d'un petit test que j'ai fait. La source pour hge 1.81 est here.

Éditer4: La taille de la question devient incontrôlable mais elle ne peut pas être prise en compte. C'est le plus petit code que j'ai pu réduire.

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

Alors le deuxième appel à 'lua_next' se bloque? C'est bizarre ... avez-vous des informations de débogage sur le crash (comme où il se bloque exactement)? En outre, juste pour s'assurer que les choses fonctionnent correctement, vous devez enregistrer la clé à chaque étape (il doit également s'agir d'un nombre) et modifier cette réponse. –

+0

J'ai ajouté la valeur de retour de lua_next. Je n'ai aucune information de débogage et je ne sais pas trop comment l'ajouter non plus ... – Jonas

+0

Cette deuxième édition est un indice - jetez un coup d'œil à l'édition de ma réponse –

Répondre

0

Pourquoi faites-vous la lua_pop(L, 1) supplémentaire à la fin de la version du manuel de référence? Je peux voir comment cela pourrait être un problème, puisque vous êtes au-delà de la profondeur de la pile.

+0

Je retire la table de la pile, dans le manuel il n'y a que l'index d'une table mais vous avez de pousser et de l'éclater quelque part aussi. – Jonas

27

Lorsque vous appelez lua_next, le deuxième argument doit être l'index de la table.Puisque vous êtes juste pousser la table sur la pile avec

lua_getglobal(L, "level"); 

après appeler votre pile ressemblera

 
-1: table "level" 

(pas +1, puisque la pile est en lecture à la baisse). Ensuite, vous appelez

lua_pushnil(L); 

de sorte que votre pile sera

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

Votre table est à -2, donc quand vous appelez lua_next, vous devez utiliser l'index -2. Enfin, après chaque itération, votre pile devrait ressembler à:

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

Donc, vous voulez lire la valeur (à -1), puis de la pop (donc juste une fois pop), puis appelez lua_next pour obtenir la clé suivante . Donc, quelque chose comme cela devrait fonctionner:

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

Modifier en fonction de votre deuxième édition

Puisqu'il fonctionne lorsque vous retirez des choses externes, mais ne pas lorsque vous ajoutez le dans, ma meilleure estimation est que vous corrompez la pile d'une façon ou d'une autre (soit la pile C++, soit la pile lua). Regardez vraiment soigneusement à vos pointeurs, surtout lorsque vous manipulez l'état lua.

+0

Je ne l'ai pas eu pour travailler - voir mon édition pour info. – Jonas

+0

Je l'ai réduit davantage, il y a encore une autre édition pour vous. – Jonas

1

lecture LUA manuel lua_next vous trouvez que les problèmes peuvent se poser sur l'utilisation lua_tostring sur une touche directement, qui vous devez vérifier la valeur de la clé, puis décider d'utiliser ou lua_tostring lua_tonumber. Donc, vous pouvez essayer ce code:

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

Espérons que ça aide.

Questions connexes