Lua is both very simple and very complex at the same time. Because it's so simple and flexible, and is designed to be embedded into apps as an "extension language", it is able to be used in many different ways. This means that the way that Lua is used by different applications can be quite different.
The best way to integrate it into your project then depends on how you want to use it.
First up, bookmark the manual, online tutorial book and wiki
http://www.lua.org/manual/http://www.lua.org/pil/http://lua-users.org/wiki/ The way that you connect your C++ code to your Lua code is usually called the binding system. There's many ways to do this, from writing the bindings yourself manually, or using a helper library that was designed for just this purpose. There's a wiki page that lists a bunch of these here:
http://lua-users.org/wiki/BindingCodeToLuaMost people prefer a binding system, but some people do prefer to do it all manually. For example, the bitsquid engine authors argue that when you write the bindings manually, you end up creating a Lua API that is much more in the style of Lua, rather that one that is in the style of C++, and you are aware of any strange C++/Lua conversions that must take place.
If you don't want to do the bindings manually, then look through the binding systems in that link and pick one that meets your needs.
To manually bind a C function to Lua, you have to write a wrapper function that returns an
int and takes a single argument of
lua_State*. Inside that wrapper function, you can then pop your C function's arguments from the Lua strack, call your C function, then push it's return value to the lua stack (and then return the number of items you pushed).
Once you're written this function, you can give it to lua by use of the lua_pushcfunction method.
For example (
using some copy&pasted helper functions from my own binding code), if in Lua I want to be able to write engine.DoStuff(1,2,3), I can use this code:
int Lua_DoStuff(lua_State* L)
{
int numArgs = lua_gettop(L); // how many arguments the Lua caller put on the stack for us
if( numArgs != 3 ) // If the lua user calls your API incorrectly, you can generate lua errors
luaL_error(L, "Expected 3 args, received %d", numArgs );
int a, b, c = ...//todo - pop arguments from stack
float result = Actual_DoStuff( a, b, c );
//todo push result to stack
return /*num results pushed*/;
}
...
Register(myLua, "engine", "DoStuff", &Lua_DoStuff );//register my C function with Lua, under the name "engine.DoStuff"
void PushNewGlobalTable(lua_State *L, const char* name, int nameLen)
{
lua_pushlstring(L, name, nameLen);
lua_pushvalue(L, -1);
lua_rawget(L, LUA_GLOBALSINDEX); /* get name */
if (!lua_isnil(L, -1)) // name already in use?
{
lua_remove(L, -2); //remove name
return; // leave previous value on top
}
lua_pop(L, 1); // pop the nil
lua_newtable(L);//todo - size hint?
lua_pushvalue(L, -2);//push name
lua_pushvalue(L, -2);//push table
lua_rawset(L, LUA_GLOBALSINDEX); // globals.name = table
lua_remove(L, -2); //remove name
}
void Register(lua_State* L, const char* table, const char* method, int (*luaCall)(lua_State*))
{
PushNewGlobalTable(L, table, strlen(table));
lua_pushstring(L, method);
lua_pushcfunction(L, luaCall);
lua_rawset(L, -3);//table[method] = luaCall
lua_pop(L, 2); // pop the tables
}
To manually call a Lua function from C, you push it to the stack, then push your args, then use pcall to execute it, then pop it's return value.
e.g. if you want to call the global Lua function "example()" from C, you could use
if( PushGlobalFunction(L, "example") ) // push function to stack
{
int numReturnValuesExpected = 0;
int numArgumentsPushed = 0;
//todo - push any arguments here
int returnCode = lua_pcall(L, numArgumentsPushed, numReturnValuesExpected, 0);
//pcall pops the arguments and the function from the stack, and replaces them with the return value
if( returnCode )//pcall failed!
{
const char* errorText = lua_tostring(L, -1);//todo - print error
lua_pop(L, 1);//pop error
}
else if( numReturnValuesExpected )
{
//todo - fetch/pop return value(s) here
}
}
bool PushGlobalFunction(lua_State* L, const char* name)
{
lua_pushstring(L, name);//push name
lua_rawget(L, LUA_GLOBALSINDEX);//pops name, replaces it with _G[name]
if(!lua_isfunction(L, -1))
{
lua_pop(L, 1); // not a function, pop it from stack and return error
return false;
}
//our function is now on the top of the stack
return true;
}