home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
APPS
/
lout2.lzh
/
LOUT2
/
z29.c
< prev
next >
Wrap
Text File
|
1994-01-23
|
24KB
|
591 lines
/*@z29.c:Symbol Table:Declarations, hash()@***********************************/
/* */
/* LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05) */
/* COPYRIGHT (C) 1993 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@cs.su.oz.au) */
/* Basser Department of Computer Science */
/* The University of Sydney 2006 */
/* AUSTRALIA */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 1, or (at your option) */
/* any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/* FILE: z29.c */
/* MODULE: Symbol Table */
/* EXTERNS: InitSym(), PushScope(), PopScope(), SuppressVisible(), */
/* UnSuppressVisible(), SuppressScope(), UnSuppressScope(), */
/* SwitchScope(), UnSwitchScope(), BodyParAllowed(), */
/* BodyParNotAllowed(), InsertSym(), SearchSym(), */
/* SymName(), FullSymName(), ChildSym(), CheckSymSpread(), */
/* DeleteEverySym() */
/* */
/*****************************************************************************/
#include "externs"
#define MAX_STACK 40 /* size of scope stack */
#define MAX_TAB 1024 /* size of hash table */
#define TAB_MASK 0x3FF /* i & TAB_MASK == i % MAX_TAB */
#define length(x) word_font(x)
static OBJECT scope[MAX_STACK]; /* the scope stack */
static BOOLEAN npars_only[MAX_STACK]; /* look for NPAR exc */
static BOOLEAN vis_only[MAX_STACK]; /* look for visibles */
static BOOLEAN body_ok[MAX_STACK]; /* look for body par */
static BOOLEAN suppress_scope; /* suppress scoping */
static BOOLEAN suppress_visible; /* suppress visible */
static int scope_top; /* scope stack top */
static struct { OBJECT f1, f2; } symtab[MAX_TAB]; /* the hash table */
#if DEBUG_ON
static int sym_spread[MAX_TAB] = { 0 }; /* hash table spread */
static int sym_count = 0; /* symbol count */
#endif
/*****************************************************************************/
/* */
/* #define hash(str, len, val) */
/* */
/* Set val to the hash value of string str, which has length len. */
/* The hash function is just the character sum mod MAX_TAB. */
/* This definition assumes that working variables rlen and x exist. */
/* */
/*****************************************************************************/
#define hash(str, len, val) \
{ rlen = len; \
x = str; \
val = *x++; \
while( --rlen ) val += *x++; \
val &= TAB_MASK; \
}
/*@::InitSym(), PushScope(), PopScope(), SuppressVisible(), etc.@*************/
/* */
/* InitSym() */
/* */
/* Initialize the symbol table to empty. */
/* */
/*****************************************************************************/
InitSym()
{ int i;
scope_top = 0;
suppress_scope = FALSE;
suppress_visible = FALSE;
for( i = 0; i < MAX_TAB; i++ )
symtab[i].f1 = symtab[i].f2 = (OBJECT) &symtab[i];
} /* end InitSym */
/*****************************************************************************/
/* */
/* PushScope(x, npars, vis) */
/* PopScope() */
/* */
/* Add or remove an OBJECT x (which must be in the symbol table) to or from */
/* the scope stack. If npars is TRUE, only the named parameters of x are */
/* added to scope. If vis is TRUE, only visible locals and parameters are */
/* added. */
/* */
/*****************************************************************************/
PushScope(x, npars, vis)
OBJECT x; BOOLEAN npars, vis;
{ debug2(DST, DD, "[ PushScope( %s, %s )", SymName(x), bool(npars));
assert( suppress_scope == FALSE, "PushScope: suppress_scope!" );
if( scope_top >= MAX_STACK )
{ int i;
for( i = 0; i < scope_top; i++ )
debug2(DST, D, " scope[%2d] = %s", i, SymName(scope[i]));
Error(INTERN, &fpos(x), "scope depth limit exceeded");
}
scope[scope_top] = x;
npars_only[scope_top] = npars;
vis_only[scope_top] = vis;
body_ok[scope_top] = FALSE;
scope_top++;
} /* end PushScope */
PopScope()
{ debug0(DST, DD, "] PopScope()");
assert( scope_top > 0, "tried to pop empty scope stack");
assert( suppress_scope == FALSE, "PopScope: suppress_scope!" );
scope_top--;
} /* end PopScope */
/*****************************************************************************/
/* */
/* SuppressVisible() */
/* UnSuppressVisible() */
/* */
/* Suppress all scopes (so that all calls to SearchSym fail); and undo it. */
/* */
/*****************************************************************************/
SuppressVisible()
{ debug0(DST, DD, "[ SuppressVisible()");
suppress_visible = TRUE;
} /* end SuppressVisible */
UnSuppressVisible()
{ debug0(DST, DD, "] UnSuppressVisible()");
suppress_visible = FALSE;
} /* end UnSuppressVisible */
/*@::SuppressScope(), UnSuppressScope(), SwitchScope(), UnswitchScope()@******/
/* */
/* SuppressScope() */
/* UnSuppressScope() */
/* */
/* Suppress all scopes (so that all calls to SearchSym fail); and undo it. */
/* */
/*****************************************************************************/
SuppressScope()
{ debug0(DST, DD, "[ SuppressScope()");
suppress_scope = TRUE;
} /* end SuppressScope */
UnSuppressScope()
{ debug0(DST, DD, "] UnSuppressScope()");
suppress_scope = FALSE;
} /* end UnSuppressScope */
/*****************************************************************************/
/* */
/* SwitchScope(sym) */
/* UnSwitchScope(sym) */
/* */
/* Switch to the scope of sym (if nil, StartSym); and switch back again. */
/* */
/*****************************************************************************/
SwitchScope(sym)
OBJECT sym;
{ int i;
OBJECT new_scopes[MAX_STACK];
if( sym == nil ) PushScope(StartSym, FALSE, FALSE);
else
{ i = 0;
while( sym != StartSym )
{ new_scopes[i++] = enclosing(sym);
sym = enclosing(sym);
}
while( i > 0 ) PushScope(new_scopes[--i], FALSE, FALSE);
}
}
UnSwitchScope(sym)
OBJECT sym;
{ if( sym == nil ) PopScope();
else
{ while( sym != StartSym )
{ PopScope();
sym = enclosing(sym);
}
}
}
/*****************************************************************************/
/* */
/* BodyParAllowed() */
/* BodyParNotAllowed() */
/* */
/* Allow or disallow invokations of the body parameter of the current tos. */
/* */
/*****************************************************************************/
BodyParAllowed()
{ debug0(DST, DD, "BodyParAllowed()");
body_ok[scope_top-1] = TRUE;
} /* end BodyParAllowed */
BodyParNotAllowed()
{ debug0(DST, DD, "BodyParNotAllowed()");
body_ok[scope_top-1] = FALSE;
} /* end BodyParNotAllowed */
/*@::InsertSym()@*************************************************************/
/* */
/* OBJECT InsertSym(str, xtype, xfpos, xprecedence, indefinite, xrecursive, */
/* xpredefined, xenclosing, xbody) */
/* */
/* Insert a new symbol into the table. Its string value is str. */
/* Initialise the symbol as the parameters indicate. */
/* Return a pointer to the new symbol. */
/* If str is not a valid symbol name, InsertSym prints an error */
/* message and does not insert the symbol. */
/* */
/*****************************************************************************/
OBJECT InsertSym(str, xtype, xfpos, xprecedence, xindefinite, xrecursive,
xpredefined, xenclosing, xbody)
FULL_CHAR *str; unsigned char xtype;
FILE_POS *xfpos; unsigned char xprecedence;
BOOLEAN xindefinite, xrecursive; unsigned xpredefined;
OBJECT xenclosing, xbody;
{ register int sum, rlen;
register unsigned char *x;
OBJECT p, q, s, link, entry, plink; int len;
debug3(DST, DD, "InsertSym( %s, %s, in %s )",
Image(xtype), str, SymName(xenclosing));
if( !LexLegalName(str) ) Error(WARN, xfpos, "invalid symbol name %s", str);
s = New(xtype);
FposCopy(fpos(s), *xfpos);
has_body(s) = FALSE;
right_assoc(s) = TRUE;
precedence(s) = xprecedence;
indefinite(s) = xindefinite;
recursive(s) = xrecursive;
predefined(s) = xpredefined;
enclosing(s) = xenclosing;
sym_body(s) = xbody;
base_uses(s) = nil;
uses(s) = nil;
marker(s) = nil;
cross_sym(s) = nil;
is_extern_target(s) = FALSE;
uses_extern_target(s) = FALSE;
visible(s) = FALSE;
uses_galley(s) = FALSE;
uses_count(s) = 0;
dirty(s) = FALSE;
if( enclosing(s) != nil && type(enclosing(s)) == NPAR )
dirty(enclosing(s)) = TRUE;
has_par(s) = FALSE;
has_lpar(s) = FALSE;
has_rpar(s) = FALSE;
if( is_par(type(s)) ) has_par(enclosing(s)) = TRUE;
if( type(s) == LPAR ) has_lpar(enclosing(s)) = TRUE;
if( type(s) == RPAR ) has_rpar(enclosing(s)) = TRUE;
has_target(s) = FALSE;
force_target(s) = FALSE;
if( !StringEqual(str, KW_TARGET) ) is_target(s) = FALSE;
else
{ is_target(s) = has_target(enclosing(s)) = TRUE;
if( has_key(enclosing(s)) && xbody != nil && type(xbody) == CROSS )
{ if( LastDown(xbody) != Down(xbody) )
{ OBJECT sym;
Child(sym, Down(xbody));
if( type(sym) == CLOSURE )
{ is_extern_target(actual(sym)) = TRUE;
uses_extern_target(actual(sym)) = TRUE;
}
}
}
}
has_tag(s) = FALSE;
if( !StringEqual(str, KW_TAG) ) is_tag(s) = FALSE;
else is_tag(s) = has_tag(enclosing(s)) = dirty(enclosing(s)) = TRUE;
has_key(s) = FALSE;
if( !StringEqual(str, KW_KEY) ) is_key(s) = FALSE;
else is_key(s) = has_key(enclosing(s)) = TRUE;
if( type(s) == RPAR && has_body(enclosing(s)) && (is_tag(s) || is_key(s)) )
Error(WARN, &fpos(s), "a body parameter may not be named %s", str);
if( type(s) == RPAR && has_target(enclosing(s)) && (is_tag(s) || is_key(s)) )
Error(WARN,&fpos(s), "the right parameter of a galley may not be %s", str);
len = StringLength(str);
hash(str, len, sum);
ifdebug(DST, D, sym_spread[sum]++; sym_count++);
entry = (OBJECT) &symtab[sum];
for( plink = Down(entry); plink != entry; plink = NextDown(plink) )
{ Child(p, plink);
if( length(p) == len && StringEqual(str, string(p)) )
{ for( link = Down(p); link != p; link = NextDown(link) )
{ Child(q, link);
if( enclosing(s) == enclosing(q) )
{ Error(WARN, &fpos(s), "symbol %s previously defined at%s",
str, EchoFilePos(&fpos(q)) );
break;
}
}
goto wrapup;
}
}
/* need a new OBJECT as well as s */
p = NewWord(WORD, len, xfpos);
length(p) = len;
StringCopy(string(p), str);
Link(entry, p);
wrapup:
Link(p, s);
if( enclosing(s) != nil ) Link(enclosing(s), s);
debug2(DST, DD, "InsertSym Link(%s, %s) and returning.",
SymName(enclosing(s)), SymName(s));
return s;
} /* end InsertSym */
/*@::SearchSym(), SymName()@**************************************************/
/* */
/* OBJECT SearchSym(str, len) */
/* */
/* Search the symbol table for str, with length len, and return an */
/* OBJECT referencing the entry if found. Otherwise return nil. */
/* */
/*****************************************************************************/
OBJECT SearchSym(str, len)
FULL_CHAR *str; int len;
{ register int rlen, sum;
register FULL_CHAR *x, *y;
OBJECT p, q, link, plink, entry;
int s;
debug2(DST, DDD, "SearchSym( %c..., %d )", str[0], len);
hash(str, len, sum);
rlen = len;
entry = (OBJECT) &symtab[sum];
for( plink = Down(entry); plink != entry; plink = NextDown(plink) )
{ Child(p, plink);
if( rlen == length(p) )
{ x = str; y = string(p);
do; while( *x++ == *y++ && --rlen );
if( rlen == 0 )
{ s = scope_top;
do
{ s--;
for( link = Down(p); link != p; link = NextDown(link) )
{ Child(q, link);
if( enclosing(q) == scope[s]
&& (!npars_only[s] || type(q) == NPAR)
&& (!vis_only[s] || visible(q) || suppress_visible )
&& (body_ok[s] || type(q)!=RPAR || !has_body(enclosing(q)) )
&& !suppress_scope )
{ debug1(DST, DDD, "SearchSym returning %s", Image(type(q)));
return q;
}
}
} while( scope[s] != StartSym );
}
}
rlen = len;
}
debug0(DST, DDD, "SearchSym returning <nil>");
return nil;
} /* end SearchSym */
/*****************************************************************************/
/* */
/* FULL_CHAR *SymName(s) */
/* */
/* Return the string value of the name of symbol s. */
/* */
/*****************************************************************************/
FULL_CHAR *SymName(s)
OBJECT s;
{ OBJECT p;
if( s == nil ) return AsciiToFull("<nil>");
Parent(p, Up(s));
assert( is_word(type(p)), "SymName: !is_word(type(p))!" );
return string(p);
} /* end SymName */
/*@::FullSymName(), ChildSym()@***********************************************/
/* */
/* FULL_CHAR *FullSymName(x, str) */
/* */
/* Return the path name of symbol x. with str separating each entry. */
/* */
/*****************************************************************************/
FULL_CHAR *FullSymName(x, str)
OBJECT x; FULL_CHAR *str;
{ OBJECT stack[20]; int i;
static FULL_CHAR buff[MAX_LINE], *sname;
if( x == nil ) return AsciiToFull("<nil>");
assert( enclosing(x) != nil, "FullSymName: enclosing(x) == nil!" );
for( i = 0; enclosing(x) != nil && i < 20; i++ )
{ stack[i] = x;
x = enclosing(x);
}
StringCopy(buff, STR_EMPTY);
for( i--; i > 0; i-- )
{ sname = SymName(stack[i]);
if( StringLength(sname)+StringLength(str)+StringLength(buff) >= MAX_LINE )
Error(FATAL, &fpos(x), "full name of symbol is too long");
StringCat(buff, sname);
StringCat(buff, str);
}
sname = SymName(stack[0]);
if( StringLength(sname) + StringLength(buff) >= MAX_LINE )
Error(FATAL, &fpos(x), "full name of symbol is too long");
StringCat(buff, sname);
return buff;
} /* end FullSymName */
/*****************************************************************************/
/* */
/* OBJECT ChildSym(s, typ) */
/* */
/* Find the child of symbol s of type typ, either LPAR or RPAR. */
/* */
/*****************************************************************************/
OBJECT ChildSym(s, typ)
OBJECT s; unsigned typ;
{ OBJECT link, y;
for( link = Down(s); link != s; link = NextDown(link) )
{ Child(y, link);
if( type(y) == typ && enclosing(y) == s ) return y;
}
Error(INTERN, &fpos(s), "Symbol %s has missing %s", SymName(s), Image(typ));
return nil;
} /* end ChildSym */
/*@::CheckSymSpread(), DeleteSymBody()@***************************************/
/* */
/* CheckSymSpread() */
/* */
/* Check the spread of symbols through the hash table. */
/* */
/*****************************************************************************/
#if DEBUG_ON
CheckSymSpread()
{ int i, j, sum, usum; OBJECT entry, plink;
debug2(DST, D, "Symbol table spread (table size = %d, symbols = %d):",
MAX_TAB, sym_count);
usum = sum = 0;
for( i = 0; i < MAX_TAB; i++ )
{ fprintf(stderr, "%4d: ", i);
for( j = 1; j <= sym_spread[i]; j++ )
{ fprintf(stderr, ".");
sum += j;
}
entry = (OBJECT) &symtab[i];
for( plink=Down(entry), j=1; plink != entry; plink=NextDown(plink), j++ )
{ fprintf(stderr, "+");
usum += j;
}
fprintf(stderr, "\n");
}
fprintf(stderr, "average length counting duplicate names = %.1f\n",
(float) sum / sym_count);
fprintf(stderr, "average length not counting duplicate names = %.1f\n",
(float) usum / sym_count);
} /* end CheckSymSpread */
/*****************************************************************************/
/* */
/* static DeleteSymBody(s) */
/* */
/* Delete the body of symbol s. */
/* */
/*****************************************************************************/
static DeleteSymBody(s)
OBJECT s;
{ debug1(DST, DDD, "DeleteSymBody( %s )", SymName(s));
switch( type(s) )
{
case MACRO: while( sym_body(s) != nil )
sym_body(s) = DeleteAndDispose(sym_body(s), PARENT);
break;
case LPAR:
case NPAR:
case RPAR:
case LOCAL: if( sym_body(s) != nil ) DisposeObject(sym_body(s));
break;
default: Error(INTERN,no_fpos, "unknown symbol type %s",Image(type(s)));
break;
}
debug0(DST, DDD, "DeleteSymBody returning.");
} /* end DeleteSymBody */
/*@::DeleteEverySym()@********************************************************/
/* */
/* DeleteEverySym() */
/* */
/* Delete every symbol in the symbol table. */
/* Note that we first delete all bodies, then the symbols themselves. */
/* This is so that the closures within the bodies have well-defined */
/* actual() pointers, even while the symbol table is being disposed. */
/* If this is not done, debug output during the disposal gets confused. */
/* */
/*****************************************************************************/
DeleteEverySym()
{ int i, j, load, cost; OBJECT p, plink, link, x, entry;
debug0(DST, D, "DeleteEverySym()");
/* dispose the bodies of all symbols */
for( i = 0; i < MAX_TAB; i++ )
{ entry = (OBJECT) &symtab[i];
for( plink = Down(entry); plink != entry; plink = NextDown(plink) )
{ Child(p, plink);
for( link = Down(p); link != p; link = NextDown(link) )
{ Child(x, link); DeleteSymBody(x);
/* *** will not work now
while( base_uses(x) != nil )
{ tmp = base_uses(x); base_uses(x) = next(tmp);
PutMem(tmp, USES_SIZE);
}
while( uses(x) != nil )
{ tmp = uses(x); uses(x) = next(tmp);
PutMem(tmp, USES_SIZE);
}
*** */
}
}
}
/* dispose the symbol name strings, gather statistics, and print them */
load = cost = 0;
for( i = 0; i < MAX_TAB; i++ )
{ j = 1; entry = (OBJECT) &symtab[i];
while( Down(entry) != entry )
{ load += 1; cost += j; j += 1;
DisposeChild(Down(entry));
}
}
if( load > 0 ) debug4(DST, D, "size = %d, items = %d (%d%%), probes = %.1f",
MAX_TAB, load, (100*load)/MAX_TAB, (float) cost/load);
else debug1(DST, D, "table size = %d, no entries in table", MAX_TAB);
debug0(DST, D, "DeleteEverySym returning.");
} /* end DeleteEverySym */
#endif