ack/util/misc/decode.c
1985-06-21 12:55:17 +00:00

500 lines
8.3 KiB
C

/*
* (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
*
*/
#ifndef NORCSID
static char rcsid[] = "$Header$";
#endif
/*
* Decode compact EM assembly language
*
* Author: Johan Stevenson, Vrije Universiteit, Amsterdam
*/
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <em_spec.h>
#include <em_pseu.h>
#include <em_flag.h>
#include <em_ptyp.h>
#include <em_mes.h>
#define get8() ((unsigned)getchar())
#define check(x) if (!(x)) fail_check()
#define MAXSTR 256
/*
* global variables
*/
int opcode;
int offtyp;
long argval;
int dlbval;
char string[MAXSTR];
int strsiz;
int wsize;
int psize;
int lineno;
int argnum;
int errors;
char *progname;
char *filename;
long wordmask[] = { /* allowed bits in a word */
0x00000000,
0x000000FF,
0x0000FFFF,
0x00000000,
0xFFFFFFFF
};
long sizemask[] = { /* allowed bits in multiples of 'wsize' */
0x00000000,
0x7FFFFFFF,
0x7FFFFFFE,
0x00000000,
0x7FFFFFFC
};
/*
* external tables
*/
extern char em_flag[];
extern short em_ptyp[];
extern char em_mnem[][4];
extern char em_pseu[][4];
/*
* routines
*/
int get16();
long get32();
main(argc,argv) char **argv; {
progname = argv[0];
if (argc >= 2) {
filename = argv[1];
if (freopen(argv[1],"r",stdin) == NULL)
fatal("can't open %s",argv[1]);
}
if (argc >= 3)
if (freopen(argv[2],"w",stdout) == NULL)
fatal("can't create %s",argv[2]);
if (get16() != sp_magic)
fatal("bad magic word");
/* In System III the array is called _ctype[] without the trailing '_' */
(_ctype_+1)['_'] = (_ctype_+1)['a'];
while (nextline())
;
return(errors ? -1 : 0);
}
/* ----- copy ----- */
int nextline() {
register t;
lineno++;
argnum = 1;
switch (t = table1()) {
case EOF:
return(0);
case sp_fmnem:
instr();
break;
case sp_fpseu:
pseudo();
break;
case sp_ilb1:
case sp_ilb2:
argnum = 0;
putarg(sp_cst2);
break;
case sp_dlb1:
case sp_dlb2:
case sp_dnam:
argnum = 0;
putarg(t);
break;
default:
error("unknown opcode %d",t);
}
putchar('\n');
return(1);
}
instr() {
register i,j,t;
register long l;
i = opcode - sp_fmnem;
printf(" %s",em_mnem[i]);
j = em_flag[i] & EM_PAR;
if (j == PAR_NO)
return;
t = em_ptyp[j];
t = getarg(t);
/*
* range checking
*/
switch (j) {
case PAR_N:
check(argval >= 0);
break;
case PAR_G:
if (t != sp_cst2 && t != sp_cst4)
break;
check(argval >= 0);
/* fall through */
case PAR_L:
l = argval >= 0 ? argval : -argval;
check((l & ~wordmask[psize]) == 0);
break;
case PAR_W:
if (t == sp_cend)
break;
check((argval & ~wordmask[wsize]) == 0);
/* fall through */
case PAR_S:
check(argval != 0);
/* fall through */
case PAR_Z:
check((argval & ~sizemask[wsize]) == 0);
break;
case PAR_O:
check(argval != 0);
check((argval & ~sizemask[wsize])==0 || (wsize % argval)==0);
break;
case PAR_B:
t = sp_ilb2;
break;
case PAR_R:
check(argval >= 0 && argval <= 2);
break;
}
putarg(t);
}
pseudo() {
register i,t;
i = opcode;
printf(" %s",em_pseu[i - sp_fpseu]);
switch (i) {
case ps_bss:
case ps_hol:
putarg(getarg(cst_ptyp));
putarg(getarg(val_ptyp));
putarg(getarg(ptyp(sp_cst2)));
check(argval==0 || argval==1);
break;
case ps_rom:
case ps_con:
putarg(getarg(val_ptyp));
while ((t = getarg(any_ptyp)) != sp_cend)
putarg(t);
break;
case ps_mes:
putarg(getarg(ptyp(sp_cst2)));
if (argval == ms_emx) {
putarg(getarg(ptyp(sp_cst2)));
check(argval > 0 && argval <= 4);
wsize = (int) argval;
putarg(getarg(ptyp(sp_cst2)));
check(argval > 0 && argval <= 4);
psize = (int) argval;
}
while ((t = getarg(any_ptyp)) != sp_cend)
putarg(t);
break;
case ps_exa:
case ps_ina:
putarg(getarg(sym_ptyp));
break;
case ps_exp:
case ps_inp:
putarg(getarg(ptyp(sp_pnam)));
break;
case ps_exc:
putarg(getarg(ptyp(sp_cst2)));
putarg(getarg(ptyp(sp_cst2)));
break;
case ps_pro:
putarg(getarg(ptyp(sp_pnam)));
putarg(getarg(cst_ptyp|ptyp(sp_cend)));
break;
case ps_end:
putarg(getarg(cst_ptyp|ptyp(sp_cend)));
break;
default:
error("bad pseudo %d",i);
}
}
/* ----- input ----- */
int getarg(typset) {
register t,argtyp;
argtyp = t = table2();
if (t == EOF)
fatal("unexpected EOF");
t -= sp_fspec;
assert(t >= 0 && t < 16);
t = 1 << t;
if ((typset & t) == 0)
error("bad argument type %d",argtyp);
return(argtyp);
}
int table1() {
register 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));
}
int table2() {
register i;
i = get8();
if (i < sp_fcst0+sp_ncst0 && i >= sp_fcst0) {
argval = i - sp_zcst0;
return(sp_cst2);
}
return(table3(i));
}
int table3(i) {
long consiz;
switch(i) {
case sp_ilb1:
argval = get8();
break;
case sp_dlb1:
dlbval = get8();
break;
case sp_dlb2:
dlbval = get16();
if ( dlbval<0 ) {
error("illegal data label .%d",dlbval);
dlbval=0 ;
}
break;
case sp_cst2:
argval = get16();
break;
case sp_ilb2:
argval = get16();
if ( argval<0 ) {
error("illegal instruction label %ld",argval);
argval=0 ;
}
break;
case sp_cst4:
argval = get32();
break;
case sp_dnam:
case sp_pnam:
getstring(1);
break;
case sp_scon:
getstring(0);
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 = (long) argval;
getstring(0);
argval = consiz;
break;
}
return(i);
}
int get16() {
register int l_byte, h_byte;
l_byte = get8();
h_byte = get8();
if ( h_byte>=128 ) h_byte -= 256 ;
return l_byte | (h_byte*256) ;
}
long get32() {
register long l;
register 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) ;
}
getstring(ident) {
register char *p;
register n;
getarg(cst_ptyp);
if (argval < 0 || argval > MAXSTR)
fatal("string/identifier too long");
strsiz = n = argval;
p = string;
while (--n >= 0)
*p++ = get8();
if (ident) {
if (!isascii(string[0]) || !isalpha(string[0])) {
identerror();
return;
}
for (n=strsiz,p=string+1;--n>0;p++)
if (!isascii(*p) || !isalnum(*p)) {
identerror();
return;
}
}
}
/* ----- output ----- */
putarg(t) {
if (argnum != 0)
putchar(argnum == 1 ? ' ' : ',');
argnum++;
puttyp(t);
}
puttyp(t) {
switch (t) {
case sp_ilb1:
case sp_ilb2:
printf("*%d",(int) argval);
break;
case sp_dlb1:
case sp_dlb2:
printf(".%d",dlbval);
break;
case sp_dnam:
putstr(0,0);
break;
case sp_cst2:
case sp_cst4:
printf("%ld",argval);
break;
case sp_doff:
puttyp(offtyp);
if (argval >= 0) putchar('+');
printf("%ld",argval);
break;
case sp_pnam:
putstr('$',0);
break;
case sp_scon:
putstr('\'','\'');
break;
case sp_icon:
putstr(0,'I');
printf("%ld",argval);
break;
case sp_ucon:
putstr(0,'U');
printf("%ld",argval);
break;
case sp_fcon:
putstr(0,'F');
printf("%ld",argval);
break;
case sp_cend:
putchar('?');
break;
}
}
putstr(c,c2) register c; {
register char *p;
if (c)
putchar(c);
p = string;
while (--strsiz >= 0) {
c = *p++ & 0377;
if (c >= 040 && c < 0177) {
if (c == '\'' || c == '\\')
putchar('\\');
putchar(c);
} else
printf("\\%03o",c);
}
if (c2)
putchar(c2);
}
/* ----- error handling ----- */
fail_check() {
error("argument range error");
}
identerror() {
error("'%s' is not a correct identifier",string);
}
/* VARARGS */
error(s,a1,a2,a3,a4) char *s; {
fprintf(stderr,
"%s: line %d: ",
filename ? filename : progname,
lineno);
fprintf(stderr,s,a1,a2,a3,a4);
fprintf(stderr,"\n");
errors++;
}
/* VARARGS */
fatal(s,a1,a2,a3,a4) char *s; {
error(s,a1,a2,a3,a4);
exit(-1);
}