Page 1 of 1

Advanced Lua - Part III

#1 KYA  Icon User is offline

  • g++ jameson.cpp -o beverage
  • member icon

Reputation: 3089
  • View blog
  • Posts: 19,137
  • Joined: 14-September 07

Posted 20 November 2009 - 10:16 AM

Advanced Lua- Part III

Prerequisites:

A solid understanding of Lua. It is recommended, but certainly not required, that you read my previous tutorials on the subject, which can be found starting here(intro) and here(advanced). Since this tutorial covers how to embed Lua in other languages a grasp on programming fundamentals will also be required. In particular, be familiar with C/C++/Java. I will not be explaining things like control or data structures. Having that said, let's begin:

Getting in Bed With Lua:

Up until this point, all of the Lua we've been using has been stand alone. Suffice it to say that this is not the intention or purpose of the language. Not to say it isn't or cannot be useful by itself, it truly shines when embedded in another language. (A testament to this is Lua's widespread usage in the video game industry). Those with prior programming experience will immediately note that Lua is a library that is used to bring Lua functionality into a program.


From Programming in Lua, 2nd Edition:

Quote

[The] ability to be used as a library to extend an application is what makes Lua an extension language.
At the same time a program that uses Lua can register new functions in the Lua environment...This is what makes Lua an extensible language.


At running the risk of a gross oversimplification, Lua is quite flexible. Given the definitions above, there are varying instances where Lua and [another programming language] will switch roles between application and library depending on the circumstances. We could go down a rat hole about this, but as long as you can recognize when each is playing the part [application or library, etc...] then you'll be fine.


A quick example of opening a basic Lua interpreter in C:

#include <stdio.h>
#include <string.h>

/* If using a ANSI C compile, just include the libs
I'm using VS 2005 and compiling from a C++ environment requires extern "C"
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#ifdef __cplusplus
}
#endif

int main()
{
	char buff[256];
	int error;
		lua_State *L = luaL_newstate();			/*open a new lua state*/
	luaL_openlibs(L);						/*open standard libraries*/

	/* this is an embedded lua interpreter,
			like if you opened the interpreter from the executable directly
	   gathers input, crtl + Z exits
	 */
	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); /*pop error message from the stack*/
		}
	}

	lua_close(L); /*clean up*/

	return 0;
}



In the above code, C is the controller (application) and Lua is the library used. Without getting too far ahead of myself, here's a quick list of how to embed Lua in generally any language since the APIs are so similar:

1. Ensure the Lua libraries are imported correctly
2. Open up a new Lua state, this is your handle to everything
3. Open any other libraries you may need
4. Perform your program's functions utilizing the API as needed
5. Clean up after your Lua instance

Whenever interfacing occurs, there is an API to handle transitions. This is of particular importance to us because C and Lua are radically different: dynamic versus static typing, garbage collection vs. not, so on and so forth. We cannot simply pass values without some sort of interface. The C API handles these issues (scroll down on that page).

The Stack:

Lua uses an abstract stack to exchange values between the language it is embedded in and itself. Each slot in this stack can hold any Lua value (for a list, check the reference manual or a previous tutorial). Data exchange follows the following rough guidelines:

To retrieve a value from Lua:
1. Call Lua
2. Lua pushes the value onto the stack
3. Retrieve value from stack in embedding language
4. Use value


To pass a value to Lua:
1. Push value onto the stack from embedding language
2. Call Lua
3. Lua pops value from stack
4. Use value


There are different functions for each data type, but the concept is the same regardless of the situation. The stack is managed by Lua so it knows which value the embedding language is using and will not garbage collect them. [This seems simple, but that fact is extremely important, if C was in charge of those values, Lua might inadvertently "eat" them since it isn't aware of their usage]. When Lua starts the stack has at least 20 free "slots" (which is defined as a constant LUA_MINSTACK in lua.h), so it is important to keep tabs on your usage, which you can do with this function. Remember that indexes start at 1 in Lua, so the stack index starts at 1 as well. You can also access the stack with negative indexes from the view of the top, so -1 refers to the element at the top, so on and so forth. I find that it is helpful when you want to default to the top (like when printing error messages).

Some examples:

In this code, we use C to get a global value from a Lua file in the local directory. The contents of the Lua file are as follows:

xCursor = 5



#include <cstdio>
#include <cstring>

#ifdef __cplusplus
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#ifdef __cplusplus
}
#endif

int main()
{
	lua_State *L = luaL_newstate();			/*open a new lua state*/
	luaL_openlibs(L);						/*open standard libraries*/

	luaL_dofile(L, "test.lua");	/* open up a lua file in the current directory*/
	lua_getglobal(L, "xCursor"); /* push a global onto the stack*/
	printf("%d\n\n", lua_tointeger(L,lua_gettop(L))); /*retrieve and print*/
	lua_close(L); /*clean up*/
	return 0;
}



In this next example, we're going to call a function in Lua from C, the contents of the Lua file:

function f(x, y)
	return (x^2*math.sin(y))/(1-x)
end



We call the Lua function in C, we then pass two values and call lua_pcall which takes the lua handle, the number of arguments, the number of results, and an error handling number (zero indicates that we should print the exact, original error message):

#include <cstdio>
#include <cstring>

#ifdef __cplusplus
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#ifdef __cplusplus
}
#endif

int main()
{
	lua_State *L = luaL_newstate();			/*open a new lua state*/
	luaL_openlibs(L);						/*open standard libraries*/

	/*vars we'll pas to Lua*/
	double x = 5, y = 6, result;

	luaL_dofile(L, "test.lua");	/* open up a lua file in the current directory*/
	lua_getglobal(L, "f"); /* push a global onto the stack*/
	lua_pushnumber(L, x);
	lua_pushnumber(L, y);

	/*2 arguments, 1 result*/
	if(lua_pcall(L, 2, 1, 0) != 0){
		/* if a problem arose, print the error from the top of stack (-1)*/
		luaL_error(L, "error running function 'f': %s", lua_tostring(L, -1));
	}

	/* it succeeded, get value off the stack */
	result = lua_tonumber(L, -1);
	lua_pop(L, 1); /*pop it*/

	printf("\n\nResult: %f\n\n", result);
	lua_close(L); /*clean up*/
	return 0;
}




Output:

Quote

1.746347


(If you wanted to verify on your calculator, make sure you're in Radian mode).

To show how consistent the APIs are, here is an example in Java of what we just did with C:

import org.keplerproject.luajava.LuaObject;
import org.keplerproject.luajava.LuaState;
import org.keplerproject.luajava.LuaStateFactory;

public class LuaJavaTest {

	 public static void main(String[] args){
		LuaState L = LuaStateFactory.newLuaState(); //create state
		L.LdoFile("test.lua"); //open external file
		L.getGlobal("xCursor"); //retrieve value
		System.out.println("xCursor's value is:" + L.toInteger(L.getTop())); //pop it off and print
	}
}



I found to be a bit more troublesome to set up Lua with Java, but after experimenting a bit I was able to get LuaJava up and running. Make sure you add it as an external library to your project. Netbeans allows this to be done rather easily, but feel free to use whatever you want.

Hopefully you found this post helpful. There are many more things you can do when you embed Lua in another language, but the stack concept is consistent (not mention crucial) wherever your Lua endeavors take you. Happy Coding!

This post has been edited by KYA: 20 November 2009 - 01:54 PM


Is This A Good Question/Topic? 1
  • +

Page 1 of 1