view src/symtab.c @ 8:f1df096aa76f 1.1

Tagged 1.1 bugfix release
author lost
date Sun, 04 Jan 2009 05:46:07 +0000
parents 34568fab6058
children
line wrap: on
line source

/*
symtab.c
Copyright © 2008 William Astle

This file is part of LWASM.

LWASM is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.

Implements code for handling the symbol table.
*/

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __symtab_c_seen__
#include "lwasm.h"

void register_symbol(asmstate_t *as, sourceline_t *cl, char *symstr, int val, int flags)
{
	symtab_t *st;
	symtab_t *prev;
	int cv = -2;
	
	for (prev = NULL, st = as -> symbol_table; st; st = st -> next)
	{
		cv = strcasecmp(st -> symbol, symstr);
		if (cv == 0)
		{
			cv = strcmp(st -> symbol, symstr);
		}
		if (cv >= 0)
			break;
		prev = st;
	}
	// cv is 0 if we found the symbol, > 0 if we didn't and found one
	// later in order, or -2 if we never did a comparison
	// if st is NULL, the value of cv is irrelevant as it means
	// we fell off the end of the list
	// if st is NULL and prev is not, then prev is the tail of the list
	// if both are NULL, the list is empty
	
	// handle adding the symbol if needed
	if (!st || cv != 0)
	{
		symtab_t *st2;
		// register the symbol
		st2 = malloc(sizeof(symtab_t));
		st2 -> symbol = strdup(symstr);
		st2 -> addr = val;
		st2 -> flags = 0;
		if (flags & SYMFLAG_SET)
			st2 -> flags |= SYMFLAG_SET;

		if (prev)
			prev -> next = st2;
		else
			as -> symbol_table = st2;
		
		st2 -> next = st;
		return;
	}
	
	// st is NOT NULL here and cv IS 0
	if ((flags & SYMFLAG_SET) && ((st -> flags) & SYMFLAG_SET))
	{
		// symbol already exists but it is a "SET" symbol so reset the value
		st -> addr = val;
		return;
	}
	if (st && as -> passnum == 1)
	{
		// duplicate symbol, flag error
		errorp1(ERR_DUPSYM);
	}
	if (st -> addr != val)
		errorp2(ERR_PHASE);
}

int lookup_symbol(asmstate_t *as, char *symstr)
{
	symtab_t *st;

	for (st = as -> symbol_table; st; st = st -> next)
	{
		if (!strcmp(symstr, st -> symbol))
			break;
	}
	if (st)
		return st -> addr;
	return -1;
}

void list_symbols(asmstate_t *as, FILE *f)
{
	symtab_t *st;
	for (st = as -> symbol_table; st; st = st -> next)
	{
		fprintf(f, "%04X %s%s\n", st -> addr, st -> symbol, (st -> flags & SYMFLAG_SET) ? "(S)" : "");
	}
}