view src/parse.c @ 57:035b95a3690f

Added conditional assembly and macros
author lost
date Mon, 05 Jan 2009 00:01:21 +0000
parents b9856da2674a
children d85ba47b1e8f
line wrap: on
line source

/*
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 <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;
	
	p = l -> text;
	
	if (!*p)
	{
		if (as -> inmacro == 0)
			as -> context = lwasm_next_context(as);
		return 0;
	}
	
	// for output generation later but only on pass 1
	if (as -> passnum == 1)
		l -> codeaddr = as -> addr;
	
	if (!isspace(*p) && *p != '*' && *p != ';')
	{
		// we have a symbol specified here
		// parse it and define
		// need to handle local symbols here...
		for (p2 = p; *p2 && !isspace(*p2); p2++)
			/* do nothing */ ;
		
		sym = lwasm_alloc((p2 - p) + 1);
		sym[p2 - p] = '\0';
		memcpy(sym, p, p2 - p);
		
		p = p2;
		
		if (as -> passnum == 1)
		{
			l -> sym = sym;
			// 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) < 0)
				l -> sym = NULL;
		}
	}
	else
	{
		while (*p && isspace(*p))
			p++;
		if (!*p)
		{
			if (as -> inmacro == 0)
				as -> context = lwasm_next_context(as);
			return 0;
		}
	}

	// skip white space
	while (*p && isspace(*p))
		p++;
	
	// if comment or end of line, return
	if (!*p || *p == '*' || *p == ';')
	{
		if (sym)
			lwasm_free(l -> sym);
		return 0;
	}
	
	// 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';

	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 (as -> inmacro && instab[opnum].endm == 0)
	{
		add_macro_line(as, l -> text);
	}

	if (as -> inmacro == 0 && as -> skipcond == 0)
	{
		if (expand_macro(as, l, &p2, opc) == 0)
			goto done_line;
	}
	
	if (!(instab[opnum].opcode) || !(instab[opnum].fn) && !(as -> skipcond || as -> inmacro))
	{
		// 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;
	}

	// 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);

done_line:
	lwasm_free(opc);
	if (sym)
		lwasm_free(sym);
}