I’ve not yet had a project that’s needed an embedded scripting language. When I do, I think I’ll reach for Lua.
$ apt-get install lua5.2 liblua5.2-dev
Command line lua:
$ lua
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
> print("Hello, World")
Hello, World
Embedded lua:
#include <lua5.2/lua.hpp>
int main()
{
// Create a Lua virtual machine
lua_State *l = luaL_newstate();
// Make all the lua libs to the virtual machine
luaL_openlibs(l);
// Test it
luaL_dostring(l, "print(\"Helua, World!\")");
cout << lua_tostring(l, -1);
lua_close(l);
}
I’m not sure it gets much easier.
Calling C from Lua
Obviously the main reason for embedding a scripting language is to make custom routines from your application available to the script.
int x = 0;
int customFunction(lua_State *L) {
// Number of elements on the parameter stack
int n = lua_gettop(L);
if( n == 0 )
return 0;
for(int i = 0; i < n; i++) {
if( !lua_isnumber(L, i+1) ) {
lua_pushstring(L, "incorrect arguments");
lua_error(L);
}
x += lua_tointeger(L, i+1);
}
// return x
lua_pushinteger(L, x);
return 1;
}
Then register it and call it.
int main()
{
// Create a Lua virtual machine
lua_State *l = luaL_newstate();
lua_register(l, "customFunction", customFunction);
// Test it
luaL_dostring(l, "return customFunction(1)");
std::cout << lua_tointeger(l, -1) << endl;
lua_close(l);
}
It took me quite a while to realise that “return
†was needed inside the luaL_dostring()
parameter. It seems that the string being evaluated is treated as being inside some anonymous function and we are effectively calling that entire function. Now I understand that, the following from the Lua reference manual is clearer:
int luaL_dofile (lua_State *L, const char *filename);
Loads and runs the given file. It is defined as the following macro:
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
It returns false if there are no errors or true in case of errors.
luaL_loadfile()
uses lua_load()
which says this:
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.
So the string we give to luaL_dostring()
becomes a function on the stack, which is what lua_pcall()
calls … calls means it must return. That’s in addition to our customFunction()
which itself returns to this anonymous function.
Calling Lua from C
The reverse will also be useful; when you want to let your script react to events generated by the C/C++ application.
int main()
{
// Create a Lua virtual machine
lua_State *l = luaL_newstate();
// Define the lua callback in the state; note that this doesn't
// call the function, it creates the reference to it in the
// global table
luaL_dostring(L, R"***(
function onEvent(a)
return a+10
end
)***"));
// Random number
int x = 0x7673f562;
// What function do we want to call? Find it and push it onto
// the stack
lua_getglobal(L, "onEvent");
// Then push the arguments
lua_pushnumber(L, x);
// Call it, telling Lua it has one argument, one result
lua_call(L, 1, 1);
// Fetch the result
int y = lua_tointeger(L, -1);
// Restore the stack
lua_pop(L, 1);
cout << "LUA.onEvent()" = y << endl;
}