diff src/parse.c @ 66:aa9d9fedfdf4

Redid lwasm_parse_line() to correct overly complex logic flaws
author lost
date Mon, 05 Jan 2009 05:40:16 +0000
parents aaddd47219b4
children cef25b0088e6
line wrap: on
line diff
--- a/src/parse.c	Mon Jan 05 01:40:01 2009 +0000
+++ b/src/parse.c	Mon Jan 05 05:40:16 2009 +0000
@@ -38,25 +38,35 @@
 	char *opc;
 	int opnum;
 	char *sym = NULL;
+
+	// if this was a bad op first pass (or otherwise a no-process line)
+	// ignore it
+	if (l -> badop)
+		return;
 	
 	p = l -> text;
-	
+
+	// blank lines are a no brainer
 	if (!*p)
 	{
-		if (as -> inmacro == 0)
-			as -> context = lwasm_next_context(as);
+		as -> context = lwasm_next_context(as);
 		return 0;
 	}
 	
 	// for output generation later but only on pass 1
+	// also used by some pseudo ops on pass 2
 	if (as -> passnum == 1)
 		l -> codeaddr = as -> addr;
 	
-	if (!isspace(*p) && *p != '*' && *p != ';')
+	// if it's a comment, return (this doesn't cause a context change)
+	if (*p == '*' || *p == ';')
+		return;
+	
+	// if we start with a non-space character, it's a symbol
+	if (!isspace(*p))
 	{
 		// we have a symbol specified here
-		// parse it and define
-		// need to handle local symbols here...
+		// parse it out and record it for later use
 		for (p2 = p; *p2 && !isspace(*p2); p2++)
 			/* do nothing */ ;
 		
@@ -65,30 +75,19 @@
 		memcpy(sym, p, p2 - p);
 		
 		p = p2;
-		
 	}
-	else
-	{
-		while (*p && isspace(*p))
-			p++;
-		if (!*p)
-		{
-			if (as -> inmacro == 0)
-				as -> context = lwasm_next_context(as);
-			return 0;
-		}
-	}
+	l -> sym = sym;
 
-	// skip white space
+	// now skip any whitespace to find the opcode
 	while (*p && isspace(*p))
 		p++;
 	
-	// if comment or end of line, return
-	if (!*p || *p == '*' || *p == ';')
+	// is the line blank?
+	if (!*p && !sym)
 	{
-		if (sym)
-			lwasm_free(l -> sym);
-		return 0;
+		// nothing but white space *is* a context break
+		as -> context = lwasm_next_context(as);
+		return;
 	}
 	
 	// parse the opcode
@@ -112,44 +111,73 @@
 			break;
 	}
 	
+	// if we found no operation, check if we had a comment
+	// the reason this check is here is to allow for "private"
+	// operation codes like "*pragma" which will be ignored by
+	// other assemblers
+	if (!(instab[opnum].opcode))
+	{
+		if (*opc == '*' || *opc == ';')
+			goto done_line;
+	}
+
+	// now we have the opcode and the symbol, we can decide if we're
+	// actually going to do anything with this line
+	
+	// we will NOT call the function if any of the following are true:
+	
+	// - we are skipping a condition and the operation code is not a conditional
+	// - we are defining a macro and the operation code is not ENDM
+
+	// we will call the function in any other circumstance
+	
+	// first condition above
 	if (as -> inmacro && instab[opnum].endm == 0)
 	{
 		add_macro_line(as, l -> text);
+		goto done_line;
 	}
 
-	if (as -> inmacro == 0 && as -> skipcond == 0)
+	// second condition above	
+	if (as -> skipcond && instab[opnum].iscond == 0)
+		goto done_line;
+
+	// register symbol if the operation won't
+	if (sym && instab[opnum].setsym == 0)
 	{
-		if (expand_macro(as, l, &p2, opc) == 0)
-			goto done_line;
-	}
-	
-	// register symbol if needed
-	if (as -> skipcond == 0 && as -> inmacro == 0 && sym)
-	{
-		l -> sym = sym;
-		if (as -> passnum == 1 && !(instab[opnum].opcode && instab[opnum].setsym))
+		if (as -> passnum == 1)
 		{
-			// have a symbol; now determine if it is valid and register it
-			// at the current address of the line
 			debug_message(1, "Registering symbol '%s' at %04X", sym, as -> addr);
 			if (lwasm_register_symbol(as, l, sym, as -> addr, SYMBOL_NORM) < 0)
 				l -> sym = NULL;
 		}
 	}
 
-	if (!(instab[opnum].opcode) || !(instab[opnum].fn) && !(as -> skipcond || as -> inmacro))
+	// we've registered the symbol as needed
+	// now we need to check for a macro call IFF we don't collide with
+	// an operation code; otherwise, call the operation function
+	if (instab[opnum].opcode)
 	{
-		// invalid operation code, throw error
-		register_error(as, l, 1, "Invalid operation code '%s'", opc);
-		if (sym)
-			lwasm_free(l -> sym);
-		lwasm_free(opc);
-		return -1;
+		if (instab[opnum].fn)
+		{
+			(instab[opnum].fn)(as, l, &p2, opnum);
+		}
+		else
+		{
+			// carp about unimplemented operation
+			register_error(as, l, 1, "Unimplemented operation code: %s", opc);
+		}
 	}
+	else
+	{
+		if (expand_macro(as, l, &p2, opc) == 0)
+			goto done_line;
 
-	// dispatch handler if we're not ignoring items
-	if (as -> skipcond == 0 && as -> inmacro == 0 && !(instab[opnum].iscond))
-		(instab[opnum].fn)(as, l, &p2, opnum);
+		// carp about an unknown operation code and note that fact for
+		// pass 2 in case a macro appears later with the same name!
+		register_error(as, l, 1, "Uknown operation code: %s", opc);
+		l -> badop = 1;
+	}
 
 done_line:
 	lwasm_free(opc);