Lua在游戏中是非常常见的嵌入式语言,常用来做ui界面,ai逻辑脚本,手机热更等.最近一个项目中用到了lua,需要自己写一些lua的库.这块其实并不是很难,这里简单总结下.
建议对照lua的文档阅读 https://www.runoob.com/manual/lua53doc/contents.html, 里面有每个函数具体功能的解释.
以及lua的源码,lua.c就是C中调用lua的一个解释器实现,lmathlib.c和lstrlib.c就是lua的模块实现.
最后再推荐一本书,讲的非常详细:Programming in Lua, Fourth Edition.
从C中启动Lua
启动一个Lua State并处理输入:
#include <stdio.h>
#include <string.h>
#include "lua.h" //Lua头文件
#include "luaxlib.h" //Lua辅助库
#include "lualib.h" //Lua自带的库
int main(void) {
char buff[256];
int error;
lua_State *L = luaL_newstate(); //初始化Lua State
luaL_openlibs(L); //加载Lua自带的lib库
while (fgets(buff, sizeof(buff), stdin) != NULL) {
error = luaL_loadstring(L, buff) || lua_pcall(L, 0, 0, 0);
if (error) {
fprintf(stderr, "%sn", luaL_tostring(L, -1);
lua_pop(L, 1);
}
}
lua_close(L):
return 0;
}
lua.h是Lua的主要头文件,包含了所有Lua提供的基础函数,里面的函数都是lua_开头.
luaxlib.h是Lua的辅助库头文件,里面的函数都是通过lua.h中提供的函数来实现的,是为了方便编程实现的一个辅助库,里面的函数都以luaL_开头.
luaL_newstate新建一个Lua State并返回一个指针,几乎所有的Lua交互函数都需要传入一个lua_State的指针作为第一个参数.
新建出来的Lua State是没有Lua的math,io等这些库甚至print函数的,luaL_openLibs是加载Lua自带的一些库.
栈的操作
Lua和C交互的最大特色就是使用一个虚拟的栈来实现,虚拟的栈上可以是任意类型的值,包括nil,number,string,userdata等.
Lua内部所有的值类型都是用TValue这种结构来实现的,TValue包括Value和_tt,_tt标识Value的类型,Value是一个Union,可以表示不同类型的值,userdate和string是*gc表示,lightuserdata是*p表示.
/*
** Union of all Lua values
*/
typedef union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
} Value;
#define TValuefields Value value_; int tt_
typedef struct lua_TValue {
TValuefields;
} TValue;
默认情况下栈满足LIFO.大部分函数需要通过索引index指定一个栈上元素的位置作为参数,索引的位置可以是正数或者负数,正数表示从栈底计数,负数表示从栈顶计数.比如一个有4个元素的栈的索引:
Push 元素:
void lua_pushnil (Lua_State *L);
void lua_pushboolean (Lua_State *L, int bool);
void lua_pushnumber (Lua_State *L, lua_Number n);
void lua_pushinteger (Lua_State *L, lua_Integr n);
void lua_pushlstring (Lua_State *L, const char* s, size_t len);
void lua_pushstring (Lua_State *L, const char* s);
检查栈上空余格子数:
int lua_checkstack (lua_State *L, int n); //检查栈上空余的格子是否满足n个
void luaL_checkstack (lua_State *L, int sz, const char *msg); //检查栈上空余格子数,不满足则抛出一个异常信息
检查栈中元素类型:
int lua_isnumber (lua_State *L, int idx); //idx是索引位置
int lua_isstring (lua_State *L, int idx);
int lua_iscfunction (lua_State *L, int idx);
int lua_isinteger (lua_State *L, int idx);
int lua_isuserdata (lua_State *L, int idx);
int lua_type (lua_State *L, int idx);//将得到的值和LUA_TNIL,LUA_TNUMBER等比较来获取类型
const char* lua_typename(lua_State *L, int idx);//返回类型名称"nil","boolean","number"等
获取栈上的元素:
lua_Number lua_tonumber