#include <stdlib.h>
#include "em_arith.h"
#include "em_label.h"
#include "../read_em/em_comp.h"
#include "em_pseu.h"
#include "em_flag.h"
#include "em_ptyp.h"
#include "em_private.h"

/* $Id$ */

static void arg(struct e_instr *p, int comma);
static void pseudo(struct e_instr *p);

extern char em_flag[];
char *C_error;

#define flags(pp)	(em_flag[(pp)->em_opcode - sp_fmnem] & EM_PAR)

struct e_instr *C_alloc(void)
{
	static struct e_instr b;

	return &b;
}

int C_out(register struct e_instr *p)
{
	/*	Generate EM-code from the e_instr structure "p"
	*/

	switch(p->em_type) {
	case EM_MNEM:
		OP(p->em_opcode);
		if (flags(p) == PAR_B && p->em_argtype == cst_ptyp) {
			p->em_ilb = p->em_cst;
			p->em_argtype = ilb_ptyp;
		}
		if (flags(p) != PAR_NO) arg(p, 0);
		NL();
		break;

	case EM_PSEU:
		pseudo(p);
		break;

	case EM_STARTMES:
		PS(ps_mes);
		CST(p->em_cst);
		break;

	case EM_MESARG:
		arg(p, 1);
		break;

	case EM_ENDMES:
		CEND();
		NL();
		break;

	case EM_DEFILB:
		DFILB(p->em_ilb);
		NL();
		break;

	case EM_DEFDLB:
		DFDLB(p->em_dlb);
		NL();
		break;

	case EM_DEFDNAM:
		DFDNAM(p->em_dnam);
		NL();
		break;
	default:
		C_error = "Illegal EM line";
		return 0;
	}
	return 1;
}

static void arg(register struct e_instr *p, int comma)
{
	/*	Output the argument of "p".
	*/

	if (comma) COMMA();

	switch(p->em_argtype) {
	case 0:
		if (p->em_type == EM_MNEM && flags(p) != PAR_W) {
			abort();
		}
		CCEND();
		break;

	case ilb_ptyp:
		if (p->em_type == EM_MNEM) {
			CILB(p->em_ilb);
		}
		else {
			ILB(p->em_ilb);
		}
		break;

	case nof_ptyp:
		DOFF(p->em_dlb, p->em_off);
		break;

	case sof_ptyp:
		NOFF(p->em_dnam, p->em_off);
		break;

	case cst_ptyp:
		CST(p->em_cst);
		break;

	case pro_ptyp:
		PNAM(p->em_pnam);
		break;

	case str_ptyp:
		SCON(p->em_string, p->em_size);
		break;

	case ico_ptyp:
		WCON(sp_icon, p->em_string, p->em_size);
		break;

	case uco_ptyp:
		WCON(sp_ucon, p->em_string, p->em_size);
		break;

	case fco_ptyp:
		WCON(sp_fcon, p->em_string, p->em_size);
		break;

	default:
		abort();
	}
}

static void pseudo(register struct e_instr *p)
{

	PS(p->em_opcode);

	switch(p->em_opcode) {
	case ps_exc:
		CST(p->em_exc1);
		COMMA();
		CST(p->em_exc2);
		break;

	case ps_rom:
	case ps_con:
		arg(p, 0);
		CEND();
		break;

	case ps_bss:
		CST(EM_bsssize);
		arg(p, 1);
		COMMA();
		CST((arith) EM_bssinit);
		break;

	case ps_hol:
		CST(EM_holsize);
		arg(p, 1);
		COMMA();
		CST((arith) EM_holinit);
		break;

	case ps_pro:
		arg(p, 0);
		COMMA();
		if (p->em_nlocals != -1) CST(p->em_nlocals);
		else	CCEND();
		break;

	case ps_end:
		if (p->em_argtype == 0) CCEND();
		else CST(p->em_cst);
		break;

	default:
		arg(p, 0);
		break;
	}

	NL();
}
