# 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);
}