C++ 识别 .lua文件内用户自定义的全局函数

admin2024-07-01  13

摘要:

   此系列是为经手的项目介绍编译和使用,以及项目开发过程中遇到的bug解决方案或项目开发过程中有意思的需求设计等等项目相关的博文。

   此篇是为开发自定义界面项目过程中系统页面与脚本交互的一个小需求,系统导入用户自己编写的.lua脚本文件,需要页面获取.lua文件内用户自定义的函数名称,并保存到系统供控件后续绑定调用。

(开发环境:VSCode,cmake,Qt5)

关键词C++lua项目开发问题需求分析

文章目录

      • 摘要:
      • 正文:
        • 解决方案
        • 解决
      • 推荐阅读

正文:

print("lua load")
function Example1()
    print("lua load1")
end

function Example2()
    print("lua load2")
end

function Example3()
    print("lua load3")
end

function Example4()
    print("lua load4")
end

   用户定义的.lua文件类似这样,系统页面需要获取到Example1,Example2,Example3,Example4。难点在于用户需要高自定义性,不能过多限制用户编写的.lua文件,又需要精确识别,不能多也不能少。

解决方案

通过internet,以及stackoverflow1、stackoverflow2找到四种解决方案:

  • 第一种就是给用户做点小限制,让用户把需要导入的脚本函数归类到一个表(例如functions),然后系统页面迭代这个函数包也行,比较方便,效率也高。
  • 第二种不做限制,系统页面找.lua文件的"_G"的全局函数表,表内包括用户定义的全局对象和默认函数例如print之类的,不过如果用户导包了,默认函数会更多, 获取_G集合后减去默认函数集合得到用户定义的函数集合,效率比较低准确度也不好把握容易出错。
  • 第三种C++逐行获取字符串匹配function关键字后在" “和”(" 之间的就是函数名保存下来即可,效率20行大概0.2ms ,不过也要考虑local和print-function相关字符串等,参考:https://www.cnblogs.com/dechinphy/p/cppio.html。
  • 第四种使用第三方lbci lua字节编码检测器,没深入了解,感觉很麻烦,要解析运行后的编码。
解决

   综合考虑使用第一种,限制小准确度高开发也比较方便,那么本质上也只是C++ 与 lua数据交互的问题。

-- .lua文件
print("lua load")
functions = {}

function functions.Example1()
    print("lua load1")
end

function functions.Example2()
    print("lua load2")
end

function functions.Example3()
    print("lua load3")
end

function Example4()
    print("lua load4")
end
// 识别.lua	CCustomLuaBridge.cpp
// lua_State *Lua		Lua状态机
// QString luaPath		./lua文件路径
// bool openSuccess		是否成功载入.lua文件
......
{
	QStringList nameList;
    // 加载Lua脚本  
    if (luaL_loadfile(Lua, luaPath.toStdString().c_str()) != LUA_OK || lua_pcall(Lua, 0, LUA_MULTRET, 0)) {  
        qDebug() << "Error loading/running Lua script: " << lua_tostring(Lua, -1);  
        lua_pop(Lua, 1); 	// 移除错误消息    
        lua_close(Lua);     // 关闭Lua状态机
        openSuccess = false;
        return QStringList();
    }
    openSuccess = true;

    // 将全局环境functions压入栈顶
    lua_getglobal(Lua, "functions");
  
    // 检查栈顶functions是否是一个表
    if (!lua_istable(Lua, -1)) {
        qDebug() << "Error: functions is not a table";
        lua_pop(Lua, 1);    // 移除栈顶元素
        lua_close(Lua);     // 关闭Lua状态机
        return QStringList();  
    }

    // 遍历functions表
    lua_pushnil(Lua); // 第一个key
    while (lua_next(Lua, -2)) {
        // -1 是值,-2 是键
        // 检查值是否是一个函数
        if (lua_isfunction(Lua, -1)) {
            // 获取键(函数名)
            const char* functionName = lua_tostring(Lua, -2);
            qDebug() << "Found function: " << functionName;
            nameList << functionName;
        }  
        // 移除值(保留键用于下一次迭代)
        lua_pop(Lua, 1);
    }
    nameList.sort();	// 排序一下
    // 移除表
    lua_pop(Lua, 1);
    lua_close(Lua);     // 关闭Lua状态机
    return nameList;
}
......

主体功能完成,后续就是完善需求细节部分,导入脚本以及刷新机制等等。

推荐阅读

博客主页:https://blog.csdn.net/weixin_45068267
(客官逛一逛,有许多其它有趣的专栏博文)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!