Browse Source

simplified version of `gc' tag method (only for userdata now).

v5-2
Roberto Ierusalimschy 25 years ago
parent
commit
4343420d4d
  1. 30
      lapi.c
  2. 63
      lbuiltin.c
  3. 15
      ldo.c
  4. 3
      ldo.h
  5. 34
      lfunc.c
  6. 6
      lfunc.h
  7. 302
      lgc.c
  8. 7
      lgc.h
  9. 8
      llex.c
  10. 9
      lobject.c
  11. 24
      lobject.h
  12. 27
      lstate.c
  13. 10
      lstate.h
  14. 142
      lstring.c
  15. 18
      lstring.h
  16. 25
      ltable.c
  17. 4
      ltable.h
  18. 8
      ltm.c
  19. 31
      makefile
  20. 61
      manual.tex

30
lapi.c

@ -1,11 +1,10 @@
/*
** $Id: lapi.c,v 1.49 1999/09/20 14:57:29 roberto Exp roberto $
** $Id: lapi.c,v 1.50 1999/09/21 16:10:13 roberto Exp roberto $
** Lua API
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#include <string.h>
#include "lapi.h"
@ -15,6 +14,7 @@
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lref.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
@ -387,14 +387,14 @@ void lua_settag (int tag) {
TaggedString *luaA_nextvar (TaggedString *g) {
if (g == NULL)
g = (TaggedString *)L->rootglobal.next; /* first variable */
g = L->rootglobal; /* first variable */
else {
/* check whether name is in global var list */
luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected");
g = (TaggedString *)g->head.next; /* get next */
luaL_arg_check(g != g->next, 1, "variable name expected");
g = g->next; /* get next */
}
while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */
g = (TaggedString *)g->head.next;
g = g->next;
if (g) {
ttype(L->stack.top) = LUA_T_STRING; tsvalue(L->stack.top) = g;
incr_top;
@ -574,12 +574,18 @@ static int checkfunc (TObject *o) {
const char *lua_getobjname (lua_Object o, const char **name) {
/* try to find a name for given function */
TaggedString *g;
set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc" */
if ((*name = luaS_travsymbol(checkfunc)) != NULL)
return "global";
else if ((*name = luaT_travtagmethods(checkfunc)) != NULL)
for (g=L->rootglobal; g; g=g->next) {
if (checkfunc(&g->u.s.globalval)) {
*name = g->str;
return "global";
}
}
/* not found: try tag methods */
if ((*name = luaT_travtagmethods(checkfunc)) != NULL)
return "tag-method";
else return "";
else return ""; /* not found at all */
}
/* }====================================================== */
@ -615,7 +621,7 @@ void lua_endblock (void) {
int lua_ref (int lock) {
int ref;
checkCparams(1);
ref = luaC_ref(L->stack.top-1, lock);
ref = luaR_ref(L->stack.top-1, lock);
L->stack.top--;
return ref;
}
@ -623,7 +629,7 @@ int lua_ref (int lock) {
lua_Object lua_getref (int ref) {
const TObject *o = luaC_getref(ref);
const TObject *o = luaR_getref(ref);
return (o ? put_luaObject(o) : LUA_NOOBJECT);
}

63
lbuiltin.c

@ -1,5 +1,5 @@
/*
** $Id: lbuiltin.c,v 1.62 1999/09/08 20:45:18 roberto Exp roberto $
** $Id: lbuiltin.c,v 1.63 1999/09/20 14:57:29 roberto Exp roberto $
** Built-in functions
** See Copyright Notice in lua.h
*/
@ -222,9 +222,15 @@ static void luaB_rawsettable (void) {
}
static void luaB_settagmethod (void) {
int tag = luaL_check_int(1);
const char *event = luaL_check_string(2);
lua_Object nf = luaL_nonnullarg(3);
#ifndef LUA_COMPAT_GC
if (strcmp(event, "gc") == 0 && tag != LUA_T_NIL)
lua_error("cannot set this tag method from Lua");
#endif
lua_pushobject(nf);
lua_pushobject(lua_settagmethod(luaL_check_int(1), luaL_check_string(2)));
lua_pushobject(lua_settagmethod(tag, event));
}
static void luaB_gettagmethod (void) {
@ -437,12 +443,11 @@ static void luaB_foreach (void) {
static void luaB_foreachvar (void) {
GCnode *g;
TaggedString *s;
TObject f; /* see comment in 'foreachi' */
f = *luaA_Address(luaL_functionarg(1));
luaD_checkstack(4); /* for extra var name, f, var name, and globalval */
for (g = L->rootglobal.next; g; g = g->next) {
TaggedString *s = (TaggedString *)g;
for (s = L->rootglobal; s; s = s->next) {
if (s->u.s.globalval.ttype != LUA_T_NIL) {
pushtagstring(s); /* keep (extra) s on stack to avoid GC */
*(L->stack.top++) = f;
@ -451,10 +456,10 @@ static void luaB_foreachvar (void) {
luaD_calln(2, 1);
if (ttype(L->stack.top-1) != LUA_T_NIL) {
L->stack.top--;
*(L->stack.top-1) = *L->stack.top; /* remove extra s */
*(L->stack.top-1) = *L->stack.top; /* remove extra `s' */
return;
}
L->stack.top-=2; /* remove result and extra s */
L->stack.top-=2; /* remove result and extra `s' */
}
}
}
@ -602,20 +607,42 @@ static void mem_query (void) {
static void query_strings (void) {
lua_pushnumber(L->string_root[luaL_check_int(1)].nuse);
int h = luaL_check_int(1) - 1;
int s = luaL_opt_int(2, 0) - 1;
if (s==-1) {
if (h < NUM_HASHS) {
lua_pushnumber(L->string_root[h].nuse);
lua_pushnumber(L->string_root[h].size);
}
}
else {
TaggedString *ts = L->string_root[h].hash[s];
if (ts == NULL) lua_pushstring("<NIL>");
else if (ts == &luaS_EMPTY) lua_pushstring("<EMPTY>");
else if (ts->constindex == -1) lua_pushstring("<USERDATA>");
else lua_pushstring(ts->str);
}
}
static void countlist (void) {
const char *s = luaL_check_string(1);
GCnode *l = (s[0]=='t') ? L->roottable.next : (s[0]=='c') ? L->rootcl.next :
(s[0]=='p') ? L->rootproto.next : L->rootglobal.next;
int i=0;
while (l) {
i++;
l = l->next;
static void extra_services (void) {
const char *service = luaL_check_string(1);
switch (*service) {
case 'U': /* create a userdata with a given value/tag */
lua_pushusertag((void *)luaL_check_int(2), luaL_check_int(3));
break;
case 'u': /* return the value of a userdata */
lua_pushnumber((int)lua_getuserdata(lua_getparam(2)));
break;
case 't': /* set `gc' tag method */
lua_pushobject(lua_getparam(3));
lua_settagmethod(luaL_check_int(2), "gc");
break;
default: luaL_arg_check(0, 1, "invalid service");
}
lua_pushnumber(i);
}
@ -679,9 +706,9 @@ static void testC (void) {
static const struct luaL_reg builtin_funcs[] = {
#ifdef DEBUG
{"extra", extra_services},
{"testC", testC},
{"totalmem", mem_query},
{"count", countlist},
{"querystr", query_strings},
#endif
{"_ALERT", luaB_alert},

15
ldo.c

@ -1,18 +1,16 @@
/*
** $Id: ldo.c,v 1.46 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: ldo.c,v 1.47 1999/09/06 15:24:46 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lauxlib.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
@ -219,17 +217,6 @@ void luaD_calln (int nArgs, int nResults) {
}
/*
** Traverse all objects on L->stack.stack
*/
void luaD_travstack (int (*fn)(TObject *)) {
StkId i;
for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--)
fn(L->stack.stack+i);
}
static void message (const char *s) {
const TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval);
if (ttype(em) == LUA_T_PROTO || ttype(em) == LUA_T_CPROTO ||

3
ldo.h

@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 1.6 1999/06/22 20:37:23 roberto Exp roberto $
** $Id: ldo.h,v 1.7 1999/08/16 20:52:00 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -39,7 +39,6 @@ void luaD_calln (int nArgs, int nResults);
void luaD_callTM (const TObject *f, int nParams, int nResults);
int luaD_protectedrun (void);
void luaD_gcIM (const TObject *o);
void luaD_travstack (int (*fn)(TObject *));
void luaD_checkstack (int n);

34
lfunc.c

@ -1,5 +1,5 @@
/*
** $Id: lfunc.c,v 1.10 1999/03/04 21:17:26 roberto Exp roberto $
** $Id: lfunc.c,v 1.11 1999/08/16 20:52:00 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@ -18,7 +18,9 @@
Closure *luaF_newclosure (int nelems) {
Closure *c = (Closure *)luaM_malloc(sizeof(Closure)+nelems*sizeof(TObject));
luaO_insertlist(&(L->rootcl), (GCnode *)c);
c->next = L->rootcl;
L->rootcl = c;
c->marked = 0;
L->nblocks += gcsizeclosure(c);
c->nelems = nelems;
return c;
@ -33,14 +35,16 @@ TProtoFunc *luaF_newproto (void) {
f->consts = NULL;
f->nconsts = 0;
f->locvars = NULL;
luaO_insertlist(&(L->rootproto), (GCnode *)f);
f->next = L->rootproto;
L->rootproto = f;
f->marked = 0;
L->nblocks += gcsizeproto(f);
return f;
}
static void freefunc (TProtoFunc *f) {
void luaF_freeproto (TProtoFunc *f) {
L->nblocks -= gcsizeproto(f);
luaM_free(f->code);
luaM_free(f->locvars);
luaM_free(f->consts);
@ -48,23 +52,9 @@ static void freefunc (TProtoFunc *f) {
}
void luaF_freeproto (TProtoFunc *l) {
while (l) {
TProtoFunc *next = (TProtoFunc *)l->head.next;
L->nblocks -= gcsizeproto(l);
freefunc(l);
l = next;
}
}
void luaF_freeclosure (Closure *l) {
while (l) {
Closure *next = (Closure *)l->head.next;
L->nblocks -= gcsizeclosure(l);
luaM_free(l);
l = next;
}
void luaF_freeclosure (Closure *c) {
L->nblocks -= gcsizeclosure(c);
luaM_free(c);
}

6
lfunc.h

@ -1,5 +1,5 @@
/*
** $Id: lfunc.h,v 1.5 1997/12/15 16:17:20 roberto Exp roberto $
** $Id: lfunc.h,v 1.6 1999/08/16 20:52:00 roberto Exp roberto $
** Lua Function structures
** See Copyright Notice in lua.h
*/
@ -14,8 +14,8 @@
TProtoFunc *luaF_newproto (void);
Closure *luaF_newclosure (int nelems);
void luaF_freeproto (TProtoFunc *l);
void luaF_freeclosure (Closure *l);
void luaF_freeproto (TProtoFunc *f);
void luaF_freeclosure (Closure *c);
const char *luaF_getlocalname (TProtoFunc *func, int local_number, int line);

302
lgc.c

@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 1.25 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: lgc.c,v 1.26 1999/09/27 18:00:25 roberto Exp roberto $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -8,8 +8,8 @@
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lref.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
@ -21,138 +21,15 @@
static int markobject (TObject *o);
/*
** =======================================================
** REF mechanism
** =======================================================
*/
int luaC_ref (const TObject *o, int lock) {
int ref;
if (ttype(o) == LUA_T_NIL)
ref = LUA_REFNIL;
else {
for (ref=0; ref<L->refSize; ref++)
if (L->refArray[ref].status == FREE)
break;
if (ref == L->refSize) { /* no more empty spaces? */
luaM_growvector(L->refArray, L->refSize, 1, struct ref, refEM, MAX_INT);
L->refSize++;
}
L->refArray[ref].o = *o;
L->refArray[ref].status = lock ? LOCK : HOLD;
}
return ref;
}
void lua_unref (int ref) {
if (ref >= 0 && ref < L->refSize)
L->refArray[ref].status = FREE;
}
const TObject *luaC_getref (int ref) {
if (ref == LUA_REFNIL)
return &luaO_nilobject;
if (ref >= 0 && ref < L->refSize &&
(L->refArray[ref].status == LOCK || L->refArray[ref].status == HOLD))
return &L->refArray[ref].o;
else
return NULL;
}
static void travlock (void) {
int i;
for (i=0; i<L->refSize; i++)
if (L->refArray[i].status == LOCK)
markobject(&L->refArray[i].o);
}
static int ismarked (const TObject *o) {
/* valid only for locked objects */
switch (o->ttype) {
case LUA_T_STRING: case LUA_T_USERDATA:
return o->value.ts->head.marked;
case LUA_T_ARRAY:
return o->value.a->head.marked;
case LUA_T_CLOSURE:
return o->value.cl->head.marked;
case LUA_T_PROTO:
return o->value.tf->head.marked;
#ifdef DEBUG
case LUA_T_LINE: case LUA_T_CLMARK:
case LUA_T_CMARK: case LUA_T_PMARK:
LUA_INTERNALERROR("invalid type");
#endif
default: /* nil, number or cproto */
return 1;
}
}
/* mark a string; marks bigger than 1 cannot be changed */
#define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;}
static void invalidaterefs (void) {
int i;
for (i=0; i<L->refSize; i++)
if (L->refArray[i].status == HOLD && !ismarked(&L->refArray[i].o))
L->refArray[i].status = COLLECTED;
}
void luaC_hashcallIM (Hash *l) {
TObject t;
ttype(&t) = LUA_T_ARRAY;
for (; l; l=(Hash *)l->head.next) {
avalue(&t) = l;
luaD_gcIM(&t);
}
}
void luaC_strcallIM (TaggedString *l) {
TObject o;
ttype(&o) = LUA_T_USERDATA;
for (; l; l=(TaggedString *)l->head.next)
if (l->constindex == -1) { /* is userdata? */
tsvalue(&o) = l;
luaD_gcIM(&o);
}
}
static GCnode *listcollect (GCnode *l) {
GCnode *frees = NULL;
while (l) {
GCnode *next = l->next;
l->marked = 0;
while (next && !next->marked) {
l->next = next->next;
next->next = frees;
frees = next;
next = l->next;
}
l = next;
}
return frees;
}
/*
** mark a string; marks bigger than 1 cannot be changed.
*/
#define strmark(s) {if ((s)->head.marked == 0) (s)->head.marked = 1;}
static void protomark (TProtoFunc *f) {
if (!f->head.marked) {
if (!f->marked) {
int i;
f->head.marked = 1;
f->marked = 1;
strmark(f->source);
for (i=f->nconsts-1; i>=0; i--)
markobject(&f->consts[i]);
@ -161,9 +38,9 @@ static void protomark (TProtoFunc *f) {
static void closuremark (Closure *f) {
if (!f->head.marked) {
if (!f->marked) {
int i;
f->head.marked = 1;
f->marked = 1;
for (i=f->nelems; i>=0; i--)
markobject(&f->consts[i]);
}
@ -171,9 +48,9 @@ static void closuremark (Closure *f) {
static void hashmark (Hash *h) {
if (!h->head.marked) {
if (!h->marked) {
int i;
h->head.marked = 1;
h->marked = 1;
for (i=nhash(h)-1; i>=0; i--) {
Node *n = node(h,i);
if (ttype(ref(n)) != LUA_T_NIL) {
@ -187,7 +64,7 @@ static void hashmark (Hash *h) {
static void globalmark (void) {
TaggedString *g;
for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next){
for (g=L->rootglobal; g; g=g->next) {
LUA_ASSERT(g->constindex >= 0, "userdata in global list");
if (g->u.s.globalval.ttype != LUA_T_NIL) {
markobject(&g->u.s.globalval);
@ -197,6 +74,21 @@ static void globalmark (void) {
}
static void travstack (void) {
StkId i;
for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--)
markobject(L->stack.stack+i);
}
static void travlock (void) {
int i;
for (i=0; i<L->refSize; i++)
if (L->refArray[i].status == LOCK)
markobject(&L->refArray[i].o);
}
static int markobject (TObject *o) {
switch (ttype(o)) {
case LUA_T_USERDATA: case LUA_T_STRING:
@ -217,36 +109,138 @@ static int markobject (TObject *o) {
}
static void collectproto (void) {
TProtoFunc **p = &L->rootproto;
TProtoFunc *next;
while ((next = *p) != NULL) {
if (next->marked) {
next->marked = 0;
p = &next->next;
}
else {
*p = next->next;
luaF_freeproto(next);
}
}
}
static void collectclosure (void) {
Closure **p = &L->rootcl;
Closure *next;
while ((next = *p) != NULL) {
if (next->marked) {
next->marked = 0;
p = &next->next;
}
else {
*p = next->next;
luaF_freeclosure(next);
}
}
}
static void collecttable (void) {
Hash **p = &L->roottable;
Hash *next;
while ((next = *p) != NULL) {
if (next->marked) {
next->marked = 0;
p = &next->next;
}
else {
*p = next->next;
luaH_free(next);
}
}
}
static void clear_global_list (void) {
TaggedString **p = &L->rootglobal;
TaggedString *next;
while ((next = *p) != NULL) {
if (next->marked) p = &next->next;
else *p = next->next;
}
}
/*
** collect all elements with `marked' < `limit'.
** with limit=1, that means all unmarked elements;
** with limit=MAX_INT, that means all elements (but EMPTY).
*/
static void collectstring (int limit) {
TObject o; /* to call userdata 'gc' tag method */
int i;
ttype(&o) = LUA_T_USERDATA;
clear_global_list();
for (i=0; i<NUM_HASHS; i++) {
stringtable *tb = &L->string_root[i];
int j;
for (j=0; j<tb->size; j++) {
TaggedString *t = tb->hash[j];
if (t == NULL) continue;
if (t->marked < limit) {
if (t->constindex == -1) { /* is userdata? */
tsvalue(&o) = t;
luaD_gcIM(&o);
}
luaS_free(t);
tb->hash[j] = &luaS_EMPTY;
}
else if (t->marked == 1)
t->marked = 0;
}
}
}
#ifdef LUA_COMPAT_GC
static void tableTM (void) {
Hash *p;
TObject o;
ttype(&o) = LUA_T_ARRAY;
for (p = L->roottable; p; p = p->next) {
if (!p->marked) {
avalue(&o) = p;
luaD_gcIM(&o);
}
}
}
#else
#define tableTM() /* do nothing */
#endif
static void markall (void) {
luaD_travstack(markobject); /* mark stack objects */
travstack(); /* mark stack objects */
globalmark(); /* mark global variable values and names */
travlock(); /* mark locked objects */
luaT_travtagmethods(markobject); /* mark fallbacks */
luaT_travtagmethods(markobject); /* mark tag methods */
}
void luaC_collect (int all) {
L->GCthreshold *= 4; /* to avoid GC during GC */
tableTM(); /* call TM for tables (if LUA_COMPAT_GC) */
collecttable();
collectstring(all?MAX_INT:1);
collectproto();
collectclosure();
luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
}
long lua_collectgarbage (long limit) {
unsigned long recovered = L->nblocks; /* to subtract nblocks after gc */
Hash *freetable;
TaggedString *freestr;
TProtoFunc *freefunc;
Closure *freeclos;
markall();
invalidaterefs();
freestr = luaS_collector();
freetable = (Hash *)listcollect(&(L->roottable));
freefunc = (TProtoFunc *)listcollect(&(L->rootproto));
freeclos = (Closure *)listcollect(&(L->rootcl));
L->GCthreshold *= 4; /* to avoid GC during GC */
luaC_hashcallIM(freetable); /* GC tag methods for tables */
luaC_strcallIM(freestr); /* GC tag methods for userdata */
luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
luaH_free(freetable);
luaS_free(freestr);
luaF_freeproto(freefunc);
luaF_freeclosure(freeclos);
recovered = recovered-L->nblocks;
luaR_invalidaterefs();
luaC_collect(0);
recovered = recovered - L->nblocks;
L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit;
return recovered;
}

7
lgc.h

@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 1.4 1997/12/01 20:31:25 roberto Exp roberto $
** $Id: lgc.h,v 1.5 1999/08/16 20:52:00 roberto Exp roberto $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -12,10 +12,7 @@
void luaC_checkGC (void);
const TObject *luaC_getref (int ref);
int luaC_ref (const TObject *o, int lock);
void luaC_hashcallIM (Hash *l);
void luaC_strcallIM (TaggedString *l);
void luaC_collect (int all);
#endif

8
llex.c

@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 1.38 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: llex.c,v 1.39 1999/09/06 13:55:09 roberto Exp roberto $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@ -37,7 +37,7 @@ void luaX_init (void) {
int i;
for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) {
TaggedString *ts = luaS_new(reserved[i]);
ts->head.marked = FIRST_RESERVED+i; /* reserved word (always > 255) */
ts->marked = FIRST_RESERVED+i; /* reserved word (always > 255) */
}
}
@ -426,8 +426,8 @@ int luaX_lex (LexState *LS) {
} while (isalnum(LS->current) || LS->current == '_');
save('\0');
ts = luaS_new(L->Mbuffer+L->Mbuffbase);
if (ts->head.marked >= FIRST_RESERVED)
return ts->head.marked; /* reserved word */
if (ts->marked >= FIRST_RESERVED)
return ts->marked; /* reserved word */
LS->seminfo.ts = ts;
return NAME;
}

9
lobject.c

@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 1.22 1999/09/06 20:19:22 roberto Exp roberto $
** $Id: lobject.c,v 1.23 1999/09/08 20:45:18 roberto Exp roberto $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@ -55,13 +55,6 @@ int luaO_equalval (const TObject *t1, const TObject *t2) {
}
void luaO_insertlist (GCnode *root, GCnode *node) {
node->next = root->next;
root->next = node;
node->marked = 0;
}
#ifdef OLD_ANSI
void luaO_memup (void *dest, void *src, int size) {
while (size--)

24
lobject.h

@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 1.29 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: lobject.h,v 1.30 1999/09/06 20:34:18 roberto Exp roberto $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@ -85,21 +85,13 @@ typedef struct TObject {
/*
** generic header for garbage collector lists
*/
typedef struct GCnode {
struct GCnode *next;
int marked;
} GCnode;
/*
** String headers for string table
*/
typedef struct TaggedString {
GCnode head;
struct TaggedString *next;
int marked;
unsigned long hash;
int constindex; /* hint to reuse constants (= -1 if this is a userdata) */
union {
@ -122,7 +114,8 @@ typedef struct TaggedString {
** Function Prototypes
*/
typedef struct TProtoFunc {
GCnode head;
struct TProtoFunc *next;
int marked;
struct TObject *consts;
int nconsts;
Byte *code; /* ends with opcode ENDCODE */
@ -157,7 +150,8 @@ typedef struct LocVar {
** Closures
*/
typedef struct Closure {
GCnode head;
struct Closure *next;
int marked;
int nelems; /* not included the first one (always the prototype) */
TObject consts[1]; /* at least one for prototype */
} Closure;
@ -170,7 +164,8 @@ typedef struct node {
} Node;
typedef struct Hash {
GCnode head;
struct Hash *next;
int marked;
Node *node;
int nhash;
int nuse;
@ -189,7 +184,6 @@ extern const TObject luaO_nilobject;
: luaO_equalval(t1,t2))
int luaO_equalval (const TObject *t1, const TObject *t2);
int luaO_redimension (int oldsize);
void luaO_insertlist (GCnode *root, GCnode *node);
int luaO_str2d (const char *s, real *result);
#ifdef OLD_ANSI

27
lstate.c

@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 1.12 1999/05/11 20:08:20 roberto Exp roberto $
** $Id: lstate.c,v 1.13 1999/08/16 20:52:00 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -7,13 +7,11 @@
#include "lbuiltin.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
@ -36,14 +34,10 @@ void lua_open (void) {
L->debug = 0;
L->callhook = NULL;
L->linehook = NULL;
L->rootproto.next = NULL;
L->rootproto.marked = 0;
L->rootcl.next = NULL;
L->rootcl.marked = 0;
L->rootglobal.next = NULL;
L->rootglobal.marked = 0;
L->roottable.next = NULL;
L->roottable.marked = 0;
L->rootproto = NULL;
L->rootcl = NULL;
L->rootglobal = NULL;
L->roottable = NULL;
L->IMtable = NULL;
L->refArray = NULL;
L->refSize = 0;
@ -58,21 +52,14 @@ void lua_open (void) {
void lua_close (void) {
TaggedString *alludata = luaS_collectudata();
L->GCthreshold = MAX_INT; /* to avoid GC during GC */
luaC_hashcallIM((Hash *)L->roottable.next); /* GC t.methods for tables */
luaC_strcallIM(alludata); /* GC tag methods for userdata */
luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */
luaH_free((Hash *)L->roottable.next);
luaF_freeproto((TProtoFunc *)L->rootproto.next);
luaF_freeclosure((Closure *)L->rootcl.next);
luaS_free(alludata);
luaC_collect(1); /* collect all elements */
luaS_freeall();
luaM_free(L->stack.stack);
luaM_free(L->IMtable);
luaM_free(L->refArray);
luaM_free(L->Mbuffer);
luaM_free(L->Cblocks);
LUA_ASSERT(L->nblocks == 0, "wrong count for nblocks");
luaM_free(L);
L = NULL;
#ifdef DEBUG

10
lstate.h

@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 1.18 1999/05/11 14:19:32 roberto Exp roberto $
** $Id: lstate.h,v 1.19 1999/05/11 20:08:20 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -73,10 +73,10 @@ struct lua_State {
lua_CHFunction callhook;
lua_LHFunction linehook;
/* global state */
GCnode rootproto; /* list of all prototypes */
GCnode rootcl; /* list of all closures */
GCnode roottable; /* list of all tables */
GCnode rootglobal; /* list of strings with global values */
TProtoFunc *rootproto; /* list of all prototypes */
Closure *rootcl; /* list of all closures */
Hash *roottable; /* list of all tables */
TaggedString *rootglobal; /* list of strings with global values */
stringtable *string_root; /* array of hash tables for strings and udata */
struct IM *IMtable; /* table for tag methods */
int last_tag; /* last used tag in IMtable */

142
lstring.c

@ -1,5 +1,5 @@
/*
** $Id: lstring.c,v 1.20 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: lstring.c,v 1.21 1999/09/28 12:27:06 roberto Exp roberto $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@ -14,17 +14,13 @@
#include "lua.h"
#define NUM_HASHSTR 31
#define NUM_HASHUDATA 31
#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA)
#define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */
static TaggedString EMPTY = {{NULL, 2}, 0L, 0,
{{{LUA_T_NIL, {NULL}}, 0L}}, {0}};
TaggedString luaS_EMPTY = {NULL, MAX_INT, 0L, 0,
{{{LUA_T_NIL, {NULL}}, 0L}}, {0}};
@ -49,6 +45,16 @@ void luaS_init (void) {
}
void luaS_freeall (void) {
int i;
for (i=0; i<NUM_HASHS; i++) {
if (L->string_root[i].hash != init_hash)
luaM_free(L->string_root[i].hash);
}
luaM_free(L->string_root);
}
static unsigned long hash_s (const char *s, long l) {
unsigned long h = 0; /* seed */
while (l--)
@ -57,12 +63,12 @@ static unsigned long hash_s (const char *s, long l) {
}
static int newsize (stringtable *tb) {
static int newsize (const stringtable *tb) {
int realuse = 0;
int i;
/* count how many entries are really in use */
for (i=0; i<tb->size; i++) {
if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY)
if (tb->hash[i] != NULL && tb->hash[i] != &luaS_EMPTY)
realuse++;
}
return luaO_redimension(realuse*2);
@ -78,7 +84,7 @@ static void grow (stringtable *tb) {
/* rehash */
tb->nuse = 0;
for (i=0; i<tb->size; i++) {
if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) {
if (tb->hash[i] != NULL && tb->hash[i] != &luaS_EMPTY) {
unsigned long h = tb->hash[i]->hash;
int h1 = h%ns;
while (newhash[h1]) {
@ -103,8 +109,8 @@ static TaggedString *newone_s (const char *str, long l, unsigned long h) {
ts->u.s.len = l;
ts->constindex = 0;
L->nblocks += gcsizestring(l);
ts->head.marked = 0;
ts->head.next = (GCnode *)ts; /* signal it is in no list */
ts->marked = 0;
ts->next = ts; /* signal it is in no list */
ts->hash = h;
return ts;
}
@ -115,8 +121,8 @@ static TaggedString *newone_u (void *buff, int tag, unsigned long h) {
ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag;
ts->constindex = -1; /* tag -> this is a userdata */
L->nblocks++;
ts->head.marked = 0;
ts->head.next = (GCnode *)ts; /* signal it is in no list */
ts->marked = 0;
ts->next = ts; /* signal it is in no list */
ts->hash = h;
return ts;
}
@ -144,7 +150,7 @@ static TaggedString *insert_s (const char *str, long l, stringtable *tb) {
int j = -1; /* last empty place found (or -1) */
int h1 = h%size;
while ((ts = tb->hash[h1]) != NULL) {
if (ts == &EMPTY)
if (ts == &luaS_EMPTY)
j = h1;
else if (ts->u.s.len == l && (memcmp(str, ts->str, l) == 0))
return ts;
@ -168,7 +174,7 @@ static TaggedString *insert_u (void *buff, int tag, stringtable *tb) {
int j = -1;
int h1 = h%size;
while ((ts = tb->hash[h1]) != NULL) {
if (ts == &EMPTY)
if (ts == &luaS_EMPTY)
j = h1;
else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v)
return ts;
@ -200,115 +206,29 @@ TaggedString *luaS_new (const char *str) {
TaggedString *luaS_newfixedstring (const char *str) {
TaggedString *ts = luaS_new(str);
if (ts->head.marked == 0)
ts->head.marked = 2; /* avoid GC */
if (ts->marked == 0) ts->marked = 2; /* avoid GC */
return ts;
}
void luaS_free (TaggedString *l) {
while (l) {
TaggedString *next = (TaggedString *)l->head.next;
L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len);
luaM_free(l);
l = next;
}
}
/*
** Garbage collection functions.
*/
static void remove_from_list (GCnode *l) {
while (l) {
GCnode *next = l->next;
while (next && !next->marked)
next = l->next = next->next;
l = next;
}
}
TaggedString *luaS_collector (void) {
TaggedString *frees = NULL;
int i;
remove_from_list(&(L->rootglobal));
for (i=0; i<NUM_HASHS; i++) {
stringtable *tb = &L->string_root[i];
int j;
for (j=0; j<tb->size; j++) {
TaggedString *t = tb->hash[j];
if (t == NULL) continue;
if (t->head.marked == 1)
t->head.marked = 0;
else if (!t->head.marked) {
t->head.next = (GCnode *)frees;
frees = t;
tb->hash[j] = &EMPTY;
}
}
}
return frees;
}
TaggedString *luaS_collectudata (void) {
TaggedString *frees = NULL;
int i;
L->rootglobal.next = NULL; /* empty list of globals */
for (i=NUM_HASHSTR; i<NUM_HASHS; i++) {
stringtable *tb = &L->string_root[i];
int j;
for (j=0; j<tb->size; j++) {
TaggedString *t = tb->hash[j];
if (t == NULL || t == &EMPTY)
continue;
LUA_ASSERT(t->constindex == -1, "must be userdata");
t->head.next = (GCnode *)frees;
frees = t;
tb->hash[j] = &EMPTY;
}
}
return frees;
}
void luaS_freeall (void) {
int i;
for (i=0; i<NUM_HASHS; i++) {
stringtable *tb = &L->string_root[i];
int j;
for (j=0; j<tb->size; j++) {
TaggedString *t = tb->hash[j];
if (t != &EMPTY) luaM_free(t);
}
if (tb->hash != init_hash) luaM_free(tb->hash);
}
luaM_free(L->string_root);
void luaS_free (TaggedString *t) {
L->nblocks -= (t->constindex == -1) ? 1 : gcsizestring(t->u.s.len);
luaM_free(t);
}
void luaS_rawsetglobal (TaggedString *ts, TObject *newval) {
void luaS_rawsetglobal (TaggedString *ts, const TObject *newval) {
ts->u.s.globalval = *newval;
if (ts->head.next == (GCnode *)ts) { /* is not in list? */
ts->head.next = L->rootglobal.next;
L->rootglobal.next = (GCnode *)ts;
if (ts->next == ts) { /* is not in list? */
ts->next = L->rootglobal;
L->rootglobal = ts;
}
}
const char *luaS_travsymbol (int (*fn)(TObject *)) {
TaggedString *g;
for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next)
if (fn(&g->u.s.globalval))
return g->str;
return NULL;
}
int luaS_globaldefined (const char *name) {
TaggedString *ts = luaS_new(name);
return ts->u.s.globalval.ttype != LUA_T_NIL;
}

18
lstring.h

@ -1,5 +1,5 @@
/*
** $Id: lstring.h,v 1.7 1998/03/06 16:54:42 roberto Exp roberto $
** $Id: lstring.h,v 1.8 1999/08/16 20:52:00 roberto Exp roberto $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@ -11,18 +11,22 @@
#include "lobject.h"
#define NUM_HASHSTR 31
#define NUM_HASHUDATA 31
#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA)
extern TaggedString luaS_EMPTY;
void luaS_init (void);
TaggedString *luaS_createudata (void *udata, int tag);
TaggedString *luaS_collector (void);
void luaS_free (TaggedString *l);
void luaS_freeall (void);
void luaS_free (TaggedString *ts);
TaggedString *luaS_newlstr (const char *str, long l);
TaggedString *luaS_new (const char *str);
TaggedString *luaS_newfixedstring (const char *str);
void luaS_rawsetglobal (TaggedString *ts, TObject *newval);
const char *luaS_travsymbol (int (*fn)(TObject *));
void luaS_rawsetglobal (TaggedString *ts, const TObject *newval);
int luaS_globaldefined (const char *name);
TaggedString *luaS_collectudata (void);
void luaS_freeall (void);
#endif

25
ltable.c

@ -1,10 +1,9 @@
/*
** $Id: ltable.c,v 1.23 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: ltable.c,v 1.24 1999/09/22 14:38:45 roberto Exp roberto $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#include "lauxlib.h"
#include "lmem.h"
@ -69,17 +68,6 @@ Node *luaH_present (const Hash *t, const TObject *key) {
}
void luaH_free (Hash *frees) {
while (frees) {
Hash *next = (Hash *)frees->head.next;
L->nblocks -= gcsize(frees->nhash);
luaM_free(nodevector(frees));
luaM_free(frees);
frees = next;
}
}
static Node *hashnodecreate (int nhash) {
Node *const v = luaM_newvector(nhash, Node);
int i;
@ -96,12 +84,21 @@ Hash *luaH_new (int nhash) {
nhash(t) = nhash;
nuse(t) = 0;
t->htag = TagDefault;
luaO_insertlist(&(L->roottable), (GCnode *)t);
t->next = L->roottable;
L->roottable = t;
t->marked = 0;
L->nblocks += gcsize(nhash);
return t;
}
void luaH_free (Hash *t) {
L->nblocks -= gcsize(t->nhash);
luaM_free(nodevector(t));
luaM_free(t);
}
static int newsize (Hash *t) {
Node *const v = t->node;
const int size = nhash(t);

4
ltable.h

@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 1.11 1999/02/23 14:57:28 roberto Exp roberto $
** $Id: ltable.h,v 1.12 1999/08/16 20:52:00 roberto Exp roberto $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@ -19,7 +19,7 @@
#define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from)))
Hash *luaH_new (int nhash);
void luaH_free (Hash *frees);
void luaH_free (Hash *t);
Node *luaH_present (const Hash *t, const TObject *key);
void luaH_set (Hash *t, const TObject *ref, const TObject *val);
int luaH_pos (const Hash *t, const TObject *r);

8
ltm.c

@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 1.26 1999/08/16 20:52:00 roberto Exp roberto $
** $Id: ltm.c,v 1.27 1999/09/20 14:57:29 roberto Exp roberto $
** Tag methods
** See Copyright Notice in lua.h
*/
@ -39,13 +39,17 @@ static const char luaT_validevents[NUM_TAGS][IM_N] = {
{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_USERDATA */
{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_NUMBER */
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */
{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */
{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_ARRAY */
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_PROTO */
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CPROTO */
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} /* LUA_T_NIL */
};
int luaT_validevent (int t, int e) { /* ORDER LUA_T */
#ifdef LUA_COMPAT_GC
if (t == LUA_T_ARRAY && e == IM_GC)
return 1; /* old versions allowed gc tag method for tables */
#endif
return (t < LUA_T_NIL) ? 1 : luaT_validevents[-t][e];
}

31
makefile

@ -1,5 +1,5 @@
#
## $Id: makefile,v 1.19 1999/02/24 21:31:03 roberto Exp roberto $
## $Id: makefile,v 1.20 1999/08/17 20:21:52 roberto Exp roberto $
## Makefile
## See Copyright Notice in lua.h
#
@ -15,20 +15,19 @@
# facilities (e.g. strerror, locale.h, memmove). SunOS does not comply;
# so, add "-DOLD_ANSI" on SunOS
#
# define LUA_COMPAT2_5 if yous system does need to be compatible with
# version 2.5 (or older)
#
# define LUA_NUM_TYPE if you need numbers to be different from double
# (for instance, -DLUA_NUM_TYPE=float)
#
# define LUA_COMPAT_GC if you need garbage-collect tag methods for tables
# (only for compatibility with previous versions)
CONFIG = -DPOPEN -D_POSIX_SOURCE
#CONFIG = -DLUA_COMPAT2_5 -DOLD_ANSI -DDEBUG
#CONFIG = -DOLD_ANSI -DDEBUG -DLUA_COMPAT_GC
# Compilation parameters
CC = gcc
CWARNS = -Wall -Wmissing-prototypes -Wshadow -pedantic -Wpointer-arith -Wcast-align -Waggregate-return -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-declarations -Wnested-externs
CWARNS = -Wall -Wmissing-prototypes -Wshadow -pedantic -Wpointer-arith -Wcast-align -Waggregate-return -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-declarations -Wnested-externs -Werror
CFLAGS = $(CONFIG) $(CWARNS) -ansi -O2
@ -53,6 +52,7 @@ LUAOBJS = \
lmem.o \
lobject.o \
lparser.o \
lref.o \
lstate.o \
lstring.o \
ltable.o \
@ -99,7 +99,7 @@ clear :
lapi.o: lapi.c lapi.h lua.h lobject.h lauxlib.h ldo.h lstate.h \
luadebug.h lfunc.h lgc.h lmem.h lstring.h ltable.h ltm.h lvm.h
luadebug.h lfunc.h lgc.h lmem.h lref.h lstring.h ltable.h ltm.h lvm.h
lauxlib.o: lauxlib.c lauxlib.h lua.h luadebug.h
lbuffer.o: lbuffer.c lauxlib.h lua.h lmem.h lstate.h lobject.h \
luadebug.h
@ -107,11 +107,11 @@ lbuiltin.o: lbuiltin.c lapi.h lua.h lobject.h lauxlib.h lbuiltin.h \
ldo.h lstate.h luadebug.h lfunc.h lmem.h lstring.h ltable.h ltm.h \
lundump.h lzio.h lvm.h
ldblib.o: ldblib.c lauxlib.h lua.h luadebug.h lualib.h
ldo.o: ldo.c ldo.h lobject.h lua.h lstate.h luadebug.h lfunc.h lgc.h \
ldo.o: ldo.c lauxlib.h lua.h ldo.h lobject.h lstate.h luadebug.h lgc.h \
lmem.h lparser.h lzio.h lstring.h ltm.h lundump.h lvm.h
lfunc.o: lfunc.c lfunc.h lobject.h lua.h lmem.h lstate.h luadebug.h
lgc.o: lgc.c ldo.h lobject.h lua.h lstate.h luadebug.h lfunc.h lgc.h \
lmem.h lstring.h ltable.h ltm.h
lref.h lstring.h ltable.h ltm.h
linit.o: linit.c lua.h lualib.h
liolib.o: liolib.c lauxlib.h lua.h luadebug.h lualib.h
llex.o: llex.c lauxlib.h lua.h llex.h lobject.h lzio.h lmem.h \
@ -119,12 +119,11 @@ llex.o: llex.c lauxlib.h lua.h llex.h lobject.h lzio.h lmem.h \
lmathlib.o: lmathlib.c lauxlib.h lua.h lualib.h
lmem.o: lmem.c lmem.h lstate.h lobject.h lua.h luadebug.h
lobject.o: lobject.c lobject.h lua.h
lparser.o: lparser.c lauxlib.h lua.h ldo.h lobject.h lstate.h \
luadebug.h lfunc.h llex.h lzio.h lmem.h lopcodes.h lparser.h \
lstring.h
lparser.o: lparser.c ldo.h lobject.h lua.h lstate.h luadebug.h lfunc.h \
llex.h lzio.h lmem.h lopcodes.h lparser.h lstring.h
lref.o: lref.c lmem.h lref.h lobject.h lua.h lstate.h luadebug.h
lstate.o: lstate.c lbuiltin.h ldo.h lobject.h lua.h lstate.h \
luadebug.h lfunc.h lgc.h llex.h lzio.h lmem.h lstring.h ltable.h \
ltm.h
luadebug.h lgc.h llex.h lzio.h lmem.h lstring.h ltm.h
lstring.o: lstring.c lmem.h lobject.h lua.h lstate.h luadebug.h \
lstring.h
lstrlib.o: lstrlib.c lauxlib.h lua.h lualib.h
@ -134,7 +133,7 @@ ltm.o: ltm.c lauxlib.h lua.h lmem.h lobject.h lstate.h luadebug.h \
ltm.h
lua.o: lua.c lua.h luadebug.h lualib.h
lundump.o: lundump.c lauxlib.h lua.h lfunc.h lobject.h lmem.h \
lstring.h lundump.h lzio.h
lopcodes.h lstring.h lundump.h lzio.h
lvm.o: lvm.c lauxlib.h lua.h ldo.h lobject.h lstate.h luadebug.h \
lfunc.h lgc.h lmem.h lopcodes.h lstring.h ltable.h ltm.h lvm.h
lfunc.h lgc.h lopcodes.h lstring.h ltable.h ltm.h lvm.h
lzio.o: lzio.c lzio.h

61
manual.tex

@ -1,4 +1,4 @@
% $Id: manual.tex,v 1.32 1999/05/11 20:46:28 roberto Exp roberto $
% $Id: manual.tex,v 1.33 1999/05/27 20:21:03 roberto Exp roberto $
\documentclass[11pt]{article}
\usepackage{fullpage,bnf}
@ -41,7 +41,7 @@ Waldemar Celes
\tecgraf\ --- Computer Science Department --- PUC-Rio
}
\date{{\small \tt\$Date: 1999/05/11 20:46:28 $ $}}
\date{{\small \tt\$Date: 1999/05/27 20:21:03 $ $}}
\maketitle
@ -1273,7 +1273,8 @@ is terminated, returning an error condition.
The only argument to \verb|_ERRORMESSAGE| is a string
describing the error.
The default definition for this function calls \verb|_ALERT|,
The default definition for
this function calls \verb|_ALERT|, \Deffunc{_ALERT}
which prints the message to \verb|stderr| \see{alert}.
The standard I/O library redefines \verb|_ERRORMESSAGE|,
and uses the debug facilities \see{debugI}
@ -1835,6 +1836,8 @@ void lua_unref (int ref);
The function \verb|lua_ref| creates a reference
to the object that is on the top of the stack,
and returns this reference.
For a \nil{} object, the reference is always -1;
otherwise, it is a non-negative integer.
If \verb|lock| is true, the object is \emph{locked}:
this means the object will not be garbage collected.
Note that an unlocked reference may be garbage collected.
@ -2503,26 +2506,32 @@ The following combinations are allowed in describing a character class:
\item[\T{\%s}] --- represents all space characters.
\item[\T{\%u}] --- represents all upper case letters.
\item[\T{\%w}] --- represents all alphanumeric characters.
\item[\T{\%x}] --- represents all hexa-decimal digits.
\item[\T{\%x}] --- represents all hexadecimal digits.
\item[\T{\%z}] --- represents the character with representation 0.
\item[\T{\%\M{x}}] (where \M{x} is any non alphanumeric character) ---
represents the character \M{x}.
This is the standard way to escape the magic characters \verb|()%.[]*-?|.
It is strongly recommended that any control character (even the non magic),
when used to represent itself in a pattern, should be preceded by a \verb|%|.
\item[\T{[char-set]}] ---
Represents the class which is the union of all
characters in char-set.
To include a \verb|]| in char-set, it must be the first character.
A range of characters may be specified by
separating the end characters of the range with a \verb|-|.
If \verb|-| appears as the first or last character of char-set,
then it represents itself.
All classes \verb|%|\emph{x} described above can also be used as
components in a char-set.
All other characters in char-set represent themselves.
E.g., assuming an \emph{ascii} character set,
\verb|[%dA-Fa-f]| specifies the hexa-decimal digits.
E.g., \verb|[%w_]| (or \verb|[_%w]|)
represents all alphanumeric characters plus the underscore,
\verb|[0-7]| represents the octal digits,
and \verb|[0-7%l%-]| represents the octal digits plus
the lower case letters plus the \verb|-| character.
The interaction between ranges and classes is not defined.
Therefore, patterns like \verb|[%a-z]| or \verb|[a-%%]|
have no meaning.
\item[\T{[\^{ }char-set]}] ---
represents the complement of char-set,
where char-set is interpreted as above.
@ -3187,6 +3196,8 @@ accepting commands from standard input until an \verb|EOF|.
Each line entered is immediately executed.
\item[\T{-q}] same as \T{-i}, but without a prompt (quiet mode).
\item[\T{-}] executes \verb|stdin| as a file.
\item[\T{--}] stops the execution of arguments;
all arguments after it are simply passed to the Lua script.
\item[\T{var=value}] sets global \verb|var| with string \verb|"value"|.
\item[\T{filename}] executes file \verb|filename| as a Lua chunk.
\end{description}
@ -3203,6 +3214,37 @@ will first interact with the user until an \verb|EOF|,
then will set \verb|a| to \verb|"test"|,
and finally will run the file \verb|prog.lua|.
All arguments from the command line are passed to the Lua program in
a table called \verb|arg|.
If the command line has the \verb|--| argument,
this argument is at index 0;
the arguments after it get indices 1, 2, \ldots;
and the arguments before it get negative indices.
The field \verb|n| gets the index of the last argument,
and the field \verb|nn| gets the index of the first argument
(always a negative number).
For instance:
\begin{verbatim}
$ lua -e "foreach(arg, print)" -- a b
-1 foreach(arg, print)
-2 -e
-3 lua
0 --
1 a
2 b
nn -3
n 2
\end{verbatim}
If the command line has no \verb|--| argument,
all arguments have negative indices, with the last one at position -1.
As a general rule, if you want to traverse all the
arguments after the \verb|--|, you loop from 1 to \verb|arg.n|
(you can use the \verb|foreachi| function, for instance).
If you want to traverse all arguments,
you loop from \verb|arg.nn| until \verb|arg.n|.
In any case, you may call \verb|exit| at the end of a script,
to stop Lua from running the other arguments.
When in interactive mode,
a multi-line statement can be written finishing intermediate
lines with a backslash (\verb|\|).
@ -3216,6 +3258,7 @@ In Unix systems, Lua scripts can be made into executable programs
by using the \verb|#!| form,
as in \verb|#!/usr/local/bin/lua|.
\section*{Acknowledgments}
The authors would like to thank CENPES/PETROBRAS which,

Loading…
Cancel
Save