Mercurial > hg-old > index.cgi
diff old-trunk/lwasm/old/symbol.c @ 339:eb230fa7d28e
Prepare for migration to hg
author | lost |
---|---|
date | Fri, 19 Mar 2010 02:54:14 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/old-trunk/lwasm/old/symbol.c Fri Mar 19 02:54:14 2010 +0000 @@ -0,0 +1,252 @@ +/* +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 <config.h> +#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(sym, '$')) + { + 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 == '@' || (*p == '$' && !(as -> pragmas & PRAGMA_DOLLARNOTLOCAL))) + 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) && ((flags & SYMBOL_COMPLEX) || !(flags & SYMBOL_GLOBAL))) + 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); + } +}