Mercurial > hg > index.cgi
diff lwasm/macro.c @ 0:2c24602be78f
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author | lost@l-w.ca |
---|---|
date | Wed, 19 Jan 2011 22:27:17 -0700 |
parents | |
children | 7317fbe024af |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/macro.c Wed Jan 19 22:27:17 2011 -0700 @@ -0,0 +1,292 @@ +/* +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 <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <lw_alloc.h> +#include <lw_string.h> + +#include "lwasm.h" +#include "input.h" +#include "instab.h" + +PARSEFUNC(pseudo_parse_macro) +{ + macrotab_t *m; + + l -> len = 0; + + 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_parse_endm) +{ + l -> len = 0; + + 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; +}