
/*
 * sym.c
 *
 * (C) Copyright 1995 Archie L. Cobbs
 */

#include <stdio.h>
#include <assert.h>
#include "util.h"
#include "error.h"
#include "hash.h"
#include "names.h"
#include "obj.h"
#include "asm.h"

/*
 * Definitions
 */

/* How many buckets? */

	#define	NUM_BITS			10

	#define	NUM_BUCKETS			(1 << NUM_BITS)
	#define	HASH_MASK			(NUM_BUCKETS - 1)

/*
 * INTERNAL VARIABLES
 */

/* Hash buckets point to first symbol in the list */

	static	Symbol			sBuckets[NUM_BUCKETS];

/*
 * INTERNAL FUNCTIONS
 */

	static	Symbol			*Locate(unsigned id);

/*
 * DefineSym()
 */

Symbol
DefineSym(unsigned id)
{
	Symbol	sym, *symp;

/* Error if previously defined (sometimes) */

	if ((sym = *(symp = Locate(id))))
		cerror("symbol \"%s\" multiply defined", Name(gNames, id));

/* Make a new entry in the hash chain */

	*symp = sym = NewOpaque(Symbol);

/* Initialize symbol */

	sym->id = id;

/* Done */

	return(sym);
}

/*
 * GetSym()
 *
 * Get symbol table entry
 */

Symbol
GetSym(unsigned id)
{
	return(*Locate(id));
}

/*
 * Locate()
 *
 * Locate (possibly non-existent) entry for given symbol
 */

static	Symbol	*
Locate(unsigned id)
{
	int		bucket;
	Symbol	*symp;

	bucket = Hash(&id, sizeof(id)) & HASH_MASK;
	for (symp = sBuckets + bucket;
			*symp && (*symp)->id != id;
			symp = &(*symp)->next);
	return(symp);
}

/*
 * SymDump()
 *
 * Dump symbol table to stream
 */

void
SymDump(FILE *fp)
{
	int		bucket;
	Symbol	sym;

	fprintf(fp, "--- SYMBOL TABLE ---\n");
	for (bucket = 0; bucket < NUM_BUCKETS; bucket++)
		for (sym = sBuckets[bucket]; sym; sym = sym->next)
			ShowSym(fp, sym);
}

/*
 * ShowSym()
 */

void
ShowSym(FILE *fp, Symbol sym)
{
	int	offset = 0;

	fprintf(fp, "%s\t", Name(gNames, sym->id));
	switch (sym->type)
	{
		case sSegRel:
			fprintf(fp, "SEGREL [%s]",
				sym->u.segrel.segment == CodeSegment ? "CODE" :
				sym->u.segrel.segment == DataSegment ? "DATA" :
				sym->u.segrel.segment == BssSegment ? "BSS" :
				sym->u.segrel.segment == AbsSegment ? "ABSL" : "???");
				offset = sym->u.segrel.offset;
			break;
		case sSymOff:
			fprintf(fp, "SYMOFF [%s]", Name(gNames, sym->u.symoff.id));
			offset = sym->u.symoff.offset;
			break;
		default:
			assert(0);
	}
	fprintf(fp, "\t$%04X", offset);
	if (!sym->valid)
		fprintf(fp, "\t(not valid)");
	fprintf(fp, "\n");
}

