Lua学习笔记——Lua作为库嵌入到C中

本文详细记录了如何将Lua作为一种库嵌入到C程序中,涵盖了Lua的表、函数、内存分配以及文件操作等核心概念,为C开发者提供了一条深入理解Lua并与之集成的路径。
/*C++程序接收用户输入的字符串,把该字符串作为Lua的一个chunk送到stack中编译执行。
*/
#include <stdio.h>
#include <string.h>
#include <lua.hpp>

int main(int argc, char* argv[]){
	char buff[256];
	int error = 0;
	lua_State* L=lua_open();
	if(0 == L){
		return -1;
	}
	luaL_openlibs(L);
	
	while (fgets(buff, sizeof(buff), stdin) != 0){
		error = luaL_loadbuffer(L, buff, strlen(buff), \
			"line") || lua_pcall(L, 0, 0, 0);
		if(error){
			fprintf(stderr, "%s", lua_tostring(L, -1));
			lua_pop(L, 1);
		}
	}

	lua_close(L);
	return 0;
}
/*
函数luaL_loadbuffer编译一段字符串为chunk, lua_pcall执行chunk.
lua_tostring(L, -1)拿到栈顶元素,并将其转换为字符串
*/
/*
@param errfunc if errfunc is 0, then error message returned on the stack is exactly the original error message. otherwise, errfunc is the stack index of an error handler function.In case of runtime errors, this function will be called with error message and its return value  will be the message returned on the stack by lua_pcall.
@return zero in case of success or one of the following error codes(definded in lua.h)
LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc)

Loads a buffer as a Lua chunk.
@param name is the chunk name.
@return the same with lua_load function. 0 in case of success or LUA_ERRSYNTAX, LUA_ERRMEM.
int luaL_loadbuffer(lua_State* L, const char* buff, size_t sz, const char* name)

Changes in the API(Lua 5.1)
--The luaopen_* functions(to open libraries) cannot be  called directly, like a regular C function. They must be called through Lua, like a Lua function.
--Function lua_open was replaced by lua_newstate to allow the user to set a memory-allocation function. You can use luaL_newstate from the standard library to create a state with a standard allocation function (based on realloc)
--Functions luaL_getn and luaL_setn are deprecated. Use lua_objlen instead of luaL_getn and nothing instead of luaL_setn.
--Function luaL_checkudata now throws an error when the given value is not a userdata of expected type. (In Lua5.0 it returned NULL)
*/

/*
class Uncopyable{
public:
	virtual ~Uncopyable();
protected:
	Uncopyable();
private:
	Uncopyable(const Uncopyable& rhs);
	Uncopyable& operator=(const Uncopyable& rhs);
};

class Uninheritable{
public:
	Uninheritable* NewInstance();
	~Uninheritable();
private:
	Uninheritable();
};
*/

/*
Accepts any acceptable index, or 0, and sets the stack top to this index. If the new top is larger the old  one, then the new elements are filled with nil. If index is 0, then all stack elements are removed.
void lua_settop (lua_State *L, int index);
--补充说明:设置index位置为栈顶。如果原先的栈顶大于index,则大于index的部分被清空,只保留小于等于index的部分。
*/

void Error(lua_State* L, const char* fmt, ...){
	va_list argp;
	va_start(argp, fmt);
	vfprintf(stderr, fmt, argp);
	va_end(argp);
	if(0 != L){
		lua_close(L);
		L = 0;
	}
	exit(EXIT_FAILURE);
}

bool Load(const char* filename, int* width, int*height){
	lua_State* L = luaL_newstate();
	if(0 == L){
		return false;
	}
	// luaL_openlibs(L);
	if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0)){
		Error(L, "Cannot run configuration file: %s", \
			lua_tostring(L, -1));
	}
	lua_getglobal(L, "width");
	lua_getglobal(L, "height");
	if(!lua_isnumber(L, -2)){
		Error(L, "'width' should be a number \n");
	}

	if(!lua_isnumber(L, -1)){
		Error(L, "'height' should be a number \n");
	}

	*width = (int)lua_tonumber(L, -2);
	*height = (int)lua_tonumber(L, -1);
	lua_close(L);
	return true;
}

/*example_2*/
int main(int argc, char* argv[]){
	if(2 > argc){
		return -1;
	}

	int width(0), height(0);
	if(Load(argv[1], &width, &height)){
		std::cout << "width = \t" << width << "\n";
		std::cout << "height = \t" << height << "\n";
	}
	return 0;
}
/*
--filename : configuration.lua
--configuration file for LuaTest appliation
horizontal = true
if horizontal then 
	width = 1024
	height = 768
else
	width = 768
	height = 1024
end

命令行运行LuaTest控制台程序: LuaTest.exe configuration.lua
*/

/*
Push onto the stack the value of global name. It is defined as macro:
	#define lua_getglobal(L, s) lua_getfield(L, LUA_GLOBALSINDEX, s)
void lua_getglobal (lua_State *L, const char *name);

Pushes onto the stack the value t[k], where t is the value at given valid index.
void lua_getfield (lua_State *L, int index, const char *k);
*/

/*sample_3*/
#include <iostream>
#include <string.h>
#include <lua.hpp>

void Error(lua_State* L, const char* fmt, ...){
	va_list argp;
	va_start(argp, fmt);
	vfprintf(stderr, fmt, argp);
	va_end(argp);
	if(0 != L){
		lua_close(L);
		L = 0;
	}
	exit(EXIT_FAILURE);
}

const int MAX_COLOR = 255;
/*Assume that table is on the stack top*/
int GetField(lua_State* L, const char* key){
	int res;
	lua_pushstring(L, key);
	lua_gettable(L, -2); /*get background[key]*/
	if(!lua_isnumber(L, -1)){
		Error(L, "invalid component in background color.");
	}

	res = (int)(lua_tonumber(L, -1) * MAX_COLOR);
	lua_pop(L, 1);	
	return res;
}

struct ColorRGB{
	unsigned char red, green, blue;
};

bool GetBackgroundColor(const char* filename, ColorRGB& rgb){	
	lua_State* L = luaL_newstate();
	if(0 == L){
		return false;
	}
	if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0)){
		Error(L, "Cannot run configuration file : %s ", lua_tostring(L, -1));
	}

	/*push 全局变量background 到 stack.*/
	lua_getglobal(L, "background");
	if(!lua_istable(L, -1)){
		Error(L, "'background' is not a valid color table!");
	}

	rgb.red = GetField(L, "r");
	rgb.green = GetField(L, "g");
	rgb.blue = GetField(L, "b");

	lua_close(L);
	return true;
}

int main(int argc, char* argv[]){
	if(2 > argc){
		return -1;
	}

	ColorRGB backgroundColor= {0, 0, 0};
	if(GetBackgroundColor(argv[1], backgroundColor)){
		std::cout << "Red \t" << (int)backgroundColor.red << "\n";
		std::cout << "Green \t" << (int)backgroundColor.green << "\n";
		std::cout << "Blue \t" << (int)backgroundColor.blue << "\n";
	}
	return 0;
}

/*
Pushes onto the stack the value t[k], where t is the value at the given valid index and k is the value at the top of the stack.
把t[k]入栈,t是栈中的一个table,由index来指定,k是栈顶的值。从命名可知t代表table,k代表key, t[k]代表value.
This function pops the key from the stack (putting the resulting value in its place).
弹出将原先在栈顶的key,代之以value,即table[key]

void lua_gettable (lua_State *L, int index);
*/

/*
Does the equivalent to t[k] = v, where t is the value at the given valid index, v is the value at the top of the stack, and k is the value just below the top.
这条语句的作用相当于table[key] = value, index 指定了table在栈中的位置。value是栈顶元素,key是栈顶元素的下一个元素。
This function pops both the key and the value from the stack.
赋值结束后,value和key将被弹出栈。
void lua_settable (lua_State *L, int index);
*/

/*
Pops n elements from the stack.
从栈中弹出n个元素
void lua_pop (lua_State *L, int n);
*/

/*
从stack中弹出一个值,并将这个值命名为 name。
Pops a value from the stack and sets it as the new value of global name.
void lua_setglobal (lua_State *L, const char *name);
*/

/*
Loads a Lua chunk (without running it). If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it push an error message.
The return values of lua_load are:
	LUA_OK: no error
	...
int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *source,
              const char *mode);
*/


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值