[net.sources] cw sources

ccohesh@ucdavis.UUCP (Hesh) (01/07/86)

#!/bin/sh
: "This is a shell archive, meaning:                              "
: "1. Remove everything above the #! /bin/sh line.                "
: "2. Save the resulting test in a file.                          "
: "3. Execute the file with /bin/sh (not csh) to create the files:"
: "	READ_ME"
: "	Makefile"
: "	cw.h"
: "	getopt.c"
: "	mars.c"
: "	movmem.c"
: "	msg.c"
: "	print.c"
: "	scheduler.c"
: "	sum.c"
: "	vdisplay.c"
: "	vstatus.c"
: "	unrc.c"
: "	cw.6"
: "	rcasm.y"
: "	rcasm.l"
: "	shar"
: "	bdwarf.rc"
: "	dwarf.rc"
: "	fibo.rc"
: "	gemini.rc"
: "	imp.rc"
: "	random.rc"
: "	stomper.rc"
: "This archive created:  Mon Jan 6 21:32:36 PST 1986 "
echo file: READ_ME
sed 's/^X//' >READ_ME << 'END-of-READ_ME'
XThis is the second source distribution of the Core Wars.
X
XSome of the bugs that have been fixed:
X
X	1. unrc.c has been modified to recognize the MUL, DIV
X	   and RND instructions.
X	2. cw.6 had some problems with the tables.  These have
X	   been solved.
X	3. The RND instruction no longer causes a job to halt.
X	4. A bug in the lexical analyzer where the toggle variable
X	   "toggle" wasn't being toggled has been corrected.
X
XFor further reading on the origins and purpose of this system,
Xplease see the the "SEE ALSO" section of the documentation.
X
XPlease send all new bug reports to the author.
X-------------------------------------------------------------------------------
XWed Dec 11 18:26:00 PST 1985
X
XThis is the first source distribution of the game of Core Wars.
XThis game has been tested on BSD4.2 UNIX.  It should run under
Xany UNIX system that has curses, lex and yacc and virtual memory
Xand whose compiler allows bitfields in structures.
XIf your system does not have virtual memory but does have separate
XI and D space, you should insert the appropriate loader options in
Xthe Makefile.  You may also have to decrease "MAX_MEM" and make the
Xcorresponding changes to the bitfield widths.
X
XI think that it would be great if we could have world wide competition
Xplaying this game.  Perhaps people could post their best redcode code
Xto net.sources.games.  Perhaps an unbeatable program might evolve.
X
X			Peter Costantinidis, Jr.
X			...!ucbvax!ucdavis!deneb!ccohesh001
END-of-READ_ME
echo file: Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#
X#	Makefile for Corewar system
X#
X#static	char	rcsid[] = "$Header: Makefile,v 7.0 85/12/28 14:35:38 ccohesh Dist $";
X#
X#	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X#
X#
X#	If you are running under SysV, I am told that you would want to
X#	uncomment the following commented lines.
X#
X#	.SUFFIXES: .rc
X#	.rc:
X#		rcasm $< $@
X
XHDRS	=	Makefile cw.h
XYSRC	=	rcasm.y
XLSRC	=	rcasm.l
XSRCS	=	getopt.c mars.c movmem.c msg.c print.c scheduler.c sum.c\
X		vdisplay.c vstatus.c
XOBJS	=	getopt.o mars.o movmem.o msg.o print.o scheduler.o sum.o\
X		vdisplay.o vstatus.o
XPROGS	=	bdwarf.rc dwarf.rc fibo.rc gemini.rc imp.rc\
X		random.rc stomper.rc
X#
X# libs
X#
XCWLIB	=	cw.a
XCRLIB	=	-lcurses
XTERMLIB	=	-ltermlib
XALLLIBS	=	$(CWLIB) $(CRLIB) $(TERMLIB)
X
X#
X# It has been suggested that FLAGS should include "-DSYS5" when running
X# under SYS5
X#
XFLAGS	=	#-DDEBUG
XCFLAGS	=	-O $(FLAGS)
XLDFLAGS =	-o $@
XLINTARGS=	-ahxc $(DEFS) -DLINT
XSHAR	=	shar
XSHAROUT	=	cw.shar
XALLSRCS	=	$(HDRS) $(SRCS) unrc.c cw.6 $(YSRC) $(LSRC)
XALLEXES	=	rcasm unrc mars
XALL	=	READ_ME $(ALLSRCS) $(CWDOC) $(SHAR)
XCI	=	ci -u
X
XNAME =		mars
X
Xdemo:		mars rcasm
X#
X#	You may want to comment out the "rcasm" lines if
X#	running SysV.
X#
X		rcasm imp.rc imp
X		rcasm dwarf.rc dwarf
X		rcasm gemini.rc gemini
X		rcasm stomper.rc stomper
X		mars -p imp dwarf gemini stomper
X
Xinstall:	mars rcasm unrc cw.nr
X
Xcw.nr:		cw.6
X		tbl cw.6 | nroff -man | col > cw.nr
X
Xmars:		$(CWLIB)
X		cc $(LDFLAGS) $(ALLLIBS)
X
X#
X# RCS stuff
X#
Xci:		$(ALLSRCS)
X		-$(CI) $?
X		@touch ci
Xcoall:
X		co -l $(ALLSRCS)
Xupdate:
X		ci -sDist -u -f$(VERS) $(ALLSRCS)
X		@touch ci
X
Xall:		$(ALLEXES)
X
X$(CWLIB):	$(OBJS)
X		@ar rv $@ $?; ranlib $@
X
X$(OBJS):	$(HDRS)
X
Xrcasm:		rcasm.o $(CWLIB) rcasm.h
X		cc $(LDFLAGS) rcasm.o $(CWLIB) -ll
X
Xrcasm.o:	rcasm.c rcasm.h $(HDRS)
X
Xrcasm.h:	$(LSRC) $(HDRS)
X		$(LEX) $(LFLAGS) $(LSRC)
X		@mv lex.yy.c rcasm.h
X
Xrcasm.c:	$(YSRC) $(HDRS)
X		$(YACC) $(YFLAGS) $(YSRC)
X		@mv y.tab.c rcasm.c
X
Xunrc:		unrc.o $(CWLIB)
X		cc -O $(LDFLAGS) unrc.o $(CWLIB)
X
Xunrc.o:		$(HDRS)
X
Xlint:
X		lint $(LINTARGS) $(SRCS)
X
Xprint:
X		lpr -Pc -p Makefile $(ALLSRC)
X
Xtags:		$(HDRS) $(SRCS)
X		ctags -u $?
X		sort tags -o tags
X
Xwc:
X		wc $(ALLSRCS)
X
Xexport:
X		/bin/sh $(SHAR) $(ALL) $(PROGS) > $(SHAROUT)
X
Xclean:
X		rm $(OBJS) rcasm.c rcasm.h
END-of-Makefile
echo file: cw.h
sed 's/^X//' >cw.h << 'END-of-cw.h'
X/*
X** cw.h	- misc. constants and macros used throughout corewar system
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X*/
X
X/*
X**
Xstatic	char	rcsid[] = "$Header: cw.h,v 7.0 85/12/28 14:35:45 ccohesh Dist $";
X**
X*/
X#include <sys/types.h>		/* necessary for void */
X
X#ifdef	BSD42|BSD43
X#	define	SETJMP	_setjmp
X#	define	LONGJMP	_longjmp
X#else
X#	define	SETJMP	setjmp
X#	define	LONGJMP	longjmp
X#endif
X
X/*
X** curses conflicts
X*/
X#ifndef	WINDOW
X#	define	TRUE	1
X#	define	FALSE	0
X#	undef	reg
X#endif
X
X#ifdef	DEBUG
X#	define	reg
X#else
X#	define	reg	register
X#endif
X
X#ifndef	CTRL
X#	define	CTRL(c)	('c'&037)
X#endif
X#ifndef	CINTR
X#	define	CINTR	CTRL(?)
X#endif
X#define	min(a,b)	((a) < (b) ? (a) : (b))
X#define	max(a,b)	((a) > (b) ? (a) : (b))
X#define	abs(a)		((a) < 0 ? -(a) : (a))
X
X/*
X** Visual display related constants
X*/
X#define	MIN_LINES	24	/* minimum lines allowed in display */
X#define	MIN_COLS	80	/* minimum columns allowed in display */
X
X/*
X** memory window
X*/
X#define	MLINES		16	/* # lines in memwin */
X#define	MCOLS		(MAX_MEM/(MLINES*NUMMEM))/* # columns in memwin */
X#define	MYBEGIN		1	/* y offset in stdscr of memwin */
X#define	MXBEGIN		1	/* x offset in stdscr of memwin */
X
X/*
X** message window
X*/
X#define	MSGLINES	(MIN_LINES-MLINES-2)/* lines in status window */
X#define	MSGCOLS		(MXBEGIN+MCOLS)/* columns in status window */
X#define	MSGYBEGIN	(MYBEGIN+MLINES+1)/* y offset in stdscr of status win */
X#define	MSGXBEGIN	0
X
X/*
X** status window
X*/
X#define	SLINES		MIN_LINES
X#define	SCOLS		(MIN_COLS-MCOLS-2)
X#define	SYBEGIN		0
X#define	SXBEGIN		(MXBEGIN+MCOLS+1)
X
X#define	NUMMEM		PAGESIZE/* # memwords per character in memwin */
X#define	HORTBORDER	'-'	/* horizontal border char for memwin box */
X#define	VERTBORDER	'|'	/* vertical border char for memwin box */
X
X/*
X** misc. characters in memory window
X*/
X#define	MEMPTY	'.'	/* nothing of note about memsect */
X#define	MSHARE	'-'	/* more than one job writing */
X#define	MHIT	'+'	/* hit near a PC */
X#define	MFULL	'*'	/* >=10 PC's in memsect */
X
X/*
X** output controls
X*/
X#define	SIZE_START	0x0001L		/* print size and start of job */
X#define	PASSNUM		0x0002L		/* print current cycle */
X#define	PASSFREQ	10		/* print every n cycles */
X#define	PINST		0x0004L		/* print current instruction */
X#define	VISUAL		0x0008L		/* visual display */
X#define	STATUS		0x0010L		/* status window for v.d. */
X#define	DEF_CTRLS	(VISUAL|STATUS|PINST)
X
X#define	ON(x)		(octrl&(x))
X#define	TOGGLE(x)	octrl=(octrl&x)?(octrl&~x):(octrl|x)
X
X#define	HALTED(j)	(j->pdied)
X#define	PC	_pc
X
X#define	uns		unsigned
X#define	unss		unsigned short
X#define	when		break;case
X#define	otherwise	break;default
X
X#define	RC_OUT		"rc.out"
X
X/*
X** memory constraints and other limits
X*/
X#define	PAGESIZE	16	/* jobs placed on page boundaries */
X#define	MAX_PAGE	512	/* max. pages in mem. */
X#define	MAX_MEM		(PAGESIZE*MAX_PAGE)/* size of mem. */
X#define	JMAX_LEN	512	/* max. len for job */
X#define	PAGESEP		8	/* min. job separation in pages */
X#define	JOB_WIDTH	(JMAX_LEN+ (PAGESEP*PAGESIZE))
X#define	CYCLES		1024	/* max. execution cycle limit */
X#define	MAX_USERS	(SLINES-1)/* max. # jobs (some might not fit...) */
X#define	MAX_LABELS	128	/* maximum number of labels allowed */
X#define	LABEL_LEN	6	/* max. len of labels */
X
X/*
X** field bit-widths needed
X*/
X#define	OP_BITS		4
X#define	MODE_BITS	2
X#define	ADDR_BITS	13	/* # of bits needed to address all memory */
X
X/*
X** Redcode instruction set
X*/
X#define	DAT	0	/* initialize location to value B */
X#define	MOV	1	/* move A into location B */
X#define	ADD	2	/* add A to contents of B, results in B */
X#define	SUB	3	/* subtract A from contents of B, results in B */
X#define	JMP	4	/* jump to B */
X#define	JMZ	5	/* if A == 0 then jump to B, otherwise continue */
X#define	DJZ	6	/* --A; if A == 0 then jump to B */
X#define	CMP	7	/* compare A with B; if != then skip next instruction */
X#define	MUL	8	/* multiply B by A, results in B */
X#define	DIV	9	/* divide B by A, results in B */
X#define	RND	10	/* random number between 0 and MAX_MEM, results in B */
X
X/*
X** Addressing modes
X*/
X#define	IMM	0	/* number is operand */
X#define	REL	1	/* number specifies offset from current instruction */
X#define	IND	2	/* number specifies offset from current instruction */
X			/* to location where relative address of operand is */
X			/* found */
X
X/*
X** character and string constants representing the various modes
X** and instructions
X*/
X#define	CIMM	'#'
X#define	CREL	' '
X#define	CIND	'@'
X#define	SDAT	"DAT"
X#define	SMOV	"MOV"
X#define	SADD	"ADD"
X#define	SSUB	"SUB"
X#define	SJMP	"JMP"
X#define	SJMZ	"JMZ"
X#define	SDJZ	"DJZ"
X#define	SCMP	"CMP"
X#define SMUL	"MUL"
X#define	SDIV	"DIV"
X#define	SRND	"RND"
X
X/*
X** termination reasons for mars/processes
X*/
X#define	EALIVE		0	/* currently active */
X#define	ECYCLE		1	/* max cycle limit exceeded */
X#define	EWIN		2	/* normal termination (a winner) */
X#define	EILLINST	3	/* illegal instruction */
X#define	EBADMODE	4	/* invalid addressing mode */
X#define	EINTERRUPT	5	/* process interrupted */
X
Xtypedef	struct
X{
X	uns	op:OP_BITS,	/* opcode */
X		moda:MODE_BITS,	/* mod argument A */
X		modb:MODE_BITS,	/* mod argument B */
X		arga:ADDR_BITS,	/* argument A */
X		argb:ADDR_BITS;	/* argument B */
X} memword;
X#define	val	argb
X
Xtypedef	struct
X{
X	char	*pname;		/* name of player (input file name) */
X	int	pid;		/* process number */
X	int	pc;		/* current program counter */
X	int	psize;		/* # of instruction in program */
X	int	picnt;		/* # of instructions executed at job halt */
X	int	pdied;		/* non-zero if dead, if dead then reason */
X	memword	*plstmem;	/* # of last memword modified */
X} process;
X
Xextern	char	*argv0;
Xextern	int	jobcnt, jobsleft, min_sep;
Xextern	int	cycle, max_cyc;
Xextern	long	octrl;
Xextern	memword	memory[];
X
Xextern	char	*strcpy();
X
Xextern	char	*diedstr(), *punctrl();
Xextern	void	usage(), msg(), msgfini(), movmem(), statfini(),
X		vfini(), vstatus(), vstajob();
Xextern	int	printit(), sum(), msginit(), statinit(), vupdate();
END-of-cw.h
echo file: getopt.c
sed 's/^X//' >getopt.c << 'END-of-getopt.c'
X/*
X** getopt.c	- argument parser
X**
Xstatic	char	rcsid[] = "$HEADER$";
X**
X*/
X
X#include "cw.h"
X
X/*LINTLIBRARY*/
X#ifndef	EOF
X#	define	EOF	-1
X#endif
X#ifndef	SYSV
X#	define	strchr	index
X#endif
X#define ERR(s, c)	if(opterr){\
X		extern int strlen(), write();\
X		char errbuf[2];\
X		errbuf[0] = c; errbuf[1] = '\n';\
X		(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
X		(void) write(2, s, (unsigned)strlen(s));\
X		(void) write(2, errbuf, 2);}
X
Xextern	int	strcmp();
Xextern	char	*strchr();
X
Xstatic	int	opterr = 1;
Xint	optind = 1;
Xstatic	int	optopt;
Xchar	*optarg;
X
Xint	getopt (argc, argv, opts)
Xint	argc;
Xchar	**argv, *opts;
X{
X	static	int	sp = 1;
X	reg	int	c;
X	reg	char	*cp;
X
X	if (sp == 1)
X	{
X		if (optind >= argc ||
X		    argv[optind][0] != '-' ||
X		    !argv[optind][1])
X			return(EOF);
X		if (!strcmp(argv[optind], "--"))
X			return(optind++, EOF);
X	}
X	optopt = c = argv[optind][sp];
X	if (c == ':' || !(cp=strchr(opts, c)))
X	{
X		ERR(": illegal option -- ", c);
X		if (!argv[optind][++sp])
X			optind++, sp = 1;
X		return('?');
X	}
X	if (*++cp == ':')
X	{
X		if (argv[optind][sp+1])
X			optarg = &argv[optind++][sp+1];
X		else if (++optind >= argc)
X		{
X			ERR(": option requires an argument -- ", c);
X			sp = 1;
X			return('?');
X		}
X		else
X			optarg = argv[optind++];
X		sp = 1;
X	}
X	else
X	{
X		if (!argv[optind][++sp])
X		{
X			sp = 1;
X			optind++;
X		}
X		optarg = (char *) 0;
X	}
X	return(c);
X}
END-of-getopt.c
echo file: mars.c
sed 's/^X//' >mars.c << 'END-of-mars.c'
X/*
X** mars.c -	corewar machine interpreter
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X*/
X
X#include <stdio.h>
X#include <setjmp.h>
X#include <signal.h>
X#include "cw.h"
X
Xstatic	char	rcsid[] = "$Header: mars.c,v 6.0 85/12/13 00:31:16 ccohesh001 Dist $";
X
Xchar	*argv0;
Xint	jobcnt = 0;		/* # of jobs */
Xint	jobsleft;		/* # of jobs left running */
Xint	min_sep = PAGESEP;	/* initial min. dist. between jobs */
Xint	max_cyc = CYCLES;	/* min. # of process cycles */
Xint	cycle;			/* # of cycles */
Xstatic	process	pcs[MAX_USERS];
X
X/*
X** the following variables are used globally and rarely passed
X** to any other functions
X*/
Xlong	octrl = DEF_CTRLS;	/* output control variable */
Xmemword	memory[MAX_MEM+1];
X
Xextern	void	fini(), init(), randomize(), trap(), zeromem();
Xextern	int	pcscompar();
Xextern	char	*diedstr();
X
X/*
X** main()	- the main program
X**		- parse arguments, call initialization routines, start game
X**		  and call de-initialization routines
X*/
Xmain (argc, argv)
Xreg	int	argc;
Xreg	char	**argv;
X{
X	reg	int	i;
X	auto	int	arg;
X	extern	int	optind;
X
X	argv0 = *argv;
X	while ((arg = getopt(argc, argv, "s:c:dlipvr:")) != EOF)
X	{
X		switch (arg)
X		{
X			extern	char	*optarg;
X
X			when 'r':	/* randomize */
X				if (*optarg == '0')
X					randomize(0);
X				else
X					randomize(atoi(optarg));
X			when 's':	/* separation */
X				if ((min_sep = atoi(optarg)) < 0)
X					min_sep = 1;
X				else if (min_sep > (MAX_PAGE-1))
X				{
X					fprintf(stderr, "%s: separation too large (must be < %d)\n", argv0, MAX_PAGE-1);
X					usage();
X				}
X			when 'c':	/* cycles */
X				max_cyc = atoi(optarg);
X			when 'd':	/* status window display */
X				TOGGLE(STATUS);
X			when 'l':	/* print starting stats */
X				TOGGLE(SIZE_START);
X			when 'i':	/* print instructions */
X				TOGGLE(PINST);
X			when 'p':	/* don't print cycle # */
X				TOGGLE(PASSNUM);
X			when 'v':	/* visual display */
X				TOGGLE(VISUAL);
X			otherwise:
X			case '?':
X				usage();
X		}
X	}
X	argc -= optind, argv += optind;
X	if (argc < 2)
X	{
X		fprintf(stderr, "%s: missing file arguments\n", argv0);
X		usage();
X	}
X	if (ON(VISUAL) && ON(PINST))
X		TOGGLE(PINST);
X	if (ON(PINST))
X		octrl |= PASSNUM;
X	zeromem();
X	if (ON(SIZE_START))
X		printf("%d words of memory available\n", MAX_MEM);
X	if (argc > MAX_USERS)
X	{
X		fprintf(stderr, "%s: only %d jobs at once\n", argv0, MAX_USERS);
X		exit(1);
X	}
X	for (i=jobcnt=0; *argv && i<argc; i++, argv++, jobcnt++)
X	{
X		pcs[i].pname = *argv;
X		pcs[i].pdied = EALIVE;
X		pcs[i].picnt = 0;
X		pcs[i].plstmem = (memword *) NULL;
X		pcs[i].pid = jobcnt;
X		if ((pcs[i].pc = get_start()) < 0)
X		{
X			fprintf(stderr, "%s: not all jobs will fit\n", argv0);
X			exit(1);
X		}
X		if (!(pcs[i].psize = load(pcs[i].pname, pcs[i].pc)))
X		{
X			fprintf(stderr, "%s: couldn't read in player \"%s\"\n",
X				argv0, pcs[i].pname);
X			exit(1);
X		}
X		if (ON(SIZE_START))
X			printf("Player \"%s\" @ %4d, size: %d\n",
X				pcs[i].pname, pcs[i].pc, pcs[i].psize);
X	}
X	if (ON(SIZE_START))
X	{
X		auto	char	buf[BUFSIZ];
X
X		printf("Hit return to continue");
X		gets(buf);
X	}
X	init();
X	fini(scheduler(pcs));
X	exit(0);
X}
X
X/*
X** init()	- perform various initializations
X*/
Xstatic	void	init ()
X{
X	jobsleft = jobcnt;
X	if (ON(VISUAL))
X	{
X		if (vinit())
X		{
X			fprintf(stderr, "%s: visual not working\n", argv0);
X			exit(1);
X		}
X		if (ON(STATUS) && statinit(pcs))
X		{
X			msg("Status window not working\n");
X			TOGGLE(STATUS);
X		}
X	}
X	trap(0);
X	if (!ON(VISUAL))
X	{
X		auto	char	buf[BUFSIZ];
X
X		printf("Press return to start ");
X		(void) gets(buf);
X		return;
X	}
X	msg("Press any key to start");
X	getchar();
X	vupdate(pcs);
X}
X
X/*
X** trap()	- catches signals
X**		- signum is zero for the initial call, non-zero
X**		  when an interrupt is recieved
X**		- when interrupt is received, call fini()
X*/
Xstatic	void	trap (signum)
Xreg	int	signum;
X{
X#ifndef	LINT	/* keeps lint from complaining */
X	signal(SIGINT, SIG_IGN);	/* i realize that these 2 statements */
X	signal(SIGHUP, SIG_IGN);	/* could follow the if */
X#endif
X	if (!signum)
X	{
X#ifndef	LINT
X		signal(SIGINT, trap);
X		signal(SIGHUP, trap);
X#endif
X		return;
X	}
X	fini(EINTERRUPT);
X	exit(1);
X}
X
X/*
X** fini()	- misc. things to be done before termination
X**		- print status at termination of processes
X*/
Xvoid	fini (status)
Xreg	int	status;
X{
X	reg	int	i;
X	auto	process	*spcs[MAX_USERS];
X
X	if (ON(VISUAL))
X	{
X		msg("Hit return to continue");
X		getchar();
X		if (ON(STATUS))
X			statfini();
X		vfini();
X	}
X	printf("Halted: %s\n", diedstr(status));
X	for (i=0; i < jobcnt; i++)
X	{
X		if (!pcs[i].pdied)
X			pcs[i].picnt = cycle;
X		spcs[i] = &(pcs[i]);
X	}
X	qsort(spcs, jobcnt, sizeof(spcs[0]), pcscompar);
X	printf("%-20s\t#Inst\tPC\tReason for termination\n", "Process");
X	for (i=0; i<jobcnt; i++)
X		printf("%-20s\t%5d\t%4d\t%s\n",
X			spcs[i]->pname, spcs[i]->picnt, spcs[i]->pc,
X			diedstr(spcs[i]->pdied));
X}
X
X/*
X** pcscompar()	- compare function used by qsort
X*/
Xint	pcscompar (p1, p2)
Xreg	process	**p1, **p2;
X{
X	return((*p2)->picnt - (*p1)->picnt);
X}
X
X/*
X** diedstr()	- return a string describing the reason for termination
X*/
Xchar	*diedstr (status)
Xreg	int	status;
X{
X	switch (status)
X	{
X		when EALIVE:
X			return("Still alive");
X		when ECYCLE:
X			return("Cycle limit exceeded");
X		when EWIN:
X			return("Winner found");
X		when EILLINST:
X			return("Bad instruction");
X		when EBADMODE:
X			return("Bad addressing mode");
X		when EINTERRUPT:
X			return("Interrupted");
X		otherwise:
X			return("Unknown reason");
X	}
X	/*NOTREACHED*/
X}
X
X/*
X** get_start()	- get a starting location for process
X**		- starting locations on page boundaries
X**		- return negative on error
X**
X**	Assumption:
X**		If start location can't be found, then there are too many jobs.
X*/
Xint	get_start ()
X{
X	reg	int	i;
X	reg	int	start;
X
X	start = rand() % MAX_MEM;
X	start -= start % PAGESIZE;
X	for (i = 0; i < MAX_USERS; i++)
X	{
X		if (!collision(start))
X			return(start);
X		start = sum(start, (min_sep * PAGESIZE));
X	}
X	return(-1);
X}
X
X/*
X** collision()	- return TRUE if address is taken, else FALSE
X*/
Xint	collision (addr)
Xreg	int	addr;
X{
X	reg	int	i;
X	auto	int	ll,	/* lower limit to range */
X			ul;	/* upper limit to range */
X
X	for (i=0; i<jobcnt; i++)
X	{
X		ll = sum(pcs[i].pc, -min_sep);
X		ul = sum(sum(pcs[i].pc, pcs[i].psize), min_sep);
X		if (pcs[i].pc >= ul || pcs[i].pc <= ll)
X		{	/* wrapped around memory */
X			if (addr <= ul || addr >= ll)
X				return(TRUE);
X			continue;
X		}
X		if (addr >= ll && addr <= ul)
X			return(TRUE);
X	}
X	return(FALSE);
X}
X
X/*
X** load()	- load the player
X**		- return the size of the player (in instructions), 0 on error
X*/
Xint	load (fname, start)
Xchar	*fname;
Xreg	int	start;
X{
X	reg	int	i, status;
X	reg	FILE	*fp;
X
X	if (!(fp = fopen(fname, "r")))
X	{
X		perror(fname);
X		return(0);
X	}
X	for (i=start;
X	     (status=fread(&(memory[i]),sizeof(memory[i]),1,fp)) == 1; i++)
X		continue;
X	fclose(fp);
X	if (status < 0)
X		return(0);
X	return(i - start);
X}
X
X/*
X** zeromem()	- set all memory locations to zero
X*/
Xvoid	zeromem ()
X{
X	reg	int	i;
X
X	for (i=0; i<MAX_MEM; i++)
X		memory[i].op = memory[i].val = 0;
X}
X
X/*
X** randomize()	- randomize the random number generator
X*/
Xstatic	void	randomize (seed)
Xreg	int	seed;
X{
X	extern	long	getpid();
X	extern	long	time();
X
X	if (seed)
X	{
X		srand(seed);
X		return;
X	}
X	srand(seed = (int) ((time(0) + getpid()) & 0x0000ffffL));
X	printf("seed: %d\n", seed);
X}
X
X/*
X** usage() -	print a usage message and exit
X*/
Xstatic	void	usage ()
X{
X	fprintf(stderr, "Usage: %s [-dilpv] [-rn] [-sn] [-cn] file ...\n", argv0);
X	exit(1);
X}
END-of-mars.c
echo file: movmem.c
sed 's/^X//' >movmem.c << 'END-of-movmem.c'
X/*
X** movmem.c	-
X**
Xstatic	char	rcsid[] = "$Header: movmem.c,v 7.0 85/12/28 14:35:55 ccohesh Dist $";
X**
X*/
X#include "cw.h"
X
X/*
X** movmem()	- move contents of one location in `memory' to another
X*/
Xvoid	movmem (m1, m2)
Xreg	memword	*m1, *m2;
X{
X	m1->op = m2->op;
X	m1->moda = m2->moda;
X	m1->modb = m2->modb;
X	m1->arga = m2->arga;
X	m1->argb = m2->argb;
X}
END-of-movmem.c
echo file: msg.c
sed 's/^X//' >msg.c << 'END-of-msg.c'
X/*
X** msg.c -	code dealing with the printing of messages
X**
X**	Routines:
X**		msginit()	initialize the window
X**		msgfini()	de-initialize the window
X**		msg(fmt, args)	write message to window
X**		msgclear()	clear the message window
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: msg.c,v 7.0 85/12/28 14:36:01 ccohesh Dist $";
X**
X*/
X
X#include <curses.h>
X#include <ctype.h>
X#include "cw.h"
X
X
Xstatic	WINDOW	*msgwin;	/* status window for msg's */
X
Xextern	void	doadd();
X
X/*
X** msginit()	- initialize the message window
X**		- return non-zero on error
X*/
Xint	msginit ()
X{
X	if (!(msgwin = subwin(stdscr, MSGLINES, MSGCOLS, MSGYBEGIN, MSGXBEGIN)))
X	{
X		fprintf(stderr, "%s: message screen initialization error\n",
X			argv0);
X		return(TRUE);
X	}
X	wclear(msgwin);
X	scrollok(msgwin, TRUE);
X	return(FALSE);
X}
X
X/*
X** msgfini()	- re-initialize the message window
X*/
Xvoid	msgfini ()
X{
X	wclear(msgwin);
X	delwin(msgwin);
X}
X
Xstatic char msgbuf[BUFSIZ];
X/*
X** msg()	- display message in message window using printf() like
X**		  function
X*/
X/*VARARGS1*/
Xvoid	msg (fmt, args)
Xchar	*fmt;
Xint	args;
X{
X	/*
X	** if the string is "", just clear the line
X	*/
X	if (*fmt == '\0')
X	{
X		wclear(msgwin);
X		wrefresh(msgwin);
X		return;
X	}
X	/*
X	** otherwise print the message and flush it out
X	*/
X	doadd(fmt, &args);
X	waddch(msgwin, '\n');
X	waddstr(msgwin, msgbuf);
X	wrefresh(msgwin);
X}
X
Xstatic	void	doadd (fmt, args)
Xchar	**fmt;
Xint	***args;
X{
X	static	FILE	junk;
X
X	/*
X	** Do the printf into buf
X	*/
X#ifdef	_IOSTRG
X	junk._flag = _IOWRT + _IOSTRG;
X	junk._ptr = &msgbuf[0];
X#else
X 	junk._flag = _IOWRT;
X 	junk._file = _NFILE;
X 	junk._ptr = (unsigned char *) &msgbuf[0];
X#endif
X	junk._cnt = 32767;
X	_doprnt(fmt, args, &junk);
X	putc('\0', &junk);
X}
X
X/*
X** punctrl()	- print a readable version of a certain character
X**
X**	Note:	Due to the inconsistent availability of a function to perform
X**		this, my own version has been built in and used in place of
X**		any pre-existing function.  I believe that this particular
X**		version suts down on data space considerably from the versions
X**		I have found on the Berkley systems.
X*/
Xchar	*punctrl (ch)
Xchar	ch;
X{
X	static	char	*str = "^ ";
X
X	ch &= 0177;
X	if (ch >= ' ' && ch <= '~')
X	{
X		static	char	*str1 = " ";
X
X		*str1 = ch;
X		return(str1);
X	}
X	if (ch == CINTR)
X		return("^?");
X	*(str+1) = ch + '@';
X	return(str);
X}
END-of-msg.c
echo file: print.c
sed 's/^X//' >print.c << 'END-of-print.c'
X/*
X** print.c	- various printing routines
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: print.c,v 7.0 85/12/28 14:36:14 ccohesh Dist $";
X**
X*/
X
X#include <stdio.h>
X#include "cw.h"
X
X/*
X** printit()	- print the given instruction
X**		- return non-zero on error
X*/
Xint	printit (fp, i)
XFILE	*fp;
Xreg	memword	*i;
X{
X	reg	char	*inst, *fmt;
X	auto	char	adda, addb;
X	static	char	*fmt1 = "%3.3s\t\t%c%d\n",
X			*fmt2 = "%3.3s\t%c%d\t%c%d\n";
X
X	switch (i->op)
X	{
X		when DAT:
X			inst = SDAT, fmt = fmt1;
X		when MOV:
X			inst = SMOV, fmt = fmt2;
X		when ADD:
X			inst = SADD, fmt = fmt2;
X		when SUB:
X			inst = SSUB, fmt = fmt2;
X		when JMP:
X			inst = SJMP, fmt = fmt1;
X		when JMZ:
X			inst = SJMZ, fmt = fmt2;
X		when DJZ:
X			inst = SDJZ, fmt = fmt2;
X		when CMP:
X			inst = SCMP, fmt = fmt2;
X		when MUL:
X			inst = SMUL, fmt = fmt2;
X		when DIV:
X			inst = SDIV, fmt = fmt2;
X		when RND:
X			inst = SRND, fmt = fmt1;
X		otherwise:
X			return(TRUE);
X	}
X	switch (i->moda)
X	{
X		when IMM:
X			adda = CIMM;
X		when REL:
X			adda = CREL;
X		when IND:
X			adda = CIND;
X		otherwise:
X			adda = '?';
X	}
X	switch (i->modb)
X	{
X		when IMM:
X			addb = CIMM;
X		when REL:
X			addb = CREL;
X		when IND:
X			addb = CIND;
X		otherwise:
X			addb = '?';
X	}
X	if (fmt == fmt1)
X		fprintf(fp, fmt, inst, addb, i->argb);
X	else
X		fprintf(fp, fmt, inst, adda, i->arga, addb, i->argb);
X	return(FALSE);
X}
END-of-print.c
echo file: scheduler.c
sed 's/^X//' >scheduler.c << 'END-of-scheduler.c'
X/*
X** scheduler.c	- routines dealing with the running of the jobs
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: scheduler.c,v 7.0 85/12/28 14:36:26 ccohesh Dist $";
X**
X*/
X
X#include <stdio.h>
X#include <setjmp.h>
X#include "cw.h"
X
X
Xstatic	int	_pc;			/* current pc */
Xstatic	jmp_buf	haltit;
X
Xextern	void	halt(), run();
Xextern	memword	*getoperand();
X
X/*
X** scheduler()	- run the processes
X**		- very simple algorithm to determine what job is scheduled next:
X**			jobs are scheduled by thier order in the process table
X**		- each job gets to execute one instruction during its scheduled
X**		  period
X*/
Xint	scheduler (pcs)
Xreg	process	*pcs;
X{
X	reg	int	flag;
X
X	if (ON(VISUAL))
X		return(vscheduler(pcs));
X	for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++)
X	{
X		reg	process	*j;
X
X		if (ON(PASSNUM) && (!(cycle % PASSFREQ) || ON(PINST)))
X			printf("Pass #%04d\t", cycle);
X		if (!ON(PINST) && ON(PASSNUM) &&
X		    (!(cycle % PASSFREQ) || ON(PINST)))
X			putchar('\r'), fflush(stdout);
X		for (flag=0, j=pcs; j < (pcs+jobcnt); j++, flag++)
X		{
X			if (ON(PINST) && ON(PASSNUM) && flag &&
X			    (!(cycle % PASSFREQ) || ON(PINST)))
X				printf("\t\t");
X			if (!HALTED(j))
X				run(j);
X		}
X	}
X	if (cycle >= max_cyc)
X		return(ECYCLE);
X	return(EWIN);
X}
X
X/*
X** vscheduler()	- the scheduler used for visual display mode
X*/
Xint	vscheduler (pcs)
Xreg	process	*pcs;
X{
X	for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++)
X	{
X		reg	process	*j;
X
X		for (j=pcs; j < (pcs+jobcnt); j++)
X			if (!HALTED(j))
X				run(j);
X		vupdate(pcs);
X		if (ON(STATUS) && !(cycle % PASSFREQ) && ON(PASSNUM))
X			vstatus();
X	}
X	if (cycle >= max_cyc)
X		return(ECYCLE);
X	return(EWIN);
X}
X
X/*
X** run()	- execute one instruction of the given job
X*/
Xstatic	void	run (j)
Xreg	process	*j;
X{
X	reg	memword	*w;
X	reg	int	status;
X
X	/* fetch pc (incremented at end of function or where appropriate) */
X	PC = j->pc;
X	/* fetch instruction */
X	w = &(memory[j->pc]);
X	/* remember this for halting processes */
X	if (status = SETJMP(haltit))
X	{
X		halt(j, status);
X		return;
X	}
X	if (ON(PINST))
X	{
X		printf("PC: %4d\t", PC);
X		if (printit(stdout, w))
X			fprintf(stderr, "%s: printit() error\n", argv0);
X	}
X	switch (w->op)
X	{
X		auto	int	tmp;
X
X#define	A	w->moda, w->arga
X#define	B	w->modb, w->argb
X/*
X** when modifying memory locations through arithmetic operations
X** make sure the opcode gets reset
X*/
X#define	COREA	tmp=getaddr(w->moda, w->arga),memory[tmp].op=DAT,memory[tmp].val
X#define	COREB	tmp=getaddr(w->modb, w->argb),memory[tmp].op=DAT,memory[tmp].val
X
X		when MOV:/* move A into location B */
X			movmem(j->plstmem=(&(memory[getaddr(B)])),
X				getoperand(A));
X		when ADD:/* add A to contents of B, results in B */
X			COREB = sum((int) (getoperand(A))->val,(int) (getoperand(B))->val);
X		when MUL:
X		{
X			reg	int	temp = (int) (getoperand(B))->val;
X
X			temp *= (int) (getoperand(A))->val;
X			COREB = sum(temp, 0);
X		}
X		when DIV:
X		{
X			reg	int	temp = (int) (getoperand(B))->val;
X
X			temp /= (int) (getoperand(A))->val;
X			COREB = sum(temp, 0);
X		}
X		when SUB:/* subtract A from contents of B, results in B */
X			COREB = sum((int) -(getoperand(A))->val,(int) (getoperand(B))->val);
X		when JMP:/* jump to B */
X			j->pc = getaddr(B);
X			return;
X		when JMZ:/* if A == 0 then jump to B, otherwise continue */
X			if (getoperand(A)->val == 0)
X			{
X				j->pc = getaddr(B);
X				return;
X			}
X		when DJZ:/* --A; if A == 0 then jump to B */
X			COREA = sum((int) getoperand(A)->val, -1);
X			if (COREA == 0)
X			{
X				j->pc = getaddr(B);
X				return;
X			}
X		when CMP:/* compare A with B; if != then skip next inst. */
X			if (getoperand(A)->val != getoperand(B)->val)
X			{
X				j->pc = sum(j->pc, 2);
X				return;
X			}
X		when RND:/* into A a random number between 0 and MAX_MEM */
X			COREB = sum((int) rand(), 0);
X		otherwise:
X			halt(j, EILLINST);
X#undef	A
X#undef	B
X#undef	COREA
X#undef	COREB
X	}
X	if (!HALTED(j))
X		j->pc = sum(j->pc, 1);		/* increment pc */
X}
X
X/*
X** getoperand()	- return the operand
X**		- since a pointer to static data is returned, care is
X**		  taken to insure that this static data isn't corrupted
X**		  due to two `simultaneous' calls.
X*/
Xstatic	memword	*getoperand (m, a)
Xreg	uns	m, a;
X{
X	static	memword	mw1, mw2, *mw;
X
X	mw = (mw == &mw1) ? &mw2 : &mw1;
X	switch (m)
X	{
X		case IMM:
X			mw->op = 0;
X			mw->val = a;
X			return(mw);
X		case REL:
X			return(&(memory[sum(PC, (int) a)]));
X		case IND:
X			return(&(memory[getaddr(m,a)]));
X		default:
X			LONGJMP(haltit, EBADMODE);
X	}
X	/*NOTREACHED*/
X}
X
X/*
X** getaddr()	- return the address
X*/
Xstatic	int	getaddr (m, a)
Xreg	uns	m, a;
X{
X	switch (m)
X	{
X		case REL:
X			return(sum((int) PC, (int) a));
X		case IND:
X		{
X			reg	int	tmp;
X
X			tmp = sum(PC, (int) a);
X			return(sum(tmp, (int) memory[tmp].val));
X		}
X		case IMM:
X		default:
X			LONGJMP(haltit, EBADMODE);
X	}
X	/*NOTREACHED*/
X}
X
X/*
X** halt()	- halt the specified process
X*/
Xstatic	void	halt (j, reason)
Xreg	process	*j;
Xreg	int	reason;
X{
X#ifdef	DEBUG
X	fprintf(stderr, "%s: process \"%s\" halted\n", argv0, j->pname);
X#endif
X	j->pdied = reason;
X	j->picnt = cycle;
X	jobsleft--;
X	if (ON(VISUAL) && ON(STATUS))
X		vstajob(j);
X}
END-of-scheduler.c
echo file: sum.c
sed 's/^X//' >sum.c << 'END-of-sum.c'
X/*
X** sum.c	- add two numbers, wrapping if sum is out-of-bounds
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: sum.c,v 7.0 85/12/28 14:36:36 ccohesh Dist $";
X**
X*/
X
X#include "cw.h"
X
X
X/*
X** sum()	- sum two integers w/ memory wrapping
X*/
Xint	sum (x, y)
Xreg	int	x, y;
X{
X	reg	int	tot = x + y;
X
X	if (tot < 0)
X		return(sum(MAX_MEM + tot, 0));
X	if (tot >= MAX_MEM)
X		return(tot % MAX_MEM);
X	return(tot);
X}
END-of-sum.c
echo file: vdisplay.c
sed 's/^X//' >vdisplay.c << 'END-of-vdisplay.c'
X/*
X** vdisplay.c	- routines dealing with the visual display of the
X**		  Corewar game
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: vdisplay.c,v 7.0 85/12/28 14:36:39 ccohesh Dist $";
X**
X*/
X
X#include <curses.h>
X#include <ctype.h>
X#include "cw.h"
X
X
X/*
X** Strategy:
X**
X** 1.	Fill the screen with a rectangle of characters (MEMPTY).
X**	Let each character represent 10 memory locations.
X**	Since MAX_MEM is 10,000 (and I am afraid this value is
X**	going to be rather hard coded into the display routines)
X**	this will have to be a 50 column by 20 row box.
X** 2.	Place an uppercase letter in the location corresponding to
X**	the value of the job's PC.  If more than one job occupies the
X**	same location, then place a digit representing the number of
X**	jobs.
X** 3.	Place a lowercase letter at the square corresponding to the
X**	memory location that the job is modifying.  If more than one
X**	job is modifying the same memory section, place MSHARE there.
X** 4.	If a job is modifying a memsect that another job is modifying,
X**	place a MHIT.
X**
X**	Therefore, we need routines to do the following:
X**
X**		initialize window
X**			fill with MEMPTY's
X**		update screen wrt PC values and delta mem locs
X*/
X
X#define	BOXS(p)		(p/NUMMEM)
X#define	BOXX(p)		(BOXS(p) % MCOLS)
X#define	BOXY(p)		(BOXS(p) / MCOLS)
X
Xstatic	WINDOW	*memwin;
X
Xextern	void	clearbox(), membox();
X
X/*
X** vupdate()	- update the memory display
X*/
Xint	vupdate (ps)
Xreg	process	*ps;
X{
X	reg	process	*p;
X
X	for (p = ps; (p - ps) < jobcnt; p++)
X	{	/* update plstmem's	*/
X		auto	int	addr = (p->plstmem - &(memory[0]));
X		auto	int	y = BOXY(addr),		/* hides earlier def. */
X				x = BOXX(addr);		/* hides earlier def. */
X		auto	char	pch = (char) p->pid + 'a';
X		reg	char	ch;
X
X		if (!p->plstmem || p->pdied)
X			continue;
X		if ((addr/PAGESIZE) == (p->pc/PAGESIZE))
X			continue;	/* writing to same mem page */
X		if ((ch = mvwinch(memwin, y, x)) == MEMPTY)
X			waddch(memwin, pch);
X		else if (islower(ch))
X			waddch(memwin, MSHARE);
X		else
X			msg("Unknown character in membox (%s) @ (%d,%d)",
X				punctrl(ch), y, x);
X	}
X	for (p = ps; (p - ps) < jobcnt; p++)
X	{	/* upate pc's	*/
X		auto	int	y = BOXY(p->pc),	/* hides earlier def. */
X				x = BOXX(p->pc);	/* hides earlier def. */
X		auto	char	pch = (char) p->pid + 'A';
X		reg	char	ch = mvwinch(memwin, y, x);
X
X		if (p->pdied || ch == MFULL || ch == MHIT)
X			continue;
X		if (ch == MEMPTY)
X			waddch(memwin, pch);
X		else if (isupper(ch))
X			waddch(memwin, '2');
X		else if (isdigit(ch))
X			waddch(memwin, (ch<'9') ? (ch + (char) 1) : MFULL);
X		else if (ch == MSHARE)
X			waddch(memwin, MHIT);
X		else if (islower(ch))
X		{
X			if (ch == tolower(pch))
X				waddch(memwin, pch);
X			else
X				waddch(memwin, MHIT);
X		}
X		else
X			msg("unknown character in membox (%s) @ (%d,%d)",
X				punctrl(ch), y, x);
X	}
X	wrefresh(memwin);
X	for (p = ps; (p - ps) < jobcnt; p++)
X	{	/* upate pc's	*/
X		auto	int	addr = (p->plstmem - &(memory[0]));
X
X		if (p->pdied)
X			continue;
X		mvwaddch(memwin, BOXY(p->pc), BOXX(p->pc), MEMPTY);
X		if (!p->plstmem)
X			continue;
X		mvwaddch(memwin, BOXY(addr), BOXX(addr), MEMPTY);
X	}
X}
X
X/*
X** vinit()	- perform curses initializations
X**		- initialize memory window
X**		- return non-zero on error
X*/
Xint	vinit ()
X{
X	if (initscr() == ERR)
X	{
X		fprintf(stderr, "%s: screen initialization error\n", argv0);
X		perror(argv0);
X		return(TRUE);
X	}
X	if (LINES < MIN_LINES || COLS < MIN_COLS)
X	{
X		fprintf(stderr, "%s: screen must be at least %d by %d\n",
X			argv0, MIN_LINES, MIN_COLS);
X		return(TRUE);
X	}
X	if (!(memwin = subwin(stdscr, MLINES, MCOLS, MYBEGIN, MXBEGIN)))
X	{
X		fprintf(stderr, "%s: can't create memory-window\n", argv0);
X		return(TRUE);
X	}
X	if (msginit())
X		return(TRUE);
X	membox();
X	clearbox();
X	refresh();
X	crmode();
X	noecho();
X	return(FALSE);
X}
X
X/*
X** vfini()	- perform screen shutdown actions
X*/
Xvoid	vfini ()
X{
X	msgfini();
X	clear();
X	refresh();
X	delwin(memwin);
X	endwin();
X}
X
X/*
X** clearbox()	- fill the box with MEMPTY's
X*/
Xstatic	void	clearbox ()
X{
X	reg	int	y, x;
X
X	for (y=0; y<MLINES; y++)
X		for (x=0; x<MCOLS; x++)
X			mvwaddch(memwin, y, x, MEMPTY);
X}
X
X/*
X** membox()	- draw a box around the memory window
X*/
Xstatic	void	membox ()
X{
X	reg	int	y, x;
X
X	for (x = MXBEGIN-1, y = MYBEGIN-1; x < (MXBEGIN+MCOLS+1); x++)
X		mvaddch(y, x, HORTBORDER), mvaddch(y+MLINES+1, x, HORTBORDER);
X	for (y = MYBEGIN, x = MXBEGIN-1; y < (MYBEGIN+MLINES); y++)
X		mvaddch(y, x, VERTBORDER), mvaddch(y, x+MCOLS+1, VERTBORDER);
X}
END-of-vdisplay.c
echo file: vstatus.c
sed 's/^X//' >vstatus.c << 'END-of-vstatus.c'
X/*
X** vstatus.c	- manage the status window
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: vstatus.c,v 7.0 85/12/28 14:36:44 ccohesh Dist $";
X**
X*/
X
X#include <curses.h>
X#include "cw.h"
X
X
Xstatic	WINDOW	*statwin;
X
X/*
X** statinit()	- initialize the status window
X*/
Xint	statinit (jobs)
Xreg	process	*jobs;
X{
X	reg	int	i;
X
X	if (!(statwin = subwin(stdscr, SLINES, SCOLS, SYBEGIN, SXBEGIN)))
X	{
X		fprintf(stderr, "%s: status screen initialization error\n",
X			argv0);
X		return(TRUE);
X	}
X	wclear(statwin);
X	scrollok(statwin, FALSE);
X	for (i=0; i<jobcnt && i < SLINES; i++)
X		vstajob(jobs++);
X	if (ON(PASSNUM))
X		vstatus();
X	return(FALSE);
X}
X
X/*
X** statfini()	- de-initialize the status window
X*/
Xvoid	statfini ()
X{
X	wclear(statwin);
X	delwin(statwin);
X}
X
X/*
X** vstatus()	- print the current cycle number and jobs left 
X**		  in the status window
X*/
Xvoid	vstatus ()
X{
X	wmove(statwin, SLINES-1, 0);
X	wprintw(statwin, "Cycle: %04d  Jobs: %2d", cycle, jobsleft);
X	wrefresh(statwin);
X}
X
X/*
X** vstajob()	- update the entry for the given job in the status window
X*/
Xvoid	vstajob (j)
Xreg	process	*j;
X{
X	wmove(statwin, j->pid, 0);
X	wprintw(statwin,"%c. \"%.10s\" %4d %s",
X		'A' + j->pid, j->pname, j->pc, diedstr(j->pdied));
X	wrefresh(statwin);
X}
END-of-vstatus.c
echo file: unrc.c
sed 's/^X//' >unrc.c << 'END-of-unrc.c'
X/*
X** unrc.c -	disassemble rc binaries
X**
X**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
X**
Xstatic	char	rcsid[] = "$Header: unrc.c,v 7.0 85/12/28 14:36:48 ccohesh Dist $";
X**
X*/
X
X#include <stdio.h>
X#include "cw.h"
X
X
Xchar	*argv0;
X
Xmain (argc, argv)
Xreg	int	argc;
Xreg	char	**argv;
X{
X	auto	memword	i;
X
X	argv0 = *argv++, argc--;
X	if (argc == 0)
X		*argv = RC_OUT;
X	else if (argc != 1)
X		usage();
X	if (!freopen(*argv, "r", stdin))
X	{
X		perror(*argv);
X		exit(1);
X	}
X	while (fread((char *) &i, sizeof(i), 1, stdin) == 1)
X		unrc(&i);
X	fclose(stdin);
X}
X
X/*
X** unrc() -	unassemble the given instruction
X*/
Xunrc (i)
Xreg	memword	*i;
X{
X	reg	int	incnt;
X	static	int	icnt = 0;
X
X	icnt++;
X	switch (i->op)
X	{
X		when DAT:
X		case JMP:
X		case RND:
X			incnt = 1;
X		when MOV:
X		case ADD:
X		case SUB:
X		case JMZ:
X		case DJZ:
X		case CMP:
X		case MUL:
X		case DIV:
X			incnt = 2;
X		otherwise:
X			fprintf(stderr, "Inst. %d: bad opcode: %d\n",
X				icnt, i->op);
X			return;
X	}
X	switch (i->modb)
X	{
X		case IMM:
X		case REL:
X		case IND:
X		otherwise:
X			fprintf(stderr, "Inst. %d: bad address mode for B\n", icnt);
X			return;
X	}
X	if (incnt == 1)
X	{
X		if (printit(stdout, i))
X			fprintf(stderr, "Inst. %d: printit() problem\n", icnt);
X		return;
X	}
X	switch (i->moda)
X	{
X		case IMM:
X		case REL:
X		case IND:
X		otherwise:
X			fprintf(stderr, "Inst. %d: bad address mode for A\n", icnt);
X			return;
X	}
X	if (printit(stdout, i))
X		fprintf(stderr, "Inst. %d: printit() problem\n", icnt);
X}
X
X/*
X** usage() -	print a usage message and exit
X*/
Xvoid	usage ()
X{
X	fprintf(stderr, "Usage: %s file\n", argv0);
X	exit(1);
X}
END-of-unrc.c
echo file: cw.6
sed 's/^X//' >cw.6 << 'END-of-cw.6'
X.\"	Documentation for Corewars system
X.\"
X.\"	static	char	rcsid[] = "$Header: cw.6,v 7.2 86/01/06 21:28:21 ccohesh Exp $";
X.\"
X.TH CW UCD "2 December 1985"
X.SH NAME
Xmars, rcasm, unrc \- Core Wars simulation system
X.SH SYNOPSIS
X.B mars
X[
X.B \-dilpv
X] [
X.B \-rn
X] [
X.B \-sn
X] [
X.B \-cn
X] file file ...
X.br
X.B rcasm
Xfile [ofile]
X.br
X.B unrc
Xfile
X.SH OPTIONS
X.TP
X.B \-d
XDo not print the status window if in visual display mode.
X.TP
X.B \-i
XPrint current instruction.  This turns on the
X.B \-p
Xand the
X.B \-v
Xoptions.
X.TP
X.B \-l
XPrint job size and load location during startup.
X.TP
X.B \-p
XPrint the current cycle number.
X.TP
X.B \-rn
XSet the seed for the random number generator to
X.B n.
XIf
X.B n
Xis zero, then
X.B mars
Xwill create its own seed and print it.
X.TP
X.B \-sn
XSet the minimum amount of memory initially separating jobs to
X.B n
Xmemory pages.  A memory page is 16 words.  This value must be less
Xthan 511.  The default separation value is 8 pages.
X.TP
X.B \-cn
XSet the maximum number of execution cycles to
X.B n.
XThe default value is 1024.
X.TP
X.B \-v
XDo not run in visual display mode.  This is useful to quickly
Xdetermine the outcome.  Also, the instruction display will not
Xwork in visual display mode.
X.TP
X.SH DESCRIPTION
X.I Mars
X(an acronym for Memory Array Redcode Simulator) executes battle
Xprograms created by
X.I rcasm.
XThe battle programs are entered into the battlefield at randomly
Xchosen positions and executed in a simple version of time-sharing.
XExecution continues until all but one program is left running or
Xthe instruction cycle limit is reached.
XPrograms are halted when they attempt to execute an invalid instruction 
Xor an instruction with an illegal addressing mode.
XWhen
X.I mars
Xterminates it prints a summary of results of the battle indicating
Xhow long each job ran and the reason (if any) for a job's termination.
X.LP
XBy default
X.I mars
Xwill display the battle using a box of 512 periods ('.'), each representing
Xone memory page of 16 memory locations.  The position of each program's
Xprogram counter is marked by a capital letter and the areas affected by the
Xprogram executing the "MOV" instruction by the corresponding lowercase
Xletter.  An optional status window is displayed to the right of this box.
XEach line in the window contains information for one program.
XThis information includes the letter representing the program, the `name'
Xof the program (via the command line argument) and the program's current
Xstatus.  If the
X.B \-p
Xoption is specified on the command line the bottom line of the status window
Xwill indicate the number of cycles elapsed and the number of programs
Xstill operational.
X.LP
X.I Rcasm
Xassembles the named
X.I redcode
Xassembly language
X.I file.
XThe output of the assembly is left on the file
X.I ofile;
Xif that is ommitted,
X.I rc.out
Xis used.
X.LP
X.I Unrc
Xdis-assembles the named
X.I redcode
Xobject file writing the
X.I redcode
Xassembly instructions to the standard output.
XHowever, be aware that since
X.I rcasm
Xdoes not include comments in the object files that it creates, the output from
X.I unrc
Xwill not contain any comments that once might have been in the original
Xsource core.
X.SH DETAILS
XThe size of the memory into which the programs are loaded is 8192 words.
XThis is divided into 512 16 word pages.  Jobs are loaded on page
Xboundaries with the default minimum separation between programs being
X8 pages.
XSince jobs are loaded on page boundaries they can work in teams
X(i.e. employ strategies such that if two jobs of the same type are
Xloaded they will only kill jobs of a different type).
XThis is obvious in the
X.B dwarf
Xprogram.  If one
X.B dwarf
Xjob can not kill itself it will not be able to kill other
X.B dwarfs.
XThis isn't necessarily true for programs that use the
X.B RND
Xinstruction.
X.LP
XNone of the programs know where the other ones are, they do not
Xeven know how many other programs exist.
XBecause a program can never refer to an absolute address, some addressing
Xmodes for some operands do not make sense.
XAll memory addressing is relative to the current instruction.
XSince memory is `circular', addressing location 8192 would be the same as
Xaddressing location 0.
X.LP
XSince execution of a program starts on its first instruction, the user
Xis cautioned to not have any
X.B DAT
Xinstructions at this point.  If a user prefers to place all his
X.B DAT
Xinstructions at the beginning of his program, it is suggested that he
Xprecede them with a
X.B JMP
Xinstruction to the appropriate address.
X.SH REDCODE
X.TS
Xcenter tab(:);
Xc s s s
Xc c s c.
XRedcode Instruction Set
X=
XMnemonic:Arguments:Action
XSymbol::
X_
X.T&
Xlw(0.35i) cw(0.25i) cw(0.25i) lw(4i).
XDAT::B:T{
XInitialize location to value B.
XT}
XMOV:A:B:T{
XMove A into location B.
XT}
XADD:A:B:T{
XAdd operand A to contents of location B and store result in location B.
XT}
XSUB:A:B:T{
XSubtract operand A from contents of location B and store result in location B.
XT}
XJMP::B:T{
XJump to location B.
XT}
XJMZ:A:B:T{
XIf operand A is 0, jump to location B; otherwise continue with next instruction.
XT}
XDJZ:A:B:T{
XDecrement contants of location A by 1.  If location A now holds 0,
Xjump to location B; otherwise continue with next instruction.
XT}
XCMP:A:B:T{
XCompare operand A with operand B.
XIf they are not equal, skip next instruction; otherwise continue with
Xnext instruction.
XT}
XMUL:A:B:T{
XMultiply operand B by operand A and store result in location B.
XT}
XDIV:A:B:T{
XDivide operand B by operand A and store result in location B.
XT}
XRND::B:T{
XChose a random integer between 0 and the maximum memory size and store
Xit in location B.
XT}
X.TE
X.sp 2
X.TS
Xcenter tab(:);
Xc s s
Xc c c.
XRedcode Addressing Modes
X=
XMnemonic:Name:Meaning
XSymbol::
X_
X.T&
Xc l lw(4.0i).
X#:Immediate:T{
XThe number following this symbol is the operand.
XT}
X<none>:Relative:T{
XThe number specifies an offset from the current instruction.
XMars adds the offset to the address of the current instruction;
Xthe number stored at the location reached in this was is the operand.
XT}
X@:Indirect:T{
XThe number following this symbol specifies an offset from the current
Xinstruction to a location where the relative address of the operand is found.
XMars adds the offset to the address of the current instruction and retrieves
Xthe number stored at the specified location; this number is the interpreted
Xas an offset from its own address.  The number found at this second location
Xis the operand.
XT}
X.TE
X.LP
XLabels are another feature of this assembly language.
XLabels consist of alphanumerical characters witha maximum length of
Xsix characters starting with a dollar sign ('$').
XTo declare a label, simply place the label with a colon (':') appended to it
Xat the beginning of an instruction.
XLabels can be used anywhere where you would normally specify an integer address.
X.SH EXAMPLES
X.ta 1.5i 2.0i 2.25i
X	JMP		$START
X.br
X$ADDR:	DAT		0
X.br
X$START:	ADD	#8	$ADDR
X.br
X	MOV	#0	@$ADDR
X.br
X	JMP		$START
X.LP
XThis is a simple program, usually refered to as
X.B Dwarf.
XIt works its way through memory bombarding every eighth memory
Xaddress with a zero.
X.LP
XAn even simpler program,
X.B imp,
Xsimply copies itself throughout memory, one memory location at a time.
X.br
X$ME:	MOV	$ME	$AFTERME
X$AFTERME:	DAT	0
X.SH FILES
X.ta 1.5i
Xrc.out	default resultant object file
X.SH "SEE ALSO"
XD. G. Jones and A. K. Dewdney, "CORE WAR GUIDELINES."
X.br
XA. K. Dewdney,
X"Computer Recreations,"
X.I Scientific American,
XMay, 1984, pp. 14-23
X.SH DIAGNOSTICS
X.B Rcasm
Xwill complain if it discovers syntax errors in the input file.
X.B Unrc
Xwill complain if the input file contains invalid redcode instructions.
X.B Mars
Xwill complain about argument syntax errors and files that it cannot open.
X.SH AUTHOR
XPeter Costantinidis, Jr., University of California, Davis
X.SH BUGS
XNone known at this time.  When they are discovered the author would
Xappreciate notification.
END-of-cw.6
echo file: rcasm.y
sed 's/^X//' >rcasm.y << 'END-of-rcasm.y'
X	/*
X	** grammar for the input to the Redcode Assembler
X	**
X	** [cw by Peter Costantinidis, Jr. @ University of California at Davis]
X	**
X	static	char	rcsid[] = "$Header: rcasm.y,v 7.0 85/12/28 14:37:04 ccohesh Dist $";
X	**
X	*/
X
X	/* instructions */
X%{
X#include <stdio.h>
X#include "cw.h"
X
Xtypedef	struct	/* simple single purpose symbol table */
X{
X	int	sym_abs;	/* absolute address of symbol */
X	char	*sym_nam;	/* symbols name */
X} symtab;
X
Xmemword	inst;		/* current instruction */
Xmemword	memory[JMAX_LEN];
Xsymtab	symbols[MAX_LABELS];	/* symbol table */
Xsymtab	*unres[JMAX_LEN];	/* list of unresolved references */
Xuns	opcode;		/* set in lexical analyzer */
Xint	icnt = 0;	/* instruction count */
Xint	lcnt = 1;	/* line count */
Xint	ocnt = 0;	/* # of operands for current instruction */
Xint	toggle = 0;	/* for multi-arg inst.'s indicates which arg */
Xint	orc;		/* required # of operands for current inst. */
Xchar	*dlabel, *alabel, *blabel;/* set in lexical analyzer */
X
Xextern	void	yyerror();
X%}
X
X
X	/* operand tokens */
X%token	OIMM	/* number is operand					(#) */
X%token	OREL	/* number specifies offset from current instruction	( ) */
X%token	OIND	/* number specifies offset from current instruction	(@) */
X		/* to location where relative address of operand is found   */
X
X%token	OPCODE
X%token	INTEGER	/* the operands */
X%token	COMMENT	/* a comment */
X%token	ERROR	/* error in lex */
X%token	NL	/* new line */
X
X%token	DLABEL	/* defining a label */
X%token	LABEL	/* a label being used */
X
X%start	program
X
X%%	/* beginning of rules section */
X
Xprogram	:	/* empty */
X	|	program line
X	|	program error NL
X		{
X			toggle = 0;
X			lcnt++;
X			yyerrok;
X		}
X	;
X
Xline	:	comment NL
X		{
X			lcnt++;
X		}
X	|	label statement comment NL
X		{
X			inst.op = $2;
X			lcnt++;
X			toggle = 0;	/* a hack for labels */
X			if (icnt > JMAX_LEN)
X			{
X				static	int	once = FALSE;
X
X				if (!once)
X				{
X					once = TRUE;
X					fprintf(stderr, "Maximum instruction limit of %d exceeded\n", JMAX_LEN);
X					fprintf(stderr, "Will continue processing...\n");
X				}
X			}
X			movmem(&(memory[icnt++]), &inst);
X		}
X	;
X
Xlabel	:
X	|	DLABEL
X		{
X			if (addsym(dlabel))
X				YYERROR;
X		}
X	;
X
Xcomment	:
X	|	COMMENT
X	;
X
Xstatement:	OPCODE arga argb
X		{
X			if (orc != 2)
X			{
X				yyerror("bad argument count");
X				YYERROR;
X			}
X			if ((opcode == MOV && $3 == IMM) ||
X			    (opcode == ADD && $3 == IMM) ||
X			    (opcode == SUB && $3 == IMM) ||
X			    (opcode == JMZ && $3 == IMM) ||
X			    (opcode == DJZ && $3 == IMM) ||
X			    (opcode == MUL && $3 == IMM) ||
X			    (opcode == DIV && $3 == IMM))
X			{
X				yyerror("non-sensicle mode for operand");
X				YYERROR;
X			}
X			$$ = opcode;
X		}
X	|	OPCODE argb
X		{
X			if (orc != 1)
X			{
X				yyerror("bad argument count");
X				YYERROR;
X			}
X			if ((opcode == JMP && $2 == IMM) ||
X			    (opcode == RND && $2 == IMM) ||
X			    (opcode == DAT && $2 != REL))
X			{
X				yyerror("non-sensicle mode for operand");
X				YYERROR;
X			}
X			$$ = opcode;
X		}
X	;
X
Xarga	:	addr INTEGER	/* returns addr */
X		{
X			$$ = $1;
X			inst.moda = $1;
X			inst.arga = $2;
X		}
X	|	addr LABEL
X		{
X			$$ = $1;
X			inst.moda = $1;
X			inst.arga = getsymval(alabel, 0);
X		}
X	;
X
Xargb	:	addr INTEGER	/* returns addr */
X		{
X			$$ = $1;
X			inst.modb = $1;
X			inst.argb = $2;
X		}
X	|	addr LABEL
X		{
X			$$ = $1;
X			inst.modb = $1;
X			inst.argb = getsymval(blabel, 1);
X		}
X	;
X
Xaddr:	/* no operand (relative addressing mode) */
X		{	$$=REL;		}
X	|	OIMM
X		{	$$=IMM;		}
X	|	OIND
X		{	$$=IND;		}
X	;
X
X%%
X
Xchar	*argv0;
X
Xextern	void	fatal(), init();
X
X/*
X** main() -	the main program
X*/
Xvoid	main (argc, argv)
Xreg	int	argc;
Xreg	char	**argv;
X{
X	auto	char	buf[BUFSIZ];
X	reg	char	*ptr;
X	auto	char	*ifname, *ofname;
X	auto	int	error = 0;
X
X	argv0 = *argv++, argc--;
X	ofname = RC_OUT;
X	if (argc < 1)
X		usage();
X	ifname = *argv++, argc--;
X	if (argc > 1)
X		usage();
X	if (argc)
X		ofname = *argv;
X	if (!freopen(ptr = ifname, "r", stdin) ||
X	    !freopen(ptr = ofname, "w", stdout))
X	{
X		perror(ptr);
X		exit(1);
X	}
X	init();
X	error = yyparse();
X	fclose(stdin);
X	if (error)
X		fprintf(stderr, "%s: yyparse() error\n", argv0);
X	if (error || fini())
X	{
X		fclose(stdout);
X		unlink(ofname);
X		exit(1);
X	}
X	exit(0);
X}
X
X/*
X** fini()	- resolve any unresolved symbols
X**		- write instructions
X*/
Xint	fini ()
X{
X	reg	int	i;
X	reg	symtab	**us = unres;
X	auto	int	error = FALSE;
X
X	for (us = unres; *us; us++)
X	{
X		reg	symtab	*s;
X		auto	int	inum = abs((*us)->sym_abs)-1;
X		extern	symtab	*getsym();
X
X		if (!(s = getsym((*us)->sym_nam)) || s->sym_abs < 0)
X		{
X			fprintf(stderr, "Inst. %d: label \"%s\" not defined\n",
X				inum, (*us)->sym_nam);
X			error++;
X			continue;
X		}
X		/*
X		fprintf(stderr, "Us inum: %d, \"%s\", %d\n",
X			inum, (*us)->sym_nam, (*us)->sym_abs);
X		*/
X		if ((*us)->sym_abs < 0)
X			memory[inum].argb = s->sym_abs - inum;
X		else
X			memory[inum].arga = s->sym_abs - inum;
X	}
X	if (error)
X	{
X		fprintf(stderr, "%d unresolved labels\n", error);
X		fprintf(stderr, "%s: object file not created\n", argv0);
X		return(TRUE);
X	}
X	for (i=0; i<icnt; i++)
X		if (fwrite(&(memory[i]), sizeof(memory[i]), 1, stdout) != 1)
X		{
X			fprintf(stderr, "%s: write error to output file\n",
X				argv0);
X			perror(argv0);
X			return(TRUE);
X		}
X	return(FALSE);
X}
X
X/*
X** init()	- perform various initializations
X*/
Xvoid	init ()
X{
X	reg	int	i;
X
X	for (i=0; i<MAX_LABELS; i++)
X		symbols[i].sym_nam = (char *) 0;
X	for (i=0; i<JMAX_LEN; i++)
X		unres[i] = (symtab *) NULL;
X}
X
X/*
X** usage() -	print a usage message and exit
X*/
Xvoid	usage ()
X{
X	fprintf(stderr, "Usage: %s infile [outfile]\n", argv0);
X	exit(1);
X}
X
X/*
X** yyerror() -	yacc error routine
X*/
Xvoid	yyerror (msg)
Xreg	char	*msg;
X{
X	fprintf(stderr, "%s: error on line %d (%s)\n", argv0, lcnt, msg);
X}
X
Xstatic	int	sym_cnt = 0;	/* number of symbols in table */
Xextern	symtab	*_addsym(), *addunres(), *getsym();
X
X/*
X** getsymval()	- return the value of the specified symbol relative to
X**		  the current instruction
X**		- if symbol is undefined:
X**			add it to symtab w/o a value
X**			mark this instruction as having an unresolved symbol
X**			return 0
X**		- if which==0, then arga, else argb
X*/
Xint	getsymval (sname, which)
Xreg	char	*sname;
Xreg	int	which;
X{
X	reg	symtab	*s;
X	auto	int	len;
X
X	if (s = getsym(sname))
X	{
X		if (s->sym_abs >= 0)
X			return(s->sym_abs - icnt);
X	}
X	else
X		s = _addsym(sname);
X	s = addunres(s->sym_nam);
X	s->sym_abs += 1;		/* must be >0 */
X	if (which)
X		s->sym_abs *= -1;	/* negative for argb */
X	return(0);
X}
X
X/*
X** addunres()	- add a symbol to the unresolved list
X*/
Xsymtab	*addunres (sname)
Xreg	char	*sname;
X{
X	static	int	index = 0;
X	reg	symtab	**s = &(unres[index++]);
X
X	if (index >= JMAX_LEN)
X		fatal("Symbols used to often");
X	if (!(*s = (symtab *) malloc(sizeof(symtab))))
X		fatal("memory allocation failure");
X	(*s)->sym_nam = sname;
X	(*s)->sym_abs = icnt;
X	return(*s);
X}
X
X/*
X** addsym()	- add a symbol to the symbols[] list
X*/
Xint	addsym (sname)
Xreg	char	*sname;
X{
X	reg	symtab	*s;
X	auto	int	len;
X
X	if ((s = getsym(sname)) && s->sym_abs >= 0)
X	{
X		fprintf(stderr, "label \"%s\" multiply defined\n", sname);
X		return(TRUE);
X	}
X	if (s)
X	{	/* previously used symbol is declared */
X		s->sym_abs = icnt;
X		return(FALSE);
X	}
X	s = _addsym(sname);
X	s->sym_abs = icnt;
X	return(FALSE);
X}
X
X/*
X** _addsym()	- slightly lower lever function, used by both addsym()
X**		  and getsymval()
X*/
Xsymtab	*_addsym (sname)
Xreg	char	*sname;
X{
X	reg	symtab	*s = &(symbols[sym_cnt++]);
X	reg	int	len;
X
X	if (!(s->sym_nam = (char *) malloc(len=(strlen(sname)+1))))
X	{
X		fprintf(stderr, "%s: can't malloc %d bytes\n", argv0, len);
X		fatal("memory allocation failure");
X	}
X	strcpy(s->sym_nam, sname);
X	s->sym_abs = -1;
X	return(s);
X}
X
X/*
X** getsym()	- return a pointer to the specified symbol in the symbol table
X*/
Xsymtab	*getsym (sname)
Xreg	char	*sname;
X{
X	reg	int	i;
X
X	for (i=0; i<sym_cnt; i++)
X		if (!strcmp(sname, symbols[i].sym_nam))
X			return(&(symbols[i]));
X	return((symtab *) NULL);
X}
X
X/*
X** fatal()	- print an error message and exit
X*/
Xvoid	fatal (mesg)
Xreg	char	*mesg;
X{
X	fprintf(stderr, "%s: FATAL error: %s\n", argv0);
X	exit(1);
X}
X
X#include "rcasm.h"	/* the lexical analyzer */
END-of-rcasm.y
echo file: rcasm.l
sed 's/^X//' >rcasm.l << 'END-of-rcasm.l'
X	/*
X	**	lexical analyzer for input to Redcode Assembler
X	**
X	** [cw by Peter Costantinidis, Jr. @ University of California at Davis]
X	**
X	static	char	rcsid[] = "$Header: rcasm.l,v 7.0 85/12/28 14:37:16 ccohesh Dist $";
X	**
X	*/
X	/* definitions */
XI	-?[0-9]+
XC	\/.*$
XW	[" "\t]+
XL	"$"[a-zA-Z0-9]+
X%%
X{C}	return(COMMENT);
Xdat|DAT	return(opcode=DAT, orc=1, OPCODE);
Xmov|MOV	return(opcode=MOV, orc=2, OPCODE);
Xadd|ADD	return(opcode=ADD, orc=2, OPCODE);
Xsub|SUB	return(opcode=SUB, orc=2, OPCODE);
Xjmp|JMP	return(opcode=JMP, orc=1, OPCODE);
Xjmz|JMZ	return(opcode=JMZ, orc=2, OPCODE);
Xdjz|DJZ	return(opcode=DJZ, orc=2, OPCODE);
Xcmp|CMP	return(opcode=CMP, orc=2, OPCODE);
Xmul|MUL	return(opcode=MUL, orc=2, OPCODE);
Xdiv|DIV	return(opcode=DIV, orc=2, OPCODE);
Xrnd|RND	return(opcode=RND, orc=1, OPCODE);
X"#"	return(OIMM);
X"@"	return(OIND);
X"\n"	return(NL);
X{W}	;
X^{L}":"	{
X		static	char	buf[LABEL_LEN+1];
X		auto	int	len = min(yyleng-2, LABEL_LEN);
X
X		strncpy(buf, &(yytext[1]), len);
X		buf[len] = '\0';
X		dlabel = &(buf[0]);
X		return(DLABEL);
X	}
X{L}	{
X		static	char	bufs[2][LABEL_LEN+1];
X		auto	int	len = min(yyleng+1, LABEL_LEN);
X		auto	char	**ptr;
X
X		if (orc == 1)
X			ptr = &blabel;
X		else
X			ptr = (toggle ? &blabel : &alabel);
X		strncpy(bufs[toggle], &(yytext[1]), len);
X		bufs[toggle][len] = '\0';
X		*ptr = bufs[toggle];
X		toggle = (toggle ? 0 : 1);
X		return(LABEL);
X	}
X{I}	{
X		extern	int	yy