/*
	Copyright 1982
	Alcyon Corporation
	8716 Production Ave.
	San Diego, Ca.  92121

	@(#)symt.c	1.8	12/30/83
*/

/**
 * symbol table entry allocation and lookup routines
**/

#include "parser.h"

#define	STEL	HSIZE/2

#ifndef SYM_TO_DSK
struct symbol *symtab[HSIZE];		/*hash table*/
struct symbol *symbols;				/*pointer to next avail symbol buf*/
#endif

/**
 * syminit - initialize the symbol table, install reswords
 *		Goes thru the resword table and installs them into the symbol
 *		table.
**/
syminit()							/* returns - none*/
{
	register struct resword *rp;

#ifdef SYM_TO_DSK
	install("",0,0);	/* null entry at zero */
#endif
	for( rp = &reswords[0]; rp->r_name != 0; rp++ )
		install(rp->r_name,SRESWORD|SDEFINED,rp->r_value);
}

#ifndef SYM_TO_DSK
/**
 * install - install a symbol in the symbol table
 *		Allocates a symbol entry, copies info into it and links it
 *		into the hash table chain.
**/
char *
install(sym,attrib,offset)			/* returns pointer to symbol struct*/
char *sym;							/* symbol to install*/
int attrib;							/* attribues of symbol*/
int offset;							/* symbol offset (resword value)*/
{
	register struct symbol *sp;
	register short i, is;

#ifndef DECC
	while( (sp=symbols) <= 0 ) {
#else
	/**
	 *	Peculiar bug on the vax required changing <= to ==.  DEC
	 *	people are checking into why the relational <, >, <=, >=
	 *	don't work properly when a global pointer to a structure
	 *	is compared with 0.
	**/
	while( (sp=symbols) == 0 ) {
#endif
		if( (sp = (struct symbol *)sbrk(SYMSIZE)) == -1 )
			ferror("symbol table overflow");
		for( i = SYMSIZE/(sizeof *symbols); --i >= 0; ) {
			if (sp <= 0)
				ferror("bad symbol table");
			sp->s_next = symbols;
			symbols = sp++;
		}
	}
	is = in_struct;
	symbols = sp->s_next;
	sp->s_attrib = attrib;
	sp->s_offset = offset;
	sp->s_sc = sp->s_type = sp->s_dp = sp->s_ssp = 0;
	sp->s_sib = sp->s_child = sp->s_par = 0;
	if (is) {
		sp->s_par = struc_parent[is];
		hold_sib = struc_sib[is];
		sp->s_scope = (infunc) ? FUNC_SCOPE : GLOB_SCOPE;	        /* [vlh] 4.2 */
		if (struc_sib[is])
			struc_sib[is]->s_sib = sp;
		else
			struc_parent[is]->s_child = sp;
		struc_sib[is] = sp;
	}
	else
		sp->s_scope = scope_level;			/* [vlh] 4.2 */

	symcopy(sym,sp->s_symbol);			/*copy symbol to symbol struct*/
	i = symhash(sym,is|smember);		/*link into chain list*/
	sp->s_next = symtab[i];
	symtab[i] = sp;
#ifdef DEBUG
		if (symdebug && attrib != (SRESWORD|SDEFINED)) {
			printf("    scope %d\n",sp->s_scope);
			/*
			if(sp->s_par) printf("    struct element parent [%.8s] %d %ld\n", 
						  sp->s_par->s_symbol,is,sp->s_par);
			else printf("    NO parent\n");
			if(struc_sib[is]) printf("    struct sib [%.8s]\n",
						 struc_sib[is]->s_symbol);
			else printf("    struct sib NULL\n");
			if(struc_parent[is]) { 
				printf("    struct par [%.8s] ",struc_parent[is]->s_symbol);
				if(struc_parent[is]->s_child) printf("child [%.8s]\n",
									        struc_parent[is]->s_child->s_symbol);
				else printf("no child\n");
			}
			else printf("    struct parent NULL\n");
			*/
		}
#endif
	return((char *)sp);
}

/**
 * lookup - looks up a symbol in symbol table
 *		Hashes symbol, then goes thru chain, if not found, then
 *		installs the symbol.
**/
char *
lookup(sym,force)			/* returns pointer to symbol buffer*/
char *sym;					/* pointer to symbol*/
int force;					/* [vlh] 4.2 force entry in symbol table */
{
	register struct symbol *sp, *hold;
	register char *p;
	short exact, prev_level;		/* same name, diff type or offset */

	p = sym; prev_level = 0;
	for( sp = symtab[symhash(p,0)]; sp != 0; sp = sp->s_next )
		if((sp->s_attrib&(SRESWORD|STYPEDEF)) && symequal(p,sp->s_symbol))
			return(sp);
	hold = 0;
	if (!(smember|in_struct)) {	/*[vlh]*/
		for( sp=symtab[symhash(p,0)]; sp!=0; sp=sp->s_next )
			if(symequal(p,sp->s_symbol)) {
				if (scope_level == sp->s_scope)	/* [vlh] 4.2 added scope... */
					return(sp);			        	/* perfect scope match */
				else
					if (!force && prev_level <= sp->s_scope) {
						hold = sp;
						prev_level = sp->s_scope;
					}
			}
		if ( hold ) /* [vlh] 4.2 added scope... */
			return(hold);
	}
	else {	/* doing a declaration or an expression */
		exact = 0;
		for( sp=symtab[symhash(p,in_struct|smember)]; sp!=0; sp=sp->s_next ) {
			if( symequal(p,sp->s_symbol) ) {
				if (symsame(sp,hold,&exact)) 
					return(sp);
				else if (!hold && !exact) 
					hold = sp;
			}
		}
		if (hold && (instmt || in_struct==0 || smember!=0)) /*4.1*/
			return(hold);
	}
#ifdef DEBUG
	if (symdebug) printf("installing [%.8s] %d\n",p,indecl);
#endif
	return(install(p,0,0));
}

/**
 * freesyms - frees all local symbols at end of function declaration
 *		Searches thru symbol table, deleting all symbols marked as locals
**/
freesyms(level)							/* returns - none*/
int level;								/* [vlh] 4.2 scope levels... */
{
	register short i;
	register struct symbol *sp, *tp, *nextp, **htp;

	for( htp = &symtab[0], i = HSIZE; --i >= 0; htp++ )
		for( tp = 0, sp = *htp; sp != 0; sp = nextp ) {
			nextp = sp->s_next;
			if (level == FUNC_SCOPE)
				if( !(sp->s_attrib&SDEFINED) ) {
					error("undefined label: %.8s",sp->s_symbol);
					sp->s_attrib |= SDEFINED;
				}
			if (sp->s_attrib & (SGLOBAL|SRESWORD) )
				tp = sp;
			else if ( !(sp->s_attrib & SGLOBAL) && sp->s_scope < level)
				tp = sp;
			else {
#ifdef DEBUG
	if (symdebug)
		printf("freeing %s, level %d\n",sp->s_symbol,level);
#endif
				if( tp )
					tp->s_next = sp->s_next;
				else
					*htp = sp->s_next;
				sp->s_next = symbols;
				symbols = sp;
			}
		}
}

/**
 * chksyms - checks symbol table for undefined symbols, etc.
 *		Goes thru the symbol table checking for undeclared forward
 *		referenced structures, and outputs local symbols for debugger.
**/
chksyms(ok)							/* returns - none*/
int ok;
{
	register struct symbol **htp, *sp;
	register short i, sc;

	for( htp = &symtab[0], i = HSIZE; --i >= 0; htp++ )
		for( sp = *htp; sp != 0; sp = sp->s_next ) {
			sc = sp->s_sc;
			if(sc!=0 && sp->s_ssp>=0 && (BTYPE(sp->s_type))==FRSTRUCT) {
				sp->s_par = frstab[sp->s_ssp]->s_par;
#ifdef DEBUG
	if(symdebug) printf("[%s] <= par [%s]\n",sp->s_symbol,sp->s_par->s_symbol);
#endif
				sp->s_ssp = frstab[sp->s_ssp]->s_ssp;	  /* 3.4 ssp>0 */
				sp->s_type = (sp->s_type&~TYPE) | STRUCT; /* 4.2+ moved */
			}
			if( sc == PDECLIST || sc == PDECREG ) {
				error("not in parameter list: %.8s",sp->s_symbol);
				sp->s_sc = (sc == PDECLIST) ? AUTO : REGISTER;
				if (ok) 
					outlocal(sp->s_type,sp->s_sc,sp->s_symbol,sp->s_offset);
			}
		}
}
#endif

/**
 * symhash - compute hash value for symbol
 *		Sums the symbols characters and takes that modulus the hash table
 *		size.
 *		[vlh] 4.3, symhash must be on minimum number of chars which is a max
 *			eg. Maximum number for external variable is SSIZE-1...
**/
symhash(sym,stel)					/* returns hash value for symbol*/
char *sym;							/* pointer to symbol*/
int stel;							/* structure element flag*/
{
	register char *p;
	register short hashval, i;

	hashval = (stel ? STEL : 0 );
	for( p = sym, i = SSIZE-1; *p != '\0' && i > 0; i-- )
		hashval += *p++;
	return( hashval % HSIZE );
}

/**
 * symequal - check for symbol equality
 *		Does comparison between two symbols.
 *		[vlh] 4.3, global (external symbols) match at SSIZE-1!!!
**/
symequal(sym1,sym2)					/* returns 1 if equal, 0 otherwise*/
char *sym1;							/* pointer to first symbol*/
char *sym2;							/* pointer to second symbol*/
{
	register char *p, *q;
	register short i;

	i = (scope_level == GLOB_SCOPE && !smember && !in_struct) ? SSIZE-1 : SSIZE;
	for( p = sym1, q = sym2; *p == *q++; )
		if( *p++ == '\0' || --i == 0 )
			return(1);
	return(0);
}

/* symsame - symbol member same as declared */
symsame(sp,hold,exact)	/* [vlh] */
struct symbol *sp, *hold;
short *exact;
{
	if (struc_parent[in_struct]==sp->s_par) /* all structures have parents */
		return(1);
	if (hold)
		if (sp->s_type != hold->s_type || sp->s_offset != hold->s_offset)
			*exact = 1;
	return(0);
}

/* symcopy - symbol copy*/
/*		Copies one symbol to another.*/
symcopy(sym1,sym2)					/* returns - none*/
char *sym1;							/* pointer to symbol to copy*/
char *sym2;							/* pointer to area to copy to*/
{
	register char *p, *q;
	register short i;

	for( p = sym1, q = sym2, i = SSIZE; --i >= 0; )
		*q++ = ( *p ? *p++ : '\0');
}
IZE; --i >= 0; )
		*q++ = ( *p ? *p++ : '\0');
}
IZE; --i >= 0; )
		*q++ = ( *p ? *p++ : '\0');
}
IZE; --i >= 0; )
		*q++ = ( *p ? *p++ : '\0');
}
IZE; --i >= 0; )
		*q++ = ( *p ? *p++ : '\0');
}
