lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



> On Behalf Of Brian Hook Sent: March 6, 2003 1:23 PM
> Subject: Re: 5.0 changes question

> Yes, that's pretty much exactly what I want to do.  Since I'm using 
> Lua as a data description language, I often have lots of things where 
> the C code wants to query a specific value that is global, e.g.:
> 
> //contrived but reasonably accurate example
> float r = lua.getFloat( "/environment/ambient/color.red" );
> float g = lua.getFloat( "/environment/ambient/color.green" );
> float b = lua.getFloat( "/environment/ambient/color.blue" );
> 
> >You cannot get a table a in C. Instead of that you have to keep that
> >reference inside lua, in a safe place like the registry. 
> 
> I may be using the wrong nomenclature here, but basically I don't 
> want to "Get" the table, only to query a value in that table (or a 
> subtable).

You can use lua2c to help you out here. What this does is turns a pieces
of Lua code into a piece of C code using the Lua C API. This is ideal
for turning easy Lua queries of data into more complicated stack based
queries using the API (which can be pretty error prone as well).

Thinking this would be useful I put these scripts online at:
http://doris.sourceforge.net/lua/weblua.php

Using your example, which assumes that "environment" is a table that
contains an "ambient" table, which contains a "color" table with the
element "red". We enter the following into the Lua code box:

r = environment.ambient.color.red

Hit luac and you get:

luac generates the follow output:

main <0:@/tmp/wlRsF0HY> (6 instructions/24 bytes at 0x8052af0)
0 params, 2 stacks, 0 locals, 5 strings, 0 numbers, 0 functions, 3 lines
     1	[2]	GETGLOBAL  	1	; environment
     2	[2]	GETDOTTED  	2	; ambient
     3	[2]	GETDOTTED  	3	; color
     4	[2]	GETDOTTED  	4	; red
     5	[2]	SETGLOBAL  	0	; r
     6	[2]	END

So you can check that your query is doing what you want it to do
(assuming you can make sense of the VM code :D ). Then hit the "lua2c"
button and you'll get:

lua2c generates the following: 

static int MAIN(lua_State *L)
{
 lua_getglobal(L,"environment");
 lua_pushstring(L,"ambient");
 lua_gettable(L,-2);
 lua_remove(L,-2);
 lua_pushstring(L,"color");
 lua_gettable(L,-2);
 lua_remove(L,-2);
 lua_pushstring(L,"red");
 lua_gettable(L,-2);
 lua_remove(L,-2);
 lua_setglobal(L,"r");
 return 0;
}

So you can pretty much cut and paste this into your app.

> I thought that was basically how Lua4 worked, either that or I was 
> using it completely incorrectly and it was broken in a manner that I 
> expected =/  
> 
> This lack of documentation is a killer.  It's much better now than a 
> year or two ago, but this is fairly trivial information that isn't 
> documented anywhere, not even the lists (and the code isn't commented 
> either).

I know, some of it can be a little hard to grasp. I suppose I've had the
benefit of following this list for a few years although I've kind of
list track recently with the move to Lua5 as I just can't spend the time
I'd like to following the threads. And given my experience I still have
trouble with a few of the new concepts so I sympathise with any newbies.
There is no substitute for getting your hands dirty so I wrote Doris as
a learning experience. I've tried to tidy it up as much as possible so
that perhaps people might find it useful (http://doris.sf.net). It is
still Lua4, and when tolua5 emerges I will port it over. So you might
want to look at Doris as an example.

The above example you use for extracting data I would call the "pull"
approach. ie. imagine you are in the app and you are pulling data from a
Lua state. I experiemented and found that this takes quite a lot of
maintainence and generates a lot of handcrafted code if you pull a lot
of data. Another approach is to "push" data from Lua into your app from
Lua. I found this advantageous not only because you can transfer the
data using Lua but also because you can take advantage more readily of
Luas nice clear syntax (as you desired). 

To do this a binding tool is very useful, and tolua works very well. So
you might bind a function: 

void setAmbientColor(float r, float g, float b);

Which would mean that you can call setAmbientColor(r,g,b) from a Lua
script. Now it gets intesting, because you can just execute Lua scripts
to set up your environment, eg.

env = createEnvironment()
env:setAmbientColor(.5,.7,.2)

Which is nice but you can go further and add a wrapper layer between
your Lua config script and the binding. eg.

function Environment(t)
  local env = createEnviornment()
  for k,v in t do
    if k=='ambient' then
      env:setAmbientColor(v[1],v[2],v[3])
    elseif ...
      ...
    end
  end
  return env
end

So your config script can now look like:

env = Environment{
  ambient = {.5, .7, .2}
}

So the problem is not really that the C API is a little sticky but how
you set up your system. I have followed the above system in Doris and I
think you end up with some pretty nice, clear scripts. 

eg. http://doris.sourceforge.net/eg_simple.html

----

As an example, if we look at the GLUT Window wrapper class in Doris, the
interface is: 

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/doriswin.
h?rev=1.10&content-type=text/vnd.viewcvs-markup

Which we bind using the tolua package: (Please note this contains the
Lua documentation as well, generated using selfdoc)

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/doris.pkg
?rev=1.15&content-type=text/vnd.viewcvs-markup

Which gives us some binding code (not so interesting :o) :-

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/dorisbind
.cpp?rev=1.12&content-type=text/vnd.viewcvs-markup

This is the interesting bit, the wrapper, which takes nice tables and
sends it through our interface: (again documented using selfdoc)

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/dorisgui.
lua?rev=1.21&content-type=text/vnd.viewcvs-markup

This might be a fairly complicated example. For a modest amount of
information it would be far less complicated. But I think the end result
for creating various GUIs is quite nice, have a look at the examples:

http://doris.sourceforge.net/

-----

If you'd like to document your code the selfdoc script:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/selfdoc.l
ua?rev=1.10&content-type=text/vnd.viewcvs-markup

uses the format followed by Vector:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/doris/doris/src/dorisobjs
.h?rev=1.10&content-type=text/vnd.viewcvs-markup

and produces the following:

http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/doris/doris/do
cs/doris.html?rev=1.2&content-type=text/plain

I hope this is all useful. I could make some more notes on the wiki if
you like.

Regards,
Nick