view src/macro.c @ 8:f1df096aa76f 1.1

Tagged 1.1 bugfix release
author lost
date Sun, 04 Jan 2009 05:46:07 +0000
parents 34568fab6058
children 035b95a3690f
line wrap: on
line source

/*
macro.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 stuff associated with macro processing
*/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "lwasm.h"

extern void resolve_insn(asmstate_t *as, sourceline_t *cl);

void pseudo_macro(asmstate_t *as, sourceline_t *cl, char **optr)
{
	macrotab_t *m;

	if (as -> inmacro)
	{
		errorp1(ERR_MACRO);
		return;
	}
	as -> inmacro = 1;
	if (as -> passnum != 1)
		return;
	
	for (m = as -> macros; m; m = m -> next)
	{
		if (!strcmp(m -> name, cl -> symstr))
			break;
	}
	if (m)
	{
		errorp1(ERR_DUPSYM);
		return;
	}
	m = calloc(sizeof(macrotab_t), 1);
	m -> name = strdup(cl -> symstr);
	m -> next = as -> macros;
	as -> macros = m;
	cl -> hassym = 0;
	while (**optr && !isspace(**optr))
		(*optr)++;
	cl -> macrodef = 1;
}

void pseudo_endm(asmstate_t *as, sourceline_t *cl, char **optr)
{
	if (!as -> inmacro)
	{
		errorp1(ERR_ENDM);
		return;
	}
	
	as -> inmacro = 0;
	cl -> macrodef = 1;
}

int add_macro_line(asmstate_t *as, sourceline_t *cl, 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;
	return 1;
}

void macro_add_to_buff(char **buff, int *loc, int *len, char c)
{
	if (*loc == *len)
	{
		*buff = realloc(*buff, *len + 32);
		*len += 32;
	}
	(*buff)[(*loc)++] = c;
}

// this is just like a regular operation function
/*
macro args are references by "\n" where 1 <= n <= 9
or by "\{n}"; a \ can be included by writing \\
*/
void expand_macro(asmstate_t *as, sourceline_t *cl, char **optr)
{
	char **args = NULL;
	int nargs = 0;
	int c;
	sourceline_t *nl;
	int nline = 1;
	macrotab_t *m;
	macroline_t *ml;
	char *buff = NULL;
	int bufflen = 0, buffloc;
	
	m = cl -> macro;
	
	// step the first: parse arguments
	while (**optr && !isspace(**optr))
	{
		c = 0;
		while ((*optr)[c] && !isspace((*optr)[c]) && (*optr)[c] != ',')
		{
			c++;
		}
		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)
	{
		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;

		buffloc = 0;
		c = 0;
		while (ml -> linetext[c])
		{
			int ch;
			ch = ml -> linetext[c++];
			if (ch == '{')
			{
				int v = 0;
			again:
				ch = ml -> linetext[c++];
				if (!ch)
				{
					c--;
					continue;
				}
				if (ch >= '0' && ch <= '9')
				{
					v = v * 10 + (ch - '0');
					goto again;
				}
				if (ch == '}')
				{
					v--;
					if (v < nargs)
					{
						char *t;
						for (t = args[v]; *t; t++)
						{
							macro_add_to_buff(&buff, &buffloc, &bufflen, *t);
						}
					}
					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, '\\');
				}
			}
			else
			{
				macro_add_to_buff(&buff, &buffloc, &bufflen, ch);
			}
		}
		macro_add_to_buff(&buff, &buffloc, &bufflen, 0);
		nl -> line = strdup(buff);

		resolve_insn(as, nl);
		cl = nl;
	}
	if (buff)
		free(buff);
}