Home | History | Annotate | Download | only in sym
      1 /*
      2  * Simple symbol table manager using coalesced chaining to resolve collisions
      3  *
      4  * Doubly-linked lists are used for fast removal of entries.
      5  *
      6  * 'sym.h' must have a definition for typedef "Sym".  Sym must include at
      7  * minimum the following fields:
      8  *
      9  *		...
     10  *		char *symbol;
     11  *		struct ... *next, *prev, **head, *scope;
     12  *		unsigned int hash;
     13  *		...
     14  *
     15  * 'template.h' can be used as a template to create a 'sym.h'.
     16  *
     17  * 'head' is &(table[hash(itself)]).
     18  * The hash table is not resizable at run-time.
     19  * The scope field is used to link all symbols of a current scope together.
     20  * Scope() sets the current scope (linked list) to add symbols to.
     21  * Any number of scopes can be handled.  The user passes the address of
     22  * a pointer to a symbol table
     23  * entry (INITIALIZED TO NULL first time).
     24  *
     25  * Available Functions:
     26  *
     27  *	zzs_init(s1,s2)	--	Create hash table with size s1, string table size s2.
     28  *	zzs_done()		--	Free hash and string table created with zzs_init().
     29  *	zzs_add(key,rec)--	Add 'rec' with key 'key' to the symbol table.
     30  *	zzs_newadd(key)	--	create entry; add using 'key' to the symbol table.
     31  *	zzs_get(key)	--	Return pointer to last record entered under 'key'
     32  *						Else return NULL
     33  *	zzs_del(p)		--	Unlink the entry associated with p.  This does
     34  *						NOT free 'p' and DOES NOT remove it from a scope
     35  *						list.  If it was a part of your intermediate code
     36  *						tree or another structure.  It will still be there.
     37  *			  			It is only removed from further consideration
     38  *						by the symbol table.
     39  *	zzs_keydel(s)	--	Unlink the entry associated with key s.
     40  *						Calls zzs_del(p) to unlink.
     41  *	zzs_scope(sc)	--	Specifies that everything added to the symbol
     42  *			   			table with zzs_add() is added to the list (scope)
     43  *						'sc'.  'sc' is of 'Sym **sc' type and must be
     44  *						initialized to NULL before trying to add anything
     45  *						to it (passing it to zzs_scope()).  Scopes can be
     46  *					    switched at any time and merely links a set of
     47  *						symbol table entries.  If a NULL pointer is
     48  *						passed, the current scope is returned.
     49  *	zzs_rmscope(sc)	--	Remove (zzs_del()) all elements of scope 'sc'
     50  *						from the symbol table.  The entries are NOT
     51  *						free()'d.  A pointer to the first
     52  *			   			element in the "scope" is returned.  The user
     53  *			   			can then manipulate the list as he/she chooses
     54  *			   			(such as freeing them all). NOTE that this
     55  *			   			function sets your scope pointer to NULL,
     56  *			   			but returns a pointer to the list for you to use.
     57  *	zzs_stat()		--	Print out the symbol table and some relevant stats.
     58  *	zzs_new(key)	--	Create a new record with calloc() of type Sym.
     59  *			   			Add 'key' to the string table and make the new
     60  *			   			records 'symbol' pointer point to it.
     61  *	zzs_strdup(s)	--	Add s to the string table and return a pointer
     62  *			   			to it.  Very fast allocation routine
     63  *						and does not require strlen() nor calloc().
     64  *
     65  * Example:
     66  *
     67  *	#include <stdio.h>
     68  *	#include "sym.h"
     69  *
     70  *	main()
     71  *	{
     72  *	    Sym *scope1=NULL, *scope2=NULL, *a, *p;
     73  *
     74  *	    zzs_init(101, 100);
     75  *
     76  *	    a = zzs_new("Apple");	zzs_add(a->symbol, a);	-- No scope
     77  *	    zzs_scope( &scope1 );	-- enter scope 1
     78  *	    a = zzs_new("Plum");	zzs_add(a->symbol, a);
     79  *	    zzs_scope( &scope2 );	-- enter scope 2
     80  *	    a = zzs_new("Truck");	zzs_add(a->symbol, a);
     81  *
     82  *    	p = zzs_get("Plum");
     83  *    	if ( p == NULL ) fprintf(stderr, "Hmmm...Can't find 'Plum'\n");
     84  *
     85  *    	p = zzs_rmscope(&scope1)
     86  *    	for (; p!=NULL; p=p->scope) {printf("Scope1:  %s\n", p->symbol);}
     87  *    	p = zzs_rmscope(&scope2)
     88  *    	for (; p!=NULL; p=p->scope) {printf("Scope2:  %s\n", p->symbol);}
     89  * }
     90  *
     91  * Terence Parr
     92  * Purdue University
     93  * February 1990
     94  *
     95  * CHANGES
     96  *
     97  *	Terence Parr
     98  *	May 1991
     99  *		Renamed functions to be consistent with ANTLR
    100  *		Made HASH macro
    101  *		Added zzs_keydel()
    102  *		Added zzs_newadd()
    103  *		Fixed up zzs_stat()
    104  *
    105  *	July 1991
    106  *		Made symbol table entry save its hash code for fast comparison
    107  *			during searching etc...
    108  */
    109 
    110 #include <stdio.h>
    111 #if defined(__STDC__) || defined(__USE_PROTOS)
    112 #include <string.h>
    113 #include <stdlib.h>
    114 #else
    115 #include <malloc.h>
    116 #endif
    117 #include "sym.h"
    118 
    119 #define StrSame		0
    120 
    121 static Sym **CurScope = NULL;
    122 static unsigned size = 0;
    123 static Sym **table=NULL;
    124 static char *strings;
    125 static char *strp;
    126 static int strsize = 0;
    127 
    128 #ifdef __USE_PROTOS
    129 void zzs_init(int sz,int strs)
    130 #else
    131 void zzs_init(sz, strs)
    132 int sz, strs;
    133 #endif
    134 {
    135 	if ( sz <= 0 || strs <= 0 ) return;
    136 	table = (Sym **) calloc(sz, sizeof(Sym *));
    137 	if ( table == NULL )
    138 	{
    139 		fprintf(stderr, "Cannot allocate table of size %d\n", sz);
    140 		exit(1);
    141 	}
    142 	strings = (char *) calloc(strs, sizeof(char));
    143 	if ( strings == NULL )
    144 	{
    145 		fprintf(stderr, "Cannot allocate string table of size %d\n", strs);
    146 		exit(1);
    147 	}
    148 	size = sz;
    149 	strsize = strs;
    150 	strp = strings;
    151 }
    152 
    153 #ifdef __USE_PROTOS
    154 void zzs_done(void)
    155 #else
    156 void zzs_done()
    157 #endif
    158 {
    159 	if ( table != NULL ) free( table );
    160 	if ( strings != NULL ) free( strings );
    161 }
    162 
    163 #ifdef __USE_PROTOS
    164 void zzs_add(char *key,Sym rec)
    165 #else
    166 void zzs_add(key, rec)
    167 char *key;
    168 register Sym *rec;
    169 #endif
    170 {
    171 	register unsigned int h=0;
    172 	register char *p=key;
    173 
    174 	HASH(p, h);
    175 	rec->hash = h;					/* save hash code for fast comp later */
    176 	h %= size;
    177 
    178 	if ( CurScope != NULL ) {rec->scope = *CurScope; *CurScope = rec;}
    179 	rec->next = table[h];			/* Add to doubly-linked list */
    180 	rec->prev = NULL;
    181 	if ( rec->next != NULL ) (rec->next)->prev = rec;
    182 	table[h] = rec;
    183 	rec->head = &(table[h]);
    184 }
    185 
    186 #ifdef __USE_PROTOS
    187 Sym * zzs_get(char *key)
    188 #else
    189 Sym * zzs_get(key)
    190 char *key;
    191 #endif
    192 {
    193 	register unsigned int h=0;
    194 	register char *p=key;
    195 	register Sym *q;
    196 
    197 	HASH(p, h);
    198 
    199 	for (q = table[h%size]; q != NULL; q = q->next)
    200 	{
    201 		if ( q->hash == h )		/* do we even have a chance of matching? */
    202 			if ( strcmp(key, q->symbol) == StrSame ) return( q );
    203 	}
    204 	return( NULL );
    205 }
    206 
    207 /*
    208  * Unlink p from the symbol table.  Hopefully, it's actually in the
    209  * symbol table.
    210  *
    211  * If p is not part of a bucket chain of the symbol table, bad things
    212  * will happen.
    213  *
    214  * Will do nothing if all list pointers are NULL
    215  */
    216 #ifdef __USE_PROTOS
    217 void zzs_del(Sym *p)
    218 #else
    219 void zzs_del(p)
    220 register Sym *p;
    221 #endif
    222 {
    223 	if ( p == NULL ) {fprintf(stderr, "zzs_del(NULL)\n"); exit(1);}
    224 	if ( p->prev == NULL )	/* Head of list */
    225 	{
    226 		register Sym **t = p->head;
    227 
    228 		if ( t == NULL ) return;	/* not part of symbol table */
    229 		(*t) = p->next;
    230 		if ( (*t) != NULL ) (*t)->prev = NULL;
    231 	}
    232 	else
    233 	{
    234 		(p->prev)->next = p->next;
    235 		if ( p->next != NULL ) (p->next)->prev = p->prev;
    236 	}
    237 	p->next = p->prev = NULL;	/* not part of symbol table anymore */
    238 	p->head = NULL;
    239 }
    240 
    241 #ifdef __USE_PROTOS
    242 void zzs_keydel(char *key)
    243 #else
    244 void zzs_keydel(key)
    245 char *key;
    246 #endif
    247 {
    248 	Sym *p = zzs_get(key);
    249 
    250 	if ( p != NULL ) zzs_del( p );
    251 }
    252 
    253 /* S c o p e  S t u f f */
    254 
    255 /* Set current scope to 'scope'; return current scope if 'scope' == NULL */
    256 
    257 #ifdef __USE_PROTOS
    258 Sym ** zzs_scope(Sym **scope)
    259 #else
    260 Sym ** zzs_scope(scope)
    261 Sym **scope;
    262 #endif
    263 {
    264 	if ( scope == NULL ) return( CurScope );
    265 	CurScope = scope;
    266 	return( scope );
    267 }
    268 
    269 /* Remove a scope described by 'scope'.  Return pointer to 1st element in scope */
    270 
    271 #ifdef __USE_PROTOS
    272 Sym * zzs_rmscope(Sym **scope)
    273 #else
    274 Sym * zzs_rmscope(scope)
    275 register Sym **scope;
    276 #endif
    277 {
    278 	register Sym *p;
    279 	Sym *start;
    280 
    281 	if ( scope == NULL ) return(NULL);
    282 	start = p = *scope;
    283 	for (; p != NULL; p=p->scope) { zzs_del( p ); }
    284 	*scope = NULL;
    285 	return( start );
    286 }
    287 
    288 #ifdef __USE_PROTOS
    289 void zzs_stat(void)
    290 #else
    291 void zzs_stat()
    292 #endif
    293 {
    294 	static unsigned short count[20];
    295 	unsigned int i,n=0,low=0, hi=0;
    296 	register Sym **p;
    297 	float avg=0.0;
    298 
    299 	for (i=0; i<20; i++) count[i] = 0;
    300 	for (p=table; p<&(table[size]); p++)
    301 	{
    302 		register Sym *q = *p;
    303 		unsigned int len;
    304 
    305 		if ( q != NULL && low==0 ) low = p-table;
    306 		len = 0;
    307 		if ( q != NULL ) printf("[%d]", p-table);
    308 		while ( q != NULL )
    309 		{
    310 			len++;
    311 			n++;
    312 			printf(" %s", q->symbol);
    313 			q = q->next;
    314 			if ( q == NULL ) printf("\n");
    315 		}
    316 		if ( len>=20 ) printf("zzs_stat: count table too small\n");
    317 		else count[len]++;
    318 		if ( *p != NULL ) hi = p-table;
    319 	}
    320 
    321 	printf("Storing %d recs used %d hash positions out of %d\n",
    322 			n, size-count[0], size);
    323 	printf("%f %% utilization\n",
    324 			((float)(size-count[0]))/((float)size));
    325 	for (i=0; i<20; i++)
    326 	{
    327 		if ( count[i] != 0 )
    328 		{
    329 			avg += (((float)(i*count[i]))/((float)n)) * i;
    330 			printf("Buckets of len %d == %d (%f %% of recs)\n",
    331 					i, count[i], 100.0*((float)(i*count[i]))/((float)n));
    332 		}
    333 	}
    334 	printf("Avg bucket length %f\n", avg);
    335 	printf("Range of hash function: %d..%d\n", low, hi);
    336 }
    337 
    338 /*
    339  * Given a string, this function allocates and returns a pointer to a
    340  * symbol table record whose "symbol" pointer is reset to a position
    341  * in the string table.
    342  */
    343 
    344 #ifdef __USE_PROTOS
    345 Sym * zzs_new(char *text)
    346 #else
    347 Sym * zzs_new(text)
    348 char *text;
    349 #endif
    350 {
    351 	Sym *p;
    352 
    353 	if ( (p = (Sym *) calloc(1,sizeof(Sym))) == 0 )
    354 	{
    355 		fprintf(stderr,"Out of memory\n");
    356 		exit(1);
    357 	}
    358 	p->symbol = zzs_strdup(text);
    359 
    360 	return p;
    361 }
    362 
    363 /* create a new symbol table entry and add it to the symbol table */
    364 
    365 #ifdef __USE_PROTOS
    366 Sym * zzs_newadd(char *text)
    367 #else
    368 Sym * zzs_newadd(text)
    369 char *text;
    370 #endif
    371 {
    372 	Sym *p = zzs_new(text);
    373 	if ( p != NULL ) zzs_add(text, p);
    374 	return p;
    375 }
    376 
    377 /* Add a string to the string table and return a pointer to it.
    378  * Bump the pointer into the string table to next avail position.
    379  */
    380 
    381 #ifdef __USE_PROTOS
    382 char * zzs_strdup(char *s)
    383 #else
    384 char * zzs_strdup(s)
    385 register char *s;
    386 #endif
    387 {
    388 	register char *start=strp;
    389 
    390 	while ( *s != '\0' )
    391 	{
    392 		if ( strp >= &(strings[strsize-2]) )
    393 		{
    394 			fprintf(stderr, "sym: string table overflow (%d chars)\n", strsize);
    395 			exit(-1);
    396 		}
    397 		*strp++ = *s++;
    398 	}
    399 	*strp++ = '\0';
    400 
    401 	return( start );
    402 }
    403