1. Basics:
One of the important uses of Lua is as a configuration language. Let's start with a simple example.
--This is the configuration information of the window size defined by Lua code
width = 200
height = 300
The following is the C/C++ code for reading configuration information:
#include <>
#include <>
#include <>
#include <>
#include <>
void load(lua_State* L, const char* fname, int* w, int* h) {
if (luaL_loadfile(L,fname) || lua_pcall(L,0,0,0)) {
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"width");
lua_getglobal(L,"height");
if (!lua_isnumber(L,-2)) {
printf("'width' should be a number\n" );
return;
}
if (!lua_isnumber(L,-1)) {
printf("'height' should be a number\n" );
return;
}
*w = lua_tointeger(L,-2);
*h = lua_tointeger(L,-1);
}
int main()
{
lua_State* L = luaL_newstate();
int w,h;
load(L,"D:/",&w,&h);
printf("width = %d, height = %d\n",w,h);
lua_close(L);
return 0;
}
Here is an explanation for the new function:
lua_getglobal is a macro, and its prototype is: #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)).
Every time this macro is called, the corresponding global variable value in Lua code will be pushed into the stack. When the first call is called, the value of the global variable "width" is pushed into the stack, and when the call is called again, the value of "height" is also pushed into the stack.
2. Table operation:
We can manipulate table data in Lua in C language code, which is a very, very convenient and practical function. This not only makes the structure of Lua code clearer, but also defines equivalent structures in C language code to correspond to them, thereby greatly improving the readability of the code. See the following code:
#include <>
#include <>
#include <>
#include <>
#include <>
void load(lua_State* L) {
if (luaL_loadstring(L,"background = { r = 0.30, g = 0.10, b = 0 }")
|| lua_pcall(L,0,0,0)) {
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"background");
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"g");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b");
lua_getfield(L,-1,"b");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);
lua_pop(L,1);
return;
}
int main()
{
lua_State* L = luaL_newstate();
load(L);
lua_close(L);
return 0;
}
void lua_getfield(lua_State *L, int idx, const char *k); The second parameter is the index value of the table variable in the stack, and the last parameter is the key value of the table. After the function is successfully executed, the field value will be pushed into the stack.
void lua_setfield(lua_State *L, int idx, const char *k); The second parameter is the index value of the table variable in the stack, the last parameter is the key name of the table, and the field value is pushed into the stack through the previous command lua_pushnumber(L,0.4). After the execution is successful, the function will pop the field value that has just been pushed out of the stack.
The following code example is to construct a table object in C code, initialize the field value of the table, and finally assign the table object to a global variable in Lua.
#include <>
#include <>
#include <>
#include <>
#include <>
void load(lua_State* L)
{
lua_newtable(L);
lua_pushnumber(L,0.3);
lua_setfield(L,-2,"r");
lua_pushnumber(L,0.1);
lua_setfield(L,-2,"g");
lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b");
lua_setglobal(L,"background");
lua_getglobal(L,"background");
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"g");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"b");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);
lua_pop(L,1);
return;
}
int main()
{
lua_State* L = luaL_newstate();
load(L);
lua_close(L);
return 0;
}
The above code will output the same result as the previous code.
lua_newtable is a macro, and its prototype is: #define lua_newtable(L) lua_createtable(L, 0, 0). After calling the macro, Lua generates a new table object and pushes it into the stack.
lua_setglobal is a macro, and its prototype is: #define lua_setglobal(L,s) lua_setfield(L,LUA_GLOBALSINDEX,(s)). After calling this macro, Lua will assign the value at the top of the current stack to the global variable name specified by the second parameter. After the macro is successfully executed, the value that has just been assigned will pop up from the top of the stack.
3. Call the Lua function:
The API for calling functions is also very simple. First, push the function to be called onto the stack, then press the parameter of the function, then use lua_pcall to make the actual call, and finally pop the call result from the stack. See the following code:
#include <>
#include <>
#include <>
#include <>
#include <>
const char* lua_function_code = "function add(x,y) return x + y end";
void call_function(lua_State* L)
{
//luaL_dostring is equivalent to luaL_loadstring() || lua_pcall()
//Note: Lua script must be executed before being able to call Lua function, otherwise an error will be reported when the Lua function is actually called later.
//The error message is: "attempt to call a nil value."
if (luaL_dostring(L,lua_function_code)) {
printf("Failed to run lua code.\n");
return;
}
double x = 1.0, y = 2.3;
lua_getglobal(L,"add");
lua_pushnumber(L,x);
lua_pushnumber(L,y);
//The second parameter below indicates that there are two parameters in the lua function with call.
//The third parameter indicates that even if there are multiple return values for the function called, only one will be pushed into the stack after execution.
//After lua_pcall is called, the function parameters and function names in the virtual stack are popped up.
if (lua_pcall(L,2,1,0)) {
printf("error is %s.\n",lua_tostring(L,-1));
return;
}
//The result has been pushed into the stack at this time.
if (!lua_isnumber(L,-1)) {
printf("function 'add' must return a number.\n");
return;
}
double ret = lua_tonumber(L,-1);
lua_pop(L,-1); //Popt the return value.
printf("The result of call function is %f.\n",ret);
}
int main()
{
lua_State* L = luaL_newstate();
call_function(L);
lua_close(L);
return 0;
}