C/C++与Lua交互(C实现的Lua编译器的例子)
#include <stdio.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#pragma comment(lib,"C:\\Program Files\\Lua\\5.1\\lib\\lua51.lib")
int main (void)
{
char buff[256];
int error;
lua_State *L = lua_open();
//luaL_openlibs(L);
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
while (fgets(buff, sizeof(buff), stdin) != NULL) {
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;
}
该版本是Lua 5.0的例子,若用于Lua 5.1做解释器,运行到红色处会出现
PANIC: unprotected error in call to Lua API (no calling environment)
修改后的版本为:
#include <stdio.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#pragma comment(lib,"C:\\Program Files\\Lua\\5.1\\lib\\lua51.lib")
int main (void)
{
char buff[256];
int error;
lua_State *L = lua_open();
luaL_openlibs(L);
//luaopen_base(L);
//luaopen_table(L);
//luaopen_io(L);
//luaopen_string(L);
//luaopen_math(L);
//printf("xxxx\n");
while (fgets(buff, sizeof(buff), stdin) != NULL) {
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;
}
头文件lua.h定义了Lua提供的基础函数。其中包括创建一个新的Lua环境的函数(如lua_open),调用Lua函数(如lua_pcall)的函数,读取/写入Lua环境的全局变量的函数,注册可以被Lua代码调用的新函数的函数,等等。所有在lua.h中被定义的都有一个lua_前缀。
头文件lauxlib.h定义了辅助库(auxlib)提供的函数。同样,所有在其中定义的函数等都以luaL_打头(例如,luaL_loadbuffer)。辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象;所有Lua标准库都使用了auxlib。基础API致力于economy and orthogonality,相反auxlib致力于实现一般任务的实用性。当然,基于你的程序的需要而创建其它的抽象也是非常容易的。需要铭记在心的是,auxlib没有存取Lua内部的权限。它完成它所有的工作都是通过正式的基本API。
Lua库没有定义任何全局变量。它所有的状态保存在动态结构lua_State中,而且指向这个结构的指针作为所有Lua函数的一个参数。这样的实现方式使得Lua能够重入(reentrant)且为在多线程中的使用作好准备。
创建一个state并将标准库载入之后,就可以着手解释用户的输入了。对于用户输入的每一行(while (fgets(buff, sizeof(buff), stdin) ),C程序首先调用luaL_loadbuffer编译这些Lua代码。如果没有错误,这个调用返回零并把编译之后的chunk压入栈。(记住,我们将在下一节中讨论魔法般的栈)之后,C程序调用lua_pcall,它将会把chunk从栈中弹出并在保护模式下运行它。和luaL_laodbuffer一样,lua_pcall在没有错误的情况下返回零。在有错误的情况下,这两个函数都将一条错误消息压入栈;我们可以用lua_tostring来得到这条信息、输出它,用lua_pop将它从栈中删除。