[net.sources] TI 99 assembler, the assembler itself

lee@unmvax.UUCP (07/22/84)

  To unarchive, remove the first line through and
 including the dashed line. Then type:

   % sh <thisfilename>

Don't forget to strip off the .signature at the end!
-------------------------------------------
: Run this with sh NOT csh!
echo extracting Makefile
cat << //*FUNKYSTUFF*// > Makefile
YACC= yacc -d -v
LEX= lex
LIBS= -ll
CFLAGS= -g -DLEXDEBUG -DYYDEBUG -DDEBUG
PR= pr
LPR= lpr

DESTDIR= /usr/local/bin
DESTLIB= /usr/local/lib

CSRC= util.c aabort.c hash.c main.c rsrvd.c tiasm.c filutil.c Tild.c adrinf.c \\
	tiload.c
OBJ= hash.o y.tab.o lex.yy.o util.o main.o rsrvd.o filutil.o aabort.o adrinf.o
FRONTEND= tiasm.o
LOADO= Tild.o hash.o aabort.o adrinf.o

install: all
	install tiasm \$(DESTDIR)
	install tiasm1 \$(DESTLIB)
	install tild \$(DESTDIR)

all:	tiasm tiasm1 tild tiload

tiasm:	\$(FRONTEND)
	cc \$(CFLAGS) \$(LDFLAGS) -o tiasm \$(FRONTEND)

tiasm1:	\$(OBJ)
	cc \$(CFLAGS) \$(LDFLAGS) -o tiasm1 \$(OBJ) \$(LIBS)

tild:	\$(LOADO)
	cc \$(CFLAGS) \$(LDFLAGS) -o tild \$(LOADO)

tiload: tiload.o
	cc \$(CFLAGS) \$(LDFLAGS) -o tiload tiload.o

print:	\$(CSRC) lex.lex parse.y TIasm.h opcodes.h mio.h TI.out.h
	\$(PR) TIasm.h opcodes.h parse.y lex.lex \$(CSRC) \\
	 mio.h TI.out.h \\
	  | \$(LPR)

clean:
	@-rm *.o core tiasm y.tab.h y.tab.c lex.yy.c tiasm1 y.output tild \\
		tiload

y.tab.c: parse.y
	\$(YACC) parse.y

lex.yy.c: lex.lex y.tab.h
	\$(LEX) lex.lex

y.tab.h: y.tab.c

\$(OBJ) y.tab.c lex.yy.c: TIasm.h

rsrvd.o: opcodes.h
//*FUNKYSTUFF*//
echo extracting TI.out.h
cat << //*FUNKYSTUFF*// > TI.out.h
/* Format for an object file and loadable image */

/* Magic numbers */
#define	OMAGIC		0x100	/* This is an obj file, not link edited yet */
#define	BOBJ		0x80	/* Down loadable binary */

struct format {
	short	f_magic;	/* Magic number */
	short	f_laddr;	/* Load address */
	short	f_saddr;	/* Start address */
	short	f_csiz;		/* Size (in bytes) of executable */
};

/* Max size of an identifier */
#define	IDENTSIZ	6

struct symbol {
	char	s_symnm[IDENTSIZ];		/* Symbol name */
	short	s_flags;			/* Flags from st_type */
	short	s_raddr;			/* Resolution address */
	short	s_naddr;			/* Addresses to 16-bit patch */
};
//*FUNKYSTUFF*//
echo extracting TIasm.h
cat << //*FUNKYSTUFF*// > TIasm.h
#include "TI.out.h"

/* Size of vector for internal symbol table
 * Not only is this a magic number but it SHOULD be the lower of twin
 * primes and large enough to make the lists of buckets small.
 */
#define	SYMVECSIZ	1103

/* Maximum number of files that can be assembled */
#define	NFILES		50

/* Template for temp file names */
#define	TFILNM		"/tmp/TiXXXXXX"

/* Location of pass1 */
#define	PASS1		"/usr/local/lib/tiasm1"

#ifdef	DEBUG
#undef	DEBUG
#define	DEBUG(l,s,a)	if (Debug > (l)) fprintf (stderr, (s), (a))
#else	DEBUG
#define	DEBUG(l,s,a)
#endif	DEBUG

#define	TRUE		1
#define	FALSE		0

typedef	short	flag;

/* Types of entries in the symbol table */
#define	TYRSRVD		0x1
#define	TYLCLID		0x2
#define	TYEXTID		0x4
#define	TYRSLVD		0x8
#define	TYDIR		0x10

/* A member of the list of addresses referencing an identifier */
struct a_lst {
	short	a_addr;				/* address of opnd making ref */
	struct a_lst *a_next;			/* next member of list */
};

/* A symbol table entry */
struct stab {
	char	st_symnm[IDENTSIZ + 1];		/* Identifier/keyword name */
	short	st_type;			/* Type of this entry */
	union st_ent {
		struct op_info {
			unsigned short	op_cod;		/* opcode */
			unsigned char op_fmt;		/* Format code */
		} en_op;
		struct r_info {
			struct a_lst *ri_lst;	/* List of references */
			struct j_lst *ri_jl;	/* Jumps having this target */
			short	ri_addr;	/* Resolution address */
		} en_rinf;
	}	st_ent;
	struct stab *st_next;			/* Next bucket */
};

#define	st_opc		st_ent.en_op.op_cod
#define	st_fmt		st_ent.en_op.op_fmt
#define	en_lst		st_ent.en_rinf.ri_lst
#define	en_addr		st_ent.en_rinf.ri_addr
#define	en_jl		st_ent.en_rinf.ri_jl

/* A structure to store info about a symbol (absolute address or
 * pointer to symbol table entry.
 */

struct symb  {
	short	sy_tag;				/* Tag */
	union {
		struct stab *sy_stb;
		short	sy_loc;
	} sy_un;
};

#define	SYMTAG		0x1		/* Operand is indexed */
#define	RELOCATABLE	0x2		/* Relocatable as opposed to absolute */

/* Information about an operand specifier */
struct infop {
	int	t;				/* T code */
	int	r;				/* register */
	struct symb sy_info;
};

#define	in_stb		sy_info.sy_un.sy_stb
#define	in_loc		sy_info.sy_un.sy_loc
#define	in_tag		sy_info.sy_tag

/* A member of the list of addresses and targets necessary to resolve jumps */
struct j_lst {
	short	j_addr;				/* Word address for patch */
	struct j_lst *j_next;			/* Next member in list */
};

#define	j_tag	j_trgt.sy_tag
#define	j_loc	j_trgt.sy_un.sy_loc
#define	j_stb	j_trgt.sy_un.sy_stb

/* Structure for the initialization tables.
 * op_fmt is for machine type formats 1 through 9
 * op_fmt of zero is reserved to this program.
 * op_code would be the opcode to plug in to the object file providing
 * it is a valid machine format.
 */

struct ops {
	char *op_name;
	unsigned short op_code;
	unsigned char op_fmt;
};

/* The following is used to reclaim space in the list of forward referencing
 * jumps. It, obviously, will need to be changed if another storage method
 * is used.
 */

#define	rmjinf(x)	(free((x)))

/* Is arg (integer) an odd number */
#define	odd(x)	((x) % 2)
//*FUNKYSTUFF*//
echo extracting mio.h
cat << //*FUNKYSTUFF*// > mio.h
/* Some absolutely RUDE macros for doing portable (buffered) reads and writes.
 * The open routine should be a macro but is just too large.
 * The ideas behind these is that they will look EXACTLY like
 * the UNIX primitives read, write and open but do their stuff
 * buffered to keep us from going to the kernel too often.
 * Close must be a routine as it must return something.
 */

extern int fread(), fwrite();
#define	read(fd,bf,sz)	fread((char *)&(bf),1,(sz),Sdvec[(fd)])
#define write(fd,bf,sz) fwrite((char *)&(bf),1,(sz),Sdvec[(fd)])
#define lseek(fd,x,w)	fseek(Sdvec[(fd)],(x),(w))

/* Macros to do error checking */
#define	xwrite(fd,bf,sz) if(Ferror == FALSE)if(write(fd,bf,sz) != sz)\\
				aabort("Write error")
#define	xseek(fd,x,w)	if(Ferror == FALSE)if(lseek((fd),(x),(w)) == -1)\\
				aabort("Seek error")

/* Is arg (integer) an odd number */
#define	odd(x)	((x) % 2)
//*FUNKYSTUFF*//
echo extracting opcodes.h
cat << //*FUNKYSTUFF*// > opcodes.h
/* Machine instructions */

#define	LI	0x200			/* Load Immediate */
#define	AI	0x220			/* Add Immediate */
#define	ANDI	0x240			/* AND Immediate */
#define	ORI	0x0260			/* OR Immediate */
#define	CI	0x0280			/* Compare Immediate */
#define	STWP	0x02a0			/* STore Workspace Pointer */
#define	STST	0x02c0			/* STore STatus register */
#define	LWPI	0x02e0			/* Load Workspace Pointer Immediate */
#define	LIMI	0x0300			/* Load Interrupt Mask Immediate */
#define	IDLE	0x0340			/* IDLE */
#define	RSET	0x0360			/* ReSET arithmetic unit */
#define	RTWP	0x0380			/* ReTurn to old Workspace Pointer */
#define	CKON	0x03a0			/* user defined */
#define	CKOF	0x03c0			/* user defined */
#define	LREX	0x03e0			/* Load Register and EXecute */
#define	BLWP	0x0400			/* Branch, Load new Workspace Pointer */
#define	B	0x0440			/* Branch */
#define	X	0x0480			/* eXecute */
#define	CLR	0x04c0			/* CLeaR to zeros */
#define	NEG	0x0500			/* NEGate to ones */
#define	INV	0x0540			/* INVert */
#define	INC	0x0580			/* INCrement by one */
#define	INCT	0x05c0			/* Increment by Two */
#define	DEC	0x0600			/* DECrement by one */
#define	DECT	0x0640			/* DECrement by two */
#define	BL	0x0680			/* Branch and Link */
#define	SWPB	0x06c0			/* SWaP Bytes */
#define	SETO	0x0700			/* SET to Ones */
#define	ABS	0x0740			/* ABSolute value */
#define	SRA	0x0800			/* Shift Right Arithmetic */
#define	SRL	0x0900			/* Shift Right Logical */
#define	SLA	0x0a00			/* Shift Left Arithmetic */
#define	SRC	0x0b00			/* Shift Right Circular */
#define	JMP	0x1000			/* unconditional JuMP */
#define	JLT	0x1100			/* Jump on Less Than */
#define	JLE	0x1200			/* Jump on Less than or Equal */
#define	JEQ	0x1300			/* Jump on EQual */
#define	JHE	0x1400			/* Jump on High or Equal */
#define	JGT	0x1500			/* Jump on Greater Than */
#define	JNE	0x1600			/* Jump on Not Equal */
#define	JNC	0x1700			/* Jump on No Carry */
#define	JOC	0x1800			/* Jump on Overflow/Carry */
#define	JNO	0x1900			/* Jump on No Overflow */
#define	JL	0x1a00			/* Jump on Low */
#define	JH	0x1b00			/* Jump on High */
#define	JOP	0x1c00			/* Jump on Odd Parity */
#define	SBO	0x1d00			/* Set cru Bits to Ones */
#define	SBZ	0x1e00			/* Set cru Bits to Zeros */
#define	TB	0x1f00			/* Test cru Bit */
#define	COC	0x2000			/* Compare Ones Corresponding */
#define	CZC	0x2400			/* Compare Zeros Corresponding */
#define	XOR	0x2800			/* eXclusive OR */
#define	LDCR	0x3000			/* LoaD CRu */
#define	STCR	0x3400			/* STore CRu */
#define	MPY	0x3800			/* MultiPlY */
#define	DIV	0x3c00			/* DIVide */
#define	SZC	0x4000			/* Set Zeros Corresponding (word) */
#define	SZCB	0x5000			/* Set Zeros Corresponding (Byte) */
#define	S	0x6000			/* Subtract (word) */
#define	SB	0x7000			/* Subtract (Byte) */
#define	C	0x8000			/* Compare (word) */
#define	CB	0x9000			/* Compare (Byte) */
#define	A	0xa000			/* Add (word) */
#define	AB	0xb000			/* Add (Byte) */
#define	MOV	0xc000			/* MOVe (word) */
#define	MOVB	0xd000			/* MOVe (Byte) */
#define	SOC	0xe000			/* Set Ones Corresponding (word) */
#define	SOCB	0xf000			/* Set Ones Corresponding (Byte) */
#define	XOP	0x2c00			/* eXtended OPeration */
//*FUNKYSTUFF*//
echo extracting Tild.c
cat << //*FUNKYSTUFF*// > Tild.c
#include "TIasm.h"
#include <stdio.h>

/* Some globals */
short	laddr = 0x200;	/* Default load address of bin file */
short	saddr = 0x200;	/* Default start address */
int	Ofd;		/* The fildes for the bin file */
short	locctr = 0;	/* The location counter */
short	Debug;

main (argc, argv)
int	argc;
char	*argv[];
{
	char *fvec[BUFSIZ];			/* Should be enough */
	char *tmp, **avec, *arg;
	char *outfil = "ti.out";		/* The output file */
	int x;
	int filcnt = 0;				/* Number of files to edit */
	struct format header;

	argv[argc] = NULL;

	avec = &argv[1];
	while (*avec != NULL)
		if (**avec != '-')
			fvec[filcnt++] = *avec++;
		else {
			arg = *avec++;
			while (*++arg != NULL)

				switch (*arg) {
				    case 'd':		/* Debug */
					break;
				    case 's':		/* Start address */
					if (sscanf (*avec++,
					    "%x", &saddr) != 1) {
						fprintf (stderr,
						    "Bad start address\\n");
						exit (1);
					}
					break;
				    case 'l':		/* Load adress */
					if (sscanf (*avec++,
					    "%x", &laddr) != 1) {
						fprintf (stderr,
						    "Bad load address\\n");
						exit (1);
					}
					break;
				    default:
					fprintf (stderr, "Unknown switch -%c\\n",
					    *arg);
				}
		}

	if ((Ofd = creat(outfil, 0777)) < 0) {
		fprintf (stderr, "cannot create \\"%s\\", aborting!\\n", outfil);
		exit (1);
	}

	/* First write the execute header */
	header.f_magic = BOBJ;
	header.f_laddr = laddr;
	header.f_saddr = saddr;
	header.f_csiz = 0;			/* Don't need this */
	if (write(Ofd, (char *)&header, sizeof(header)) != sizeof(header))
		aabort ("Error writing header");

	for (x = 0; x < filcnt; ++x)
		grabit (fvec[x]);
}

/* grabit
 *
 * Grab the file from the object module and copy it over to the .out. When
 * done we get the symbol table info out and attempt to make patches. If we
 * can't we'll save 'em for later. The routine that figures out what to do with
 * the symbols makes the patches or whatever....
 *
 * RETURNS:
 *	nothing
 */

grabit (file)
char	*file;
{
	int ifd;
	int x;
	int nbytes, rmnng;
	struct format header;
	char buf[BUFSIZ];

	if ((ifd = open(file, 0)) < 0) {
		fprintf (stderr, "Could not open %s\\n", file);
		exit (1);
	}

	/* Read in the header */
	mread (ifd, (char *)&header, sizeof(header));

	/* Check the magic number and abort if incorrect */
	if (header.f_magic != OMAGIC) {
		switch (header.f_magic) {
		    case BOBJ:		/* Already link edited */
			fprintf (stderr, "File \\"%s\\" has been link edited!\\n",
			    file);
			break;
		    default:
			fprintf (stderr, "What is \\"%s\\" ????\\n", file);
			break;
		}
		exit (1);
	}

	/* Copy the code section across (buffered no less) */
	for (x = 0; x < header.f_csiz; ) {
		rmnng = header.f_csiz - x;
		x += nbytes = rmnng / BUFSIZ > 0 ? BUFSIZ : rmnng;
		if (read(ifd, buf, nbytes) != nbytes) {
			/* Arghh!!!!!!! */
			fprintf (stderr, "Read error on %s\\n", file);
			exit (1);
		}
		if (write(Ofd, buf, nbytes) != nbytes) {
			/* Geez, just can't win! */
			fprintf (stderr, "Write error\\n");
			exit (1);
		}
	}

	/* Ok, we have everything positioned to grab the symbol table info
	 * out. So, what are ya waitin' fer...
	 */
	getsymb (ifd);

	/* Last thing, bump the location counter */
	locctr += header.f_csiz;
}

/* getsymb
 *
 * Here we get the symbol table info out of the file and deal with it. If
 * a given symbol's address is already known we just make the patch. If the
 * symbol was not defined but is by a particular symbol we patch all the
 * addresses we have been saving up for just such an occasion. If it is
 * just a reference then, alas, we save it up for christmas when all the
 * little symbols come running home.
 *
 * RETURNS:
 *	nothing
 *
 */

getsymb (ifd)
int	ifd;
{
	struct a_lst *tmp;
	struct stab *ent;
	struct symbol symb;
	struct stab *lookup(), *insert(), *newent();
	struct a_lst *build();
	void splice();
	void resolve();
	extern void mseek();

	/* Read in each entry until EOF */
	while (read(ifd, &symb, sizeof(symb)) == sizeof(symb))

		/* Has the symbol been resolved? */
		if (!(symb.s_flags & TYRSLVD)) {

			/* Ok, do we have it in the symbol table? */
			if ((ent = lookup(symb.s_symnm)) == NULL) {

				/* Do not have to deal with externel 
				 * definitions here as it would mean a
				 * reference and not a resolution was declared
				 * externel. Which is, of course, IMPOSSIBLE!
				 *
				 * Ok, let us build it then..
				 */
				ent = newent (symb.s_symnm);
				strncpy (ent->st_symnm, symb.s_symnm, IDENTSIZ);
				ent->st_type = symb.s_flags;

				/* Now, build a linked list of addresses that
				 * need to be patched and attach them to the
				 * symbol table entry.
				 */
				ent->en_lst = build (ifd, symb.s_naddr);

				/* And, finally, enter it */
				if (insert(ent) == NULL)
					aabort ("Symbol table overflow!");
			} else {

				/* Is in symbol table */
				tmp = build (ifd, symb.s_naddr);
				splice (ent->en_lst, tmp);

				if (ent->st_type & TYEXTID) {
					/* Ok, resolve them now! */
					resolve (ent->en_lst, ent->en_addr);
					ent->en_lst = NULL;	/* Chuck it! */
				}
			}
		} else {
			/* Is resolved */
			tmp = build (ifd, symb.s_naddr);
			resolve (tmp, symb.s_raddr + locctr);

			/* Now then, is it externally declared? */
			if (symb.s_flags & TYEXTID) {

				/* Then we need to enter it into the table */
				if ((ent = lookup(symb.s_symnm)) == NULL) {
					ent = newent(symb.s_symnm);
					strncpy (ent->st_symnm, symb.s_symnm,
					    IDENTSIZ);
					if (insert(ent) == NULL)
						aabort (
						    "Symbol table overflow!");
				} else
					if (ent->st_type & TYEXTID) {
						fprintf (stderr,
						    "Symbol %s multiply defined\\n",
						    ent->st_symnm);
						exit (1);
					}
				ent->en_addr = symb.s_raddr + locctr;
				ent->st_type = symb.s_flags;

				/* resolve the references we may have picked
				 * up from earlier
				 */
				if (ent->en_lst != NULL)
					resolve (ent->en_lst, ent->en_addr);
			}
		}
	/* Put Ofd back at EOF as those resolves could have left
	 * the file positioned ANYWHERE!
	 */
	mseek (Ofd, 0L, 2);
}

/* mseek
 *
 * Seek on a file. Do error checking and abort on same.
 *
 * RETURNS:
 *	nothing
 *
 */

void mseek (fd, offset, whence)
int	fd;
long	offset;
int	whence;
{

	if (lseek(fd, offset, whence) < 0)
		aabort ("Seek error");
}

/* mread
 *
 * Do a read. Check for error. Premature EOF is considered an error.
 *
 * RETURNS:
 *	nada
 *
 */

mread (fd, buf, nbytes)
int	fd;
char	*buf;
int	nbytes;
{

	if (read(fd, buf, nbytes) == nbytes)
		return;
	fprintf (stderr, "Read error\\n");
	exit (1);
}

struct a_lst *build (fd, naddr)
int	fd;
short	naddr;
{
	short buf[30];
	int x, rmnng, y, nwrds;
	struct stab fakeit;			/* adrinf wants a stab ent */

	fakeit.en_lst = NULL;

	for (x = 0; x < naddr; x += nwrds) {
		rmnng = naddr - x;
		nwrds = 30 / rmnng == 0 ? 30 : rmnng;
		mread (fd, (char *)buf, rmnng * sizeof(short));
		for (y = 0; y < nwrds; ++y)
			/* Add the location counter and offset for header
			 * so we get the addresses right.
			 */
			adrinf (&fakeit,
			    buf[y] + locctr + sizeof(struct format));
	}
	return (fakeit.en_lst);
}

/* splice
 *
 * Take the two a_lsts and splice them into one. The second will be added
 * onto the end of the second. I guess this is really a concatenation, huh?
 * Oh well, the name is already this, so there!
 *
 * RETURNS:
 *	nothing
 */

void splice (l1, l2)
struct a_lst *l1, *l2;
{
	struct a_lst *tmp;

	for (tmp = l1; tmp->a_next != NULL; tmp = tmp->a_next)
		;
	tmp->a_next = l2;
}

/* resolve
 *
 * resolve a list of references to the given address.
 * Throw the list away as we go through it. Leaves the fd pointed wherever
 * it pleases.
 *
 * RETURNS:
 *	nothing
 *
 * NOTE: May abort on a seek or write error
 */

void resolve (lst, addr)
struct a_lst *lst;
short	addr;
{
	struct a_lst *tmp;

	addr += laddr;
	while (lst) {
		mseek(Ofd, (long )lst->a_addr, 0);
		if (write (Ofd, &addr, sizeof(addr)) != sizeof(addr))
			aabort ("Write error on resolve");
		tmp = lst->a_next;
		free (lst);
		lst = tmp;
	}
}
//*FUNKYSTUFF*//
echo extracting aabort.c
cat << //*FUNKYSTUFF*// > aabort.c

#include <stdio.h>
#include "TIasm.h"

extern flag Debug;

/* aabort
 * An error internal to the assembler has been discovered. abort processing.
 * print a short but cryptic message intended for maintainers.
 *
 * Does NOT return
 */

void aabort (string)
char	*string;
{

	fflush (stdout);
	fprintf (stderr, "Internal error: %s\\n", string);
	fflush (stderr);
	exit (1);
}
//*FUNKYSTUFF*//
echo extracting adrinf.c
cat << //*FUNKYSTUFF*// > adrinf.c
#include "TIasm.h"
#include <stdio.h>

/* adrinf
 *
 * Add an address to be relocated in to the list in the symbol table entry
 * reserved for just such a purpose.
 *
 * RETURNS:
 *	nothing
 *
 * NOTE: May abort if the malloc fails.
 */

void adrinf (stab, loc)
struct stab *stab;
short	loc;
{
	struct a_lst *ainfo;
	extern char *malloc();

	if ((ainfo = (struct a_lst *)malloc(sizeof(struct a_lst))) == NULL)
		aabort ("adrinf: no mem!");
	ainfo->a_addr = loc;
	ainfo->a_next = stab->en_lst;
	stab->en_lst = ainfo;
}
//*FUNKYSTUFF*//
echo extracting filutil.c
cat << //*FUNKYSTUFF*// > filutil.c
/* File utilities, open and close */

#include <stdio.h>
#include <sys/param.h>

/* For mapping purposes */
FILE	*Sdvec[NOFILE];

/* xopen
 * Open a file buffered but make it look like the UNIX "open" sys call.
 *
 * returns:
 *	fd for a successful open.
 *	-1 for a failure
 */
int xopen (file, mode)
char	*file;
int	mode;
{
	char *md;
	int fd;
	extern FILE *fdopen();

	switch (mode) {

	    case 0:	/* read */
		md = "r";
		break;
	    case 1:	/* write */
		md = "w";
		break;
	    case 2:	/* read & write */
		md = "r+";
		break;
	    default:
		return (-1);
	}

	if (file == NULL || (fd = open(file, mode) < 0))
		return (-1);
	if ((Sdvec[fd] = fdopen(fd, md)) == NULL) {
		close (fd);
		return (-1);
	}
	return (fd);
}

/* xclose
 * close a file
 *
 * returns:
 *	0 if succesful
 *	-1 for error
 */
int xclose (fd)
int	fd;
{

	if (fd < 0 || fd >= NOFILE)
		return (-1);
	if (fclose (Sdvec[fd]) == EOF)
		return (-1);
	Sdvec[fd] = NULL;
	return (0);
}

/* xcreat
 * create a file
 *
 * returns:
 *	fildes	for success
 *	-1 on error
 */
int xcreat (file, modes)
char	*file;
int	modes;
{
	int fd;
	FILE *fdopen();

	if (file == NULL || (fd = creat(file, modes)) < 0)
		return (-1);
	if ((Sdvec[fd] = fdopen(fd, "w+")) == NULL)
		return (-1);
	return (fd);
}
//*FUNKYSTUFF*//
echo extracting hash.c
cat << //*FUNKYSTUFF*// > hash.c
#include "TIasm.h"
#include <stdio.h>

extern int Debug;
struct stab *Symtab[SYMVECSIZ];

/* initab
 * Init the hash table.
 *
 * Returns:
 *	Nothing.
 */

void initab()
{
	register struct stab **tptr;
	register int x;

	tptr = Symtab;
	for (x = 0; x < SYMVECSIZ; ++x)
		*tptr++ = NULL;
}

/* hash
 * return a hash key based on the symbol.
 */

int hash (symbol)
register char *symbol;
{
	register int ac = 0;			/* Accumulator */
	register int x;

	for (x = 0; x < IDENTSIZ && *symbol != NULL; ++x) {
		DEBUG (200, "hash: adding %d to ", (int )*symbol);
		DEBUG (200, "accumulator which is %d\\n", ac);
		ac += (int )*symbol++;
	}

	DEBUG (200, "hash: returning %d\\n", ac % SYMVECSIZ);
	return (ac % SYMVECSIZ);
}

/* lookup
 * Look up a symbol in the symbol table.
 *
 * Returns:
 * pointer to entry if succesful.
 * NULL if not found.
 */

struct stab *lookup(symbol)
char	*symbol;
{
	struct stab *entry;

	DEBUG (100, "lookup: symbol is \\"%s\\"\\n", symbol);
	DEBUG (100, "lookup: hashcode = %d\\n", hash(symbol));

	if ((entry = Symtab[hash(symbol)]) == NULL)
		return (NULL);			/* The vector was empty */

	do
		if (strcmp(symbol, entry->st_symnm) == 0)
			return (entry);
	while ((entry = entry->st_next) != NULL);
	return (NULL);					/* Doesn't exist */
}

/* insert
 * Insert a symbol table entry into the symbol table.
 *
 * Returns:
 *	The entry inserted.
 *
 * NOTE: The return here is fairly redundant as this CANNOT fail. But,
 * should a quadratic hashing scheme ever be implemented the fail here is
 * possible. So, for the sake of modularity, I include the redundant return.
 * A fail would be signified by a NULL return.
 */

struct stab *insert(entry)
struct stab *entry;
{
	struct stab *list, *eolist;
	int key;

	DEBUG (100, "insert: Inserting \\"%s\\" to vector", entry->st_symnm);
	DEBUG (100, " %d\\n", hash(entry->st_symnm));
	if ((list = Symtab[(key = hash(entry->st_symnm))]) == NULL) {
		/* vector was empty */
		Symtab[key] = entry;
		return (entry);
	}

	/* Find the end of the list */
	do {
		eolist = list;
		list = list->st_next;
	} while (list != NULL);

	/* Do the actual insert */
	eolist->st_next = entry;
	return (entry);
}

/* newent
 * This routine creates and initializes to NULL's a symbol table entry.
 *
 * Returns:
 *	NULL on error (malloc failed)
 *	pointer to an initialized entry on success
 */

struct stab *newent()
{
	extern char *calloc();

	return ((struct stab *)calloc(1, sizeof(struct stab)));
}

/* The following routines and global variables are for use when dumping
 * the symbol table.
 */

static int vec;				/* Which vector we are currently on */
static struct stab *stent;		/* Which entry we are on */

/* sstab
 *
 * Set up to dump the table. Zero the globals.
 *
 * RETURNS:
 *	nothing
 */

void sstab ()
{

	vec = 0;
	while (vec < SYMVECSIZ && Symtab[vec] == NULL)
		++vec;
	stent = Symtab[vec];
}

/* nxtent
 *
 * Return the next entry in the table. Does not return reserved words or
 * directives.
 *
 * RETURNS:
 *	A symbol table entry on success
 *	NULL if the table is empty
 */

struct stab *nxtent ()
{
	struct stab *tmp;

	while (vec < SYMVECSIZ) {
		while (stent != NULL) {
			if (!(stent->st_type & TYRSRVD ||
			    stent->st_type & TYDIR)) {
				tmp = stent;
				stent = stent->st_next;
				return (tmp);
			}
			stent = stent->st_next;
		}
		++vec;
		stent = Symtab[vec];
	}

	/* Oops, all done */
	return (NULL);
}
//*FUNKYSTUFF*//
echo extracting lex.lex
cat << //*FUNKYSTUFF*// > lex.lex
%{
#include "TIasm.h"
#include "y.tab.h"

extern int Lincnt;
extern int Debug;
extern flag Ferror;
extern flag Error;
extern struct stab *lookup(), *newsym();
extern void aabort();
%}

%%
\\"[^\\"\\n]*	{
		/* Special operators in string possibly */
		if (yytext[yyleng - 1] == '\\\\')
			yymore();
		else {
			if ((yytext[yyleng++] = input()) == '\\n')
				unput(yytext[--yyleng]);
			yytext[yyleng++] = NULL;
		}
		DEBUG (11, "Lex finds string \\"%s\\"\\n", yytext);
		return (STRING);
	}

[\\t ]*	/* Eat white space. This goes after the string stuff so
	 * we don't eat white space inside the string.
	 */
		;

"\\n"		++Lincnt;

[rR][0-9]+ {
		DEBUG (11, "lex finds register \\"%s\\"\\n", yytext);
		switch (atoi(&yytext[1])) {
		    case 0:
				yylval.val = 0;
				return (REG);
				/* NOTREACHED */
				break;
		    case 1:
				yylval.val = 1;
				return (REG);
				/* NOTREACHED */
				break;
		    case 2:
				yylval.val = 2;
				return (REG);
				/* NOTREACHED */
				break;
		    case 3:
				yylval.val = 3;
				return (REG);
				/* NOTREACHED */
				break;
		    case 4:
				yylval.val = 4;
				return (REG);
				/* NOTREACHED */
				break;
		    case 5:
				yylval.val = 5;
				return (REG);
				/* NOTREACHED */
				break;
		    case 6:
				yylval.val = 6;
				return (REG);
				/* NOTREACHED */
				break;
		    case 7:
				yylval.val = 7;
				return (REG);
				/* NOTREACHED */
				break;
		    case 8:
				yylval.val = 8;
				return (REG);
				/* NOTREACHED */
				break;
		    case 9:
				yylval.val = 9;
				return (REG);
				/* NOTREACHED */
				break;
		    case 10:
				yylval.val = 10;
				return (REG);
				/* NOTREACHED */
				break;
		    case 11:
				yylval.val = 11;
				return (REG);
				/* NOTREACHED */
				break;
		    case 12:
				yylval.val = 12;
				return (REG);
				/* NOTREACHED */
				break;
		    case 13:
				yylval.val = 13;
				return (REG);
				/* NOTREACHED */
				break;
		    case 14:
				yylval.val = 14;
				return (REG);
				/* NOTREACHED */
				break;
		    case 15:
				yylval.val = 15;
				return (REG);
				/* NOTREACHED */
				break;
		    default:
				/* It isn't a register. Try something else. */
				REJECT;
				break;
		}
	};

[+\\-]0[xX][0-9a-fA-F]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: +/- hexnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for +/- hexnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

0[xX][0-9a-fA-F]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: hexnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for hexnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[+\\-]0[oO][0-7]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: +/- octnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for +/- octnum\\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

0[oO][0-7]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: octnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for octnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[+\\-]0[bB][01]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: +/- binnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for +/- binnum\\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

0[bB][01]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: binnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for binnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[+\\-][dD][0-9]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: +/- decnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: err for +/- decnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[dD][0-9]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: decnum = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for decnum \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[0-9]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: undcl num = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for undcl num\\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

[+\\-][0-9]+ {
		yylval.val = getnum(yytext);
		DEBUG (11, "lex: +/- undcl num = %d\\n", yylval.val);
		if (Error == TRUE) {
			DEBUG (12, "lex: error for +/- undcl \\"%s\\"\\n", yytext);
			return (ERROR);		/* Will cause syntax error */
		}
		return (NUMBER);
	}

";"	{
		/* Eat comments */
		while (input() != '\\n')
			;
		unput ('\\n');
	};

"'"."'"	{
		yylval.val = (short )yytext[1];
		return (NUMBER);
	};

[+-]"'"."'" {
		yylval.val = (short )yytext[2];
		if (yytext[0] == '-')
			/* Make negative in that case */
			yylval.val *= -1;
		return (NUMBER);
	};

"."[_a-zA-Z][\\-_a-zA-Z0-9]* {
		struct stab *Entry;

		DEBUG (11, "lex: directive ===== \\"%s\\"\\n", yytext);
		if ((Entry = lookup(yytext)) == NULL) {
			/* No such directive */
			DEBUG (12, "lex: No directive \\"%s\\"\\n", yytext);
			return (ERROR);
		}
		return (Entry->st_opc);
		}

[_a-zA-Z][\\-_a-zA-Z0-9]* {
		extern struct stab *lookup();

		if ((yylval.sinfo.pntr = lookup(yytext)) == NULL) {
			/* Create the symbol table entry for this ident */
			yylval.sinfo.pntr = newsym (yytext);
			yylval.sinfo.pntr->st_type = TYLCLID;
			yylval.sinfo.enterd = FALSE;
			DEBUG (11, "lex creates \\"%s\\"\\n", yytext);
			return (IDENT);
		} else {
			if (yylval.sinfo.pntr->st_type & TYRSRVD) {
				/* This is a reserved word. Return the format */
				DEBUG (11, "lex returns RSRVD fmt = %d\\n",
				    yylval.sinfo.pntr->st_fmt);
				return (yylval.sinfo.pntr->st_fmt);
			}
			if (yylval.sinfo.pntr->st_type & TYLCLID
			    || yylval.sinfo.pntr->st_type & TYEXTID) {
				DEBUG (11, "lex returns LCL or EXTNL IDENT\\n",
				    NULL);
				yylval.sinfo.enterd = TRUE;
				return (IDENT);
			}
			DEBUG (11, "ERR: stab, name = \\"%s\\"\\n",
			    yylval.sinfo.pntr->st_symnm);
			DEBUG (11, "ERR: stab, type = 0o%o\\n",
			    yylval.sinfo.pntr->st_type);
			aabort ("lex: Null stab ent");
		}
	};

\\,	{ return (','); }

\\:	{ return (':'); }

\\(	{ return ('('); }

\\)	{ return (')'); }

\\[	{ return ('['); }

\\]	{ return (']'); }

\\+	{ return ('+'); }

.	{ return (ERROR); }

%%
//*FUNKYSTUFF*//
echo extracting main.c
cat << //*FUNKYSTUFF*// > main.c
#include "TIasm.h"
#include <stdio.h>
#include "mio.h"

/* Globals */
flag	Ferror;				/* To flag an error in assembly */
int	Lincnt = 1;			/* To count the lines in the source */
struct stab *Entry;			/* Current symbol table entry */
int	Debug;				/* debug flag */
int	Ofd;				/* Object file descriptor */
char	objtfl[40];			/* Temp file for object */
extern short lcctr;			/* The (re)location counter */

main(argc, argv)
int	argc;
char	*argv[];
{
	char *tmp;
	int x;
	int fcnt = 0;
	int fd;
	char *outfil;
	struct format header;
	struct stab *ent;
	struct symbol symb;
	struct a_lst *atmp;
	extern void resrv();
	extern yydebug;
	extern debug;
	extern struct stab *nxtent();
	extern Sdvec[];

	argv[argc] = NULL;

	umask (0111);				/* No execute bit set */

	/* Parse switches */
	for (x = 1; x < argc - 1; ++x)
		if (*(tmp = argv[x]) != '-')
			/* Should have been handled by the front end */
			aabort ("Non-switch");
		else {
			++tmp;
			while (*tmp != NULL)
				switch (*tmp++) {

				    case 'd':
					++x;
					Debug = atoi(argv[x]);
					break;
				    case 'o':
					++x;
					outfil = argv[x];
					break;
				    default:
					aabort ("Unrecognized switch\\n");
				}
		}

	if ((Ofd = xcreat(outfil, 0777)) < 0)
		aabort ("Cannot create output file");
	xwrite (Ofd, header, sizeof(header));

	resrv();
	Ferror = FALSE;
	yyparse();

	/* Put the header together */
	header.f_csiz = lcctr;
	header.f_magic = OMAGIC;
	xseek (Ofd, 0L, 0);
	xwrite (Ofd, header, sizeof(header));
	xseek (Ofd, 0L, 2);

	/* Write out the symbol table info */
	sstab();
	while ((ent = nxtent()) != NULL) {
		for (x = 0, atmp = ent->en_lst; atmp != NULL;
		    atmp = atmp->a_next)
			++x;
		if (x == 0)
			continue;
/*		if (ent->st_type & TYEXTID)
			x *= -1;
*/

		strncpy (symb.s_symnm, ent->st_symnm, IDENTSIZ);
		symb.s_flags = ent->st_type;
		symb.s_raddr = ent->en_addr;

		/* Cheaper to count */
		symb.s_naddr = (short )x;
		xwrite (Ofd, symb, sizeof(symb));

		for (atmp = ent->en_lst; atmp != NULL; atmp = atmp->a_next) {
			DEBUG (10, "\\"%s\\" ref'd at ", symb.s_symnm);
			DEBUG (10, "0x%x\\n", atmp->a_addr);
			xwrite (Ofd, atmp->a_addr, sizeof(atmp->a_addr));
		}
	}
}
//*FUNKYSTUFF*//
echo extracting parse.y
cat << //*FUNKYSTUFF*// > parse.y
%start list

%{
#include "TIasm.h"
#include <stdio.h>
#include "mio.h"

short	isbuf;				/* A place to build object */
short	lcctr = 0;			/* The relocation counter */

extern int Ofd;				/* The object file */
extern FILE *Sdvec[];			/* For doing our funny I/O */

extern char yytext[];
extern int yyleng;

extern flag Ferror;
extern flag Error;
extern int Debug;

%}

%union	{
	short	val;				/* Any old integer */
	struct p {				/* Pointer to a stab ent */
		struct stab *pntr;
		flag enterd;
	} sinfo;
	struct infop opspec;			/* Operand spec info */
}

%token  <sinfo>		OPTYP1	1
%token	<sinfo>		OPTYP2	2
%token	<sinfo>		OPTYP3	3
%token	<sinfo>		OPTYP4	4
%token	<sinfo>		OPTYP5	5
%token	<sinfo>		OPTYP6	6
%token	<sinfo>		OPTYP7	7
%token	<sinfo>		OPTYP8	8
%token	<sinfo>		OPTYP9	9
%token	<sinfo>		OPTYP10	10
%token	<sinfo>		OPTYP11	11
%token	<val>		STRINGDIR
%token	<val>		EXTNLDIR
%token	<val>		WORDDIR
%token	<val>		DATADIR
%token	<val>		REG
%token	<sinfo>		IDENT
%token	<val>		STRING
%token	<val>		NUMBER
%token	<val>		ERROR

%type	<opspec>	mopnd
%type	<val>		pcrel
%type	<val>		indir
%type	<val>		iauto
%type	<opspec>	symbol
%type	<opspec>	isymb
%type	<sinfo>		ident

%%

list	:	/* EMPTY */
			{
			DEBUG (10, "list -> EMPTY\\n", NULL);
			DEBUG (10, "lcctr = 0X%x\\n", lcctr);
			}
	|	list line
			{
			DEBUG (10, "list -> list line\\n", NULL);
			DEBUG (10, "lcctr = 0X%x\\n", lcctr);
			}
	|	error
			{
			DEBUG (10, "list -> error\\n", NULL);
			DEBUG (10, "lcctr = 0X%x\\n", lcctr);
			}
	;

line	:	ident ':'
			{
			struct j_lst *tptr, *t2ptr;
			unsigned tmp;

			DEBUG (10, "line -> ident ':'\\n", NULL);
			/* The ONLY place an address may be resolved is here */
			if (\$1.pntr->st_type & TYRSLVD) {
				yyerror ("Redeclaration error");
				YYERROR;
			}
			\$1.pntr->st_type |= TYRSLVD;
			\$1.pntr->en_addr = lcctr;
			DEBUG (9, "Resolving \\"%s\\"", \$1.pntr->st_symnm);
			DEBUG (9, " to addr 0X%x\\n", \$1.pntr->en_addr);

			/* Now resolve jumps and make these patches */
			for (tptr = \$1.pntr->en_jl; tptr != NULL; ) {
				DEBUG (9, "Resolving jumps, addr = 0x%x\\n",
				    tptr->j_addr);
				DEBUG (9, "0x%x - ", lcctr);
				DEBUG (9, "0x%x / 2 = ", tptr->j_addr);
				DEBUG (9, "0x%x\\n", (lcctr - tptr->j_addr) / 2);
				/* We KNOW this is a forward reference so
				 * we can just make the following subtraction.
				 */
				if ((tmp = (lcctr - tptr->j_addr) / 2) > 0x7f) {
					yyerror ("Jump target out of range");
					
				} else {
					/* Offset size of execute header */
					xseek (Ofd, (long )tptr->j_addr
					    + sizeof(struct format) - 1, 0);
					xwrite (Ofd, tmp, 1);
					xseek (Ofd, (long )0, 2);
				}
				t2ptr = tptr;
				tptr = tptr->j_next;
				rmjinf (t2ptr);
			}
			/* It is possible to trip through the above loop
			 * again. So......
			 */
			\$1.pntr->en_jl = NULL;
			}
	|	stmnt
			{
			DEBUG (10, "line -> stmnt\\n", NULL);
			}

	;

stmnt	:	OPTYP1	mopnd ',' mopnd
			{
			DEBUG (10, "stmnt -> OPTYP1 mopnd ',' mopnd\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			/* Source */
			isbuf |= ((0x3 & \$2.t) << 4);
			isbuf |= (0xf & \$2.r);
			/* Destination */
			isbuf |= ((0x3 & \$4.t) << 10);
			isbuf |= ((0xf & \$4.r) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & SYMTAG) {
				if (\$2.in_tag & RELOCATABLE)
					adrinf(\$2.in_stb, lcctr);
				lcctr += sizeof(\$2.in_loc);
				xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			} if (\$4.in_tag & SYMTAG) {
				if (\$4.in_tag & RELOCATABLE)
					adrinf(\$4.in_stb, lcctr);
				lcctr += sizeof(\$4.in_loc);
				xwrite (Ofd, \$4.in_loc, sizeof(\$4.in_loc));
			}
			}
	|	OPTYP2	pcrel
			{
			DEBUG (10, "fmt2 -> OPTYP2 pcrel\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			isbuf |= (0xff & \$2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP2 symbol
			{
			int tmp;

			DEBUG (10, "fmt2 -> OPTYP2 symbol\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			if (\$2.in_stb->st_type & TYRSLVD) {
				DEBUG (9, "fmt2: Label resolved do jump now\\n",
				    NULL);
				/* This reference is definately rearward
				 * so the following is legal.
				 */
				tmp = (\$2.in_stb->en_addr - lcctr - 2) / 2;
				if ( tmp < -0x7f) {
					yyerror ("Jump target out of range");
					YYERROR;
				} else
					isbuf |= (0xff & (unsigned )tmp);
			} else {
				DEBUG (9, "fmt2: Not resolved, save addr\\n",
				    NULL);
				adjinf (\$2.in_stb, lcctr + 1);
			}
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP3	mopnd ',' REG
			{
			DEBUG (10, "fmt3 -> OPTYP3 mopnd ',' REG\\n",  NULL);
			isbuf = \$1.pntr->st_opc;
			/* source */
			isbuf |= ((0x3 & \$2.t) << 4);
			isbuf |= (0xf & \$2.r);
			/* Destination register */
			isbuf |= ((0xf & \$4) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & SYMTAG) {
				if (\$2.in_tag & RELOCATABLE)
					adrinf(\$2.in_stb, lcctr);
				lcctr += sizeof(\$2.in_loc);
				xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			}
			}
	|	OPTYP4	mopnd ',' NUMBER
			{
			DEBUG (10, "fmt4 -> OPTYP4 mopnd ',' NUMBER\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			/* Register */
			isbuf |= ((0x3 & \$2.t) << 4);
			isbuf |= (0xf & \$2.r);
			/* count */
			if (\$4 < 0) {
				yyerror("transfer/shift count < 0");
				YYERROR;
			}
			if (\$4 > 0xf) {
				yyerror ("transfer/shift count > 0xf");
				YYERROR;
			}
			isbuf |= ((0xf & \$4) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & SYMTAG) {
				if (\$2.in_tag & RELOCATABLE)
					adrinf(\$2.in_stb, lcctr);
				lcctr += sizeof(\$2.in_loc);
				xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			}
			}
	|	OPTYP5	REG ',' NUMBER
			{
			DEBUG (10, "fmt5 -> OPTYP5 REG ',' NUMBER\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			/* register */
			isbuf |= (0xf & \$2);
			/* Count/shift */
			if (\$4 < 0) {
				yyerror("transfer/shift count < 0");
				YYERROR;
			}
			if (\$4 > 0xf) {
				yyerror("transfer/shift count > 0xf");
				YYERROR;
			}
			isbuf |= ((0xf & \$4) << 4);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP6	mopnd
			{
			DEBUG (10, "fmt6 -> OPTYP6 mopnd\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			/* Source */
			isbuf |= ((0x3 & \$2.t) << 4);
			isbuf |= (0xf & \$2.r);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & SYMTAG) {
				if (\$2.in_tag & RELOCATABLE)
					adrinf (\$2.in_stb, lcctr);
				lcctr += sizeof(\$2.in_loc);
				xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			}
			}
	|	OPTYP7
			{
			DEBUG (10, "fmt7 -> OPTYP7\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP8	REG ',' symbol
			{
			DEBUG (10, "fmt8 -> OPTYP8 REG ',' symbol\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			/* Destination */
			isbuf |= (0xf & \$2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			/* Source */
			if (\$4.in_tag & RELOCATABLE)
				adrinf (\$4.in_stb, lcctr);
			lcctr += sizeof(\$4.in_loc);
			xwrite (Ofd, \$4.in_loc, sizeof(\$4.in_loc));
			}
	|	OPTYP9	mopnd ',' NUMBER
			{
			DEBUG (10, "OPTYP9 mopnd ',' NUM (%d)\\n", \$4);
			isbuf = \$1.pntr->st_opc;
			/* Destination register */
			isbuf |= ((0xf & \$4) << 6);
			/* Source */
			isbuf |= ((0x3 & \$2.t) << 4);
			isbuf |= (0xf & \$2.r);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & SYMTAG) {
				if (\$2.in_tag & RELOCATABLE)
					/* Enter it to the list of addrs.
					 * So, there is garbage in the slot;
					 * We need to reserve space for the
					 * patch anyway. Who cares what is in
					 * there?
					 */
					adrinf(\$2.in_stb, lcctr);
				lcctr += sizeof(\$2.in_loc);
				xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			}
			}
	|	OPTYP10 symbol
			{
			DEBUG (10, "stmnt -> OPTYP10\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if (\$2.in_tag & RELOCATABLE)
				adrinf (\$2.in_stb, lcctr);
			lcctr += sizeof(\$2.in_loc);
			xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			}
	|	OPTYP11 REG
			{
			DEBUG (10, "stmnt -> OPTYP11\\n", NULL);
			isbuf = \$1.pntr->st_opc;
			isbuf |= (0xf & \$2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	dirctv
			{
			DEBUG (10, "stmnt -> dirctv\\n", NULL);
			}
	;
dirctv	:	STRINGDIR STRING
			{
			char null = NULL; /* Will want address, so.... */

			DEBUG (10, "dirctv -> STRINGDIR STRING\\n", NULL);
			dostr (yytext, &yyleng);
			if (Error == TRUE) {
				yyerror ("Illegal meta-character(s) in string");
				YYERROR;
			}
			lcctr += yyleng;
			/* The I/O macros force this..... BE CAREFUL if
			 * you change them!
			 */
			xwrite (Ofd, yytext[0], yyleng);
			/* If odd length, then align */
			if (odd(yyleng)) {
				lcctr += 1;
				xwrite (Ofd, null, 1);
			}
			}

	|	EXTNLDIR ident
			{
			DEBUG (10, "dirctv -> EXTNLDIR ident\\n", NULL);
			\$2.pntr->st_type |= TYEXTID;
			}
	|	WORDDIR NUMBER
			{
			short awrd;
			short x;

			DEBUG (10, "dirctv -> WORDDIR number\\n", NULL);
			lcctr += \$2 * 2;
			for (x = 0; x < \$2; ++x)
				xwrite (Ofd, awrd, sizeof(awrd));
			}
	|	WORDDIR
			{
			short awrd;

			DEBUG (10, "dirctv -> WORDDIR\\n", NULL);
			lcctr += 2;
			xwrite (Ofd, awrd, sizeof(awrd));
			}
	|	DATADIR symbol
			{
			DEBUG (10, "dirctv -> DATADIR symbol\\n", NULL);
			xwrite (Ofd, \$2.in_loc, sizeof(\$2.in_loc));
			if (\$2.in_tag & RELOCATABLE)
				adrinf (\$2.in_stb, lcctr);
			lcctr += 2;
			}
	;

mopnd	:	REG
			{
			DEBUG (10, "mopnd -> REG\\n", NULL);
			\$$.t = 0;
			\$$.r = \$1;
			\$$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	|	iauto
			{
			DEBUG (10, "mopnd -> iauto\\n", NULL);
			\$$.t = 03;
			\$$.r = \$1;
			\$$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	|	isymb
			{
			DEBUG (10, "mopnd -> isymb\\n", NULL);
			\$$ = \$1;
			\$$.t = 02;
			/* Register to index off of is already set */
			}
	|	symbol
			{
			DEBUG (10, "mopnd -> symbol\\n", NULL);
			\$$ = \$1;
			\$$.t = 02;
			\$$.r = 0;		/* Force non-indexed */
			}
	|	indir
			{
			DEBUG (10, "mopnd -> indir\\n", NULL);
			\$$.t = 01;
			\$$.r = \$1;
			\$$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	;

pcrel	:	'\$'
			{
			DEBUG (10, "pcrel -> '\$'\\n", NULL);
			\$$ = lcctr;
			}
	|	'\$' '+' NUMBER
			{
			DEBUG (10, "pcrel -> '\$' '+' NUMBER\\n", NULL);
			\$$ = lcctr + \$3;
			/* Check signed 8 bit jump range */
			if (abs(\$$) > 0x7f) {
				yyerror ("Jump target out of range");
				YYERROR;
			}
			}
	|	'\$' '-' NUMBER
			{
			DEBUG (10, "pcrel -> '\$' '-' NUMBER\\n", NULL);
			\$$ = lcctr - \$3;
			/* Check signed 8 bit jump range */
			if (abs(\$$) > 0xff) {
				yyerror ("Jump out of range");
				YYERROR;
			}
			}
	;

indir	:	'(' REG ')'
			{
			DEBUG (10, "indir -> '(' REG ')'\\n", NULL);
			\$$ = \$2;
			}
	;

iauto	:	'(' REG ')' '+'
			{
			DEBUG (10, "iauto -> '(' REG ')' '+'\\n", NULL);
			\$$ = \$2;
			}
	;

isymb	:	symbol '[' REG ']' 
			{
			DEBUG (10, "isymb -> symbol '[' REG ']'\\n", NULL);
			/* The identifier/absolute address */
			\$$ = \$1;
			\$$.r = \$3; /* Change this field to reflect indexed */
			}
	;

symbol	:	ident
			{
			DEBUG (10, "symbol -> ident\\n",  NULL);
			/* The identifier is entered into the relocation
			 * table already.
			 */
			\$$.in_tag = SYMTAG | RELOCATABLE;
			\$$.in_stb = \$1.pntr;
			}
	|	NUMBER
			{
			DEBUG (10, "symbol -> NUMBER\\n", NULL);
			/* An absolute address */
			\$$.in_tag |= SYMTAG & ~RELOCATABLE;
			\$$.in_loc = \$1;
			}
	;

ident	:	IDENT
			{
			/* This way so that we can enter it into the
			 * relocation table here
			 */
			extern struct stab *insert();

			DEBUG (10, "ident -> IDENT; name = %s\\n",
			    \$1.pntr->st_symnm);
			if (\$1.enterd != TRUE) {
				/* Mark it as entered */
				\$1.enterd = TRUE;
				/* And, enter it */
				if (insert(\$1.pntr) == NULL)
					aabort ("Symbol table overflow\\n");
			}
			\$$ = \$1;
			}
	;

%%

/* yyerror
 * The assemblers error reporting, flagging, clearing routine.
 *
 * Returns:
 *	Nothing, though for consistency it must be declared int
 */

int yyerror (string)
char	*string;
{
	char	c;
	extern flag Ferror;
	extern int Lincnt;
	fprintf (stderr, "%d: %s\\n", Lincnt, string);
/*
	while ((c = input()) != '\\n' && c != 0)
		;
	unput(c);
*/
	Ferror = TRUE;
}
//*FUNKYSTUFF*//
echo extracting rsrvd.c
cat << //*FUNKYSTUFF*// > rsrvd.c
#include "TIasm.h"
#include "opcodes.h"
#include "y.tab.h"
#include <stdio.h>

/* Actual opcodes for the machine */

struct ops Optab[] = {
	"LI",	LI,	8,
	"AI",	AI,	8,
	"ANDI",	ANDI,	8,
	"ORI",	ORI,	8,
	"CI",	CI,	8,
	"STWP",	STWP,	11,
	"STST",	STST,	11,
	"LWPI",	LWPI,	10,
	"LIMI",	LIMI,	10,
	"IDLE",	IDLE,	7,
	"RSET",	RSET,	7,
	"RTWP",	RTWP,	7,
	"CKON",	CKON,	7,
	"CKOF",	CKOF,	7,
	"LREX",	LREX,	7,
	"BLWP",	BLWP,	6,
	"B",	B,	6,
	"X",	X,	6,
	"CLR",	CLR,	6,
	"NEG",	NEG,	6,
	"INV",	INV,	6,
	"INC",	INC,	6,
	"INCT",	INCT,	6,
	"DEC",	DEC,	6,
	"DECT",	DECT,	6,
	"BL",	BL,	6,
	"SWPB",	SWPB,	6,
	"SETO",	SETO,	6,
	"ABS",	ABS,	6,
	"SRA",	SRA,	5,
	"SRL",	SRL,	5,
	"SLA",	SLA,	5,
	"SRC",	SRC,	5,
	"JMP",	JMP,	2,
	"JLT",	JLT,	2,
	"JLE",	JLE,	2,
	"JEQ",	JEQ,	2,
	"JHE",	JHE,	2,
	"JGT",	JGT,	2,
	"JNE",	JNE,	2,
	"JNC",	JNC,	2,
	"JOC",	JOC,	2,
	"JNO",	JNO,	2,
	"JL",	JL,	2,
	"JH",	JH,	2,
	"JOP",	JOP,	2,
	"SBO",	SBO,	2,
	"SBZ",	SBZ,	2,
	"TB",	TB,	2,
	"COC",	COC,	3,
	"CZC",	CZC,	3,
	"XOR",	XOR,	3,
	"LDCR",	LDCR,	4,
	"STCR",	STCR,	4,
	"MPY",	MPY,	3,
	"DIV",	DIV,	3,
	"SZC",	SZC,	1,
	"SZCB",	SZCB,	1,
	"S",	S,	1,
	"SB",	SB,	1,
	"C",	C,	1,
	"CB",	CB,	1,
	"A",	A,	1,
	"AB",	AB,	1,
	"MOV",	MOV,	1,
	"MOVB",	MOVB,	1,
	"SOC",	SOC,	1,
	"SOCB",	SOCB,	1,
	"XOP",	XOP,	9,
	NULL,	0,	0,
};

/* Directives */
struct ops Dirtab[] = {
	".str",		STRINGDIR,	STRINGDIR,
	".extern",	EXTNLDIR,	EXTNLDIR,
	".word",	WORDDIR,	WORDDIR,
	".data",	DATADIR,	DATADIR,
	NULL,		0,		0,
};
//*FUNKYSTUFF*//
echo extracting tiasm.c
cat << //*FUNKYSTUFF*// > tiasm.c
#include <stdio.h>
#include "TIasm.h"

int	Debug;

main (argc,argv)
int	argc;
char	*argv[];
{
	char **avec, *arg;
	FILE *isd, *psd;
	int x, filcnt = 0;
	char *tmp, *fpart;
	char c;
	char cbuf[BUFSIZ], swbuf[BUFSIZ], *fvec[BUFSIZ];
	char *rindex();
	FILE *popen();
	flag skippit = FALSE;

	avec = &argv[1];
	while (*avec != NULL)
		if (**avec != '-')
			fvec[filcnt++] = *avec++;
		else {
			arg = *avec++;
			while (*++arg != NULL)

				switch (*arg) {
				    case 'd':		/* Debug */
					strcat (swbuf, "-d ");
					Debug = atoi(*avec);
					strcat (swbuf, *avec++);
					break;
				    default:
					fprintf (stderr, "Unknown switch -%c\\n",
					    *arg);
				}
		}

	sprintf (cbuf, "%s %s -o ", PASS1, swbuf);
	fpart = cbuf + strlen(cbuf);

	for (x = 0; x < filcnt; ++x) {
		/* Look for ".a" and replace by ".o" for output part */
		tmp = rindex(fvec[x], '.');
		if (tmp == NULL || *++tmp != 'a') {
			fprintf (stderr,
			    "%s does not end in \\".a\\", skipping..\\n",
			    fvec[x]);
			skippit = TRUE;
		}

		if ((isd = fopen(fvec[x], "r")) == NULL) {
			fprintf (stderr,
			    "Cannot open %s, skipping...\\n",
			    fvec[x]);
			skippit = TRUE;
		}

		if (skippit == TRUE)
			skippit = FALSE;
		else {
			*tmp = 'o';

			/* Now to find basename so we leave output here */
			tmp = rindex(fvec[x],'/');
			tmp = tmp != NULL ? tmp + 1: fvec[x];

			*fpart = NULL;
			strcat (fpart, tmp);
			DEBUG (1, "%s\\n", cbuf);
			if ((psd = popen(cbuf, "w")) == NULL) {
				fprintf (stderr,
				    "Cannot popen pass1, aborting\\n");
				exit (1);
			}
			/* Now give pass1 the file */
			while ((c = fgetc(isd)) != EOF)
				if (fputc(c, psd) == EOF) {
					fprintf (stderr,
					    "I/O error, aborting\\n");
					exit (1);
				}
			fclose (isd);
			pclose (psd);
		}
	}
}
//*FUNKYSTUFF*//
echo extracting util.c
cat << //*FUNKYSTUFF*// > util.c
#include <stdio.h>
#include "TIasm.h"

extern flag Debug;
flag	Error;				/* To indicate an error for routines
					 * that can't pass back bad values
					 */

/* getnum
 * Based on certain format specifiers in the string (which have already
 * been validated) convert a character representation to a number no larger
 * than a 16 bit word. Overflow is checked.
 *
 * Returns:
 *	0 on error
 *	the internal representation on success
 *
 * Note:
 *	A possible abort.
 */

short getnum (string)
char	*string;
{
	flag fminus = FALSE;			/* number should be negative */
	flag radix = 10;			/* radix to interpret number */
	short ac;				/* An accumulator */
	short tmp;				/* A temporary */
	extern flag Error;
	void aabort();
	void yyeror();

	if (*string == '-') {
		fminus = TRUE;
		++string;
	} else
		if (*string == '+')
			++string;

	/* Next char is a '0'? Then it is a literal specification */
	if (*string == '0' && *(string + 1) != NULL) {
		++string;

		/* Next is the radix of the number */
		switch (*string++) {
	    	case 'o':
	    	case 'O':
				radix = 8;
				break;
	    	case 'x':
	    	case 'X':
				radix = 16;
				break;
	    	case 'b':
	    	case 'B':
				radix = 2;
				break;
	    	case 'D':
	    	case 'd':
				radix = 10;
				break;
	    	default:
				/* Number starts with a zero but has
				 * no declerator. Assume octal.
				 */
				radix = 8;
				--string;	/* Adjust string */
				break;
				/*NOTREACHED*/
		}
	}

	/* Ok, now get the number performing radix "conversion" in a portable
	 * (non character dependent) manner. Hey, check for overflow too!
	 */
	ac = 0;
	while (*string != NULL) {
		ac *= radix;
		switch (*string++) {
		    case '0':
			tmp = 0;
			break;
		    case '1':
			tmp = 1;
			break;
		    case '2':
			tmp = 2;
			break;
		    case '3':
			tmp = 3;
			break;
		    case '4':
			tmp = 4;
			break;
		    case '5':
			tmp = 5;
			break;
		    case '6':
			tmp = 6;
			break;
		    case '7':
			tmp = 7;
			break;
		    case '8':
			tmp = 8;
			break;
		    case '9':
			tmp = 9;
			break;
		    case 'a':
		    case 'A':
			tmp = 10;
			break;
		    case 'b':
		    case 'B':
			tmp = 11;
			break;
		    case 'c':
		    case 'C':
			tmp = 12;
			break;
		    case 'd':
		    case 'D':
			tmp = 13;
			break;
		    case 'e':
		    case 'E':
			tmp = 14;
			break;
		    case 'f':
		    case 'F':
			tmp = 15;
			break;
		    default:
			/* This CANNOT happen! */
			aabort ("getnum2");
			/*NOTREACHED*/
			break;
		}
		/* Magic number is MAXINT for 16 bit word size */
		if (tmp > 0xffff - ac ) {
			yyerror ("literal greater than word size");
			Error = TRUE;
			return (0);
		}
		ac += tmp;
	}

	/* Negative number? */
	if (fminus == TRUE)
		ac *= -1;

	return (ac);
}

/* adjinf
 *
 * Add an address  that is a jump instruction's target. These lists in the
 * symbol table entries will hold ONLY forward references to save on
 * space.
 *
 * RETURNS:
 *	nothing
 *
 * NOTE: May abort if the malloc fails.
 */

void adjinf (stab, loc)
struct stab *stab;
short	loc;
{
	struct j_lst *jinfo;
	extern char *malloc();

	if ((jinfo = (struct j_lst *)malloc(sizeof(struct j_lst))) == NULL)
		aabort ("adjinf: no mem!");
	jinfo->j_addr = loc;
	jinfo->j_next = stab->en_jl;
	stab->en_jl = jinfo;
}

/* The translation table for escaped characters */
char ctab[] = {
	'\\a', '\\b', '\\c', '\\d', '\\e', '\\f', '\\g', '\\h', '\\i', '\\j',
	'\\k', '\\l', '\\m', '\\n', '\\o', '\\p', '\\q', '\\r', '\\s', '\\t',
	'\\u', '\\v', '\\w', '\\x', '\\y', '\\z', 0
};

/* dostr
 * Interpret a string directives argument.
 *
 * RETURNS:
 *
 *	modified buf arg
 *	new length of string (by reference)
 *
 * Note: Error may be set here for an illegal meta-character
 */

void dostr (buf, leng)
char	buf[];
int	*leng;
{
	char null = NULL;
	char *tmp, *begin;
	extern int Ofd;
	extern FILE *Sdvec[];


	tmp = begin = buf;

	/* Find first quote */
	while (*tmp++ != '"')
		;
	/* Now transfer characters to the start of buf and interpret
	 * special characters as we go.
	 */
	while (*tmp != '"' && *tmp != NULL)
		if (*tmp == '\\\\') {
			++tmp;
			if (*tmp >= 'a' && *tmp <= 'z')
				*begin++ = ctab[*tmp++ - 'a'];
			else switch (*tmp) {

			    case '\\\\':
			    case '"':
				*begin++ = *tmp++;
			    default:
				Error = TRUE;
			}
		} else {
			*begin++ = *tmp++;
		}
	/* Null terminate */
	*begin = NULL;

	/* Find new length */
	*leng = begin - buf;
}

/* resrv
 * make the entries in the tables reserved. They may NOT be declared again.
 *
 * Returns:
 *	Nothing
 *
 * NOTE:
 *	May abort if any errors occur loading the symbol table
 */

void resrv()
{
	register struct stab *entry;
	register struct ops *tptr;
	register char *ctmp;
	extern struct stab *newent(), *insert();
	extern struct ops Optab[];
	extern void aabort(), initab();
	extern struct ops Dirtab[];

	initab();			/* Init the symbol table */
	/* First the opcodes as they will be accessed most often.
	 * Use pointers for speed.
	 */
	tptr = Optab;
	while ((ctmp = tptr->op_name) != NULL) {
		if((entry = newent()) == NULL)
			aabort ("Symbol table overflow\\n");
		strcpy(entry->st_symnm, ctmp);
		entry->st_type = TYRSRVD;
		entry->st_opc = tptr->op_code;
		entry->st_fmt = tptr->op_fmt;
		if (insert (entry) == NULL)
			aabort ("reserv: Could not insert\\n");
		++tptr;				/* Get next entry */
	}

	/* Now, the directives */
	tptr = Dirtab;
	while ((ctmp = tptr->op_name) != NULL) {
		if((entry = newent()) == NULL)
			aabort ("Symbol table overflow\\n");
		strcpy(entry->st_symnm, ctmp);
		entry->st_type = TYDIR;
		entry->st_opc = tptr->op_code;
		entry->st_fmt = tptr->op_fmt;
		if (insert (entry) == NULL)
			aabort ("rsrv: Could not insert directive");
		++tptr;				/* Get next entry */
	}
}

/* newsym
 * Create and partially initialize a symbol table entry. The entry is
 * NOT inserted here! st_type is left blank so that the parser may determine
 * that it is a new entry and do the insert.
 *
 * Returns:
 *	NUll on error.
 *	The partially initialized entry on success.
 */

struct stab *newsym (ident)
char	*ident;
{
	struct stab *ent;
	extern struct stab *newent();

	if ((ent = newent()) == NULL)
		return (NULL);

	strncpy (ent->st_symnm, ident, IDENTSIZ);
	return (ent);
}
//*FUNKYSTUFF*//
-- 
			--Lee (Ward)
			{ucbvax,convex,gatech,pur-ee}!unmvax!lee