8

如何将lua函数块转储到字符串?

function test(a, b)
  local c = a + b
  return c
end

print( type(test) )  --> function
print( test )         --> function: 0053B108
print( dumpToString(test) )

我希望 dumpToString 结果如下:

function test(a, b)
  local c = a + b
  return c
end

这个怎么做 ?

=== update1 ===
我想自动记录和注入代码。

4

5 回答 5

6

你没有说你为什么要这样做,这可能很重要。您可以将函数转储为字符串,但它不会是一个非常易读的字符串;您可以通过这种方式存储和传输您的函数(在兼容的 Lua 引擎之间):

string.dump(function() print "Hello" end)
于 2013-02-06T16:58:58.987 回答
6

没有简单的答案(经过这么多年,仍然如此)。我将详细说明替代方案。

1 考古学教授的回答(还有一点拆解):

这个古老问题的答案在于原始问题。即,luadec。可能是那时它处于停机状态,但是,至少到目前为止,有一个更新版本,它可以处理 lua 5.1-.3。

此外,它string.dump提供的不是完整的胡言乱语,它以机器指令的原始字节提供程序代码,您可以看到带有luac -l -p <filename>. vm 代码没有很好地记录,但人们确实在这里整理了一些东西。Luajit 在自己的指令集上有更好的文档。

从 vm 指令重建代码是 luadec 所做的。理论上,您也可以将自己的指令拼接到转储字符串中。

然而,无论你对字节码做了什么技巧,它都会遇到不同解释器之间的不兼容,包括 lua 本身的不同版本。

2.实际做X

将函数转换为字符串是一种非常特殊的愿望(除非您正在生成代码,在这种情况下,您首先已经有了字符串)。

“记录并注入代码”确实是相当一般的 X,这可能保证 Y 得到解决。但是单一的案例可以由单一的措施覆盖。Lua 是一种非常灵活的语言,例如,您可以x通过将其设为对象来跟踪示例中值的流动:

local to2number = tonumber
tonumber= function(o)
    local r= to2number(o) 
    if not r then
        local m= getmetatable(o)
        if m and m.__tonumber then
            r=m.__tonumber(o)
        end
    end
    return r
end
local number
number={
    new=function(n)
        return setmetatable({n},number)
    end,
    __add=function(me,other)
        print("I'm "..tostring(me).." and I'm being added to "..tostring(other))
        local o=tonumber(other) 
        return number.new(me[1]+o)
    end,
    __tonumber=function(me) return me[1] end,
    __tostring=function(me) return tostring(me[1]) end,
}
test(number.new(4), number.new(10))

如上例所示,您可以通过更改函数的环境来注入行为。也就是说,我已经重新定义了 global function tonumber。您可能希望在不同的环境中完全打包函数:

local test = function() print"hello" end
local newenv={print=function(s) print(s..'world')  end}
setfenv(test,newenv)--this is lua 5.1, luajit, good luck with upvalues
local test = load(string.dump(test),nil,nil,newenv)--this is lua 5.2-5.3, good luck with upvalues
test()

对于旧版本,您必须处理可能引用您尝试重新定义的全局函数的上值。对于较新的版本,您必须处理在转储加载过程中丢失的上值。

3.读取文件

最后,正如其他人所说,如果您可以访问源代码,您可以尝试从中找到函数定义。除非它是单个函数定义或单个返回文件,否则该任务最终可能等同于重新实现 lua 解析器。其中不止一个,但他们并没有考虑到这样的功能,因此可能需要一些工作来重新利用他们的代码。

如果所有的函数都是自己定义的,而且你愿意稍微克制一下,你可以再次使用lua metatables,在编码阶段解决问题:

local def=function(code,env)
    env=env or _ENV
    local compiled,q=load("return "..code,nil,nil,env)
    if not compiled then error(q) end
    local f=compiled()
    return setmetatable({code=code},{__call=function(me,...) return  f(...)  end})
end

local test=def[[function(a,b)
    return a+b
end]]

print(test(2,3))

然而,定义上值将是棘手的。

于 2017-05-16T21:46:35.747 回答
3

你没有。Lua 不会将已编译的 Lua 脚本作为原始文本存储在任何地方。而且,由于它旨在成为一种小型脚本语言,因此它也不提供反编译自己的字节码的机制。

于 2013-02-06T03:51:28.457 回答
1

好吧,您可以将多行代码全部存储在一个字符串变量中。只需使用双方括号代替引号。

chunk = [[
function test(a, b)
  local c = a + b
  return c
end
]]
于 2013-02-12T06:32:14.017 回答
-2

您可以通过以下方式获取程序的源代码

local source_code = io.open(arg[0]):read'*a'

并解析它以找到您的函数定义。
它仅适用于从命令行运行 lua 并将其作为参数传递的源文件,而不是字节码文件。

于 2013-02-06T07:14:22.357 回答