/*
 * esa1.c
 * Assemble a line.
 */
#include <stdio.h>
#include "esa.h"

/*
 * Assemble a line.
 * The code is saved in the code
 * buffers for use by the listing
 * generator.
 * Binary code gets written right
 * out.
 */
asmline()
{
	register struct sym *sp;
	register int rs, rd;
	int a, c, f, opcode;
	char id[NCPS];
	
	listaddr = dot->s_value;
	listmode = SLIST;
loop:
	if((c=getnb())=='\0' || c=='/')
		return;
	if(!alpha(c)) {
		err('q');
		return;
	}
	getid(c, id);

	/*
	 * Direct assignment.
	 */
	if((c=getnb()) == '=') {
		sp = lookup(id, ust);
		if(sp->s_type!=S_UND && (sp->s_flag&SF_ASG)==0)
			err('m');
		sp->s_type = S_ABS;
		sp->s_flag |= SF_ASG;
		sp->s_value = listaddr = expr();
		listmode = ALIST;

	/*
	 * Label.
	 */
	} else if(c == ':') {
		if((sp=lookup(id, ust)) == dot)
			err('.');
		else if(pass==0) {
			if(sp->s_type!=S_UND && (sp->s_flag&SF_ASG)==0)
				sp->s_flag |= SF_MDF;
			sp->s_type = S_ABS;
			sp->s_value = dot->s_value;
		} else {
			if((sp->s_flag&SF_MDF)!=0)
				err('m');
			if(sp->s_type!=S_ABS || sp->s_value!=dot->s_value)
				err('p');
		}
		listmode = ALIST;
		goto loop;
	
	/*
	 * Normal (keyword) line.
	 */
	} else {
		putback(c);
		listmode = CLIST;
		if((sp=lookup(id, pst)) == NULL)
			err('o');
		else {
			opcode = sp->s_value;
			switch(sp->s_type) {

			case S_BYTE:
				do {
					a = expr();
					byte(a);
					codeb(a);
				} while((c=getnb()) == ',');
				putback(c);
				break;

			case S_WORD:
				do {
					a = expr();
					codew(a);
				} while((c=getnb()) == ',');
				putback(c);
				break;

			case S_ASCII:
				ascii(0);
				break;

			case S_ASCIZ:
				ascii(1);
				break;

			case S_BLKB:
				a = expr();
				if((c=getnb()) == ',')
					f = expr();
				else {
					putback(c);
					f = 0;
				}
				while(a--)
					codeb(f);
				listmode = ALIST;
				break;

			case S_OP1:
				codeb(opcode);
				break;

			case S_OP2:
				a = expr();
				byte(a);
				codeb(opcode);
				codeb(a);
				break;

			case S_OP3:
				a = expr();
				codeb(opcode);
				codew(a);
				break;

			case S_OP4:
				lrp(LBI, LCI);
				break;

			case S_OP5:
				lrp(LDI, LEI);
				break;

			case S_OP6:
				lrp(LHI, LLI);
				break;

			case S_IN:
				a = expr();
				if((a&~07) != 0)
					err('t');
				codeb(opcode | a<<1);
				break;

			case S_OUT:
				a = expr();
				if((a&~037)!=0 || a<010)
					err('t');
				codeb(opcode | a<<1);
				break;

			default:
				err('o');
			}
		}
	}
	if((c=getnb())!='\0' && c!='/')
		err('q');
}

/*
 * Code a load register pair
 * instruction.
 * The opcode used to load up
 * the hi half is `hi'; the
 * one for the low half is
 * `lo'.
 */
lrp(hi, lo)
{
	register int a;

	a = expr();
	codeb(hi);
	codeb(a>>8);
	codeb(lo);
	codeb(a);
}

/*
 * Process the body of a `.ascii' or of a
 * `.asciz'.
 * The `z' flag is true for an
 * `.asciz'.
 */
ascii(z)
{
	register int c, delim;

	if((delim=getnb()) == '\0') {
		err('q');
		return;
	}
	while((c=getmap())!='\0' && c!=delim)
		codeb(c);
	if(c == '\0')
		err('q');
	if(z)
		codeb(0);
}

/*
 * Given a number (usually the result
 * of an expression, check that the
 * number can be expressed in a byte.
 * If it cannot put out a `t' error.
 */
byte(b)
{
	if((b&0200)!=0)
		b |= ~0377;
	if(b>127 || b<-128)
		err('t');
}
