diff lwasm/symbol.c @ 151:427e268e876b

renamed src to lwasm to better reflect its purpose
author lost
date Fri, 30 Jan 2009 04:01:55 +0000
parents src/symbol.c@0ee5f65bccf9
children 563adfccb645
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/symbol.c	Fri Jan 30 04:01:55 2009 +0000
@@ -0,0 +1,249 @@
+/*
+symbol.c
+Copyright © 2009 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/>.
+*/
+
+/*
+for handling the symbol table
+*/
+
+#define __symbol_c_seen__
+
+#include <string.h>
+
+#include "lwasm.h"
+#include "util.h"
+#include "expr.h"
+
+/*
+Note that this function may accept symbols that the expression evaluator doesn't
+recognize because the expression evaluator must avoid all ambiguity in order
+to achieve predictable results. The checks here are simply a fuzz check.
+*/
+
+/*
+NOTE: complex symbols always take their value from slot 0 on the expression placeholders
+for a line!
+*/
+int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags)
+{
+	lwasm_symbol_ent_t *se, *se2;
+	char *p;
+	
+	int scontext = -1;
+	
+	// if the symbol is constant, fall back to simple registration!
+	if (flags & SYMBOL_COMPLEX)
+	{
+		if (l -> exprs[0] == NULL)
+		{
+			val = l -> exprvals[0];
+			flags &= ~SYMBOL_COMPLEX;
+		}
+	}
+	
+	// first check if the symbol is valid
+	// the following characters are allowed in a symbol:
+	// [a-zA-Z0-9._$?@] and any byte value larger than 0x7F
+	// although symbols should be restricted to the 7 bit range
+	// symbols must start with [a-zA-Z._]
+	if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._@?", *sym))
+	{
+		register_error(as, l, 1, "Bad symbol: %s", sym);
+		return -1;
+	}
+	
+	if (*sym == '@' && isdigit(sym[1]))
+	{
+		register_error(as, l, 1, "Bad symbol: %s", sym);
+		return -1;
+	}
+	
+	for (p = sym; *p; p++)
+	{
+		if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._$?@0123456789", *sym))
+		{
+			register_error(as, l, 1, "Bad symbol: %s", sym);
+			return -1;
+		}
+		// flag local symbols while we're at it...
+		if (*p == '?' || *p == '@')
+			scontext = as -> context;
+	}
+	
+	debug_message(3, "lwasm_register_symbol(): registering '%s' (%d) at %04X; flags=%d", sym, scontext, val, flags);
+	
+	// now look it for to see if it is a duplicate
+	se = lwasm_find_symbol(as, sym, scontext);
+	if (se)
+	{
+		if (flags & SYMBOL_FORCE && as -> passnum != 2)
+		{
+			register_error(as, l, 1, "Multiply defined symbol: %s", sym);
+			return -1;
+		}
+		if (!(flags & SYMBOL_SET) || (flags & SYMBOL_SET && !(se -> flags & SYMBOL_SET)))
+		{
+			register_error(as, l, 1, "Mulitply defined symbol: %s", sym);
+			return -1;
+		}
+	}
+	if (se)
+	{
+		se -> value = val;
+		if (flags & SYMBOL_COMPLEX)
+		{
+			se -> expr = l -> exprs[0];
+		}
+		else
+		{
+			se -> expr = NULL;
+		}
+		return;
+	}
+
+	// if not a duplicate, register it with the value
+	se = lwasm_alloc(sizeof(lwasm_symbol_ent_t));
+	if (as -> symhead)
+	{
+		se -> prev = NULL;
+		se -> next = as -> symhead;
+		as -> symhead -> prev = se;
+		as -> symhead = se;
+	}
+	else
+	{
+		se -> next = NULL;
+		se -> prev = NULL;
+		as -> symhead = se;
+		as -> symtail = se;
+	}
+	se -> value = val;
+	if (flags & SYMBOL_COMPLEX)
+		se -> expr = l -> exprs[0];
+	se -> sym = lwasm_strdup(sym);
+	se -> context = scontext;
+
+	if (!(flags & SYMBOL_EXTERN))
+		se -> sect = as -> csect;
+	else
+		se -> sect = NULL;
+
+	se -> expr = NULL;
+	se -> flags = flags;
+	se -> externalname = NULL;
+
+	return 0;
+}
+
+lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext)
+{
+	lwasm_symbol_ent_t *se;
+	static int st = 0;
+	
+	for (se = as -> symhead; se; se = se -> next)
+	{
+		if (scontext == se -> context && !strcmp(sym, se -> sym))
+		{
+			return se;
+		}
+	}
+	if (as -> passnum == 2 && st == 0 && scontext == -1 && as -> outformat == OUTPUT_OBJ && as -> pragmas & PRAGMA_UNDEFEXTERN)
+	{
+		// we want undefined symbols to be considered external
+		// we didn't find it on a lookup so register it as external
+		// but we only do so when looking up in global context
+		st = 1;
+		if (lwasm_register_symbol(as, NULL, sym, 0, SYMBOL_EXTERN))
+		{
+			st = 0;
+			return NULL;
+		}
+		st = 0;
+		
+		// find the newly registered symbol and return it
+		for (se = as -> symhead; se; se = se -> next)
+		{
+			if (scontext == se -> context && !strcmp(sym, se -> sym))
+			{
+				return se;
+			}
+		}
+	}
+		
+	return NULL;
+}
+
+// reset the value of a symbol - should not be used normally
+// it is intended for use by such operations as EQU
+// returns -1 if the symbol is not registered
+int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val)
+{
+	lwasm_symbol_ent_t *se;
+	
+	se = lwasm_find_symbol(as, sym, scontext);
+	if (!se)
+		return -1;
+	
+	se -> value = val;
+	return 0;
+}
+
+void lwasm_list_symbols(asmstate_t *as, FILE *lf)
+{
+	lwasm_symbol_ent_t *se;
+	
+	for (se = as -> symhead; se; se = se -> next)
+	{
+		if (se -> expr)
+		{
+			fprintf(lf, "<incompl>");
+		}
+		else if (se -> value > 0xffff || se -> value < -0x8000)
+		{
+			fprintf(lf, "%08X ", se -> value);
+		}
+		else
+		{
+			fprintf(lf, "    %04X ", se -> value);
+		}
+		if (se -> context < 0)
+			fputc('G', lf);
+		else
+			fputc('L', lf);
+		
+		if (se -> flags & SYMBOL_SET)
+			fputc('S', lf);
+		else if (se -> flags & SYMBOL_EXTERN)
+			fputc('E', lf);
+		else
+			fputc(' ', lf);
+		
+		fprintf(lf, " %s", se -> sym);
+		
+		if (se -> context >= 0)
+			fprintf(lf, " (%d)", se -> context);
+		
+		if (se -> sect)
+		{
+			fprintf(lf, " [%s]", se -> sect -> name);
+		}
+		
+		fputc('\n', lf);
+	}
+}