
/*
 * 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 "link.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);
}

/*
 * SymWrite()
 *
 * Dump symbol as ObjSymbol structures
 */

int
SymWrite(FILE *fp)
{
	int					num, bucket;
	Symbol				sym;
	struct ObjSymbol	symbol;

	for (num = bucket = 0; bucket < NUM_BUCKETS; bucket++)
		for (sym = sBuckets[bucket]; sym; sym = sym->next, num++)
		{
			symbol.s_segment = sym->segment;
			symbol.s_offset = sym->offset;
			symbol.s_name = sym->id;
			if (fwrite(&symbol, sizeof(symbol), 1, fp) != 1)
			{
				if (ferror(fp))
					perror("fwrite");
				cerror("can't write symbol");
			}
		}
	return(num);
}

/*
 * 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)
{
	fprintf(fp, "%s\t", Name(gNames, sym->id));
	fprintf(fp, "\t[%s] : $%04X",
		sym->segment == CodeSegment ? "CODE" :
		sym->segment == DataSegment ? "DATA" :
		sym->segment == BssSegment ? "BSS" :
		sym->segment == AbsSegment ? "ABSL" :
		"???", sym->offset);
	fprintf(fp, "\n");
}

