Mercurial > hg-old > index.cgi
diff old-trunk/lwasm/old/macro.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/macro.c Fri Mar 19 02:54:14 2010 +0000 @@ -0,0 +1,342 @@ +/* +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 <http://www.gnu.org/licenses/>. + +Contains stuff associated with macro processing +*/ + +#include <config.h> + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "lwasm.h" +#include "instab.h" +#include "util.h" + +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) + { + 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, l -> sym)) + break; + } + if (m) + { + register_error(as, l, 1, "Duplicate macro definition"); + return; + } + + 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; + + while (**p && !isspace(**p)) + (*p)++; +} + +OPFUNC(pseudo_endm) +{ + if (as -> skipcond) + { + as -> skipmacro = 0; + return; + } + + if (!as -> inmacro) + { + register_error(as, l, 1, "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; + + if (as -> passnum == 2) + return 1; + + 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; +} + +void macro_add_to_buff(char **buff, int *loc, int *len, char c) +{ + if (*loc == *len) + { + *buff = lwasm_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 + +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 + +*/ +int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc) +{ + int lc; + lwasm_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); + + // step 1: parse arguments (pass 1 only) + if (as -> passnum == 1) + { + while (**p && !isspace(**p) && **p != ',') + { + p2 = *p; + while (*p2 && !isspace(*p2) && *p2 != ',') + { + if (*p2 == '\\') + { + if (p2[1]) + p2++; + } + p2++; + } + + // have arg here + args = lwasm_realloc(args, sizeof(char *) * (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++; + if (**p == ',') + (*p)++; + } + } + + { + int i; + for (i = 0; i < nargs; i++) + { + debug_message(10, "Macro (%s) arg %d: %s", m -> name, i + 1, args[i]); + } + } + + // 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 + { + // pass 1 only - construct the lines and parse them + for (lc = 0; lc < m -> numlines; lc++) + { + nl = lwasm_alloc(sizeof(lwasm_line_t)); + 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; + nl -> badop = 0; + nl -> relocoff = -1; + if (as -> linestail) + as -> linestail -> next = nl; + as -> linestail = nl; + if (!(as -> lineshead)) + as -> lineshead = nl; + + bloc = blen = 0; + linebuff = NULL; + 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, 0); + + nl -> text = linebuff; + + lwasm_parse_line(as, nl); + if (as -> endseen) + break; + + } + } + + // restore context from before the macro was called + as -> context = oldcontext; + + // clean up + if (args) + { + while (nargs) + { + lwasm_free(args[--nargs]); + } + lwasm_free(args); + } + + // indicate a macro was expanded + return 0; +}