git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8964 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			403 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Simple symbol table manager using coalesced chaining to resolve collisions
 | |
|  *
 | |
|  * Doubly-linked lists are used for fast removal of entries.
 | |
|  *
 | |
|  * 'sym.h' must have a definition for typedef "Sym".  Sym must include at
 | |
|  * minimum the following fields:
 | |
|  *
 | |
|  *		...
 | |
|  *		char *symbol;
 | |
|  *		struct ... *next, *prev, **head, *scope;
 | |
|  *		unsigned int hash;
 | |
|  *		...
 | |
|  *
 | |
|  * 'template.h' can be used as a template to create a 'sym.h'.
 | |
|  *
 | |
|  * 'head' is &(table[hash(itself)]).
 | |
|  * The hash table is not resizable at run-time.
 | |
|  * The scope field is used to link all symbols of a current scope together.
 | |
|  * Scope() sets the current scope (linked list) to add symbols to.
 | |
|  * Any number of scopes can be handled.  The user passes the address of
 | |
|  * a pointer to a symbol table
 | |
|  * entry (INITIALIZED TO NULL first time).
 | |
|  *
 | |
|  * Available Functions:
 | |
|  *
 | |
|  *	zzs_init(s1,s2)	--	Create hash table with size s1, string table size s2.
 | |
|  *	zzs_done()		--	Free hash and string table created with zzs_init().
 | |
|  *	zzs_add(key,rec)--	Add 'rec' with key 'key' to the symbol table.
 | |
|  *	zzs_newadd(key)	--	create entry; add using 'key' to the symbol table.
 | |
|  *	zzs_get(key)	--	Return pointer to last record entered under 'key'
 | |
|  *						Else return NULL
 | |
|  *	zzs_del(p)		--	Unlink the entry associated with p.  This does
 | |
|  *						NOT free 'p' and DOES NOT remove it from a scope
 | |
|  *						list.  If it was a part of your intermediate code
 | |
|  *						tree or another structure.  It will still be there.
 | |
|  *			  			It is only removed from further consideration
 | |
|  *						by the symbol table.
 | |
|  *	zzs_keydel(s)	--	Unlink the entry associated with key s.
 | |
|  *						Calls zzs_del(p) to unlink.
 | |
|  *	zzs_scope(sc)	--	Specifies that everything added to the symbol
 | |
|  *			   			table with zzs_add() is added to the list (scope)
 | |
|  *						'sc'.  'sc' is of 'Sym **sc' type and must be
 | |
|  *						initialized to NULL before trying to add anything
 | |
|  *						to it (passing it to zzs_scope()).  Scopes can be
 | |
|  *					    switched at any time and merely links a set of
 | |
|  *						symbol table entries.  If a NULL pointer is
 | |
|  *						passed, the current scope is returned.
 | |
|  *	zzs_rmscope(sc)	--	Remove (zzs_del()) all elements of scope 'sc'
 | |
|  *						from the symbol table.  The entries are NOT
 | |
|  *						free()'d.  A pointer to the first
 | |
|  *			   			element in the "scope" is returned.  The user
 | |
|  *			   			can then manipulate the list as he/she chooses
 | |
|  *			   			(such as freeing them all). NOTE that this
 | |
|  *			   			function sets your scope pointer to NULL,
 | |
|  *			   			but returns a pointer to the list for you to use.
 | |
|  *	zzs_stat()		--	Print out the symbol table and some relevant stats.
 | |
|  *	zzs_new(key)	--	Create a new record with calloc() of type Sym.
 | |
|  *			   			Add 'key' to the string table and make the new
 | |
|  *			   			records 'symbol' pointer point to it.
 | |
|  *	zzs_strdup(s)	--	Add s to the string table and return a pointer
 | |
|  *			   			to it.  Very fast allocation routine
 | |
|  *						and does not require strlen() nor calloc().
 | |
|  *
 | |
|  * Example:
 | |
|  *
 | |
|  *	#include <stdio.h>
 | |
|  *	#include "sym.h"
 | |
|  *
 | |
|  *	main()
 | |
|  *	{
 | |
|  *	    Sym *scope1=NULL, *scope2=NULL, *a, *p;
 | |
|  *	
 | |
|  *	    zzs_init(101, 100);
 | |
|  *	
 | |
|  *	    a = zzs_new("Apple");	zzs_add(a->symbol, a);	-- No scope
 | |
|  *	    zzs_scope( &scope1 );	-- enter scope 1
 | |
|  *	    a = zzs_new("Plum");	zzs_add(a->symbol, a);
 | |
|  *	    zzs_scope( &scope2 );	-- enter scope 2
 | |
|  *	    a = zzs_new("Truck");	zzs_add(a->symbol, a);
 | |
|  *	
 | |
|  *    	p = zzs_get("Plum");
 | |
|  *    	if ( p == NULL ) fprintf(stderr, "Hmmm...Can't find 'Plum'\n");
 | |
|  *	
 | |
|  *    	p = zzs_rmscope(&scope1)
 | |
|  *    	for (; p!=NULL; p=p->scope) {printf("Scope1:  %s\n", p->symbol);}
 | |
|  *    	p = zzs_rmscope(&scope2)
 | |
|  *    	for (; p!=NULL; p=p->scope) {printf("Scope2:  %s\n", p->symbol);}
 | |
|  * }
 | |
|  *
 | |
|  * Terence Parr
 | |
|  * Purdue University
 | |
|  * February 1990
 | |
|  *
 | |
|  * CHANGES
 | |
|  *
 | |
|  *	Terence Parr
 | |
|  *	May 1991
 | |
|  *		Renamed functions to be consistent with ANTLR
 | |
|  *		Made HASH macro
 | |
|  *		Added zzs_keydel()
 | |
|  *		Added zzs_newadd()
 | |
|  *		Fixed up zzs_stat()
 | |
|  *
 | |
|  *	July 1991
 | |
|  *		Made symbol table entry save its hash code for fast comparison
 | |
|  *			during searching etc...
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #if defined(__STDC__) || defined(__USE_PROTOS)
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #else
 | |
| #include <malloc.h>
 | |
| #endif
 | |
| #include "sym.h"
 | |
| 
 | |
| #define StrSame		0
 | |
| 
 | |
| static Sym **CurScope = NULL;
 | |
| static unsigned size = 0;
 | |
| static Sym **table=NULL;
 | |
| static char *strings;
 | |
| static char *strp;
 | |
| static int strsize = 0;
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_init(int sz,int strs)
 | |
| #else
 | |
| void zzs_init(sz, strs)
 | |
| int sz, strs;
 | |
| #endif
 | |
| {
 | |
| 	if ( sz <= 0 || strs <= 0 ) return;
 | |
| 	table = (Sym **) calloc(sz, sizeof(Sym *));
 | |
| 	if ( table == NULL )
 | |
| 	{
 | |
| 		fprintf(stderr, "Cannot allocate table of size %d\n", sz);
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	strings = (char *) calloc(strs, sizeof(char));
 | |
| 	if ( strings == NULL )
 | |
| 	{
 | |
| 		fprintf(stderr, "Cannot allocate string table of size %d\n", strs);
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	size = sz;
 | |
| 	strsize = strs;
 | |
| 	strp = strings;
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_done(void)
 | |
| #else
 | |
| void zzs_done()
 | |
| #endif
 | |
| {
 | |
| 	if ( table != NULL ) free( table );
 | |
| 	if ( strings != NULL ) free( strings );
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_add(char *key,Sym rec)
 | |
| #else
 | |
| void zzs_add(key, rec)
 | |
| char *key;
 | |
| register Sym *rec;
 | |
| #endif
 | |
| {
 | |
| 	register unsigned int h=0;
 | |
| 	register char *p=key;
 | |
| 	
 | |
| 	HASH(p, h);
 | |
| 	rec->hash = h;					/* save hash code for fast comp later */
 | |
| 	h %= size;
 | |
| 	
 | |
| 	if ( CurScope != NULL ) {rec->scope = *CurScope; *CurScope = rec;}
 | |
| 	rec->next = table[h];			/* Add to doubly-linked list */
 | |
| 	rec->prev = NULL;
 | |
| 	if ( rec->next != NULL ) (rec->next)->prev = rec;
 | |
| 	table[h] = rec;
 | |
| 	rec->head = &(table[h]);
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| Sym * zzs_get(char *key)
 | |
| #else
 | |
| Sym * zzs_get(key)
 | |
| char *key;
 | |
| #endif
 | |
| {
 | |
| 	register unsigned int h=0;
 | |
| 	register char *p=key;
 | |
| 	register Sym *q;
 | |
| 	
 | |
| 	HASH(p, h);
 | |
| 	
 | |
| 	for (q = table[h%size]; q != NULL; q = q->next)
 | |
| 	{
 | |
| 		if ( q->hash == h )		/* do we even have a chance of matching? */
 | |
| 			if ( strcmp(key, q->symbol) == StrSame ) return( q );
 | |
| 	}
 | |
| 	return( NULL );
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Unlink p from the symbol table.  Hopefully, it's actually in the
 | |
|  * symbol table.
 | |
|  *
 | |
|  * If p is not part of a bucket chain of the symbol table, bad things
 | |
|  * will happen.
 | |
|  *
 | |
|  * Will do nothing if all list pointers are NULL
 | |
|  */
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_del(Sym *p)
 | |
| #else
 | |
| void zzs_del(p)
 | |
| register Sym *p;
 | |
| #endif
 | |
| {
 | |
| 	if ( p == NULL ) {fprintf(stderr, "zzs_del(NULL)\n"); exit(1);}
 | |
| 	if ( p->prev == NULL )	/* Head of list */
 | |
| 	{
 | |
| 		register Sym **t = p->head;
 | |
| 		
 | |
| 		if ( t == NULL ) return;	/* not part of symbol table */
 | |
| 		(*t) = p->next;
 | |
| 		if ( (*t) != NULL ) (*t)->prev = NULL;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		(p->prev)->next = p->next;
 | |
| 		if ( p->next != NULL ) (p->next)->prev = p->prev;
 | |
| 	}
 | |
| 	p->next = p->prev = NULL;	/* not part of symbol table anymore */
 | |
| 	p->head = NULL;
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_keydel(char *key)
 | |
| #else
 | |
| void zzs_keydel(key)
 | |
| char *key;
 | |
| #endif
 | |
| {
 | |
| 	Sym *p = zzs_get(key);
 | |
| 
 | |
| 	if ( p != NULL ) zzs_del( p );
 | |
| }
 | |
| 
 | |
| /* S c o p e  S t u f f */
 | |
| 
 | |
| /* Set current scope to 'scope'; return current scope if 'scope' == NULL */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| Sym ** zzs_scope(Sym **scope)
 | |
| #else
 | |
| Sym ** zzs_scope(scope)
 | |
| Sym **scope;
 | |
| #endif
 | |
| {
 | |
| 	if ( scope == NULL ) return( CurScope );
 | |
| 	CurScope = scope;
 | |
| 	return( scope );
 | |
| }
 | |
| 
 | |
| /* Remove a scope described by 'scope'.  Return pointer to 1st element in scope */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| Sym * zzs_rmscope(Sym **scope)
 | |
| #else
 | |
| Sym * zzs_rmscope(scope)
 | |
| register Sym **scope;
 | |
| #endif
 | |
| {
 | |
| 	register Sym *p;
 | |
| 	Sym *start;
 | |
| 
 | |
| 	if ( scope == NULL ) return(NULL);
 | |
| 	start = p = *scope;
 | |
| 	for (; p != NULL; p=p->scope) { zzs_del( p ); }
 | |
| 	*scope = NULL;
 | |
| 	return( start );
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void zzs_stat(void)
 | |
| #else
 | |
| void zzs_stat()
 | |
| #endif
 | |
| {
 | |
| 	static unsigned short count[20];
 | |
| 	unsigned int i,n=0,low=0, hi=0;
 | |
| 	register Sym **p;
 | |
| 	float avg=0.0;
 | |
| 	
 | |
| 	for (i=0; i<20; i++) count[i] = 0;
 | |
| 	for (p=table; p<&(table[size]); p++)
 | |
| 	{
 | |
| 		register Sym *q = *p;
 | |
| 		unsigned int len;
 | |
| 		
 | |
| 		if ( q != NULL && low==0 ) low = p-table;
 | |
| 		len = 0;
 | |
| 		if ( q != NULL ) printf("[%d]", p-table);
 | |
| 		while ( q != NULL )
 | |
| 		{
 | |
| 			len++;
 | |
| 			n++;
 | |
| 			printf(" %s", q->symbol);
 | |
| 			q = q->next;
 | |
| 			if ( q == NULL ) printf("\n");
 | |
| 		}
 | |
| 		if ( len>=20 ) printf("zzs_stat: count table too small\n");
 | |
| 		else count[len]++;
 | |
| 		if ( *p != NULL ) hi = p-table;
 | |
| 	}
 | |
| 
 | |
| 	printf("Storing %d recs used %d hash positions out of %d\n",
 | |
| 			n, size-count[0], size);
 | |
| 	printf("%f %% utilization\n",
 | |
| 			((float)(size-count[0]))/((float)size));
 | |
| 	for (i=0; i<20; i++)
 | |
| 	{
 | |
| 		if ( count[i] != 0 )
 | |
| 		{
 | |
| 			avg += (((float)(i*count[i]))/((float)n)) * i;
 | |
| 			printf("Buckets of len %d == %d (%f %% of recs)\n",
 | |
| 					i, count[i], 100.0*((float)(i*count[i]))/((float)n));
 | |
| 		}
 | |
| 	}
 | |
| 	printf("Avg bucket length %f\n", avg);
 | |
| 	printf("Range of hash function: %d..%d\n", low, hi);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Given a string, this function allocates and returns a pointer to a
 | |
|  * symbol table record whose "symbol" pointer is reset to a position
 | |
|  * in the string table.
 | |
|  */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| Sym * zzs_new(char *text)
 | |
| #else
 | |
| Sym * zzs_new(text)
 | |
| char *text;
 | |
| #endif
 | |
| {
 | |
| 	Sym *p;
 | |
| 	
 | |
| 	if ( (p = (Sym *) calloc(1,sizeof(Sym))) == 0 )
 | |
| 	{
 | |
| 		fprintf(stderr,"Out of memory\n");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 	p->symbol = zzs_strdup(text);
 | |
| 	
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| /* create a new symbol table entry and add it to the symbol table */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| Sym * zzs_newadd(char *text)
 | |
| #else
 | |
| Sym * zzs_newadd(text)
 | |
| char *text;
 | |
| #endif
 | |
| {
 | |
| 	Sym *p = zzs_new(text);
 | |
| 	if ( p != NULL ) zzs_add(text, p);
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| /* Add a string to the string table and return a pointer to it.
 | |
|  * Bump the pointer into the string table to next avail position.
 | |
|  */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| char * zzs_strdup(char *s)
 | |
| #else
 | |
| char * zzs_strdup(s)
 | |
| register char *s;
 | |
| #endif
 | |
| {
 | |
| 	register char *start=strp;
 | |
| 
 | |
| 	while ( *s != '\0' )
 | |
| 	{
 | |
| 		if ( strp >= &(strings[strsize-2]) )
 | |
| 		{
 | |
| 			fprintf(stderr, "sym: string table overflow (%d chars)\n", strsize);
 | |
| 			exit(-1);
 | |
| 		}
 | |
| 		*strp++ = *s++;
 | |
| 	}
 | |
| 	*strp++ = '\0';
 | |
| 
 | |
| 	return( start );
 | |
| }
 |