ack/util/opt/putline.c

414 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++);
}
}