Normally, you define a lua function like this:
function foo()
print "woof"
end
foo()
All fairly unremarkable. You can also create anonymous functions and assign them to variables:
foo = function()
print "woof"
end
foo()
In actual fact, the two cases are identical. Just like in JavaScript/Actionscript (and probably a ton of other languages as well) if you write "foo()", the interpreter looks for a variable called "foo", checks to see if "foo" contains a reference to a functions, and if it does, that function is called.
So, thinking about our C++ program, all we need to do is take that chunk and store it in a global symbol. We can check that. First I want to split the loading and execution parts into their own funcs:
/*
* load the string: the compiled code will be left in a "chunk"
* (an anyonymous function) on the top of the stack
*/
int load(lua_State *L, string proggy)
{
int rc = luaL_loadstring(L, proggy.c_str());
/*
* zero means success here
*/
if(rc == 0) {
return 0;
}
/*
* report the error
*/
cout << "there was an error loading the script: <<"
<< lua_tostring(L, -1)
<< ">>"
<< endl
;
return 1;
}
* load the string: the compiled code will be left in a "chunk"
* (an anyonymous function) on the top of the stack
*/
int load(lua_State *L, string proggy)
{
int rc = luaL_loadstring(L, proggy.c_str());
/*
* zero means success here
*/
if(rc == 0) {
return 0;
}
/*
* report the error
*/
cout << "there was an error loading the script: <<"
<< lua_tostring(L, -1)
<< ">>"
<< endl
;
return 1;
}
That's exactly the same code as before, just in its own func and with some extra comments and whitespace.
Similarly for the call part:
/*
* call the function on top of the stack - bare minimum
*/
int call_top(lua_State *L)
{
int rc;
/*
* run pcall: no args, no return, default handler
*/
rc = lua_pcall(
L, // lua state
0, // number of arguments
0, // number of expected return values
0 // error handler - use lua default
);
/*
* a return of zero means everything worked OK
*/
if(rc == 0) {
return 0;
}
/*
* the only other possible return (according to the docs) is one
* which means an error
*/
cout << "there was an error loading the script: <<"
<< lua_tostring(L, -1)
<< ">>"
<< endl
;
return 1;
}
* call the function on top of the stack - bare minimum
*/
int call_top(lua_State *L)
{
int rc;
/*
* run pcall: no args, no return, default handler
*/
rc = lua_pcall(
L, // lua state
0, // number of arguments
0, // number of expected return values
0 // error handler - use lua default
);
/*
* a return of zero means everything worked OK
*/
if(rc == 0) {
return 0;
}
/*
* the only other possible return (according to the docs) is one
* which means an error
*/
cout << "there was an error loading the script: <<"
<< lua_tostring(L, -1)
<< ">>"
<< endl
;
return 1;
}
And then the main func gets a bit more manageable (and I can stop copying the include statements each time...)
int main()
{
int rc;
string prog = "print \"hello\"";
/*
* create a state for the lua interpreter
*/
lua_State *L = lua_open();
/*
* set up the standard lua libraries
*/
luaL_openlibs(L);
/*
* try and load the program - exit if it fails
*/
if(load(L, prog) == 1) {
return 0;
}
/*
* call the chunk: it's on top of the stack
*/
call_top(L);
/*
* shutdown the interpreter
*/
lua_close(L);
return 0;
}
Storing the chunk is easy:
/*
* stores the function on top of the stack as global name
* stores the function on top of the stack as global name
* lua_setglobal pops a value from the stack, so the func will
* no longer be there when this returns
*/* no longer be there when this returns
void save_chunk(lua_State *L, string name)
{
lua_setglobal(L, name.c_str());
}
Looking it up again:
/*
* stores the function on top of the stack as global name
* lua_setglobal pops a value from the stack, so the func will
* no longer be there when this returns
*/
void find_chunk(lua_State *L, string name)
{
lua_getglobal(L, name.c_str());
}
It's fairly easy to see that these functions are just wrappers around the lua calls - and in fact they can be used to assign anything to a global name - whatever is on top of the stack. So normally I wouldn't bother with the functions, and I do so here purely for the sake of clearer explanations. (Hope it works).
Anyway:
int main()
{
int rc;
string prog = "print \"hello\"";
/*
* create a state for the lua interpreter
*/
lua_State *L = lua_open();
/*
* set up the standard lua libraries
*/
luaL_openlibs(L);
/*
* try and load the program - exit if it fails
*/
if(load(L, prog) == 1) {
return 0;
}
/*
* chunk is on top of the stack - store it!
*/
save_chunk(L, "hello");
/*
* lookup the chunk under global "hello" and then call it
*/
for(int i = 0; i < 3; i++) {
/*
* need to find it before each call
*/
find_chunk(L, "hello");
call_top(L);
}
/*
* shutdown the interpreter
*/
lua_close(L);
return 0;
}
And that now works as expected, printing "hello" three times. So we can parse a script and store itas a named function. But is that the best way to do things?
And this is where I started to get seriously confused...
No comments:
Post a Comment