jwasm/symbols.c
2014-06-18 19:16:56 +04:00

854 lines
26 KiB
C

/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: symbol table access
*
****************************************************************************/
#include <time.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "segment.h"
#include "extern.h"
#include "fixup.h"
#include "fastpass.h"
#include "myassert.h"
#include "macro.h"
#include "types.h"
#include "proc.h"
#include "input.h"
#if defined(__WATCOMC__) && !defined(__FLAT__)
#define HASH_MAGNITUDE 12 /* for 16bit model */
#else
#define HASH_MAGNITUDE 15 /* is 15 since v1.94, previously 12 */
#endif
/* size of global hash table for symbol table searches. This affects
* assembly speed.
*/
#if HASH_MAGNITUDE==12
#define GHASH_TABLE_SIZE 2003
#else
#define GHASH_TABLE_SIZE 8009
#endif
/* size of local hash table */
#define LHASH_TABLE_SIZE 127
/* use memcpy()/memcmpi() directly?
* this may speed-up things, but not with OW.
* MSVC is a bit faster then.
*/
#define USEFIXSYMCMP 0 /* 1=don't use a function pointer for string compare */
#define USESTRFTIME 0 /* 1=use strftime() */
#if USEFIXSYMCMP
#define SYMCMP( x, y, z ) ( ModuleInfo.case_sensitive ? memcmp( x, y, z ) : _memicmp( x, y, z ) )
#else
#define SYMCMP( x, y, z ) SymCmpFunc( x, y, z )
#endif
extern struct asym *FileCur; /* @FileCur symbol */
extern struct asym *LineCur; /* @Line symbol */
extern struct asym *symCurSeg;/* @CurSeg symbol */
extern void UpdateLineNumber( struct asym *, void * );
extern void UpdateWordSize( struct asym *, void * );
extern void UpdateCurPC( struct asym *sym, void *p );
static struct asym *gsym_table[ GHASH_TABLE_SIZE ];
static struct asym *lsym_table[ LHASH_TABLE_SIZE ];
StrCmpFunc SymCmpFunc;
static struct asym **gsym; /* pointer into global hash table */
static struct asym **lsym; /* pointer into local hash table */
static unsigned SymCount; /* Number of symbols in global table */
static char szDate[12]; /* value of @Date symbol */
static char szTime[12]; /* value of @Time symbol */
#if USESTRFTIME
#if defined(__WATCOMC__) || defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
static const char szDateFmt[] = "%D"; /* POSIX date (mm/dd/yy) */
static const char szTimeFmt[] = "%T"; /* POSIX time (HH:MM:SS) */
#else
/* v2.04: MS VC won't understand POSIX formats */
static const char szDateFmt[] = "%x"; /* locale's date */
static const char szTimeFmt[] = "%X"; /* locale's time */
#endif
#endif
static struct asym *symPC; /* the $ symbol */
struct tmitem {
const char *name;
char *value;
struct asym **store;
};
/* table of predefined text macros */
static const struct tmitem tmtab[] = {
/* @Version contains the Masm compatible version */
/* v2.06: value of @Version changed to 800 */
//{"@Version", "615", NULL },
{"@Version", "800", NULL },
{"@Date", szDate, NULL },
{"@Time", szTime, NULL },
{"@FileName", ModuleInfo.name, NULL },
{"@FileCur", NULL, &FileCur },
/* v2.09: @CurSeg value is never set if no segment is ever opened.
* this may have caused an access error if a listing was written.
*/
{"@CurSeg", "", &symCurSeg }
};
struct eqitem {
const char *name;
uint_32 value;
void (* sfunc_ptr)( struct asym *, void * );
struct asym **store;
};
/* table of predefined numeric equates */
static const struct eqitem eqtab[] = {
{ "__JWASM__", _JWASM_VERSION_INT_, NULL, NULL },
{ "$", 0, UpdateCurPC, &symPC },
{ "@Line", 0, UpdateLineNumber, &LineCur },
{ "@WordSize", 0, UpdateWordSize, NULL }, /* must be last (see SymInit()) */
};
static unsigned int hashpjw( const char *s )
/******************************************/
{
unsigned h;
unsigned g;
#if HASH_MAGNITUDE==12
for( h = 0; *s; ++s ) {
h = (h << 4) + (*s | ' ');
g = h & ~0x0fff;
h ^= g;
h ^= g >> 12;
}
#else
for( h = 0; *s; ++s ) {
h = (h << 5) + (*s | ' ');
g = h & ~0x7fff;
h ^= g;
h ^= g >> 15;
}
#endif
return( h );
}
void SymSetCmpFunc( void )
/************************/
{
SymCmpFunc = ( ModuleInfo.case_sensitive == TRUE ? memcmp : (StrCmpFunc)_memicmp );
return;
}
/* reset local hash table */
void SymClearLocal( void )
/************************/
{
memset( &lsym_table, 0, sizeof( lsym_table ) );
return;
}
/* store local hash table in proc's list of local symbols */
void SymGetLocal( struct asym *proc )
/***********************************/
{
int i;
struct dsym **l = &((struct dsym *)proc)->e.procinfo->labellist;
for ( i = 0; i < LHASH_TABLE_SIZE; i++ ) {
if ( lsym_table[i] ) {
*l = (struct dsym *)lsym_table[i];
l = &(*l)->e.nextll;
}
}
*l = NULL;
return;
}
/* restore local hash table.
* - proc: procedure which will become active.
* fixme: It might be necessary to reset the "defined" flag
* for local labels (not for params and locals!). Low priority!
*/
void SymSetLocal( struct asym *proc )
/***********************************/
{
int i;
struct dsym *l;
SymClearLocal();
for ( l = ((struct dsym *)proc)->e.procinfo->labellist; l; l = l->e.nextll ) {
DebugMsg1(("SymSetLocal(%s): label=%s\n", proc->name, l->sym.name ));
i = hashpjw( l->sym.name ) % LHASH_TABLE_SIZE;
lsym_table[i] = &l->sym;
}
return;
}
struct asym *SymAlloc( const char *name )
/***************************************/
{
int len = strlen( name );
struct asym *sym;
sym = LclAlloc( sizeof( struct dsym ) );
memset( sym, 0, sizeof( struct dsym ) );
#if 1
/* the tokenizer ensures that identifiers are within limits, so
* this check probably is redundant */
if( len > MAX_ID_LEN ) {
EmitError( IDENTIFIER_TOO_LONG );
len = MAX_ID_LEN;
}
#endif
sym->name_size = len;
sym->list = ModuleInfo.cref;
sym->mem_type = MT_EMPTY;
if ( len ) {
sym->name = LclAlloc( len + 1 );
memcpy( sym->name, name, len );
sym->name[len] = NULLC;
} else
sym->name = "";
return( sym );
}
struct asym *SymFind( const char *name )
/**************************************/
/* find a symbol in the local/global symbol table,
* return ptr to next free entry in global table if not found.
* Note: lsym must be global, thus if the symbol isn't
* found and is to be added to the local table, there's no
* second scan necessary.
*/
{
int i;
int len;
len = strlen( name );
i = hashpjw( name );
if ( CurrProc ) {
for( lsym = &lsym_table[ i % LHASH_TABLE_SIZE ]; *lsym; lsym = &((*lsym)->nextitem ) ) {
if ( len == (*lsym)->name_size && SYMCMP( name, (*lsym)->name, len ) == 0 ) {
DebugMsg1(("SymFind(%s): found in local table, state=%u, local=%u\n", name, (*lsym)->state, (*lsym)->scoped ));
return( *lsym );
}
}
}
for( gsym = &gsym_table[ i % GHASH_TABLE_SIZE ]; *gsym; gsym = &((*gsym)->nextitem ) ) {
if ( len == (*gsym)->name_size && SYMCMP( name, (*gsym)->name, len ) == 0 ) {
DebugMsg1(("SymFind(%s): found, state=%u memtype=%X lang=%u\n", name, (*gsym)->state, (*gsym)->mem_type, (*gsym)->langtype ));
return( *gsym );
}
}
return( NULL );
}
#if 0
/* Search a symbol */
struct asym *SymSearch( const char *name )
/****************************************/
{
return( *SymFind( name ) );
}
#endif
/* SymLookup() creates a global label if it isn't defined yet */
struct asym *SymLookup( const char *name )
/****************************************/
{
struct asym *sym;
sym = SymFind( name );
if( sym == NULL ) {
sym = SymAlloc( name );
DebugMsg1(("SymLookup(%s): created new symbol, CurrProc=%s\n", name, CurrProc ? CurrProc->sym.name : "NULL" ));
//sym->next = *gsym;
*gsym = sym;
++SymCount;
}
DebugMsg1(("SymLookup(%s): found, state=%u, defined=%u\n", name, sym->state, sym->isdefined));
return( sym );
}
/* SymLookupLocal() creates a local label if it isn't defined yet.
* called by LabelCreate() [see labels.c]
*/
struct asym *SymLookupLocal( const char *name )
/*********************************************/
{
//struct asym **sym_ptr;
struct asym *sym;
sym = SymFind( name );
if ( sym == NULL ) {
sym = SymAlloc( name );
sym->scoped = TRUE;
/* add the label to the local hash table */
//sym->next = *lsym;
*lsym = sym;
DebugMsg1(("SymLookupLocal(%s): local symbol created in %s\n", name, CurrProc->sym.name));
} else if( sym->state == SYM_UNDEFINED && sym->scoped == FALSE ) {
/* if the label was defined due to a FORWARD reference,
* its scope is to be changed from global to local.
*/
/* remove the label from the global hash table */
*gsym = sym->nextitem;
SymCount--;
sym->scoped = TRUE;
/* add the label to the local hash table */
//sym->next = *lsym;
sym->nextitem = NULL;
*lsym = sym;
DebugMsg1(("SymLookupLocal(%s): label moved into %s's local namespace\n", sym->name, CurrProc->sym.name ));
}
DebugMsg1(("SymLookupLocal(%s): found, state=%u, defined=%u\n", name, sym->state, sym->isdefined));
return( sym );
}
/* free state-specific info of a symbol */
static void free_ext( struct asym *sym )
/**************************************/
{
DebugMsg(("free_ext: item=%p name=%s state=%u\n", sym, sym->name, sym->state ));
switch( sym->state ) {
case SYM_INTERNAL:
if ( sym->isproc )
DeleteProc( (struct dsym *)sym );
break;
case SYM_EXTERNAL:
if ( sym->isproc )
DeleteProc( (struct dsym *)sym );
sym->first_size = 0;
/* The altname field may contain a symbol (if weak == FALSE).
* However, this is an independant item and must not be released here
*/
#ifdef DEBUG_OUT /* to be removed, this can't happen anymore. */
if ( sym->mem_type == MT_TYPE && *sym->type->name == NULLC ) {
DebugMsg(( "free_ext: external with private type: %s\n", sym->name ));
SymFree( sym->type );
}
#endif
break;
case SYM_SEG:
if ( ((struct dsym *)sym)->e.seginfo->internal )
LclFree( ((struct dsym *)sym)->e.seginfo->CodeBuffer );
LclFree( ((struct dsym *)sym)->e.seginfo );
break;
case SYM_GRP:
DeleteGroup( (struct dsym *)sym );
break;
case SYM_TYPE:
DeleteType( (struct dsym *)sym );
break;
case SYM_MACRO:
ReleaseMacroData( (struct dsym *)sym );
LclFree( ((struct dsym *)sym)->e.macroinfo );
break;
case SYM_TMACRO:
if ( sym->predefined == FALSE )
LclFree( sym->string_ptr );
break;
#ifdef DEBUG_OUT
case SYM_STACK:
/* to be removed, this can't happen anymore. */
if ( sym->mem_type == MT_TYPE && *sym->type->name == NULLC ) {
DebugMsg(( "free_ext: case SYM_STACK, sym=%s with private type\n", sym->name ));
/* symbol has a "private" type */
SymFree( sym->type );
}
break;
#endif
}
}
/* free a symbol.
* the symbol is no unlinked from hash tables chains,
* hence it is assumed that this is either not needed
* or done by the caller.
*/
void SymFree( struct asym *sym )
/******************************/
{
//DebugMsg(("SymFree: free %X, name=%s, state=%X\n", sym, sym->name, sym->state));
free_ext( sym );
#if FASTMEM==0
if ( sym->state != SYM_EXTERNAL ) {
struct fixup *fix;
for( fix = sym->bp_fixup ; fix; ) {
struct fixup *next = fix->nextbp;
DebugMsg(("SymFree: free bp fixup %p\n", fix ));
LclFree( fix );
fix = next;
}
}
if ( sym->name_size ) LclFree( sym->name );
#endif
LclFree( sym );
return;
}
/* add a symbol to local table and set the symbol's name.
* the previous name was "", the symbol wasn't in a symbol table.
* Called by:
* - ParseParams() in proc.c for procedure parameters.
*/
struct asym *SymAddLocal( struct asym *sym, const char *name )
/************************************************************/
{
struct asym *sym2;
/* v2.10: ignore symbols with state SYM_UNDEFINED! */
//if( SymFind( name ) ) {
if( ( sym2 = SymFind( name ) ) && sym2->state != SYM_UNDEFINED ) {
/* shouldn't happen */
EmitErr( SYMBOL_ALREADY_DEFINED, name );
return( NULL );
}
#if FASTMEM==0
if ( sym->name_size ) LclFree( sym->name );
#endif
sym->name_size = strlen( name );
sym->name = LclAlloc( sym->name_size + 1 );
memcpy( sym->name, name, sym->name_size + 1 );
sym->nextitem = NULL;
*lsym = sym;
return( sym );
}
/* add a symbol to the global symbol table.
* Called by:
* - RecordDirective() in types.c to add bitfield fields (which have global scope).
*/
struct asym *SymAddGlobal( struct asym *sym )
/*******************************************/
{
if( SymFind( sym->name ) ) {
EmitErr( SYMBOL_ALREADY_DEFINED, sym->name );
return( NULL );
}
sym->nextitem = NULL;
*gsym = sym;
SymCount++;
return( sym );
}
struct asym *SymCreate( const char *name )
/****************************************/
/* Create symbol and optionally insert it into the symbol table */
{
struct asym *sym;
if( SymFind( name ) ) {
EmitErr( SYMBOL_ALREADY_DEFINED, name );
return( NULL );
}
sym = SymAlloc( name );
*gsym = sym;
SymCount++;
return( sym );
}
struct asym *SymLCreate( const char *name )
/*****************************************/
/* Create symbol and insert it into the local symbol table.
* This function is called by LocalDir() and ParseParams()
* in proc.c ( for LOCAL directive and PROC parameters ).
*/
{
struct asym *sym;
/* v2.10: ignore symbols with state SYM_UNDEFINED */
//if( SymFind( name ) ) {
if( ( sym = SymFind( name ) ) && sym->state != SYM_UNDEFINED ) {
EmitErr( SYMBOL_ALREADY_DEFINED, name );
return( NULL );
}
sym = SymAlloc( name );
*lsym = sym;
return( sym );
}
void SymMakeAllSymbolsPublic( void )
/**********************************/
{
int i;
struct asym *sym;
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
if ( sym->state == SYM_INTERNAL &&
/* v2.07: MT_ABS is obsolete */
//sym->mem_type != MT_ABS && /* no EQU or '=' constants */
sym->isequate == FALSE && /* no EQU or '=' constants */
sym->predefined == FALSE && /* no predefined symbols ($) */
sym->included == FALSE && /* v2.09: symbol already added to public queue? */
//sym->scoped == FALSE && /* v2.09: no procs that are marked as "private" */
sym->name[1] != '&' && /* v2.10: no @@ code labels */
sym->ispublic == FALSE ) {
sym->ispublic = TRUE;
AddPublicData( sym );
}
}
}
}
#ifdef DEBUG_OUT
static void DumpSymbols( void );
#endif
void SymFini( void )
/******************/
{
#if FASTMEM==0 || defined( DEBUG_OUT )
unsigned i;
#endif
#ifdef DEBUG_OUT
if ( Options.dump_symbols_hash ) {
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
struct asym *sym = gsym_table[i];
if ( sym ) {
printf("%4u ", i );
for( ; sym; sym = sym->nextitem ) {
printf("%-16s ", sym->name );
}
printf("\n" );
}
}
}
DumpSymbols();
#endif
#if FASTMEM==0 || defined( DEBUG_OUT )
/* free the symbol table */
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
struct asym *sym;
struct asym *next;
for( sym = gsym_table[i]; sym; ) {
next = sym->nextitem;
SymFree( sym );
SymCount--;
sym = next;
}
}
/**/myassert( SymCount == 0 );
#endif
}
/* initialize global symbol table */
void SymInit( void )
/******************/
{
struct asym *sym;
int i;
time_t time_of_day;
struct tm *now;
DebugMsg(("SymInit() enter\n"));
SymCount = 0;
/* v2.11: ensure CurrProc is NULL - might be a problem if multiple files are assembled */
CurrProc = NULL;
memset( gsym_table, 0, sizeof(gsym_table) );
time_of_day = time( NULL );
now = localtime( &time_of_day );
#if USESTRFTIME
strftime( szDate, 9, szDateFmt, now );
strftime( szTime, 9, szTimeFmt, now );
#else
sprintf( szDate, "%02u/%02u/%02u", now->tm_mon + 1, now->tm_mday, now->tm_year % 100 );
sprintf( szTime, "%02u:%02u:%02u", now->tm_hour, now->tm_min, now->tm_sec );
#endif
for( i = 0; i < sizeof(tmtab) / sizeof(tmtab[0]); i++ ) {
sym = SymCreate( tmtab[i].name );
sym->state = SYM_TMACRO;
sym->isdefined = TRUE;
sym->predefined = TRUE;
sym->string_ptr = tmtab[i].value;
if ( tmtab[i].store )
*tmtab[i].store = sym;
}
for( i = 0; i < sizeof(eqtab) / sizeof(eqtab[0]); i++ ) {
sym = SymCreate( eqtab[i].name );
sym->state = SYM_INTERNAL;
/* v2.07: MT_ABS is obsolete */
//sym->mem_type = MT_ABS;
sym->isdefined = TRUE;
sym->predefined = TRUE;
sym->offset = eqtab[i].value;
sym->sfunc_ptr = eqtab[i].sfunc_ptr;
//sym->variable = TRUE; /* if fixup must be created */
if ( eqtab[i].store )
*eqtab[i].store = sym;
}
sym->list = FALSE; /* @WordSize should not be listed */
/* $ is an address (usually). Also, don't add it to the list */
symPC->variable = TRUE;
symPC->list = FALSE;
LineCur->list = FALSE;
DebugMsg(("SymInit() exit\n"));
return;
}
void SymPassInit( int pass )
/**************************/
{
unsigned i;
if ( pass == PASS_1 )
return;
#if FASTPASS
/* No need to reset the "defined" flag if FASTPASS is on.
* Because then the source lines will come from the line store,
* where inactive conditional lines are NOT contained.
*/
if ( UseSavedState )
return;
#endif
/* mark as "undefined":
* - SYM_INTERNAL - internals
* - SYM_MACRO - macros
* - SYM_TMACRO - text macros
*/
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
struct asym *sym;
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
if ( sym->predefined == FALSE ) {
/* v2.04: all symbol's "defined" flag is now reset. */
// if ( sym->state == SYM_TMACRO ||
// sym->state == SYM_MACRO ||
// sym->state == SYM_INTERNAL ) {
sym->isdefined = FALSE;
//}
}
}
}
}
uint_32 SymGetCount( void )
/*************************/
{
return( SymCount );
}
/* get all symbols in global hash table */
void SymGetAll( struct asym **syms )
/**********************************/
{
struct asym *sym;
unsigned i, j;
/* copy symbols to table */
for( i = j = 0; i < GHASH_TABLE_SIZE; i++ ) {
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
syms[j++] = sym;
}
}
return;
}
/* enum symbols in global hash table.
* used for codeview symbolic debug output.
*/
struct asym *SymEnum( struct asym *sym, int *pi )
/***********************************************/
{
if ( sym == NULL ) {
*pi = 0;
sym = gsym_table[*pi];
} else {
sym = sym->nextitem;
}
/* v2.10: changed from for() to while() */
while( sym == NULL && *pi < GHASH_TABLE_SIZE - 1 )
sym = gsym_table[++(*pi)];
//printf("sym=%X, i=%u\n", sym, *pi );
return( sym );
}
#ifdef DEBUG_OUT
static void DumpSymbol( struct asym *sym )
/****************************************/
{
struct dsym *dir = (struct dsym *)sym;
char *type;
uint_64 value = sym->uvalue;
//const char *langtype;
switch( sym->state ) {
case SYM_UNDEFINED:
type = "Undefined";
break;
case SYM_INTERNAL:
if ( sym->isproc )
type = "Procedure";
//else if ( sym->mem_type == MT_ABS )
else if ( sym->segment == NULL ) {
type = "Number";
value += ((uint_64)(uint_32)sym->value3264) << 32;
} else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR )
type = "Code Label";
else
type = "Data Label";
break;
case SYM_EXTERNAL:
if ( sym->isproc )
type = "Proto";
else if ( sym->iscomm )
type = "Communal";
else if ( sym->mem_type == MT_EMPTY )
type = "Number (ext)";
else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR )
type = "Code (ext)";
else
type = "Data (ext)";
break;
case SYM_SEG:
type = "Segment";
break;
case SYM_GRP:
type = "Group";
break;
case SYM_STACK: /* should never be found in global table */
type = "Stack Var";
break;
case SYM_STRUCT_FIELD: /* record bitfields are in global namespace! */
type = "Struct Field";
break;
case SYM_TYPE:
switch ( sym->typekind ) {
case TYPE_STRUCT: type = "Structure"; break;
case TYPE_UNION: type = "Union"; break;
case TYPE_TYPEDEF: type = "Typedef"; break;
case TYPE_RECORD: type = "Record"; break;
default: type = "Undef Type";break;
}
break;
case SYM_ALIAS:
type = "Alias";
break;
case SYM_MACRO:
type = "Macro";
break;
case SYM_TMACRO:
type = "Text";
break;
//case SYM_CLASS_LNAME: /* never stored in global or local table */
// type = "CLASS";
// break;
default:
type = "Unknown";
break;
}
printf( "%-12s %16" I64_SPEC "X %02X %8p %c %8p %s\n", type, value, sym->mem_type, dir->e, sym->ispublic ? 'X' : ' ', sym->name, sym->name );
}
static void DumpSymbols( void )
/*****************************/
{
struct asym *sym;
unsigned i;
unsigned count = 0;
unsigned max = 0;
unsigned num0 = 0;
unsigned num1 = 0;
unsigned num5 = 0;
unsigned num10 = 0;
unsigned curr = 0;
DebugMsg(("DumpSymbols enter\n"));
if ( Options.dump_symbols ) {
printf( " # Addr Type Value MT Ext P pName Name\n" );
printf( "--------------------------------------------------------------------------------\n" );
}
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
for( sym = gsym_table[i], curr = 0; sym; sym = sym->nextitem ) {
curr++;
if ( Options.dump_symbols ) {
printf("%4u %8p ", i, sym );
DumpSymbol( sym );
}
}
count += curr;
if ( curr == 0 )
num0++;
else if ( curr == 1 )
num1++;
else if ( curr <= 5 )
num5++;
else if ( curr <= 10 )
num10++;
if ( max < curr )
max = curr;
}
if ( Options.quiet == FALSE ) {
printf( "%u items in symbol table, expected %u\n", count, SymCount );
printf( "max items in a line=%u, lines with 0/1/<=5/<=10 items=%u/%u/%u/%u, \n", max, num0, num1, num5, num10 );
}
}
#endif