Browse Source

Initial revision

sater 40 years ago
parent
commit
91ad12242c
3 changed files with 1288 additions and 0 deletions
  1. 36 0
      util/misc/Makefile
  2. 495 0
      util/misc/decode.c
  3. 757 0
      util/misc/encode.c

+ 36 - 0
util/misc/Makefile

@@ -0,0 +1,36 @@
+d=../..
+h=$d/h
+l=$d/lib
+
+DEC_PATH=decode
+ENC_PATH=encode
+DATA_PATH=$l/em_data.a
+
+CFLAGS=-O -I$h
+
+all:            $(DEC_PATH) $(ENC_PATH)
+
+$(DEC_PATH):    decode.o $(DATA_PATH)
+		cc -n -o $(DEC_PATH) decode.o $(DATA_PATH)
+
+$(ENC_PATH):    encode.o $(DATA_PATH)
+		cc -n -o $(ENC_PATH) encode.o $(DATA_PATH)
+
+encode.o:       $h/em_spec.h $h/em_pseu.h $h/em_flag.h $h/em_ptyp.h $h/em_mes.h
+
+decode.o:       $h/em_spec.h $h/em_pseu.h $h/em_flag.h $h/em_ptyp.h $h/em_mes.h
+
+clean:
+		rm -f $(DEC_PATH) $(ENC_PATH) *.o *.old
+install :       all
+		cp $(DEC_PATH) $l/em_$(DEC_PATH)
+		cp $(ENC_PATH) $l/em_$(ENC_PATH)
+
+cmp :           all
+		cmp $(DEC_PATH) $l/$(DEC_PATH)
+		cmp $(ENC_PATH) $l/$(ENC_PATH)
+
+opr:
+		make pr ^ opr
+pr:
+		@pr -n Makefile decode.c encode.c

+ 495 - 0
util/misc/decode.c

@@ -0,0 +1,495 @@
+/*
+ * (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
+ *
+ */
+
+/*
+ * 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 %D",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("%D",argval);
+		break;
+	case sp_doff:
+		puttyp(offtyp);
+		if (argval >= 0) putchar('+');
+		printf("%D",argval);
+		break;
+	case sp_pnam:
+		putstr('$',0);
+		break;
+	case sp_scon:
+		putstr('\'','\'');
+		break;
+	case sp_icon:
+		putstr(0,'I');
+		printf("%D",argval);
+		break;
+	case sp_ucon:
+		putstr(0,'U');
+		printf("%D",argval);
+		break;
+	case sp_fcon:
+		putstr(0,'F');
+		printf("%D",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);
+}

+ 757 - 0
util/misc/encode.c

@@ -0,0 +1,757 @@
+/*
+ * (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
+ *
+ */
+
+/*
+ * 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);
+}