/*@z29.c:Symbol Table:Declarations, hash()@***********************************/ /* */ /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */ /* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */ /* */ /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */ /* School of Information Technologies */ /* 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 3, 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]; /* hash table spread */ static int sym_count; /* 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]; #if DEBUG_ON for( i = 0; i < MAX_TAB; i++ ) sym_spread[i] = 0; sym_count = 0; #endif } /* 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, 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(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, 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(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 "); 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(""); 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(""); 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; fprintf(stderr, "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, "%s", STR_NEWLINE); } fprintf(stderr, "average length counting duplicate names = %.1f", (float) sum / sym_count); fprintf(stderr, "%s", STR_NEWLINE); fprintf(stderr, "average length not counting duplicate names = %.1f", (float) usum / sym_count); fprintf(stderr, "%s", STR_NEWLINE); } /* 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