ack/util/misc/encode.c
1984-06-26 10:08:37 +00:00

762 lines
12 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
/*
* Encode to compact EM assembly language
*
* Author: Johan Stevenson, Vrije Universiteit, Amsterdam
*/
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <setjmp.h>
#include <em_spec.h>
#include <em_pseu.h>
#include <em_flag.h>
#include <em_ptyp.h>
#include <em_mes.h>
#define put8(x) putchar(x)
#define check(x) if (!(x)) fail_check()
#define fit16i(x) ((x) >= 0xFFFF8000 && (x) <= 0x00007FFF)
#define fit8u(x) ((x) >= 0 && (x) <= 0xFF)
#define MAXSTR 256
#define HSIZE 256
#define EMPTY (EOF-1)
/*
* 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 = "INPUT";
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
};
int peekc = EMPTY;
int hashtab[HSIZE];
jmp_buf recover;
/*
* external tables
*/
extern char em_flag[];
extern short em_ptyp[];
extern char em_mnem[][4];
extern char em_pseu[][4];
int main(argc,argv) char **argv; {
progname = argv[0];
if (argc >= 2) {
filename = argv[1];
if (freopen(filename,"r",stdin) == NULL)
fatal("can't open %s",filename);
}
if (argc >= 3)
if (freopen(argv[2],"w",stdout) == NULL)
fatal("can't create %s",argv[2]);
init();
put16(sp_magic);
setjmp(recover);
while (nextline())
;
return(errors ? -1 : 0);
}
/* ----- copy ----- */
int nextline() {
register c,i;
lineno++;
argnum = 1;
c = nextchar();
if (c == EOF)
return(0);
if (isspace(c) && c != '\n') {
c = nospace();
if (isalpha(c)) {
inmnem(c);
if (opcode <= sp_lmnem)
instr();
else
pseudo();
} else
peekc = c;
} else if (c == '#') {
line_line();
} else {
peekc = c;
i = gettyp(sym_ptyp | ptyp(sp_cst2) | ptyp(sp_cend));
switch (i) {
case sp_cst2:
i = (int) argval;
if (i >= 0 && i < sp_nilb0)
put8(i + sp_filb0);
else
putarg(sp_ilb2);
break;
case sp_dlb2:
case sp_dnam:
putarg(i);
break;
case sp_cend:
break;
}
}
if (nospace() != '\n')
syntax("end of line expected");
return(1);
}
instr() {
register i,j,t;
register long l;
i = opcode;
put8(i);
i -= sp_fmnem;
j = em_flag[i] & EM_PAR;
if (j == PAR_NO)
return;
t = em_ptyp[j];
if (j == PAR_B)
t = ptyp(sp_ilb2);
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_cst2;
break;
case PAR_R:
check(argval >= 0 && argval <= 2);
break;
}
putarg(t);
}
pseudo() {
register i,t;
i = opcode;
put8(i);
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));
do
putarg(t = getarg(any_ptyp));
while (t != sp_cend);
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;
}
do
putarg(t = getarg(any_ptyp));
while (t != sp_cend);
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:
syntax("bad pseudo %d",i);
}
}
/* ----- input ----- */
int getarg(typset) {
register c;
if (argnum != 1) {
c = nospace();
if (c != ',') {
if (c != '\n')
syntax("comma expected");
peekc = c;
}
}
argnum++;
return(gettyp(typset));
}
int gettyp(typset) {
register c,t,sp;
c = nospace();
if (c == '\n') {
peekc = c;
sp = sp_cend;
} else if (isdigit(c) || c == '+' || c == '-' || c == '(') {
sp = inexpr1(c);
if (sp == sp_cst4 && fit16i(argval))
sp = sp_cst2;
} else if (isalpha(c)) {
inname(c);
sp = offsetted(sp_dnam);
} else if (c == '.') {
in15u();
dlbval = (int) argval;
sp = offsetted(sp_dlb2);
} else if (c == '*') {
in15u();
sp = sp_ilb2;
} else if (c == '$') {
inname(nextchar());
sp = sp_pnam;
} else if (c == '"' || c == '\'') {
sp = instring(c);
} else if (c == '?') {
sp = sp_cend;
} else
syntax("operand expected");
t = sp - sp_fspec;
assert(t >= 0 && t < 16);
t = 1 << t;
if ((typset & t) == 0)
error("bad argument type %d",sp);
return(sp);
}
int offsetted(sp) {
register c;
c = nospace();
if (c == '+' || c == '-') {
gettyp(cst_ptyp);
if (c == '-')
argval = -argval;
offtyp = sp;
return(sp_doff);
}
peekc = c;
return(sp);
}
inname(c) register c; {
register char *p;
if (isalpha(c) == 0)
syntax("letter expected");
p = string;
do {
if (p < &string[MAXSTR-1])
*p++ = c;
c = nextchar();
} while (isalnum(c));
peekc = c;
*p = '\0';
strsiz = p - string;
}
int inmnem(c) register c; {
register unsigned h;
register i;
inname(c);
h = hash(string);
for (;;) {
h++;
h %= HSIZE;
i = hashtab[h];
if (i == 0)
syntax("bad mnemonic");
if (i <= sp_lmnem) {
assert(i >= sp_fmnem);
if (strcmp(string,em_mnem[i - sp_fmnem]) != 0)
continue;
return(opcode = i);
}
assert(i <= sp_lpseu && i >= sp_fpseu);
if (strcmp(string,em_pseu[i - sp_fpseu]) != 0)
continue;
return(opcode = i);
}
}
int inexpr1(c) register c; {
long left;
if ((c = inexpr2(c)) != sp_cst4)
return(c);
for (;;) {
c = nospace();
if (c != '+' && c != '-') {
peekc = c;
break;
}
left = argval;
if (inexpr2(nospace()) != sp_cst4)
syntax("term expected");
if (c == '+')
argval += left;
else
argval = left - argval;
}
return(sp_cst4);
}
int inexpr2(c) register c; {
long left;
if ((c = inexpr3(c)) != sp_cst4)
return(c);
for (;;) {
c = nospace();
if (c != '*' && c != '/' && c != '%') {
peekc = c;
break;
}
left = argval;
if (inexpr3(nospace()) != sp_cst4)
syntax("factor expected");
if (c == '*')
argval *= left;
else if (c == '/')
argval = left / argval;
else
argval = left % argval;
}
return(sp_cst4);
}
inexpr3(c) register c; {
if (c == '(') {
if (inexpr1(nospace()) != sp_cst4)
syntax("expression expected");
if (nospace() != ')')
syntax("')' expected");
return(sp_cst4);
}
return(innumber(c));
}
int innumber(c) register c; {
register char *p;
register n;
int expsign;
static char numstr[MAXSTR];
long atol();
p = numstr;
expsign = 0;
if (c == '+' || c == '-') {
if (c == '-')
*p++ = c;
c = nextchar();
}
if (isdigit(c) == 0)
syntax("digit expected");
n = sp_cst4;
for (;;) {
if (p >= &numstr[MAXSTR-1])
fatal("number too long");
*p++ = c;
c = nextchar();
if (c == '.' || c == 'e' || c == 'E') {
expsign = c != '.';
n = sp_fcon;
continue;
}
if (expsign) {
expsign = 0;
if (c == '+' || c == '-')
continue;
}
if (isdigit(c) == 0)
break;
}
peekc = c;
*p = '\0';
c = nospace();
if (n == sp_fcon && c != 'F')
syntax("'F' expected");
if (c == 'I' || c == 'U' || c == 'F')
return(incon(numstr,c));
peekc = c;
argval = atol(numstr);
return(sp_cst4);
}
in15u() {
if (innumber(nextchar()) != sp_cst4)
syntax("integer expected");
check((argval & ~077777) == 0);
}
int incon(p,c) register char *p; {
register char *q;
q = string;
while (*q++ = *p++)
;
strsiz = q - string - 1;
gettyp(cst_ptyp);
return(c == 'I' ? sp_icon : (c == 'U' ? sp_ucon : sp_fcon));
}
int instring(termc) {
register char *p;
register c;
p = string;
for (;;) {
c = nextchar();
if (c == '\n' || c == EOF) {
peekc = c;
syntax("non-terminated string");
}
if (c == termc) {
if (termc == '"')
*p++ = '\0';
break;
}
if (c == '\\')
c = inescape();
if (p >= &string[MAXSTR-1])
fatal("string too long");
*p++ = c;
}
strsiz = p - string;
return(sp_scon);
}
int inescape() {
register c,j,r;
c = nextchar();
if (c >= '0' && c <= '7') {
r = c - '0';
for (j = 0; j < 2; j++) {
c = nextchar();
if (c < '0' || c > '7') {
peekc = c;
return(r);
}
r <<= 3;
r += (c - '0');
}
return(r);
}
switch (c) {
case 'b': return('\b');
case 'f': return('\f');
case 'n': return('\n');
case 'r': return('\r');
case 't': return('\t');
}
return(c);
}
int nospace() {
register c;
do
c = nextchar();
while (isspace(c) && c != '\n');
if (c == ';')
do
c = nextchar();
while (c != '\n' && c != EOF);
return(c);
}
int nextchar() {
register c;
if (peekc != EMPTY) {
c = peekc;
peekc = EMPTY;
return(c);
}
c = getchar();
if (isascii(c) == 0 && c != EOF)
fatal("non-ascii char");
return(c);
}
line_line() {
register char *p,*q;
static char filebuff[MAXSTR+1];
gettyp(ptyp(sp_cst2));
lineno = (int) (argval-1);
gettyp(ptyp(sp_scon));
p = string;
q = filebuff;
while (--strsiz >= 0)
*q++ = *p++;
*q = '\0';
filename = filebuff;
}
init() {
register i;
for (i = sp_fmnem; i <= sp_lmnem; i++)
pre_hash(i,em_mnem[i - sp_fmnem]);
for (i = sp_fpseu; i <= sp_lpseu; i++)
pre_hash(i,em_pseu[i - sp_fpseu]);
/* treat '_' as letter */
/* In System III the array is called _ctype[] without the trailing '_' */
(_ctype_+1)['_'] = (_ctype_+1)['a'];
}
pre_hash(i,s) char *s; {
register unsigned h;
assert(i != 0);
h = hash(s);
for (;;) {
h++;
h %= HSIZE;
if (hashtab[h] == 0) {
hashtab[h] = i;
return;
}
}
}
int hash(s) register char *s; {
register h;
h = 0;
while (*s) {
h <<= 1;
h += *s++;
}
return(h);
}
/* ----- output ----- */
putarg(sp) register sp; {
register i;
switch (sp) {
case sp_ilb2:
i = (int) argval;
if (fit8u(i)) {
put8(sp_ilb1);
put8(i);
break;
}
put8(sp);
put16(i);
break;
case sp_dlb2:
i = dlbval;
if (fit8u(i)) {
put8(sp_dlb1);
put8(i);
break;
}
put8(sp);
put16(i);
break;
case sp_cst2:
case sp_cst4:
if (fit16i(argval) == 0) {
put8(sp_cst4);
put32(argval);
break;
}
i = (int) argval;
if (i >= -sp_zcst0 && i < sp_ncst0 - sp_zcst0) {
put8(i + sp_zcst0 + sp_fcst0);
break;
}
put8(sp_cst2);
put16(i);
break;
case sp_doff:
put8(sp);
putarg(offtyp);
putarg(sp_cst4);
break;
case sp_dnam:
case sp_pnam:
case sp_scon:
put8(sp);
putstr();
break;
case sp_icon:
case sp_ucon:
case sp_fcon:
put8(sp);
putarg(sp_cst4);
putstr();
break;
case sp_cend:
put8(sp);
break;
}
}
putstr() {
register char *p;
long consiz;
consiz = argval;
argval = strsiz;
putarg(sp_cst4);
argval = consiz;
p = string;
while (--strsiz >= 0)
put8(*p++);
}
put16(w) int w; {
put8(w);
put8(w >> 8);
}
put32(f) long f; {
put16((int) f);
put16((int)(f >> 16));
}
/* ----- error handling ----- */
fail_check() {
error("argument range error");
}
/* VARARGS */
error(s,a1,a2,a3,a4) char *s; {
fprintf(stderr,"%s: line %d: ", filename, 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);
}
/* VARARGS */
syntax(s,a1,a2,a3,a4) char *s; {
register c;
error(s,a1,a2,a3,a4);
do
c = nextchar();
while (c != '\n' && c != EOF);
longjmp(recover);
}