diff src/macro.c @ 57:035b95a3690f

Added conditional assembly and macros
author lost
date Mon, 05 Jan 2009 00:01:21 +0000
parents 34568fab6058
children d5fe306f1ab1
line wrap: on
line diff
--- a/src/macro.c	Sun Jan 04 21:43:05 2009 +0000
+++ b/src/macro.c	Mon Jan 05 00:01:21 2009 +0000
@@ -24,71 +24,95 @@
 #include <stdlib.h>
 #include <string.h>
 #include "lwasm.h"
+#include "instab.h"
+#include "util.h"
 
-extern void resolve_insn(asmstate_t *as, sourceline_t *cl);
-
-void pseudo_macro(asmstate_t *as, sourceline_t *cl, char **optr)
+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)
 	{
-		errorp1(ERR_MACRO);
+		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, cl -> symstr))
+		if (!strcmp(m -> name, l -> sym))
 			break;
 	}
 	if (m)
 	{
-		errorp1(ERR_DUPSYM);
+		register_error(as, l, 1, "Duplicate macro definition");
 		return;
 	}
-	m = calloc(sizeof(macrotab_t), 1);
-	m -> name = strdup(cl -> symstr);
+	
+	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;
-	cl -> hassym = 0;
-	while (**optr && !isspace(**optr))
-		(*optr)++;
-	cl -> macrodef = 1;
+
+	while (**p && !isspace(**p))
+		(*p)++;
 }
 
-void pseudo_endm(asmstate_t *as, sourceline_t *cl, char **optr)
+OPFUNC(pseudo_endm)
 {
+	if (as -> skipcond)
+	{
+		as -> skipmacro = 0;
+		return;
+	}
+	
 	if (!as -> inmacro)
 	{
-		errorp1(ERR_ENDM);
+		register_error(as, l, 1, "ENDM without MACRO");
 		return;
 	}
 	
 	as -> inmacro = 0;
-	cl -> macrodef = 1;
+	
+	// a macro definition counts as a context break for local symbols
+	as -> context = lwasm_next_context(as);
 }
 
-int add_macro_line(asmstate_t *as, sourceline_t *cl, char *optr)
+// the current macro will ALWAYS be the first one in the table
+int add_macro_line(asmstate_t *as, char *optr)
 {
-	macroline_t *l;
-	
 	if (!as -> inmacro)
 		return 0;
 	
 	if (as -> passnum == 2)
 		return 1;
 
-	l = calloc(sizeof(macroline_t), 1);
-	l -> linetext = strdup(optr);
-	if (as -> macros -> linetail)
-		as -> macros -> linetail -> next = l;
-	as -> macros -> linetail = l;
-	if (!(as -> macros -> linehead))
-		as -> macros -> linehead = l;
+	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;
 }
 
@@ -104,128 +128,196 @@
 
 // this is just like a regular operation function
 /*
-macro args are references by "\n" where 1 <= n <= 9
+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
+
 */
-void expand_macro(asmstate_t *as, sourceline_t *cl, char **optr)
+int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc)
 {
-	char **args = NULL;
-	int nargs = 0;
-	int c;
-	sourceline_t *nl;
-	int nline = 1;
+	int lc;
+	lwasm_line_t *cl, *nl;
+	int oldcontext;
 	macrotab_t *m;
-	macroline_t *ml;
-	char *buff = NULL;
-	int bufflen = 0, buffloc;
+
+	char **args = NULL;		// macro arguments
+	int nargs;				// number of arguments
+
+	char *p2, *p3;
 	
-	m = cl -> macro;
+	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;
 	
-	// step the first: parse arguments
-	while (**optr && !isspace(**optr))
+
+	// 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)
 	{
-		c = 0;
-		while ((*optr)[c] && !isspace((*optr)[c]) && (*optr)[c] != ',')
+		while (**p && !isspace(**p) && **p != ',')
 		{
-			c++;
+			p2 = *p;
+			while (*p2 && !isspace(*p2) && *p2 != ',')
+			{
+				if (*p2 == '\\')
+				{
+					if (p2[1])
+						p2++;
+				}
+			}
+			
+			// have arg here
+			args = lwasm_realloc(args, 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++;
 		}
-		args = realloc(args, sizeof(char *) * (nargs + 1));
-		args[nargs] = malloc(c + 1);
-		strncpy(args[nargs], *optr, c);
-		args[nargs][c] = '\0';
-		nargs++;
-		*optr += c;
-		if (**optr == ',')
-			(*optr)++;
 	}
 	
-	// step the second: iterate over the lines and expand arguments and add
-	// them after "cl"
-	for (ml = m -> linehead; ml; ml = ml -> next)
+	// 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
 	{
-		nl = calloc(sizeof(sourceline_t), 1);
-		
-		nl -> lineno = nline++;
-		nl -> sourcefile = m -> name;
-		nl -> opcode = -1;
-		nl -> addrmode = -1;
-		nl -> addr = as -> addr;
-		nl -> dpval = as -> dpval;
-		nl -> prev = cl;
-		if (!(cl -> next))
-			as -> source_tail = nl;
-		nl -> next = cl -> next;
-		cl -> next = nl;
+		// pass 1 only - construct the lines and parse them
+		for (lc = 0; lc < m -> numlines; lc++)
+		{
+			nl = lwasm_alloc(sizeof(lwasm_line_t));
+			nl -> text = lwasm_strdup(linebuff);
+			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;
+			if (as -> linestail)
+				as -> linestail -> next = nl;
+			as -> linestail = nl;
+			if (!(as -> lineshead))
+				as -> lineshead = nl;
 
-		buffloc = 0;
-		c = 0;
-		while (ml -> linetext[c])
-		{
-			int ch;
-			ch = ml -> linetext[c++];
-			if (ch == '{')
+			bloc = blen = 0;
+			linebuff = NULL;
+			for (p2 = m -> lines[lc]; *p2; p2++)
 			{
-				int v = 0;
-			again:
-				ch = ml -> linetext[c++];
-				if (!ch)
+				if (*p2 == '\\' && isdigit(p2[1]))
 				{
-					c--;
+					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]; p3; p3++)
+						macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
 					continue;
 				}
-				if (ch >= '0' && ch <= '9')
-				{
-					v = v * 10 + (ch - '0');
-					goto again;
-				}
-				if (ch == '}')
+				else if (*p2 == '{')
 				{
-					v--;
-					if (v < nargs)
+					int n = 0, n2;
+					p2++;
+					while (*p2 && isdigit(*p2))
 					{
-						char *t;
-						for (t = args[v]; *t; t++)
-						{
-							macro_add_to_buff(&buff, &buffloc, &bufflen, *t);
-						}
+						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]; p3; p3++)
+						macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
 					continue;
 				}
 				else
-					continue;
-			}
-			else if (ch == '\\' && ml -> linetext[c])
-			{
-				ch = ml -> linetext[c++];
-				if (ch >= '1' && ch <= '9')
 				{
-					ch -= '1';
-					if (ch < nargs)
-					{
-						char *t;
-						for (t = args[ch]; *t; t++)
-						{
-							macro_add_to_buff(&buff, &buffloc, &bufflen, *t);
-						}
-					}
-				}
-				else
-				{
-					c--;
-					macro_add_to_buff(&buff, &buffloc, &bufflen, '\\');
+					macro_add_to_buff(&linebuff, &bloc, &blen, *p2);
 				}
 			}
-			else
-			{
-				macro_add_to_buff(&buff, &buffloc, &bufflen, ch);
-			}
+
+			nl -> text = linebuff;
+
+			lwasm_parse_line(as, nl);
+			if (as -> endseen)
+				break;
+
 		}
-		macro_add_to_buff(&buff, &buffloc, &bufflen, 0);
-		nl -> line = strdup(buff);
+	}
+	
+	// restore context from before the macro was called
+	as -> context = oldcontext;
 
-		resolve_insn(as, nl);
-		cl = nl;
+	// clean up
+	while (nargs)
+	{
+		lwasm_free(args[--nargs]);
 	}
-	if (buff)
-		free(buff);
+	lwasm_free(args);
+
+	// indicate a macro was expanded
+	return 0;	
 }