# HG changeset patch # User lost # Date 1231113681 0 # Node ID 035b95a3690fcf3b5c73423118d7786da712a7ef # Parent 55260a17866721ec35c05081735217b247d3ce4c Added conditional assembly and macros diff -r 55260a178667 -r 035b95a3690f src/Makefile.am --- a/src/Makefile.am Sun Jan 04 21:43:05 2009 +0000 +++ b/src/Makefile.am Mon Jan 05 00:01:21 2009 +0000 @@ -1,3 +1,3 @@ bin_PROGRAMS = lwasm -lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c symbol.c output.c pseudo.c +lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c symbol.c output.c pseudo.c macro.c EXTRA_DIST = instab.h lwasm.h expr.h util.h diff -r 55260a178667 -r 035b95a3690f src/instab.c --- a/src/instab.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/instab.c Mon Jan 05 00:01:21 2009 +0000 @@ -59,6 +59,16 @@ extern OPFUNC(pseudo_fcb); extern OPFUNC(pseudo_fdb); extern OPFUNC(pseudo_fqb); +extern OPFUNC(pseudo_ifne); +extern OPFUNC(pseudo_ifeq); +extern OPFUNC(pseudo_ifgt); +extern OPFUNC(pseudo_ifge); +extern OPFUNC(pseudo_iflt); +extern OPFUNC(pseudo_ifle); +extern OPFUNC(pseudo_else); +extern OPFUNC(pseudo_endc); +extern OPFUNC(pseudo_macro); +extern OPFUNC(pseudo_endm); instab_t instab[] = { @@ -331,6 +341,19 @@ { "error", { -1, -1, -1, -1}, pseudo_error }, + { "ifeq", { -1, -1, -1, -1}, pseudo_ifeq, 1 }, + { "ifne", { -1, -1, -1, -1}, pseudo_ifne, 1 }, + { "if", { -1, -1, -1, -1}, pseudo_ifne, 1 }, + { "ifgt", { -1, -1, -1, -1}, pseudo_ifgt, 1 }, + { "ifge", { -1, -1, -1, -1}, pseudo_ifge, 1 }, + { "iflt", { -1, -1, -1, -1}, pseudo_iflt, 1 }, + { "ifle", { -1, -1, -1, -1}, pseudo_ifle, 1 }, + { "endc", { -1, -1, -1, -1}, pseudo_endc, 1 }, + { "else", { -1, -1, -1, -1}, pseudo_else, 1 }, + + { "macro", { -1, -1, -1, -1}, pseudo_macro, 1, 0 }, + { "endm", { -1, -1, -1, -1}, pseudo_endm, 1, 1 }, + /* flag end of table */ { NULL, { -0x1, -0x1, -0x1, -0x1 }, insn_inh } }; diff -r 55260a178667 -r 035b95a3690f src/instab.h --- a/src/instab.h Sun Jan 04 21:43:05 2009 +0000 +++ b/src/instab.h Mon Jan 05 00:01:21 2009 +0000 @@ -31,6 +31,8 @@ char *opcode; /* the mneumonic */ int ops[4]; /* opcode values for up to four addr modes */ void (*fn)(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum); + int iscond; /* set if this should be dispatched even if skipping a condition/macro */ + int endm; /* end of macro? */ } instab_t; #define OPFUNC(fn) void (fn)(asmstate_t *as, lwasm_line_t *l, char **p, int opnum) diff -r 55260a178667 -r 035b95a3690f src/lwasm.c --- a/src/lwasm.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/lwasm.c Mon Jan 05 00:01:21 2009 +0000 @@ -255,3 +255,9 @@ } va_end(args); } + +int lwasm_next_context(asmstate_t *as) +{ + return (as -> nextcontext++); +} + diff -r 55260a178667 -r 035b95a3690f src/lwasm.h --- a/src/lwasm.h Sun Jan 04 21:43:05 2009 +0000 +++ b/src/lwasm.h Mon Jan 05 00:01:21 2009 +0000 @@ -31,6 +31,16 @@ #define OUTPUT_OBJ 2 // proprietary object file format #define OUTPUT_RAWREL 3 // raw bytes where ORG causes a SEEK in the file +// structure for tracking macros +typedef struct macrotab_s macrotab_t; +struct macrotab_s +{ + char *name; + char **lines; + int numlines; + macrotab_t *next; +}; + // structure for tracking errors typedef struct lwasm_error_s lwasm_error_t; struct lwasm_error_s @@ -85,6 +95,8 @@ lwasm_symbol_ent_t *symhead; // first entry in symbol table lwasm_symbol_ent_t *symtail; // last entry in symbol table + + macrotab_t *macros; // macro table const char *infile; // input file const char *outfile; // output file @@ -94,6 +106,13 @@ int filelistlen; // number of files in the list int endseen; // set to true if "end" has been seen + int skipcond; // skipping a condition? + int skipcount; // how many? + int skipmacro; // skipping a macro? + int inmacro; // are we currently in a macro? + int macroex; // current depth of macro expansion + int nextcontext; // next context number + int skiplines; // number of lines to skip } asmstate_t; #define PRAGMA_NOINDEX0TONONE 1 @@ -117,6 +136,9 @@ __lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp); +// return next context number and update it +__lwasm_E__ int lwasm_next_context(asmstate_t *as); + // also throw an error on expression eval failure // return 0 on ok, -1 on error #define EXPR_NOFLAG 0 diff -r 55260a178667 -r 035b95a3690f src/macro.c --- a/src/macro.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/macro.c Mon Jan 05 00:01:21 2009 +0000 @@ -24,71 +24,95 @@ #include #include #include "lwasm.h" +#include "instab.h" +#include "util.h" -extern void resolve_insn(asmstate_t *as, sourceline_t *cl); - -void pseudo_macro(asmstate_t *as, sourceline_t *cl, char **optr) +OPFUNC(pseudo_macro) { macrotab_t *m; + // if skipping a condition, flag in a macro + if (as -> skipcond) + { + as -> skipmacro = 1; + return; + } + + // actually define a macro if (as -> inmacro) { - errorp1(ERR_MACRO); + register_error(as, l, 1, "Attempt to define a macro inside a macro"); return; } + as -> inmacro = 1; + + // don't actually do anything if not pass 1 if (as -> passnum != 1) return; + + + if (!l -> sym) + { + register_error(as, l, 1, "Macro definition with no effect - no symbol"); + return; + } + // search for macro by same name... for (m = as -> macros; m; m = m -> next) { - if (!strcmp(m -> name, cl -> symstr)) + if (!strcmp(m -> name, l -> sym)) break; } if (m) { - errorp1(ERR_DUPSYM); + register_error(as, l, 1, "Duplicate macro definition"); return; } - m = calloc(sizeof(macrotab_t), 1); - m -> name = strdup(cl -> symstr); + + m = lwasm_alloc(sizeof(macrotab_t)); + m -> name = lwasm_strdup(l -> sym); m -> next = as -> macros; + m -> lines = NULL; + m -> numlines = 0; as -> macros = m; - cl -> hassym = 0; - while (**optr && !isspace(**optr)) - (*optr)++; - cl -> macrodef = 1; + + while (**p && !isspace(**p)) + (*p)++; } -void pseudo_endm(asmstate_t *as, sourceline_t *cl, char **optr) +OPFUNC(pseudo_endm) { + if (as -> skipcond) + { + as -> skipmacro = 0; + return; + } + if (!as -> inmacro) { - errorp1(ERR_ENDM); + register_error(as, l, 1, "ENDM without MACRO"); return; } as -> inmacro = 0; - cl -> macrodef = 1; + + // a macro definition counts as a context break for local symbols + as -> context = lwasm_next_context(as); } -int add_macro_line(asmstate_t *as, sourceline_t *cl, char *optr) +// the current macro will ALWAYS be the first one in the table +int add_macro_line(asmstate_t *as, char *optr) { - macroline_t *l; - if (!as -> inmacro) return 0; if (as -> passnum == 2) return 1; - l = calloc(sizeof(macroline_t), 1); - l -> linetext = strdup(optr); - if (as -> macros -> linetail) - as -> macros -> linetail -> next = l; - as -> macros -> linetail = l; - if (!(as -> macros -> linehead)) - as -> macros -> linehead = l; + as -> macros -> lines = lwasm_realloc(as -> macros -> lines, sizeof(char *) * as -> macros -> numlines + 1); + as -> macros -> lines[as -> macros -> numlines] = lwasm_strdup(optr); + as -> macros -> numlines += 1; return 1; } @@ -104,128 +128,196 @@ // this is just like a regular operation function /* -macro args are references by "\n" where 1 <= n <= 9 +macro args are referenced by "\n" where 1 <= n <= 9 or by "\{n}"; a \ can be included by writing \\ +a comma separates argument but one can be included with "\," +whitespace ends argument list but can be included with "\ " or the like + +In pass 1, actually add the lines to the system, in pass 2, do not +In pass 2, track the number of lines to skip because they already will be +processed by this function - this will be in as -> skiplines + */ -void expand_macro(asmstate_t *as, sourceline_t *cl, char **optr) +int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc) { - char **args = NULL; - int nargs = 0; - int c; - sourceline_t *nl; - int nline = 1; + int lc; + lwasm_line_t *cl, *nl; + int oldcontext; macrotab_t *m; - macroline_t *ml; - char *buff = NULL; - int bufflen = 0, buffloc; + + char **args = NULL; // macro arguments + int nargs; // number of arguments + + char *p2, *p3; - m = cl -> macro; + int bloc, blen; + char *linebuff; + + for (m = as -> macros; m; m = m -> next) + { + if (!strcmp(opc, m -> name)) + break; + } + // signal no macro expansion + if (!m) + return -1; - // step the first: parse arguments - while (**optr && !isspace(**optr)) + + // save current symbol context for after macro expansion + oldcontext = as -> context; + + cl = l; + + as -> context = lwasm_next_context(as); + + // step 1: parse arguments (pass 1 only) + if (as -> passnum == 1) { - c = 0; - while ((*optr)[c] && !isspace((*optr)[c]) && (*optr)[c] != ',') + while (**p && !isspace(**p) && **p != ',') { - c++; + p2 = *p; + while (*p2 && !isspace(*p2) && *p2 != ',') + { + if (*p2 == '\\') + { + if (p2[1]) + p2++; + } + } + + // have arg here + args = lwasm_realloc(args, nargs + 1); + args[nargs] = lwasm_alloc(p2 - *p + 1); + args[nargs][p2 - *p] = '\0'; + memcpy(args[nargs], *p, p2 - *p); + *p = p2; + + // now collapse out "\" characters + for (p3 = p2 = args[nargs]; *p2; p2++, p3++) + { + if (*p2 == '\\' && p2[1]) + { + p2++; + } + *p3 = *p2; + } + *p3 = '\0'; + + nargs++; } - args = realloc(args, sizeof(char *) * (nargs + 1)); - args[nargs] = malloc(c + 1); - strncpy(args[nargs], *optr, c); - args[nargs][c] = '\0'; - nargs++; - *optr += c; - if (**optr == ',') - (*optr)++; } - // step the second: iterate over the lines and expand arguments and add - // them after "cl" - for (ml = m -> linehead; ml; ml = ml -> next) + // step 2: iterate over the lines + if (as -> passnum == 2) + { + // pass 2 only - parse the lines and count them + for (lc = 0; lc < m -> numlines; lc++) + { + cl = cl -> next; + as -> skiplines++; + lwasm_parse_line(as, cl); + } + } + else { - nl = calloc(sizeof(sourceline_t), 1); - - nl -> lineno = nline++; - nl -> sourcefile = m -> name; - nl -> opcode = -1; - nl -> addrmode = -1; - nl -> addr = as -> addr; - nl -> dpval = as -> dpval; - nl -> prev = cl; - if (!(cl -> next)) - as -> source_tail = nl; - nl -> next = cl -> next; - cl -> next = nl; + // pass 1 only - construct the lines and parse them + for (lc = 0; lc < m -> numlines; lc++) + { + nl = lwasm_alloc(sizeof(lwasm_line_t)); + nl -> text = lwasm_strdup(linebuff); + nl -> lineno = lc + 1; + nl -> filename = m -> name; + nl -> next = NULL; + nl -> prev = as -> linestail; + nl -> err = NULL; + nl -> fsize = 0; + nl -> sym = NULL; + nl -> bytes = NULL; + nl -> codelen = 0; + nl -> codesize = 0; + nl -> nocodelen = 0; + nl -> addrset = 0; + nl -> symaddr = -1; + if (as -> linestail) + as -> linestail -> next = nl; + as -> linestail = nl; + if (!(as -> lineshead)) + as -> lineshead = nl; - buffloc = 0; - c = 0; - while (ml -> linetext[c]) - { - int ch; - ch = ml -> linetext[c++]; - if (ch == '{') + bloc = blen = 0; + linebuff = NULL; + for (p2 = m -> lines[lc]; *p2; p2++) { - int v = 0; - again: - ch = ml -> linetext[c++]; - if (!ch) + if (*p2 == '\\' && isdigit(p2[1])) { - c--; + int n; + + p2++; + n = *p2 - '0'; + if (n == 0) + { + for (p3 = m -> name; p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + if (n < 1 || n > nargs) + continue; + for (p3 = args[n]; p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); continue; } - if (ch >= '0' && ch <= '9') - { - v = v * 10 + (ch - '0'); - goto again; - } - if (ch == '}') + else if (*p2 == '{') { - v--; - if (v < nargs) + int n = 0, n2; + p2++; + while (*p2 && isdigit(*p2)) { - char *t; - for (t = args[v]; *t; t++) - { - macro_add_to_buff(&buff, &buffloc, &bufflen, *t); - } + n2 = *p2 - '0'; + if (n2 < 0 || n2 > 9) + n2 = 0; + n = n * 10 + n2; + p2++; } + if (*p2 == '}') + p2++; + + if (n == 0) + { + for (p3 = m -> name; p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + if (n < 1 || n > nargs) + continue; + for (p3 = args[n]; p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); continue; } else - continue; - } - else if (ch == '\\' && ml -> linetext[c]) - { - ch = ml -> linetext[c++]; - if (ch >= '1' && ch <= '9') { - ch -= '1'; - if (ch < nargs) - { - char *t; - for (t = args[ch]; *t; t++) - { - macro_add_to_buff(&buff, &buffloc, &bufflen, *t); - } - } - } - else - { - c--; - macro_add_to_buff(&buff, &buffloc, &bufflen, '\\'); + macro_add_to_buff(&linebuff, &bloc, &blen, *p2); } } - else - { - macro_add_to_buff(&buff, &buffloc, &bufflen, ch); - } + + nl -> text = linebuff; + + lwasm_parse_line(as, nl); + if (as -> endseen) + break; + } - macro_add_to_buff(&buff, &buffloc, &bufflen, 0); - nl -> line = strdup(buff); + } + + // restore context from before the macro was called + as -> context = oldcontext; - resolve_insn(as, nl); - cl = nl; + // clean up + while (nargs) + { + lwasm_free(args[--nargs]); } - if (buff) - free(buff); + lwasm_free(args); + + // indicate a macro was expanded + return 0; } diff -r 55260a178667 -r 035b95a3690f src/parse.c --- a/src/parse.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/parse.c Mon Jan 05 00:01:21 2009 +0000 @@ -43,7 +43,8 @@ if (!*p) { - as -> context += 1; + if (as -> inmacro == 0) + as -> context = lwasm_next_context(as); return 0; } @@ -81,7 +82,8 @@ p++; if (!*p) { - as -> context += 1; + if (as -> inmacro == 0) + as -> context = lwasm_next_context(as); return 0; } } @@ -112,8 +114,6 @@ while (*p2 && isspace(*p2)) p2++; - // check for macro (pass 1) - // look up instruction in insn table for (opnum = 0; instab[opnum].opcode; opnum++) { @@ -121,7 +121,18 @@ break; } - if (!(instab[opnum].opcode) || !(instab[opnum].fn)) + if (as -> inmacro && instab[opnum].endm == 0) + { + add_macro_line(as, l -> text); + } + + if (as -> inmacro == 0 && as -> skipcond == 0) + { + if (expand_macro(as, l, &p2, opc) == 0) + goto done_line; + } + + if (!(instab[opnum].opcode) || !(instab[opnum].fn) && !(as -> skipcond || as -> inmacro)) { // invalid operation code, throw error register_error(as, l, 1, "Invalid operation code '%s'", opc); @@ -131,9 +142,11 @@ return -1; } - // dispatch handler - (instab[opnum].fn)(as, l, &p2, opnum); - + // dispatch handler if we're not ignoring items + if (as -> skipcond == 0 && as -> inmacro == 0 && !(instab[opnum].iscond)) + (instab[opnum].fn)(as, l, &p2, opnum); + +done_line: lwasm_free(opc); if (sym) lwasm_free(sym); diff -r 55260a178667 -r 035b95a3690f src/pass2.c --- a/src/pass2.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/pass2.c Mon Jan 05 00:01:21 2009 +0000 @@ -37,8 +37,19 @@ as -> addr = 0; as -> context = 0; as -> endseen = 0; - + as -> skipcond = 0; + as -> skipcount = 0; + as -> skipmacro = 0; + as -> inmacro = 0; + as -> nextcontext = 1; + as -> skiplines = 0; + // iterate over all the lines and re-parse them for (l = as -> lineshead; l && !(as -> endseen); l = l -> next) - lwasm_parse_line(as, l); + { + if (as -> skiplines) + as -> skiplines--; + else + lwasm_parse_line(as, l); + } } diff -r 55260a178667 -r 035b95a3690f src/pseudo.c --- a/src/pseudo.c Sun Jan 04 21:43:05 2009 +0000 +++ b/src/pseudo.c Mon Jan 05 00:01:21 2009 +0000 @@ -75,13 +75,13 @@ { 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 += 1; + as -> context = lwasm_next_context(as); return; } @@ -118,7 +118,7 @@ fn[v1] = '\0'; // end local label context on include - as -> context += 1; + as -> context = lwasm_next_context(as); if (lwasm_read_file(as, fn) < 0) { register_error(as, l, 1, "File include error (%s)", fn); @@ -573,137 +573,165 @@ } } -/* // don't need to do anything if we are executing one of these -void pseudo_endc(asmstate_t *as, sourceline_t *cl, char **optr) +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 -void pseudo_else(asmstate_t *as, sourceline_t *cl, char **optr) +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; } -void pseudo_ifne(asmstate_t *as, sourceline_t *cl, char **optr) +OPFUNC(pseudo_ifne) { int v1; int rval; -// printf("ifne %s\n", *optr); - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) - { - errorp1(ERR_BADCOND); - } - else + + if (as -> skipcond && !(as -> skipmacro)) { -// printf("Condition value: %d\n", v1); - if (!v1) - { -// printf("condition no match\n"); - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcount++; + return; + } + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (!v1) + { + as -> skipcond = 1; + as -> skipcount = 1; } } -void pseudo_ifeq(asmstate_t *as, sourceline_t *cl, char **optr) + +OPFUNC(pseudo_ifeq) { int v1; int rval; - - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) + + if (as -> skipcond && !(as -> skipmacro)) { - errorp1(ERR_BADCOND); + as -> skipcount++; + return; } - else + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (v1) { - if (v1) - { - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcond = 1; + as -> skipcount = 1; } } -void pseudo_iflt(asmstate_t *as, sourceline_t *cl, char **optr) + +OPFUNC(pseudo_iflt) { int v1; int rval; - - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) + + if (as -> skipcond && !(as -> skipmacro)) { - errorp1(ERR_BADCOND); + as -> skipcount++; + return; } - else + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (v1 >= 0) { - if (v1 >= 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcond = 1; + as -> skipcount = 1; } } -void pseudo_ifle(asmstate_t *as, sourceline_t *cl, char **optr) + +OPFUNC(pseudo_ifle) { int v1; int rval; - - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) + + if (as -> skipcond && !(as -> skipmacro)) { - errorp1(ERR_BADCOND); + as -> skipcount++; + return; } - else + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (v1 > 0) { - if (v1 > 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcond = 1; + as -> skipcount = 1; } } -void pseudo_ifgt(asmstate_t *as, sourceline_t *cl, char **optr) + +OPFUNC(pseudo_ifgt) { int v1; int rval; - - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) + + if (as -> skipcond && !(as -> skipmacro)) { - errorp1(ERR_BADCOND); + as -> skipcount++; + return; } - else + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (v1 <= 0) { - if (v1 <= 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcond = 1; + as -> skipcount = 1; } } -void pseudo_ifge(asmstate_t *as, sourceline_t *cl, char **optr) + +OPFUNC(pseudo_ifge) { int v1; int rval; - - rval = eval_expr(as, cl, optr, &v1); - if (rval < 0) + + if (as -> skipcond && !(as -> skipmacro)) { - errorp1(ERR_BADCOND); + as -> skipcount++; + return; } - else + + rval = lwasm_expr_result(as, l, p, EXPR_PASS1CONST, &v1); + if (rval < 0) + return; + if (v1 < 0) { - if (v1 < 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } + as -> skipcond = 1; + as -> skipcount = 1; } } -*/ OPFUNC(pseudo_error) {