一种Lua到C的封装
一种Lua到C的封装
在Lua的官方C API中,Lua与C通过一个虚拟栈来交互数据。例如有个a.lua的文件中有求和函数:
function sum(a, b) return a + b end
要在C代码中打开lua文件,并调用求和函数,大致要这样写:
lua_State *s = luaL_newstate(); luaL_openlibs(s); luaL_loadfile(s, " a.lua " ); lua_getglobal(s, " sum " ); lua_pushinteger(s, 1234 ); lua_pushinteger(s, 4321 ); lua_pcall(s, 2 , 1 , 0 ); int sum = lua_tointeger(s, - 1 ); /* sum = 5555 */ lua_pop(s, 1 ); lua_close(s);
可以想见官方API的设计专注于正交性,而不考虑便利性。
自然希望有一个封装,让程序员在C代码中,尽可能地像Lua一样调用Lua。
github上没搜到特别中意的,只好自己写一个,取名Lucy。设计目标:
1) 隐藏虚拟栈——因此也隐藏基于虚拟栈的官方C API。
2) 在C代码中,尽量用Lua的方式调用Lua代码。
3) function和table在C代码中也该是第一类型,可以作为函数参数传递——其实是第2) 点的补充说明。
在Lua这样的动态类型语言中,变量本身没有类型,被赋值后才有相应的类型。
因此在Lucy中只需定义一个名为lucy_Data的结构体用以表示Lua变量:
typedef struct { lucy_Type type_; lucy_Content cntnt_; } lucy_Data;
lucy_Type是一个枚举类型,lucy_Content则是联合体。
如此定义,则对lucy_Data作任何操作,编译期都没问题,而只会在运行期断言失败,算是对Lua变量的模拟。
lucy_Content中有个类型lucy_Ref:
typedef struct { lua_State * state_; int index_; } lucy_Ref;
保存function, table这样的引用类型,在虚拟栈上的索引。于是它们就可以作为第一类型了。
function传入参数,传出返回值的基础类型,都可以是lucy_Data的数组类型lucy_List。
不难设计与实现剩下的接口。
例如有以下Lua代码:
function Loc(x, y) return function () return x, y end end function GetArea(loc) local x, y = loc() return x * y end
给定x与y,通过调用GetArea函数来取得结果,通过Lucy封装后可以这么写(比如x与y都为5):
lucy_File file = lucy_CreateFile(); lucy_OpenFile( &file, " a.lua " ); lucy_Data Loc = lucy_GetData(&file, " Loc " ); lucy_Data five = lucy_Num( 5 ); lucy_Data loc = lucy_Call(&Loc, 1 , 2 , &five, &five).datas_[ 0 ]; lucy_Data GetArea = lucy_GetData(&file, " GetArea " ); lucy_Data area = lucy_Call(&GetArea, 1 , 1 , &loc).datas_[ 0 ]; lucy_PrintData( &area);
运行结果:
代码已上传至: https://github.com/chncwang/Lucy
已有的接口包括取变量,调用function,查询table元素,长度等。
分类: Lua
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息