/* 
 *	Symbol table manipulation routines for mp.  The general symbol table
 *	organization is linked list representation with bucketing to
 *	decrease search time.  The buckets are determined by the first
 *	character of the symbol (and thus 54 buckets are needed).
 *
 *	If this implementation turns out to be a bottleneck, some other type
 *	of bucket mapping function may be defined to reduce crowding.  If this
 *	fails to be adequate, then a completely different symbol table
 *	mechanism could be tried (but remember that we need the ability to
 *	delete symbols, which makes a simple hasing technique untenable).
 */

/*
 * Include global constant definitions
 */

#include "mpdefs.h"

struct sym *sym_bkts[54];	/* Symbol table buckets */

/*
 * Symbol table lookup
 */

struct sym *lookup(symbol)
    register char *symbol;
    {
	register struct sym *ptr;

	for (ptr = sym_bkts[bkt_map(*symbol)]; ptr != NIL; ptr = ptr->next)
		if (lexeq(symbol, ptr->name))
			break;
	return(ptr);
    }

/*
 * Enter a symbol into the symbol table
 */

struct sym *sym_enter(symbol, nargs, defptr)
char *symbol, *defptr;
int nargs;
{
	register int bucket;
	register struct sym *p, *tp;

	bucket = bkt_map(*symbol);
	if ((p = lookup(symbol)) != NIL)
		free(p->defptr);	/* free old definition buffer	*/
	else {
		/*
		 * Allocate a new symbol table node
		 */
		p = get_mem(sizeof *sym_bkts[0]);
		p->next = NIL;
		if(sym_bkts[bucket] == NIL)
			sym_bkts[bucket] = p;
		else {
			for (tp = sym_bkts[bucket]; tp->next != NIL;
					tp = tp->next);
			tp->next = p;
		}
	}
	strcpy(p->name, symbol);	/* Copy name into entry		*/
	p->nargs = nargs;		/* Set number of parameters	*/
	p->defptr = defptr;		/* Set ptr to definition block	*/
	p->ref = 0;			/* Clear reference flag		*/
	return(p);
}

/*
 * Delete a symbol from the symbol table
 */

int sym_del(symbol)
char *symbol;
{
	register struct sym *p, *tp;
	register int bucket;

	bucket = bkt_map(*symbol);
	for (p = sym_bkts[bucket]; p != NIL; tp = p, p = p->next)
		if (lexeq(symbol, p->name)) {
			free(p->defptr);	/* Free old definition	*/
			if (p == sym_bkts[bucket])
				sym_bkts[bucket] = p->next;
			else tp->next = p->next;
			free(p);		/* And release node	*/
			return(OK);
		}
	return(ERROR);
}

/*
 * Map an alphabetic character into a symbol table bucket index
 */

int bkt_map(c)
    register char c;
    {
	if(!c_alpha(c))
		screech("Invalid call to bkt_map()");
	if (c == '_')
		return(52);
	else if (c == '$')
		return(53);
	else if (c >= 'A' && c <= 'Z')
		return(c - 'A');
	else return(c - ('a' - 26));
    }

/* Dump contents of symbol table */

sym_print()
{
	register int i;
	register struct sym *p;
	register char *cp;

	printf("\n\nSymbol table dump follows:\n");
	for (i = 0; i < 54; i++)
		for (p = sym_bkts[i]; p != NIL; p = p->next) {
			printf("%s<%d,%d>=", p->name, p->nargs, p->ref);
			for (cp = p->defptr; *cp != EOS; cp++)
				if (*cp & 0200)
					printf("#%c",(*cp & 0177)+'0');
				else	printf("%c", *cp);
			printf("\n");
		}
	return;
}

/* Initialize symbol table buckets */

sym_init()
{
	register int i;

	for (i = 0; i < 54; i++)
		sym_bkts[i] = NIL;
	return;
}
