File:  [MW Coherent from dump] / coherent / b / bin / as / sym.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * Symbol table functions.
 */
#include <asm.h>
#include <symtab.h>
#include <y_tab.h>

#define SHASH	((unsigned short)1021)	/* symbol table hash */
sym 	**symhash;			/* macros equs and symbols */
static	char	*lastSym;		/* last symbol defined */

/*
 * This routine is called early in the
 * game to set up the hashtable.
 */
void
symInit()
{
	register psym  *sp;
	register unsigned short ht;

	symhash = (sym **)alloc(SHASH * sizeof(sp));

	/* init symbol table */
	for(sp = symtab;  sp < symtab  + SYMCOUNT; sp++) {
		if (rswitch && ('%' == sp->name[0]) && sp->name[1])
			sp->name++;
		sp->next = symhash[ht = hash(sp->name) % SHASH];
		symhash[ht] = (sym *)sp;
	}

	lastSym = "";	/* last symbol defined is null */
}

/*
 * Free macro space.
 */
freeMac(mp)
register macro *mp;
{
	freeList((parm *)mp->first);	/* free lines */
	freeList(mp->names);		/* free parms */
	free((char *)mp);		/* free macro */
}

/*
 * Returns a 1 if this symbol should not be output
 * to the symbol table.
 */
static
notSym(sp)
register sym *sp;
{
	/* don't out put symbols given numbers already */
	if (sp->num)
		return (1);

	/* don't output unused .globls */
	if ((sp->flag & S_EXREF) && !(sp->flag & S_USED))
		return (1);

	if (!(sp->flag & (S_EXREF|S_EXDEF))) {
		register char *p;

		/* don't output non global symbols if -x option */
		if (xswitch)
			return (1);

		p = SYMNAME(sp);

		/* don't output symbols starting .L is -X option */
		if (Xswitch && (p[0] == '.') && (p[1] == 'L'))
			return (1);

		/* don't output local symbols */
		if (NULL != strchr(p, ';'))
			return (1);
	}

	/* don't output dot symbol */
	if (&dot == (psym *)sp)
		return (1);

	return (0);
}

/*
 * Give numbers to all identifier symbols.
 * Mark undefined symbols as exref if -g.
 * Delete symbols defined by macro, equs and equ.
 * Called at the end of pass 0 and 1.
 */
unsigned short
symGlob(number)
{
	register sym *sp, **psp;
	register unsigned short i;

	for(i = 0; i < SHASH; i++) {
		for(psp = symhash + i; NULL != (sp = *psp); ) {
			switch(sp->type) {
			case MACTYPE: /* delete macro */
			case MACSTR:  /* delete define */
				*psp = sp->next;	/* rechain list */
				freeMac((macro *)sp);
				continue;

			case NUMBER: /* delete equ */
				if ((2 == pass) && (sp->flag & S_EXDEF))
					sp->num = number++;
				sp->type = IDENTIFIER;
				sp->flag = S_UNDEF;
				break;

			case IDENTIFIER:
				if((sp->flag & S_UNDEF) && gswitch)
					sp->flag = (S_EXREF | S_USED);

				if((2 == pass) && !notSym(sp))
					sp->num = number++;
			}
			psp = &(sp->next);	/* follow list */
		}
	}
	lastSym = "";
	return(number);
}

/*
 * Dump symbol data
 */
void
symDump(output, limit)
int (*output)();
long limit;
{
	register sym *sp;
	register i;

	for(i = 0; i < SHASH; i++)
		for(sp = symhash[i]; NULL != sp; sp = sp->next) {
			if(sp->num > limit) {
				switch(sp->type) {
				case NUMBER:
				case IDENTIFIER:
					(*output)(sp);
				}
			}
		}
}

/*
 * This is called when debug records are created. It repoints
 * the symbol number to one of the debug records. symDump then
 * uses this information to avoid dumping the symbol twice.
 * This means debug data can seriously screw up an output file
 * if it is wrong.
 */
symReNumber(id, number)
char *id;
int number;
{
	short i;
	register sym *sp;

	for(sp = symhash[i = hash(id) % SHASH];
	    sp != NULL;
	    sp = sp->next) {
		if(!strcmp(id, SYMNAME(sp))) {
			sp->num = number;
			break;
		}
	}
}

/*
 * Undefined symbol message.
 */
static void
unDefMsg(id)
char *id;
{
	char *pt;

	if(NULL != (pt = strchr(id, ';'))) {
		*pt = '\0';
		yyerror("Undefined symbol '?%s'", id);
		/* NODOC */
		*pt = ';';
	}
	else
		yyerror("Undefined symbol '%s'", id);
		/* A symbol was used without defining it or using
		 * a \fB-g\fR option.
		 * You must define local symbols. */
}

/*
 * Redefined symbol message.
 */
static void
redef(id)
char *id;
{
	yyerror("Redefinition of '%s'", id);
	/* An assembler internal symbol is being redefined. */
}

/*
 * Duplicate symbol message.
 */
static void
dupsym(id)
register char *id;
{
	register char *pt;

	if(NULL != (pt = strchr(id, ';'))) {
		*pt = '\0';
		yyerror("Duplicate symbol '?%s'", id);
		/* NODOC */
		*pt = ';';
	}
	else
		yyerror("Duplicate symbol '%s'", id);
	/* \fIsymbol\fR is defined on two different lines. */
}

/*
 * Lookup the name `id' in a hashtable.
 * If it is not found build it.
 */
sym *
symLookUp(id, flag, loc, sg)
long loc;
char *id;
{
	register sym *sp;
	char *locSym;
	short i;

	if('?' == id[0] && id[1]) {	/* local symbol */
		locSym = galloc((unsigned)(strlen(id) + strlen(lastSym) + 1));
		sprintf(locSym, "%s;%s", id + 1, lastSym);
		id = locSym;
	}
	else
		locSym = NULL;

	for(sp = symhash[i = hash(id) % SHASH];
	    sp != NULL;
	    sp = sp->next) {
		if((sp->type > MACSCAN) && !strcmp(id, SYMNAME(sp))) {
			if(2 == pass) {
				switch(flag) {
				case S_UNDEF: /* we are looking for it */
					if((S_UNDEF & sp->flag) &&
					   (DEFINED != lastToken) &&
					   (S_GLOBL != kind))
						unDefMsg(id);
					if (sp->flag & S_ASYM)
						sp->flag |= S_USED;
					return(sp);

				case S_LOCAL: /* being defined here */
					if(!(sp->flag & S_ASYM))
						redef(id);

					else if(sp->flag & S_EXREF) {
						sp->flag &= ~S_EXREF;
						sp->flag |= S_EXDEF|S_LOCAL;
					}
					else if(statement != sp->statement)
						dupsym(id);
					else if((sp->loc != loc) ||
						(sp->sg != sg))
						yyerror("Phase error '%s'",
							id);
		/* A symbol is defined one way in one phase of the assembly
		 * and another way in the next phase. */
					break;

				case S_XSYM:  /*  a number */
					if(!(sp->flag & S_ASYM)) {
						redef(id);
						return(sp);
					}
					if (sp->flag & S_LOCAL)
						dupsym(id);
					if (sp->flag & S_EXREF) {
						sp->flag &= ~S_EXREF;
						sp->flag |= S_EXDEF;
					}
					sp->flag &= ~(S_UNDEF|S_LOCAL);
					sp->flag |= S_XSYM;
					sp->type = NUMBER;
					sp->loc  = loc;
					sp->sg   = -1;	/* absolute */
					return(sp);
				}
				break;
			}
			else {	/* pass 0 and 1 */
				switch(flag) {
				case S_UNDEF:	/* looking for it */
					if (sp->flag & S_ASYM)
						sp->flag |= S_USED;
					return(sp);

				case S_LOCAL:	/* being defined here */
					if(!(sp->flag & S_ASYM))
						return(sp);

					sp->statement = statement;

					if(sp->flag & S_EXREF) {
						sp->flag &= ~S_EXREF;
						sp->flag |= S_EXDEF|S_LOCAL;
					}
					else {
						sp->flag &= ~S_UNDEF;
						sp->flag |= flag;
					}
					break;

				case S_XSYM:  /* a number */
					if(!(sp->flag & S_ASYM))
						return(sp);
					if (sp->flag & S_EXREF) {
						sp->flag &= ~S_EXREF;
						sp->flag |= S_EXDEF;
					}
					sp->flag &= ~(S_UNDEF|S_LOCAL);
					sp->flag |= S_XSYM;
					sp->type = NUMBER;
					sp->loc  = loc;
					sp->sg   = -1;	/* absolute */
					return(sp);
				}
				break;
			}
		}
	}

	if(NULL == sp) 	{
		if (DEFINED == lastToken) {
			static psym sy = {
				NULL, IDENTIFIER, 0, 0, 0, S_UNDEF,
				NULL, 0, 0, NULL
			};

			return (&sy);
		}
		sp = (sym *) scpy(id, offset(sym, name));
		sp->next = symhash[i];
		sp->ref = symhash[i] = sp;
		sp->flag = flag;
	}
	sp->type = IDENTIFIER;
	switch(flag) {
	case S_UNDEF:
		if (S_GLOBL != kind)
			sp->flag |= S_USED;
		break;
	case S_XSYM:
		sp->type = NUMBER;
		sp->loc = loc;
		sp->sg   = -1;	/* absolute */
		break;
	case S_LOCAL:
		sp->loc = loc;
		sp->sg = sg;
		sp->statement = statement;
		if(NULL == locSym)
			lastSym = sp->name;
	}
	return(sp);
}

/*
 * Lookup a name in opcodes.
 * return it's index or -1.
 */
short
opLookUp(id)
char *id;
{
	register nhash *op;
	short i, l;

	for (l = strlen(id), i = hash(id) % OPCOUNT;;) {
		if ((l == (op = hashCodes + i)->nlen) &&
		   !memcmp(id, (charLump + op->nameIx), l)) {
			choices = op->count;
			return(op->prefIx);
		}
		if (-1 == (i = op->next))
			return (-1);
	}
}

/*
 * Remove an entry from the opcode table.
 */
void
opDelete(id)
char *id;
{
	register nhash *op;
	short i, l;

	l = strlen(id);
	for(i = hash(id) % OPCOUNT; -1 != i; i = op->next) {
		if((l == (op = hashCodes + i)->nlen) &&
		   !memcmp(id, (charLump + op->nameIx), l)) {
			op->nlen = 0;
			return;
		}
	}
	return;
}

/*
 * Look up macros and equs symbols. Shares table with symbols.
 */
macro *
macLookUp(id, type)
char *id;
{
	register macro *mp;

	for(mp = (macro *)symhash[hash(id) % SHASH];
	    mp != NULL;
	    mp = mp->next)
		if((mp->type == type) && !strcmp(id, mp->name))
			return(mp);
	return(NULL);
}

/*
 * Delete a macro or equs.
 */
macDelete(s, t)
char *s;
short t;
{
	register macro *mp, **pmp;
	short ht;

	for(pmp = (macro **)(symhash + (ht = hash(s) % SHASH));
	    NULL != (mp = *pmp);
	    pmp = &(mp->next)) {
		if((mp->type == t) && !strcmp(s, mp->name)) {
			*pmp = mp->next;	/* unChain */
			freeMac(mp);
			break;
		}
	}
	return(ht);
}

/*
 * Define macro or equs symbol.
 * Shares symbol table with other symbols.
 */
void
defMac(s, p, t)
char *s;
parm *p;
short t;
{
	register macro *tmp;
	short ht;

	ht = macDelete(s, t);	/* remove old form */
	tmp = (macro *)scpy(s, offset(macro, name));

	tmp->names = p;	/* parm names */
	umList(p);

	tmp->next = (macro *)symhash[ht];
	symhash[ht] = (sym *)tmp;
	if(MACTYPE == (tmp->type = t)) {
		newLevel(INMACDEF);
		inMacDef = tmp;
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.