[net.sources.games] Core Wars

ccohesh001@ucdavis.UUCP (Peter Costantinidis, Jr.) (12/13/85)

TITLE
        cw - Core Ware with visual display

INTENDED ENVIRONMENT
        UNIX

TESTED ENVIRONMENTS
        BSD 4.2 VAX 11/750

DESCRIPTION
        Cw is the "Core War" game system.  There are three programs in
        this system, "rcasm" the assembler, "unrc" the disassembler, and
        "mars" the simulator.  By default the simulator runs in visual
        mode (representing the memory array with a box of periods ('.')),
        but can be run in non-visual mode where you have the option to
        print each instruction as it is executed.
     
        This program is entirely new and has not been posted previously.

NOTES
        Cw uses curses, lex, yacc and bitfields.  If your system does
        not have virtual memory, some of the sizes defined in "cw.h"
        will have to be changed.  There is no equivalent of a "fork"
        instruction in this implementation, but "mars" can run more
        than two programs at once.

CHALLENGE
        Lets have a net-wide battle where those participating post
        their best redcode program to net.sources.games.  Winners are
        invited to boast on net.games.

WHEREAMI
        net.sources.games

BUGS

        Please send all bug reports to:
     
                {dual,lll-crg,ucbvax}!ucdavis!deneb!ccohesh001

AUTHOR
        Peter Costantinidis, Jr., University of California at Davis

THANKS TO
        A. K. Dewdney and D. G. Jones
--
-- Peter Costantinidis, Jr.
-- ucdavis!deneb!ccohesh001@ucb-vax.arpa                (ARPA)
-- ...!{ucbvax,lll-crg,dual}!ucdavis!deneb!ccohesh001   (UUCP)

ccohesh001@ucdavis.UUCP (Peter Costantinidis, Jr.) (12/13/85)

#!/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"
: "     gemini.rc"
: "     dwarf.rc"
: "     imp.rc"
: "     stomper.rc"
: "This archive created:  Fri Dec 13 00:35:42 PST 1985 "
echo file: READ_ME
sed 's/^X//' >READ_ME << 'END-of-READ_ME'
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 6.0 85/12/13 00:30:57 ccohesh001 Dist $";
X#
X#      [cw by Peter Costantinidis, Jr. @ University of California at Davis]
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  =       gemini.rc dwarf.rc imp.rc stomper.rc
X#
X# libs
X#
XCWLIB  =       cw.a
XCRLIB  =       -lcurses
XTERMLIB        =       -ltermlib
XALLLIBS        =       $(CWLIB) $(CRLIB) $(TERMLIB)
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               rcasm dwarf.rc dwarf
X               rcasm imp.rc imp
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
Xcw.nr:         cw.6
X               tbl cw.6 | nroff -ms
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)
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 6.0 85/12/13 00:31:06 ccohesh001 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
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 [-dilprv] [-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 6.0 85/12/13 00:31:27 ccohesh001 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 6.0 85/12/13 00:31:33 ccohesh001 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       junk._flag = _IOWRT + _IOSTRG;
X       junk._ptr = &msgbuf[0];
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 6.0 85/12/13 00:31:37 ccohesh001 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               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 6.0 85/12/13 00:31:42 ccohesh001 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                       COREA = 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 6.0 85/12/13 00:31:49 ccohesh001 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 6.0 85/12/13 00:31:52 ccohesh001 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 6.0 85/12/13 00:32:03 ccohesh001 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 6.0 85/12/13 00:32:10 ccohesh001 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                       incnt = 1;
X               when MOV:
X                       incnt = 2;
X               when ADD:
X                       incnt = 2;
X               when SUB:
X                       incnt = 2;
X               when JMP:
X                       incnt = 1;
X               when JMZ:
X                       incnt = 2;
X               when DJZ:
X                       incnt = 2;
X               when CMP:
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 6.0 85/12/13 00:32:14 ccohesh001 Dist $";
X.\"
X.TH CW UCD "2 December 1985"
X.SH NAME
Xmars, rcasm, unrc \- Corewar game 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 ammount 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 botto 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(:) box;
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::BT{
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(:) box;
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 6.0 85/12/13 00:32:23 ccohesh001 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%}
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                       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                       $$ = inst.moda = $1;
X                       inst.arga = $2;
X               }
X       |       addr LABEL
X               {
X                       $$ = inst.moda = $1;
X                       inst.arga = getsymval(alabel, 0);
X               }
X       ;
X
Xargb   :       addr INTEGER    /* returns addr */
X               {
X                       $$ = inst.modb = $1;
X                       inst.argb = $2;
X               }
X       |       addr LABEL
X               {
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               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*/
Xyyerror (msg)
Xreg    char    *msg;
X{
X       fprintf(stderr, "%s: error on line %d (%s)\n", argv0, lcnt, msg);
X       fprintf(stderr, "yychar: %d\n", yychar);
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;
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 6.0 85/12/13 00:32:34 ccohesh001 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     yylval;
X
X               if (sscanf(yytext, "%d", &yylval) != 1)
X                       return(ERROR);
X               yylval = sum(yylval, 0);
X               return(INTEGER);
X       }
X.
X       {
X               fprintf(stderr, "%s: unrecognized character in lex: %o\n",
X                       argv0, yytext[0]);
X               return(ERROR);
X       }
X%%
END-of-rcasm.l
echo file: shar
sed 's/^X//' >shar << 'END-of-shar'
X#!/bin/sh
Xecho "#!/bin/sh"
Xecho ": \"This is a shell archive, meaning:                              \""
Xecho ": \"1. Remove everything above the #! /bin/sh line.                \""
Xecho ": \"2. Save the resulting test in a file.                          \""
Xecho ": \"3. Execute the file with /bin/sh (not csh) to create the files:\""
Xfor i
Xdo
X       echo ": \"      $i\""
Xdone
Xecho -n ": \"This archive created:  "
Xecho `date` \"
Xfor i
Xdo
X       echo "echo file: $i"
X       echo "sed 's/^X//' >$i << 'END-of-$i'"
X       sed 's/^/X/' $i
X       echo "END-of-$i"
Xdone
Xecho exit
END-of-shar
echo file: gemini.rc
sed 's/^X//' >gemini.rc << 'END-of-gemini.rc'
X       jmp             $START          /jump to start of program
X$SRC:  dat             0               /pointer to source address
X$DST:  dat             99              /pointer to dest. address
X$START:        mov     @$SRC   @$DST           /copy source to dest.
X       cmp     $SRC    #11             /if all 10 lines have been copied...
X       jmp     $DONE                   /...then leave the loop
X       add     #1      $SRC            /otherwise, increment the source address
X       add     #1      $DST            /...and the dest. address
X       jmp     $START                  /...and return to the loop
X$DONE: mov     #99     93              /restore the starting dest. address
X       jmp     93                      /jump to the new copy
END-of-gemini.rc
echo file: dwarf.rc
sed 's/^X//' >dwarf.rc << 'END-of-dwarf.rc'
X       JMP              $BEGIN
X$WHERE:        DAT              9              / change this to a 4 and dwarf's
X$BEGIN:        ADD     #8       $WHERE         / won't kill eachother
X       MOV     #-3     @$WHERE
X       JMP              $BEGIN
END-of-dwarf.rc
echo file: imp.rc
sed 's/^X//' >imp.rc << 'END-of-imp.rc'
X$START:        mov     $START  $END
X$END:  dat     0
END-of-imp.rc
echo file: stomper.rc
sed 's/^X//' >stomper.rc << 'END-of-stomper.rc'
X/
X/ stomper.rc   - son of dwarf and gemini (he's a mover and he's aggressive)
X/
X       jmp             $START          /jump to start of program
X$SRC:  dat             0               /pointer to source address
X$DST:  dat             191             /pointer to destination address
X$START:        mov     @$SRC   @$DST           /copy source to destination
X       cmp     $SRC    #13             /if all 10 lines have been copied...
X       jmp     $DONE                   /...then leave the loop
X       add     #1      $SRC            /otherwise, increment the source address
X       add     #1      $DST            /...and the destination address
X       add     #8      $BOMB           /increment bomber address
X       mov     #0      @$BOMB          /drop bomb
X       jmp     $START                  /...and return to the loop
X$DONE: mov     #4      @$DST           /reset bomber address
X       mov     #191    182             /restore the starting destination address
X       jmp     182                     /jump to the new copy
X$BOMB: dat             4
END-of-stomper.rc
exit
--
-- Peter Costantinidis, Jr.
-- ucdavis!deneb!ccohesh001@ucb-vax.arpa                (ARPA)
-- ...!{ucbvax,lll-crg,dual}!ucdavis!deneb!ccohesh001   (UUCP)

myke@gitpyr.UUCP (Myke Reynolds) (12/20/85)

>>>>>>>> marks a changed line in rcasm.[ly]

in rcasm.l: starting at line 40
--------------------------------------------------------------------------------
{L}	{
		static	char	bufs[2][LABEL_LEN+1];
		auto	int	len = min(yyleng+1, LABEL_LEN);
		auto	char	**ptr;

		if (orc == 1)
			ptr = &blabel;
		else
			ptr = (toggle ? &blabel : &alabel);
		strncpy(bufs[toggle], &(yytext[1]), len);
		bufs[toggle][len] = '\0';
		*ptr = bufs[toggle];
		toggle = (toggle ? 0 : 1);
>>>>>>>>	blabel = *ptr;				/* ADD THIS! */
		return(LABEL);
	}


and in rcasm.y: starting at line 137
--------------------------------------------------------------------------------
word order is reverse on our machine, when you set:
$$ = inst.modb = $1;  modb is a bit field in inst, so when $1 gets passed though
inst, it is put in the wrong place and yyval ($$) gets entirely the wrong value.
--------------------------------------------------------------------------------
arga	:	addr INTEGER	/* returns addr */
		{
>>>>>>>>		inst.moda = $$ = $1;
			inst.arga = $2;
		}
	|	addr LABEL
		{
>>>>>>>>		inst.moda = $$ = $1;
			inst.arga = getsymval(alabel, 0);
		}
	;

argb	:	addr INTEGER	/* returns addr */
		{
>>>>>>>>		inst.modb = $$ = $1;
			inst.argb = $2;
		}
	|	addr LABEL
		{
>>>>>>>>		inst.modb = $$ = $1;
			inst.argb = getsymval(blabel, 1);
		}
	;
-- 
Myke Reynolds
Office of Telecommunications and Networking
Georgia Insitute of Technology, Atlanta Georgia, 30332
...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!myke

"Drawing from my fine command of the english language, I said nothing."