Mercurial > hg-old > index.cgi
diff old-trunk/lwasm/old/pseudo.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/pseudo.c Fri Mar 19 02:54:14 2010 +0000 @@ -0,0 +1,1336 @@ +/* +pseudo.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/>. + + +This file implements the various pseudo operations. +*/ +#include <config.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "lwasm.h" +#include "instab.h" +#include "expr.h" +#include "util.h" + +extern int lwasm_read_file(asmstate_t *as, const char *filename); + +OPFUNC(pseudo_noop) +{ + skip_operand(p); +} + +OPFUNC(pseudo_org) +{ + int v, r; + + if (as -> csect) + { + register_error(as, l, 1, "ORG not allowed within sections"); + return; + } + if (as -> inmod) + { + register_error(as, l, 1, "ORG not allowed within modules"); + return; + } + + if (as -> passnum != 1) + { + // org is not needed to be processed on pass 2 + // this will prevent phasing errors for forward references that + // resolve on the second pass + // we saved the org address in l -> codeaddr on pass 1 + as -> addr = l -> codeaddr; + skip_operand(p); + return; + } + + if (l -> sym) + { + register_error(as, l, 1, "No symbol allowed with ORG"); + } + + r = lwasm_expr_result2(as, l, p, EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + l -> codeaddr = v; + l -> addrset = 1; + as -> addr = v; +} + +/* +The operand for include is a string optionally enclosed in " +*/ +OPFUNC(pseudo_include) +{ + int v1; + char *fn; + + // only include files on pass 1 + // but make sure local include context is right + // for the next line... + if (as -> passnum != 1) + { + as -> context = lwasm_next_context(as); + skip_operand(p); + return; + } + + while (**p && isspace(**p)) + (*p)++; + + if (!**p) + { + register_error(as, l, 1, "Bad file name"); + return; + } + + if (**p == '"') + { + // search for ending " + (*p)++; + for (v1 = 0; *((*p)+v1) && *((*p)+v1) != '"'; v1++) + /* do nothing */ ; + if (*((*p)+v1) != '"') + { + register_error(as, l, 1, "Bad file name"); + return; + } + } + else + { + // search for a space type character + for (v1 = 0; *((*p)+v1) && !isspace(*((*p)+v1)); v1++) + ; + } + + fn = lwasm_alloc(v1 + 1); + memcpy(fn, *p, v1); + fn[v1] = '\0'; + + (*p) += v1; + if (**p == '"') + (*p)++; + + // end local label context on include + as -> context = lwasm_next_context(as); + if (lwasm_read_file(as, fn) < 0) + { + register_error(as, l, 1, "File include error (%s)", fn); + } + lwasm_free(fn); +} + +/* +The operand for includebin is a string optionally enclosed in " +*/ +OPFUNC(pseudo_includebin) +{ + int v1; + char *fn; + FILE *f; + + // only include files on pass 1 + while (**p && isspace(**p)) + (*p)++; + + if (!**p) + { + register_error(as, l, 1, "Bad file name"); + return; + } + + if (**p == '"') + { + // search for ending " + (*p)++; + for (v1 = 0; *((*p)+v1) && *((*p)+v1) != '"'; v1++) + /* do nothing */ ; + if (*((*p)+v1) != '"') + { + register_error(as, l, 1, "Bad file name"); + return; + } + } + else + { + // search for a space type character + for (v1 = 0; *((*p)+v1) && !isspace(*((*p)+v1)); v1++) + ; + } + + fn = lwasm_alloc(v1 + 1); + memcpy(fn, *p, v1); + fn[v1] = '\0'; + + (*p) += v1; + if (**p == '"') + (*p)++; + + // open the file + f = fopen(fn, "rb"); + if (!f) + { + register_error(as, l, 1, "Cannot open file: %s", strerror(errno)); + register_error(as, l, 2, "Cannot open file: %s", strerror(errno)); + } + + // don't need fn any more + lwasm_free(fn); + + // read the contents of the file and "emit()" it + while (!feof(f) && !ferror(f)) + { + v1 = fgetc(f); + if (v1 == EOF) + break; + lwasm_emit(as, l, v1); + } + // close file + fclose(f); +} + +OPFUNC(pseudo_rmb) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + skip_operand(p); + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, -1); + if (r != 0) + return; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_rmd) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + skip_operand(p); + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 2; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_rmq) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + skip_operand(p); + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 4; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_zmb) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_zmd) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 2; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_zmq) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 4; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_end) +{ + int r, v; + lwasm_expr_stack_t *s; + + + as -> endseen = 1; + + // address only matters for DECB output + if (as -> outformat != OUTPUT_DECB) + { + skip_operand(p); + return; + } + + r = lwasm_expr_result2(as, l, p, 0, &v, 0); + if (r != 0) + { + register_error(as, l, 2, "Bad operand"); + } + + v = v & 0xffff; + if (as -> passnum == 2) + { + as -> execaddr = v; + l -> symaddr = v; + l -> addrset = 2; + } +} + + +OPFUNC(pseudo_align) +{ + int cn; + int r, v; + int pad = 0; +// we have to parse this on pass 2 so that we get the pad value +// if (as -> passnum == 2) +// { +// skip_operand(p); +// while (as -> addr < l -> symaddr) +// lwasm_emit(as, l, 0); +// return; +// } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + { + l -> symaddr = as -> addr; + return; + } + + if (v < 1) + { + register_error(as, l, 1, "Illegal alignment %d", v); + return; + } + + cn = l -> codeaddr % v; + if (cn) + cn = v - cn; + + if (**p == ',') + { + // we have a padding value specified + (*p)++; + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &pad, 1); + if (r != 0 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal padding value - must be constant on pass 2"); + return; + } + } + + while (cn--) + { + lwasm_emit(as, l, pad); + } + l -> symaddr = as -> addr; +} + +OPFUNC(pseudo_equ) +{ + int r, v; + + if (l -> sym == NULL) + { + register_error(as, l, 1, "No symbol specified"); + return; + } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r < 0) + v = 0; + + l -> symaddr = v & 0xFFFF; + l -> addrset = 2; + + // note: we need to do this because the symbol might have resolved + // to a constant! + lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_FORCE | (l -> forceglobal ? SYMBOL_GLOBAL : SYMBOL_NORM)); +} + +OPFUNC(pseudo_set) +{ + int r, v; + + // set MUST run on both passes as the symbol value changes! + + if (l -> sym == NULL) + { + register_error(as, l, 1, "No symbol specified"); + return; + } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r < 0) + v = 0; + + l -> symaddr = v & 0xFFFF; + l -> addrset = 2; + + lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_SET); +} + +OPFUNC(pseudo_setdp) +{ + int r, v; + + if (as -> outformat == OUTPUT_OBJ) + { + register_error(as, l, 1, "SETDP not permitted with OBJ target"); + return; + } + + // setdp is needed on both passes; must resolve to a constant on pass 1 + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + + if (v < -127 || v > 255) + { + register_error(as, l, 1, "Byte overflow"); + return; + } + + l -> symaddr = v & 0xFF; + l -> addrset = 2; + + as -> dpval = v & 0xFF; +} + +// used to get a byte from a string +// -1 is end of line +int pseudo_fcc_fetchchar(asmstate_t *as, char **p) +{ + int c; + + // - + if (!**p) + return -1; + + c = (unsigned char)(**p); + (*p)++; + + if (as -> pragmas & PRAGMA_CESCAPES && c == '\\') + { + // decode escapes if needed + if (!**p) + return c; + + c = **p; + (*p)++; + + switch (c) + { + // octal value + // 1, 2, or 3 digits + // NOTE: \0 for NUL is included in this... + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c -= '0'; + if (**p < '0' || **p > '9') + return c; + c = c << 3; + c |= **p - '0'; + (*p)++; + if (**p < '0' || **p > '9') + return c; + c = c << 3; + c |= **p - '0'; + (*p)++; + return c; + + // LF + case 'n': + return 10; + + // CR + case 'r': + return 13; + + // TAB + case 't': + return 9; + + // VT + case 'v': + return 11; + + // BS + case 'b': + return 8; + + // FF + case 'f': + return 12; + + // BEL + case 'a': + return 7; + + // hex char code (2 chars) + case 'x': + { + int c2; + if (!**p) + return 'x'; + c = toupper(**p); + (*p)++; + if (c < '0' || (c > '9' && c < 'A') || c > 'F') + return 0; + c -= '0'; + if (c > 9) + c -= 7; + c2 = c << 4; + if (!**p) + return 0; + c = toupper(**p); + (*p)++; + if (c < '0' || (c > '9' && c < 'A') || c > 'F') + return 0; + c -= '0'; + if (c > 9) + c -= 7; + c2 |= c; + return c2; + } + // everything else stands for itself as a fall back or legit + default: + return c; + } + } + return c; +} + +OPFUNC(pseudo_fcc) +{ + int delim = 0; + int c; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + for (;;) + { + c = pseudo_fcc_fetchchar(as, p); + if (c == delim || c < 0) + break; + + lwasm_emit(as, l, c); + } +} + + +OPFUNC(pseudo_fcs) +{ + int delim = 0; + int c, lc = -1; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + for (;;) + { + c = pseudo_fcc_fetchchar(as, p); + if (c == delim || c < 0) + { + if (lc >= 0) + lwasm_emit(as, l, lc | 0x80); + break; + } + if (lc >= 0) + lwasm_emit(as, l, lc); + lc = c; + } +} + +OPFUNC(pseudo_fcn) +{ + int delim = 0; + int c; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + for (;;) + { + c = pseudo_fcc_fetchchar(as, p); + if (c == delim || c < 0) + break; + + lwasm_emit(as, l, c); + } + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_fcb) +{ + int r, v; + +fcb_again: + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0) + { + register_error(as, l, 2, "Illegal external or inter-segment reference"); + v = 0; + } + + if (v < -127 || v > 255) + { + register_error(as, l, 1, "Byte overflow"); + } + + lwasm_emit(as, l, v); + if (**p == ',') + { + (*p)++; + goto fcb_again; + } +} + +// FIXME: handle external references in an intelligent way +OPFUNC(pseudo_fdb) +{ + int r, v; + int extseen = 0; + char *p1; + +fdb_again: + p1 = *p; + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0 && extseen == 1) + { + register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)"); + v = 0; + } + else if (r > 0) + { + l -> relocoff = as -> addr - l -> codeaddr; + *p = p1; + r = lwasm_expr_result2(as, l, p, 0, &v, 0); + } + + lwasm_emit(as, l, v >> 8); + lwasm_emit(as, l, v & 0xff); + if (**p == ',') + { + (*p)++; + goto fdb_again; + } +} + +// FIXME: handle external references in a sensible way +OPFUNC(pseudo_fqb) +{ + int r, v; + +fqb_again: + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0) + { + register_error(as, l, 2, "Illegal external or inter-segment reference"); + v = 0; + } + + lwasm_emit(as, l, v >> 24); + lwasm_emit(as, l, v >> 16); + lwasm_emit(as, l, v >> 8); + lwasm_emit(as, l, v & 0xff); + if (**p == ',') + { + (*p)++; + goto fqb_again; + } +} + +// don't need to do anything if we are executing one of these +OPFUNC(pseudo_endc) +{ + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount -= 1; + if (as -> skipcount <= 0) + { + as -> skipcond = 0; + } + } + return; +} + +// if "else" executes, we must be going into an "ignore" state +OPFUNC(pseudo_else) +{ + if (as -> skipmacro) + return; + + if (as -> skipcond) + { + if (as -> skipcount == 1) + { + as -> skipcount = 0; + as -> skipcond = 0; + } + return; + } + + as -> skipcond = 1; + as -> skipcount = 1; +} + +OPFUNC(pseudo_ifne) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (!v1) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifdef) +{ + lwasm_symbol_ent_t *se; + char *sym; + char *p2; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + if (as -> passnum != 1) + { + skip_operand(p); + if (!(l -> fsize)) + { + as -> skipcond = 1; + as -> skipcount = 1; + } + return; + } + + if (!**p) + { + register_error(as, l, 1, "Need symbol name"); + return; + } + + for (p2 = *p; **p && !isspace(**p); (*p)++) + /* do nothing */ ; + + sym = lwasm_alloc(*p - p2 + 1); + memcpy(sym, p2, *p - p2); + sym[*p - p2] = '\0'; + +// fprintf(stderr, "STUFF: %s; '%s'; '%s' (%d)\n", p2, *p, sym, as -> passnum); + se = lwasm_find_symbol(as, sym, l -> context); + if (!se) + se = lwasm_find_symbol(as, sym, -1); + + lwasm_free(sym); + + if (!se) + { + as -> skipcond = 1; + as -> skipcount = 1; + l -> fsize = 0; + } + else + { + l -> fsize = 1; + } +} + +OPFUNC(pseudo_ifndef) +{ + lwasm_symbol_ent_t *se; + char *sym; + char *p2; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + if (as -> passnum != 1) + { + skip_operand(p); + if (l -> fsize) + { + as -> skipcond = 1; + as -> skipcount = 1; + } + return; + } + + if (!**p) + { + register_error(as, l, 1, "Need symbol name"); + return; + } + + for (p2 = *p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sym = lwasm_alloc(p2 - *p + 1); + memcpy(sym, *p, p2 - *p); + sym[p2 - *p] = '\0'; + + *p = p2; + +// fprintf(stderr, "STUFF2: %s; '%s'; '%s' (%d)\n", *p, p2, sym, as -> passnum); + se = lwasm_find_symbol(as, sym, l -> context); + if (!se) + se = lwasm_find_symbol(as, sym, -1); + + lwasm_free(sym); + + if (se) + { + as -> skipcond = 1; + as -> skipcount = 1; + l -> fsize = 0; + } + else + { + l -> fsize = 1; + } +} + +OPFUNC(pseudo_ifp1) +{ + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + if (as -> passnum != 1) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifp2) +{ + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + if (as -> passnum != 2) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifeq) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_iflt) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 >= 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifle) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 > 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifgt) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 <= 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifge) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + skip_operand(p); + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 < 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_error) +{ + register_error(as, l, 1, "User error: %s", *p); +} + + +OPFUNC(pseudo_section) +{ + sectiontab_t *s; + char *p2; + char *sn; + char *opts; + + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Sections only supported for obj target"); + return; + } + + if (as -> csect) + { + as -> csect -> offset = as -> addr; + as -> csect = NULL; + } + + if (!**p) + { + register_error(as, l, 1, "Need section name"); + return; + } + + for (p2 = *p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sn = lwasm_alloc(p2 - *p + 1); + memcpy(sn, *p, p2 - *p); + sn[p2 - *p] = '\0'; + + *p = p2; + + opts = strchr(sn, ','); + if (opts) + { + *opts++ = '\0'; + } + + // have we seen the section name already? + for (s = as -> sections; s; s = s -> next) + { + if (!strcmp(s -> name, sn)) + break; + } + + if (s && as -> passnum == 1) + { + lwasm_free(sn); + if (opts) + { + register_error(as, l, 1, "Section options can only be specified the first time"); + return; + } + } + else if (!s) + { + s = lwasm_alloc(sizeof(sectiontab_t)); + s -> name = sn; + s -> offset = 0; + s -> flags = 0; + s -> obytes = NULL; + s -> oblen = 0; + s -> obsize = 0; + s -> rl = NULL; + s -> exports = NULL; + // if name of section is "bss" or ".bss", assume bss flag + // which can be overridden with !bss flag + if (!strcasecmp(sn, "bss") || !strcasecmp(sn, ".bss")) + s -> flags = SECTION_BSS; + // parse options; only one "bss" + if (opts && as -> passnum == 1) + { + if (!strcasecmp(opts, "bss")) + { + s -> flags |= SECTION_BSS; + } + else if (!strcasecmp(opts, "!bss")) + { + s -> flags &= ~SECTION_BSS; + } + else + { + register_error(as, l, 1, "Unrecognized section option '%s'", opts); + lwasm_free(s -> name); + lwasm_free(s); + return; + } + } + + s -> next = as -> sections; + as -> sections = s; + } + as -> addr = s -> offset; + as -> csect = s; + as -> context = lwasm_next_context(as); +} + +OPFUNC(pseudo_endsection) +{ + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Sections only supported for obj target"); + return; + } + + if (!(as -> csect)) + { + register_error(as, l, 1, "ENDSECTION when not in a section"); + return; + } + + as -> csect -> offset = as -> addr; + as -> addr = 0; + as -> csect = 0; + as -> context = lwasm_next_context(as); + skip_operand(p); +} + +OPFUNC(pseudo_extern) +{ + if (as -> passnum != 1) + return; + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "External references only supported for obj target"); + return; + } + + if (as -> csect) + { + register_error(as, l, 1, "Cannot declare external symbols within a section"); + return; + } + + if (l -> sym) + { + lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN); + for ( ; **p; (*p)++) ; + return; + } + + while (**p) + { + char *sym2, *sym3; + for (sym2 = *p; **p && !isspace(**p) && **p != ','; (*p)++) + /* do nothing */ ; + + if (l -> sym) + lwasm_free(l -> sym); + + sym3 = lwasm_alloc(*p - sym2 + 1); + memcpy(sym3, sym2, *p - sym2); + sym3[*p - sym2] = '\0'; + + l -> sym = sym3; + debug_message(2, "import symbol: '%s'", sym3); + lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN); + if (**p && (**p != ',')) + { + register_error(as, l, 1, "Bad import list"); + return; + } + if (**p == ',') + (*p)++; + } + if (!(l -> sym)) + register_error(as, l, 1, "Bad import list"); +} + +OPFUNC(pseudo_export) +{ + lwasm_symbol_ent_t *se; + export_list_t *ex; + char *sym2, *sym3; + int after = 0; + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Symbol exports only supported for obj target"); + return; + } + + if (as -> passnum == 1) + { + skip_operand(p); + return; + } + + if (l -> sym) + { + for ( ; **p; (*p)++) ; + } + +again: + if (!(l -> sym) || after == 1) + { + + after = 1; + // look for symbol after op + if (**p) + { + for (sym2 = *p; **p && !isspace(**p) && **p != ','; (*p)++) + /* do nothing */ ; + + debug_message(2, "export expression: %s", sym2); + if (l -> sym) + lwasm_free(l -> sym); + sym3 = lwasm_alloc(*p - sym2 + 1); + memcpy(sym3, sym2, *p - sym2); + sym3[*p - sym2] = '\0'; + + l -> sym = sym3; + debug_message(2, "export symbol: '%s'", sym3); + } + } + if (!(l -> sym)) + { + register_error(as, l, 2, "No symbol"); + return; + } + + + // the symbol better be defined at this point (pass 2) + // local symbols cannot be exported nor can "global" symbols + se = lwasm_find_symbol(as, l -> sym, -1); + if ((!se || (se -> flags & SYMBOL_EXTERN)) && (as -> pragmas & PRAGMA_IMPORTUNDEFEXPORT)) + { + void *p; + p = as -> csect; + as -> csect = NULL; + lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN); + as -> csect = p; + } + else + { + if (!se) + { + register_error(as, l, 2, "Exported symbols must be fully defined within a section"); + return; + } + if (se -> sect == NULL) + { + register_error(as, l, 2, "Only non-local symbols within a section can be exported"); + return; + } + + if (se -> flags & SYMBOL_SET) + { + register_error(as, l, 2, "You cannot export symbols defined with SET"); + return; + } + + // if the symbol is not already a simple value, re-evaluate it + // and see if it becomes simple + + + if (se -> flags & SYMBOL_COMPLEX) + { + register_error(as, l, 2, "Exported symbols must be fully resolved on pass 2"); + return; + } + + // search for existing export + for (ex = se -> sect -> exports; ex; ex = ex -> next) + if (!strcmp(l -> sym, ex -> sym)) + break; + if (ex) + { + register_error(as, l, 2, "Symbol %s already exported", l -> sym); + return; + } + + // add an external reference + ex = lwasm_alloc(sizeof(export_list_t)); + ex -> next = se -> sect -> exports; + se -> sect -> exports = ex; + ex -> offset = se -> value; + ex -> sym = lwasm_strdup(se -> sym); + } +next: + if (after == 1) + { + if (**p == ',') + { + debug_message(2, "Export another symbol: %s", *p); + (*p)++; + for ( ; **p && isspace(**p); (*p)++) + /* do nothing */ ; + goto again; + } + } +}