413 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			413 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  *
 | |
|  * Author: Hans van Staveren
 | |
|  */
 | |
| #include <assert.h>
 | |
| #include <stdlib.h>
 | |
| #include "param.h"
 | |
| #include "types.h"
 | |
| #include "tes.h"
 | |
| #include <em_spec.h>
 | |
| #include <em_pseu.h>
 | |
| #include <em_mnem.h>
 | |
| #include <em_flag.h>
 | |
| #include "alloc.h"
 | |
| #include "line.h"
 | |
| #include "putline.h"
 | |
| #include "util.h"
 | |
| #include "lookup.h"
 | |
| #include "proinf.h"
 | |
| #include "optim.h"
 | |
| #include "ext.h"
 | |
| 
 | |
| #define outbyte(b) putc(b,outfile)
 | |
| 
 | |
| /* Forward declarations. */
 | |
| static void numlab(register num_p);
 | |
| static void putargs(register arg_p);
 | |
| static void putstr(register argb_p);
 | |
| 
 | |
| void putlines(register line_p lnp)
 | |
| {
 | |
| 	register arg_p ap;
 | |
| 	line_p temp;
 | |
| 	register int instr;
 | |
| 	short curlin = -2;
 | |
| 	short thislin;
 | |
| 
 | |
| 	while (lnp != (line_p) 0)
 | |
| 	{
 | |
| 		instr = lnp->l_instr & BMASK;
 | |
| 		switch (lnp->l_optyp)
 | |
| 		{
 | |
| 			case OPSYMBOL:
 | |
| 				if ((lnp->l_instr & BMASK) == ps_sym)
 | |
| 					outdef(lnp->l_a.la_sp);
 | |
| 				else
 | |
| 					outocc(lnp->l_a.la_sp);
 | |
| 				break;
 | |
| 			case OPSVAL:
 | |
| 				outocc(lnp->l_a.la_sval.lasv_sp);
 | |
| 				break;
 | |
| #ifdef LONGOFF
 | |
| 			case OPLVAL:
 | |
| 				outocc(lnp->l_a.la_lval.lalv_sp);
 | |
| 				break;
 | |
| #endif
 | |
| 			case OPLIST:
 | |
| 				ap = lnp->l_a.la_arg;
 | |
| 				while (ap != (arg_p) 0)
 | |
| 				{
 | |
| 					switch (ap->a_typ)
 | |
| 					{
 | |
| 						case ARGSYM:
 | |
| 							outocc(ap->a_a.a_sp);
 | |
| 							break;
 | |
| 						case ARGVAL:
 | |
| 							outocc(ap->a_a.a_val.av_sp);
 | |
| 							break;
 | |
| 					}
 | |
| 					ap = ap->a_next;
 | |
| 				}
 | |
| 				break;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * global symbols now taken care of
 | |
| 		 */
 | |
| 
 | |
| 		switch (instr)
 | |
| 		{
 | |
| 			case ps_sym:
 | |
| 				break;
 | |
| 			case op_lni:
 | |
| 				if (curlin != -2)
 | |
| 					curlin++;
 | |
| 				outinst(instr);
 | |
| 				break;
 | |
| 			case op_lin:
 | |
| 				switch (lnp->l_optyp)
 | |
| 				{
 | |
| 					case OPNO:
 | |
| 					case OPOFFSET:
 | |
| 					case OPNUMLAB:
 | |
| 					case OPSYMBOL:
 | |
| 					case OPSVAL:
 | |
| 					case OPLVAL:
 | |
| 					case OPLIST:
 | |
| 						outinst(instr);
 | |
| 						goto processoperand;
 | |
| 					case OPSHORT:
 | |
| 						thislin = lnp->l_a.la_short;
 | |
| 						break;
 | |
| 					default:
 | |
| 						thislin = (lnp->l_optyp & BMASK) - Z_OPMINI;
 | |
| 						break;
 | |
| 				}
 | |
| 				if (thislin == curlin && !nflag)
 | |
| 				{
 | |
| 					temp = lnp->l_next;
 | |
| 					oldline(lnp);
 | |
| 					lnp = temp;
 | |
| 					OPTIM(O_LINGONE);
 | |
| 					continue;
 | |
| 				}
 | |
| 				else if (thislin == curlin + 1 && !nflag)
 | |
| 				{
 | |
| 					instr = op_lni;
 | |
| 					outinst(instr);
 | |
| 					temp = lnp->l_next;
 | |
| 					oldline(lnp);
 | |
| 					OPTIM(O_LINLNI);
 | |
| 					lnp = newline(OPNO);
 | |
| 					lnp->l_next = temp;
 | |
| 					lnp->l_instr = instr;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					outinst(instr);
 | |
| 				}
 | |
| 				curlin = thislin;
 | |
| 				break;
 | |
| 			case op_lab:
 | |
| 				curlin = -2;
 | |
| 				break;
 | |
| 			default:
 | |
| 				if ((em_flag[instr - sp_fmnem] & EM_FLO) == FLO_P)
 | |
| 					curlin = -2;
 | |
| 				outinst(instr);
 | |
| 		}
 | |
| 		processoperand: switch (lnp->l_optyp)
 | |
| 		{
 | |
| 			case OPNO:
 | |
| 				if ((em_flag[instr - sp_fmnem] & EM_PAR) != PAR_NO)
 | |
| 					outbyte((byte) sp_cend);
 | |
| 				break;
 | |
| 			default:
 | |
| 				outint((lnp->l_optyp & BMASK) - Z_OPMINI);
 | |
| 				break;
 | |
| 			case OPSHORT:
 | |
| 				outint(lnp->l_a.la_short);
 | |
| 				break;
 | |
| #ifdef LONGOFF
 | |
| 			case OPOFFSET:
 | |
| 				outoff(lnp->l_a.la_offset);
 | |
| 				break;
 | |
| #endif
 | |
| 			case OPNUMLAB:
 | |
| 				if (instr == op_lab)
 | |
| 					numlab(lnp->l_a.la_np->n_repl);
 | |
| 				else if (instr < sp_fpseu) /* plain instruction */
 | |
| 					outint((short) lnp->l_a.la_np->n_repl->n_number);
 | |
| 				else
 | |
| 					outnum(lnp->l_a.la_np->n_repl);
 | |
| 				break;
 | |
| 			case OPSYMBOL:
 | |
| 				outsym(lnp->l_a.la_sp);
 | |
| 				break;
 | |
| 			case OPSVAL:
 | |
| 				outbyte((byte) sp_doff);
 | |
| 				outsym(lnp->l_a.la_sval.lasv_sp);
 | |
| 				outint(lnp->l_a.la_sval.lasv_short);
 | |
| 				break;
 | |
| #ifdef LONGOFF
 | |
| 			case OPLVAL:
 | |
| 				outbyte((byte) sp_doff);
 | |
| 				outsym(lnp->l_a.la_lval.lalv_sp);
 | |
| 				outoff(lnp->l_a.la_lval.lalv_offset);
 | |
| 				break;
 | |
| #endif
 | |
| 			case OPLIST:
 | |
| 				putargs(lnp->l_a.la_arg);
 | |
| 				switch (instr)
 | |
| 				{
 | |
| 					case ps_con:
 | |
| 					case ps_rom:
 | |
| 					case ps_mes:
 | |
| 						outbyte((byte) sp_cend);
 | |
| 				}
 | |
| 		}
 | |
| 		/*
 | |
| 		 * instruction is output now.
 | |
| 		 * remove its useless body
 | |
| 		 */
 | |
| 
 | |
| 		temp = lnp->l_next;
 | |
| 		oldline(lnp);
 | |
| 		lnp = temp;
 | |
| 		if (ferror(outfile))
 | |
| 			error("write error");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void putargs(register arg_p ap)
 | |
| {
 | |
| 
 | |
| 	while (ap != (arg_p) 0)
 | |
| 	{
 | |
| 		switch (ap->a_typ)
 | |
| 		{
 | |
| 			default:
 | |
| 				assert(FALSE);
 | |
| 				break;
 | |
| 			case ARGOFF:
 | |
| 				outoff(ap->a_a.a_offset);
 | |
| 				break;
 | |
| 			case ARGNUM:
 | |
| 				outnum(ap->a_a.a_np->n_repl);
 | |
| 				break;
 | |
| 			case ARGSYM:
 | |
| 				outsym(ap->a_a.a_sp);
 | |
| 				break;
 | |
| 			case ARGVAL:
 | |
| 				outbyte((byte) sp_doff);
 | |
| 				outsym(ap->a_a.a_val.av_sp);
 | |
| 				outoff(ap->a_a.a_val.av_offset);
 | |
| 				break;
 | |
| 			case ARGSTR:
 | |
| 				outbyte((byte) sp_scon);
 | |
| 				putstr(&ap->a_a.a_string);
 | |
| 				break;
 | |
| 			case ARGICN:
 | |
| 				outbyte((byte) sp_icon);
 | |
| 				goto casecon;
 | |
| 			case ARGUCN:
 | |
| 				outbyte((byte) sp_ucon);
 | |
| 				goto casecon;
 | |
| 			case ARGFCN:
 | |
| 				outbyte((byte) sp_fcon);
 | |
| 				casecon: outint(ap->a_a.a_con.ac_length);
 | |
| 				putstr(&ap->a_a.a_con.ac_con);
 | |
| 				break;
 | |
| 		}
 | |
| 		ap = ap->a_next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void putstr(register argb_p abp)
 | |
| {
 | |
| 	register argb_p tbp;
 | |
| 	register int length;
 | |
| 
 | |
| 	length = 0;
 | |
| 	tbp = abp;
 | |
| 	while (tbp != (argb_p) 0)
 | |
| 	{
 | |
| 		length += tbp->ab_index;
 | |
| 		tbp = tbp->ab_next;
 | |
| 	}
 | |
| 	outint(length);
 | |
| 	while (abp != (argb_p) 0)
 | |
| 	{
 | |
| 		for (length = 0; length < abp->ab_index; length++)
 | |
| 			outbyte((byte ) abp->ab_contents[length]);
 | |
| 		abp = abp->ab_next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void outdef(register sym_p sp)
 | |
| {
 | |
| 
 | |
| 	/*
 | |
| 	 * The surrounding If statement is removed to be friendly
 | |
| 	 * to Backend writers having to deal with assemblers
 | |
| 	 * not following our conventions.
 | |
| 	 if ((sp->s_flags&SYMOUT)==0) {
 | |
| 	 */
 | |
| 	sp->s_flags |= SYMOUT;
 | |
| 	if (sp->s_flags & SYMGLOBAL)
 | |
| 	{
 | |
| 		outinst(sp->s_flags & SYMPRO ? ps_exp : ps_exa);
 | |
| 		outsym(sp);
 | |
| 	}
 | |
| 	/*
 | |
| 	 }
 | |
| 	 */
 | |
| }
 | |
| 
 | |
| void outocc(register sym_p sp)
 | |
| {
 | |
| 
 | |
| 	if ((sp->s_flags & SYMOUT) == 0)
 | |
| 	{
 | |
| 		sp->s_flags |= SYMOUT;
 | |
| 		if ((sp->s_flags & SYMGLOBAL) == 0)
 | |
| 		{
 | |
| 			outinst(sp->s_flags & SYMPRO ? ps_inp : ps_ina);
 | |
| 			outsym(sp);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void outpro(void)
 | |
| {
 | |
| 	outdef(curpro.symbol);
 | |
| 	outinst(ps_pro);
 | |
| 	outsym(curpro.symbol);
 | |
| 	outoff(curpro.localbytes);
 | |
| }
 | |
| 
 | |
| void outend(void)
 | |
| {
 | |
| 	outinst(ps_end);
 | |
| 	outoff(curpro.localbytes);
 | |
| }
 | |
| 
 | |
| void outinst(int m)
 | |
| {
 | |
| 	outbyte((byte ) m);
 | |
| }
 | |
| 
 | |
| void outoff(offset off)
 | |
| {
 | |
| #ifdef LONGOFF
 | |
| 	if ((short) off == off)
 | |
| #endif
 | |
| 		outint((short) off);
 | |
| #ifdef LONGOFF
 | |
| 	else
 | |
| 	{
 | |
| 		outbyte((byte) sp_cst4);
 | |
| 		outshort((short) (off & 0177777L));
 | |
| 		outshort((short) (off >> 16));
 | |
| 	}
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void outint(short i)
 | |
| {
 | |
| 
 | |
| 	if (i >= -sp_zcst0 && i < sp_ncst0 - sp_zcst0)
 | |
| 		outbyte((byte) (i+sp_zcst0+sp_fcst0));
 | |
| 	else
 | |
| 	{
 | |
| 		outbyte((byte) sp_cst2);
 | |
| 		outshort(i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void outshort(short i)
 | |
| {
 | |
| 	outbyte((byte) (i&BMASK));
 | |
| 	outbyte((byte ) (i >> 8));
 | |
| }
 | |
| 
 | |
| static void numlab(register num_p np)
 | |
| {
 | |
| 	if (np->n_number < sp_nilb0)
 | |
| 		outbyte((byte) (np->n_number + sp_filb0));
 | |
| 	else
 | |
| 		outnum(np);
 | |
| }
 | |
| 
 | |
| void outnum(register num_p np)
 | |
| {
 | |
| 	if (np->n_number < 256)
 | |
| 	{
 | |
| 		outbyte((byte) sp_ilb1);
 | |
| 		outbyte((byte ) (np->n_number));
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		outbyte((byte) sp_ilb2);
 | |
| 		outshort((short) np->n_number);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void outsym(register sym_p sp)
 | |
| {
 | |
| 	register char *p;
 | |
| 	register unsigned num;
 | |
| 
 | |
| 	if (sp->s_name[0] == '.')
 | |
| 	{
 | |
| 		num = atoi(&sp->s_name[1]);
 | |
| 		if (num < 256)
 | |
| 		{
 | |
| 			outbyte((byte) sp_dlb1);
 | |
| 			outbyte((byte ) (num));
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			outbyte((byte) sp_dlb2);
 | |
| 			outshort((short) num);
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		p = sp->s_name;
 | |
| 		/* This is not a real warning, because s_name is dynamically
 | |
| 		 * allocated as necessary.
 | |
| 		 */
 | |
| 		while (*p && p < &sp->s_name[IDL])
 | |
| 			p++;
 | |
| 		num = p - sp->s_name;
 | |
| 		outbyte((byte) (sp->s_flags&SYMPRO ? sp_pnam : sp_dnam));
 | |
| 		outint((short) num);
 | |
| 		p = sp->s_name;
 | |
| 		while (num--)
 | |
| 			outbyte((byte ) *p++);
 | |
| 	}
 | |
| }
 |