Mercurial > hg-old > index.cgi
diff lwasm/lwasm.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/lwasm.c@0ee5f65bccf9 |
children | bae1e3ecdce1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/lwasm.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,428 @@ +/* +lwasm.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/>. + + +Contains random functions used by the assembler +*/ + +#define __lwasm_c_seen__ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include "lwasm.h" +#include "util.h" +#include "expr.h" + +int debug_level = 0; + +int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...) +{ + lwasm_error_t *e; + va_list args; + char errbuff[1024]; + int r; + + if (!l) + return; + + if (as -> passnum != pass) + return; + + va_start(args, fmt); + + e = lwasm_alloc(sizeof(lwasm_error_t)); + + e -> next = l -> err; + l -> err = e; + + as -> errorcount++; + + r = vsnprintf(errbuff, 1024, fmt, args); + e -> mess = lwasm_strdup(errbuff); + + va_end(args); + + return r; +} + +void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b) +{ + as -> addr += 1; + as -> addr &= 0xffff; + + if (as -> outformat == OUTPUT_OBJ && !(as -> csect)) + { + register_error(as, l, 1, "Output not allowed outside sections with obj target"); + return; + } + if (as -> outformat == OUTPUT_OBJ && as -> csect -> flags & SECTION_BSS) + { + register_error(as, l, 1, "Output not allowed inside BSS sections"); + return; + } + if (as -> passnum == 1) + return; + + + if (l -> codelen >= l -> codesize) + { + l -> bytes = realloc(l -> bytes, l -> codesize + 16); + l -> codesize += 16; + } + l -> bytes[l -> codelen] = b & 0xff; + l -> codelen += 1; +} + +void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o) +{ + if (o >= 0x100) + lwasm_emit(as, l, o >> 8); + lwasm_emit(as, l, o & 0xff); +} + +int lwasm_lookupreg2(const char *reglist, char **str) +{ + int rval = 0; + + while (*reglist) + { + if (toupper(**str) == *reglist) + { + // first char matches + if (reglist[1] == ' ' && !isalpha(*(*str + 1))) + break; + if (toupper(*(*str + 1)) == reglist[1]) + break; + } + reglist += 2; + rval++; + } + if (!*reglist) + return -1; + if (reglist[1] == ' ') + (*str)++; + else + (*str) += 2; + return rval; +} + +int lwasm_lookupreg3(const char *rlist, const char **str) +{ + int rval = 0; + int f = 0; + const char *reglist = rlist; + + while (*reglist) + { + if (toupper(**str) == *reglist) + { + // first char matches + if (reglist[1] == ' ') + { + f = 1; + break; + } + if (toupper(*(*str + 1)) == reglist[1]) + { + // second char matches + if (reglist[2] == ' ') + { + f = 1; + break; + } + if (toupper(*(*str + 2)) == reglist[2]) + { + f = 1; + break; + } + } + } + reglist += 3; + rval++; + } + if (f == 0) + return -1; + + + reglist = rval * 3 + rlist; + if (reglist[1] == ' ') + (*str) += 1; + else if (reglist[2] == ' ') + (*str) += 2; + else + (*str)+=3; + return rval; +} + +struct symstateinfo +{ + asmstate_t *as; + lwasm_line_t *l; + int flags; +}; + +lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state) +{ + lwasm_symbol_ent_t *se; + struct symstateinfo *st; + lwasm_expr_stack_t *rs; + lwasm_expr_term_t *t; + lwasm_expr_stack_node_t *n; + + int val; + + st = state; + debug_message(3, "lwasm_expr_lookup_symbol(): find '%s' (context=%d)", sym, st -> as -> context); + + // check for special symbols first... + if (sym[1] == '\0') + { + switch (sym[0]) + { + // current line address + case '*': + case '.': + val = st -> l -> codeaddr; + goto retconst; + + case '<': + // previous branch point + // not implemented + break; + case '>': + // next branch point + // not implemented + break; + } + } + + // look for local symbol first then global symbol + se = lwasm_find_symbol(st -> as, sym, st -> as -> context); + if (!se) + se = lwasm_find_symbol(st -> as, sym, -1); + debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se); + if (!se) + { + register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym); + return NULL; + } + // external reference - can not resolve it + if (se -> flags & SYMBOL_EXTERN) + { + return NULL; + } + if (st -> flags & EXPR_SECTCONST) + { + if (se -> sect == st -> l -> sect) + { + if (se -> expr) + goto retsym; + val = se -> value; + goto retconst; + } + } + if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) + { + return NULL; + } + if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL) + { + // global symbol, intrasegment reference, or not an object target + val = se -> value; + goto retconst; + } + + // an intersegment reference will return as NULL (to be resolved at output/link time) + // if se -> expr is NULL, it has to be an intersegment reference here + if (se -> expr == NULL) + { + return NULL; + } + +retsym: + // duplicate the expression for return + rs = lwasm_expr_stack_create(); + for (n = se -> expr -> head; n; n = n -> next) + { + lwasm_expr_stack_push(rs, n -> term); + } + return rs; + +retconst: + rs = lwasm_expr_stack_create(); + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(rs, t); + lwasm_expr_term_free(t); + return rs; +} + +lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + st.flags = flags; + + debug_message(2, "Evaluate expression: %s", inp); + + return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st)); +} + + +int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + st.flags = flags; + return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st)); +} + +// return 1 if no undefined symbols (externals and incompletes are okay) +// return 0 if there are undefined symbols +int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s) +{ + lwasm_expr_stack_node_t *n; + lwasm_symbol_ent_t *se; + + if (as -> outformat != OUTPUT_OBJ) + { + if (lwasm_expr_is_constant(s)) + return 1; + else + return 0; + } + + for (n = s -> head; n; n = n -> next) + { + if (n -> term -> term_type == LWASM_TERM_SYM) + { + se = lwasm_find_symbol(as, n -> term -> symbol, as -> context); + if (!se) + se = lwasm_find_symbol(as, n -> term -> symbol, -1); + if (!se) + return 0; + } + } + return 1; +} + +/* +Evaluate an expression according to the flag value. Return 0 if a constant result was +obtained, 1 if an incomplete result was obtained, and -1 if an error was flagged. + +*/ +int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot) +{ + lwasm_expr_stack_t *s = NULL; + const char *ep; + int rval; + + if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0) + { + s = lwasm_evaluate_expr(as, l, *inp, &ep, flag); + if (slot >= 0) + l -> exprs[slot] = s; + if (!s) + { + register_error(as, l, 1, "Bad expression"); + *val = 0; + return -1; + } + *inp = (char *)ep; + if (slot >= 0) + { + l -> exprends[slot] = (char *)ep; + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + } + else if (l -> exprs[slot]) + { + s = l -> exprs[slot]; + lwasm_reevaluate_expr(as, l, s, flag); + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + if (as -> passnum == 2 && slot >= 0) + *inp = l -> exprends[slot]; + + if (s && lwasm_expr_is_constant(s)) + { + *val = lwasm_expr_get_value(s); + lwasm_expr_stack_free(s); + l -> exprs[slot] = NULL; + s = NULL; + return 0; + } + + if (!s && slot >= 0) + { + *val = l -> exprvals[slot]; + return 0; + } + else if (!s) + { + *val = 0; + return 0; + } + + // was a constant result on pass 1 requested? + // that means we must have a constant on either pass + if (flag & EXPR_PASS1CONST) + { + *val = 0; + if (slot >= 0) + l -> exprvals[slot] = 0; + register_error(as, l, 1, "Illegal forward, external, or inter-section reference"); + lwasm_expr_stack_free(s); + if (slot >= 0) + l -> exprs[slot] = NULL; + return -1; + } + + return 1; +} + +void debug_message(int level, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (debug_level >= level) + { + if (level > 0) + fprintf(stderr, "DEBUG %d: ", level); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + } + va_end(args); +} + +int lwasm_next_context(asmstate_t *as) +{ + int r; + r = as -> nextcontext; + as -> nextcontext += 1; + debug_message(3, "lwasm_next_context(): %d (%d) pass %d", r, as -> nextcontext, as -> passnum); + return r; +} +