【LuaWithC++】Lua的基础

来源:互联网 发布:怎么下载淘宝号 编辑:程序博客网 时间:2024/06/05 16:12

操作流程

1.宿主语言建立Lua解释器(lua状态机)对象。

2.将宿主语言实现的Lua扩展(若有),如函数等,注册到Lua解释器中,供其使用。

3.读入Lua源程序或预先编译后的Lua程序(可以从文件、字符串、网络等任意来源)。

4.执行读入的Lua程序。

Lua与宿主语言的交互

宿主语言通过虚拟机,对Lua脚本中的变量实现增、删、读、写

宿主语言通过虚拟机调用Lua脚本中的函数

宿主语言定义新的数据类型供Lua脚本使用

Lua调用宿主语言编写的函数

基本用法

需要引入的头文件:

extern "C"               //**使用C语言编译**!{   #include <lua.h>         //Lua语言解析器   #include <lualib.h>          //Lua标准库   #include <lauxlib.h>         //Lua辅助工具}

C++对Lua脚本的调用、解析,无交互

char* code = "for i=0, 5 do print(\'Hello, world!\') end";void TestCWithLua(){    cout << "/*******测试C++调用lua的代码*******/" << endl;    //1.创建lua解释器对象    lua_State* s = luaL_newstate(); /*lua_open();*/    //2.打开所有lua的库文件    luaL_openlibs(s);    //3.执行lua字符串代码    luaL_dostring(s, code);    //luaL_dofile(s, "LuaSrc\\testcwithlua.lua");    //4.关闭lua解释器对象    lua_close(s);    cout << "/*******结束测试*******/" << endl;}

上例只实现了对Lua脚本的解析,并没有实现Lua与宿主语言的数据交换和互操作。

和典型的脚本语言引擎相同,Lua虚拟机是一个堆栈机,其一切运算基本都在堆栈上完成,这个堆栈也是Lua API的关键部分,是Lua与宿主语言交换数据的手段。

题外:宿主语言可以用字符串构建任意Lua脚本,实现向Lua程序传递任意数据,就像构建SQL语句一样,也不失是最“笨”的交互方式。

Lua堆栈

这里写图片描述

Lua虚拟机内部有一个堆栈,Lua API提供了对其的操作,不仅有出入栈操作,还可以以数组的形式,通过索引值随机读写栈元素,这是双方交换数据的主要方式。

用宿主语言可以编写供Lua调用的函数,宿主语言需要遵守调用约定,从栈中取得参数,最后也将结果入栈。将宿主函数通过lua_register注册入Lua虚拟机(这一过程实质为向Lua语言添加全局变量),就可以被Lua语言所调用。

宿主语言也可以将Lua函数压栈,再将参数依次压栈,最后使用lua_call,完成对Lua函数的调用。

Lua堆栈索引

这里写图片描述

若Lua虚拟机堆栈里有N个元素,则可以用 1 ~ N 从栈底向上索引,也可以用 -1 ~ -N 从栈顶向下索引,一般后者更加常用。

堆栈的每个元素可以为任意复杂的Lua数据类型,堆栈中没有元素的空位,隐含为包含一个“空”类型数据。

Lua调用C++

testluawithc.lua

a = 13 b = 5 q, r = div(a, b) print(q, r)
int Divided(lua_State* s)//供Lua使用的函数通用原型{    double a = lua_tonumber(s, -2);//取得第一个参数    double b = lua_tonumber(s, -1);//取得第二个参数    int ia = static_cast<int>(a);    int ib = static_cast<int>(b);    int quot = ia / ib;    int rem = ia % ib;    lua_pushnumber(s, quot);//将第一个返回值入栈    lua_pushnumber(s, rem);//将第二个返回值入栈    return 2;//返回值为结果个数}void TestLuaWithC(){    cout << "/*******测试lua调用c++的代码*******/" << endl;    lua_State* s = luaL_newstate();    luaL_openlibs(s);    lua_register(s, "div", Divided);    int ret = luaL_dofile(s, "LuaSrc\\testluawithc.lua");    //luaL_dostring(s, "a = 13 b = 5 q, r = div(a, b) print(q, r)");    lua_close(s);    cout << "/*******结束测试*******/" << endl;}

注意:参数的传递,都是通过Lua栈。

由上例可见,可被Lua调用的宿主函数具有统一的原型:int f(lua_State *s),数据传递不通过其参数,而是通过堆栈;整型返回值指明了该函数真正向Lua返回的值的个数,即压栈的结果个数。函数返回后,Lua虚拟机会自动进行清栈工作,不需在函数内部来做。

显然,在Lua中函数可以有不止一个返回值,这在Lua语法中也有体现,可以将函数返回赋值给多个变量。

C++调用lua,lua全局变量和函数调用,有交互

testglobal.lua

show = function(m)    print('Lua has got: ' ..m)    return 'It is from Lua'end
void TestGlobalAndCall(){    cout << "/*******测试使用lua全局变量的代码*******/" << endl;    lua_State* s = luaL_newstate();    luaL_openlibs(s);    /*luaL_dostring(s, "show = function(m) \                                                    print('Lua has got: ' ..m) \     //..字符串连接符                                                    return 'It is from Lua' \                                                end");*/    luaL_dofile(s, "LuaSrc\\testglobal.lua");    lua_getglobal(s, "show");//获得全局变量show    lua_pushstring(s, "It is from C");//将字符串压栈    lua_call(s, 1, 1);//调用lua函数,1个参数,1个返回值    const char* result = lua_tostring(s, -1);//获取执行后的栈顶元素,即函数执行结果    cout << "C has got:" << result << endl;    lua_pop(s, 1);//弹出栈顶元素    lua_close(s);    cout << "/*******结束测试*******/" << endl;}
原创粉丝点击