#include <stdio.h>
#include "defs.h"
#include "externs.h"

/* translate source line to machine language */

assemble()
{
	struct t_line *ptr;
	char *buf;
	char c;
	int	 flag;
	int	 i, j;		/* prlnbuf pointer */

	/* -- Macro definition. */

	if (in_macro) {
		i = SFIELD;
		if (colsym(&i))
			if (prlnbuf[i] == ':')
				i++;
		while (isspace(prlnbuf[i]))
			i++;
		if (pass == LAST_PASS)
			println();
		if (oplook(&i) >= 0) {
			if (opflg == PSEUDO) {
				if (opval == 11) {
					error("Can not nest macro definitions!");
					return;
				}
				if (opval == 12) {
					if (!check_eol(&i))
						return;
					in_macro = 0;
					return;
				}
			}
		}
		if (pass == FIRST_PASS) {
			ptr = (void *)malloc(sizeof(struct t_line));
			buf = (void *)malloc(strlen(&prlnbuf[SFIELD]) + 1);
			if ((ptr == NULL) || (buf == NULL)) {
				error("Out of memory!");
				return;
			}
			strcpy(buf, &prlnbuf[SFIELD]);
			ptr->next = NULL;
			ptr->data = buf;
			if (mlptr)
			    mlptr->next = ptr;
			else
				mptr->line = ptr;
		    mlptr = ptr;
		}
		return;
	}

	/* -- Comment line. */

	c = prlnbuf[SFIELD];
	if (c == ';' || c == '*' || c == '\0') {
		if (pass == LAST_PASS) {
			println();
			return;
		}
	}

	/* -- Search for a label. */

	i = SFIELD;
	j = 0;
	lablptr = NULL;

	while (isspace(prlnbuf[i]))
		i++;
	while (c = prlnbuf[i + j]) {
		if ((c == '_') || (c == '.') || isalpha(c) || (isdigit(c) && (j >= 1)));
		else break;
		j++;
	}
	if ((j == 0) || ((i != SFIELD) && (c != ':')))
		i = SFIELD;
	else {
		if (colsym(&i) != 0)
			if ((lablptr = stlook()) == NULL)
				return;
		if ((lablptr) && (prlnbuf[i] == ':'))
			i++;
	}
	while (isspace(prlnbuf[i]))
		i++;

	/* -- Test if a macro. */

	if (flag = macro_look(i)) {
		if (flag < 0)
			return;
		labldef(loccnt, 1);
		if (pass == LAST_PASS) {
			if (!mlist)
				loadlc((page << 13) + loccnt, 0);
			println();
		}
		mcntmax++;
		mcounter = mcntmax;
		expand_macro = 1;
		mlptr = mptr->line;
		return;
	}

	/* -- Test if an instruction. */

	if ((flag = oplook(&i)) < 0) {
		labldef(loccnt, 1);
		if (flag == -1)
			error("Invalid instruction!");
		if ((flag == -2) && (pass == LAST_PASS)) {
			if (lablptr)
				loadlc((page << 13) + loccnt, 1);
			println();
		}
		return;
	}

	/* -- Generate code. */

	if (opflg == PSEUDO)
		pseudo(&i);
	else if (labldef(loccnt, 1) == -1)
		return;
	else {
		if (opflg == CLASS1)
			class1(&i);
		else if (opflg == CLASS2)
			class2(&i);
		else if (opflg == CLASS3)
			class3(&i);
		else if (opflg == CLASS5)
			class5(&i);
		else if (opflg == CLASS6)
			class6(&i);
		else if (opflg == CLASS7)
			class7(&i);
		else if (opflg == CLASS8)
			class8(&i);
		else
			class4(&i);
	}
}

/****************************************************************************/

/*  operation code table lookup
 *	if found, return pointer to symbol,
 *	else, return -1
 */

oplook(int *idx)
{
	char c, opcode[16];
	int	i;

	i = 0;
	while(c = prlnbuf[*idx]) {
		if (c == ' ' || c == '\t' || c == ';')
			break;
		if (!isalnum(c) && c != '.' && c != '*' && c != '=')
			return(-1);
		opcode[i++] = c;
		(*idx)++;
		if (c == '=')
			break;
		if (i >= 9)
			return(-1);
	}

	opcode[i] = '\0';

	if (i == 0)
		return (-2);

	i = 0;
	while (optab[i].name) {
		if (!stricmp(opcode, optab[i].name)) {
			opflg = optab[i].flag;
			opval = optab[i].value;
			optype = optab[i].type_idx;
			return(i);
		}
		i++;
	}

	return(-1);
}

/* check the end of line for garbage */

check_eol(int *ip)
{
	while (isspace(prlnbuf[*ip]))
		(*ip)++;
	if (prlnbuf[*ip] == ';' || prlnbuf[*ip] == '\0')
		return (1);
	else {
		error("Syntax error!");
		return (0);
	}
}

