Mercurial > hg-old > index.cgi
view src/lwasm.c @ 96:7fbccdd1defb
Added doc subdirectory to distribution
author | lost |
---|---|
date | Sat, 17 Jan 2009 07:09:02 +0000 |
parents | 83ba34ed11b3 |
children | 81fc353d4d69 |
line wrap: on
line source
/* 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 (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; }; 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 -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) { // do not resolve any section symbols in object mode 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; } // 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) { struct symstateinfo st; st.as = as; st.l = l; 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) { struct symstateinfo st; st.as = as; st.l = l; 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. Symbol resolution will be modified for the object target as follows: - a symbol which is not defined within a section will evaluate as a constant - a symbol which is defined within the same section will evaluate as a constant - a symbol defined in another section will remain unresolved - external references will also remain unresolved EXPR_PASS2PASS will cause the result from pass 1 along with the offset to the end of the expression to be stored in the line data. There can only be one such expression per source line. In this case, the expression is parsed and evaluated on pass 1 but the intermediate representation is re-evaluated on pass 2. */ /* int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val) { lwasm_expr_stack_t *s; const char *ep; int rval; s = lwasm_evaluate_expr(as, l, *inp, &ep); if (!s) { register_error(as, l, 1, "Bad expression"); *val = 0; return -1; } *inp = (char *)ep; if (flag & EXPR_PASS1CONST && as -> passnum == 1 && !lwasm_expr_result_ckconst(as, s)) { register_error(as, l, 1, "Undefined reference (pass 1)"); *val = 0; lwasm_expr_stack_free(s); return -1; } if (flag & EXPR_PASS2CONST && as -> passnum == 2 && !lwasm_expr_result_ckconst(as, s)) { register_error(as, l, 2, "Undefined reference (pass 2)"); *val = 0; lwasm_expr_stack_free(s); return -1; } if (flag & EXPR_NOINTERSECT && !lwasm_expr_is_constant(s)) { register_error(as, l, 2, "Invalid inter-section reference"); } *val = lwasm_expr_get_value(s); if (l -> expr) { lwasm_expr_stack_free(l -> expr); l -> expr = NULL; } if (lwasm_is_constant(s)) { // fully resolved value here lwasm_expr_stack_free(s); } else { // incomplete reference here l -> expr = s; } if (flag & EXPR_BYTE && as -> passnum == 2 && (*val < -128 || *val > 255)) { register_error(as, l, 2, "Byte overflow"); *val &= 0xff; return -1; } if (flag & EXPR_BYTE) { *val &= 0xff; } return 0; } */ 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 || slot < 0) { s = lwasm_evaluate_expr(as, l, *inp, &ep); 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); 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; }