c#读取lua嵌套表格

来源:互联网 发布:mac landesk 卸载 编辑:程序博客网 时间:2024/06/05 00:38

新项目,准备把行为树挪过来,需要解析行为树的xml配置。因为现在的项目使用的是lua配置,所以想可不可以使用嵌套table来实现xml的功能。

1 lua table 常用方法

lua与其他语言交互都是使用栈进行的,所以熟练掌握各种api对应的栈操作很重要。对于table比较重要的几个api和相应操作如下:

1.1 lua_gettable

lua_getglobal(L, "mytable") <== push mytablelua_pushnumber(L, 1)        <== push key 1lua_gettable(L, -2)         <== pop key 1, push mytable[1]

1.2 lua_settable

lua_getglobal(L, "mytable") <== push mytablelua_pushnumber(L, 1)        <== push key 1lua_pushstring(L, "abc")    <== push value "abc"lua_settable(L, -3)         <== mytable[1] = "abc", pop key & value

1.3 lua_rawget:

用法同lua_gettable,但更快(因为当key不存在时不用访问元方法__index)

1.4 lua_rawset:

用法同lua_settable,但更快(因为当key不存在时不用访问元方法__newindex)

1.5 lua_rawgeti必须为数值键

lua_getglobal(L, "mytable") <== push mytablelua_rawgeti(L, -1, 1)       <== push mytable[1],作用同下面两行调用--lua_pushnumber(L, 1)      <== push key 1--lua_rawget(L,-2)          <== pop key 1, push mytable[1]

1.6 lua_rawseti必须为数值键

lua_getglobal(L, "mytable") <== push mytablelua_pushstring(L, "abc")    <== push value "abc"lua_rawseti(L, -2, 1)       <== mytable[1] = "abc", pop value "abc"

1.7 lua_getfield必须为字符串键

lua_getglobal(L, "mytable") <== push mytablelua_getfield(L, -1, "x")    <== push mytable["x"],作用同下面两行调用--lua_pushstring(L, "x")    <== push key "x"--lua_gettable(L,-2)        <== pop key "x", push mytable["x"]

1.8 lua_setfield必须为字符串键

lua_getglobal(L, "mytable") <== push mytablelua_pushstring(L, "abc")    <== push value "abc"lua_setfield(L, -2, "x")    <== mytable["x"] = "abc", pop value "abc"

2 迭代及递归遍历table

2.1 lua_next

上文中的api大多需要知道key,这个可以解析固定格式的k-v对,但是想要递归遍历嵌套表格,就需要在不知道具体key值的情况下进行迭代。这时候需要lua_next接口。
lua_next

上图显示了lua_next在调用过程中栈的变化情况(这里省略了栈底元素table),整个过程分为以下几步:

1. 如果栈顶元素为nil,则弹出nil,将table第一个k-v对中的key和value先后入栈,返回true;
2. 如果栈顶元素为key,先弹出当前key,并以该key为基础,将table的下一个k-v对中的key和value先后入栈,返回true;
3. 如果栈顶元素为最后一个key,则弹出key,然后返回false;

再用代码示意一遍。

//循环遍历lua_pushnil(L);此时lua栈状态----------------------------------|  -1 nil|  -2 table NUMBER_TABLE----------------------------------while(lua_next(L,-2)){    此时lua栈状态    ----------------------------------    |  -1 value    |  -2 key    |  -3 table NUMBER_TABLE    ----------------------------------    if(lua_isnumber(L,-2))        cout<<"key:"<<lua_tonumber(L,-2)<<'\t';    else if(lua_isstring(L,-2))        cout<<"key:"<<lua_tostring(L,-2)<<'\t';    if(lua_isnumber(L,-1))        cout<<"value:"<<lua_tonumber(L,-1)<<endl;    else if(lua_isstring(L,-1))        cout<<"value:"<<lua_tostring(L,-1)<<endl;    /*此时lua栈状态    ----------------------------------    |  -1 value    |  -2 key    |  -3 table NUMBER_TABLE    ----------------------------------    */    lua_pop(L,1);    /*此时lua栈状态    ----------------------------------    |  -1 key    |  -2 table NUMBER_TABLE    ----------------------------------    */}/*此时lua栈状态----------------------------------|  -1 table NUMBER_TABLE----------------------------------*/

2.2 递归访问lua_table

了解了lua_next的工作原理之后,我们可以使用其进行递归访问table。

void ParseLuaTable(lua_State *L){    if (!lua_istable(L, -1))    {        return;    }    lua_pushnil(L);    while (lua_next(L, -2))    {        fprintf(stdout, "%s : %s    ", luaL_typename(L,-2), luaL_typename(L,-1));        int nKeyType = lua_type(L, -2);        int nValueType = lua_type(L, -1);        if (nKeyType == LUA_TNUMBER)            fprintf(stdout, "%g,", lua_tonumber(L, -2));        else if (nKeyType == LUA_TSTRING)            fprintf(stdout, "\"%s\",", lua_tostring(L, -2));        if (nValueType == LUA_TNUMBER)            fprintf(stdout, "%g", lua_tonumber(L, -1));        else if (nValueType == LUA_TSTRING)            fprintf(stdout, "\"%s\"", lua_tostring(L, -1));        else if (nValueType == LUA_TTABLE)        {            fprintf(stdout, "\n");            // 这里进行递归访问table            ParseLuaTable(L);        }           lua_pop(L, 1);        fprintf(stdout, "\n");       }}int test(){    lua_State *L = luaL_newstate();    luaL_openlibs(L);    int error = 0;    // test.lua     //s = {    //g = "g",    //b = "b",    //r = 2,    //t = {    //    width = 100,    //    height = 200,    //    path = "path",    //    te = { a = 1, b = 2}    //},    //    //3,    //4,    //5,    //"test"    //}    //    luaL_loadfile(L, "test.lua");    error = lua_pcall(L, 0, 0, 0);    if (error) {        fprintf(stderr, "%s", lua_tostring(L, -1));        lua_pop(L, 1);/* pop error message from the stack */    }    lua_getglobal(L, "s");    ParseLuaTable(L);    if (error) {        fprintf(stderr, "%s", lua_tostring(L, -1));        lua_pop(L, 1);/* pop error message from the stack */    }    return 0;}

了解了这些api的使用原理,使用table嵌套构造行为树配置就方便的多。而且,相比xml配置,lua配置更加简洁灵活。

这里要注意一个问题,lua_next在对表格中的k-v对进行遍历的时候,不保证顺序!!!
这里要注意一个问题,lua_next在对表格中的k-v对进行遍历的时候,不保证顺序!!!
这里要注意一个问题,lua_next在对表格中的k-v对进行遍历的时候,不保证顺序!!!