/*
	1802 Cross-Assembler  v. 2.3

	May, 1980

	June, 1980 -- Rev. 2.1 consisting of fixing P errors that come
		from EQUing things to the pre-defined symbols, and adding
		the LOAD pseudo-op.

	July, 1980 -- Rev. 2.2 consisting of fixing the M errors that
		come from forward references in WORD and BYTE pseudo-ops.

	October, 1980 -- Rev. 2.3 consisting of modifying the assembly
		language routines and I/O routines to match and take
		advantage of BDS C V1.4.

	Copyright (c) 1980 William C. Colley, III.

File:	a18asmln.c

Line assembly routine.
*/

/*  Get globals:  */

#include "a18.h"

/*
This function is the workhorse of the assembler.  The routine
gets any labels off the line and processes them, gets the opcode
and builds the binary output as it evaluates the operand field.
*/

asmline()
{
	char c, label[2*SYMLEN], opcode, opattr, getchr();
	nbytes = 0;
	address = pc;
	directok = TRUE;
	evalerr = FALSE;
	hexflg = NOCODE;
	label[0] = '\0';
	binbuf[0] = binbuf[1] = binbuf[2] = 0xc4;
	switch (getchr(&c,NOSKIP))
	{
		case ALPHA:	backchr;
				getname(label);
				if (strcmp(label,"$") == 0 || chkoprat(label) != NO_OPR)
				{
					markerr('L');
					label[0] = '\0';
				}
				break;

		case END_LIN:	return;

		case BLANK:	break;

		default:	markerr('L');
				while((c = getchr(&c,NOSKIP)) != BLANK && c != END_LIN);
				backchr;
	}
	switch (getopcod(&opcode,&opattr))
	{
		case 0:		nbytes = 3;

		case -1:	opcode = 255;	/*  Set nil pseudo-op.	*/
				opattr = 0x80;

		case 1:		if ((opattr & (PSOP | IFGROUP)) == (PSOP | IFGROUP))
				{
					if (label[0] != '\0') markerr('L');
				}
				else
				{
					if (ifstack[ifsp] == 0) return;
					if (label[0] != '\0')
					{
						strcat(label,PADDING);
						if (pass == 1)
						{
							if (addsym(label))
							{
								sympoint -> symvalu = pc;
								if ((opattr & PSOP) && opcode == 10)
								{
									sympoint -> symname[1] |= 0x80;
								}
							}
						}
						else
						{
							if (slookup(label))
							{
								markerr('P');
								label[0] = '\0';
							}
							else
							{
								if (sympoint -> symvalu != pc || (sympoint -> symname[1] & 0x80))
								{
									markerr('M');
								}
								sympoint -> symname[0] &= 0x7f;
							}
						}
					}
				}
				hexflg = PUTCODE;
				if (opattr & PSOP) _psop(opcode,label);
				else _normop(opcode,opattr);
				return;
	}
}

/*
Internal function to process pseudo opcodes.
*/

_psop(opcode,label)
char opcode, *label;
{
	char *bptr, c, d;
	unsigned t, t2;
	struct symbtbl *sptr;
	sptr = sympoint;
	bptr = binbuf;
	switch (opcode)
	{
		case 0:		t = eval(START);		/* ORG.	*/
				if (evalerr || !directok)
				{
					markerr('P');
					return;
				}
				address = pc = t;
				hexflg = FLUSH;
				if (label[0] == '\0') goto chkargs;
				backitem(t,VALUE);
				backchr;

		equlabl:
		case 1:		if (label[0] == '\0')		/* EQU.	*/
				{
					markerr('L');
					return;
				}
				if (!(sptr -> symname[1] & 0x80) && errcode == 'M')
				{
					errcode = ' ';
					errcount--;
				}
				t = eval(START);
				if (evalerr || !directok)
				{
					markerr('P');
					return;
				}
				address = sptr -> symvalu;
				sptr -> symvalu = t;
				if (address != t) markerr('M');
				goto chkargs;

		case 2:					/* BYTE.	*/
				while ((c = getitem(&t,SMALST)) != END_LIN)
				{
					if (c == COMMA)
					{
						*bptr++ = 0;
						nbytes++;
						continue;
					}
					backitem(t,c);
					t = eval(START);
					if (t > 0xff && t < 0xff80)
					{
						markerr('V');
						t = 0;
					}
					*bptr++ = t;
					nbytes++;
				}
				return;

		case 3:					/* WORD.	*/
				while ((c = getitem(&t,SMALST)) != END_LIN)
				{
					if (c == COMMA)
					{
						*bptr++ = 0;
						*bptr++ = 0;
						nbytes += 2;
						continue;
					}
					backitem(t,c);
					t = eval(START);
					*bptr++ = t >> 8;
					*bptr++ = t;
					nbytes += 2;
				}
				return;

		case 4:					/* TEXT.	