lua和c的交互

  1. extern "C" { 
  2. #include "lua.h" 
  3. #include "lualib.h" 
  4. #include "lauxlib.h" 
  5.   
  6. #include <iostream> 
  7. #include <string> 
  8. using namespace std; 
  9.      
  10. int main() 
  11.     //Lua示例代碼 
  12.     char *szLua_code = 
  13.         "r = string.gsub(c_Str, c_Mode, c_Tag) --宿主給的變量 "
  14.         "u = string.upper(r)"
  15.     //Lua的字符串模式 
  16.     char *szMode = "(%w+)%s*=%s*(%w+)"
  17.     //要處理的字符串 
  18.     char *szStr = "key1 = value1 key2 = value2"
  19.     //目標字符串模式 
  20.     char *szTag = "<%1>%2</%1>"
  21.   
  22.     lua_State *L = luaL_newstate(); 
  23.     luaL_openlibs(L); 
  24.   
  25.     //把一個數據送給Lua 
  26.     lua_pushstring(L, szMode); 
  27.     lua_setglobal(L, "c_Mode"); 
  28.     lua_pushstring(L, szTag); 
  29.     lua_setglobal(L, "c_Tag"); 
  30.     lua_pushstring(L, szStr); 
  31.     lua_setglobal(L, "c_Str"); 
  32.   
  33.     //執行 
  34.     bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code), 
  35.                 "demo") || lua_pcall(L, 0, 0, 0); 
  36.     if(err) 
  37.     { 
  38.         //如果錯誤,顯示 
  39.         cerr << lua_tostring(L, -1); 
  40.         //彈出棧頂的這個錯誤信息 
  41.         lua_pop(L, 1); 
  42.     } 
  43.     else
  44.     { 
  45.         //Lua執行後取得全局變量的值 
  46.         lua_getglobal(L, "r"); 
  47.         cout << "r = " << lua_tostring(L,-1) << endl; 
  48.         lua_pop(L, 1); 
  49.          
  50.         lua_getglobal(L, "u"); 
  51.         cout << "u = " << lua_tostring(L,-1) << endl;     
  52.         lua_pop(L, 1); 
  53.     } 
  54.     lua_close(L); 
  55.     return 0; 


    這段代碼把字符串中的key=value字符串全部轉換成XML格式<key>value</key>
    在這個例子中,C++程序通過調用lua_pushstring把C字符串壓入棧頂,lua_setglobal的作用是把棧頂的數據傳到Lua環境中作爲全局變量。
    執行代碼完成後,使用lua_getglobal從Lua環境中取得全局變量壓入棧頂,然後使用lua_tostring把棧頂的數據轉成字符串。由於lua_tostring本身沒有出棧功能,所以爲了平衡(即調用前與調用後棧裏的數據量不變),使用lua_pop彈出由lua_setglobal壓入的數據。
    從上面的例子可以看出,C++和Lua之間一直圍繞着棧在轉,可見棧是極爲重要的。有必要列出一些Lua C API中的主要棧操作先,它們的作用直接可以從函數名中看出。
壓入元素到棧裏

void lua_pushnil (lua_State *L);    
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
void lua_pushcfunction (lua_State *L, lua_CFunction fn);


查詢棧裏的元素

lua_isnil (lua_State *L, int index);
lua_isboolean (lua_State *L, int index);
int lua_isnumber (lua_State *L, int index);
int lua_isstring (lua_State *L, int index);
int lua_isfunction (lua_State *L, int index);
int lua_istable (lua_State *L, int index);
int lua_isuserdata (lua_State *L, int index);
lua_islightuserdata (lua_State *L, int index);
lua_isthread (lua_State *L, int index);

 

轉換棧裏的元素

int                lua_toboolean (lua_State *L, int index);
double            lua_tonumber (lua_State *L, int index);
const char *    lua_tostring (lua_State *L, int index);
const char *    lua_tolstring (lua_State *L, int idx, size_t *len);
size_t            lua_strlen (lua_State *L, int index);
lua_CFunction   lua_tocfunction (lua_State *L, int idx);
void *          lua_touserdata (lua_State *L, int idx);
lua_State *     lua_tothread (lua_State *L, int idx);

 

Lua棧的維護

int  lua_gettop (lua_State *L);
    取得棧頂元素的索引,即棧中元素的個數
void lua_settop (lua_State *L, int index);
    設置棧頂索引,即設置棧中元素的個數,如果index<0,則從棧頂往下數,下同
void lua_pushvalue (lua_State *L, int index);
    把棧中指定索引的元素複製一份到棧頂
void lua_remove (lua_State *L, int index);
    刪除指定索引的元素
void lua_insert (lua_State *L, int index);
    移動棧頂元素到指定索引的位置,棧中數目沒有改變
void lua_replace (lua_State *L, int index);
    從棧頂彈出元素值並將其設置到指定索引位置,棧中的數目減一
int  lua_checkstack (lua_State *L, int extra);
    確保堆棧上至少有 extra 個空位。如果不能把堆棧擴展到相應的尺寸,函數返回 false 。這個函數永遠不會縮小堆棧。
int  lua_pop(L,n)
    從棧頂彈出n個元素,它是一個lua_settop的包裝:#define lua_pop(L,n)  lua_settop(L, -(n)-1)

 

表的操作
上面的列表中並沒有lua_pushtable和lua_totable,那麼怎樣取得或設置Lua中的table數據呢?
在Lua中,table是一個很重要的數據類型,在table中不僅可以象C中的數據一樣放一組數據,還可以象map一樣以key=value的方式存放數據,如Lua代碼中的:

tb = {"abc",12,true,x=10,y=20,z=30}

    前三個數據可以用tb[1]~tb[3]取得
    而後三個數據通過tb.x, tb.y, tb.z取得
儘管看起來很牛叉,不過剝開神奇的外衣,實際上Lua的table中,所有的數據都是以key=value的形式存放的,這句Lua代碼也可以寫成:

tb = {[1]="abc", [2]=12, [3] = true, ["x"]=10, ["y"]=20, ["z"]=30}

    它的形式就是[key]=value,所謂的tb.x只是tb["x"]的語法糖而已,如果願意,也可以用tb["x"]取得這個數據10。
我們把上面的例子改成使用表的

  1. ... 
  2. int main() 
  3.     //Lua示例代碼,使用table 
  4.     char *szLua_code = 
  5.         "x = {} --用於存放結果的table "
  6.         "x[1],x[2] = string.gsub(c.Str, c.Mode, c.Tag) --x[1]裏是結果,x[2]裏是替換次數 "
  7.         "x.u = string.upper(x[1])"
  8.     //Lua的字符串模式 
  9.     char *szMode = "(%w+)%s*=%s*(%w+)"
  10.     //要處理的字符串 
  11.     char *szStr = "key1 = value1 key2 = value2"
  12.     //目標字符串模式 
  13.     char *szTag = "<%1>%2</%1>"
  14.   
  15.     lua_State *L = luaL_newstate(); 
  16.     luaL_openlibs(L); 
  17.   
  18.     //把一個tabele送給Lua 
  19.     lua_newtable(L);    //新建一個table並壓入棧頂 
  20.     lua_pushstring(L, "Mode");// key 
  21.     lua_pushstring(L, szMode);// value 
  22.     //設置newtable[Mode]=szMode 
  23.     //由於上面兩次壓棧,現在table元素排在棧頂往下數第三的位置 
  24.     lua_settable(L, -3); 
  25.     //lua_settable會自己彈出上面壓入的key和value 
  26.   
  27.     lua_pushstring(L, "Tag");// key 
  28.     lua_pushstring(L, szTag);// value 
  29.     lua_settable(L, -3);    //設置newtable[Tag]=szTag 
  30.   
  31.     lua_pushstring(L, "Str");// key 
  32.     lua_pushstring(L, szStr);// value 
  33.     lua_settable(L, -3);    //設置newtable[Str]=szStr 
  34.   
  35.     lua_setglobal(L,"c"); //將棧頂元素(newtable)置爲Lua中的全局變量c 
  36.   
  37.     //執行 
  38.     bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code), 
  39.                 "demo") || lua_pcall(L, 0, 0, 0); 
  40.     if(err) 
  41.     { 
  42.         //如果錯誤,顯示 
  43.         cerr << lua_tostring(L, -1); 
  44.         //彈出棧頂的這個錯誤信息 
  45.         lua_pop(L, 1); 
  46.     } 
  47.     else
  48.     { 
  49.         //Lua執行後取得全局變量的值 
  50.         lua_getglobal(L, "x"); 
  51.   
  52.         //這個x應該是個table 
  53.         if(lua_istable(L,-1)) 
  54.         { 
  55.             //取得x.u,即x["u"] 
  56.             lua_pushstring(L,"u");    //key 
  57.             //由於這次壓棧,x處於棧頂第二位置 
  58.             lua_gettable(L,-2); 
  59.             //lua_gettable會彈出上面壓入的key,然後把對應的value壓入 
  60.             //取得數據,然後從棧中彈出這個value 
  61.             cout << "x.u = " << lua_tostring(L,-1) << endl; 
  62.             lua_pop(L, 1); 
  63.              
  64.             //取得x[1]和x[2] 
  65.             for(int i=1; i<=2; i++) 
  66.             { 
  67.                 //除了key是數字外,與上面的沒什麼區別 
  68.                 lua_pushnumber(L,i); 
  69.                 lua_gettable(L,-2); 
  70.                 cout << "x[" << i <<"] = " << lua_tostring(L,-1) << endl; 
  71.                 lua_pop(L, 1); 
  72.             } 
  73.         } 
  74.   
  75.         //彈出棧頂的x 
  76.         lua_pop(L, 1); 
  77.     } 
  78.     lua_close(L); 
  79.     return 0; 

本例中用到的新Lua C API是:

void lua_newtable (lua_State *L);
    新建一個空的table並壓入棧頂。
void lua_settable (lua_State *L, int idx);
    lua_settable以table在棧中的索引作爲參數,並將棧頂的key和value出棧,用這兩個值修改table。
void lua_gettable (lua_State *L, int idx);
    lua_gettable以table在棧中的索引作爲參數,彈出棧頂的元素作爲key,返回與key對應的value並壓入棧頂。
最後,Lua告別針對table提供了存取函數
void lua_rawgeti (lua_State *L, int idx, int n)
    取得table[n]並放到棧頂,上例中69-70行的lua_pushnumber(L,i);lua_gettable(L,-2);可以用lua_rawgeti(L,-1)代替。
lua_getfield (lua_State *L, int idx, const char *k)
    取得table.k並放到棧頂,上例中57-59行的lua_pushstring(L,"u");lua_gettable(L,-2);可以替換成lua_getfield(L,-1,"u")。
void lua_setfield (lua_State *L, int idx, const char *k)
    把棧頂的數據作爲value放入table.k中,上例中的形如lua_pushstring(L, "key");lua_pushstring(L, value);lua_settable(L, -3);可以改成lua_pushstring(L, value);lua_setfield(L,-2,"key");的形式。
void lua_rawseti (lua_State *L, int idx, int n)
    把棧頂的數據作爲value放入table[n]中
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章