# HG changeset patch # User lost@starbug # Date 1269580674 21600 # Node ID 7416c3f9c321aba3160f451982203cff15eb52b6 # Parent 0215a0fbf61bbf4d910f2a938298c3c20c2ba40e Basic macro processor ported forward; added context break handling for local symbols diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/Makefile.am --- a/lwasm/Makefile.am Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/Makefile.am Thu Mar 25 23:17:54 2010 -0600 @@ -1,5 +1,5 @@ AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib -I$(top_builddir)/lwlib -I$(top_srcdir)/lwlib bin_PROGRAMS = lwasm -lwasm_SOURCES = main.c pragma.c input.c pass1.c lwasm.c instab.c symbol.c +lwasm_SOURCES = main.c pragma.c input.c pass1.c lwasm.c instab.c symbol.c macro.c lwasm_LDADD = -L$(top_builddir)/lib -L$(top_srcdir)/lib -L$(top_builddir)/lwlib -L$(top_srcdir)/lwlib -lgnu -llw EXTRA_DIST = lwasm.h input.h instab.h diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/instab.c --- a/lwasm/instab.c Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/instab.c Thu Mar 25 23:17:54 2010 -0600 @@ -26,7 +26,10 @@ #define __instab_c_seen__ #include "instab.h" -extern PARSEFUNC(insn_parse_inh); +// don't need to parse anything for inh +// so it can just be NULL +#define insn_parse_inh NULL + extern RESOLVEFUNC(insn_resolve_inh); extern PARSEFUNC(insn_parse_gen8); extern RESOLVEFUNC(insn_resolve_gen8); diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/lwasm.c --- a/lwasm/lwasm.c Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/lwasm.c Thu Mar 25 23:17:54 2010 -0600 @@ -77,3 +77,11 @@ va_end(args); } + +int lwasm_next_context(asmstate_t *as) +{ + int r; + r = as -> nextcontext; + as -> nextcontext++; + return r; +} diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/lwasm.h --- a/lwasm/lwasm.h Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/lwasm.h Thu Mar 25 23:17:54 2010 -0600 @@ -104,6 +104,15 @@ struct symtabe *head; // start of symbol table } symtab_t; +typedef struct macrotab_s macrotab_t; +struct macrotab_s +{ + char *name; // name of macro + char **lines; // macro lines + int numlines; // number lines in macro + macrotab_t *next; // next macro in list +}; + typedef struct { int output_format; // output format @@ -112,13 +121,18 @@ int flags; // assembly flags int pragmas; // pragmas currently in effect int errorcount; // number of errors encountered + int inmacro; // are we in a macro? + int skipcond; // skipping a condition? + int skipmacro; // are we skipping in a macro? line_t *line_head; // start of lines list line_t *line_tail; // tail of lines list int context; // the current "context" - + int nextcontext; // the next available context + symtab_t symtab; // meta data for the symbol table + macrotab_t *macros; // macro table char *list_file; // name of file to list to char *output_file; // output file name @@ -138,6 +152,7 @@ #ifndef ___lwasm_c_seen___ extern void lwasm_register_error(asmstate_t *as, line_t *cl, const char *msg, ...); +extern int lwasm_next_context(asmstate_t *as); #endif diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/macro.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/macro.c Thu Mar 25 23:17:54 2010 -0600 @@ -0,0 +1,290 @@ +/* +macro.c +Copyright © 2008 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 . + +Contains stuff associated with macro processing +*/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "lwasm.h" +#include "input.h" +#include "instab.h" + +PARSEFUNC(pseudo_macro_parse) +{ + macrotab_t *m; + + if (as -> skipcond) + { + as -> skipmacro = 1; + return; + } + + if (as -> inmacro) + { + lwasm_register_error(as, l, "Attempt to define a macro inside a macro"); + return; + } + + if (!(l -> sym)) + { + lwasm_register_error(as, l, "Missing macro name"); + return; + } + + for (m = as -> macros; m; m = m -> next) + { + if (!strcmp(m -> name, l -> sym)) + break; + } + if (m) + { + lwasm_register_error(as, l, "Duplicate macro definition"); + return; + } + + m = lw_alloc(sizeof(macrotab_t)); + m -> name = lw_strdup(l -> sym); + m -> next = as -> macros; + m -> lines = NULL; + m -> numlines = 0; + as -> macros = m; + + while (**p && !isspace(**p)) + (*p)++; + + as -> inmacro = 1; +} + +PARSEFUNC(pseudo_endm_parse) +{ + if (as -> skipcond) + { + as -> skipmacro = 0; + return; + } + + if (!as -> inmacro) + { + lwasm_register_error(as, l, "ENDM without MACRO"); + return; + } + + as -> inmacro = 0; + + // a macro definition counts as a context break for local symbols + as -> context = lwasm_next_context(as); +} + +// the current macro will ALWAYS be the first one in the table +int add_macro_line(asmstate_t *as, char *optr) +{ + if (!as -> inmacro) + return 0; + + as -> macros -> lines = lw_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1)); + as -> macros -> lines[as -> macros -> numlines] = lw_strdup(optr); + as -> macros -> numlines += 1; + return 1; +} + +void macro_add_to_buff(char **buff, int *loc, int *len, char c) +{ + if (*loc == *len) + { + *buff = lw_realloc(*buff, *len + 32); + *len += 32; + } + (*buff)[(*loc)++] = c; +} + +// this is just like a regular operation function +/* +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 + +*/ +int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc) +{ + int lc; + line_t *cl, *nl; + int oldcontext; + macrotab_t *m; + + char **args = NULL; // macro arguments + int nargs = 0; // number of arguments + + char *p2, *p3; + + 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; + + // save current symbol context for after macro expansion + oldcontext = as -> context; + + cl = l; + + as -> context = lwasm_next_context(as); + + while (**p && !isspace(**p) && **p != ',') + { + p2 = *p; + while (*p2 && !isspace(*p2) && *p2 != ',') + { + if (*p2 == '\\') + { + if (p2[1]) + p2++; + } + p2++; + } + + // have arg here + args = lw_realloc(args, sizeof(char *) * (nargs + 1)); + args[nargs] = lw_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++; + if (**p == ',') + (*p)++; + } + + + // now create a string for the macro + // and push it into the front of the input stack + bloc = blen = 0; + linebuff = NULL; + + for (lc = 0; lc < m -> numlines; lc++) + { + for (p2 = m -> lines[lc]; *p2; p2++) + { + if (*p2 == '\\' && isdigit(p2[1])) + { + 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 - 1]; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + else if (*p2 == '{') + { + int n = 0, n2; + p2++; + while (*p2 && isdigit(*p2)) + { + 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 - 1]; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + else + { + macro_add_to_buff(&linebuff, &bloc, &blen, *p2); + } + } + + macro_add_to_buff(&linebuff, &bloc, &blen, '\n'); + + } + + { + char ctcbuf[100]; + char *p; + snprintf(ctcbuf, 100, "\001\001SETCONTEXT %d\n", oldcontext); + for (p = ctcbuf; *p; p++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p); + } + + // push the macro into the front of the stream + input_openstring(as, opc, linebuff); + + lw_free(linebuff); + + // clean up + if (args) + { + while (nargs) + { + lw_free(args[--nargs]); + } + lw_free(args); + } + + // indicate a macro was expanded + return 0; +} diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/main.c --- a/lwasm/main.c Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/main.c Thu Mar 25 23:17:54 2010 -0600 @@ -180,6 +180,7 @@ /* initialize assembler state */ asmstate.include_list = lw_stringlist_create(); asmstate.input_files = lw_stringlist_create(); + asmstate.nextcontext = 1; /* parse command line arguments */ argp_parse(&argp, argc, argv, 0, 0, &asmstate); diff -r 0215a0fbf61b -r 7416c3f9c321 lwasm/pass1.c --- a/lwasm/pass1.c Thu Mar 25 22:06:50 2010 -0600 +++ b/lwasm/pass1.c Thu Mar 25 23:17:54 2010 -0600 @@ -59,6 +59,22 @@ line = input_readline(as); if (!line) break; + if (line[0] == 1 && line[1] == 1) + { + // special internal directive + // these DO NOT appear in the output anywhere + // they are generated by the parser to pass information + // forward + for (p1 = line + 2; *p1 && !isspace(*p1); p1++) + /* do nothing */ ; + *p1++ = '\0'; + if (!strcmp(line + 2, "SETCONTEXT")) + { + as -> context = strtol(p1, NULL, 10); + } + lw_free(line); + continue; + } printf("%s\n", line); cl = lw_alloc(sizeof(line_t)); @@ -84,12 +100,15 @@ as -> line_tail = cl; // blank lines don't count for anything + // except a local symbol context break if (!*line) { + as -> context = lwasm_next_context(as); goto nextline; } // skip comments + // commends do not create a context break if (*line == '*' || *line == ';' || *line == '#') goto nextline; @@ -105,9 +124,14 @@ p1++; } + // blank line - context break if (!*p1) + { + as -> context = lwasm_next_context(as); goto nextline; + } + // comment - no context break if (*p1 == '*' || *p1 == ';' || *p1 == '#') goto nextline; @@ -120,8 +144,14 @@ else stspace = 0; - if (*p1 == '*' || *p1 == ';' || *p1 == '#' || !*p1) + if (*p1 == '*' || *p1 == ';' || *p1 == '#') goto nextline; + if (!*p1) + { + // nothing but whitespace - context break + as -> context = lwasm_next_context(as); + goto nextline; + } // find the end of the first token for (tok = p1; *p1 && !isspace(*p1) && *p1 != ':'; p1++) @@ -156,50 +186,77 @@ if (!strcasecmp(instab[opnum].opcode, sym)) break; } - lw_free(sym); // p1 points to the start of the operand + // if we're inside a macro definition and not at ENDM, + // add the line to the macro definition and continue + if (as -> inmacro && !(instab[opnum].flags & lwasm_insn_endm)) + { + add_macro_line(as, line); + goto linedone; + } + + // if skipping a condition and the operation code doesn't + // operate within a condition (not a conditional) + // do nothing + if (as -> skipcond && !(instab[opnum].flags & lwasm_insn_cond)) + goto linedone; + if (instab[opnum].opcode == NULL) { cl -> insn = -1; if (*tok != ';' && *tok != '*') { // bad opcode; check for macro here - lwasm_register_error(as, cl, "Bad opcode"); + if (expand_macro(as, cl, &p1, sym) != 0) + { + // macro expansion failed + lwasm_register_error(as, cl, "Bad opcode"); + } } } else { cl -> insn = opnum; - // call parse function - - if (*p1 && !isspace(*p1)) + // no parse func means operand doesn't matter + if (instab[opnum].parse) { - // flag bad operand error - lwasm_register_error(as, cl, "Bad operand (%s)", p1); + // call parse function + (instab[opnum].parse)(as, cl, &p1); + + if (*p1 && !isspace(*p1)) + { + // flag bad operand error + lwasm_register_error(as, cl, "Bad operand (%s)", p1); + } } } } + + linedone: + lw_free(sym); - if (cl -> sym && cl -> symset == 0) + if (!as -> skipcond && !as -> inmacro) { - printf("Register symbol %s:", sym); + if (cl -> sym && cl -> symset == 0) + { + printf("Register symbol %s:", sym); + lw_expr_print(cl -> addr); + printf("\n"); + + // register symbol at line address + if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none)) + { + // symbol error + lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym); + } + } + lw_expr_print(cl -> addr); printf("\n"); - - // register symbol at line address - if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none)) - { - // symbol error - lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym); - } } - lw_expr_print(cl -> addr); - printf("\n"); - // now parse the line - nextline: lw_free(line); }