diff old-trunk/lwasm/old/parse.c @ 339:eb230fa7d28e

Prepare for migration to hg
author lost
date Fri, 19 Mar 2010 02:54:14 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/old-trunk/lwasm/old/parse.c	Fri Mar 19 02:54:14 2010 +0000
@@ -0,0 +1,236 @@
+/*
+parse.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 the general parser
+*/
+
+#define __parse_c_seen__
+#include <config.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include "lwasm.h"
+#include "instab.h"
+#include "util.h"
+
+// parse a line and despatch to the appropriate handlers for opcodes
+int lwasm_parse_line(asmstate_t *as, lwasm_line_t *l)
+{
+	char *p, *p2;
+	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;
+	l -> sect = as -> csect;
+	l -> inmod = as -> inmod;
+
+	// blank lines are a no brainer
+	if (!*p)
+	{
+		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 it's a comment, return (this doesn't cause a context change)
+	if (*p == '*' || *p == ';')
+		return;
+	
+	// if we have C pre-processor directives/output, ignore it
+	if (*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 out and record it for later use
+		for (p2 = p; *p2 && !isspace(*p2) && *p2 != ':'; p2++)
+			/* do nothing */ ;
+		
+		sym = lwasm_alloc((p2 - p) + 1);
+		sym[p2 - p] = '\0';
+		memcpy(sym, p, p2 - p);
+		
+		p = p2;
+		if (!*sym)
+		{
+			register_error(as, l, 1, "Invalid symbol");
+			lwasm_free(sym);
+			sym = NULL;
+		}
+		if (*p == ':')
+			p++;
+	}
+	l -> sym = sym;
+
+	// now skip any whitespace to find the opcode
+	while (*p && isspace(*p))
+		p++;
+	
+	// is the line blank?
+	if (!*p && !sym)
+	{
+		// nothing but white space *is* a context break
+		as -> context = lwasm_next_context(as);
+		return;
+	}
+	
+	// parse the opcode
+	for (p2 = p; *p2 && !isspace(*p2); p2++)
+		/* do nothing */ ;
+	
+	opc = lwasm_alloc((p2 - p) + 1);
+	memcpy(opc, p, p2 - p);
+	opc[p2 - p] = '\0';
+
+	l -> forceglobal = 0;
+	// if the opcode contains an =, treat it as "symbol = expr"
+	if (!sym && strchr(opc, '='))
+	{
+		for (p2 = opc; *p2 && *p2 != '='; p2++)
+			/* do nothing */ ;
+		sym = lwasm_alloc((p2 - opc) + 1);
+		memcpy(sym, opc, p2 - opc);
+		sym[p2 - opc] = '\0';
+		l -> sym = sym;
+		
+		p2 = p + (p2 - opc) + 1;
+//		p2++;
+		opc[0] = '=';
+		opc[1] = '\0';
+		debug_message(2, "Found opcode = with symbol %s and operand %s", sym, p2);
+		l -> forceglobal = 1;
+	}
+	
+	debug_message(2, "Found operation code: '%s'", opc);
+
+	// skip intervening whitespace if present
+	while (*p2 && isspace(*p2))
+		p2++;
+
+	// look up instruction in insn table
+	for (opnum = 0; instab[opnum].opcode; opnum++)
+	{
+		if (!strcasecmp(instab[opnum].opcode, opc))
+			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
+	// also skip empty ops
+	if (!(instab[opnum].opcode))
+	{
+		if (*opc == '*' || *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;
+	}
+
+	// second condition above	
+	if (as -> skipcond && instab[opnum].iscond == 0)
+		goto done_line;
+
+	// 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)
+	{
+		if (instab[opnum].fn && !(as -> no6309 && instab[opnum].is6309))
+		{
+			(instab[opnum].fn)(as, l, &p2, opnum);
+			
+			// if we didn't end on a "space" character or EOL, throw error
+			if (*p2 && !isspace(*p2) && !(l -> err) && as -> passnum == 1)
+				register_error(as, l, 1, "Bad operand: %s (%d)", p2, as -> passnum);
+		}
+		else
+		{
+			// carp about unimplemented operation
+			if (instab[opnum].is6309)
+				register_error(as, l, 1, "Use of 6309 operation code: %s", opc);
+			else
+				register_error(as, l, 1, "Unimplemented operation code: %s", opc);
+		}
+	}
+	else
+	{
+		if (expand_macro(as, l, &p2, opc) == 0)
+			goto done_line;
+
+		// 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:
+	if (!(as -> skipcond || as -> inmacro))
+	{
+		// register symbol if the operation didn't
+		if (sym && instab[opnum].setsym == 0)
+		{
+			if (as -> passnum == 1)
+			{
+				debug_message(1, "Registering symbol '%s' at %04X", sym, l -> codeaddr);
+				if (lwasm_register_symbol(as, l, sym, l -> codeaddr, SYMBOL_NORM) < 0)
+					l -> sym = NULL;
+				else
+					l -> addrset = 1;
+			}
+		}
+	}
+
+	l -> sect = as -> csect;
+	l -> context = as -> context;
+	
+	lwasm_free(opc);
+	if (sym)
+		lwasm_free(sym);
+}