/* * (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 #include #include #include #include #include #include #include #include #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); }