lua和C++交互的lua栈操作——以LuaTinker为例

 一、

 -- C++类注册函数(LuaTinker) 的lua栈操作:

--    lua栈内容(执行到pop语句)            栈地址        <--执行语句
space_name[name] = t1                      -- (2b8)     -- lua_rawset(L, -4);
-- t1[__gc] = destroyer<T>                  -- (2d8)     -- lua_rawset(L, -3);
-- destroyer<T>                              -- (2f8)     -- lua_pushcclosure(L, destroyer<T>, 0);
-- __gc                                      -- (2e8)     -- lua_pushstring(L, "__gc");
-- t1[__newindex] = meta_set              -- (2d8)     -- lua_rawset(L, -3);
-- meta_set                                  -- (2f8)     -- lua_pushcclosure(L, meta_set, 0);
-- __newindex                              -- (2e8)     -- lua_pushstring(L, "__newindex");
-- t1[__index] = meta_get                  -- (2d8)     -- lua_rawset(L, -3);
-- meta_get                                  -- (2f8)     -- lua_pushcclosure(L, meta_get, 0);
-- __index                                  -- (2e8)     -- lua_pushstring(L, "__index");
-- t1[__name] = name                      -- (2d8)     -- lua_rawset(L, -3);
-- name                                   -- (2f8)     -- lua_pushstring(L, name);
-- __name                                  -- (2e8)     -- lua_pushstring(L, "__name");
-- setmetatable(t1, t2)                  -- (2d8)     -- lua_setmetatable(L, -2);
-- t2[__index] = static_meta_get         -- (2e8)     -- lua_rawset(L, -3);
-- static_meta_get                        -- (308)     -- lua_pushcclosure(L, static_meta_get, 0);
-- __index                                -- (2f8)     -- lua_pushstring(L, "__index");
-- t2                                      -- (2e8)     -- lua_newtable(L);
-- t1                                      -- (2d8)     -- lua_newtable(L);
-- name                                 -- (2c8)     -- lua_pushstring(L, name);
-- space_name[name]                     -- (2b8)     -- lua_rawget(L, -2);
-- name                                 -- (2b8)     -- lua_pushstring(L, name);
space_name                                 -- (2a8)     -- push_meta(L, space_name::name);
L                                           -- (298)     -- 初始状态

 -- C++类注册函数(LuaTinker),支持注册到命名空间namespace

template<typename T>
void class_addEx(lua_State* L, const char* name) 
{
    push_meta(L, space_name::name());
    if(lua_istable(L, -1))
    {
        class_name<T>::name(name);

        lua_pushstring(L, name);
        lua_rawget(L, -2);
        if (!lua_istable(L, -1))
        {
            lua_pushstring(L, name);
            lua_newtable(L);

            lua_newtable(L);
            lua_pushstring(L, "__index");
            lua_pushcclosure(L, static_meta_get, 0);
            lua_rawset(L, -3);
            lua_setmetatable(L, -2);

            lua_pushstring(L, "__name");
            lua_pushstring(L, name);
            lua_rawset(L, -3);

            lua_pushstring(L, "__index");
            lua_pushcclosure(L, meta_get, 0);
            lua_rawset(L, -3);

            lua_pushstring(L, "__newindex");
            lua_pushcclosure(L, meta_set, 0);
            lua_rawset(L, -3);

            lua_pushstring(L, "__gc");
            lua_pushcclosure(L, destroyer<T>, 0);
            lua_rawset(L, -3);

            lua_rawset(L, -4);
        }
    }
    lua_pop(L, 2);
}

 二、

-- meta_get栈操作如下:
--    lua栈内容            栈地址        <--执行语句
t_meta[__index]            -- (ed8)     -- lua_rawget(L,-2); <-- 执行到此语句
-- __index                 -- (ed8)     -- lua_pushvalue(L,2);
t_meta                     -- (ec8)     -- lua_getmetatable(L,1);
__index                    -- (eb8)     -- 初始 lua_pushstring(L, "__index");
t                         -- (ea8)     -- 初始 
L                         -- (e98)     -- 初始状态
--// int lua_tinker::meta_get(lua_State *L)
int lua_tinker::meta_get(lua_State *L)
{
    lua_getmetatable(L,1);

    lua_pushvalue(L,2);
    lua_rawget(L,-2);

    bool is_dispatcher = false;
    const char* func_name = lua_tostring(L, 2);

    if(lua_isuserdata(L,-1))
    {
        user2type<var_base*>::invoke(L,-1)->get(L);
        lua_remove(L, -2);
    }
    else if (lua_istable(L, -1))
    {
        lua_remove(L, -1);
        is_dispatcher = true;
    }
    else if (lua_isnil(L, -1))
    {
        lua_remove(L, -1);
        invoke_parent(L, func_name);
        if (lua_isnil(L, -1))
        {
            lua_remove(L, -1);
            invoke_child(L, func_name);
        }
        if (lua_istable(L, -1))
        {
            lua_remove(L, -1);
            is_dispatcher = true;
        }
    }

    //函数分发
    if (is_dispatcher)
    {
        push_currfuncname(L, func_name);
        
        push_dispatcher(L);
    }
    
    lua_remove(L,-2);

    return 1;
}

三、

--> 假设:meta_get函数执行到上面语句(栈内容如上) ——> t_meta[__index] == nil ——> 进入invoke_parent(L, func_name);

--    lua栈内容                栈地址        <--执行语句
tt[funcname]                -- (e18)     -- lua_remove(L, -2);
-- tt[funcname]                -- (e28)     -- lua_rawget(L, -2); -->lua_istable(L, -1) || lua_isfunction(L, -1)
-- funcname                    -- (e28)     -- lua_pushstring(L, funcname); 
-- t_meta[__parent] = tt    -- (e18)     -- lua_rawget(L, -2); --> lua_istable(L,-1),重命名为tt
-- __parent                    -- (e18)     -- lua_pushstring(L, "__parent"); 
--                             -- (e08)     -- lua_remove(L, -1); 
-- t_meta[__index]            -- (e18)     -- lua_rawget(L,-2); 
t_meta                         -- (d08)     -- lua_getmetatable(L,1);
__index                        -- (cf8)     -- 初始 lua_pushstring(L, "__index");
t                             -- (ce8)     -- 初始 
L                             -- (cd8)     -- 初始状态(和上面的栈内容不匹配,因为是另一个过程,其满足t_meta[__index] == nil)
// static void invoke_parent(lua_State *L, const char* funcname)

static void invoke_parent(lua_State *L, const char* funcname)
{
    lua_pushstring(L, "__parent");
    lua_rawget(L, -2);
    if(lua_istable(L,-1))
    {
        lua_pushstring(L, funcname);
        lua_rawget(L, -2);

        if (lua_istable(L, -1) || lua_isfunction(L, -1))
        {
            lua_remove(L, -2);
        }
        else
        {
            lua_remove(L, -1);
            invoke_parent(L, funcname);
            lua_remove(L, -2);
        }
    }
}
原文地址:https://www.cnblogs.com/yyxt/p/4262500.html