2009-09-17 106 views
19

我試圖從Lua加載表到C++,但我很難得到它的權利。 我正在通過第一次迭代很好,但隨後在第二次調用 lua_next它崩潰。有任何想法嗎?從C++迭代通過Lua表?

的Lua文件:

level = { 1, 2, 3, } 

C++文件 - 首先,我這樣做:

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

最後這個:

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

然後我從reference manual嘗試

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

自然L是一個lua_State *,我正在初始化它並解析該文件。

編輯: 針對傑西·貝德爾答案我想這個代碼,用記錄儀,但我仍然無法得到它的工作。

這給了這樣的輸出:

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 

一切你說,傑西,似乎是正確的。但它仍未能進入下一次迭代。

EDIT2: 我想確切的代碼複製到一個新的項目,跳過所有周圍的類和東西我也懶得在這裏和那裏它的作品包括。但是在這裏它不會,而且只會在一個叫做lua_next的節目中生存下來。

編輯3: 我已經縮小了一點點。我使用hge作爲我的2D引擎。 我把功能測試的所有以前的代碼:

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

據我瞭解HGE不LUA做任何事情。 Here是我做的小測試的源代碼。 hge 1.81的來源是here

編輯4: 問題的大小越來越失控,但它無法幫助。這是我能夠減少到的最小代碼。

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

所以第二次調用'lua_next'崩潰?這很奇怪......你有任何關於崩潰的調試信息(比如崩潰的地方)?此外,爲了確保事情正常工作,您應該在每一步都記錄密鑰(它也應該是一個數字)並編輯此答案 – 2009-09-17 15:50:26

+0

我添加了lua_next的返回值。我沒有任何調試信息,我真的不知道如何添加它... – Jonas 2009-09-17 16:25:33

+0

第二次編輯是一個提示 - 檢查我的回答編輯 – 2009-09-17 19:26:17

回答

0

你爲什麼這樣做在距離參考手冊版本到底額外lua_pop(L, 1)?我可以看到這可能是一個問題,因爲你超出了堆棧深度。

+0

我從堆棧中刪除表,在手冊中只有表的索引,但你有推動並在某處彈出它。 – Jonas 2009-09-17 14:01:54

27

當您致電lua_next時,第二個參數應該是表的索引。既然你只需按下表到堆棧

lua_getglobal(L, "level"); 

後調用你的籌碼看起來就像

 
-1: table "level" 

(不+1,因爲堆棧讀下去)。然後調用

lua_pushnil(L); 

所以你的籌碼將是

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

你的表是在-2,所以當你打電話lua_next,你應該使用索引-2。最後,在每次迭代之後,你的籌碼應該是這樣的:

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

所以,你要讀值(-1),然後彈出它(所以只是彈出一次),然後調用lua_next獲得下一個關鍵。所以,這樣的事情應該工作:

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

編輯根據您的第二個編輯

因爲當你刪除外部的東西它的工作原理,但不會當你回來添加它,我最好的猜測是你以某種方式破壞堆棧(C++堆棧或lua堆棧)。仔細看看真的你的指針,特別是當你操縱lua狀態。

+0

我沒有得到它的工作 - 請參閱我的編輯信息。 – Jonas 2009-09-17 15:23:11

+0

我縮小了範圍,還有另一個編輯。 – Jonas 2009-09-17 20:00:50

1

閱讀LUA手冊lua_next您發現直接在鍵上使用lua_tostring可能會出現問題,即您必須檢查該鍵的值,然後決定使用lua_tostring或lua_tonumber。所以你可以試試這個代碼:

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

希望它有幫助。