【问题标题】:Placeholder evaluation of lua codelua代码的占位符评估
【发布时间】:2009-10-20 23:41:03
【问题描述】:

我有一个使用 lua 文件的应用程序,它的一些更晦涩的配置选项。因此,它主要包含对应用程序的调用以创建事物和更改属性;大多数 C 函数没有返回值,但有些有。

我现在需要将这些相同的配置文件读入不同的应用程序,并在调用函数时执行明显不同的事情(所以我不能使用通用代码)。此外,我只对可能的函数的子集感兴趣,我认为我可以默认忽略(和/或返回 nil)任何其他函数调用。

所以我想知道这里最好的方法是什么。如何(从 C++ 应用程序)加载和执行 lua 脚本,以便表达式等被正常评估,但我可以拦截和处理某些应用程序定义的 C 函数,同时简单地忽略(如果需要,返回 nil)对任何其他 C 的调用函数?

(注意:我确实可以访问原始应用程序的词汇表,它主要使用 luabind;我可以使用相同的定义并更改实现,但这太脆弱了,因为原始应用程序可以添加更多功能稍后。我想要更通用的东西。)


我们的目标是获得一些可以用作通用占位符的 C 代码;最终结果是“任何已定义的程序(标准库例程、Lua 中定义的函数和显式注册的 C 函数),都照常调用它;对于其他任何事情,调用一个什么都不做的特定例程,而不是引发错误”。最好是与 luabind 兼容的东西。

整个过程由一段 C 代码启动,设置 Lua 环境,加载一组文件,调用一个函数,然后销毁环境。不会有任何进展。

【问题讨论】:

    标签: lua


    【解决方案1】:

    为 nil 设置一个 __call 元方法:

    debug.setmetatable(nil, { __call=function () end })
    

    _G 或其他表的 _index 元方法不起作用,因为名称在调用之前解析。

    (如果您从 C 中设置,则无需使用调试 API 或库。)

    【讨论】:

    • 我已经勾选了这个(暂时),因为到目前为止它似乎比其他选项工作得更好,尽管它确实需要提前注册包含函数的表/子表。 (没关系,但如果这也能自动处理就更好了。)
    • 我不确定你的意思,但是你可以在上表中添加__index:debug.setmetatable(nil, { __call=function () end, __index=function() end }) 这个如果 a 未定义,将使 a.b 返回 nil。
    • 抱歉耽搁了,但我已经在其他项目上工作了一段时间。使用 __index 似乎也能做我想做的事,谢谢!
    【解决方案2】:

    使用setfenvmetatable 怎么样?您可以用空表替换某些函数的全局环境表。然后,将占位符函数设置为忽略 C 定义的函数。

    local env = {}  -- empty environment
    local metatbl = {}
    function metatbl.__index (tbl, key)  -- provides placeholder function
        return function()
            print(key .. " called")
            return(nil)
        end
    end
    
    setmetatable(env, metatbl)
    
    function samplefunc()  -- your Lua code goes here
        globalfunction "xyz"   -- calls placeholder function
    end
    
    setfenv(samplefunc, env)
    samplefunc()
    

    如果你想使用 print 这样的内置函数,你可以将它推送到 env talbe 中,例如:

    local env = {print = print}
    

    【讨论】:

    • 对不起,我可能没有正确解释这一点。我希望所有标准 Lua 库函数仍能正常工作(尽管已经说过,忽略文件 i/o 函数等某些函数会很有用)。而且我不想写更多的lua代码;替换函数正在替换 C 函数,它们本身应该是用 C 编写的,设置的代码也应该是 C。
    • @Miral:您对标准库函数的问题已在此答案的末尾进行了介绍。此外,任何用 Lua 编写的东西都可以写成 C(尽管会更难)。此外,luaL_dostring() 可用于从 C 中加载类似的 Lua 代码。
    • @gwell:有点,只是需要单独添加我想要工作的每一件事,这不是很好。我尝试了一个变体,将 env 设置为 getfenv(0) 而不是 {}。这适用于全局函数,但不适用于子表中的函数,并且在这种情况下给了一个相当模糊的(对用户)错误。
    【解决方案3】:

    如果您有某种方法可以将 C 函数与脚本中的普通 Lua 函数区分开来,您可以遍历 Lua 系统中定义的所有函数,以及每个不在您关心的函数列表中的 C 函数关于,用一个简单的返回零的函数替换该函数的实现。如果所有的 c 绑定函数都整齐地定义在一个表中,这真的很容易;如果他们在_G 中,那么您还有一些工作要做。你关心的函数会像往常一样通过 luabind 绑定。

    【讨论】:

    • 有些是全局的,有些在表中(有些在子表中)。在这种情况下,我很高兴假设没有错误,所以基本上任何已经定义为函数的东西都必须是 lua 函数,而任何未知的东西都可能是 C 函数或表名。我确实知道表的名称和当前存在的函数,但我希望不要依赖这些知识,因为原始应用程序是可扩展的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 2018-11-05
    • 2017-05-26
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    相关资源
    最近更新 更多