view lwasm/pass1.c @ 340:1a6fc6ebb31c

Checkpoint
author lost
date Fri, 19 Mar 2010 02:54:43 +0000
parents 04c80c51b16a
children 7b4123dce741
line wrap: on
line source

/*
pass1.c

Copyright © 2010 William Astle

This file is part of LWTOOLS.

LWTOOLS 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/>.
*/

#include <config.h>

#include <stdio.h>

#include <lw_alloc.h>

#include "lwasm.h"
#include "input.h"

/*
pass 1: parse the lines

line format:

[<symbol>] <opcode> <operand>[ <comment>]

If <symbol> is followed by a :, whitespace may precede the symbol

A line may optionally start with a number which must not be preceded by
white space and must be followed by a single whitespace character. After
that whitespace character, the line is parsed as if it had no line number.

*/
void do_pass1(asmstate_t *as)
{
	char *line;
	line_t *cl;
	char *p1;
	int stpace;
	char *tok, *sym;
	int opnum;
	
	for (;;)
	{
		sym = NULL;
		line = input_readline(as);
		if (!line)
			break;
		printf("%s\n", line);
		
		cl = lw_alloc(sizeof(line_t));
		cl -> next = NULL;
		cl -> prev = as -> line_tail;
		cl -> len = -1;
		cl -> insn = -1;
		if (!as -> line_tail)
		{
			as -> line_head = cl;
			cl -> addr = lw_expr_build(lw_expr_type_int, 0);
		}
		else
		{
			lw_expr_t te;
			as -> line_tail -> next = cl;
			te = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, cl -> prev);
			cl -> addr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> addr, te);
			lw_expr_destroy(te);
			lw_expr_simplify(cl -> addr);
		}
		as -> line_tail = cl;

		// blank lines don't count for anything
		if (!*line)
		{
			goto nextline;
		}
	
		// skip comments
		if (*line == '*' || *line == ';' || *line == '#')
			goto nextline;

		p1 = line;
		if (isdigit(*p1))
		{
			// skip line number
			while (*p1 && isdigit(*p1))
				p1++;
			if (!*p1 && !isspace(*p1))
				p1 = line;
			else if (*p1 && isspace(*p1))
				p1++;
		}

		if (!*p1)
			goto nextline;

		if (*p1 == '*' || *p1 == ';' || *p1 == '#')
			goto nextline;

		if (isspace(*p1))
		{
			for (; *p1 && isspace(*p1); p1++)
				/* do nothing */ ;
			stspace = 1;
		}
		else
			stspace = 0;

		if (*p1 == '*' || *p1 == ';' || *p1 == '#' || !*p1)
			goto nextline;

		
		for (tok = p1; *p1 && !isspace(*p1) && *p1 != ':'; p1++)
			/* do nothing */ ;
		
		if (*p1 == ':' || stspace == 0)
		{
			// have a symbol here
			sym = lw_strndup(tok, p1 - tok);
			if (*p1 == ':')
				p1++;
			for (; *p1 && isspace(*p1); p1++)
				/* do nothing */ ;
			
			for (tok = p1; *p1 && !isspace(*p1); p1++)
				/* do nothing */ ;
		}

		cl -> sym = sym;
		cl -> symset = 0;
		
		// tok points to the opcode for the line or NUL if none
		if (*tok)
		{
			// look up operation code
			sym = lw_strndup(tok, p1 - tok);
			for (; *p1 && isspace(p1); p1++)
				/* do nothing */ ;

			for (opnum = 0; instab[opnum].opcode; opnum++)
			{
				if (!strcasecmp(instab[opnum].opcode, sym))
					break;
			}
			lw_free(sym);
			
			// p1 points to the start of the operand
			
			if (instab[opnum].opcode == NULL)
			{
				cl -> insn = -1;
				if (*tok != ';' && *tok != '*')
				{
					// bad opcode; check for macro here
				}
			}
			else
			{
				cl -> insn = opnum;
				// call parse function
				
				if (*p1 && !isspace(*p1))
				{
					// flag bad operand error
				}
			}
		}
		
		if (cl -> sym && cl -> symset == 0)
		{
			// register symbol at line address
		}
		
		lw_expr_print(cl -> addr);
		printf("\n");
		// now parse the line
		
	nextline:
		lw_free(line);
	}
}