wagner | 12 Apr 2000 22:12
Picon
Favicon

Make EXE

Hello
I have a LUA 4.0 , and how i can make the program be a executable (EXE)
And the same question in the LUA IDE.EXE
Much Obliged
Wagner
Ashley Fryer | 1 Apr 2000 13:15

constant tables code


I've put together a few helper macros for creating tables of constant values
in Lua.  They are useful in situations where you would like scripts to have
access to a set of values without allowing the scripts to modify the values
or the set.

For example, I have used this code to generate a table of the VK_xxx and
DIK_xxx key constants for Windows programming.  It could also be useful for
generating a table of error strings, mathematical constants, etc.

Here's an example...

First, define the table in C.  I find it convenient to group the CONST_TABLE
definitions together with my lua_register() calls.

    int num_var = 42;
    char str_var[] = "this is str_var";

    CONST_TABLE_BEGIN( "MY_TABLE" )
        CONST_NUM_VAR( num_var )
        CONST_STR_VAR( str_var )
        CONST_NUM( "foo",  7 )
        CONST_STR( "bar", "this is bar")
    CONST_TABLE_END

Then, once the table is initialized, you can do this in Lua:

    print( MY_TABLE.num_var )
    42
    print( MY_TABLE.str_var )
    this is str_var
    print( MY_TABLE.foo )
    7
    print( MY_TABLE.bar )
    this is bar

The table is "constant" because all of these things generate an error:

    MY_TABLE = 9
    MY_TABLE.str_var = 5
    MY_TABLE.new_var = "new variable"

The error message is:

    Cannot modify constant table: MY_TABLE

One unfortunate limitation of the macros is that you can't directly use
#defined values.  This is because the C pre-processor isn't reentrant.  So,
for example, this fails:

  #define PI 3.14

  CONST_TABLE_BEGIN( "MATH_TABLE" )
      CONST_NUM( "PI", PI )
  CONST_TABLE_END

My workaround is:

  #define PI 3.14

  CONST_TABLE_BEGIN( "MATH_TABLE" )
      double pi = PI;
      CONST_NUM( "PI", pi )
  CONST_TABLE_END

Perhaps someone can think of a better solution.

The code follows.  Anyone is free to use it any way, and I hope that someone
DOES find it useful.  :-)

ashley

--- cut here ---

#define CONST_TABLE_BEGIN( TABLE_NAME ) \
    {\
    lua_Object table = lua_createtable();\
    lua_pushobject( table );\
    lua_setglobal( TABLE_NAME );\
    lua_dostring( "function tmp() error(\
    \"Cannot modify constant table: " TABLE_NAME "\" ) end" );

#define CONST_NUM( NAME, VALUE) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) NAME );\
    lua_pushnumber( VALUE );\
    lua_settable();

#define CONST_NUM_VAR( NAME ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) #NAME );\
    lua_pushnumber( NAME );\
    lua_settable();

#define CONST_STR( NAME, VALUE ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) NAME );\
    lua_pushstring( VALUE );\
    lua_settable();

#define CONST_STR_VAR( NAME ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) #NAME );\
    lua_pushstring( ( char * ) NAME );\
    lua_settable();

#define CONST_TABLE_END \
    int tag = lua_newtag();\
    lua_pushobject( table );\
    lua_settag( tag );\
    lua_pushobject( table );\
    lua_pushobject( lua_getglobal( "tmp" ) );\
    lua_settagmethod( tag, "settable" );\
    lua_pushobject( table );\
    lua_pushobject( lua_getglobal( "tmp" ) );\
    lua_settagmethod( tag, "setglobal" );\
    }

--- cut here ---

Erik Hougaard | 1 Apr 2000 13:19

Sv: constant tables code

----- Original Message ----- 
From: Ashley Fryer <lua <at> bmarket.com>
> I've put together a few helper macros for creating tables of constant values
> in Lua.  They are useful in situations where you would like scripts to have
> access to a set of values without allowing the scripts to modify the values
> or the set.

Very nice, but ths is one of the things that I'm playing with... To make a table (not lua table) so all these
constants would get replaced with their actual values on parse time, so there was no need for lua to do the
lookup. In a application with many constants that should give a performance gain !

/Erik

Ashley Fryer | 1 Apr 2000 15:01

RE: constant tables code


Thanks to some excellent feedback from lhf, we're already up to version 1.1
of the constant table code.

This version is compatible with plain C, doesn't have the temporary
variable, and uses a lua_beginblock/lua_endblock pair.

Also, lhf points out that the following code DOES work:

#define PI 3.14
CONST_TABLE_BEGIN("MY_TABLE")
    CONST_NUM( "PI", PI )
CONST_TABLE_END

So there's reason to rejoice.  :-)

Thanks, lhf!

ashley

--- cut here ---

#define CONST_TABLE_BEGIN( TABLE_NAME ) \
    lua_beginblock(); {\
    lua_Object err_func;\
    int tag;\
    lua_Object table = lua_createtable();\
    lua_pushobject( table );\
    lua_setglobal( TABLE_NAME );\
    lua_dostring( "return function () error(\
    \"Cannot modify constant table: " TABLE_NAME "\" ) end" );\
    err_func = lua_lua2C( 1 );

#define CONST_NUM( NAME, VALUE) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) NAME );\
    lua_pushnumber( VALUE );\
    lua_settable();

#define CONST_NUM_VAR( NAME ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) #NAME );\
    lua_pushnumber( NAME );\
    lua_settable();

#define CONST_STR( NAME, VALUE ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) NAME );\
    lua_pushstring( VALUE );\
    lua_settable();

#define CONST_STR_VAR( NAME ) \
    lua_pushobject( table );\
    lua_pushstring( ( char * ) #NAME );\
    lua_pushstring( ( char * ) NAME );\
    lua_settable();

#define CONST_TABLE_END \
    tag = lua_newtag();\
    lua_pushobject( table );\
    lua_settag( tag );\
    lua_pushobject( table );\
    lua_pushobject( err_func );\
    lua_settagmethod( tag, "settable" );\
    lua_pushobject( table );\
    lua_pushobject( err_func );\
    lua_settagmethod( tag, "setglobal" );\
    } lua_endblock();

--- cut here ---

Edgar Toernig | 2 Apr 2000 19:29
Picon
Picon

2 bugs and patches

Hi,

I found two bugs in lua 3.2:

1. tostring() without an argument generates a SEGV.

--- lbuiltin.c  Sun Apr  2 19:15:41 2000
+++ lbuiltin.c  Sun Apr  2 19:16:22 2000
 <at>  <at>  -328,7 +328,7  <at>  <at> 

 
 static void luaB_tostring (void) {
-  lua_Object obj = lua_getparam(1);
+  lua_Object obj = luaL_nonnullarg(1);
   TObject *o = luaA_Address(obj);
   char buff[64];
   switch (ttype(o)) {

2. Something like "repeat until 1 %foo()" gives a syntax error.
   Looks, like '%' is missing in expfollow[]:

--- lparser.c  Sun Apr  2 19:14:15 2000
+++ lparser.c  Sun Apr  2 19:14:32 2000
 <at>  <at>  -598,7 +598,7  <at>  <at> 

 
 static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME,
-   LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',',  0};
+   LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', '%', EOS, ',',  0};

 
 static int is_in (int tok, int *toks) {

Ciao, ET.

Edgar Toernig | 2 Apr 2000 23:10
Picon
Picon

Some enhancement requests

Hi,

while working with lua I made numerous modifications to the source.
IMHO, some of them should be in the standard version.

1. Allow the $if/$ifnot statement to test if debugging is turned on
   so that one can add additional debugging code in lua programs.
   Example:

$if $debug
    print("x.n=", getn(x))
    foreach(x, function(i,v) assert(type(i)=="number", "bad x") end)
$end

   Here's a patch that implements this:   

--- llex.c    Thu Jun 17 19:04:03 1999
+++ llex.c    Thu Mar 23 19:32:50 2000
 <at>  <at>  -117,8 +117,9  <at>  <at> 

 
 static int checkcond (LexState *LS, char *buff) {
-  static char *opts[] = {"nil", "1", NULL};
+  static char *opts[] = {"nil", "1", "$debug", NULL};
   int i = luaL_findstring(buff, opts);
+  if (i == 2) return L->debug;
   if (i >= 0) return i;
   else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
     return luaS_globaldefined(buff);
 <at>  <at>  -132,7 +133,7  <at>  <at> 
 static void readname (LexState *LS, char *buff) {
   int i = 0;
   skipspace(LS);
-  while (isalnum(LS->current) || LS->current == '_') {
+  while (isalnum(LS->current) || LS->current == '_' || LS->current == '$') {
     if (i >= PRAGMASIZE) {
       buff[PRAGMASIZE] = 0;
       luaX_syntaxerror(LS, "pragma too long", buff);

2. The second argument to the next() function should be optional so that
   next(foo, nil) is the same as next(foo).  I use next() regularly to test
   if a table is empty (if next(tab) then print"not empty" end) and the 
   additional nil is disturbing and inconsistent.

--- lbuiltin.c  Sun Apr  2 19:15:41 2000
+++ lbuiltin.c  Sun Apr  2 19:51:54 2000
 <at>  <at>  -320,15 +320,15  <at>  <at> 

 static void luaB_next (void) {
   Hash *a = gethash(1);
-  TObject *k = luaA_Address(luaL_nonnullarg(2));
-  int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
+  TObject *k = luaA_Address(lua_getparam(2));
+  int i = (k == 0 || ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
   if (luaA_next(a, i) == 0)
     lua_pushnil();
 }

[Side note]
   In my opinion there's an unnecessary difference between handling
   of arguments to C functions and lua functions.  A lua function
   f(a,b) cannot say if it was called via f(a,nil) or f(a).  A C
   function gets either a nil or LUA_NOOBJECT for b.  Why this
   difference?  Isn't nil supposed to stand for "no object"?  ;-)

   I think it would have been better to return nil for not passed
   arguments.  The functions that check for optional arguments
   check against nil instead of LUA_NOOBJECT (then giving exactly the
   same behavior as lua functions).  And an additional function (i.e
   lua_narg()) gives the real number of passed arguments to simulate
   vararg lua functions.

   But I guess it's too late now...

3. The last thing is a little bit more difficult.  A garbage collected
   system is a nice thing to have.  You don't have to care about freeing
   objects.  But often you come to the situation that you want to create
   a new one and assume that it is already present somewhere.  For example,
   you have a function to load a graphics image.  It gets a file name,
   load's it and returns an image object.  The object itself is garbage
   collected.  Now, you want to cache all images, so that you don't have
   to load the same image multiple times.  But unfortunately, the cache
   itself holds a reference to every image and it is no longer garbage
   collected :-(

   What you want: weak references that won't hinder the gc of collecting
   the referenced object.

   My first idea was:  add a function to mark a table as holding weak
   reference which means, all values (not indexes) hold in that table
   will not be marked during the mark phase.  Later in the collection
   phase replace all table values not marked with nil.  But the imple-
   mentation is not that easy and I'm still not sure if this really
   works.  (I would love to hear comments about this idea, especially
   if this would really work.)

   So I went an easier way.  The C-API already has a method to hold weak
   references (lua_ref(0)).  I just created some bindings to access them
   from lua.  Because the references itself have to be garbage collected
   I mapped them to userdata with a private tag.  The result:  there are
   two new functions, x = ref(obj) and  obj = getref(x).  getref returns
   nil if the object referenced by x is already garbage collected.

   I think, these two function are elementary enough to be part of the
   standard list of builtin functions (the short names may be a problem).

   Here is a code fragment of my implementation:

lua_api
xlua_ref(void)
{
    lua_pushobject(luaL_nonnullarg(1));
    lua_pushusertag((void*)lua_ref(0), tag_ref);
}

lua_api
xlua_getref(void)
{
    lua_Object o = lua_getparam(1);

    luaL_arg_check(lua_tag(o) == tag_ref, 1, "reference expected");
    o = lua_getref((int)lua_getuserdata(o));
    if (o != LUA_NOOBJECT) /* object not already gc'ed */
        lua_pushobject(o);
}

static void
gc_ref(void)
{
    lua_unref((int)lua_getuserdata(lua_getparam(1)));
}

Ok, that's all for the moment.  Discussion opened *g*

Ciao, ET.

Edgar Toernig | 2 Apr 2000 23:31
Picon
Picon

Re: Lua Future (Was: Re: The ~)

Erik Hougaard wrote:
> I know some of the things I would like to see?
> ...
> 1. Language constants - That would compile to values.

I though about that myself, something like:

	x = $(f(3)+4*5)

so that part inside the $(...) is executed  by the lexer
and the result, a lua object, is passed up to the parser
as a special kind of constant.

But I never started to implement it.  It was just an idea...

> 1. BCD support for embedded platforms without floating point.

I made a complete lua with integer arithmetic.  No floating point
anywhere.  The standard lua has some problem when LUA_NUM_TYPE is
long - it still uses floating point in a lot of places.

I once posted a patch for this to the mailing list.  In the
meantime I've added some more stuff (more operators, and, or, xor,
not, shift left/right, ...).

Ciao, ET.

Picon

Re: 2 bugs and patches

>From: Edgar Toernig <froese <at> gmx.de>

>1. tostring() without an argument generates a SEGV.

Oops, sorry about that. This will be fixed in the next version.
(On the other, hand, who would want to call tostring() without an argument :-)

>2. Something like "repeat until 1 %foo()" gives a syntax error.

This has been fixed in the next version.

Thanks for spoting these bugs.

--lhf

Picon

Re: Some enhancement requests

>From: Edgar Toernig <froese <at> gmx.de>

>1. Allow the $if/$ifnot statement to test if debugging is turned on
>   so that one can add additional debugging code in lua programs.

The purpose of $debug is to enable better error messages, not to support
user-level debugging.
I think you could do what you want using a global variable, say DEBUG,
and then write:

$if DEBUG
    print("x.n=", getn(x))
    foreach(x, function(i,v) assert(type(i)=="number", "bad x") end)
$end

To enable this code using the standard standalone interpreter, you can simply
do	lua DEBUG=1 myfile.lua

>2. The second argument to the next() function should be optional so that
>   next(foo, nil) is the same as next(foo).  I use next() regularly to test
>   if a table is empty (if next(tab) then print"not empty" end) and the 
>   additional nil is disturbing and inconsistent.

Using "next" to test whether a table is empty is a clever idea, but it got me
thinking *why* you would want to do this.

Anyway, the request sounds reasonable to me. We'll see...
--lhf

Picon

Re: Lua Future

>From: Edgar Toernig <froese <at> gmx.de>

>I made a complete lua with integer arithmetic.  No floating point
>anywhere.  The standard lua has some problem when LUA_NUM_TYPE is
>long - it still uses floating point in a lot of places.

Not "a lot of places", but only in the lexer and in tonumber and tostring:

% grep LUA_NUMBER *.[ch]
lobject.c:double luaO_str2d (char *s) {  /* LUA_NUMBER */
lobject.h:** GREP LUA_NUMBER to change that
lundump.h:#define NUMBER_FMT    "%.16g"         /* LUA_NUMBER */
lvm.c:int luaV_tonumber (TObject *obj) {  /* LUA_NUMBER */
lvm.c:int luaV_tostring (TObject *obj) {  /* LUA_NUMBER */

(NUMBER_FMT in only used in luac.)

Of course, to completely avoid floating point, you have to change the API.
I've promised to write a LTN about this. Will do.
--lhf


Gmane