Compare commits

...

53 Commits

Author SHA1 Message Date
Roberto Ierusalimschy
05caf09a36 list of incompatibilities with version 2.2.
new macro \Version.
1996-02-16 10:12:12 -03:00
Roberto Ierusalimschy
168a865e60 more appropriate error message for "date" 1996-02-16 10:10:14 -03:00
Roberto Ierusalimschy
15c17c24fa small improvements 1996-02-14 16:11:09 -03:00
Roberto Ierusalimschy
45cf24485d useless #include. 1996-02-14 15:25:04 -03:00
Roberto Ierusalimschy
c56e2b2e30 new version 1996-02-14 10:40:26 -03:00
Roberto Ierusalimschy
d1608c597e reserved words are stored in main string table; "marked" field is
used to indicate its type.
Table initializations centralized by "tree.c".
1996-02-14 10:35:51 -03:00
Roberto Ierusalimschy
0f4903a5d7 new header "lex.h". 1996-02-13 14:30:39 -03:00
Roberto Ierusalimschy
772f25d3dd new header for lex.c 1996-02-13 14:30:39 -03:00
Roberto Ierusalimschy
f1a1eda7c5 old trick in "strsub" does not work with new hash table for strings. 1996-02-12 15:34:44 -03:00
Roberto Ierusalimschy
41259bff31 BIG CHANGE: new data structure for constants, strings and globals, using
an array of hash tables for all them.
1996-02-12 15:32:40 -03:00
Roberto Ierusalimschy
afaa98a666 no more "lua_pushliteral". 1996-02-12 15:32:09 -03:00
Roberto Ierusalimschy
73be918285 a backslash followed by a newline allows the newline to go into
a string.
1996-02-09 17:35:23 -02:00
Roberto Ierusalimschy
ca412214cb new function "date", replaces old "date" and "time". 1996-02-09 17:02:30 -02:00
Roberto Ierusalimschy
801722825d "lua_check_number" accepts strings convertible to numbers. 1996-02-09 17:00:23 -02:00
Roberto Ierusalimschy
3abc25fa54 new functions "random" and "randomseed". 1996-02-09 15:21:27 -02:00
Roberto Ierusalimschy
f4d67761f1 new section describing the debug interface. 1996-02-09 14:37:58 -02:00
Roberto Ierusalimschy
369c5fe3c0 lock mechanism more robust; nil is pseudo-locked under index -1. 1996-02-08 17:08:34 -02:00
Roberto Ierusalimschy
7918c6cf11 small bug 1996-02-08 16:14:17 -02:00
Roberto Ierusalimschy
826d70fcba new type lua_Function for activation records 1996-02-08 15:03:20 -02:00
Roberto Ierusalimschy
bbb23048e3 correction of dependencies (include's). 1996-02-07 16:14:38 -02:00
Roberto Ierusalimschy
5a3a1fe458 debug interface functions to manipulated local variables:
"lua_getlocal" and "lua_setlocal".
1996-02-07 16:10:27 -02:00
Roberto Ierusalimschy
56fb06b6f5 "lua_debug" now is exported through debug interface (luadebug.h) 1996-02-07 12:14:40 -02:00
Roberto Ierusalimschy
995a9f7188 no more "Bool" type 1996-02-07 12:13:17 -02:00
Roberto Ierusalimschy
a0ef046ef1 elimination of unused declarations (left from old modifications) 1996-02-06 14:18:21 -02:00
Roberto Ierusalimschy
5fa51fc426 new option "q" in function "write", to write literal strings. 1996-02-05 19:32:19 -02:00
Roberto Ierusalimschy
15057aa0a4 new examples showing data structures and object-oriented programming.
generic improvements and corrections.
1996-02-05 12:52:47 -02:00
Roberto Ierusalimschy
1431b52e76 improve of compiling error messages. 1996-02-05 11:26:01 -02:00
Roberto Ierusalimschy
98fe770cab small bug 1996-02-04 14:59:12 -02:00
Roberto Ierusalimschy
43382ce5a2 new fallback "getglobal". 1996-01-30 13:25:23 -02:00
Roberto Ierusalimschy
abfebf1e21 new example showing how to build modules. 1996-01-30 13:24:49 -02:00
Roberto Ierusalimschy
b1c02c7f00 new fallback "getglobal".
modifications to generate an index (not automatically yet).
1996-01-30 10:55:10 -02:00
Roberto Ierusalimschy
84df3ac267 new functions "tostring", "assert", and "format". 1996-01-29 15:08:23 -02:00
Roberto Ierusalimschy
55a70c9719 "read('s')" was "eating" delimiter. 1996-01-29 14:40:09 -02:00
Roberto Ierusalimschy
0d50b87aa4 lua_table now has references to global variable names (TreeNode's). 1996-01-26 16:03:19 -02:00
Roberto Ierusalimschy
19290a8e92 "dofile" issues an error when called with non string arguments, and
runs stdin when called without arguments.
1996-01-26 14:52:47 -02:00
Roberto Ierusalimschy
d845963349 "setglobal" and "getglobal" moved to inout.c, as it concentrates pre-defined
library.
new function "assert".
1996-01-26 12:05:28 -02:00
Roberto Ierusalimschy
8dae4657a1 "setglobal" and "getglobal" moved to inout.c, as it concentrates pre-defined
library.
1996-01-26 12:04:32 -02:00
Roberto Ierusalimschy
ca7be1cfeb elimination of function "int2str", as it can be replaced by "format('%c', .)" 1996-01-26 10:11:28 -02:00
Roberto Ierusalimschy
445872a6e2 "dofile" does not issue a warning when unable to open the file,
but only returns an error code.
1996-01-23 16:43:07 -02:00
Roberto Ierusalimschy
3681d025ac new function "assert" 1996-01-23 16:39:45 -02:00
Roberto Ierusalimschy
2998049f51 local variable stack needs only the name of the variable (TreeNode);
this way is simpler and faster than old way.
1996-01-23 15:50:29 -02:00
Roberto Ierusalimschy
24ccc7c038 correction of some order dependencies in debug code. 1996-01-22 16:39:37 -02:00
Roberto Ierusalimschy
be48c4d91e add_char now is global.
time returns week-day.
1996-01-22 15:46:55 -02:00
Roberto Ierusalimschy
a19f9056f3 new function "tostring". 1996-01-22 15:40:00 -02:00
Roberto Ierusalimschy
5b71ab780c add_char now is global.
new function format.
1996-01-22 15:38:57 -02:00
Roberto Ierusalimschy
481bafd581 add_char now is global. 1996-01-22 15:38:57 -02:00
Roberto Ierusalimschy
e74b250d71 memory overflow tries a garbage collection; if it fails then exit the
program.
1996-01-22 12:15:13 -02:00
Roberto Ierusalimschy
cd54c95ee1 bug: "read" with format MUST read given number of chars (if file ends
before that reports an error, returning nil).
"readuntil" can be called with nil or no parameters to read until EOF.
1996-01-12 15:00:30 -02:00
Roberto Ierusalimschy
bf006eeaf5 "getobjectname" got a "lua_" prefix. 1996-01-09 18:23:19 -02:00
Roberto Ierusalimschy
b2afc410fa hooks for line change and function calls; first version. 1996-01-09 18:22:44 -02:00
Roberto Ierusalimschy
19cfa32393 correction of dependencies from "luadebug.h". 1996-01-09 18:22:08 -02:00
Roberto Ierusalimschy
27ae8432b6 names generated by yacc (starting with "yy") are changed to start with
"luaY_", to avoid name clashes with hosts using yacc.
1995-12-21 14:14:04 -02:00
Roberto Ierusalimschy
415ee250b5 bug: luaI_findconstantbyname may change the value of lua_constant. 1995-12-18 14:47:29 -02:00
27 changed files with 1366 additions and 621 deletions

View File

@@ -3,7 +3,7 @@
** TecCGraf - PUC-Rio ** TecCGraf - PUC-Rio
*/ */
char *rcs_fallback="$Id: fallback.c,v 1.16 1995/10/17 11:52:38 roberto Exp roberto $"; char *rcs_fallback="$Id: fallback.c,v 1.18 1996/01/30 15:25:23 roberto Exp roberto $";
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -36,8 +36,10 @@ struct FB luaI_fallBacks[] = {
{"concat", {LUA_T_CFUNCTION, {concatFB}}, 2, 1}, {"concat", {LUA_T_CFUNCTION, {concatFB}}, 2, 1},
{"settable", {LUA_T_CFUNCTION, {gettableFB}}, 3, 0}, {"settable", {LUA_T_CFUNCTION, {gettableFB}}, 3, 0},
{"gc", {LUA_T_CFUNCTION, {GDFB}}, 1, 0}, {"gc", {LUA_T_CFUNCTION, {GDFB}}, 1, 0},
{"function", {LUA_T_CFUNCTION, {funcFB}}, -1, -1} {"function", {LUA_T_CFUNCTION, {funcFB}}, -1, -1},
/* no fixed number of params or results */ /* no fixed number of params or results */
{"getglobal", {LUA_T_CFUNCTION, {indexFB}}, 1, 1}
/* same default behavior of index FB */
}; };
#define N_FB (sizeof(luaI_fallBacks)/sizeof(struct FB)) #define N_FB (sizeof(luaI_fallBacks)/sizeof(struct FB))
@@ -121,7 +123,7 @@ int luaI_lock (Object *object)
Word i; Word i;
Word oldSize; Word oldSize;
if (tag(object) == LUA_T_NIL) if (tag(object) == LUA_T_NIL)
return -1; return -1; /* special lock ref for nil */
for (i=0; i<lockSize; i++) for (i=0; i<lockSize; i++)
if (tag(&lockArray[i]) == LUA_T_NIL) if (tag(&lockArray[i]) == LUA_T_NIL)
{ {
@@ -149,13 +151,18 @@ int luaI_lock (Object *object)
void lua_unlock (int ref) void lua_unlock (int ref)
{ {
tag(&lockArray[ref]) = LUA_T_NIL; if (ref >= 0 && ref < lockSize)
tag(&lockArray[ref]) = LUA_T_NIL;
} }
Object *luaI_getlocked (int ref) Object *luaI_getlocked (int ref)
{ {
return &lockArray[ref]; static Object nul = {LUA_T_NIL, {0}};
if (ref >= 0 && ref < lockSize)
return &lockArray[ref];
else
return &nul;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: fallback.h,v 1.9 1995/10/09 13:14:29 roberto Exp roberto $ ** $Id: fallback.h,v 1.10 1995/10/17 11:52:38 roberto Exp roberto $
*/ */
#ifndef fallback_h #ifndef fallback_h
@@ -23,6 +23,7 @@ extern struct FB {
#define FB_SETTABLE 6 #define FB_SETTABLE 6
#define FB_GC 7 #define FB_GC 7
#define FB_FUNCTION 8 #define FB_FUNCTION 8
#define FB_GETGLOBAL 9
void luaI_setfallback (void); void luaI_setfallback (void);
int luaI_lock (Object *object); int luaI_lock (Object *object);

86
func.c
View File

@@ -6,8 +6,23 @@
#include "func.h" #include "func.h"
#include "opcode.h" #include "opcode.h"
static TFunc *function_root = NULL; #define LOCALVARINITSIZE 10
static TFunc *function_root = NULL;
static LocVar *currvars = NULL;
static int numcurrvars = 0;
static int maxcurrvars = 0;
/*
** Initialize TFunc struct
*/
void luaI_initTFunc (TFunc *f)
{
f->code = NULL;
f->lineDefined = 0;
f->locvars = NULL;
}
/* /*
** Insert function in list for GC ** Insert function in list for GC
@@ -27,6 +42,8 @@ void luaI_insertfunction (TFunc *f)
static void freefunc (TFunc *f) static void freefunc (TFunc *f)
{ {
luaI_free (f->code); luaI_free (f->code);
if (f->locvars)
luaI_free (f->locvars);
luaI_free (f); luaI_free (f);
} }
@@ -77,3 +94,70 @@ void lua_funcinfo (lua_Object func, char **filename, int *linedefined)
} }
} }
/*
** Stores information to know that variable has been declared in given line
*/
void luaI_registerlocalvar (TaggedString *varname, int line)
{
if (numcurrvars >= maxcurrvars)
if (currvars == NULL)
{
maxcurrvars = LOCALVARINITSIZE;
currvars = newvector (maxcurrvars, LocVar);
}
else
{
maxcurrvars *= 2;
currvars = growvector (currvars, maxcurrvars, LocVar);
}
currvars[numcurrvars].varname = varname;
currvars[numcurrvars].line = line;
numcurrvars++;
}
/*
** Stores information to know that variable has been out of scope in given line
*/
void luaI_unregisterlocalvar (int line)
{
luaI_registerlocalvar(NULL, line);
}
/*
** Copies "currvars" into a new area and store it in function header.
** The values (varname = NULL, line = -1) signal the end of vector.
*/
void luaI_closelocalvars (TFunc *func)
{
func->locvars = newvector (numcurrvars+1, LocVar);
memcpy (func->locvars, currvars, numcurrvars*sizeof(LocVar));
func->locvars[numcurrvars].varname = NULL;
func->locvars[numcurrvars].line = -1;
numcurrvars = 0; /* prepares for next function */
}
/*
** Look for n-esim local variable at line "line" in function "func".
** Returns NULL if not found.
*/
char *luaI_getlocalname (TFunc *func, int local_number, int line)
{
int count = 0;
char *varname = NULL;
LocVar *lv = func->locvars;
if (lv == NULL)
return NULL;
for (; lv->line != -1 && lv->line < line; lv++)
{
if (lv->varname) /* register */
{
if (++count == local_number)
varname = lv->varname->str;
}
else /* unregister */
if (--count < local_number)
varname = NULL;
}
return varname;
}

16
func.h
View File

@@ -4,8 +4,15 @@
#include "types.h" #include "types.h"
#include "lua.h" #include "lua.h"
typedef struct LocVar
{
TaggedString *varname; /* NULL signals end of scope */
int line;
} LocVar;
/* /*
** Header para funcoes. ** Function Headers
*/ */
typedef struct TFunc typedef struct TFunc
{ {
@@ -15,10 +22,17 @@ typedef struct TFunc
Byte *code; Byte *code;
int lineDefined; int lineDefined;
char *fileName; char *fileName;
LocVar *locvars;
} TFunc; } TFunc;
Long luaI_funccollector (void); Long luaI_funccollector (void);
void luaI_insertfunction (TFunc *f); void luaI_insertfunction (TFunc *f);
void luaI_initTFunc (TFunc *f);
void luaI_registerlocalvar (TaggedString *varname, int line);
void luaI_unregisterlocalvar (int line);
void luaI_closelocalvars (TFunc *func);
char *luaI_getlocalname (TFunc *func, int local_number, int line);
#endif #endif

29
hash.c
View File

@@ -3,9 +3,8 @@
** hash manager for lua ** hash manager for lua
*/ */
char *rcs_hash="$Id: hash.c,v 2.25 1995/05/02 18:43:03 roberto Exp $"; char *rcs_hash="$Id: hash.c,v 2.28 1996/02/12 18:32:40 roberto Exp roberto $";
#include <string.h>
#include "mem.h" #include "mem.h"
#include "opcode.h" #include "opcode.h"
@@ -13,7 +12,6 @@ char *rcs_hash="$Id: hash.c,v 2.25 1995/05/02 18:43:03 roberto Exp $";
#include "table.h" #include "table.h"
#include "lua.h" #include "lua.h"
#define streq(s1,s2) (s1 == s2 || (*(s1) == *(s2) && strcmp(s1,s2)==0))
#define nhash(t) ((t)->nhash) #define nhash(t) ((t)->nhash)
#define nuse(t) ((t)->nuse) #define nuse(t) ((t)->nuse)
@@ -24,19 +22,18 @@ char *rcs_hash="$Id: hash.c,v 2.25 1995/05/02 18:43:03 roberto Exp $";
#define val(n) (&(n)->val) #define val(n) (&(n)->val)
#define REHASH_LIMIT 0.70 /* avoid more than this % full */ #define REHASH_LIMIT 0.70 /* avoid more than this % full */
static Hash *listhead = NULL; static Hash *listhead = NULL;
/* hash dimensions values */ /* hash dimensions values */
static Word dimensions[] = static Word dimensions[] =
{3, 5, 7, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, {3, 5, 7, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421,
12853, 25717, 51437, 65521, 0}; /* 65521 == last prime < MAX_WORD */ 12853, 25717, 51437, 65521, 0}; /* 65521 == last prime < MAX_WORD */
static Word redimension (Word nhash) Word luaI_redimension (Word nhash)
{ {
Word i; Word i;
for (i=0; dimensions[i]!=0; i++) for (i=0; dimensions[i]!=0; i++)
@@ -58,17 +55,7 @@ static Word hashindex (Hash *t, Object *ref) /* hash function */
case LUA_T_NUMBER: case LUA_T_NUMBER:
return (((Word)nvalue(ref))%nhash(t)); return (((Word)nvalue(ref))%nhash(t));
case LUA_T_STRING: case LUA_T_STRING:
{ return (Word)((tsvalue(ref)->hash)%nhash(t)); /* make it a valid index */
unsigned long h = tsvalue(ref)->hash;
if (h == 0)
{
char *name = svalue(ref);
while (*name)
h = ((h<<5)-h)^(unsigned char)*(name++);
tsvalue(ref)->hash = h;
}
return (Word)h%nhash(t); /* make it a valid index */
}
case LUA_T_FUNCTION: case LUA_T_FUNCTION:
return (((IntPoint)ref->value.tf)%nhash(t)); return (((IntPoint)ref->value.tf)%nhash(t));
case LUA_T_CFUNCTION: case LUA_T_CFUNCTION:
@@ -80,14 +67,14 @@ static Word hashindex (Hash *t, Object *ref) /* hash function */
} }
} }
Bool lua_equalObj (Object *t1, Object *t2) int lua_equalObj (Object *t1, Object *t2)
{ {
if (tag(t1) != tag(t2)) return 0; if (tag(t1) != tag(t2)) return 0;
switch (tag(t1)) switch (tag(t1))
{ {
case LUA_T_NIL: return 1; case LUA_T_NIL: return 1;
case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2);
case LUA_T_STRING: return streq(svalue(t1), svalue(t2)); case LUA_T_STRING: return svalue(t1) == svalue(t2);
case LUA_T_ARRAY: return avalue(t1) == avalue(t2); case LUA_T_ARRAY: return avalue(t1) == avalue(t2);
case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf; case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf;
case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2); case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2);
@@ -126,7 +113,7 @@ static Node *hashnodecreate (Word nhash)
static Hash *hashcreate (Word nhash) static Hash *hashcreate (Word nhash)
{ {
Hash *t = new(Hash); Hash *t = new(Hash);
nhash = redimension((Word)((float)nhash/REHASH_LIMIT)); nhash = luaI_redimension((Word)((float)nhash/REHASH_LIMIT));
nodevector(t) = hashnodecreate(nhash); nodevector(t) = hashnodecreate(nhash);
nhash(t) = nhash; nhash(t) = nhash;
nuse(t) = 0; nuse(t) = 0;
@@ -237,7 +224,7 @@ static void rehash (Hash *t)
Word i; Word i;
Word nold = nhash(t); Word nold = nhash(t);
Node *vold = nodevector(t); Node *vold = nodevector(t);
nhash(t) = redimension(nhash(t)); nhash(t) = luaI_redimension(nhash(t));
nodevector(t) = hashnodecreate(nhash(t)); nodevector(t) = hashnodecreate(nhash(t));
for (i=0; i<nold; i++) for (i=0; i<nold; i++)
{ {

6
hash.h
View File

@@ -2,13 +2,14 @@
** hash.h ** hash.h
** hash manager for lua ** hash manager for lua
** Luiz Henrique de Figueiredo - 17 Aug 90 ** Luiz Henrique de Figueiredo - 17 Aug 90
** $Id: hash.h,v 2.7 1994/12/20 21:20:36 roberto Exp roberto $ ** $Id: hash.h,v 2.9 1996/02/07 14:13:17 roberto Exp roberto $
*/ */
#ifndef hash_h #ifndef hash_h
#define hash_h #define hash_h
#include "types.h" #include "types.h"
#include "opcode.h"
typedef struct node typedef struct node
{ {
@@ -26,7 +27,8 @@ typedef struct Hash
} Hash; } Hash;
Bool lua_equalObj (Object *t1, Object *t2); int lua_equalObj (Object *t1, Object *t2);
Word luaI_redimension (Word nhash);
Hash *lua_createarray (Word nhash); Hash *lua_createarray (Word nhash);
void lua_hashmark (Hash *h); void lua_hashmark (Hash *h);
Long lua_hashcollector (void); Long lua_hashcollector (void);

105
inout.c
View File

@@ -5,15 +5,13 @@
** Also provides some predefined lua functions. ** Also provides some predefined lua functions.
*/ */
char *rcs_inout="$Id: inout.c,v 2.24 1995/10/23 13:54:11 roberto Exp roberto $"; char *rcs_inout="$Id: inout.c,v 2.31 1996/02/13 17:30:39 roberto Exp roberto $";
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "mem.h" #include "lex.h"
#include "opcode.h" #include "opcode.h"
#include "hash.h"
#include "inout.h" #include "inout.h"
#include "table.h" #include "table.h"
#include "tree.h" #include "tree.h"
@@ -29,7 +27,6 @@ char *rcs_inout="$Id: inout.c,v 2.24 1995/10/23 13:54:11 roberto Exp roberto $";
/* Exported variables */ /* Exported variables */
Word lua_linenumber; Word lua_linenumber;
Bool lua_debug = 0;
char *lua_parsedfile; char *lua_parsedfile;
@@ -54,9 +51,9 @@ static int stringinput (void)
/* /*
** Function to open a file to be input unit. ** Function to open a file to be input unit.
** Return 0 on success or error message on error. ** Return 0 on success or 1 error.
*/ */
char *lua_openfile (char *fn) int lua_openfile (char *fn)
{ {
lua_setinput (fileinput); lua_setinput (fileinput);
if (fn == NULL) if (fn == NULL)
@@ -67,14 +64,10 @@ char *lua_openfile (char *fn)
else else
fp = fopen (fn, "r"); fp = fopen (fn, "r");
if (fp == NULL) if (fp == NULL)
{ return 1;
static char buff[255];
sprintf(buff, "unable to open file `%.200s'", fn);
return buff;
}
lua_linenumber = 1; lua_linenumber = 1;
lua_parsedfile = lua_constcreate(fn)->ts.str; lua_parsedfile = lua_constcreate(fn)->str;
return NULL; return 0;
} }
/* /*
@@ -97,7 +90,7 @@ void lua_openstring (char *s)
lua_setinput (stringinput); lua_setinput (stringinput);
st = s; st = s;
lua_linenumber = 1; lua_linenumber = 1;
lua_parsedfile = lua_constcreate("(string)")->ts.str; lua_parsedfile = lua_constcreate("(string)")->str;
} }
/* /*
@@ -126,33 +119,52 @@ void lua_internaldostring (void)
void lua_internaldofile (void) void lua_internaldofile (void)
{ {
lua_Object obj = lua_getparam (1); lua_Object obj = lua_getparam (1);
if (lua_isstring(obj) && !lua_dofile(lua_getstring(obj))) char *fname = NULL;
if (lua_isstring(obj))
fname = lua_getstring(obj);
else if (obj != LUA_NOOBJECT)
lua_error("invalid argument to function `dofile'");
/* else fname = NULL */
if (!lua_dofile(fname))
lua_pushnumber(1); lua_pushnumber(1);
else else
lua_pushnil(); lua_pushnil();
} }
/*
** Internal function: print object values static char *tostring (lua_Object obj)
*/
void lua_print (void)
{ {
int i=1; static char buff[20];
lua_Object obj; if (lua_isstring(obj))
while ((obj=lua_getparam (i++)) != LUA_NOOBJECT) return lua_getstring(obj);
{ if (lua_isnumber(obj))
if (lua_isnumber(obj)) printf("%g\n",lua_getnumber(obj)); sprintf(buff, "%g", lua_getnumber(obj));
else if (lua_isstring(obj)) printf("%s\n",lua_getstring(obj)); else if (lua_isfunction(obj))
else if (lua_isfunction(obj)) printf("function: %p\n",(luaI_Address(obj))->value.tf); sprintf(buff, "function: %p", (luaI_Address(obj))->value.tf);
else if (lua_iscfunction(obj)) printf("cfunction: %p\n",lua_getcfunction(obj) else if (lua_iscfunction(obj))
); sprintf(buff, "cfunction: %p", lua_getcfunction(obj));
else if (lua_isuserdata(obj)) printf("userdata: %p\n",lua_getuserdata(obj)); else if (lua_isuserdata(obj))
else if (lua_istable(obj)) printf("table: %p\n",avalue(luaI_Address(obj))); sprintf(buff, "userdata: %p", lua_getuserdata(obj));
else if (lua_isnil(obj)) printf("nil\n"); else if (lua_istable(obj))
else printf("invalid value to print\n"); sprintf(buff, "table: %p", avalue(luaI_Address(obj)));
} else if (lua_isnil(obj))
sprintf(buff, "nil");
else buff[0] = 0;
return buff;
} }
void luaI_tostring (void)
{
lua_pushstring(tostring(lua_getparam(1)));
}
void luaI_print (void)
{
int i = 1;
lua_Object obj;
while ((obj = lua_getparam(i++)) != LUA_NOOBJECT)
printf("%s\n", tostring(obj));
}
/* /*
** Internal function: return an object type. ** Internal function: return an object type.
@@ -218,3 +230,28 @@ void luaI_error (void)
lua_error(s); lua_error(s);
} }
void luaI_assert (void)
{
lua_Object p = lua_getparam(1);
if (p == LUA_NOOBJECT || lua_isnil(p))
lua_error("assertion failed!");
}
void luaI_setglobal (void)
{
lua_Object name = lua_getparam(1);
lua_Object value = lua_getparam(2);
if (!lua_isstring(name))
lua_error("incorrect argument to function `setglobal'");
lua_pushobject(value);
lua_storeglobal(lua_getstring(name));
lua_pushobject(value); /* return given value */
}
void luaI_getglobal (void)
{
lua_Object name = lua_getparam(1);
if (!lua_isstring(name))
lua_error("incorrect argument to function `getglobal'");
lua_pushobject(lua_getglobal(lua_getstring(name)));
}

11
inout.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: inout.h,v 1.9 1995/05/16 17:23:58 roberto Exp roberto $ ** $Id: inout.h,v 1.12 1996/01/26 14:05:28 roberto Exp roberto $
*/ */
@@ -10,20 +10,23 @@
extern Word lua_linenumber; extern Word lua_linenumber;
extern Bool lua_debug;
extern Word lua_debugline; extern Word lua_debugline;
extern char *lua_parsedfile; extern char *lua_parsedfile;
char *lua_openfile (char *fn); int lua_openfile (char *fn);
void lua_closefile (void); void lua_closefile (void);
void lua_openstring (char *s); void lua_openstring (char *s);
void lua_closestring (void); void lua_closestring (void);
void lua_internaldofile (void); void lua_internaldofile (void);
void lua_internaldostring (void); void lua_internaldostring (void);
void lua_print (void); void luaI_tostring (void);
void luaI_print (void);
void luaI_type (void); void luaI_type (void);
void lua_obj2number (void); void lua_obj2number (void);
void luaI_error (void); void luaI_error (void);
void luaI_assert (void);
void luaI_setglobal (void);
void luaI_getglobal (void);
#endif #endif

188
iolib.c
View File

@@ -3,7 +3,7 @@
** Input/output library to LUA ** Input/output library to LUA
*/ */
char *rcs_iolib="$Id: iolib.c,v 1.28 1995/11/10 17:55:48 roberto Exp roberto $"; char *rcs_iolib="$Id: iolib.c,v 1.35 1996/02/09 19:35:23 roberto Exp roberto $";
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@@ -12,6 +12,7 @@ char *rcs_iolib="$Id: iolib.c,v 1.28 1995/11/10 17:55:48 roberto Exp roberto $";
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include "lua.h" #include "lua.h"
#include "luadebug.h" #include "luadebug.h"
@@ -142,15 +143,14 @@ static char getformat (char *f, int *just, int *m, int *n)
int t; int t;
switch (*f++) switch (*f++)
{ {
case 'q': case 'Q':
case 's': case 'S': case 's': case 'S':
t = 's'; case 'i': case 'I':
t = tolower(*(f-1));
break; break;
case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'e': case 'E':
t = 'f'; t = 'f';
break; break;
case 'i': case 'I':
t = 'i';
break;
default: default:
t = 0; /* to avoid compiler warnings */ t = 0; /* to avoid compiler warnings */
lua_arg_error("read/write (format)"); lua_arg_error("read/write (format)");
@@ -177,32 +177,6 @@ static char getformat (char *f, int *just, int *m, int *n)
} }
static char *add_char (int c)
{
static char *buff = NULL;
static int max = 0;
static int n = 0;
if (n >= max)
{
if (max == 0)
{
max = 100;
buff = (char *)malloc(max);
}
else
{
max *= 2;
buff = (char *)realloc(buff, max);
}
if (buff == NULL)
lua_error("memory overflow");
}
buff[n++] = c;
if (c == 0)
n = 0; /* prepare for next string */
return buff;
}
/* /*
** Read a variable. On error put nil on stack. ** Read a variable. On error put nil on stack.
** LUA interface: ** LUA interface:
@@ -222,23 +196,23 @@ static int read_until_char (int del)
{ {
int c; int c;
while((c = fgetc(in)) != EOF && c != del) while((c = fgetc(in)) != EOF && c != del)
add_char(c); luaI_addchar(c);
return c; return c;
} }
static int read_until_blank (void) static void read_until_blank (void)
{ {
int c; int c;
while((c = fgetc(in)) != EOF && !isspace(c)) while((c = fgetc(in)) != EOF && !isspace(c))
add_char(c); luaI_addchar(c);
return c; if (c != EOF) ungetc(c,in);
} }
static void read_m (int m) static void read_m (int m)
{ {
int c; int c;
while (m-- && (c = fgetc(in)) != EOF) while (m-- && (c = fgetc(in)) != EOF)
add_char(c); luaI_addchar(c);
} }
@@ -256,21 +230,18 @@ static void read_free (void)
{ /* string */ { /* string */
c = read_until_char(c); c = read_until_char(c);
if (c == EOF) if (c == EOF)
{
add_char(0); /* to be ready for next time */
lua_pushnil(); lua_pushnil();
}
else else
lua_pushstring(add_char(0)); lua_pushstring(luaI_addchar(0));
} }
else else
{ {
double d; double d;
char dummy; char dummy;
char *s; char *s;
add_char(c); luaI_addchar(c);
read_until_blank(); read_until_blank();
s = add_char(0); s = luaI_addchar(0);
if (sscanf(s, "%lf %c", &d, &dummy) == 1) if (sscanf(s, "%lf %c", &d, &dummy) == 1)
lua_pushnumber(d); lua_pushnumber(d);
else else
@@ -281,6 +252,7 @@ static void read_free (void)
static void io_read (void) static void io_read (void)
{ {
lua_Object o = lua_getparam (1); lua_Object o = lua_getparam (1);
luaI_addchar(0); /* initialize buffer */
if (o == LUA_NOOBJECT) /* free format */ if (o == LUA_NOOBJECT) /* free format */
read_free(); read_free();
else /* formatted */ else /* formatted */
@@ -289,12 +261,19 @@ static void io_read (void)
switch (getformat(lua_check_string(1, "read"), &dummy1, &m, &dummy2)) switch (getformat(lua_check_string(1, "read"), &dummy1, &m, &dummy2))
{ {
case 's': case 's':
{
char *s;
if (m < 0) if (m < 0)
read_until_blank(); read_until_blank();
else else
read_m(m); read_m(m);
lua_pushstring(add_char(0)); s = luaI_addchar(0);
if ((m >= 0 && strlen(s) == m) || (m < 0 && strlen(s) > 0))
lua_pushstring(s);
else
lua_pushnil();
break; break;
}
case 'i': /* can read as float, since it makes no difference to Lua */ case 'i': /* can read as float, since it makes no difference to Lua */
case 'f': case 'f':
@@ -306,7 +285,7 @@ static void io_read (void)
else else
{ {
read_m(m); read_m(m);
result = sscanf(add_char(0), "%lf", &d); result = sscanf(luaI_addchar(0), "%lf", &d);
} }
if (result == 1) if (result == 1)
lua_pushnumber(d); lua_pushnumber(d);
@@ -314,6 +293,8 @@ static void io_read (void)
lua_pushnil(); lua_pushnil();
break; break;
} }
default:
lua_arg_error("read (format)");
} }
} }
} }
@@ -324,10 +305,16 @@ static void io_read (void)
*/ */
static void io_readuntil (void) static void io_readuntil (void)
{ {
int del = *lua_check_string(1, "readuntil"); int del, c;
int c = read_until_char(del); lua_Object p = lua_getparam(1);
luaI_addchar(0); /* initialize buffer */
if (p == LUA_NOOBJECT || lua_isnil(p))
del = EOF;
else
del = *lua_check_string(1, "readuntil");
c = read_until_char(del);
if (c != EOF) ungetc(c,in); if (c != EOF) ungetc(c,in);
lua_pushstring(add_char(0)); lua_pushstring(luaI_addchar(0));
} }
@@ -384,6 +371,30 @@ static int write_string (char *s, int just, int m)
return status; return status;
} }
static int write_quoted (int just, int m)
{
char *s = lua_check_string(1, "write");
luaI_addchar(0);
luaI_addchar('"');
while (1)
{
switch (*s)
{
case '"': case '\\': case '\n':
luaI_addchar('\\');
luaI_addchar(*s);
break;
case 0:
goto END_WHILE;
default:
luaI_addchar(*s);
}
s++;
} END_WHILE:
luaI_addchar('"');
return write_string(luaI_addchar(0), just, m);
}
static int write_float (int just, int m, int n) static int write_float (int just, int m, int n)
{ {
char buffer[100]; char buffer[100];
@@ -428,7 +439,7 @@ static void io_write (void)
else /* formated */ else /* formated */
{ {
int just, m, n; int just, m, n;
switch (getformat (lua_check_string(2, "write"), &just, &m, &n)) switch (getformat(lua_check_string(2, "write"), &just, &m, &n))
{ {
case 's': case 's':
{ {
@@ -439,6 +450,9 @@ static void io_write (void)
status = 0; status = 0;
break; break;
} }
case 'q':
status = write_quoted(just, m);
break;
case 'f': case 'f':
status = write_float(just, m, n); status = write_float(just, m, n);
break; break;
@@ -473,9 +487,14 @@ static void io_remove (void)
lua_pushnil(); lua_pushnil();
} }
static void io_errorno (void)
{
/* lua_pushstring(strerror(errno));*/
}
/* /*
** To get a environment variables ** To get a environment variable
*/ */
static void io_getenv (void) static void io_getenv (void)
{ {
@@ -485,41 +504,23 @@ static void io_getenv (void)
} }
/* /*
** Return time: hour, min, sec ** Return user formatted time stamp
*/
static void io_time (void)
{
time_t t;
struct tm *s;
time(&t);
s = localtime(&t);
lua_pushnumber(s->tm_hour);
lua_pushnumber(s->tm_min);
lua_pushnumber(s->tm_sec);
}
/*
** Return date: dd, mm, yyyy
*/ */
static void io_date (void) static void io_date (void)
{ {
time_t t; time_t t;
struct tm *s; struct tm *tm;
char *s;
time(&t); char b[BUFSIZ];
s = localtime(&t); if (lua_getparam(1) == LUA_NOOBJECT)
lua_pushnumber(s->tm_mday); s = "%c";
lua_pushnumber(s->tm_mon+1); else
lua_pushnumber(s->tm_year+1900); s = lua_check_string(1, "date");
} time(&t); tm = localtime(&t);
if (strftime(b,sizeof(b),s,tm))
/* lua_pushstring(b);
** Beep else
*/ lua_error("invalid `date' format");
static void io_beep (void)
{
printf("\a");
} }
/* /*
@@ -560,7 +561,7 @@ void lua_printstack (FILE *f)
char *name; char *name;
int currentline; int currentline;
fprintf(f, "\t"); fprintf(f, "\t");
switch (*getobjname(func, &name)) switch (*lua_getobjname(func, &name))
{ {
case 'g': case 'g':
fprintf(f, "function %s", name); fprintf(f, "function %s", name);
@@ -610,13 +611,34 @@ void iolib_open (void)
lua_register ("write", io_write); lua_register ("write", io_write);
lua_register ("execute", io_execute); lua_register ("execute", io_execute);
lua_register ("remove", io_remove); lua_register ("remove", io_remove);
lua_register ("ioerror", io_errorno);
lua_register ("getenv", io_getenv); lua_register ("getenv", io_getenv);
lua_register ("time", io_time);
lua_register ("date", io_date); lua_register ("date", io_date);
lua_register ("beep", io_beep);
lua_register ("exit", io_exit); lua_register ("exit", io_exit);
lua_register ("debug", io_debug); lua_register ("debug", io_debug);
lua_register ("print_stack", errorfb); lua_register ("print_stack", errorfb);
lua_setfallback("error", errorfb); lua_setfallback("error", errorfb);
} }
/*
** Return user formatted time stamp
*
static void sys_localtime (void)
{
time_t t;
struct tm *tm;
lua_Object o = lua_getparam(1);
time(&t); tm = localtime(&t);
if (lua_isstring(o))
{
char b[BUFSIZ];
if (strftime(b,sizeof(b),lua_getstring(o),tm)==0)
lua_pushstring(ctime(&t));
else
lua_pushstring(b);
}
else
lua_pushstring(ctime(&t));
}
*/

56
lex.c
View File

@@ -1,23 +1,21 @@
char *rcs_lex = "$Id: lex.c,v 2.20 1995/10/25 13:05:51 roberto Exp roberto $"; char *rcs_lex = "$Id: lex.c,v 2.27 1996/02/14 13:35:51 roberto Exp roberto $";
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "mem.h" #include "mem.h"
#include "tree.h" #include "tree.h"
#include "table.h" #include "table.h"
#include "opcode.h" #include "lex.h"
#include "inout.h" #include "inout.h"
#include "luadebug.h"
#include "parser.h" #include "parser.h"
#include "ugly.h" #include "ugly.h"
#define MINBUFF 260 #define MINBUFF 260
#define lua_strcmp(a,b) (a[0]<b[0]?(-1):(a[0]>b[0]?(1):strcmp(a,b)))
#define next() { current = input(); } #define next() { current = input(); }
#define save(x) { *yytextLast++ = (x); } #define save(x) { *yytextLast++ = (x); }
#define save_and_next() { save(current); next(); } #define save_and_next() { save(current); next(); }
@@ -47,7 +45,6 @@ char *lua_lasttext (void)
} }
/* The reserved words must be listed in lexicographic order */
static struct static struct
{ {
char *name; char *name;
@@ -74,22 +71,14 @@ static struct
#define RESERVEDSIZE (sizeof(reserved)/sizeof(reserved[0])) #define RESERVEDSIZE (sizeof(reserved)/sizeof(reserved[0]))
static int findReserved (char *name) void luaI_addReserved (void)
{ {
int l = 0; int i;
int h = RESERVEDSIZE - 1; for (i=0; i<RESERVEDSIZE; i++)
while (l <= h)
{ {
int m = (l+h)/2; TaggedString *ts = lua_createstring(reserved[i].name);
int comp = lua_strcmp(name, reserved[m].name); ts->marked = reserved[i].token; /* reserved word (always > 255) */
if (comp < 0)
h = m-1;
else if (comp == 0)
return reserved[m].token;
else
l = m+1;
} }
return 0;
} }
@@ -144,7 +133,7 @@ static int read_long_string (void)
} }
int yylex (void) int luaY_lex (void)
{ {
float a; float a;
static int linelasttoken = 0; static int linelasttoken = 0;
@@ -174,14 +163,14 @@ int yylex (void)
while (isalnum(current) || current == '_') while (isalnum(current) || current == '_')
save_and_next(); save_and_next();
*yytextLast = 0; *yytextLast = 0;
if (lua_strcmp(yytext, "debug") == 0) if (strcmp(yytext, "debug") == 0)
{ {
yylval.vInt = 1; luaY_lval.vInt = 1;
return DEBUG; return DEBUG;
} }
else if (lua_strcmp(yytext, "nodebug") == 0) else if (strcmp(yytext, "nodebug") == 0)
{ {
yylval.vInt = 0; luaY_lval.vInt = 0;
return DEBUG; return DEBUG;
} }
return WRONGTOKEN; return WRONGTOKEN;
@@ -203,7 +192,7 @@ int yylex (void)
return WRONGTOKEN; return WRONGTOKEN;
save_and_next(); /* pass the second ']' */ save_and_next(); /* pass the second ']' */
*(yytextLast-2) = 0; /* erases ']]' */ *(yytextLast-2) = 0; /* erases ']]' */
yylval.vWord = luaI_findconstantbyname(yytext+2); luaY_lval.vWord = luaI_findconstantbyname(yytext+2);
return STRING; return STRING;
} }
@@ -254,6 +243,7 @@ int yylex (void)
case 'n': save('\n'); next(); break; case 'n': save('\n'); next(); break;
case 't': save('\t'); next(); break; case 't': save('\t'); next(); break;
case 'r': save('\r'); next(); break; case 'r': save('\r'); next(); break;
case '\n': lua_linenumber++; /* goes through */
default : save(current); next(); break; default : save(current); next(); break;
} }
break; break;
@@ -263,7 +253,7 @@ int yylex (void)
} }
next(); /* skip the delimiter */ next(); /* skip the delimiter */
*yytextLast = 0; *yytextLast = 0;
yylval.vWord = luaI_findconstantbyname(yytext); luaY_lval.vWord = luaI_findconstantbyname(yytext);
return STRING; return STRING;
} }
@@ -281,12 +271,14 @@ int yylex (void)
case 'Z': case 'Z':
case '_': case '_':
{ {
Word res; TaggedString *ts;
do { save_and_next(); } while (isalnum(current) || current == '_'); do { save_and_next(); } while (isalnum(current) || current == '_');
*yytextLast = 0; *yytextLast = 0;
res = findReserved(yytext); ts = lua_createstring(yytext);
if (res) return res; if (ts->marked > 2)
yylval.pNode = lua_constcreate(yytext); return ts->marked; /* reserved word */
luaY_lval.pTStr = ts;
ts->marked = 2; /* avoid GC */
return NAME; return NAME;
} }
@@ -327,7 +319,7 @@ fraction:
ea*=ea; ea*=ea;
} }
} }
yylval.vFloat = a; luaY_lval.vFloat = a;
return NUMBER; return NUMBER;
} }

19
lex.h Normal file
View File

@@ -0,0 +1,19 @@
/*
** lex.h
** TecCGraf - PUC-Rio
** $Id: lex.h,v 1.1 1996/02/13 17:30:39 roberto Exp roberto $
*/
#ifndef lex_h
#define lex_h
typedef int (*Input) (void);
void lua_setinput (Input fn);
char *lua_lasttext (void);
int luaY_lex (void);
void luaI_addReserved (void);
#endif

9
lua.h
View File

@@ -2,14 +2,14 @@
** LUA - Linguagem para Usuarios de Aplicacao ** LUA - Linguagem para Usuarios de Aplicacao
** Grupo de Tecnologia em Computacao Grafica ** Grupo de Tecnologia em Computacao Grafica
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: lua.h,v 3.20 1995/10/31 16:41:53 roberto Exp roberto $ ** $Id: lua.h,v 3.22 1996/02/12 18:32:09 roberto Exp roberto $
*/ */
#ifndef lua_h #ifndef lua_h
#define lua_h #define lua_h
#define LUA_VERSION "Lua 2.2" #define LUA_VERSION "Lua 2.3 (beta)"
#define LUA_COPYRIGHT "Copyright (C) 1994, 1995 TeCGraf" #define LUA_COPYRIGHT "Copyright (C) 1994, 1995 TeCGraf"
#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo"
@@ -60,7 +60,6 @@ void *lua_getuserdata (lua_Object object);
void lua_pushnil (void); void lua_pushnil (void);
void lua_pushnumber (float n); void lua_pushnumber (float n);
void lua_pushstring (char *s); void lua_pushstring (char *s);
void lua_pushliteral (char *s);
void lua_pushcfunction (lua_CFunction fn); void lua_pushcfunction (lua_CFunction fn);
void lua_pushusertag (void *u, int tag); void lua_pushusertag (void *u, int tag);
void lua_pushobject (lua_Object object); void lua_pushobject (lua_Object object);
@@ -98,7 +97,9 @@ lua_Object lua_createtable (void);
#define lua_isuserdata(_) (lua_type(_)>=LUA_T_USERDATA) #define lua_isuserdata(_) (lua_type(_)>=LUA_T_USERDATA)
/* for lua 1.1 compatibility. Avoid using these macros */ /* for compatibility with old versions. Avoid using these macros */
#define lua_pushliteral(o) lua_pushstring(o)
#define lua_getindexed(o,n) (lua_pushobject(o), lua_pushnumber(n), lua_getsubscript()) #define lua_getindexed(o,n) (lua_pushobject(o), lua_pushnumber(n), lua_getsubscript())
#define lua_getfield(o,f) (lua_pushobject(o), lua_pushliteral(f), lua_getsubscript()) #define lua_getfield(o,f) (lua_pushobject(o), lua_pushliteral(f), lua_getsubscript())

118
lua.stx
View File

@@ -1,12 +1,13 @@
%{ %{
char *rcs_luastx = "$Id: lua.stx,v 3.24 1995/10/26 14:21:56 roberto Exp roberto $"; char *rcs_luastx = "$Id: lua.stx,v 3.31 1996/02/13 17:30:39 roberto Exp roberto $";
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "luadebug.h"
#include "mem.h" #include "mem.h"
#include "lex.h"
#include "opcode.h" #include "opcode.h"
#include "hash.h" #include "hash.h"
#include "inout.h" #include "inout.h"
@@ -44,21 +45,25 @@ static Long varbuffer[MAXVAR]; /* variables in an assignment list;
static int nvarbuffer=0; /* number of variables at a list */ static int nvarbuffer=0; /* number of variables at a list */
#define MAXLOCALS 32 #define MAXLOCALS 32
static Word localvar[MAXLOCALS]; /* store local variable names */ static TaggedString *localvar[MAXLOCALS]; /* store local variable names */
static int nlocalvar=0; /* number of local variables */ static int nlocalvar=0; /* number of local variables */
#define MAXFIELDS FIELDS_PER_FLUSH*2 #define MAXFIELDS FIELDS_PER_FLUSH*2
static Word fields[MAXFIELDS]; /* fieldnames to be flushed */ static Word fields[MAXFIELDS]; /* fieldnames to be flushed */
static int nfields=0; static int nfields=0;
int lua_debug = 0;
/* Internal functions */ /* Internal functions */
static void yyerror (char *s) static void yyerror (char *s)
{ {
static char msg[256]; char msg[256];
sprintf (msg,"%s near \"%s\" at line %d in file `%s'", char *token = lua_lasttext();
s, lua_lasttext (), lua_linenumber, lua_parsedfile); if (token[0] == 0)
token = "<eof>";
sprintf (msg,"%s; last token read: \"%s\" at line %d in file `%s'",
s, token, lua_linenumber, lua_parsedfile);
lua_error (msg); lua_error (msg);
} }
@@ -67,7 +72,7 @@ static void code_byte (Byte c)
if (pc>maxcurr-2) /* 1 byte free to code HALT of main code */ if (pc>maxcurr-2) /* 1 byte free to code HALT of main code */
{ {
if (maxcurr >= MAX_INT) if (maxcurr >= MAX_INT)
lua_error("code size overflow"); yyerror("code size overflow");
maxcurr *= 2; maxcurr *= 2;
if (maxcurr >= MAX_INT) if (maxcurr >= MAX_INT)
maxcurr = MAX_INT; maxcurr = MAX_INT;
@@ -117,7 +122,7 @@ static void push_field (Word name)
if (nfields < MAXFIELDS) if (nfields < MAXFIELDS)
fields[nfields++] = name; fields[nfields++] = name;
else else
lua_error ("too many fields in nested constructors"); yyerror ("too many fields in nested constructors");
} }
static void flush_record (int n) static void flush_record (int n)
@@ -142,24 +147,24 @@ static void flush_list (int m, int n)
code_byte(m); code_byte(m);
} }
else else
lua_error ("list constructor too long"); yyerror ("list constructor too long");
code_byte(n); code_byte(n);
} }
static void add_localvar (Word name) static void store_localvar (TaggedString *name, int n)
{
if (nlocalvar < MAXLOCALS)
localvar[nlocalvar++] = name;
else
lua_error ("too many local variables");
}
static void store_localvar (Word name, int n)
{ {
if (nlocalvar+n < MAXLOCALS) if (nlocalvar+n < MAXLOCALS)
localvar[nlocalvar+n] = name; localvar[nlocalvar+n] = name;
else else
lua_error ("too many local variables"); yyerror ("too many local variables");
if (lua_debug)
luaI_registerlocalvar(name, lua_linenumber);
}
static void add_localvar (TaggedString *name)
{
store_localvar(name, 0);
nlocalvar++;
} }
static void add_varbuffer (Long var) static void add_varbuffer (Long var)
@@ -167,7 +172,7 @@ static void add_varbuffer (Long var)
if (nvarbuffer < MAXVAR) if (nvarbuffer < MAXVAR)
varbuffer[nvarbuffer++] = var; varbuffer[nvarbuffer++] = var;
else else
lua_error ("variable buffer overflow"); yyerror ("variable buffer overflow");
} }
static void code_number (float f) static void code_number (float f)
@@ -197,7 +202,7 @@ static void code_number (float f)
/* /*
** Search a local name and if find return its index. If do not find return -1 ** Search a local name and if find return its index. If do not find return -1
*/ */
static int lua_localname (Word n) static int lua_localname (TaggedString *n)
{ {
int i; int i;
for (i=nlocalvar-1; i >= 0; i--) for (i=nlocalvar-1; i >= 0; i--)
@@ -388,7 +393,6 @@ static void codeIf (Long thenAdd, Long elseAdd)
*/ */
void lua_parse (TFunc *tf) void lua_parse (TFunc *tf)
{ {
lua_debug = 0;
initcode = &(tf->code); initcode = &(tf->code);
*initcode = newvector(CODE_BLOCK, Byte); *initcode = newvector(CODE_BLOCK, Byte);
maincode = 0; maincode = 0;
@@ -416,7 +420,7 @@ void lua_parse (TFunc *tf)
Word vWord; Word vWord;
Long vLong; Long vLong;
TFunc *pFunc; TFunc *pFunc;
TreeNode *pNode; TaggedString *pTStr;
} }
%start functionlist %start functionlist
@@ -429,7 +433,7 @@ void lua_parse (TFunc *tf)
%token FUNCTION %token FUNCTION
%token <vFloat> NUMBER %token <vFloat> NUMBER
%token <vWord> STRING %token <vWord> STRING
%token <pNode> NAME %token <pTStr> NAME
%token <vInt> DEBUG %token <vInt> DEBUG
%type <vLong> PrepJump %type <vLong> PrepJump
@@ -481,7 +485,7 @@ funcname : var { $$ =$1; init_func(); }
code_word(luaI_findconstant($3)); code_word(luaI_findconstant($3));
$$ = 0; /* indexed variable */ $$ = 0; /* indexed variable */
init_func(); init_func();
add_localvar(luaI_findsymbolbyname("self")); add_localvar(lua_constcreate("self"));
} }
; ;
@@ -489,11 +493,14 @@ body : '(' parlist ')' block END
{ {
codereturn(); codereturn();
$$ = new(TFunc); $$ = new(TFunc);
luaI_initTFunc($$);
$$->size = pc; $$->size = pc;
$$->code = newvector(pc, Byte); $$->code = newvector(pc, Byte);
$$->fileName = lua_parsedfile; $$->fileName = lua_parsedfile;
$$->lineDefined = $2; $$->lineDefined = $2;
memcpy($$->code, basepc, pc*sizeof(Byte)); memcpy($$->code, basepc, pc*sizeof(Byte));
if (lua_debug)
luaI_closelocalvars($$);
/* save func values */ /* save func values */
funcCode = basepc; maxcode=maxcurr; funcCode = basepc; maxcode=maxcurr;
#if LISTING #if LISTING
@@ -554,7 +561,11 @@ block : {$<vInt>$ = nlocalvar;} statlist ret
{ {
if (nlocalvar != $<vInt>1) if (nlocalvar != $<vInt>1)
{ {
nlocalvar = $<vInt>1; if (lua_debug)
for (; nlocalvar > $<vInt>1; nlocalvar--)
luaI_unregisterlocalvar(lua_linenumber);
else
nlocalvar = $<vInt>1;
lua_codeadjust (0); lua_codeadjust (0);
} }
} }
@@ -672,14 +683,8 @@ parlist : /* empty */ { lua_codeadjust(0); $$ = lua_linenumber; }
| parlist1 { lua_codeadjust(0); $$ = lua_linenumber; } | parlist1 { lua_codeadjust(0); $$ = lua_linenumber; }
; ;
parlist1 : NAME parlist1 : NAME { add_localvar($1); }
{ | parlist1 ',' NAME { add_localvar($3); }
add_localvar(luaI_findsymbol($1));
}
| parlist1 ',' NAME
{
add_localvar(luaI_findsymbol($3));
}
; ;
fieldlist : lfieldlist fieldlist : lfieldlist
@@ -759,10 +764,9 @@ var : singlevar { $$ = $1; }
singlevar : NAME singlevar : NAME
{ {
Word s = luaI_findsymbol($1); int local = lua_localname($1);
int local = lua_localname (s);
if (local == -1) /* global var */ if (local == -1) /* global var */
$$ = s + 1; /* return positive value */ $$ = luaI_findsymbol($1)+1; /* return positive value */
else else
$$ = -(local+1); /* return negative value */ $$ = -(local+1); /* return negative value */
} }
@@ -771,10 +775,10 @@ singlevar : NAME
varexp : var { lua_pushvar($1); } varexp : var { lua_pushvar($1); }
; ;
localdeclist : NAME {store_localvar(luaI_findsymbol($1), 0); $$ = 1;} localdeclist : NAME {store_localvar($1, 0); $$ = 1;}
| localdeclist ',' NAME | localdeclist ',' NAME
{ {
store_localvar(luaI_findsymbol($3), $1); store_localvar($3, $1);
$$ = $1+1; $$ = $1+1;
} }
; ;
@@ -804,8 +808,8 @@ static void PrintCode (Byte *code, Byte *end)
p++; p++;
break; break;
case PUSHBYTE: case PUSHBYTE:
printf ("%d PUSHBYTE %d\n", p-code, *(++p)); printf ("%d PUSHBYTE %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case PUSHWORD: case PUSHWORD:
{ {
@@ -850,8 +854,8 @@ static void PrintCode (Byte *code, Byte *end)
printf ("%d PUSHLOCAL%c\n", p-code, *p-PUSHLOCAL0+'0'); printf ("%d PUSHLOCAL%c\n", p-code, *p-PUSHLOCAL0+'0');
p++; p++;
break; break;
case PUSHLOCAL: printf ("%d PUSHLOCAL %d\n", p-code, *(++p)); case PUSHLOCAL: printf ("%d PUSHLOCAL %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case PUSHGLOBAL: case PUSHGLOBAL:
{ {
@@ -870,8 +874,8 @@ static void PrintCode (Byte *code, Byte *end)
p++; p++;
break; break;
case STORELOCAL: case STORELOCAL:
printf ("%d STORELOCAL %d\n", p-code, *(++p)); printf ("%d STORELOCAL %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case STOREGLOBAL: case STOREGLOBAL:
{ {
@@ -892,25 +896,25 @@ static void PrintCode (Byte *code, Byte *end)
} }
break; break;
case STOREINDEXED0: printf ("%d STOREINDEXED0\n", (p++)-code); break; case STOREINDEXED0: printf ("%d STOREINDEXED0\n", (p++)-code); break;
case STOREINDEXED: printf ("%d STOREINDEXED %d\n", p-code, *(++p)); case STOREINDEXED: printf ("%d STOREINDEXED %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case STORELIST0: case STORELIST0:
printf("%d STORELIST0 %d\n", p-code, *(++p)); printf("%d STORELIST0 %d\n", p-code, *(p+1));
p++; p+=2+;
break; break;
case STORELIST: case STORELIST:
printf("%d STORELIST %d %d\n", p-code, *(p+1), *(p+2)); printf("%d STORELIST %d %d\n", p-code, *(p+1), *(p+2));
p+=3; p+=3;
break; break;
case STORERECORD: case STORERECORD:
printf("%d STORERECORD %d\n", p-code, *(++p)); printf("%d STORERECORD %d\n", p-code, *(p+1));
p += *p*sizeof(Word) + 1; p += *p*sizeof(Word) + 2;
break; break;
case ADJUST0: printf ("%d ADJUST0\n", (p++)-code); break; case ADJUST0: printf ("%d ADJUST0\n", (p++)-code); break;
case ADJUST: case ADJUST:
printf ("%d ADJUST %d\n", p-code, *(++p)); printf ("%d ADJUST %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case CREATEARRAY: case CREATEARRAY:
{ {
@@ -993,8 +997,8 @@ static void PrintCode (Byte *code, Byte *end)
break; break;
case RETCODE0: printf ("%d RETCODE0\n", (p++)-code); break; case RETCODE0: printf ("%d RETCODE0\n", (p++)-code); break;
case RETCODE: case RETCODE:
printf ("%d RETCODE %d\n", p-code, *(++p)); printf ("%d RETCODE %d\n", p-code, *(p+1));
p++; p+=2;
break; break;
case SETLINE: case SETLINE:
{ {
@@ -1006,7 +1010,9 @@ static void PrintCode (Byte *code, Byte *end)
} }
break; break;
default: printf ("%d Cannot happen: code %d\n", (p++)-code, *(p-1)); break; default: printf ("%d Cannot happen: code %d\n", p-code, *p));
p+=1;
break;
} }
} }
} }

View File

@@ -2,7 +2,7 @@
** LUA - Linguagem para Usuarios de Aplicacao ** LUA - Linguagem para Usuarios de Aplicacao
** Grupo de Tecnologia em Computacao Grafica ** Grupo de Tecnologia em Computacao Grafica
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: luadebug.h,v 1.1 1995/10/17 14:12:45 roberto Exp roberto $ ** $Id: luadebug.h,v 1.4 1996/02/07 18:10:27 roberto Exp roberto $
*/ */
@@ -11,10 +11,21 @@
#include "lua.h" #include "lua.h"
lua_Object lua_stackedfunction(int level); typedef lua_Object lua_Function;
void lua_funcinfo (lua_Object func, char **filename, int *linedefined);
int lua_currentline (lua_Object func);
char *getobjname (lua_Object o, char **name);
typedef void (*lua_LHFunction) (int line);
typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
lua_Function lua_stackedfunction (int level);
void lua_funcinfo (lua_Object func, char **filename, int *linedefined);
int lua_currentline (lua_Function func);
char *lua_getobjname (lua_Object o, char **name);
lua_LHFunction lua_setlinehook (lua_LHFunction hook);
lua_CHFunction lua_setcallhook (lua_CHFunction hook);
lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
int lua_setlocal (lua_Function func, int local_number);
extern int lua_debug;
#endif #endif

View File

@@ -2,7 +2,7 @@
** Libraries to be used in LUA programs ** Libraries to be used in LUA programs
** Grupo de Tecnologia em Computacao Grafica ** Grupo de Tecnologia em Computacao Grafica
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: lualib.h,v 1.3 1994/12/13 15:59:16 roberto Exp roberto $ ** $Id: lualib.h,v 1.5 1996/01/22 17:38:57 roberto Exp roberto $
*/ */
#ifndef lualib_h #ifndef lualib_h
@@ -16,7 +16,8 @@ void mathlib_open (void);
/* auxiliar functions (private) */ /* auxiliar functions (private) */
void lua_arg_error(char *funcname); void lua_arg_error(char *funcname);
char *lua_check_string (int numArg, char *funcname); char *lua_check_string (int numArg, char *funcname);
float lua_check_number (int numArg, char *funcname); double lua_check_number (int numArg, char *funcname);
char *luaI_addchar (int c);
#endif #endif

View File

@@ -3,13 +3,27 @@
** TecCGraf - PUC-Rio ** TecCGraf - PUC-Rio
*/ */
char *rcs_mem = "$Id: mem.c,v 1.4 1995/01/13 22:11:12 roberto Exp roberto $"; char *rcs_mem = "$Id: mem.c,v 1.6 1996/01/22 14:15:13 roberto Exp roberto $";
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include "mem.h" #include "mem.h"
#include "lua.h" #include "lua.h"
#include "table.h"
static void mem_error (void)
{
Long recovered = luaI_collectgarbage(); /* try to collect garbage */
if (recovered)
lua_error("not enough memory");
else
{ /* if there is no garbage then must exit */
fprintf(stderr, "lua error: memory overflow - unable to recover\n");
exit(1);
}
}
void luaI_free (void *block) void luaI_free (void *block)
{ {
@@ -22,7 +36,7 @@ void *luaI_malloc (unsigned long size)
{ {
void *block = malloc((size_t)size); void *block = malloc((size_t)size);
if (block == NULL) if (block == NULL)
lua_error("not enough memory"); mem_error();
return block; return block;
} }
@@ -31,7 +45,7 @@ void *luaI_realloc (void *oldblock, unsigned long size)
{ {
void *block = realloc(oldblock, (size_t)size); void *block = realloc(oldblock, (size_t)size);
if (block == NULL) if (block == NULL)
lua_error("not enough memory"); mem_error();
return block; return block;
} }

View File

@@ -1,4 +1,4 @@
# $Id: makefile,v 1.15 1995/10/17 18:16:58 roberto Exp roberto $ # $Id: makefile,v 1.19 1996/02/07 18:14:38 roberto Exp roberto $
#configuration #configuration
@@ -47,14 +47,19 @@ lualib.a : $(LIBOBJS)
liblua.so.1.0 : lua.o liblua.so.1.0 : lua.o
ld -o liblua.so.1.0 $(LUAOBJS) ld -o liblua.so.1.0 $(LUAOBJS)
y.tab.c y.tab.h : lua.stx
yacc++ -d lua.stx
parser.c : lua.stx parser.c : y.tab.c
yacc++ -d lua.stx ; mv -f y.tab.c parser.c ; mv -f y.tab.h parser.h sed -e 's/yy/luaY_/g' y.tab.c > parser.c
parser.h : y.tab.h
sed -e 's/yy/luaY_/g' y.tab.h > parser.h
clear : clear :
rcsclean rcsclean
rm -f *.o rm -f *.o
rm -f parser.c parser.h rm -f parser.c parser.h y.tab.c y.tab.h
co lua.h lualib.h luadebug.h co lua.h lualib.h luadebug.h
% : RCS/%,v % : RCS/%,v
@@ -62,21 +67,20 @@ clear :
fallback.o : fallback.c mem.h fallback.h opcode.h lua.h types.h tree.h func.h fallback.o : fallback.c mem.h fallback.h opcode.h lua.h types.h tree.h func.h
func.o : func.c table.h tree.h types.h opcode.h lua.h func.h mem.h func.o : func.c luadebug.h lua.h table.h tree.h types.h opcode.h func.h mem.h
hash.o : hash.c mem.h opcode.h lua.h types.h tree.h func.h hash.h table.h hash.o : hash.c mem.h opcode.h lua.h types.h tree.h func.h hash.h table.h
inout.o : inout.c mem.h opcode.h lua.h types.h tree.h func.h hash.h inout.h \ inout.o : inout.c lex.h opcode.h lua.h types.h tree.h func.h inout.h table.h
table.h iolib.o : iolib.c lua.h luadebug.h lualib.h
iolib.o : iolib.c lua.h lualib.h luadebug.h lex.o : lex.c mem.h tree.h types.h table.h opcode.h lua.h func.h lex.h inout.h \
lex.o : lex.c mem.h tree.h types.h table.h opcode.h lua.h func.h inout.h parser.h \ luadebug.h parser.h ugly.h
ugly.h
lua.o : lua.c lua.h lualib.h lua.o : lua.c lua.h lualib.h
mathlib.o : mathlib.c lualib.h lua.h mathlib.o : mathlib.c lualib.h lua.h
mem.o : mem.c mem.h lua.h mem.o : mem.c mem.h lua.h table.h tree.h types.h opcode.h func.h
opcode.o : opcode.c mem.h opcode.h lua.h types.h tree.h func.h hash.h inout.h \ opcode.o : opcode.c luadebug.h lua.h mem.h opcode.h types.h tree.h func.h hash.h \
table.h fallback.h luadebug.h inout.h table.h fallback.h
parser.o : parser.c mem.h opcode.h lua.h types.h tree.h func.h hash.h inout.h \ parser.o : parser.c luadebug.h lua.h mem.h lex.h opcode.h types.h tree.h func.h \
table.h hash.h inout.h table.h
strlib.o : strlib.c lua.h lualib.h strlib.o : strlib.c lua.h lualib.h
table.o : table.c mem.h opcode.h lua.h types.h tree.h func.h hash.h table.h \ table.o : table.c mem.h opcode.h lua.h types.h tree.h func.h hash.h table.h \
inout.h fallback.h inout.h fallback.h luadebug.h
tree.o : tree.c mem.h lua.h tree.h types.h table.h opcode.h func.h tree.o : tree.c mem.h lua.h tree.h types.h hash.h opcode.h func.h table.h

View File

@@ -1,3 +1,5 @@
% $Id: manual.tex,v 1.10 1996/02/12 18:32:09 roberto Exp roberto $
\documentstyle[A4,11pt,bnf]{article} \documentstyle[A4,11pt,bnf]{article}
\newcommand{\rw}[1]{{\bf #1}} \newcommand{\rw}[1]{{\bf #1}}
@@ -9,13 +11,15 @@
\newcommand{\Index}[1]{#1\index{#1}} \newcommand{\Index}[1]{#1\index{#1}}
\newcommand{\IndexVerb}[1]{{\tt #1}\index{#1}} \newcommand{\IndexVerb}[1]{{\tt #1}\index{#1}}
\newcommand{\Def}[1]{{\em #1}\index{#1}} \newcommand{\Def}[1]{{\em #1}\index{#1}}
\newcommand{\Deffunc}[1]{\index{{\tt #1}}} \newcommand{\Deffunc}[1]{\index{#1}}
\newcommand{\Version}{2.3}
\makeindex
\begin{document} \begin{document}
\title{Reference Manual of the Programming Language Lua 2.2} \title{Reference Manual of the Programming Language Lua \Version}
\author{% \author{%
Roberto Ierusalimschy\quad Roberto Ierusalimschy\quad
@@ -27,20 +31,19 @@ Waldemar Celes Filho
\small\tt roberto,lhf,celes@icad.puc-rio.br \small\tt roberto,lhf,celes@icad.puc-rio.br
\vspace{2.0ex}\\ \vspace{2.0ex}\\
%MCC 08/95 --- %MCC 08/95 ---
Departamento de Inform\'atica --- PUC-Rio \tecgraf\ --- Departamento de Inform\'atica --- PUC-Rio
} }
\date{November, 1995} \date{\small \verb$Date: 1996/02/12 18:32:09 $}
\maketitle \maketitle
\begin{abstract} \begin{abstract}
\noindent \noindent
Lua is an extension programming language designed to be used Lua is an extension programming language designed to be used
as a configuration language for any program that needs one. as a configuration language for any program that needs one.
This document describes version 2.2 of the Lua programming language and the This document describes Version \Version\ of the Lua programming language and
API that allows interaction between Lua programs and its host C program. the API that allows interaction between Lua programs and its host C program.
It also presents some examples of using the main features of the system. It also presents some examples of using the main features of the system.
\end{abstract} \end{abstract}
@@ -53,9 +56,9 @@ It also presents some examples of using the main features of the system.
Lua \'e uma linguagem de extens\~ao projetada para ser usada como Lua \'e uma linguagem de extens\~ao projetada para ser usada como
linguagem de configura\c{c}\~ao em qualquer programa que precise de linguagem de configura\c{c}\~ao em qualquer programa que precise de
uma. uma.
Este documento descreve a vers\~ao 2.2 da linguagem de programa\c{c}\~ao Lua e a Este documento descreve a vers\~ao \Version\ da linguagem de
Interface de Programa\c{c}\~ao que permite a intera\c{c}\~ao entre programas Lua programa\c{c}\~ao Lua e a Interface de Programa\c{c}\~ao que permite
e o programa C hospedeiro. a intera\c{c}\~ao entre programas Lua e o programa C hospedeiro.
O documento tamb\'em apresenta alguns exemplos de uso das principais O documento tamb\'em apresenta alguns exemplos de uso das principais
ca\-racte\-r\'{\i}sticas do sistema. ca\-racte\-r\'{\i}sticas do sistema.
\end{quotation} \end{quotation}
@@ -68,9 +71,9 @@ general procedural programming features with data description
facilities. facilities.
It is supposed to be used as a configuration language for any It is supposed to be used as a configuration language for any
program that needs one. program that needs one.
Its main extensions are related to object-oriented facilities, %Its main extensions are related to object-oriented facilities,
and fallbacks, %and fallbacks,
but it has some other minor contributions. %but it has some other minor contributions.
Lua has been designed and implemented by Lua has been designed and implemented by
W.~Celes~F., L.~H.~de Figueiredo and R.~Ierusalimschy. W.~Celes~F., L.~H.~de Figueiredo and R.~Ierusalimschy.
@@ -90,7 +93,7 @@ and provided as usual with no guarantees.
The implementation described in this manual is available The implementation described in this manual is available
by anonymous ftp from by anonymous ftp from
\begin{verbatim} \begin{verbatim}
ftp.icad.puc-rio.br:/pub/lua/lua-2.2.tar.gz ftp.icad.puc-rio.br:/pub/lua/lua.tar.gz
\end{verbatim} \end{verbatim}
or by WWW (World Wide Web) from or by WWW (World Wide Web) from
\begin{verbatim} \begin{verbatim}
@@ -98,7 +101,7 @@ or by WWW (World Wide Web) from
\end{verbatim} \end{verbatim}
\section{Environment and Modules} \section{Environment and Chunks}
All statements in Lua are executed in a \Def{global environment}. All statements in Lua are executed in a \Def{global environment}.
This environment, which keeps all global variables and functions, This environment, which keeps all global variables and functions,
@@ -229,7 +232,7 @@ double hyphen (\verb'--') and run until the end of the line.
and an optional decimal exponent. and an optional decimal exponent.
Examples of valid numerical constants are: Examples of valid numerical constants are:
\begin{verbatim} \begin{verbatim}
4 4. .4 4.57e-3 .3e12 4 4.0 0.4 4.57e-3 0.3e12
\end{verbatim} \end{verbatim}
@@ -342,17 +345,14 @@ the syntax for a \Index{return statement} is:
\produc{ret}{\rwd{return} explist} \produc{ret}{\rwd{return} explist}
\end{Produc} \end{Produc}
\subsubsection{Expressions as Statements} \label{statexp} \subsubsection{Function Calls as Statements} \label{funcstat}
All expressions with possible side-effects can be Because of possible side-effects,
executed as statements. function calls can be executed as statements.
These include function calls and table constructors:
\begin{Produc} \begin{Produc}
\produc{stat}{functioncall} \produc{stat}{functioncall}
\produc{stat}{tableconstructor}
\end{Produc}% \end{Produc}%
Eventual returned values are thrown away. Eventual returned values are thrown away.
Function calls are explained in Section \ref{functioncall}; Function calls are explained in Section \ref{functioncall}.
constructors are the subject of Section \ref{tableconstructor}.
\subsubsection{Local Declarations} \label{localvar} \subsubsection{Local Declarations} \label{localvar}
\Index{Local variables} can be declared anywhere inside a block. \Index{Local variables} can be declared anywhere inside a block.
@@ -403,7 +403,8 @@ Lua offers the following \Index{relational operators}:
\begin{verbatim} \begin{verbatim}
< > <= >= ~= == < > <= >= ~= ==
\end{verbatim} \end{verbatim}
All return \nil\ as false and 1 as true. All return \nil\ as false and a value different from \nil\
(actually the number 1) as true.
Equality first compares the types of its operands. Equality first compares the types of its operands.
If they are different, the result is \nil. If they are different, the result is \nil.
@@ -544,7 +545,7 @@ the parameter list is a single new table.
Because a function can return any number of results Because a function can return any number of results
(\see{return}), (\see{return}),
the number of results must be adjusted before used. the number of results must be adjusted before used.
If the function is called as an statement (\see{statexp}), If the function is called as a statement (\see{funcstat}),
its return list is adjusted to 0. its return list is adjusted to 0.
If the function is called in a place that needs a single value If the function is called in a place that needs a single value
(syntactically denoted by the non-terminal \verb'exp1'), (syntactically denoted by the non-terminal \verb'exp1'),
@@ -556,7 +557,7 @@ no adjustment is done.
\subsection{\Index{Function Definitions}} \subsection{\Index{Function Definitions}}
Functions in Lua can be defined anywhere in the global level of a module. Functions in Lua can be defined anywhere in the global level of a chunk.
The syntax for function definition is: The syntax for function definition is:
\begin{Produc} \begin{Produc}
\produc{function}{\rwd{function} var \ter{(} \opt{parlist1} \ter{)} \produc{function}{\rwd{function} var \ter{(} \opt{parlist1} \ter{)}
@@ -572,7 +573,7 @@ into the variable \verb'var'.
Parameters act as local variables, Parameters act as local variables,
initialized with the argument values. initialized with the argument values.
\begin{Produc} \begin{Produc}
\produc{parlist1}{'name' \rep{\ter{,} name}} \produc{parlist1}{name \rep{\ter{,} name}}
\end{Produc} \end{Produc}
Results are returned using the \verb'return' statement (\see{return}). Results are returned using the \verb'return' statement (\see{return}).
@@ -599,7 +600,7 @@ end
\end{verbatim} \end{verbatim}
that is, the function gets an extra formal parameter called \verb'self'. that is, the function gets an extra formal parameter called \verb'self'.
Notice that Notice that
the variable \verb'v' must be previously initialized with a table value. the variable \verb'v' must have been previously initialized with a table value.
\subsection{Fallbacks} \label{fallback} \subsection{Fallbacks} \label{fallback}
@@ -645,6 +646,12 @@ not present in a table.
It receives as arguments the table and the index. It receives as arguments the table and the index.
Its return value is the final result of the indexing operation. Its return value is the final result of the indexing operation.
The default function returns nil. The default function returns nil.
\item[``getglobal'']\index{index getglobal}
called when Lua tries to retrieve the value of a global variable
which has a nil value (or which has not been initialized).
It receives as argument the name of the variable.
Its return value is the final result of the expression.
The default function returns nil.
\item[``gettable'']\index{gettable fallback} \item[``gettable'']\index{gettable fallback}
called when Lua tries to index a non table value. called when Lua tries to index a non table value.
It receives as arguments the non table value and the index. It receives as arguments the non table value and the index.
@@ -696,18 +703,18 @@ and then the corresponding function from the library
is terminated returning an error condition. is terminated returning an error condition.
The only argument to the error fallback function is a string describing The only argument to the error fallback function is a string describing
the error and some extra informations, the error.
like current line (when the error is at compilation) The standard I/O library redefines this fallback,
or current function (when the error is at execution). using the debug facilities (\see{debugI},
in order to print some extra informations,
like the stack of calls.
For more information about an error, For more information about an error,
the Lua program can include the compilation pragma \verb'$debug'. the Lua program can include the compilation pragma \verb'$debug'.
\index{debug pragma} \index{debug pragma}\label{pragma}
This pragma must be written in a line by itself. This pragma must be written in a line by itself.
When an error occurs in a program compiled with this option, When an error occurs in a program compiled with this option,
the error message includes extra information showing the stack of calls. the error routine is able to print also the lines where the calls
(and the error) were made.
The standard error routine only prints the error message
to \verb'stderr'.
If needed, it is possible to change the error fallback routine; If needed, it is possible to change the error fallback routine;
\see{fallback}. \see{fallback}.
@@ -747,8 +754,12 @@ executes the ``file'' {\tt stdin}.
\subsection{Converting Values between C and Lua} \label{valuesCLua} \subsection{Converting Values between C and Lua} \label{valuesCLua}
Because Lua has no static type system, Because Lua has no static type system,
all values passed between Lua and C have type \IndexVerb{lua\_Object}, all values passed between Lua and C have type
\verb'lua_Object'\Deffunc{lua_Object},
which works like an abstract type in C that can hold any Lua value. which works like an abstract type in C that can hold any Lua value.
Values of type \verb'lua_Object' have no meaning outside Lua;
for instance,
the comparisson of two \verb"lua_Object's" is of no significance.
Lua has automatic memory management, and garbage collection. Lua has automatic memory management, and garbage collection.
Because of that, a \verb'lua_Object' has a limited scope, Because of that, a \verb'lua_Object' has a limited scope,
@@ -827,12 +838,12 @@ otherwise, the function returns 0 (the null pointer).
The reverse process, that is, passing a specific C value to Lua, The reverse process, that is, passing a specific C value to Lua,
is done by using the following functions: is done by using the following functions:
\Deffunc{lua_pushnumber}\Deffunc{lua_pushstring}\Deffunc{lua_pushliteral} \Deffunc{lua_pushnumber}\Deffunc{lua_pushstring}
\Deffunc{lua_pushcfunction}\Deffunc{lua_pushusertag}\Deffunc{lua_pushuserdata} \Deffunc{lua_pushcfunction}\Deffunc{lua_pushusertag}
\Deffunc{lua_pushuserdata}
\begin{verbatim} \begin{verbatim}
void lua_pushnumber (double n); void lua_pushnumber (double n);
void lua_pushstring (char *s); void lua_pushstring (char *s);
void lua_pushliteral (char *s);
void lua_pushcfunction (lua_CFunction f); void lua_pushcfunction (lua_CFunction f);
void lua_pushusertag (void *u, int tag); void lua_pushusertag (void *u, int tag);
\end{verbatim} \end{verbatim}
@@ -845,12 +856,6 @@ convert it to a correspondent \verb'lua_Object',
and leave the result on the top of the Lua stack, and leave the result on the top of the Lua stack,
where it can be assigned to a Lua variable, where it can be assigned to a Lua variable,
passed as paramenter to a Lua function, etc (see below). \label{pushing} passed as paramenter to a Lua function, etc (see below). \label{pushing}
\verb'lua_pushliteral' is like \verb'lua_pushstring',
but also puts the string in the Lua literal table.
This avoids the string to be garbage collected,
and therefore has a better overall performance.
As a rule, when the string to be pushed is a literal,
\verb'lua_pushliteral' should be used.
User data can have different tags, User data can have different tags,
whose semantics are defined by the host program. whose semantics are defined by the host program.
@@ -875,6 +880,9 @@ one can use the function:
\begin{verbatim} \begin{verbatim}
lua_Object lua_getglobal (char *varname); lua_Object lua_getglobal (char *varname);
\end{verbatim} \end{verbatim}
As in Lua, if the value of the global is \nil,
the \verb'"getglobal"' fallback is called.
To store a value previously pushed onto the stack in a global variable, To store a value previously pushed onto the stack in a global variable,
there is the function: there is the function:
\Deffunc{lua_storeglobal} \Deffunc{lua_storeglobal}
@@ -894,15 +902,15 @@ As in Lua, if the first object is not a table,
or the index is not present in the table, or the index is not present in the table,
the correspondent fallback is called. the correspondent fallback is called.
For compatibility with previous versions of the API, %For compatibility with previous versions of the API,
the following macros are supported: %the following macros are supported:
\Deffunc{lua_getindexed}\Deffunc{lua_getfield} %\Deffunc{lua_getindexed}\Deffunc{lua_getfield}
\begin{verbatim} %\begin{verbatim}
lua_Object lua_getindexed (lua_Object table, float index); %lua_Object lua_getindexed (lua_Object table, float index);
lua_Object lua_getfield (lua_Object table, char *field); %lua_Object lua_getfield (lua_Object table, char *field);
\end{verbatim} %\end{verbatim}
The first one is used for numeric indices, %The first one is used for numeric indices,
while the second can be used for any string index. %while the second can be used for any string index.
To store a value in an index, To store a value in an index,
the program must push onto the stack the table, the index, the program must push onto the stack the table, the index,
@@ -999,7 +1007,7 @@ The first parameter is the fallback name,
and the second a CFunction to be used as the new fallback. and the second a CFunction to be used as the new fallback.
This function returns a \verb'lua_Object', This function returns a \verb'lua_Object',
which is the old fallback value, which is the old fallback value,
or nil on fail (invalid fallback name). or \nil\ on fail (invalid fallback name).
This old value can be used for chaining fallbacks. This old value can be used for chaining fallbacks.
An example of C code calling a Lua function is shown in An example of C code calling a Lua function is shown in
@@ -1036,7 +1044,8 @@ lua_Object lua_getparam (int number);
\end{verbatim} \end{verbatim}
where \verb'number' starts with 1 to get the first argument. where \verb'number' starts with 1 to get the first argument.
When called with a number larger than the actual number of arguments, When called with a number larger than the actual number of arguments,
this function returns \IndexVerb{LUA\_NOOBJECT}. this function returns
\verb'LUA_NOOBJECT'\Deffunc{LUA_NOOBJECT}.
In this way, it is possible to write functions that work with In this way, it is possible to write functions that work with
a variable number of parameters. a variable number of parameters.
@@ -1080,8 +1089,9 @@ it can be unlocked with a call to \verb'lua_unlock'.
The set of \Index{predefined functions} in Lua is small but powerful. The set of \Index{predefined functions} in Lua is small but powerful.
Most of them provide features that allows some degree of Most of them provide features that allows some degree of
\Index{reflexivity} in the language. \Index{reflexivity} in the language.
Many of these features cannot be simulated with the rest of the Some of these features cannot be simulated with the rest of the
Language nor with the standard API. Language nor with the standard Lua API.
Others are just helpful interfaces to common API functions.
The libraries, on the other hand, provide useful routines The libraries, on the other hand, provide useful routines
that are implemented directly through the standard API. that are implemented directly through the standard API.
@@ -1104,7 +1114,10 @@ declared in \verb-lualib.h-.
\subsubsection*{{\tt dofile (filename)}}\Deffunc{dofile} \subsubsection*{{\tt dofile (filename)}}\Deffunc{dofile}
This function receives a file name, This function receives a file name,
opens it and executes its contents as a Lua chunk. opens it and executes its contents as a Lua chunk.
When called without arguments,
it executes the contents of the standard input.
It returns 1 if there are no errors, \nil\ otherwise. It returns 1 if there are no errors, \nil\ otherwise.
It issues an error when called with a non string argument.
\subsubsection*{{\tt dostring (string)}}\Deffunc{dostring} \subsubsection*{{\tt dostring (string)}}\Deffunc{dostring}
This function executes a given string as a Lua chunk. This function executes a given string as a Lua chunk.
@@ -1141,6 +1154,10 @@ and its value,
or \nil\ if there are no more variables. or \nil\ if there are no more variables.
See Section \ref{exnext} for an example of the use of this function. See Section \ref{exnext} for an example of the use of this function.
\subsubsection*{{\tt tostring (e)}}\Deffunc{tostring}
This function receives an argument of any type and
converts it to a string in a reasonable format.
\subsubsection*{{\tt print (e1, e2, ...)}}\Deffunc{print} \subsubsection*{{\tt print (e1, e2, ...)}}\Deffunc{print}
This function receives any number of arguments, This function receives any number of arguments,
and prints their values in a reasonable format. and prints their values in a reasonable format.
@@ -1174,6 +1191,10 @@ This tag can be used to distinguish between user
data with different tags, data with different tags,
and between C functions and Lua functions. and between C functions and Lua functions.
\subsubsection*{{\tt assert (v)}}\Deffunc{assert}
This function issues an {\em ``assertion failed!''} error
when its argument is \nil.
\subsubsection*{{\tt error (message)}}\Deffunc{error} \subsubsection*{{\tt error (message)}}\Deffunc{error}
This function issues an error message and terminates This function issues an error message and terminates
the last called function from the library the last called function from the library
@@ -1185,6 +1206,7 @@ This function assigns the given value to a global variable.
The string \verb'name' does not need to be a syntactically valid variable name. The string \verb'name' does not need to be a syntactically valid variable name.
Therefore, this function can set global variables with strange names like Therefore, this function can set global variables with strange names like
\verb'm v 1' or \verb'34'. \verb'm v 1' or \verb'34'.
It returns the value of its second argument.
\subsubsection*{{\tt getglobal (name)}}\Deffunc{getglobal} \subsubsection*{{\tt getglobal (name)}}\Deffunc{getglobal}
This function retrieves the value of a global variable. This function retrieves the value of a global variable.
@@ -1240,11 +1262,20 @@ All other characters are left unchanged.
Returns the ascii code of the character \verb's[i]'. Returns the ascii code of the character \verb's[i]'.
If \verb'i' is absent, it is assumed to be 1. If \verb'i' is absent, it is assumed to be 1.
\subsubsection*{{\tt int2str (\{i\})}}\Deffunc{int2str} \subsubsection*{{\tt format (formatstring, e1, e2, \ldots)}}\Deffunc{format}
Receives 0 or more numbers. \label{format}
Returns a string with length equal to the number of arguments, This function returns a formated version of its variable number of arguments
wherein each character has ascii value equal following the description given in its first argument (which must be a string).
to its correspondent argument. The format string follows the same rules as the \verb'printf' family of
standard C functions.
The only differencies are that the options/modifiers
\verb'*', \verb'l', \verb'L', \verb'n', \verb'p',
and \verb'h' are not supported.
The options \verb'c', \verb'd', \verb'i', \verb'o', \verb'u',
\verb'x', \verb'X', \verb'e', \verb'E', \verb'f', and \verb'g' all
expect a number argument,
while \verb's' expects a string.
\subsection{Mathematical Functions} \label{mathlib} \subsection{Mathematical Functions} \label{mathlib}
@@ -1257,9 +1288,10 @@ The library provides the following functions:
\Deffunc{atan2}\Deffunc{ceil}\Deffunc{cos}\Deffunc{floor} \Deffunc{atan2}\Deffunc{ceil}\Deffunc{cos}\Deffunc{floor}
\Deffunc{log}\Deffunc{log10}\Deffunc{max}\Deffunc{min} \Deffunc{log}\Deffunc{log10}\Deffunc{max}\Deffunc{min}
\Deffunc{mod}\Deffunc{sin}\Deffunc{sqrt}\Deffunc{tan} \Deffunc{mod}\Deffunc{sin}\Deffunc{sqrt}\Deffunc{tan}
\Deffunc{random}\Deffunc{randomseed}
\begin{verbatim} \begin{verbatim}
abs acos asin atan atan2 ceil cos floor abs acos asin atan atan2 ceil cos floor log log10
log log10 max min mod sin sqrt tan max min mod sin sqrt tan random randomseed
\end{verbatim} \end{verbatim}
Most of them Most of them
are only interfaces to the homonymous functions in the C library, are only interfaces to the homonymous functions in the C library,
@@ -1273,6 +1305,12 @@ Both can be used with an unlimited number of arguments.
The function \verb'mod' is equivalent to the \verb'%' operator in C. The function \verb'mod' is equivalent to the \verb'%' operator in C.
The functions \verb'random' and \verb'randomseed' are interfaces to
the simple random generator functions \verb'rand' and \verb'srand',
provided by ANSI C.
The function \verb'random' returns pseudo-random numbers in the range
$[0,1)$.
\subsection{I/O Facilities} \label{libio} \subsection{I/O Facilities} \label{libio}
@@ -1299,8 +1337,8 @@ then a \Index{piped input} is open, via function \IndexVerb{popen}.
This function opens a file named \verb'filename' and sets it as the This function opens a file named \verb'filename' and sets it as the
{\em current} output file. {\em current} output file.
Notice that, if the file already exists, it is completely erased with this Notice that, if the file already exists,
operation. it will be {\em completely erased} with this operation.
When called without parameters, When called without parameters,
this function closes the current output file, this function closes the current output file,
and restores \verb'stdout' as the current output file. and restores \verb'stdout' as the current output file.
@@ -1350,6 +1388,8 @@ Particularly, the format \verb'"s1"' reads a single character.
\subsubsection*{{\tt readuntil (char)}}\Deffunc{readuntil} \subsubsection*{{\tt readuntil (char)}}\Deffunc{readuntil}
Reads the current input until the first ocurrence of the given character. Reads the current input until the first ocurrence of the given character.
When called with no parameters,
reads until the end of the current input file.
Returns the string read. Returns the string read.
The character itself is not read. The character itself is not read.
@@ -1363,7 +1403,13 @@ following characters:
\begin{description} \begin{description}
\item['s' or 'S'] to write strings; \item['s' or 'S'] to write strings;
\item['f' or 'F'] to write floats; \item['f' or 'F'] to write floats;
\item['i' or 'I'] to write integers. \item['i' or 'I'] to write integers;
\item['q' or 'Q'] to write quoted strings.
This format writes the string in a form suitable to be safely read
back by the Lua interpreter.
The string is written between double quotes,
and all double quotes, returns and backslashes in the string
are correctly escaped when written.
\end{description} \end{description}
These characters can be followed by These characters can be followed by
\begin{verbatim} \begin{verbatim}
@@ -1386,6 +1432,20 @@ This option has no meaning for strings.
When called without a format string, When called without a format string,
this function writes numbers using the \verb'%g' format this function writes numbers using the \verb'%g' format
and strings with \verb'%s'. and strings with \verb'%s'.
For better format facilities,
the function \verb'format' should be used (\see{format}).
\subsubsection*{{\tt date ([format])}}\Deffunc{date}
This function returns a string containing date and time
formatted according to the given string \verb'format',
following the same rules of the ANSI C function \verb'strftime'.
When called without arguments,
it returns a reasonable date and time representation.
This function replaces functions \verb'date' and \verb'time' from
previous Lua versions.
% \subsubsection*{{\tt debug ()}} % \subsubsection*{{\tt debug ()}}
% This function, when called, repeatedly presents a prompt \verb'lua_debug> ' % This function, when called, repeatedly presents a prompt \verb'lua_debug> '
@@ -1396,6 +1456,135 @@ and strings with \verb'%s'.
% This function then returns and the execution of the program continues. % This function then returns and the execution of the program continues.
\section{The Debuger Interface} \label{debugI}
Lua has no built in debuger facilities.
Instead, it offers a special interface,
by means of functions and {\em hooks},
which allows the construction of different
kinds of debugers, profiles, and other tools
that need ``inside'' information from the interpreter.
This interface is declared in the file \verb'luadebug.h'.
\subsection{Stack and Function Information}
The main function to get information about the interpreter stack
is
\begin{verbatim}
lua_Function lua_stackedfunction (int level);
\end{verbatim}
It returns a handle (\verb'lua_Function') to the {\em activation record\/}
of the function executing at a given level.
Level 0 is the current running function,
while level $n+1$ is the function that has called level $n$.
When called with a level greater than the stack depth,
\verb'lua_stackedfunction' returns \verb'LUA_NOOBJECT'.
The type \verb'lua_Function' is just another name
to \verb'lua_Object'.
Although, in this library,
a \verb'lua_Function' can be used wherever a \verb'lua_Object' is required,
a parameter \verb'lua_Function' accepts only a handle returned by
\verb'lua_stackedfunction'.
Three other functions produce extra information about a function:
\begin{verbatim}
void lua_funcinfo (lua_Object func, char **filename, int *linedefined);
int lua_currentline (lua_Function func);
char *lua_getobjname (lua_Object o, char **name);
\end{verbatim}
\verb'lua_funcinfo' gives the file name and the line where the
given function has been defined.
If the ``function'' is in fact the main code of a chunk,
\verb'linedefined' is 0.
If the function is a C function,
\verb'linedefined' is -1, and \verb'filename' is \verb'"(C)"'.
The function \verb'lua_currentline' gives the current line where
a given function is executing.
It only works if the function has been pre-compiled with debug
information (\see{pragma}).
When no line information is available, it returns -1.
Function \verb'lua_getobjname' tries to find a reasonable name for
a given function.
Because functions in Lua are first class values,
they do not have a fixed name.
Some functions may be the value of many global variables,
while others may be stored only in a table field.
Function \verb'lua_getobjname' first checks whether the given
function is a fallback.
If so, it returns the string \verb'"fallback"',
and \verb'name' is set to point to the fallback name.
Otherwise, if the given function is the value of a global variable,
\verb'lua_getobjname' returns the string \verb'"global"',
while \verb'name' points to the variable name.
If the given function is neither a fallback nor a global variable,
\verb'lua_getobjname' returns the empty string,
and \verb'name' is set to \verb'NULL'.
\subsection{Manipulating Local Variables}
The following functions allow the manipulation of the
local variables of a given activation record.
They only work if the function has been pre-compiled with debug
information (\see{pragma}).
\begin{verbatim}
lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
int lua_setlocal (lua_Function func, int local_number);
\end{verbatim}
The first one returns the value of a local variable,
and sets \verb'name' to point to the variable name.
\verb'local_number' is an index for local variables.
The first parameter has index 1, and so on, until the
last active local variable.
When called with a \verb'local_number' greater than the
number of active local variables,
or if the activation record has no debug information,
\verb'lua_getlocal' returns \verb'LUA_NOOBJECT'.
The function \verb'lua_setlocal' sets the local variable
\verb'local_number' to the value previously pushed on the stack
(\see{valuesCLua}).
If the function succeeds it returns 1.
If \verb'local_number' is greater than the number
of active local variables,
or if the activation record has no debug information,
this function fails and returns 0.
\subsection{Hooks}
The Lua interpreter offers two hooks for debug purposes:
\begin{verbatim}
typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
typedef void (*lua_LHFunction) (int line);
\end{verbatim}
The first one is called whenever the interpreter enters or leaves a
function.
When entering a function,
its parameters are a handle to the function activation record,
plus the file and the line where the function is defined (the same
information which is provided by \verb'lua_funcinfo');
when leaving a function, \verb'func' is \verb'LUA_NOOBJECT',
\verb'file' is \verb'"(return)"', and \verb'line' is 0.
The other hook is called every time the interpreter changes
the line of code it is executing.
Its only parameter is the line number
(the same information which is provided by the call
\verb'lua_currentline(lua_stackedfunction(0))').
This second hook is only called if the active function
has been pre-compiled with debug information (\see{pragma}).
To set these hooks, there are the functions:
\begin{verbatim}
lua_LHFunction lua_setlinehook (lua_LHFunction hook);
lua_CHFunction lua_setcallhook (lua_CHFunction hook);
\end{verbatim}
Both return the previous hook.
\section{Some Examples} \section{Some Examples}
This section gives examples showing some features of Lua. This section gives examples showing some features of Lua.
@@ -1403,6 +1592,50 @@ It does not intend to cover the whole language,
but only to illustrate some interesting uses of the system. but only to illustrate some interesting uses of the system.
\subsection{\Index{Data Structures}}
Tables are a strong unifying data constructor.
They directly implement a multitude of data types,
like ordinary arrays, records, sets, bags, and lists.
Arrays need no explanations.
In Lua, it is conventional to start indices from 1,
but this is only a convention.
Arrays can be indexed by 0, negative numbers, or any other value (but \nil).
Records are also trivially implemented by the syntactic sugar
\verb'a.x'.
The best way to implement a set is to store
its elements as indices of a table.
The statement \verb's = {}' creates an empty set \verb's'.
The statement \verb's[x] = 1' inserts the value of \verb'x' into
the set \verb's'.
The expression \verb's[x]' is true if and only if
\verb'x' belongs to \verb's'.
Finally, the statement \verb's[x] = nil' erases \verb'x' from \verb's'.
Bags can be implemented similarly to sets,
but using the value associated to an element as its counter.
So, to insert an element,
the following code is enough:
\begin{verbatim}
if s[x] then s[x] = s[x]+1
else s[x] = 1 end
\end{verbatim}
and to remove an element:
\begin{verbatim}
if s[x] then s[x] = s[x]-1 end
if s[x] == 0 then s[x] = nil end
\end{verbatim}
Lisp-like lists also have an easy implementation.
The ``cons'' of two elements \verb'x' and \verb'y' can be
created with the code \verb'l = {car=x, cdr=y}'.
The expression \verb'l.car' extracts the header,
while \verb'l.cdr' extracts the tail.
An alternative way is to create the list directly with \verb'l={x,y}',
and then to extract the header with \verb'l[1]' and
the tail with \verb'l[2]'.
\subsection{The Functions {\tt next} and {\tt nextvar}} \label{exnext} \subsection{The Functions {\tt next} and {\tt nextvar}} \label{exnext}
\Deffunc{next}\Deffunc{nextvar} \Deffunc{next}\Deffunc{nextvar}
This example shows how to use the function \verb'next' to iterate This example shows how to use the function \verb'next' to iterate
@@ -1410,7 +1643,7 @@ over the fields of a table.
Function \Def{clone} receives any table and returns a clone of it. Function \Def{clone} receives any table and returns a clone of it.
\begin{verbatim} \begin{verbatim}
function clone (t) -- t is a table function clone (t) -- t is a table
local new_t = {} -- creates a new table local new_t = {} -- create a new table
local i, v = next(t, nil) -- i is an index of t, v = t[i] local i, v = next(t, nil) -- i is an index of t, v = t[i]
while i do while i do
new_t[i] = v new_t[i] = v
@@ -1475,7 +1708,7 @@ To store a single value with a name,
the following code is enough: the following code is enough:
\begin{verbatim} \begin{verbatim}
function store (name, value) function store (name, value)
write('\n' .. name .. '=') write(format('\n%s =', name))
write_value(value) write_value(value)
end end
\end{verbatim} \end{verbatim}
@@ -1484,7 +1717,7 @@ function write_value (value)
local t = type(value) local t = type(value)
if t == 'nil' then write('nil') if t == 'nil' then write('nil')
elseif t == 'number' then write(value) elseif t == 'number' then write(value)
elseif t == 'string' then write('[[' .. value .. ']]') elseif t == 'string' then write(value, 'q')
end end
end end
\end{verbatim} \end{verbatim}
@@ -1501,7 +1734,7 @@ function write_value (value)
local t = type(value) local t = type(value)
if t == 'nil' then write('nil') if t == 'nil' then write('nil')
elseif t == 'number' then write(value) elseif t == 'number' then write(value)
elseif t == 'string' then write('"' .. value .. '"') elseif t == 'string' then write(value, 'q')
elseif t == 'table' then write_record(value) elseif t == 'table' then write_record(value)
end end
end end
@@ -1604,6 +1837,112 @@ This code must be registered with:
Notice how the string \verb'"parent"' is kept Notice how the string \verb'"parent"' is kept
locked in Lua for optimal performance. locked in Lua for optimal performance.
\subsection{\Index{Programming with Classes}}
There are many different ways to do object-oriented programming in Lua.
This section presents one possible way to
implement classes,
using the inheritance mechanism presented above.
As one could expect, a good way to represent a class is
as a table.
This table will contain all instance methods of the class,
plus eventual default values for instance variables.
An instance of a class has its \verb'parent' field pointing to
the class,
and so it ``inherits'' all methods.
For instance, a class \verb'Point' can be described as in
Figure~\ref{Point}.
Function \verb'create' helps the creation of new points,
adding the parent field.
Function \verb'move' is an example of an instance method.
\begin{figure}
\Line
\begin{verbatim}
Point = {x = 0, y = 0}
function Point:create (o)
o.parent = self
return o
end
function Point:move (p)
self.x = self.x + p.x
self.y = self.y + p.y
end
...
--
-- creating points
--
p1 = Point:create{x = 10, y = 20}
p2 = Point:create{x = 10} -- y will be inherited until it is set
--
-- example of a method invocation
--
p1:move(p2)
\end{verbatim}
\caption{A Class Point.\label{Point}}
\Line
\end{figure}
Finally, a subclass can be created as a new table,
with the \verb'parent' field pointing to its superclass.
It is interesting to notice how the use of \verb'self' in
method \verb'create' allows this method to work properly even
when inherited by a subclass.
As usual, a subclass may overwrite any inherited method with
its own version.
\subsection{\Index{Modules}}
Here we explain one possible way to simulate modules in Lua.
The main idea is to use a table to store the module functions.
A module should be written as a separate chunk, starting with:
\begin{verbatim}
if modulename then return end -- avoid loading twice the same module
modulename = {} -- create a table to represent the module
\end{verbatim}
After that, functions can be directly defined with the syntax
\begin{verbatim}
function modulename.foo (...)
...
end
\end{verbatim}
Any code that needs this module has only to execute
\verb'dofile("filename")', where \verb'filename' is the file
where the module is written.
After this, any function can be called with
\begin{verbatim}
modulename.foo(...)
\end{verbatim}
If a module function is going to be used many times,
the program can give a local name to it.
Because functions are values, it is enough to write
\begin{verbatim}
localname = modulename.foo
\end{verbatim}
Finally, a module may be {\em opened},
giving direct access to all its functions,
as shown in the code in Figure~\ref{openmod}.
\begin{figure}
\Line
\begin{verbatim}
function open (mod)
local n, f = next(mod, nil)
while n do
setglobal(n, f)
n, f = next(mod, n)
end
end
\end{verbatim}
\caption{Opening a module.\label{openmod}}
\Line
\end{figure}
\subsection{A CFunction} \label{exCFunction}\index{functions in C} \subsection{A CFunction} \label{exCFunction}\index{functions in C}
A CFunction to compute the maximum of a variable number of arguments A CFunction to compute the maximum of a variable number of arguments
is shown in Figure~\ref{Cmax}. is shown in Figure~\ref{Cmax}.
@@ -1664,11 +2003,11 @@ void remove_blanks (char *s)
\section*{Acknowledgments} \section*{Acknowledgments}
The authors would like to thank CENPES/PETROBR\'AS which, The authors would like to thank CENPES/PETROBR\'AS which,
jointly with TeCGraf, used extensively early versions of jointly with \tecgraf, used extensively early versions of
this system and gave valuable comments. this system and gave valuable comments.
The authors would also like to thank Carlos Henrique Levy, The authors would also like to thank Carlos Henrique Levy,
who found the name of the game% who found the name of the game.
\footnote{BTW, Lua means {\em moon} in Portuguese.}. Lua means {\em moon} in Portuguese.
@@ -1681,10 +2020,24 @@ the previous public versions of Lua,
some differences had to be introduced. some differences had to be introduced.
Here is a list of all these differences. Here is a list of all these differences.
\subsection*{Incompatibilities with \Index{version 2.2}}
\begin{itemize}
\item
Functions \verb'date' and \verb'time' (from \verb'iolib')
have been superseded by the new version of function \verb'date'.
\item
Function \verb'int2str' (from \verb'strlib') has been superseded by new
function \verb'format', with parameter \verb'"%c"'.
\item
API function \verb'lua_pushliteral' now is just a macro to
\verb'lua_pushstring'.
Programmers are encouraged not to use this macro.
\end{itemize}
\subsection*{Incompatibilities with \Index{version 2.1}} \subsection*{Incompatibilities with \Index{version 2.1}}
\begin{itemize} \begin{itemize}
\item \item
The function {\tt type} now returns the string {\tt function} The function \verb'type' now returns the string \verb'"function"'
both for C and Lua functions. both for C and Lua functions.
Because Lua functions and C functions are compatible, Because Lua functions and C functions are compatible,
this behavior is usually more useful. this behavior is usually more useful.
@@ -1738,4 +2091,13 @@ Special care should be taken with macros like
\verb'lua_getindexed' and \verb'lua_getfield'. \verb'lua_getindexed' and \verb'lua_getfield'.
\end{itemize} \end{itemize}
\newcommand{\indexentry}[2]{\item {#1} #2}
%\catcode`\_=12
\begin{theindex}
\input{manual.id}
\end{theindex}
\pagebreak
\tableofcontents
\end{document} \end{document}

View File

@@ -3,9 +3,9 @@
** Mathematics library to LUA ** Mathematics library to LUA
*/ */
char *rcs_mathlib="$Id: mathlib.c,v 1.12 1995/10/09 12:48:38 roberto Exp roberto $"; char *rcs_mathlib="$Id: mathlib.c,v 1.13 1995/11/10 17:54:31 roberto Exp roberto $";
#include <stdio.h> /* NULL */ #include <stdlib.h>
#include <math.h> #include <math.h>
#include "lualib.h" #include "lualib.h"
@@ -184,6 +184,18 @@ static void math_rad (void)
lua_pushnumber (d/180.*PI); lua_pushnumber (d/180.*PI);
} }
static void math_random (void)
{
lua_pushnumber((double)(rand()%RAND_MAX) / (double)RAND_MAX);
}
static void math_randomseed (void)
{
srand(lua_check_number(1, "randomseed"));
}
/* /*
** Open math library ** Open math library
*/ */
@@ -208,5 +220,8 @@ void mathlib_open (void)
lua_register ("exp", math_exp); lua_register ("exp", math_exp);
lua_register ("deg", math_deg); lua_register ("deg", math_deg);
lua_register ("rad", math_rad); lua_register ("rad", math_rad);
lua_register ("random", math_random);
lua_register ("randomseed", math_randomseed);
old_pow = lua_lockobject(lua_setfallback("arith", math_pow)); old_pow = lua_lockobject(lua_setfallback("arith", math_pow));
} }

162
opcode.c
View File

@@ -3,7 +3,7 @@
** TecCGraf - PUC-Rio ** TecCGraf - PUC-Rio
*/ */
char *rcs_opcode="$Id: opcode.c,v 3.49 1995/11/10 14:12:02 roberto Exp roberto $"; char *rcs_opcode="$Id: opcode.c,v 3.56 1996/02/08 17:03:20 roberto Exp roberto $";
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h> #include <stdlib.h>
@@ -53,6 +53,11 @@ static int CnResults = 0; /* when Lua calls C, has the number of parameters; */
static jmp_buf *errorJmp = NULL; /* current error recover point */ static jmp_buf *errorJmp = NULL; /* current error recover point */
/* Hooks */
static lua_LHFunction line_hook = NULL;
static lua_CHFunction call_hook = NULL;
static StkId lua_execute (Byte *pc, StkId base); static StkId lua_execute (Byte *pc, StkId base);
static void do_call (StkId base, int nResults); static void do_call (StkId base, int nResults);
@@ -64,6 +69,23 @@ Object *luaI_Address (lua_Object o)
} }
/*
** Functions to change hook functions.
*/
lua_LHFunction lua_setlinehook (lua_LHFunction hook)
{
lua_LHFunction temp = line_hook;
line_hook = hook;
return temp;
}
lua_CHFunction lua_setcallhook (lua_CHFunction hook)
{
lua_CHFunction temp = call_hook;
call_hook = hook;
return temp;
}
/* /*
** Init stack ** Init stack
@@ -192,6 +214,48 @@ static void open_stack (int nelems)
} }
/*
** call Line hook
*/
static void lineHook (int line)
{
StkId oldBase = CBase;
int oldCnResults = CnResults;
StkId old_top = CBase = top-stack;
CnResults = 0;
(*line_hook)(line);
top = stack+old_top;
CnResults = oldCnResults;
CBase = oldBase;
}
/*
** Call hook
** The function being called is in [stack+base-1]
*/
static void callHook (StkId base, lua_Type type, int isreturn)
{
StkId oldBase = CBase;
int oldCnResults = CnResults;
StkId old_top = CBase = top-stack;
CnResults = 0;
if (isreturn)
(*call_hook)(LUA_NOOBJECT, "(return)", 0);
else
{
Object *f = stack+base-1;
if (type == LUA_T_MARK)
(*call_hook)(Ref(f), f->value.tf->fileName, f->value.tf->lineDefined);
else
(*call_hook)(Ref(f), "(C)", -1);
}
top = stack+old_top;
CnResults = oldCnResults;
CBase = oldBase;
}
/* /*
** Call a C function. CBase will point to the top of the stack, ** Call a C function. CBase will point to the top of the stack,
** and CnResults is the number of parameters. Returns an index ** and CnResults is the number of parameters. Returns an index
@@ -204,8 +268,15 @@ static StkId callC (lua_CFunction func, StkId base)
StkId firstResult; StkId firstResult;
CnResults = (top-stack) - base; CnResults = (top-stack) - base;
/* incorporate parameters on the stack */ /* incorporate parameters on the stack */
CBase = base+CnResults; CBase = base+CnResults; /* == top-stack */
(*func)(); if (call_hook)
{
callHook (base, LUA_T_CMARK, 0);
(*func)();
callHook (base, LUA_T_CMARK, 1);
}
else
(*func)();
firstResult = CBase; firstResult = CBase;
CBase = oldBase; CBase = oldBase;
CnResults = oldCnResults; CnResults = oldCnResults;
@@ -303,6 +374,18 @@ static void storesubscript (void)
} }
static void getglobal (Word n)
{
*top = lua_table[n].object;
incr_top;
if (tag(top-1) == LUA_T_NIL)
{ /* must call getglobal fallback */
tag(top-1) = LUA_T_STRING;
tsvalue(top-1) = lua_table[n].varname;
callFB(FB_GETGLOBAL);
}
}
/* /*
** Traverse all objects on stack ** Traverse all objects on stack
*/ */
@@ -340,7 +423,7 @@ void lua_error (char *s)
} }
lua_Object lua_stackedfunction (int level) lua_Function lua_stackedfunction (int level)
{ {
Object *p = top; Object *p = top;
while (--p >= stack) while (--p >= stack)
@@ -351,13 +434,45 @@ lua_Object lua_stackedfunction (int level)
} }
int lua_currentline (lua_Object func) int lua_currentline (lua_Function func)
{ {
Object *f = Address(func); Object *f = Address(func);
return (f+1 < top && (f+1)->tag == LUA_T_LINE) ? (f+1)->value.i : -1; return (f+1 < top && (f+1)->tag == LUA_T_LINE) ? (f+1)->value.i : -1;
} }
lua_Object lua_getlocal (lua_Function func, int local_number, char **name)
{
Object *f = luaI_Address(func);
*name = luaI_getlocalname(f->value.tf, local_number, lua_currentline(func));
if (*name)
{
/* if "*name", there must be a LUA_T_LINE */
/* therefore, f+2 points to function base */
return Ref((f+2)+(local_number-1));
}
else
return LUA_NOOBJECT;
}
int lua_setlocal (lua_Function func, int local_number)
{
Object *f = Address(func);
char *name = luaI_getlocalname(f->value.tf, local_number, lua_currentline(func));
adjustC(1);
--top;
if (name)
{
/* if "name", there must be a LUA_T_LINE */
/* therefore, f+2 points to function base */
*((f+2)+(local_number-1)) = *top;
return 1;
}
else
return 0;
}
/* /*
** Execute a protected call. Assumes that function is at CBase and ** Execute a protected call. Assumes that function is at CBase and
** parameters are on top of it. Leave nResults on the stack. ** parameters are on top of it. Leave nResults on the stack.
@@ -397,9 +512,8 @@ static int do_protectedmain (void)
adjustC(1); /* one slot for the pseudo-function */ adjustC(1); /* one slot for the pseudo-function */
stack[CBase].tag = LUA_T_FUNCTION; stack[CBase].tag = LUA_T_FUNCTION;
stack[CBase].value.tf = &tf; stack[CBase].value.tf = &tf;
tf.lineDefined = 0; luaI_initTFunc(&tf);
tf.fileName = lua_parsedfile; tf.fileName = lua_parsedfile;
tf.code = NULL;
if (setjmp(myErrorJmp) == 0) if (setjmp(myErrorJmp) == 0)
{ {
lua_parse(&tf); lua_parse(&tf);
@@ -449,12 +563,8 @@ int lua_call (char *funcname)
int lua_dofile (char *filename) int lua_dofile (char *filename)
{ {
int status; int status;
char *message = lua_openfile (filename); if (lua_openfile(filename))
if (message)
{
lua_message(message);
return 1; return 1;
}
status = do_protectedmain(); status = do_protectedmain();
lua_closefile(); lua_closefile();
return status; return status;
@@ -637,10 +747,8 @@ int lua_lock (void)
*/ */
lua_Object lua_getglobal (char *name) lua_Object lua_getglobal (char *name)
{ {
Word n = luaI_findsymbolbyname(name);
adjustC(0); adjustC(0);
*top = s_object(n); getglobal(luaI_findsymbolbyname(name));
incr_top;
CBase++; /* incorporate object in the stack */ CBase++; /* incorporate object in the stack */
return Ref(top-1); return Ref(top-1);
} }
@@ -683,16 +791,6 @@ void lua_pushstring (char *s)
incr_top; incr_top;
} }
/*
** Push an object (tag=string) on stack and register it on the constant table.
*/
void lua_pushliteral (char *s)
{
tsvalue(top) = lua_constant[luaI_findconstantbyname(s)];
tag(top) = LUA_T_STRING;
incr_top;
}
/* /*
** Push an object (tag=cfunction) to stack. ** Push an object (tag=cfunction) to stack.
*/ */
@@ -783,6 +881,8 @@ static void comparison (lua_Type tag_less, lua_Type tag_equal,
*/ */
static StkId lua_execute (Byte *pc, StkId base) static StkId lua_execute (Byte *pc, StkId base)
{ {
if (call_hook)
callHook (base, LUA_T_MARK, 0);
while (1) while (1)
{ {
OpCode opcode; OpCode opcode;
@@ -849,8 +949,7 @@ static StkId lua_execute (Byte *pc, StkId base)
{ {
CodeWord code; CodeWord code;
get_word(code,pc); get_word(code,pc);
*top = s_object(code.w); getglobal(code.w);
incr_top;
} }
break; break;
@@ -1143,10 +1242,10 @@ static StkId lua_execute (Byte *pc, StkId base)
break; break;
case RETCODE0: case RETCODE0:
return base;
case RETCODE: case RETCODE:
return base+*pc; if (call_hook)
callHook (base, LUA_T_MARK, 1);
return (base + ((opcode==RETCODE0) ? 0 : *pc));
case SETLINE: case SETLINE:
{ {
@@ -1160,6 +1259,8 @@ static StkId lua_execute (Byte *pc, StkId base)
(stack+base-1)->tag = LUA_T_LINE; (stack+base-1)->tag = LUA_T_LINE;
} }
(stack+base-1)->value.i = code.w; (stack+base-1)->value.i = code.w;
if (line_hook)
lineHook (code.w);
break; break;
} }
@@ -1169,4 +1270,3 @@ static StkId lua_execute (Byte *pc, StkId base)
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: opcode.h,v 3.13 1995/10/17 11:58:41 roberto Exp roberto $ ** $Id: opcode.h,v 3.16 1996/01/26 18:03:19 roberto Exp roberto $
*/ */
#ifndef opcode_h #ifndef opcode_h
@@ -11,9 +11,6 @@
#include "tree.h" #include "tree.h"
#include "func.h" #include "func.h"
#ifndef real
#define real float
#endif
#define FIELDS_PER_FLUSH 40 #define FIELDS_PER_FLUSH 40
@@ -74,12 +71,9 @@ typedef enum
#define MULT_RET 255 #define MULT_RET 255
typedef void (*Cfunction) (void);
typedef int (*Input) (void);
typedef union typedef union
{ {
Cfunction f; lua_CFunction f;
real n; real n;
TaggedString *ts; TaggedString *ts;
TFunc *tf; TFunc *tf;
@@ -94,10 +88,6 @@ typedef struct Object
Value value; Value value;
} Object; } Object;
typedef struct
{
Object object;
} Symbol;
/* Macros to access structure members */ /* Macros to access structure members */
#define tag(o) ((o)->tag) #define tag(o) ((o)->tag)
@@ -144,9 +134,6 @@ typedef union
/* Exported functions */ /* Exported functions */
char *lua_strdup (char *l); char *lua_strdup (char *l);
void lua_setinput (Input fn); /* from "lex.c" module */
char *lua_lasttext (void); /* from "lex.c" module */
int yylex (void); /* from "lex.c" module */
void lua_parse (TFunc *tf); /* from "lua.stx" module */ void lua_parse (TFunc *tf); /* from "lua.stx" module */
void luaI_codedebugline (int line); /* from "lua.stx" module */ void luaI_codedebugline (int line); /* from "lua.stx" module */
void lua_travstack (int (*fn)(Object *)); void lua_travstack (int (*fn)(Object *));

160
strlib.c
View File

@@ -3,7 +3,7 @@
** String library to LUA ** String library to LUA
*/ */
char *rcs_strlib="$Id: strlib.c,v 1.13 1995/10/09 12:49:21 roberto Exp roberto $"; char *rcs_strlib="$Id: strlib.c,v 1.18 1996/02/12 18:32:40 roberto Exp $";
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@@ -29,21 +29,46 @@ char *lua_check_string (int numArg, char *funcname)
return lua_getstring(o); return lua_getstring(o);
} }
float lua_check_number (int numArg, char *funcname) double lua_check_number (int numArg, char *funcname)
{ {
lua_Object o = lua_getparam(numArg); lua_Object o = lua_getparam(numArg);
if (!lua_isnumber(o)) if (lua_isnumber(o))
lua_arg_error(funcname); return lua_getnumber(o);
return lua_getnumber(o); else if (lua_isstring(o))
{
float t;
char c;
if (sscanf(lua_getstring(o), "%f %c",&t, &c) == 1)
return t;
}
lua_arg_error(funcname);
return 0; /* to avoid warnings */
} }
static char *newstring (char *s) char *luaI_addchar (int c)
{ {
char *ns = (char *)malloc(strlen(s)+1); static char *buff = NULL;
if (ns == 0) static int max = 0;
lua_error("not enough memory for new string"); static int n = 0;
strcpy(ns, s); if (n >= max)
return ns; {
if (max == 0)
{
max = 100;
buff = (char *)malloc(max);
}
else
{
max *= 2;
buff = (char *)realloc(buff, max);
}
if (buff == NULL)
lua_error("memory overflow");
}
buff[n++] = c;
if (c == 0)
n = 0; /* prepare for next string */
return buff;
} }
@@ -100,30 +125,13 @@ static void str_sub (void)
lua_pushliteral(""); lua_pushliteral("");
else else
{ {
char temp = s[end]; luaI_addchar(0);
s[end] = 0; while (start <= end)
lua_pushstring (&s[start-1]); luaI_addchar(s[start++ - 1]);
s[end] = temp; lua_pushstring (luaI_addchar(0));
} }
} }
/*
** Convert a string according to given function.
*/
typedef int (*strfunc)(int s);
static void str_apply (strfunc f, char *funcname)
{
char *s, *c;
c = s = newstring(lua_check_string(1, funcname));
while (*c != 0)
{
*c = f(*c);
c++;
}
lua_pushstring(s);
free(s);
}
/* /*
** Convert a string to lower case. ** Convert a string to lower case.
** LUA interface: ** LUA interface:
@@ -131,7 +139,11 @@ static void str_apply (strfunc f, char *funcname)
*/ */
static void str_lower (void) static void str_lower (void)
{ {
str_apply(tolower, "strlower"); char *s = lua_check_string(1, "strlower");
luaI_addchar(0);
while (*s)
luaI_addchar(tolower(*s++));
lua_pushstring(luaI_addchar(0));
} }
@@ -142,7 +154,11 @@ static void str_lower (void)
*/ */
static void str_upper (void) static void str_upper (void)
{ {
str_apply(toupper, "strupper"); char *s = lua_check_string(1, "strupper");
luaI_addchar(0);
while (*s)
luaI_addchar(toupper(*s++));
lua_pushstring(luaI_addchar(0));
} }
/* /*
@@ -159,24 +175,72 @@ static void str_ascii (void)
lua_pushnumber(s[pos]); lua_pushnumber(s[pos]);
} }
/*
** converts one or more integers to chars in a string #define MAX_CONVERTION 2000
*/ #define MAX_FORMAT 50
#define maxparams 50
static void str_int2str (void) static void str_format (void)
{ {
char s[maxparams+1]; int arg = 1;
int i = 0; char *strfrmt = lua_check_string(arg++, "format");
while (lua_getparam(++i) != LUA_NOOBJECT) luaI_addchar(0); /* initialize */
while (*strfrmt)
{ {
if (i > maxparams) if (*strfrmt != '%')
lua_error("too many parameters to function `int2str'"); luaI_addchar(*strfrmt++);
s[i-1] = (int)lua_check_number(i, "int2str"); else if (*++strfrmt == '%')
luaI_addchar(*strfrmt++); /* %% */
else
{ /* format item */
char form[MAX_FORMAT]; /* store the format ('%...') */
char buff[MAX_CONVERTION]; /* store the formated value */
int size = 0;
int i = 0;
form[i++] = '%';
form[i] = *strfrmt++;
while (!isalpha(form[i]))
{
if (isdigit(form[i]))
{
size = size*10 + form[i]-'0';
if (size >= MAX_CONVERTION)
lua_error("format size/precision too long in function `format'");
}
else if (form[i] == '.')
size = 0; /* re-start */
if (++i >= MAX_FORMAT)
lua_error("bad format in function `format'");
form[i] = *strfrmt++;
}
form[i+1] = 0; /* ends string */
switch (form[i])
{
case 's':
{
char *s = lua_check_string(arg++, "format");
if (strlen(s) >= MAX_CONVERTION)
lua_error("string argument too long in function `format'");
sprintf(buff, form, s);
break;
}
case 'c': case 'd': case 'i': case 'o':
case 'u': case 'x': case 'X':
sprintf(buff, form, (int)lua_check_number(arg++, "format"));
break;
case 'e': case 'E': case 'f': case 'g':
sprintf(buff, form, lua_check_number(arg++, "format"));
break;
default: /* also treat cases 'pnLlh' */
lua_error("invalid format option in function `format'");
}
for (i=0; buff[i]; i++) /* move formated value to result */
luaI_addchar(buff[i]);
}
} }
s[i-1] = 0; lua_pushstring(luaI_addchar(0)); /* push the result */
lua_pushstring(s);
} }
/* /*
** Open string library ** Open string library
*/ */
@@ -188,5 +252,5 @@ void strlib_open (void)
lua_register ("strlower", str_lower); lua_register ("strlower", str_lower);
lua_register ("strupper", str_upper); lua_register ("strupper", str_upper);
lua_register ("ascii", str_ascii); lua_register ("ascii", str_ascii);
lua_register ("int2str", str_int2str); lua_register ("format", str_format);
} }

134
table.c
View File

@@ -3,9 +3,7 @@
** Module to control static tables ** Module to control static tables
*/ */
char *rcs_table="$Id: table.c,v 2.37 1995/10/26 14:21:56 roberto Exp roberto $"; char *rcs_table="$Id: table.c,v 2.46 1996/02/14 13:35:51 roberto Exp roberto $";
/*#include <string.h>*/
#include "mem.h" #include "mem.h"
#include "opcode.h" #include "opcode.h"
@@ -33,46 +31,48 @@ static Long lua_maxconstant = 0;
#define MIN_GARBAGE_BLOCK (GARBAGE_BLOCK/2) #define MIN_GARBAGE_BLOCK (GARBAGE_BLOCK/2)
static void lua_nextvar (void); static void lua_nextvar (void);
static void setglobal (void);
static void getglobal (void);
/* /*
** Initialise symbol table with internal functions ** Initialise symbol table with internal functions
*/ */
static void lua_initsymbol (void) static struct {
char *name;
lua_CFunction func;
} int_funcs[] = {
{"nextvar", lua_nextvar},
{"error", luaI_error},
{"tonumber", lua_obj2number},
{"setfallback", luaI_setfallback},
{"next", lua_next},
{"dofile", lua_internaldofile},
{"setglobal", luaI_setglobal},
{"getglobal", luaI_getglobal},
{"type", luaI_type},
{"tostring", luaI_tostring},
{"print", luaI_print},
{"dostring", lua_internaldostring},
{"assert", luaI_assert}
};
#define INTFUNCSIZE (sizeof(int_funcs)/sizeof(int_funcs[0]))
void luaI_initsymbol (void)
{ {
Word n; int i;
lua_maxsymbol = BUFFER_BLOCK; lua_maxsymbol = BUFFER_BLOCK;
lua_table = newvector(lua_maxsymbol, Symbol); lua_table = newvector(lua_maxsymbol, Symbol);
n = luaI_findsymbolbyname("next"); for (i=0; i<INTFUNCSIZE; i++)
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_next; {
n = luaI_findsymbolbyname("dofile"); Word n = luaI_findsymbolbyname(int_funcs[i].name);
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_internaldofile; s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = int_funcs[i].func;
n = luaI_findsymbolbyname("setglobal"); }
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = setglobal;
n = luaI_findsymbolbyname("getglobal");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = getglobal;
n = luaI_findsymbolbyname("nextvar");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_nextvar;
n = luaI_findsymbolbyname("type");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = luaI_type;
n = luaI_findsymbolbyname("tonumber");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_obj2number;
n = luaI_findsymbolbyname("print");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_print;
n = luaI_findsymbolbyname("dostring");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = lua_internaldostring;
n = luaI_findsymbolbyname("setfallback");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = luaI_setfallback;
n = luaI_findsymbolbyname("error");
s_tag(n) = LUA_T_CFUNCTION; s_fvalue(n) = luaI_error;
} }
/* /*
** Initialise constant table with pre-defined constants ** Initialise constant table with pre-defined constants
*/ */
void lua_initconstant (void) void luaI_initconstant (void)
{ {
lua_maxconstant = BUFFER_BLOCK; lua_maxconstant = BUFFER_BLOCK;
lua_constant = newvector(lua_maxconstant, TaggedString *); lua_constant = newvector(lua_maxconstant, TaggedString *);
@@ -83,10 +83,8 @@ void lua_initconstant (void)
** Given a name, search it at symbol table and return its index. If not ** Given a name, search it at symbol table and return its index. If not
** found, allocate it. ** found, allocate it.
*/ */
Word luaI_findsymbol (TreeNode *t) Word luaI_findsymbol (TaggedString *t)
{ {
if (lua_table == NULL)
lua_initsymbol();
if (t->varindex == NOT_USED) if (t->varindex == NOT_USED)
{ {
if (lua_ntable == lua_maxsymbol) if (lua_ntable == lua_maxsymbol)
@@ -99,8 +97,11 @@ Word luaI_findsymbol (TreeNode *t)
lua_table = growvector(lua_table, lua_maxsymbol, Symbol); lua_table = growvector(lua_table, lua_maxsymbol, Symbol);
} }
t->varindex = lua_ntable; t->varindex = lua_ntable;
lua_table[lua_ntable].varname = t;
s_tag(lua_ntable) = LUA_T_NIL; s_tag(lua_ntable) = LUA_T_NIL;
lua_ntable++; lua_ntable++;
if (!t->marked)
t->marked = 2; /* avoid GC */
} }
return t->varindex; return t->varindex;
} }
@@ -108,7 +109,7 @@ Word luaI_findsymbol (TreeNode *t)
Word luaI_findsymbolbyname (char *name) Word luaI_findsymbolbyname (char *name)
{ {
return luaI_findsymbol(lua_constcreate(name)); return luaI_findsymbol(lua_createstring(name));
} }
@@ -116,10 +117,8 @@ Word luaI_findsymbolbyname (char *name)
** Given a tree node, check it is has a correspondent constant index. If not, ** Given a tree node, check it is has a correspondent constant index. If not,
** allocate it. ** allocate it.
*/ */
Word luaI_findconstant (TreeNode *t) Word luaI_findconstant (TaggedString *t)
{ {
if (lua_constant == NULL)
lua_initconstant();
if (t->constindex == NOT_USED) if (t->constindex == NOT_USED)
{ {
if (lua_nconstant == lua_maxconstant) if (lua_nconstant == lua_maxconstant)
@@ -132,8 +131,10 @@ Word luaI_findconstant (TreeNode *t)
lua_constant = growvector(lua_constant, lua_maxconstant, TaggedString *); lua_constant = growvector(lua_constant, lua_maxconstant, TaggedString *);
} }
t->constindex = lua_nconstant; t->constindex = lua_nconstant;
lua_constant[lua_nconstant] = &(t->ts); lua_constant[lua_nconstant] = t;
lua_nconstant++; lua_nconstant++;
if (!t->marked)
t->marked = 2; /* avoid GC */
} }
return t->constindex; return t->constindex;
} }
@@ -141,7 +142,13 @@ Word luaI_findconstant (TreeNode *t)
Word luaI_findconstantbyname (char *name) Word luaI_findconstantbyname (char *name)
{ {
return luaI_findconstant(lua_constcreate(name)); return luaI_findconstant(lua_createstring(name));
}
TaggedString *lua_constcreate(char *name)
{
int i = luaI_findconstantbyname(name);
return lua_constant[i];
} }
@@ -153,7 +160,7 @@ static char *lua_travsymbol (int (*fn)(Object *))
Word i; Word i;
for (i=0; i<lua_ntable; i++) for (i=0; i<lua_ntable; i++)
if (fn(&s_object(i))) if (fn(&s_object(i)))
return luaI_nodebysymbol(i)->ts.str; return lua_table[i].varname->str;
return NULL; return NULL;
} }
@@ -162,7 +169,7 @@ static char *lua_travsymbol (int (*fn)(Object *))
** Mark an object if it is a string or a unmarked array. ** Mark an object if it is a string or a unmarked array.
*/ */
int lua_markobject (Object *o) int lua_markobject (Object *o)
{ {/* if already marked, does not change mark value */
if (tag(o) == LUA_T_STRING && !tsvalue(o)->marked) if (tag(o) == LUA_T_STRING && !tsvalue(o)->marked)
tsvalue(o)->marked = 1; tsvalue(o)->marked = 1;
else if (tag(o) == LUA_T_ARRAY) else if (tag(o) == LUA_T_ARRAY)
@@ -178,12 +185,9 @@ int lua_markobject (Object *o)
** Garbage collection. ** Garbage collection.
** Delete all unused strings and arrays. ** Delete all unused strings and arrays.
*/ */
void lua_pack (void) Long luaI_collectgarbage (void)
{ {
static Long block = GARBAGE_BLOCK; /* when garbage collector will be called */
static Long nentity = 0; /* counter of new entities (strings and arrays) */
Long recovered = 0; Long recovered = 0;
if (nentity++ < block) return;
lua_travstack(lua_markobject); /* mark stack objects */ lua_travstack(lua_markobject); /* mark stack objects */
lua_travsymbol(lua_markobject); /* mark symbol table objects */ lua_travsymbol(lua_markobject); /* mark symbol table objects */
luaI_travlock(lua_markobject); /* mark locked objects */ luaI_travlock(lua_markobject); /* mark locked objects */
@@ -191,6 +195,16 @@ void lua_pack (void)
recovered += lua_strcollector(); recovered += lua_strcollector();
recovered += lua_hashcollector(); recovered += lua_hashcollector();
recovered += luaI_funccollector(); recovered += luaI_funccollector();
return recovered;
}
void lua_pack (void)
{
static Long block = GARBAGE_BLOCK; /* when garbage collector will be called */
static Long nentity = 0; /* counter of new entities (strings and arrays) */
Long recovered = 0;
if (nentity++ < block) return;
recovered = luaI_collectgarbage();
nentity = 0; /* reset counter */ nentity = 0; /* reset counter */
block=(16*block-7*recovered)/12; /* adapt block size */ block=(16*block-7*recovered)/12; /* adapt block size */
if (block < MIN_GARBAGE_BLOCK) block = MIN_GARBAGE_BLOCK; if (block < MIN_GARBAGE_BLOCK) block = MIN_GARBAGE_BLOCK;
@@ -225,36 +239,16 @@ static void lua_nextvar (void)
} }
else else
{ {
TreeNode *t = luaI_nodebysymbol(next); TaggedString *t = lua_table[next].varname;
Object name; Object name;
tag(&name) = LUA_T_STRING; tag(&name) = LUA_T_STRING;
tsvalue(&name) = &(t->ts); tsvalue(&name) = t;
luaI_pushobject(&name); luaI_pushobject(&name);
luaI_pushobject(&s_object(next)); luaI_pushobject(&s_object(next));
} }
} }
static void setglobal (void)
{
lua_Object name = lua_getparam(1);
lua_Object value = lua_getparam(2);
if (!lua_isstring(name))
lua_error("incorrect argument to function `setglobal'");
lua_pushobject(value);
lua_storeglobal(lua_getstring(name));
}
static void getglobal (void)
{
lua_Object name = lua_getparam(1);
if (!lua_isstring(name))
lua_error("incorrect argument to function `getglobal'");
lua_pushobject(lua_getglobal(lua_getstring(name)));
}
static Object *functofind; static Object *functofind;
static int checkfunc (Object *o) static int checkfunc (Object *o)
{ {
@@ -270,7 +264,7 @@ static int checkfunc (Object *o)
} }
char *getobjname (lua_Object o, char **name) char *lua_getobjname (lua_Object o, char **name)
{ /* try to find a name for given function */ { /* try to find a name for given function */
functofind = luaI_Address(o); functofind = luaI_Address(o);
if ((*name = luaI_travfallbacks(checkfunc)) != NULL) if ((*name = luaI_travfallbacks(checkfunc)) != NULL)

22
table.h
View File

@@ -1,7 +1,7 @@
/* /*
** Module to control static tables ** Module to control static tables
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: table.h,v 2.12 1995/10/17 11:58:41 roberto Exp roberto $ ** $Id: table.h,v 2.17 1996/02/12 18:32:40 roberto Exp roberto $
*/ */
#ifndef table_h #ifndef table_h
@@ -10,19 +10,25 @@
#include "tree.h" #include "tree.h"
#include "opcode.h" #include "opcode.h"
typedef struct
{
Object object;
TaggedString *varname;
} Symbol;
extern Symbol *lua_table; extern Symbol *lua_table;
extern TaggedString **lua_constant; extern TaggedString **lua_constant;
extern char *lua_file[]; void luaI_initsymbol (void);
extern int lua_nfile; void luaI_initconstant (void);
void lua_initconstant (void);
Word luaI_findsymbolbyname (char *name); Word luaI_findsymbolbyname (char *name);
Word luaI_findsymbol (TreeNode *t); Word luaI_findsymbol (TaggedString *t);
Word luaI_findconstant (TreeNode *t); Word luaI_findconstant (TaggedString *t);
Word luaI_findconstantbyname (char *name); Word luaI_findconstantbyname (char *name);
TaggedString *lua_constcreate (char *str);
int lua_markobject (Object *o); int lua_markobject (Object *o);
Long luaI_collectgarbage (void);
void lua_pack (void); void lua_pack (void);

189
tree.c
View File

@@ -3,7 +3,7 @@
** TecCGraf - PUC-Rio ** TecCGraf - PUC-Rio
*/ */
char *rcs_tree="$Id: tree.c,v 1.13 1995/01/12 14:19:04 roberto Exp roberto $"; char *rcs_tree="$Id: tree.c,v 1.17 1996/02/14 13:35:51 roberto Exp roberto $";
#include <string.h> #include <string.h>
@@ -11,66 +11,105 @@ char *rcs_tree="$Id: tree.c,v 1.13 1995/01/12 14:19:04 roberto Exp roberto $";
#include "mem.h" #include "mem.h"
#include "lua.h" #include "lua.h"
#include "tree.h" #include "tree.h"
#include "lex.h"
#include "hash.h"
#include "table.h" #include "table.h"
#define lua_strcmp(a,b) (a[0]<b[0]?(-1):(a[0]>b[0]?(1):strcmp(a,b))) #define NUM_HASHS 64
typedef struct {
int size;
int nuse; /* number of elements (including EMPTYs) */
TaggedString **hash;
} stringtable;
static int initialized = 0;
static stringtable string_root[NUM_HASHS];
static TaggedString EMPTY = {NOT_USED, NOT_USED, 0, 2, {0}};
typedef struct StringNode { static unsigned long hash (char *str)
struct StringNode *next;
TaggedString ts;
} StringNode;
static StringNode *string_root = NULL;
static TreeNode *constant_root = NULL;
/*
** Insert a new constant/variable at the tree.
*/
static TreeNode *tree_create (TreeNode **node, char *str)
{ {
if (*node == NULL) unsigned long h = 0;
{ while (*str)
*node = (TreeNode *) luaI_malloc(sizeof(TreeNode)+strlen(str)); h = ((h<<5)-h)^(unsigned char)*(str++);
(*node)->left = (*node)->right = NULL; return h;
strcpy((*node)->ts.str, str); }
(*node)->ts.marked = 0;
(*node)->ts.hash = 0; static void initialize (void)
(*node)->varindex = (*node)->constindex = NOT_USED; {
return *node; initialized = 1;
} luaI_addReserved();
else luaI_initsymbol();
{ luaI_initconstant();
int c = lua_strcmp(str, (*node)->ts.str); }
if (c < 0)
return tree_create(&(*node)->left, str);
else if (c > 0) static void grow (stringtable *tb)
return tree_create(&(*node)->right, str); {
int newsize = luaI_redimension(tb->size);
TaggedString **newhash = newvector(newsize, TaggedString *);
int i;
for (i=0; i<newsize; i++)
newhash[i] = NULL;
if (tb->size > 0)
{ /* rehash */
tb->nuse = 0;
for (i=0; i<tb->size; i++)
if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY)
{
int h = tb->hash[i]->hash%newsize;
while (newhash[h])
h = (h+1)%newsize;
newhash[h] = tb->hash[i];
tb->nuse++;
}
luaI_free(tb->hash);
}
tb->size = newsize;
tb->hash = newhash;
}
static TaggedString *insert (char *str, stringtable *tb)
{
TaggedString *ts;
unsigned long h = hash(str);
int i;
int j = -1;
if ((Long)tb->nuse*3 >= (Long)tb->size*2)
{
if (!initialized)
initialize();
grow(tb);
}
i = h%tb->size;
while (tb->hash[i])
{
if (tb->hash[i] == &EMPTY)
j = i;
else if (strcmp(str, tb->hash[i]->str) == 0)
return tb->hash[i];
i = (i+1)%tb->size;
}
/* not found */
if (j != -1) /* is there an EMPTY space? */
i = j;
else else
return *node; tb->nuse++;
} ts = tb->hash[i] = (TaggedString *)luaI_malloc(sizeof(TaggedString)+strlen(str));
strcpy(ts->str, str);
ts->marked = 0;
ts->hash = h;
ts->varindex = ts->constindex = NOT_USED;
return ts;
} }
TaggedString *lua_createstring (char *str) TaggedString *lua_createstring (char *str)
{ {
StringNode *newString; return insert(str, &string_root[(unsigned)str[0]%NUM_HASHS]);
if (str == NULL) return NULL;
lua_pack();
newString = (StringNode *)luaI_malloc(sizeof(StringNode)+strlen(str));
newString->ts.marked = 0;
newString->ts.hash = 0;
strcpy(newString->ts.str, str);
newString->next = string_root;
string_root = newString;
return &(newString->ts);
}
TreeNode *lua_constcreate (char *str)
{
return tree_create(&constant_root, str);
} }
@@ -80,44 +119,28 @@ TreeNode *lua_constcreate (char *str)
*/ */
Long lua_strcollector (void) Long lua_strcollector (void)
{ {
StringNode *curr = string_root, *prev = NULL;
Long counter = 0; Long counter = 0;
while (curr) int i;
for (i=0; i<NUM_HASHS; i++)
{ {
StringNode *next = curr->next; stringtable *tb = &string_root[i];
if (!curr->ts.marked) int j;
for (j=0; j<tb->size; j++)
{ {
if (prev == NULL) string_root = next; TaggedString *t = tb->hash[j];
else prev->next = next; if (t != NULL && t->marked <= 1)
luaI_free(curr); {
++counter; if (t->marked)
t->marked = 0;
else
{
luaI_free(t);
tb->hash[j] = &EMPTY;
counter++;
}
}
} }
else
{
curr->ts.marked = 0;
prev = curr;
}
curr = next;
} }
return counter; return counter;
} }
/*
** Traverse the constant tree looking for a specific symbol number
*/
static TreeNode *nodebysymbol (TreeNode *root, Word symbol)
{
TreeNode *t;
if (root == NULL) return NULL;
if (root->varindex == symbol) return root;
t = nodebysymbol(root->left, symbol);
if (t) return t;
return nodebysymbol(root->right, symbol);
}
TreeNode *luaI_nodebysymbol (Word symbol)
{
return nodebysymbol(constant_root, symbol);
}

17
tree.h
View File

@@ -1,7 +1,7 @@
/* /*
** tree.h ** tree.h
** TecCGraf - PUC-Rio ** TecCGraf - PUC-Rio
** $Id: tree.h,v 1.9 1995/01/12 14:19:04 roberto Exp roberto $ ** $Id: tree.h,v 1.12 1996/02/12 18:32:40 roberto Exp roberto $
*/ */
#ifndef tree_h #ifndef tree_h
@@ -14,24 +14,15 @@
typedef struct TaggedString typedef struct TaggedString
{ {
unsigned short varindex; /* != NOT_USED if this is a symbol */
unsigned short constindex; /* != NOT_USED if this is a constant */
unsigned long hash; /* 0 if not initialized */ unsigned long hash; /* 0 if not initialized */
char marked; /* for garbage collection */ int marked; /* for garbage collection; never collect (nor change) if > 1 */
char str[1]; /* \0 byte already reserved */ char str[1]; /* \0 byte already reserved */
} TaggedString; } TaggedString;
typedef struct TreeNode
{
struct TreeNode *right;
struct TreeNode *left;
unsigned short varindex; /* != NOT_USED if this is a symbol */
unsigned short constindex; /* != NOT_USED if this is a constant */
TaggedString ts;
} TreeNode;
TaggedString *lua_createstring (char *str); TaggedString *lua_createstring (char *str);
TreeNode *lua_constcreate (char *str);
Long lua_strcollector (void); Long lua_strcollector (void);
TreeNode *luaI_nodebysymbol (Word symbol);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
** TeCGraf - PUC-Rio ** TeCGraf - PUC-Rio
** $Id: types.h,v 1.2 1994/12/27 20:41:47 celes Exp roberto $ ** $Id: types.h,v 1.3 1995/02/06 19:32:43 roberto Exp roberto $
*/ */
#ifndef types_h #ifndef types_h
@@ -12,8 +12,6 @@
#define real float #define real float
#endif #endif
typedef int Bool; /* boolean values */
#define Byte lua_Byte /* some systems have Byte as a predefined type */ #define Byte lua_Byte /* some systems have Byte as a predefined type */
typedef unsigned char Byte; /* unsigned 8 bits */ typedef unsigned char Byte; /* unsigned 8 bits */