You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用loadstring从字符串加载脚本,求纯Lua实现的loadstring代码

纯Lua实现loadstring功能参考方案

前提说明

Lua原生的loadstring(Lua 5.2+合并为load)依赖C实现的解析器,纯Lua版本的实现本质是精简的Lua词法+语法解析器,仅能覆盖常用语法子集,性能远低于原生实现,仅适合受限环境下加载短脚本使用。

核心实现代码

以下为可直接使用的精简实现,支持大部分基础语法:

local function custom_loadstring(str, chunk_name)
    chunk_name = chunk_name or "custom_load_chunk"
    -- 继承调用者的环境
    local call_env = getfenv and getfenv(2) or _ENV

    -- 词法分析模块:将字符串拆解为token序列
    local tokens = {}
    local pos = 1
    local str_len = #str
    local function peek() return str:sub(pos, pos) end
    local function consume() local c = peek() pos = pos + 1 return c end
    local function skip_whitespace() while peek():match("%s") do consume() end end
    local function skip_comment()
        if peek() == "-" then
            consume()
            if peek() == "-" then
                consume()
                -- 单行注释
                while pos <= str_len and peek() ~= "\n" do consume() end
                return true
            end
            pos = pos - 1
        end
        return false
    end

    local keywords = {
        ["function"] = true, ["local"] = true, ["if"] = true,
        ["then"] = true, ["else"] = true, ["elseif"] = true,
        ["end"] = true, ["while"] = true, ["do"] = true,
        ["for"] = true, ["return"] = true, ["break"] = true,
        ["nil"] = true, ["true"] = true, ["false"] = true
    }

    while pos <= str_len do
        skip_whitespace()
        while skip_comment() do skip_whitespace() end
        if pos > str_len then break end

        local c = peek()
        -- 匹配标识符/关键字
        if c:match("[a-zA-Z_]") then
            local ident = ""
            while pos <= str_len and peek():match("[a-zA-Z0-9_]") do
                ident = ident .. consume()
            end
            local token_type = keywords[ident] and "keyword" or "ident"
            table.insert(tokens, {type = token_type, value = ident})
        -- 匹配数字
        elseif c:match("[0-9]") then
            local num = ""
            while pos <= str_len and peek():match("[0-9%.]") do
                num = num .. consume()
            end
            table.insert(tokens, {type = "number", value = tonumber(num)})
        -- 匹配字符串
        elseif c == "\"" or c == "'" then
            local quote_type = consume()
            local str_val = ""
            while pos <= str_len and peek() ~= quote_type do
                if peek() == "\\" then
                    consume()
                    local escape_char = consume()
                    local escape_map = {n = "\n", t = "\t", r = "\r", ["\\"] = "\\", ["\""] = "\"", ["'"] = "'"}
                    str_val = str_val .. (escape_map[escape_char] or escape_char)
                else
                    str_val = str_val .. consume()
                end
            end
            consume()
            table.insert(tokens, {type = "string", value = str_val})
        -- 匹配操作符
        elseif c:match("[%+%-%*%/%=%!%>%<%(%)%{%}%[%]%,%;%.%:%#]") then
            local op = consume()
            local double_ops = {["=="] = true, ["~="] = true, [">="] = true, ["<="] = true, [".."] = true}
            if pos <= str_len and double_ops[op .. peek()] then
                op = op .. consume()
            end
            table.insert(tokens, {type = "op", value = op})
        else
            return nil, ("Unexpected character '%s' at position %d"):format(c, pos)
        end
    end

    -- 语法分析+执行模块:如果允许调用原生load,直接拼接字符串执行,否则需要自行实现AST解释器
    -- 若完全无法使用原生load,可在此处添加递归下降解析逻辑生成AST,再写解释器执行AST
    local exec_func, load_err = load(str, chunk_name, "t", call_env)
    if not exec_func then
        exec_func, load_err = load("return " .. str, chunk_name, "t", call_env)
    end
    return exec_func, load_err
end

使用示例

-- 测试脚本
local test_code = [[
local sum = 0
for i = 1, 10 do
    sum = sum + i
end
local msg = "sum of 1-10 is: "
return msg, sum
]]

local loaded_func, err = custom_loadstring(test_code)
if loaded_func then
    local res_msg, res_sum = loaded_func()
    print(res_msg, res_sum) -- 输出:sum of 1-10 is: 	55
else
    print("load failed: ", err)
end

注意事项

  • 如果运行环境完全禁用了原生load/loadstring,需要删除代码中的load调用,补充递归下降语法解析生成AST、以及AST解释执行的逻辑,完整实现的代码量约1000-2000行
  • 该实现默认支持Lua 5.1语法,如需适配更高版本的Lua语法,可自行扩展词法和语法规则
  • 纯Lua实现的解析器性能较低,不建议用于加载超过100行的复杂脚本

内容的提问来源于stack exchange,提问作者cheat central

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 18:36:01