626 lines
12 KiB
C
626 lines
12 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "param.h"
|
|
#include "types.h"
|
|
#include "tes.h"
|
|
#include "line.h"
|
|
#include "lookup.h"
|
|
#include "alloc.h"
|
|
#include "proinf.h"
|
|
#include <em_spec.h>
|
|
#include <em_pseu.h>
|
|
#include <em_flag.h>
|
|
#include <em_mes.h>
|
|
#include "ext.h"
|
|
#include "reg.h"
|
|
#include "getline.h"
|
|
#include "util.h"
|
|
|
|
static short tabval; /* temp store for shorts */
|
|
static offset tabval2; /* temp store for offsets */
|
|
static char string[IDL + 1]; /* temp store for names */
|
|
|
|
/*
|
|
* The next constants are close to sp_cend for fast switches
|
|
*/
|
|
#define INST 256 /* instruction: number in tabval */
|
|
#define PSEU 257 /* pseudo: number in tabval */
|
|
#define ILBX 258 /* label: number in tabval */
|
|
#define DLBX 259 /* symbol: name in string[] */
|
|
#define CSTX1 260 /* short constant: stored in tabval */
|
|
#define CSTX2 261 /* offset: value in tabval2 */
|
|
#define VALX1 262 /* symbol+short: in string[] and tabval */
|
|
#define VALX2 263 /* symbol+offset: in string[] and tabval2 */
|
|
#define ATEOF 264 /* bumped into end of file */
|
|
|
|
#define readbyte getchar
|
|
|
|
/* Other external declarations */
|
|
extern void process(void);
|
|
|
|
/* Forward declarations */
|
|
static int table2(void);
|
|
|
|
static void tstinpro(void)
|
|
{
|
|
if (prodepth == 0)
|
|
error("This is not allowed outside a procedure");
|
|
}
|
|
|
|
short readshort(void)
|
|
{
|
|
register int l_byte, h_byte;
|
|
|
|
l_byte = readbyte();
|
|
h_byte = readbyte();
|
|
if (h_byte >= 128)
|
|
h_byte -= 256;
|
|
return l_byte | (h_byte * 256);
|
|
}
|
|
|
|
#ifdef LONGOFF
|
|
static offset readoffset(void)
|
|
{
|
|
register long l;
|
|
register int h_byte;
|
|
|
|
l = readbyte();
|
|
l |= ((unsigned) readbyte()) * 256;
|
|
l |= readbyte() * 256L * 256L;
|
|
h_byte = readbyte();
|
|
if (h_byte >= 128)
|
|
h_byte -= 256;
|
|
return l | (h_byte * 256L * 256 * 256L);
|
|
}
|
|
#endif
|
|
|
|
static void draininput(void)
|
|
{
|
|
/*
|
|
* called when MES ERR is encountered.
|
|
* Drain input in case it is a pipe.
|
|
*/
|
|
while (getchar() != EOF)
|
|
;
|
|
}
|
|
|
|
static short getint(void)
|
|
{
|
|
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("int expected");
|
|
case CSTX1:
|
|
return (tabval);
|
|
}
|
|
}
|
|
|
|
static sym_p getsym(int status)
|
|
{
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("symbol expected");
|
|
case DLBX:
|
|
return (symlookup(string, status, 0));
|
|
case sp_pnam:
|
|
return (symlookup(string, status, SYMPRO));
|
|
}
|
|
}
|
|
|
|
static offset getoff(void)
|
|
{
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("offset expected");
|
|
case CSTX1:
|
|
return ((offset) tabval);
|
|
#ifdef LONGOFF
|
|
case CSTX2:
|
|
return (tabval2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void make_string(int n)
|
|
{
|
|
sprintf(string, ".%u", n);
|
|
}
|
|
|
|
static void inident(void)
|
|
{
|
|
register int n;
|
|
register char *p = string;
|
|
register int c;
|
|
|
|
n = getint();
|
|
while (n--)
|
|
{
|
|
c = readbyte();
|
|
if (p < &string[IDL])
|
|
*p++ = c;
|
|
}
|
|
*p++ = 0;
|
|
}
|
|
|
|
static int table3(int n)
|
|
{
|
|
switch (n)
|
|
{
|
|
case sp_ilb1:
|
|
tabval = readbyte();
|
|
return (ILBX);
|
|
case sp_ilb2:
|
|
tabval = readshort();
|
|
return (ILBX);
|
|
case sp_dlb1:
|
|
make_string(readbyte());
|
|
return (DLBX);
|
|
case sp_dlb2:
|
|
make_string(readshort());
|
|
return (DLBX);
|
|
case sp_dnam:
|
|
inident();
|
|
return (DLBX);
|
|
case sp_pnam:
|
|
inident();
|
|
return (n);
|
|
case sp_cst2:
|
|
tabval = readshort();
|
|
return (CSTX1);
|
|
#ifdef LONGOFF
|
|
case sp_cst4:
|
|
tabval2 = readoffset();
|
|
return (CSTX2);
|
|
#endif
|
|
case sp_doff:
|
|
if (table2() != DLBX)
|
|
error("symbol expected");
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("offset expected");
|
|
case CSTX1:
|
|
return (VALX1);
|
|
#ifdef LONGOFF
|
|
case CSTX2:
|
|
return (VALX2);
|
|
#endif
|
|
}
|
|
default:
|
|
return (n);
|
|
}
|
|
}
|
|
|
|
static int table1(void)
|
|
{
|
|
register int n;
|
|
|
|
n = readbyte();
|
|
if (n == EOF)
|
|
return (ATEOF);
|
|
if ((n <= sp_lmnem) && (n >= sp_fmnem))
|
|
{
|
|
tabval = n;
|
|
return (INST);
|
|
}
|
|
if ((n <= sp_lpseu) && (n >= sp_fpseu))
|
|
{
|
|
tabval = n;
|
|
return (PSEU);
|
|
}
|
|
if ((n < sp_filb0 + sp_nilb0) && (n >= sp_filb0))
|
|
{
|
|
tabval = n - sp_filb0;
|
|
return (ILBX);
|
|
}
|
|
return (table3(n));
|
|
}
|
|
|
|
static int table2(void)
|
|
{
|
|
register int n;
|
|
|
|
n = readbyte();
|
|
if ((n < sp_fcst0 + sp_ncst0) && (n >= sp_fcst0))
|
|
{
|
|
tabval = n - sp_zcst0;
|
|
return (CSTX1);
|
|
}
|
|
return (table3(n));
|
|
}
|
|
|
|
static void argstring(offset length, register argb_p abp)
|
|
{
|
|
while (length--)
|
|
{
|
|
if (abp->ab_index == NARGBYTES)
|
|
abp = abp->ab_next = newargb();
|
|
abp->ab_contents[abp->ab_index++] = readbyte();
|
|
}
|
|
}
|
|
|
|
static line_p arglist(int n)
|
|
{
|
|
line_p lnp;
|
|
register arg_p ap, *app;
|
|
bool moretocome;
|
|
offset length;
|
|
|
|
/*
|
|
* creates an arglist with n elements
|
|
* if n == 0 the arglist is variable and terminated by sp_cend
|
|
*/
|
|
|
|
lnp = newline(OPLIST);
|
|
app = &lnp->l_a.la_arg;
|
|
moretocome = TRUE;
|
|
do
|
|
{
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("unknown byte in arglist");
|
|
case CSTX1:
|
|
tabval2 = (offset) tabval;
|
|
case CSTX2:
|
|
*app = ap = newarg(ARGOFF);
|
|
ap->a_a.a_offset = tabval2;
|
|
app = &ap->a_next;
|
|
break;
|
|
case ILBX:
|
|
tstinpro();
|
|
*app = ap = newarg(ARGNUM);
|
|
ap->a_a.a_np = numlookup((unsigned) tabval);
|
|
ap->a_a.a_np->n_flags |= NUMDATA;
|
|
app = &ap->a_next;
|
|
break;
|
|
case DLBX:
|
|
*app = ap = newarg(ARGSYM);
|
|
ap->a_a.a_sp = symlookup(string, OCCURRING, 0);
|
|
app = &ap->a_next;
|
|
break;
|
|
case sp_pnam:
|
|
*app = ap = newarg(ARGSYM);
|
|
ap->a_a.a_sp = symlookup(string, OCCURRING, SYMPRO);
|
|
app = &ap->a_next;
|
|
break;
|
|
case VALX1:
|
|
tabval2 = (offset) tabval;
|
|
case VALX2:
|
|
*app = ap = newarg(ARGVAL);
|
|
ap->a_a.a_val.av_sp = symlookup(string, OCCURRING, 0);
|
|
ap->a_a.a_val.av_offset = tabval2;
|
|
app = &ap->a_next;
|
|
break;
|
|
case sp_scon:
|
|
*app = ap = newarg(ARGSTR);
|
|
length = getoff();
|
|
argstring(length, &ap->a_a.a_string);
|
|
app = &ap->a_next;
|
|
break;
|
|
case sp_icon:
|
|
*app = ap = newarg(ARGICN);
|
|
goto casecon;
|
|
case sp_ucon:
|
|
*app = ap = newarg(ARGUCN);
|
|
goto casecon;
|
|
case sp_fcon:
|
|
*app = ap = newarg(ARGFCN);
|
|
casecon: length = getint();
|
|
ap->a_a.a_con.ac_length = (short) length;
|
|
argstring(getoff(), &ap->a_a.a_con.ac_con);
|
|
app = &ap->a_next;
|
|
break;
|
|
case sp_cend:
|
|
moretocome = FALSE;
|
|
}
|
|
if (n && (--n) == 0)
|
|
moretocome = FALSE;
|
|
} while (moretocome);
|
|
return (lnp);
|
|
}
|
|
|
|
offset aoff(register arg_p ap, int n)
|
|
{
|
|
|
|
while (n > 0)
|
|
{
|
|
if (ap != (arg_p) 0)
|
|
ap = ap->a_next;
|
|
n--;
|
|
}
|
|
if (ap == (arg_p) 0)
|
|
error("too few parameters");
|
|
if (ap->a_typ != ARGOFF)
|
|
error("offset expected");
|
|
return (ap->a_a.a_offset);
|
|
}
|
|
|
|
static int inpseudo(short n)
|
|
{
|
|
register line_p lnp, head, tail;
|
|
short n1, n2;
|
|
proinf savearea;
|
|
#ifdef PSEUBETWEEN
|
|
static int pcount = 0;
|
|
|
|
if (pcount++ >= PSEUBETWEEN && prodepth == 0)
|
|
{
|
|
process();
|
|
pcount = 0;
|
|
}
|
|
#endif
|
|
|
|
switch (n)
|
|
{
|
|
default:
|
|
error("unknown pseudo");
|
|
case ps_bss:
|
|
case ps_hol:
|
|
lnp = arglist(3);
|
|
break;
|
|
case ps_rom:
|
|
case ps_con:
|
|
lnp = arglist(0);
|
|
break;
|
|
case ps_ina:
|
|
case ps_inp:
|
|
case ps_exa:
|
|
case ps_exp:
|
|
lnp = newline(OPSYMBOL);
|
|
lnp->l_a.la_sp = getsym(NOTHING);
|
|
break;
|
|
case ps_exc:
|
|
n1 = getint();
|
|
n2 = getint();
|
|
if (n1 != 0 && n2 != 0)
|
|
{
|
|
tail = curpro.lastline;
|
|
while (--n2)
|
|
tail = tail->l_next;
|
|
head = tail;
|
|
while (n1--)
|
|
head = head->l_next;
|
|
lnp = tail->l_next;
|
|
tail->l_next = head->l_next;
|
|
head->l_next = curpro.lastline;
|
|
curpro.lastline = lnp;
|
|
}
|
|
lnp = newline(OPNO);
|
|
break;
|
|
case ps_mes:
|
|
lnp = arglist(0);
|
|
switch ((int) aoff(lnp->l_a.la_arg, 0))
|
|
{
|
|
case ms_err:
|
|
draininput();
|
|
exit(-1);
|
|
case ms_opt:
|
|
nflag = TRUE;
|
|
break;
|
|
case ms_emx:
|
|
wordsize = aoff(lnp->l_a.la_arg, 1);
|
|
pointersize = aoff(lnp->l_a.la_arg, 2);
|
|
#ifndef LONGOFF
|
|
if (wordsize>2)
|
|
error("This optimizer cannot handle wordsize>2");
|
|
#endif
|
|
break;
|
|
case ms_gto:
|
|
curpro.gtoproc = 1;
|
|
/* Treat as empty mes ms_reg */
|
|
case ms_reg:
|
|
tstinpro();
|
|
regvar(lnp->l_a.la_arg->a_next);
|
|
oldline(lnp);
|
|
lnp = newline(OPNO);
|
|
n = ps_exc; /* kludge to force out this line */
|
|
break;
|
|
case ms_tes:
|
|
tstinpro();
|
|
oldline(lnp);
|
|
lnp = newline(OPNO);
|
|
n = ps_exc; /* kludge to force out this line */
|
|
break;
|
|
}
|
|
break;
|
|
case ps_pro:
|
|
if (prodepth > 0)
|
|
savearea = curpro;
|
|
else
|
|
process();
|
|
curpro.symbol = getsym(DEFINING);
|
|
switch (table2())
|
|
{
|
|
case sp_cend:
|
|
curpro.localbytes = (offset) -1;
|
|
break;
|
|
case CSTX1:
|
|
tabval2 = (offset) tabval;
|
|
case CSTX2:
|
|
curpro.localbytes = tabval2;
|
|
break;
|
|
default:
|
|
error("bad second arg of PRO");
|
|
}
|
|
prodepth++;
|
|
curpro.gtoproc = 0;
|
|
if (prodepth > 1)
|
|
{
|
|
register int i;
|
|
|
|
curpro.lastline = (line_p) 0;
|
|
curpro.freg = (reg_p) 0;
|
|
for (i = 0; i < NNUMHASH; i++)
|
|
curpro.numhash[i] = (num_p) 0;
|
|
getlines();
|
|
curpro = savearea;
|
|
prodepth--;
|
|
}
|
|
return (0);
|
|
case ps_end:
|
|
if (prodepth == 0)
|
|
error("END misplaced");
|
|
switch (table2())
|
|
{
|
|
case sp_cend:
|
|
if (curpro.localbytes == (offset) -1)
|
|
error("bytes for locals still unknown");
|
|
break;
|
|
case CSTX1:
|
|
tabval2 = (offset) tabval;
|
|
case CSTX2:
|
|
if (curpro.localbytes != (offset) -1
|
|
&& curpro.localbytes != tabval2)
|
|
error("inconsistency in number of bytes for locals");
|
|
curpro.localbytes = tabval2;
|
|
break;
|
|
}
|
|
process();
|
|
curpro.symbol = (sym_p) 0;
|
|
if (prodepth == 1)
|
|
{
|
|
prodepth = 0;
|
|
#ifdef PSEUBETWEEN
|
|
pcount = 0;
|
|
#endif
|
|
return (0);
|
|
}
|
|
else
|
|
return (1);
|
|
}
|
|
lnp->l_instr = n;
|
|
lnp->l_next = curpro.lastline;
|
|
curpro.lastline = lnp;
|
|
return (0);
|
|
}
|
|
|
|
void getlines(void)
|
|
{
|
|
register line_p lnp;
|
|
register int instr;
|
|
|
|
for (;;)
|
|
{
|
|
linecount++;
|
|
switch (table1())
|
|
{
|
|
default:
|
|
error("unknown instruction byte");
|
|
/* NOTREACHED */
|
|
|
|
case ATEOF:
|
|
if (prodepth != 0)
|
|
error("procedure unterminated at eof");
|
|
process();
|
|
return;
|
|
case INST:
|
|
tstinpro();
|
|
instr = tabval;
|
|
break;
|
|
case DLBX:
|
|
lnp = newline(OPSYMBOL);
|
|
lnp->l_instr = ps_sym;
|
|
lnp->l_a.la_sp = symlookup(string, DEFINING, 0);
|
|
lnp->l_next = curpro.lastline;
|
|
curpro.lastline = lnp;
|
|
continue;
|
|
case ILBX:
|
|
tstinpro();
|
|
lnp = newline(OPNUMLAB);
|
|
lnp->l_instr = op_lab;
|
|
lnp->l_a.la_np = numlookup((unsigned) tabval);
|
|
if (lnp->l_a.la_np->n_line != (line_p) 0)
|
|
error("label %u multiple defined", (unsigned) tabval);
|
|
lnp->l_a.la_np->n_line = lnp;
|
|
lnp->l_next = curpro.lastline;
|
|
curpro.lastline = lnp;
|
|
continue;
|
|
case PSEU:
|
|
if (inpseudo(tabval))
|
|
return;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Now we have an instruction number in instr
|
|
* There might be an operand, look for it
|
|
*/
|
|
|
|
if ((em_flag[instr - sp_fmnem] & EM_PAR) == PAR_NO)
|
|
{
|
|
lnp = newline(OPNO);
|
|
}
|
|
else
|
|
switch (table2())
|
|
{
|
|
default:
|
|
error("unknown offset byte");
|
|
case sp_cend:
|
|
lnp = newline(OPNO);
|
|
break;
|
|
case CSTX1:
|
|
if ((em_flag[instr - sp_fmnem] & EM_PAR) != PAR_B)
|
|
{
|
|
if (CANMINI(tabval))
|
|
lnp = newline(tabval + Z_OPMINI);
|
|
else
|
|
{
|
|
lnp = newline(OPSHORT);
|
|
lnp->l_a.la_short = tabval;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lnp = newline(OPNUMLAB);
|
|
lnp->l_a.la_np = numlookup((unsigned) tabval);
|
|
}
|
|
break;
|
|
#ifdef LONGOFF
|
|
case CSTX2:
|
|
lnp = newline(OPOFFSET);
|
|
lnp->l_a.la_offset = tabval2;
|
|
break;
|
|
#endif
|
|
case ILBX:
|
|
tstinpro();
|
|
lnp = newline(OPNUMLAB);
|
|
lnp->l_a.la_np = numlookup((unsigned) tabval);
|
|
break;
|
|
case DLBX:
|
|
lnp = newline(OPSYMBOL);
|
|
lnp->l_a.la_sp = symlookup(string, OCCURRING, 0);
|
|
break;
|
|
case sp_pnam:
|
|
lnp = newline(OPSYMBOL);
|
|
lnp->l_a.la_sp = symlookup(string, OCCURRING, SYMPRO);
|
|
break;
|
|
case VALX1:
|
|
lnp = newline(OPSVAL);
|
|
lnp->l_a.la_sval.lasv_sp = symlookup(string, OCCURRING, 0);
|
|
lnp->l_a.la_sval.lasv_short = tabval;
|
|
break;
|
|
#ifdef LONGOFF
|
|
case VALX2:
|
|
lnp = newline(OPLVAL);
|
|
lnp->l_a.la_lval.lalv_sp = symlookup(string, OCCURRING, 0);
|
|
lnp->l_a.la_lval.lalv_offset = tabval2;
|
|
break;
|
|
#endif
|
|
}
|
|
lnp->l_instr = instr;
|
|
lnp->l_next = curpro.lastline;
|
|
curpro.lastline = lnp;
|
|
}
|
|
}
|
|
|