blob: 0d9215b9a7411ba38c0c0bbbcba3d5cdd0f2810a [file] [log] [blame]
/*@z29.c:Symbol Table:Declarations, hash()@***********************************/
/* */
/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.24) */
/* COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@cs.usyd.edu.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 2, 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., 59 Temple Place, Suite 330, Boston MA 02111-1307 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.h"
#define MAX_STACK 300 /* size of scope stack */
#define MAX_TAB 1783 /* size of hash table */
#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 %= MAX_TAB; \
}
/*@::InitSym(), PushScope(), PopScope(), SuppressVisible(), etc.@*************/
/* */
/* InitSym() */
/* */
/* Initialize the symbol table to empty. */
/* */
/*****************************************************************************/
void InitSym(void)
{ 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. */
/* */
/*****************************************************************************/
void PushScope(OBJECT x, BOOLEAN npars, BOOLEAN vis)
{ debug3(DST, DD, "[ PushScope(%s, %s, %s)", SymName(x), bool(npars), bool(vis));
assert( suppress_scope == FALSE, "PushScope: suppress_scope!" );
if( scope_top >= MAX_STACK )
{
#if DEBUG_ON
int i;
for( i = 0; i < scope_top; i++ )
Error(29, 1, " scope[%2d] = %s", WARN, &fpos(x), i, SymName(scope[i]));
#endif
Error(29, 2, "scope depth limit exceeded", INTERN, &fpos(x));
}
scope[scope_top] = x;
npars_only[scope_top] = npars;
vis_only[scope_top] = vis;
body_ok[scope_top] = FALSE;
scope_top++;
} /* end PushScope */
void PopScope(void)
{ debug0(DST, DD, "] PopScope()");
assert( scope_top > 0, "PopScope: tried to pop empty scope stack");
assert( suppress_scope == FALSE, "PopScope: suppress_scope!" );
scope_top--;
} /* end PopScope */
/*****************************************************************************/
/* */
/* SuppressVisible() */
/* UnSuppressVisible() */
/* */
/* Make all children of any symbol acceptable, not just the exported ones. */
/* */
/*****************************************************************************/
void SuppressVisible(void)
{ debug0(DST, DD, "[ SuppressVisible()");
suppress_visible = TRUE;
} /* end SuppressVisible */
void UnSuppressVisible(void)
{ 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. */
/* */
/*****************************************************************************/
void SuppressScope(void)
{ debug0(DST, DD, "[ SuppressScope()");
suppress_scope = TRUE;
} /* end SuppressScope */
void UnSuppressScope(void)
{ debug0(DST, DD, "] UnSuppressScope()");
suppress_scope = FALSE;
} /* end UnSuppressScope */
/*****************************************************************************/
/* */
/* SwitchScope(sym) */
/* UnSwitchScope(sym) */
/* */
/* Switch to the scope of sym (if nilobj, StartSym); and switch back again. */
/* */
/*****************************************************************************/
void SwitchScope(OBJECT sym)
{ int i;
OBJECT new_scopes[MAX_STACK];
if( sym == nilobj ) 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);
}
}
void UnSwitchScope(OBJECT sym)
{ if( sym == nilobj ) PopScope();
else
{ while( sym != StartSym )
{ PopScope();
sym = enclosing(sym);
}
}
}
/*****************************************************************************/
/* */
/* BodyParAllowed() */
/* BodyParNotAllowed() */
/* */
/* Allow or disallow invocations of the body parameter of the current tos. */
/* */
/*****************************************************************************/
void BodyParAllowed(void)
{ debug0(DST, DD, "BodyParAllowed()");
body_ok[scope_top-1] = TRUE;
} /* end BodyParAllowed */
void BodyParNotAllowed(void)
{ debug0(DST, DD, "BodyParNotAllowed()");
body_ok[scope_top-1] = FALSE;
} /* end BodyParNotAllowed */
/*****************************************************************************/
/* */
/* DebugScope(void) */
/* */
/* Debug print of current scope stack */
/* */
/*****************************************************************************/
void DebugScope(void)
{ int i;
if( suppress_scope )
{
debug0(DST, D, "suppressed");
}
else for( i = 0; i < scope_top; i++ )
{ debug6(DST, D, "%s %s%s%s%s%s",
i == scope_top - 1 ? "->" : " ",
SymName(scope[i]),
npars_only[i] ? " npars_only" : "",
vis_only[i] ? " vis_only" : "",
body_ok[i] ? " body_ok" : "",
i == scope_top - 1 && suppress_visible ? " suppress_visible" : "");
}
} /* end DebugScope */
/*@::ScopeSnapshot()@*********************************************************/
/* */
/* OBJECT GetScopeSnapshot() */
/* LoadScopeSnapshot(ss) */
/* ClearScopeSnapshot(ss) */
/* */
/* A scope snapshot is a complete record of the state of the scope stack */
/* at some moment. These routines allow you to take a scope snapshot, */
/* then subsequently load it (i.e. make it the current scope), then */
/* subsequently clear it (i.e. return to whatever was before the Load). */
/* */
/*****************************************************************************/
OBJECT GetScopeSnapshot()
{ OBJECT ss, x; int i;
New(ss, ACAT);
for( i = scope_top-1; scope[i] != StartSym; i-- )
{
New(x, SCOPE_SNAPSHOT);
Link(ss, x);
Link(x, scope[i]);
ss_npars_only(x) = npars_only[i];
ss_vis_only(x) = vis_only[i];
ss_body_ok(x) = body_ok[i];
}
ss_suppress(ss) = suppress_visible;
return ss;
} /* end GetScopeSnapshot */
void LoadScopeSnapshot(OBJECT ss)
{ OBJECT link, x, sym; BOOLEAN tmp;
assert( type(ss) == ACAT, "LoadScopeSnapshot: type(ss)!" );
PushScope(StartSym, FALSE, FALSE);
for( link = LastDown(ss); link != ss; link = PrevDown(link) )
{ Child(x, link);
assert( type(x) == SCOPE_SNAPSHOT, "LoadScopeSnapshot: type(x)!" );
Child(sym, Down(x));
PushScope(sym, ss_npars_only(x), ss_vis_only(x));
body_ok[scope_top-1] = ss_body_ok(x);
}
tmp = suppress_visible;
suppress_visible = ss_suppress(ss);
ss_suppress(ss) = tmp;
debug0(DST, D, "after LoadScopeSnapshot, scope is:")
ifdebug(DST, D, DebugScope());
} /* end LoadScopeSnapshot */
void ClearScopeSnapshot(OBJECT ss)
{
while( scope[scope_top-1] != StartSym )
scope_top--;
scope_top--;
suppress_visible = ss_suppress(ss);
} /* end ClearScopeSnapshot */
/*@::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(FULL_CHAR *str, unsigned char xtype, FILE_POS *xfpos,
unsigned char xprecedence, BOOLEAN xindefinite, BOOLEAN xrecursive,
unsigned xpredefined, OBJECT xenclosing, OBJECT xbody)
{ register int sum, rlen;
register unsigned char *x;
OBJECT p, q, s, tmp, link, entry, plink; int len;
debug3(DST, DD, "InsertSym( %s, %s, in %s )",
Image(xtype), str, SymName(xenclosing));
if( !LexLegalName(str) )
Error(29, 3, "invalid symbol name %s", WARN, xfpos, str);
New(s, xtype);
FposCopy(fpos(s), *xfpos);
has_body(s) = FALSE;
filter(s) = nilobj;
use_invocation(s) = nilobj;
imports(s) = nilobj;
imports_encl(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) = nilobj;
uses(s) = nilobj;
marker(s) = nilobj;
cross_sym(s) = nilobj;
is_extern_target(s) = FALSE;
uses_extern_target(s)= FALSE;
visible(s) = FALSE;
uses_galley(s) = FALSE;
horiz_galley(s) = ROWM;
has_compulsory(s) = 0;
is_compulsory(s) = FALSE;
uses_count(s) = 0;
dirty(s) = FALSE;
if( enclosing(s) != nilobj && type(enclosing(s)) == NPAR )
dirty(s) = 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;
/* assign a code letter between a and z to any NPAR symbol */
if( type(s) == NPAR )
{ if( LastDown(enclosing(s)) != enclosing(s) )
{ Child(tmp, LastDown(enclosing(s)));
if( type(tmp) == NPAR )
{ if( npar_code(tmp) == 'z' || npar_code(tmp) == ' ' )
npar_code(s) = ' ';
else
npar_code(s) = npar_code(tmp)+1;
}
else
npar_code(s) = 'a';
}
else npar_code(s) = 'a';
}
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 @Target is found after @Key, take note of external target */
if( has_key(enclosing(s)) && xbody != nilobj && is_cross(type(xbody)) )
{ 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) = is_tag(s) = FALSE;
has_key(s) = is_key(s) = FALSE;
has_optimize(s) = is_optimize(s) = FALSE;
has_merge(s) = is_merge(s) = FALSE;
has_enclose(s) = is_enclose(s) = FALSE;
if( enclosing(s) != nilobj && type(enclosing(s)) == LOCAL )
{
if( StringEqual(str, KW_TAG) )
is_tag(s) = has_tag(enclosing(s)) = dirty(enclosing(s)) = TRUE;
if( StringEqual(str, KW_OPTIMIZE) )
is_optimize(s) = has_optimize(enclosing(s)) = TRUE;
if( StringEqual(str, KW_KEY) )
{ is_key(s) = has_key(enclosing(s)) = dirty(enclosing(s)) = TRUE;
/* if @Key is found after @Target, take note of external target */
for( link=Down(enclosing(s)); link!=enclosing(s); link=NextDown(link) )
{ Child(p, link);
if( is_target(p) && sym_body(p)!=nilobj && is_cross(type(sym_body(p))) )
{ OBJECT sym;
Child(sym, Down(sym_body(p)));
if( type(sym) == CLOSURE )
{ is_extern_target(actual(sym)) = TRUE;
uses_extern_target(actual(sym)) = TRUE;
}
}
}
}
if( StringEqual(str, KW_MERGE) )
is_merge(s) = has_merge(enclosing(s)) = TRUE;
if( StringEqual(str, KW_ENCLOSE) )
is_enclose(s) = has_enclose(enclosing(s)) = TRUE;
}
if( StringEqual(str, KW_FILTER) )
{ if( type(s) != LOCAL || enclosing(s) == StartSym )
Error(29, 4, "%s must be a local definition", WARN, &fpos(s), str);
else if( !has_rpar(enclosing(s)) )
Error(29, 14, "%s must lie within a symbol with a right parameter",
WARN, &fpos(s), KW_FILTER);
else
{ filter(enclosing(s)) = s;
precedence(enclosing(s)) = FILTER_PREC;
}
}
if( type(s) == RPAR && has_body(enclosing(s)) &&
(is_tag(s) || is_key(s) || is_optimize(s)) )
Error(29, 5, "a body parameter may not be named %s", WARN, &fpos(s), str);
if( type(s) == RPAR && has_target(enclosing(s)) &&
(is_tag(s) || is_key(s) || is_optimize(s)) )
Error(29, 6, "the right parameter of a galley may not be called %s",
WARN, &fpos(s), str);
len = StringLength(str);
hash(str, len, sum);
ifdebug(DST, DD, 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(29, 7, "symbol %s previously defined at%s",
WARN, &fpos(s), str, EchoFilePos(&fpos(q)) );
if( AltErrorFormat )
{
Error(29, 13, "symbol %s previously defined here",
WARN, &fpos(q), str);
}
break;
}
}
goto wrapup;
}
}
/* need a new OBJECT as well as s */
NewWord(p, WORD, len, xfpos);
length(p) = len;
StringCopy(string(p), str);
Link(entry, p);
wrapup:
Link(p, s);
if( enclosing(s) != nilobj ) Link(enclosing(s), s);
debug2(DST, DD, "InsertSym Link(%s, %s) and returning.",
SymName(enclosing(s)), SymName(s));
return s;
} /* end InsertSym */
/*****************************************************************************/
/* */
/* InsertAlternativeName(str, s, xfpos) */
/* */
/* Insert an alternative name for symbol s. */
/* */
/*****************************************************************************/
void InsertAlternativeName(FULL_CHAR *str, OBJECT s, FILE_POS *xfpos)
{ register int sum, rlen;
register unsigned char *x;
int len;
OBJECT entry, link, plink, p, q;
debug3(DST, DD, "InsertAlternativeName(%s, %s, %s)",
str, SymName(s), EchoFilePos(xfpos));
len = StringLength(str);
hash(str, len, sum);
ifdebug(DST, DD, 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(29, 12, "symbol name %s previously defined at%s",
WARN, &fpos(s), str, EchoFilePos(&fpos(q)) );
break;
}
}
goto wrapup;
}
}
/* need a new OBJECT as well as s */
NewWord(p, WORD, len, xfpos);
length(p) = len;
StringCopy(string(p), str);
Link(entry, p);
wrapup:
Link(p, s);
/* not for copies if( enclosing(s) != nilobj ) Link(enclosing(s), s); */
debug0(DST, DD, "InsertAlternativeName returning.");
} /* end InsertAlternativeName */
/*@::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 nilobj. */
/* */
/*****************************************************************************/
OBJECT SearchSym(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 )
{
debug1(DST, DDD, " found %s", string(p));
s = scope_top;
do
{ s--;
for( link = Down(p); link != p; link = NextDown(link) )
{ Child(q, link);
{ debugcond4(DST, DDD, enclosing(q) == scope[s],
" !npars_only[s] = %s, !vis_only[s] = %s, body_ok[s] = %s, !ss = %s",
bool(!npars_only[s]), bool(!vis_only[s]), bool(body_ok[s]),
bool(!suppress_scope));
}
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_visible )
&& (!suppress_scope || StringEqual(string(p), KW_INCLUDE) ||
StringEqual(string(p), KW_SYSINCLUDE))
)
{ debug3(DST, DD, "SearchSym returning %s %s%%%s",
Image(type(q)), SymName(q), SymName(enclosing(q)));
return q;
}
}
} while( scope[s] != StartSym );
}
}
rlen = len;
}
debug0(DST, DDD, "SearchSym returning <nilobj>");
return nilobj;
} /* end SearchSym */
/*****************************************************************************/
/* */
/* FULL_CHAR *SymName(s) */
/* */
/* Return the string value of the name of symbol s. */
/* */
/*****************************************************************************/
FULL_CHAR *SymName(OBJECT s)
{ OBJECT p;
if( s == nilobj ) return AsciiToFull("<nilobj>");
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(OBJECT x, FULL_CHAR *str)
{ OBJECT stack[20]; int i;
static FULL_CHAR buff[MAX_BUFF], *sname;
if( x == nilobj ) return AsciiToFull("<nilobj>");
assert( enclosing(x) != nilobj, "FullSymName: enclosing(x) == nilobj!" );
for( i = 0; enclosing(x) != nilobj && 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_BUFF )
Error(29, 8, "full name of symbol is too long", FATAL, &fpos(x));
StringCat(buff, sname);
StringCat(buff, str);
}
sname = SymName(stack[0]);
if( StringLength(sname) + StringLength(buff) >= MAX_BUFF )
Error(29, 9, "full name of symbol is too long", FATAL, &fpos(x));
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(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(29, 10, "symbol %s has missing %s", FATAL, &fpos(s),
SymName(s), Image(typ));
return nilobj;
} /* end ChildSym */
/*****************************************************************************/
/* */
/* OBJECT ChildSymWithCode(s, code) */
/* */
/* Find the child of symbol s with the given npar code, else nil. */
/* */
/*****************************************************************************/
OBJECT ChildSymWithCode(OBJECT s, unsigned char code)
{ OBJECT link, y;
for( link = Down(actual(s)); link != actual(s); link = NextDown(link) )
{ Child(y, link);
if( type(y) == NPAR && enclosing(y) == actual(s) && npar_code(y) == code )
return y;
}
Error(29, 11, "symbol %s has erroneous code %c (database out of date?)",
FATAL, &fpos(s), SymName(actual(s)), (char) code);
return nilobj;
} /* end ChildSym */
/*@::CheckSymSpread(), DeleteSymBody()@***************************************/
/* */
/* CheckSymSpread() */
/* */
/* Check the spread of symbols through the hash table. */
/* */
/*****************************************************************************/
#if DEBUG_ON
void CheckSymSpread(void)
{ int i, j, sum, usum; OBJECT entry, plink;
debug2(DST, DD, "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 void DeleteSymBody(OBJECT s)
{ OBJECT t;
debug1(DST, DDD, "DeleteSymBody( %s )", SymName(s));
switch( type(s) )
{
case MACRO: while( sym_body(s) != nilobj )
{ t = sym_body(s);
sym_body(s) = Delete(sym_body(s), PARENT);
Dispose(t);
}
break;
case LPAR:
case NPAR:
case RPAR:
case LOCAL: if( sym_body(s) != nilobj ) DisposeObject(sym_body(s));
break;
default: assert1(FALSE, "DeleteSymBody:", 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. */
/* */
/*****************************************************************************/
void DeleteEverySym(void)
{ int i, j, load, cost; OBJECT p, plink, link, x, entry;
debug0(DST, DD, "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) != nilobj )
{ tmp = base_uses(x); base_uses(x) = next(tmp);
PutMem(tmp, USES_SIZE);
}
while( uses(x) != nilobj )
{ 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, DD, "size = %d, items = %d (%d%%), probes = %.1f",
MAX_TAB, load, (100*load)/MAX_TAB, (float) cost/load);
}
else
{ debug1(DST, DD, "table size = %d, no entries in table", MAX_TAB);
}
debug0(DST, DD, "DeleteEverySym returning.");
} /* end DeleteEverySym */
#endif