Mercurial > hg-old > index.cgi
view src/macro.c @ 92:ea2cfebef5d0
Make external symbols remain unresolved in expressions and also flag them in the symbol list
author | lost |
---|---|
date | Sat, 17 Jan 2009 06:11:40 +0000 |
parents | 918be0c02239 |
children |
line wrap: on
line source
/* 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 "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; }