550 lines
11 KiB
C
550 lines
11 KiB
C
|
#include <stdio.h>
|
||
|
#include "param.h"
|
||
|
#include "types.h"
|
||
|
#include "assert.h"
|
||
|
#include "line.h"
|
||
|
#include "lookup.h"
|
||
|
#include "alloc.h"
|
||
|
#include "proinf.h"
|
||
|
#include "../../h/em_spec.h"
|
||
|
#include "../../h/em_pseu.h"
|
||
|
#include "../../h/em_flag.h"
|
||
|
#include "../../h/em_mes.h"
|
||
|
#include "ext.h"
|
||
|
|
||
|
/*
|
||
|
* (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||
|
*
|
||
|
* This product is part of the Amsterdam Compiler Kit.
|
||
|
*
|
||
|
* Permission to use, sell, duplicate or disclose this software must be
|
||
|
* obtained in writing. Requests for such permissions may be sent to
|
||
|
*
|
||
|
* Dr. Andrew S. Tanenbaum
|
||
|
* Wiskundig Seminarium
|
||
|
* Vrije Universiteit
|
||
|
* Postbox 7161
|
||
|
* 1007 MC Amsterdam
|
||
|
* The Netherlands
|
||
|
*
|
||
|
* Author: Hans van Staveren
|
||
|
*/
|
||
|
|
||
|
|
||
|
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
|
||
|
|
||
|
short readshort() {
|
||
|
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
|
||
|
offset readoffset() {
|
||
|
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
|
||
|
|
||
|
draininput() {
|
||
|
|
||
|
/*
|
||
|
* called when MES ERR is encountered.
|
||
|
* Drain input in case it is a pipe.
|
||
|
*/
|
||
|
|
||
|
while (getchar() != EOF)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
short getint() {
|
||
|
|
||
|
switch(table2()) {
|
||
|
default: error("int expected");
|
||
|
case CSTX1:
|
||
|
return(tabval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sym_p getsym(status) int status; {
|
||
|
|
||
|
switch(table2()) {
|
||
|
default:
|
||
|
error("symbol expected");
|
||
|
case DLBX:
|
||
|
return(symlookup(string,status,0));
|
||
|
case sp_pnam:
|
||
|
return(symlookup(string,status,SYMPRO));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
offset getoff() {
|
||
|
|
||
|
switch (table2()) {
|
||
|
default: error("offset expected");
|
||
|
case CSTX1:
|
||
|
return((offset) tabval);
|
||
|
#ifdef LONGOFF
|
||
|
case CSTX2:
|
||
|
return(tabval2);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
make_string(n) int n; {
|
||
|
register char *s;
|
||
|
extern char *sprintf();
|
||
|
|
||
|
s=sprintf(string,".%u",n);
|
||
|
assert(s == string);
|
||
|
}
|
||
|
|
||
|
inident() {
|
||
|
register n;
|
||
|
register char *p = string;
|
||
|
register c;
|
||
|
|
||
|
n = getint();
|
||
|
while (n--) {
|
||
|
c = readbyte();
|
||
|
if (p<&string[IDL])
|
||
|
*p++ = c;
|
||
|
}
|
||
|
*p++ = 0;
|
||
|
}
|
||
|
|
||
|
int table3(n) 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int table1() {
|
||
|
register 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));
|
||
|
}
|
||
|
|
||
|
int table2() {
|
||
|
register n;
|
||
|
|
||
|
n = readbyte();
|
||
|
if ((n < sp_fcst0 + sp_ncst0) && (n >= sp_fcst0)) {
|
||
|
tabval = n - sp_zcst0;
|
||
|
return(CSTX1);
|
||
|
}
|
||
|
return(table3(n));
|
||
|
}
|
||
|
|
||
|
getlines() {
|
||
|
register line_p lnp;
|
||
|
register 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
argstring(length,abp) 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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
line_p arglist(n) 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(ap,n) register arg_p ap; {
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
int inpseudo(n) 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_reg:
|
||
|
if (prodepth==0)
|
||
|
error("MES REG outside procedure");
|
||
|
regvar(lnp->l_a.la_arg->a_next);
|
||
|
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++;
|
||
|
if (prodepth>1) {
|
||
|
register 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);
|
||
|
}
|
||
|
|
||
|
tstinpro() {
|
||
|
|
||
|
if (prodepth==0)
|
||
|
error("Instruction or label not allowed outside procedure");
|
||
|
}
|