753 lines
14 KiB
C
753 lines
14 KiB
C
#ifndef NORCSID
|
|
static char rcsid2[] = "$Id$";
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <em_spec.h>
|
|
#include <em_pseu.h>
|
|
#include <em_flag.h>
|
|
#include <em_ptyp.h>
|
|
#include <em_mes.h>
|
|
#include "mach.h"
|
|
#include "param.h"
|
|
#include "tables.h"
|
|
#include "types.h"
|
|
#include <cgg_cg.h>
|
|
#include "data.h"
|
|
#include "glosym.h"
|
|
#include "result.h"
|
|
#ifdef REGVARS
|
|
#include "regvar.h"
|
|
#include <em_reg.h>
|
|
#endif
|
|
#include "extern.h"
|
|
|
|
/*
|
|
* (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
|
|
*/
|
|
|
|
#ifndef newplb /* retrofit for older mach.h */
|
|
#define newplb newilb
|
|
#endif
|
|
|
|
#ifdef fmt_id
|
|
#ifdef id_first
|
|
It is an error to define both fmt_id and id_first.
|
|
Read the documentation.
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef fmt_ilb
|
|
#ifdef ilb_fmt
|
|
It is an error to define both fmt_ilb and ilb_fmt.
|
|
Read the documentation.
|
|
#endif
|
|
#endif
|
|
|
|
/* segment types for switchseg() */
|
|
#define SEGTXT 0
|
|
#define SEGCON 1
|
|
#define SEGROM 2
|
|
#define SEGBSS 3
|
|
|
|
#define get8() getc(emfile)
|
|
|
|
static FILE *emfile;
|
|
|
|
static int nextispseu,savetab1;
|
|
static int opcode;
|
|
static int offtyp;
|
|
static long argval;
|
|
static int dlbval;
|
|
static char *str,argstr[128],labstr[128];
|
|
static unsigned int maxstrsiz;
|
|
static int strsiz;
|
|
static int holno=0;
|
|
static int procno=0;
|
|
static int curseg= -1;
|
|
static int part_size=0;
|
|
static word part_word=0;
|
|
#ifdef REGVARS
|
|
static int regallowed=0;
|
|
#endif
|
|
|
|
extern char em_flag[];
|
|
extern short em_ptyp[];
|
|
|
|
/* machine dependent */
|
|
void con_part(int, word);
|
|
void con_mult(word);
|
|
void con_float(void); /* actually returns void, but need K&R C compatibility */
|
|
void prolog(full nlocals);
|
|
void mes(word);
|
|
|
|
static int getarg(int);
|
|
static int table1(void);
|
|
static int table2(void);
|
|
static int table3(int);
|
|
static int get16(void);
|
|
static long get32(void);
|
|
static void getstring(void);
|
|
static string strarg(int);
|
|
static void bss(full, int, int);
|
|
static long con(int);
|
|
static void switchseg(int);
|
|
static void savelab(void);
|
|
static void dumplab(void);
|
|
static void xdumplab(void);
|
|
static void part_flush(void);
|
|
static string holstr(word);
|
|
|
|
/* Own version of atol that continues computing on overflow.
|
|
We don't know that about the ANSI C one.
|
|
*/
|
|
static long our_atol(char *s) {
|
|
long total = 0;
|
|
unsigned digit;
|
|
int minus = 0;
|
|
|
|
while (*s == ' ' || *s == '\t') s++;
|
|
if (*s == '+') s++;
|
|
else if (*s == '-') {
|
|
s++;
|
|
minus = 1;
|
|
}
|
|
while ((digit = *s++ - '0') < 10) {
|
|
total *= 10;
|
|
total += digit;
|
|
}
|
|
return(minus ? -total : total);
|
|
}
|
|
|
|
|
|
#define sp_cstx sp_cst2
|
|
|
|
void in_init(char *filename) {
|
|
|
|
emfile = stdin;
|
|
if (filename && (emfile=freopen(filename,"r",stdin))==NULL)
|
|
error("Can't open %s",filename);
|
|
if (get16()!=sp_magic)
|
|
error("Bad format %s",filename ? filename : "standard-input");
|
|
str = myalloc(maxstrsiz=256);
|
|
}
|
|
|
|
void in_start(void) {
|
|
#ifdef modhead
|
|
fprintf(codefile,"%s",modhead) ;
|
|
#endif
|
|
}
|
|
|
|
static void in_finish(void) {
|
|
}
|
|
|
|
void fillemlines(void) {
|
|
int t,i;
|
|
struct emline *lp;
|
|
|
|
while ((emlines+nemlines)-emp<MAXEMLINES-5) {
|
|
assert(nemlines<MAXEMLINES);
|
|
if (nextispseu) {
|
|
emlines[nemlines].em_instr=0;
|
|
return;
|
|
}
|
|
lp = &emlines[nemlines++];
|
|
|
|
switch(t=table1()) {
|
|
default:
|
|
error("unknown instruction byte");
|
|
case sp_ilb1:
|
|
case sp_ilb2:
|
|
#ifdef USE_TES
|
|
lp->em_instr = op_lab;
|
|
lp->em_optyp = OPSYMBOL;
|
|
lp->em_soper = strarg(t);
|
|
lp->em_u.em_loper = argval;
|
|
return;
|
|
#endif
|
|
case sp_fpseu:
|
|
case sp_dlb1:
|
|
case sp_dlb2:
|
|
case sp_dnam:
|
|
nextispseu=1; savetab1=t;
|
|
nemlines--;
|
|
lp->em_instr = 0;
|
|
return;
|
|
case EOF:
|
|
nextispseu=1; savetab1=t;
|
|
nemlines--;
|
|
lp->em_instr = 0;
|
|
return;
|
|
case sp_fmnem:
|
|
lp->em_instr = opcode;
|
|
break;
|
|
}
|
|
i=em_flag[lp->em_instr-sp_fmnem] & EM_PAR;
|
|
if ( i == PAR_NO ) {
|
|
lp->em_optyp = OPNO;
|
|
lp->em_soper = 0;
|
|
continue;
|
|
}
|
|
t= em_ptyp[i];
|
|
t= getarg(t);
|
|
switch(i) {
|
|
case PAR_L:
|
|
assert(t == sp_cstx);
|
|
if (argval >= 0)
|
|
argval += TEM_BSIZE;
|
|
lp->em_optyp = OPINT;
|
|
lp->em_u.em_ioper = argval;
|
|
lp->em_soper = tostring((word) argval);
|
|
continue;
|
|
case PAR_G:
|
|
if (t != sp_cstx)
|
|
break;
|
|
lp->em_optyp = OPSYMBOL;
|
|
lp->em_soper = holstr((word) argval);
|
|
continue;
|
|
case PAR_B:
|
|
t = sp_ilb2;
|
|
#ifdef USE_TES
|
|
lp->em_optyp = OPSYMBOL;
|
|
lp->em_u.em_loper = argval;
|
|
lp->em_soper = strarg(t);
|
|
#endif
|
|
break;
|
|
case PAR_D:
|
|
assert(t == sp_cstx);
|
|
lp->em_optyp = OPSYMBOL;
|
|
lp->em_soper = strarg(t);
|
|
lp->em_u.em_loper = argval;
|
|
continue;
|
|
}
|
|
lp->em_soper = strarg(t);
|
|
if (t==sp_cend)
|
|
lp->em_optyp = OPNO;
|
|
else if (t==sp_cstx) {
|
|
lp->em_optyp = OPINT;
|
|
lp->em_u.em_ioper = argval;
|
|
} else
|
|
lp->em_optyp = OPSYMBOL;
|
|
}
|
|
}
|
|
|
|
void
|
|
dopseudo() {
|
|
int b,t;
|
|
full n;
|
|
long save;
|
|
word romcont[MAXROM+1];
|
|
int nromwords;
|
|
int rombit,rommask;
|
|
|
|
if (nextispseu==0 || nemlines>0)
|
|
error("No table entry for %d",emlines[0].em_instr);
|
|
nextispseu=0;
|
|
switch (savetab1) {
|
|
#ifndef USE_TES
|
|
case sp_ilb1:
|
|
case sp_ilb2:
|
|
swtxt();
|
|
/* dummy = */stackupto(&fakestack[stackheight-1],maxply,TRUE);
|
|
cleanregs();
|
|
strarg(savetab1);
|
|
newilb(argstr);
|
|
#ifndef NDEBUG
|
|
{ extern int Debug; extern char * strtdebug;
|
|
if (strcmp(strtdebug,argstr)==0)
|
|
Debug = strtdebug[-2]-'0';
|
|
}
|
|
#endif
|
|
return;
|
|
#endif
|
|
case sp_dlb1:
|
|
case sp_dlb2:
|
|
case sp_dnam:
|
|
strarg(savetab1);
|
|
savelab();
|
|
return;
|
|
case sp_fpseu:
|
|
break;
|
|
case EOF:
|
|
swtxt();
|
|
in_finish();
|
|
out_finish();
|
|
popstr(0);
|
|
tstoutput();
|
|
exit(0);
|
|
default:
|
|
error("Unknown opcode %d",savetab1);
|
|
}
|
|
switch (opcode) {
|
|
case ps_hol:
|
|
sprintf(labstr,hol_fmt,++holno);
|
|
case ps_bss:
|
|
getarg(cst_ptyp);
|
|
n = (full) argval;
|
|
t = getarg(val_ptyp);
|
|
save = argval;
|
|
getarg(cst_ptyp);
|
|
b = (int) argval;
|
|
argval = save;
|
|
bss(n,t,b);
|
|
break;
|
|
case ps_con:
|
|
switchseg(SEGCON);
|
|
dumplab();
|
|
con(getarg(val_ptyp));
|
|
while ((t = getarg(any_ptyp)) != sp_cend)
|
|
con(t);
|
|
break;
|
|
case ps_rom:
|
|
switchseg(SEGROM);
|
|
xdumplab();
|
|
nromwords=0;
|
|
rommask=0;
|
|
rombit=1;
|
|
for (;;) {
|
|
t=getarg(val_ptyp);
|
|
while (t!=sp_cend) {
|
|
if (t==sp_cstx && nromwords<MAXROM) {
|
|
romcont[nromwords] = (word) argval;
|
|
rommask |= rombit;
|
|
}
|
|
nromwords++;
|
|
rombit <<= 1;
|
|
con(t);
|
|
t=getarg(any_ptyp);
|
|
}
|
|
{
|
|
int c = get8();
|
|
|
|
if (c == ps_rom) continue;
|
|
if (c != EOF) ungetc(c, emfile);
|
|
}
|
|
break;
|
|
}
|
|
if (nromwords != 0) {
|
|
romcont[MAXROM]=rommask;
|
|
enterglo(labstr,romcont);
|
|
}
|
|
labstr[0]=0;
|
|
break;
|
|
case ps_mes:
|
|
getarg(ptyp(sp_cst2));
|
|
if (argval == ms_emx) {
|
|
getarg(ptyp(sp_cst2));
|
|
if (argval != TEM_WSIZE)
|
|
fatal("bad word size");
|
|
getarg(ptyp(sp_cst2));
|
|
if (argval != TEM_PSIZE)
|
|
fatal("bad pointer size");
|
|
if ( getarg(any_ptyp)!=sp_cend )
|
|
fatal("too many parameters");
|
|
#ifdef USE_TES
|
|
} else if (argval == ms_tes) {
|
|
int lbl, size, flthr;
|
|
getarg(ptyp(sp_cst2)); lbl = argval;
|
|
getarg(ptyp(sp_cst2)); size = argval;
|
|
getarg(ptyp(sp_cst2)); flthr = argval;
|
|
if ( getarg(any_ptyp)!=sp_cend )
|
|
fatal("too many parameters");
|
|
add_label(lbl,size, flthr);
|
|
#endif
|
|
#ifdef REGVARS
|
|
} else if (argval == ms_gto) {
|
|
getarg(ptyp(sp_cend));
|
|
if (!regallowed)
|
|
error("mes 3 not allowed here");
|
|
fixregvars(TRUE);
|
|
regallowed=0;
|
|
} else if (argval == ms_reg) {
|
|
long r_off;
|
|
int r_size,r_type,r_score;
|
|
|
|
if (!regallowed)
|
|
error("mes 3 not allowed here");
|
|
if(getarg(ptyp(sp_cst2)|ptyp(sp_cend)) == sp_cend) {
|
|
fixregvars(FALSE);
|
|
regallowed=0;
|
|
} else {
|
|
r_off = argval;
|
|
if (r_off >= 0)
|
|
r_off += TEM_BSIZE;
|
|
getarg(ptyp(sp_cst2));
|
|
r_size = argval;
|
|
getarg(ptyp(sp_cst2));
|
|
r_type = argval;
|
|
if (r_type<reg_any || r_type>reg_float)
|
|
fatal("Bad type in register message");
|
|
if(getarg(ptyp(sp_cst2)|ptyp(sp_cend)) == sp_cend)
|
|
r_score = 0;
|
|
else {
|
|
r_score = argval;
|
|
if ( getarg(any_ptyp)!=sp_cend )
|
|
fatal("too many parameters");
|
|
}
|
|
tryreg(linkreg(r_off,r_size,r_type,r_score),r_type);
|
|
}
|
|
#endif
|
|
} else
|
|
mes((word)argval);
|
|
break;
|
|
case ps_exa:
|
|
strarg(getarg(sym_ptyp));
|
|
ex_ap(argstr);
|
|
break;
|
|
case ps_ina:
|
|
strarg(getarg(sym_ptyp));
|
|
in_ap(argstr);
|
|
break;
|
|
case ps_exp:
|
|
strarg(getarg(ptyp(sp_pnam)));
|
|
ex_ap(argstr);
|
|
break;
|
|
case ps_inp:
|
|
strarg(getarg(ptyp(sp_pnam)));
|
|
in_ap(argstr);
|
|
break;
|
|
case ps_pro:
|
|
switchseg(SEGTXT);
|
|
procno++;
|
|
strarg(getarg(ptyp(sp_pnam)));
|
|
newplb(argstr);
|
|
getarg(cst_ptyp);
|
|
prolog((full)argval);
|
|
#ifdef REGVARS
|
|
regallowed++;
|
|
#endif
|
|
break;
|
|
case ps_end:
|
|
getarg(cst_ptyp | ptyp(sp_cend));
|
|
#ifdef USE_TES
|
|
kill_labels();
|
|
#endif
|
|
cleanregs();
|
|
#ifdef REGVARS
|
|
unlinkregs();
|
|
#endif
|
|
tstoutput();
|
|
break;
|
|
default:
|
|
error("No table entry for %d",savetab1);
|
|
}
|
|
}
|
|
|
|
/* ----- input ----- */
|
|
|
|
static int getarg(int typset) {
|
|
int t,argtyp;
|
|
|
|
argtyp = t = table2();
|
|
if (t == EOF)
|
|
fatal("unexpected EOF");
|
|
t -= sp_fspec;
|
|
t = 1 << t;
|
|
if ((typset & t) == 0)
|
|
error("bad argument type %d",argtyp);
|
|
return(argtyp);
|
|
}
|
|
|
|
static int table1(void) {
|
|
int i;
|
|
|
|
i = get8();
|
|
if (i < sp_fmnem+sp_nmnem && i >= sp_fmnem) {
|
|
opcode = i;
|
|
return(sp_fmnem);
|
|
}
|
|
if (i < sp_fpseu+sp_npseu && i >= sp_fpseu) {
|
|
opcode = i;
|
|
return(sp_fpseu);
|
|
}
|
|
if (i < sp_filb0+sp_nilb0 && i >= sp_filb0) {
|
|
argval = i - sp_filb0;
|
|
return(sp_ilb2);
|
|
}
|
|
return(table3(i));
|
|
}
|
|
|
|
static int table2(void) {
|
|
int i;
|
|
|
|
i = get8();
|
|
if (i < sp_fcst0+sp_ncst0 && i >= sp_fcst0) {
|
|
argval = i - sp_zcst0;
|
|
return(sp_cstx);
|
|
}
|
|
return(table3(i));
|
|
}
|
|
|
|
static int table3(int i) {
|
|
word consiz;
|
|
|
|
switch(i) {
|
|
case sp_ilb1:
|
|
argval = get8();
|
|
break;
|
|
case sp_dlb1:
|
|
dlbval = get8();
|
|
break;
|
|
case sp_dlb2:
|
|
dlbval = get16();
|
|
break;
|
|
case sp_cst2:
|
|
i = sp_cstx;
|
|
case sp_ilb2:
|
|
argval = get16();
|
|
break;
|
|
case sp_cst4:
|
|
i = sp_cstx;
|
|
argval = get32();
|
|
break;
|
|
case sp_dnam:
|
|
case sp_pnam:
|
|
case sp_scon:
|
|
getstring();
|
|
break;
|
|
case sp_doff:
|
|
offtyp = getarg(sym_ptyp);
|
|
getarg(cst_ptyp);
|
|
break;
|
|
case sp_icon:
|
|
case sp_ucon:
|
|
case sp_fcon:
|
|
getarg(cst_ptyp);
|
|
consiz = (word) argval;
|
|
getstring();
|
|
argval = consiz;
|
|
break;
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
static int get16(void) {
|
|
int l_byte, h_byte;
|
|
|
|
l_byte = get8();
|
|
h_byte = get8();
|
|
if ( h_byte>=128 ) h_byte -= 256 ;
|
|
return l_byte | (h_byte*256) ;
|
|
}
|
|
|
|
static long get32(void) {
|
|
long l;
|
|
int h_byte;
|
|
|
|
l = get8();
|
|
l |= ((unsigned) get8())*256 ;
|
|
l |= get8()*256L*256L ;
|
|
h_byte = get8() ;
|
|
if ( h_byte>=128 ) h_byte -= 256 ;
|
|
return l | (h_byte*256L*256*256L) ;
|
|
}
|
|
|
|
static void getstring(void) {
|
|
char *p;
|
|
int n;
|
|
|
|
getarg(cst_ptyp);
|
|
if (argval < 0)
|
|
fatal("string/identifier too long");
|
|
if (argval >= maxstrsiz) {
|
|
myfree(str);
|
|
str = myalloc((unsigned) argval + 1);
|
|
maxstrsiz = argval + 1;
|
|
}
|
|
strsiz = n = (int) argval;
|
|
p = str;
|
|
while (--n >= 0)
|
|
*p++ = get8();
|
|
*p++ = '\0';
|
|
}
|
|
|
|
static string strarg(int t) {
|
|
char *p;
|
|
|
|
switch (t) {
|
|
case sp_ilb1:
|
|
case sp_ilb2:
|
|
#ifdef fmt_ilb
|
|
fmt_ilb(procno,((int) argval),argstr);
|
|
#else
|
|
sprintf(argstr,ilb_fmt,procno,(int)argval);
|
|
#endif
|
|
break;
|
|
case sp_dlb1:
|
|
case sp_dlb2:
|
|
sprintf(argstr,dlb_fmt,dlbval);
|
|
break;
|
|
case sp_cstx:
|
|
sprintf(argstr,cst_fmt,(full)argval);
|
|
break;
|
|
case sp_dnam:
|
|
case sp_pnam:
|
|
#ifdef fmt_id
|
|
fmt_id(str,argstr);
|
|
#else
|
|
p = argstr;
|
|
if (strsiz < 8 || str[0] == id_first)
|
|
*p++ = id_first;
|
|
sprintf(p,"%.*s",strsiz,str);
|
|
#endif
|
|
break;
|
|
case sp_doff:
|
|
strarg(offtyp);
|
|
for (p = argstr; *p; p++)
|
|
;
|
|
if ((full) argval >= 0)
|
|
*p++ = '+';
|
|
else {
|
|
*p++ = '-';
|
|
argval = - (full) argval;
|
|
}
|
|
sprintf(p,off_fmt,(full)argval);
|
|
break;
|
|
case sp_cend:
|
|
return("");
|
|
}
|
|
return(mystrcpy(argstr));
|
|
}
|
|
|
|
static void bss(full n, int t, int b) {
|
|
long s = 0;
|
|
|
|
if (n % TEM_WSIZE)
|
|
fatal("bad BSS size");
|
|
if (b==0
|
|
#ifdef BSS_INIT
|
|
|| (t==sp_cstx && argval==BSS_INIT)
|
|
#endif /* BSS_INIT */
|
|
) {
|
|
switchseg(SEGBSS);
|
|
newlbss(labstr,n);
|
|
labstr[0]=0;
|
|
return;
|
|
}
|
|
switchseg(SEGCON);
|
|
dumplab();
|
|
while (n > 0)
|
|
n -= (s = con(t));
|
|
if (s % TEM_WSIZE)
|
|
fatal("bad BSS initializer");
|
|
}
|
|
|
|
static long con(int t) {
|
|
int i;
|
|
|
|
strarg(t);
|
|
switch (t) {
|
|
case sp_ilb1:
|
|
case sp_ilb2:
|
|
case sp_pnam:
|
|
part_flush();
|
|
con_ilb(argstr);
|
|
return((long)TEM_PSIZE);
|
|
case sp_dlb1:
|
|
case sp_dlb2:
|
|
case sp_dnam:
|
|
case sp_doff:
|
|
part_flush();
|
|
con_dlb(argstr);
|
|
return((long)TEM_PSIZE);
|
|
case sp_cstx:
|
|
con_part(TEM_WSIZE,(word)argval);
|
|
return((long)TEM_WSIZE);
|
|
case sp_scon:
|
|
for (i = 0; i < strsiz; i++)
|
|
con_part(1,(word) str[i]);
|
|
return((long)strsiz);
|
|
case sp_icon:
|
|
case sp_ucon:
|
|
if (argval > TEM_WSIZE) {
|
|
part_flush();
|
|
con_mult((word)argval);
|
|
} else {
|
|
con_part((int)argval,(word)our_atol(str));
|
|
}
|
|
return(argval);
|
|
case sp_fcon:
|
|
part_flush();
|
|
con_float();
|
|
return(argval);
|
|
}
|
|
assert(FALSE);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
extern char *segname[];
|
|
|
|
void swtxt(void) {
|
|
switchseg(SEGTXT);
|
|
}
|
|
|
|
static void switchseg(int s) {
|
|
|
|
if (s == curseg)
|
|
return;
|
|
part_flush();
|
|
if ((curseg = s) >= 0)
|
|
fprintf(codefile,"%s\n",segname[s]);
|
|
}
|
|
|
|
static void savelab(void) {
|
|
register char *p,*q;
|
|
|
|
part_flush();
|
|
if (labstr[0]) {
|
|
dlbdlb(argstr,labstr);
|
|
return;
|
|
}
|
|
p = argstr;
|
|
q = labstr;
|
|
while (*q++ = *p++)
|
|
;
|
|
}
|
|
|
|
static void dumplab(void) {
|
|
|
|
if (labstr[0] == 0)
|
|
return;
|
|
assert(part_size == 0);
|
|
newdlb(labstr);
|
|
labstr[0] = 0;
|
|
}
|
|
|
|
static void xdumplab(void) {
|
|
|
|
if (labstr[0] == 0)
|
|
return;
|
|
assert(part_size == 0);
|
|
newdlb(labstr);
|
|
}
|
|
|
|
static void part_flush(void) {
|
|
|
|
/*
|
|
* Each new data fragment and each data label starts at
|
|
* a new target machine word
|
|
*/
|
|
if (part_size == 0)
|
|
return;
|
|
con_cst(part_word);
|
|
part_size = 0;
|
|
part_word = 0;
|
|
}
|
|
|
|
static string holstr(word n) {
|
|
|
|
sprintf(str,hol_off,n,holno);
|
|
return(mystrcpy(str));
|
|
}
|
|
|
|
|
|
/* ----- machine dependent routines ----- */
|
|
|
|
#include "mach.c"
|