COREWARS
An Existentialist
c60a-3ci at web-3f.berkeley.edu
Sat Jan 21 07:38:45 AEST 1989
Here's a copy of the COREWARS programs. To extract, save to a file, delete
this headers, and type:
%sh < <filename>
The MANIFEST file should have a listing of ALL the files included with this
package.
Na Choon Piaw
c60a-3ci at wolf.berkeley.edu
(soon to be changed)
301P, 2650 Durant,
Berkeley, CA 94720.
P.S. There is also a "bitmapped" display version that works ONLY for the
SUN. You must have a SUN 3/50 or better and the pixrect library for
it to work. Mail me for the source.
----------------------- cut here -------------------------
echo x - MANIFEST
cat >MANIFEST <<'!E!O!F!'
CoreWars public distribution package, by Na Choon Piaw.
You should have the following files:
Assembler:
assem.h - assembler data structures
assem.c - assembler function
disassemble - disassembler
lookup.c - does symbol matching
amain.c - "main" for the assembler
aoutput.c - output function for the assembler
parse.c - parser for the assembler
tokenize.c - tokenizer for the assembler
MakeAss - Makefile for the assembler
Interpreter:
interp.h - interpreter data structures
inst.c - implementation of simulator
load.c - loader
main.c - "main" for the interpreter
output.c - output functions for the interpreter
MakeInt - Makefile for the interpreter
*.rc - redcode programs (sample)
MANIFEST - this file
README - documentation file
To install, type:
%make -f MakeAss
%make -f MakeInt
%assem *.rc
Please send all bug reports and modifications as well as other interesting
notes to:
Na Choon Piaw
c60a-3ci at web.berkeley.edu
301P, 2650 Durant,
Berkeley, CA 94720.
(to be changed later)
Note: You are now a "registered user". Doesn't mean anything, means I've
got a list of people to send updates to.
!E!O!F!
echo x - MakeAss
cat >MakeAss <<'!E!O!F!'
all: assem disassem
assem: amain.o tokenize.o parse.o lookup.o aoutput.o assem.o
cc amain.o tokenize.o parse.o assem.o lookup.o aoutput.o -o assem
disassem: disassem.c assem.h
cc -O disassem.c -o disassem
main.o: amain.c assem.h
cc -O -c amain.c -o main.o
tokenize.o: tokenize.c assem.h
cc -O -c tokenize.c -o tokenize.o
parse.o: parse.c assem.h
cc -O -c parse.c -o parse.o
lookup.o: lookup.c assem.h
cc -O -c lookup.c -o lookup.o
output.o: aoutput.c assem.h
cc -O -c aoutput.c -o aoutput.o
assem.o: assem.c assem.h
cc -O -c assem.c -o assem.o
!E!O!F!
echo x - MakeInt
cat >MakeInt <<'!E!O!F!'
CFLAGS = -DSMALL
interp: main.o load.o output.o play.o inst.o
cc -o interp main.o load.o output.o play.o inst.o -lcurses -ltermcap
main.o: interp.h main.c MakeInt
cc -c $(CFLAGS) main.c -o main.o
load.o: interp.h load.c
cc -c $(CFLAG) load.c -o load.o
output.o: interp.h output.c MakeInt
cc -c $(CFLAGS) output.c -o output.o
play.o: play.c interp.h MakeInt
cc -c $(CFLAGS) play.c -o play.o
inst.o: inst.c interp.h
cc -c $(FLAGS) inst.c -o inst.o
!E!O!F!
echo x - README
cat >README <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
This is a new version of corewars I'm working on. It will feature
ONLY 2 player games (I hate 3 or more players on corewars), some limited
amounts of display (using curses) though that will be implemented only
after the non-display functions work. And an independent, full featured
assembler. The interpreter will load "binary" code only.
Full featured -- 1 physical pass, 2 "in memory" passes.
symbolic memory addresses, immediate, direct, and indirect
addressing modes.
COREWARS is a where the players each write an assembly language program
that battle each other in the memory of a computer called MARS. (Memory
Array Redcode Simulator) The game ends when (1) all the streams of execution
on one side have died out, or (2) when the time limit is up. In (1) the
winner is the side which still has surviving execution streams. In (2)
the game is a draw. Once we are finished with implementing this game,
maybe we can schedule a corewars tournament.
My version of corewars implements (hopefully in a short while) the following
instructions from World 7 --- The First Corewars Tournament (with some
modifications) (Note: the first two articles have slightly differing
definitions):
INSTRUCTION MNEUMONIC CODE ARGUMENTS EXPLANATION
Move mov 1 A B move contents of
address A to address B
Add add 2 A B add contents of address
A to address B
Subtract sub 3 A B subtract contents of
address A from address
B
Jump jmp 4 B Transfer control
to address A
Jump if zero jmz 5 A B Transfer control
to address A if
contents of B are
greater then 0
Jump if not 0 jmn 6 A B transfer control to
address B if contents
of B is != 0
Decrement jump djn 7 A B Subtract 1 from
if not zero contents of address
B and transfer
control to
address A if contents
of address B is != 0
Compare cmp 8 A B compare contents of
addresses A and B; if
they are unequal,
skip the next
instruction.
Split spl 9 B split execution into
next instruction and
the instruction at A
Data statment dat 0 B A nonexecuatble
statement; B is the
data value.
Addressing modes:-
immediate mode: #argument
direct mode: symbol
indirect mode: @symbol
Expected other differences -
1) When +/- are conducted to an address that contains other than a
data instruction, parameter B is always modified (even in spl
instructions). There is no way and add or sub instruction can
change one type of instruction to another, so the CODE part of
the table is really rather worthless.
2) The assembler will feature the "real" symbol. In other words,
you do not have to convert all your symbols into numbers before
feeding your program to the assembler.
There will be a reserved symbol, though, called "start" and this
will be where your code will start executing.
All symbols are characterized by a ':' character at the end, e.g.
"start:"
3) Separate assembly. In the interest of modularity and ease of
debugging (for my code, of course, not for the redcode assembly
program, so I still don't suggest writing 200 instruction redcode
programs, even though the assembler permits it), I have decided
to separate the assembler from the interpreter. The interpreter
will have to be fed the preassembled programs, etc. in a special
format. (produced by the assembler).
4) Will not implement stuff like the "<" or the ">". i.e., decrease
stuff pointed to by operand, then get that address.
5) Randomized starting memory for the redcode programs.
Make corewars more deterministic - predictable.
Can be implemented later if demand arises.
Other expected differences -
BUGS!!!
BUG REPORT SECTION:-
assem/main.c - The program will not accept files with ".e" anywhere
in the last portion of it (i.e., the extension)
These files will be rejected.
e.g. "mice.eecs" will be rejected
tokenize.c - The program will not be able to handle comments without
any delimiters between them and the code.
e.g. "mov 0 1;;help" will be tokenized into:
"mov" "0" "1;;help" which is not acceptable, since
the later functions like lookup will not be able
to handle it.
play.c/main.c: - The BIG option (to fully bit map the memory array,
doesn't work. I wonder why?)
Note:
A.K. Dewdney's THE ARMCHAIR UNIVERSE is available from Freeman (publisher).
I highly recommend buying a copy and reading it. It's a whole lot
of fun and teaches a lot of great programming techniques.
It's moderately priced at around $13.25, and, in my opinion, worth every
penny.
Choon Piaw
Assembler portion of corewars
Usage:
assem <file1> <file2> .....
All output files will have an additional extension ".e"
for instance, if the input file was "help.rc" the ouput file will be "help.e"
Assembler limits: 200 instructions
100 symbols
255 characters in a string
Comments are indicated by a ;
Assembler is not case sensitive.
Remember that this does not conform to ALL the A.K. Dewdney standards
in the implementation of OPCODES/PARAMETERS, but as long as you write
code that does not depend on changing other's opcode, you should be
all right. The instruction set is standard, however.
BUGS:
Any file starting with a .e extension is rejected automatically
Any character is recognized as a symbol. Therefore, in
mov 0 1;this is a comment
1;this will be interpreted as a symbol instead of a number with
a comment following it. The proper form would be:
mov 0 1 ;this is a comment
Corewars interpreter
- started 12/14/88 by Na Choon Piaw (The Existentialist)
usage:
interp cycles file1 file2
cycles -number of machine cycles
file1, file2 -preassembled corewars programs
Programmer's documentation for Redcode interpreter
Goal:
To provide a visual version of corewars that is fast, standard and portable.
Modules
1. int loader(int position)
- load up files into main memory to position.
- setup the starting pcs
2. eval
- input the memory element + a host of other info
(including the list of streams)
- each of the instructions will be handled by a separate
subroutine that will be passed just sufficient info to carry
it out.
3. control
- responsible for keeping track of who's what and passing the
correct instruction to the evaluator
4. Display
- Display in a visual format (to be decided) what's going on
in memory at that time.
Data Structures
Streams of execution are kept as circularly linked list, with split
instructions adding to the linked list, and with trying to execute data
instructions.
All parameters will range from 0 to +8000. Excess will be trimmed off,
negatives will be wrapped back around.
Credit where credit is due:
Case Larsen wrote and debugged the SUN graphics function interface2.c
Adrain Ho wrote and debugged the loader load.c
I wrote and debugged the rest.
!E!O!F!
echo x - assem.h
cat >assem.h <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* MARS redcode assembler:
Header file
Restarted in Novemeber '88
Na Choon Piaw */
/* note that tag is just a generic name for something that I can't think
of a name for. ---- CP */
/* define instruction set */
typedef enum { dat, mov, add, sub, jmp, jmz, jmn, djn, cmp, spl } instr;
/* define addressing modes */
typedef enum { immed, direct, indirect } mode;
/* define structure of an instruction */
/* NOTE: this will probably differ from the interpreter's version */
typedef struct
{
instr inst; /* instruction */
int para1,para2; /* first parameter, second parameter */
mode m1,m2; /* addressing modes for parameters */
} memory; /* memory element */
/* define compiler limits */
#define MAXINST 200 /* maximum number of instructions */
#define SYMBOLS 100 /* maximum number of symbols in symbol table */
#define MAXBUFFER 256 /* maximum size of string buffer */
#define COMMENT ';' /* comment character */
/* linked list of tokens for tokenizer and assembler to work on */
typedef struct tag0
{
char *token; /* token as a string */
struct tag0 *next; /* next token */
} tokenlist;
/* symbol table structure */
typedef struct
{
char *symbol; /* pointer to string of symbol */
int position; /* position the symbol belongs to */
} tag1;
/* now to define the strings that the assembler recognizes */
#define MOV "MOV"
#define ADD "ADD"
#define SUB "SUB"
#define JMP "JMP"
#define JMZ "JMZ"
#define JMN "JMN"
#define DJN "DJN"
#define CMP "CMP"
#define SPL "SPL"
#define DAT "DAT"
!E!O!F!
echo x - interp.h
cat >interp.h <<'!E!O!F!'
/* MARS redcode interpreter:
Header file
Started December '88
Na Choon Piaw */
/* instruction set */
typedef enum { dat, mov, add, sub, jmp, jmz, jmn, djn, cmp, spl } instr;
/* addressing modes */
typedef enum { immed, direct, indirect } mode;
/* this is the new definition of a memory cell */
typedef struct
{
instr inst; /* instruction */
int para1, para2; /* first parameter, second parameter */
mode m1, m2; /* addressing modes */
int lastmod; /* last modified by */
} cell;
/* old assembler definition of memory cell */
typedef struct
{
instr inst;
int para1, para2;
mode m1, m2;
} memory;
/* doubly circularly linked list for streams of execution */
typedef struct tag0
{
int pc; /* program counter */
struct tag0 *next, *prev;
} stream;
/* interpreter limits */
#define MAXINST 200 /* maximum number of instructions */
#define SIZE 8000 /* size of array */
#define MAXPLAY 3 /* maximum number of players */
#define RANDIVISOR 33
!E!O!F!
echo x - amain.c
cat >amain.c <<'!E!O!F!'
/* this module contains the main function, which settles open/close
file i/o as well as little trivial details like adding an extension
and stuff like that. It has been debuged (except for BUG NOTES)
so it's safe to trust. There is a little bit of inefficiency, but
that's justified since I want a more easily readable program */
#include "assem.h"
#include <stdio.h>
#include <malloc.h>
#include <strings.h>
char *outname(str)
char *str;
/* accepts an input string and outputs a proper output file with ".e"
extension. If already has .e, as an extension, produce an error.
BUG NOTE: even if it's as innoculous as .eex, etc (as long as the
extension starts with .e) it will still produce an error
Otherwise, remove current extension
and add .e extension.
returns pointer to new output name */
{
char *newstr;
char *dot; /* position of '.' */
if (!(newstr =(char *) malloc( (unsigned) strlen(str) + 3)))
{
printf("not enough memory --- outname\n");
exit(1);
}
strcpy(newstr,str);
if (!(dot = rindex(newstr,'.')))
strcat(newstr,".e"); /* no extenstion */
else if (*(dot + 1) == 'e') /* same extension as output? */
{
printf("wrong input file name: %s\n", newstr);
printf("try moving to non .e extension --- outname\n");
exit(1);
}
else /* perform surgery */
{
(*(dot + 1)) = 'e';
(*(dot + 2)) = '\0';
}
return newstr;
}
/* main -- Open input and output files, giving default names if
necessary. Detects errors like not being able to open files
etc.
*/
main(argc, argv)
int argc;
char *argv[];
{
FILE *f1,*f2; /* input file, output file */
char *outfile = "NONAME", /* default output file */
flag = 0; /* standard input */
if (argc == 1) /* no arguments */
{
flag = 1; /* read from standard input */
argv[1] = outfile;
argc = 2; /* one file */
}
for (;argc > 1; argc--)
{
if (flag)
f1 = stdin; /* set file to standard input */
else
/* open input file */
if (!(f1 = fopen(argv[argc - 1],"r")))
{
printf("oops cannot open file %s",
argv[argc - 1]);
printf("\n-- in main\n");
exit(1); /* error status 1 */
}
/* open output file */
if (!(f2 = fopen(outname(argv[argc - 1]), "w")))
{
printf("cannot open write file %s",
outname(argv[argc - 1]));
printf("\n --- in main\n");
exit(1);
}
printf("%s:\n", argv[argc - 1]);
assemble(f1,f2); /* call assembler */
if (!flag) /* close file */
fclose(f1);
fclose(f2);
}
}
/* debugging version of assemble */
/* commented out because this module is now fully debugged */
/* --- Na Choon Piaw, 11/14 */
/*
assemble(infile,outfile)
FILE *infile, *outfile;
{
int c;
while ((c = fgetc(infile)) != EOF)
fputc(c, outfile);
}
*/
!E!O!F!
echo x - aoutput.c
cat >aoutput.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* output.c --- output routine for the asssembler.
11/25/88 --- NCP */
/* algorithm:
1. write number of instructions into file
2. write code number of start instruction
3. while there are still instructions do
4. write instruction n
5. end
*/
#include "assem.h"
#include <stdio.h>
#define IO(i,j) if ((i) < (j)) { printf("error in writing file --- output\n" \
); }
output(f, table, code, no)
FILE *f; /* file to output to */
tag1 table[]; /* table of symbols */
memory code[]; /* code itself */
int no; /* number of instructions */
{
int check, /* check on how many bytes have been written */
start; /* starting instruction */
check = fwrite(&no, sizeof(int), 1, f);
IO(check,1)
start = getsym("START",table);
check = fwrite(&start, sizeof(int), 1, f);
IO(check,1);
check = fwrite(code, sizeof(memory), no, f);
IO(check,no);
}
!E!O!F!
echo x - assem.c
cat >assem.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* assembler portion of the program */
/* 11/14 '88
Implementing a one-pass "text in memory" assembler that handle tokens
as well. Symbol table is a linear table.
Algorithm:
1) Tokenize the input file (i.e. produce a list of symbols in mem)
2) Run through once, parsing instructions but not turning
into machine code yet. Insert all new symbols into symbol
table.
3) Run through second time, turning it into machine code
and looking up symbols. -- the real error phase.
*/
#include <stdio.h>
#include <malloc.h>
#include "assem.h"
/* symbol table */
static tag1 table[SYMBOLS];
/* instructions list */
static memory elements[MAXINST];
/* declaring the functions */
tokenlist *tokenize();
/* top level connections for assembler hooks up tokenize, parse, lookup
and output so that they can be written independently (no global
variables in this program */
assemble(infile, outfile)
FILE *infile,*outfile;
{
tokenlist *head;
int i; /* number of instructions */
head = tokenize(infile);
parse(head, table);
i = lookup(head, table, elements);
output(outfile, table, elements, i);
}
!E!O!F!
echo x - disassem.c
cat >disassem.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
#include <stdio.h>
#include "assem.h"
/* dissassembler for red code programs.
NOTE: I'm not bothering with writing code to REALLY disassemble
it, just output starting position, number of instructions,
opcode, and operands.
11/25 ---- NCP */
#define IO(i,j) if ((i) < (j)) {printf("error reading file\n");exit(1);}
main(argc, argv)
int argc;
char *argv[];
{
FILE *f;
int i,j,k;
memory elements[MAXINST];
if (argc < 1)
{
printf("usage: disassem <file>\n");
exit(1);
}
if (!(f = fopen(argv[1],"r")))
{
printf("cannot open file %s\n", argv[1]);
printf("------ main\n");
exit(1);
}
i = fread(&j, sizeof(int), 1, f);
IO(i,1)
printf("Number of instructions: %d\n", j);
i = fread(&k, sizeof(int), 1, f);
IO(i,1)
printf("Starting instruction: %d\n", k);
i = fread(elements, sizeof(memory), j, f);
IO(i,j)
printf("NO.\tOPCODE\tFIRSTPARA\tSECONDPARA\n");
for (i = 0; i < j;i++)
{
printf("%d\t", i);
printf("%d\t", (int) elements[i].inst);
if (elements[i].m1 == immed)
putchar('#');
else if (elements[i].m1 == indirect)
putchar('@');
printf("%d\t\t", (int) elements[i].para1);
if (elements[i].m2 == immed)
putchar('#');
else if (elements[i].m2 == indirect)
putchar('@');
printf("%d\n", (int) elements[i].para2);
}
fclose(f);
}
!E!O!F!
echo x - inst.c
cat >inst.c <<'!E!O!F!'
/* execution code for the machine */
/* This is a replacement for the screwed up code in "execute.c"
Each instruction is a function, and accepts just enough information
to execute that instruction.
*/
#include "interp.h"
#include <malloc.h>
#include <stdio.h>
extern cell a[]; /* core */
correct(thing)
int *thing;
{
if (*thing >= 0)
*thing %= SIZE;
else if (*thing < 0)
{
*thing %= SIZE;
*thing = SIZE + *thing;
}
}
int getdirect(ins, off)
/* get position of direct parameter */
int ins; /* current position */
int off; /* offset of instruction */
{
int temp;
temp = ins + off;
correct(&temp);
return (temp);
}
int getindirect(ins, off)
/* get position of indirect parameter */
/* Note :-
A.K. Dewdney's specifications say that the pointer points relative to its
current position, NOT the instruction's position. */
int ins;
int off;
{
int temp; /* temporary variable */
correct(&off);
temp = getdirect(ins, off); /* get direct variable */
correct(&temp); /* correct it */
temp = getdirect(temp, a[temp].para2); /* This time it's for real */
correct(&temp);
return (temp);
}
int getpara(ins, m, p)
/* Note:- This routine is designed only to work with indirect and direct
operations. NOT with immediate mode operations. Returns the address
of the parameter by calling getdirect or getindirect */
int ins; /* location of current instruction */
mode m; /* mode */
int p; /* parameter */
{
if (m == direct)
return(getdirect(ins, p));
else if (m == indirect)
return(getindirect(ins, p));
/* else */
printf("getpara passed wrong parameter --- getpara\n");
exit(1);
}
Mov (ins, pc, pid)
/* MOV instruction :
sets the lastmod flag to the process id */
int ins; /* position of instruction to execute */
int *pc; /* program counter */
int pid; /* process ID */
{
int realpos;
cell temp; /* store item to be moved */
if (a[ins].m1 == immed)
{
temp.inst = dat;
temp.para1 = 0;
temp.para2 = a[ins].para1;
temp.m1 = temp.m2 = immed;
}
else
{
realpos = getpara(ins, a[ins].m1, a[ins].para1);
temp = a[realpos];
}
if (a[ins].m2 == immed)
{
printf("Tried to mov to immediate parameter\n");
printf("--- mov\n");
exit(1);
}
else
realpos = getpara(ins, a[ins].m2, a[ins].para2);
a[realpos] = temp;
a[realpos].lastmod = pid;
(*pc)++;
correct(pc);
}
Add(ins, pc, pid)
/* ADD instruction */
int ins;
int *pc;
int pid;
{
int x; /* parameter A */
int realpos; /* real position of B */
if (a[ins].m1 == immed)
x = a[ins].para1;
else
x = a[getpara(ins, a[ins].m1, a[ins].para1)].para2;
if (a[ins].m2 == immed)
{
printf("Trying to add to immediate address\n");
printf("--- ADD\n");
exit(1);
}
else
realpos = getpara(ins, a[ins].m2, a[ins].para2);
a[realpos].para2 += x;
a[realpos].lastmod = pid;
correct(&(a[realpos].para2));
(*pc)++;
correct(pc);
}
Sub(ins, pc, pid)
/* SUB instruction */
int ins;
int *pc;
{
int x; /* parameter A */
int realpos; /* real position of B */
if (a[ins].m1 == immed)
x = a[ins].para1;
else
x = a[getpara(ins, a[ins].m1, a[ins].para1)].para2;
if (a[ins].m2 == immed)
{
printf("Trying to subtract from immediate address\n");
printf("--- SUB\n");
exit(1);
}
else
realpos = getpara(ins, a[ins].m2, a[ins].para2);
a[realpos].para2 -= x;
a[realpos].lastmod = pid;
correct(&(a[realpos].para2));
(*pc)++;
correct(pc);
}
Jmp(ins,pc)
int ins;
int *pc;
{
if (a[ins].m2 == immed)
{
printf("attempt to jump to immediate address\n");
printf("-- JMP\n");
exit(1);
}
else
*pc = getpara(ins, a[ins].m2, a[ins].para2);
correct(pc);
}
Jmz(ins, pc)
int ins;
int *pc;
{
int value; /* value of first parameter */
if (a[ins].m2 == immed)
value = a[ins].para2;
else
{
value = getpara(ins, a[ins].m2, a[ins].para2);
correct(&value);
value = a[value].para2;
}
correct(&value);
if (value)
(*pc)++;
else
*pc = getpara(ins, a[ins].m1, a[ins].para1);
correct(pc);
}
Jmn(ins,pc)
int ins;
int *pc;
{
int value;
if (a[ins].m2 == immed)
value = a[ins].para2;
else
{
value = getpara(ins, a[ins].m2, a[ins].para2);
correct(&value);
value = a[value].para2;
}
if (!value)
*pc = getpara(ins, a[ins].m1, a[ins].para1);
else
(*pc)++;
correct(pc);
}
Djn(ins, pc, pid)
int ins;
int *pc;
{
int temp; /* position to decrement */
if (a[ins].m2 == immed)
{
printf("tried to decrement immediate address\n");
printf("--- DJZ\n");
exit(1);
}
else
temp = getpara(ins, a[ins].m2, a[ins].para2);
(a[temp].para2)--;
correct(&(a[temp].para2));
a[temp].lastmod = pid;
if (!a[temp].para2)
(*pc)++;
else
*pc = getpara(ins, a[ins].m1, a[ins].para1);
correct(pc);
}
Cmp(ins, pc)
int ins;
int *pc;
{
int value1, value2;
if (a[ins].m1 == immed)
value1 = a[ins].para1;
else
value1 = a[getpara(ins, a[ins].m1, a[ins].para1)].para2;
if (a[ins].m2 == immed)
value2 = a[ins].para2;
else
value2 = a[getpara(ins, a[ins].m2, a[ins].para2)].para2;
correct(&value1);
correct(&value2);
if (value1 == value2)
(*pc) += 2;
else
(*pc)++;
correct(pc);
}
Spl(ins, pc, mem)
int ins;
int *pc;
stream *mem; /* pointer to structure of current pc */
{
int newpc;
stream *newmem;
if (a[ins].m2 == immed)
{
printf("Tried to split into immediate address\n");
printf("--- SPL\n");
exit(1);
}
else
newpc = getpara(ins, a[ins].m2, a[ins].para2);
if (!(newmem = (stream *) malloc(sizeof(stream))))
{
printf("no more memory!!\n");
printf("--- SPL\n");
exit(1);
}
correct(&newpc);
newmem -> pc = newpc;
newmem -> next = mem -> next;
mem -> next = newmem;
newmem -> prev = mem;
newmem -> next -> prev = newmem;
(*pc)++;
correct(pc);
}
extern stream *exe[];
Dat(i)
/* kill stream */
int i;
{
stream *curr = exe[i]; /* current */
if (curr -> next == curr)
{
exe[i] = NULL;
free(curr);
return;
}
exe[i] = curr -> next;
curr -> next -> prev = curr -> prev;
curr -> prev -> next = curr -> next;
free(curr);
}
!E!O!F!
echo x - interp.c
cat >interp.c <<'!E!O!F!'
!E!O!F!
echo x - load.c
cat >load.c <<'!E!O!F!'
/* program loader for MARS
12/16/88 --- NCP */
#include "interp.h"
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#define IO(i,j) if((i) < (j)){printf("error reading file\n");exit(1);}
extern cell a[];
extern stream *exe[];
/* generates starting position */
/* debugging non random version */
int startposition()
{
/* debugging code:
static int i = 0;
if (i == 0)
{
i = 1;
return(0);
}
else
return((int) SIZE / 2)
*/
return(rand()%SIZE);
}
load(f, no)
FILE *f; /* file */
int no; /* player number */
{
memory ele[MAXINST];
int i; /* number of instructions */
int test; /* test instructions read */
int start; /* starting instruction */
int position; /* loading position */
int counter; /* general-purpose counter */
test = fread(&i, sizeof(int), 1, f);
IO(test, 1)
printf("Found %d/%d instructions\n", i, MAXINST);
if (i > MAXINST) {
printf("load: Oops! Too large!!\n");
return(1); /* oops - too large */
}
test = fread(&start, sizeof(int), 1, f);
IO(test, 1)
test = fread(ele, sizeof(memory), i, f);
IO(test, i)
/* get a new starting position */
do {
position = startposition();
printf("Trying position %d\n", position);
} while (testpos(position,i));
/* and load the code there */
printf("Loading %d instructions at location %d\n", i, position);
for (counter = 0; counter < i; counter++) {
memcpy(&a[(counter+position)%SIZE],&ele[counter],sizeof(memory));
#ifdef DEBUG
if (!(((counter+position)%SIZE)%10)) {
printf("%d%",(counter+position)%SIZE);
} else {
putchar('.');
}
#endif
a[(counter+position)%SIZE].lastmod = no;
printf("Contents of location %d: %d %d %d %d %d %d\n",
(counter+position)%SIZE,
a[(counter+position)%SIZE].inst,
a[(counter+position)%SIZE].para1,
a[(counter+position)%SIZE].para2,
a[(counter+position)%SIZE].m1,
a[(counter+position)%SIZE].m2,
a[(counter+position)%SIZE].lastmod);
}
if ((exe[no] = (stream *) malloc(sizeof(stream))) == NULL) {
printf("load: Can't malloc the PC - aborting\n");
exit(1);
} else {
exe[no]->pc = (position + start) % SIZE;
exe[no]->next = exe[no]->prev = exe[no];
#ifdef DEBUG
printf("Starting PC: %d %d %d\n", exe[no]->pc, exe[no]->next->pc, exe[no]->prev->pc);
#endif
}
return(0); /* all OK */
}
/* tests for empty segment of *no* bytes starting at *start* */
testpos(start,no)
int start,no;
{
int counter; /* general-purpose counter */
for (counter = 0; counter < no; counter++) {
#ifdef DEBUG
if (!(((counter+start)%SIZE)%10)) {
printf("%d%",(counter+start)%SIZE);
} else {
putchar('.');
}
#endif
if (a[(counter+start)%SIZE].lastmod) {
printf("testpos: Oops -- something at %d\n",(counter+start)%SIZE);
return(1); /* oops - clash */
}
}
return(0); /* all clear - segment is free */
}
!E!O!F!
echo x - lookup.c
cat >lookup.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* lookup ---- this is the real core of the assembler. It will
perform functions such as matching symbols to instructions,
matching symbolic references to absolute code (and performing
whatever calculations necessary). */
#include "assem.h"
#include <malloc.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
/* declare external functions */
int symbol();
int instruction();
instr getin();
int para();
int getpara();
mode getmode();
/* algorithm :-
1) start from beginning of the list.
2) process element.
3) go on to next element.
4) return number of instructions
*/
int lookup(head, table, elements)
tokenlist *head;
tag1 table[];
memory elements[];
{
int i = 0, /* instruction pointer */
j = 0, /* number of parameters */
k = 0; /* current parameters */
initialize(elements); /* initialize table */
while (head && symbol(head)) /* look for first instruction */
head = head -> next;
while (head)
{
/* expect instruction */
if (!instruction(head))
{
printf("%s is not instruction\n", head -> token);
printf(" --- lookup\n");
exit(1);
}
elements[i].inst = getin(head);
/* expect number of parameters */
j = para(head);
k = 0;
while (k < j)
{
head = head -> next;
if (k == 0 && j == 2) /* if single para, put in B */
{
elements[i].para1 = getpara(head,table,i);
elements[i].m1 = getmode(head);
}
else
{
elements[i].para2 = getpara(head,table,i);
elements[i].m2 = getmode(head);
}
k++;
}
if (head)
head = head -> next; /* next instruction, if any */
while (head && symbol(head)) /* skim symbols */
head = head -> next;
i++;
} /* while */
return i;
}
/* set all instructions to init */
initialize(elements)
memory elements[];
{
memory ele; /* set all to this initialized variable */
int i;
ele.inst = dat;
ele.para1 = ele.para2 = 0;
ele.m1 = ele.m2 = immed;
for (i = 0; i < MAXINST; i++)
elements[i] = ele;
}
/* get the instr part of an instruction */
instr getin(ptr)
tokenlist *ptr;
{
char *t; /* string */
instr x; /* return value */
t = ptr -> token;
if (!strcmp(t, DAT))
x = dat;
else if (!strcmp(t, MOV))
x = mov;
else if (!strcmp(t, ADD))
x = add;
else if (!strcmp(t, SUB))
x = sub;
else if (!strcmp(t, JMP))
x = jmp;
else if (!strcmp(t, JMZ))
x = jmz;
else if (!strcmp(t, JMN))
x = jmn;
else if (!strcmp(t, DJN))
x = djn;
else if (!strcmp(t, CMP))
x = cmp;
else if (!strcmp(t, SPL))
x = spl;
else
{
printf("%s is not an instruction\n", t);
printf("--- getin\n");
exit(1);
}
return x;
} /* getin */
/* get the actual parameter (not the symbolic one)
Algorithm:
1) check if symbol
2) if symbol then look up, compare with current instruction,
and calculate what the actual parameter should be.
3) if not symbol, then check that it is a numeric. if not, error.
4) otherwise, return atoi
*/
int getpara(ptr, table, curr)
tokenlist *ptr; /* parameter instruction */
tag1 table[]; /* symbol table */
int curr; /* current instruction */
{
char *t; /* token string */
t = ptr -> token;
if (*t == '@' || *t == '#') /* ignore these */
t++;
if (number(t))
return(atoi(t));
else /* must be symbol */
return(getsym(t, table) - curr);
}
/* return the absolute location (from the beginning of the program) of
a symbol */
int getsym(str, table)
char *str;
tag1 table[];
{
int i = 0;
char s[MAXBUFFER];
/* add colon for strcmp */
strcpy(s,str);
strcat(s,":");
for (; (i < SYMBOLS) && (table[i].symbol != NULL); i++)
if (!strcmp(table[i].symbol, s))
return(table[i].position);
/* out here, not symbol */
printf("symbol %s undefined\n", str);
printf("--- getsym\n");
exit(1);
}
/* checks that every element in string is a digit */
int number(str)
char *str;
{
int i = 1;
if (*str == '+' || *str == '-') /* positive or negative */
str++;
while (*str && i)
{
if (!isdigit(*str))
i = 0;
str++;
}
return i;
}
mode getmode(ptr)
tokenlist *ptr;
{
char *t; /* token string */
t = ptr -> token;
if (*t == '@')
return(indirect);
else if (*t == '#')
return(immed);
else
return(direct);
}
/* special debugging portion */
/* declared debugged (phew! this one was tough) on 11/23/88 by CP */
/*
tokenlist *tokenize();
tag1 table[SYMBOLS];
memory elements[MAXINST];
extern tokenlist *tokenize();
main(argc, argv)
int argc;
char *argv[];
{
tokenlist *head;
FILE *f;
int i;
printf("loaded\n");
f = fopen(argv[1],"r");
printf("%s file opened\n", argv[1]);
head = tokenize(f);
printf("tokenized\n");
parse(head, table);
printf("parsed\n");
i = lookup(head, table,elements);
printf("%d instructions\n", i);
printf("OPCODE\tFIRSTPARA\tSECONDPARA\n");
for (i = 0; i < 20; i++)
{
printf("%d\t",(int) elements[i].inst);
if (elements[i].m1 == indirect)
printf("@");
else if (elements[i].m1 == immed)
printf("#");
printf("%d\t\t", elements[i].para1);
if (elements[i].m2 == indirect)
printf("@");
else if (elements[i].m2 == immed)
printf("#");
printf("%d\n", elements[i].para2);
}
fclose(f);
}
printsymbols(head)
tokenlist *head;
{
while (head != NULL)
{
printf("%s\n", head -> token);
head = head -> next;
}
}
printable(t)
tag1 t[];
{
int i;
printf("%s\t%s\n","SYMBOL","POSITION");
for (i = 0; table[i].symbol != NULL; i++)
printf("%s\t%d\n", table[i].symbol,table[i].position);
}
*/
!E!O!F!
echo x - main.c
cat >main.c <<'!E!O!F!'
/* main program for MARS interpreter
As usual, this does not do anything important.
Just calls all the proper subroutines in the right order and
opens files.
-- 12/16/88 --- NCP */
#include "interp.h"
#include <ctype.h>
#include <stdio.h>
#include <memory.h>
#include <curses.h>
long atol();
/* memory array -- called "a" for easy typing */
cell a[SIZE];
/* next execution for each player */
stream *exe[MAXPLAY];
/* returns which player won */
int play();
usage()
{
printf("usage: interp cycles file1 file2\n");
printf("--- main\n");
}
/* checks that every element in string is a digit */
int number(str)
char *str;
{
int i = 1;
while (*str && i)
{
if (!isdigit(*str))
i = 0;
str++;
}
return i;
}
initialize()
{
int counter; /* general-purpose counter */
counter = (int) time(0);
#ifndef DEBUG
initscr(); /* for "curses" library */
scrollok(stdscr, 0);
nl();
clear();
refresh();
#endif
srand(counter);
for (counter = 0; counter++; counter < SIZE)
memset(a[counter],0,sizeof(cell));
}
main(argc, argv)
int argc;
char *argv[];
{
FILE *f;
int errcode, result;
initialize(); /* initialize all global variables */
if (argc != 4) /* too many or too few */
{
usage();
exit(1);
}
if (!(number(argv[1])))
{
usage();
exit(1);
}
if ((f = fopen(argv[2], "r")) == NULL)
{
printf("%s cannot be opened\n", argv[2]);
exit(1);
}
errcode = load(f, 1);
fclose(f);
if (errcode == 1) {
printf("main: Sorry, but %s is too large to load\n",argv[2]);
exit(1);
}
if ((f = fopen(argv[3], "r")) == NULL)
{
printf("%s cannot be opened\n", argv[3]);
exit(1);
}
errcode = load(f,2);
fclose(f);
if (errcode == 1) {
printf("main: Sorry, but %s is too large to load\n",argv[3]);
exit(1);
}
#ifndef DEBUG
clear();
#endif
result = play(atol(argv[1]));
#ifndef DEBUG
output(0);
move(21, 0);
if (!result)
printw("nobody won!");
else
printw("%s won!", argv[result + 1]);
move(22, 0);
printw("Hit any key to continue...");
refresh();
getch(errcode);
endwin();
#endif
}
!E!O!F!
echo x - output.c
cat >output.c <<'!E!O!F!'
/** Output function **/
#include <stdio.h>
#include <curses.h>
#include "interp.h"
extern cell a[];
#if DEBUG
output()
{
int i;
for (i = 0; i < SIZE; i ++)
{
if (a[i].lastmod == 0)
putchar('0');
else if (a[i].lastmod == 1)
putchar('1');
else if (a[i].lastmod == 2)
putchar('2');
else
{
printf("\nerror lastmod == %d", a[i].lastmod);
printf("i == %d", i);
exit(1);
}
}
putchar('\n');
}
#endif
#ifdef SMALL
/* assume large, 80 col screen */
output(cycles)
long cycles;
{
int map[SIZE / 5]; /* map to one fifth the size */
int i, j, k = 0;
move(0,0); /* start from the top */
domap(map);
for (i = 0; i < SIZE/5;)
{
move(k, 0);
for (j = 1; j < COLS; i++, j++)
{
if (SIZE / 5<= i)
break;
if (map[i] == 0)
addch('0');
else if (map[i] == 1)
addch('1');
else if (map[i] == 2)
addch('2');
}
k++;
}
move(23, 0);
printw("Cycles left: %10d", cycles);
refresh();
}
domap(arr)
int arr[];
{
int i, j, pid1, pid2, pid3;
for (j = 0; j < SIZE/5; j++)
{
pid1 = pid2 = pid3 = 0;
for (i = j * 5; i < (j+1) * 5; i++)
{
if (SIZE <= i)
break;
if (a[i].lastmod == 0)
pid1++;
else if (a[i].lastmod == 1)
pid2++;
else if (a[i].lastmod == 2)
pid3++;
else
{
printf("invalid modification detected\n");
printf("--- domap\n");
exit(1);
}
}
arr[j] = max(pid1, pid2, pid3);
}
}
max(i, j, k)
int i, j, k;
{
if (i > j && i > k)
return 0;
else if (j > i && j > k)
return 1;
else
return 2;
}
#endif
#ifdef BIG
output(cycles)
int cycles;
{
int i, j, k;
/* perform detailed mapping */
for (i = 0, k = 0; i < SIZE; k++)
{
move (k, 0);
for (j = 0; j < COLS; i++, j++)
{
if (i >= (SIZE - 1))
break;
/* else */
if (a[i].lastmod == 0)
addch('0');
if (a[i].lastmod == 1)
addch('1');
else
addch('2');
}
}
move (k + 2, 0);
printw("Cycles left: %10d\n", cycles);
refresh();
}
#endif
!E!O!F!
echo x - parse.c
cat >parse.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* parser portion of the assembler.
11/15/88 - NCP */
#include <strings.h>
#include <stdio.h>
#include "assem.h"
/* parser:
Algorithm:
1) initialize symbol table
2) Scan first element in token list
3) if symbol declaraion (e.g. "start:") then lookup and enter into
symbol table
4) if instruction, skip forward number of parameters
that instruction accepts
5) otherwise error (not instruction or symbol)
6) repeat 3-6 until no more tokens.
*/
parse(tokens,table)
tokenlist *tokens; /* list of tokens */
tag1 table[]; /* symbol table */
{
int i = 0; /* instructon counter */
init(table); /* initialize table */
while (tokens)
{
if (symbol(tokens))
{
insert(tokens,table,i);
tokens = tokens -> next;
}
else if (instruction(tokens))
{
int j = 0, k = para(tokens);
/* move up to next instruction:
i.e., move from instruction + number of parameters
if instruction is one parameter, move twice, etc */
while (j <= k)
{
tokens = tokens -> next;
j++;
}
i++; /* next instruction */
}
else /* not instruction or symbol */
{
printf("%s not symbol or instruction\n",
tokens -> token);
printf(" --- parse\n");
exit(1);
}
} /* while */
/* test for too many instructions */
if (i > MAXINST)
{
printf("too many instructions\n");
printf("---- parse\n");
exit(1);
}
} /* parse */
init(table) /* function to initialize symbol table (set to 0 */
tag1 table[];
{
int i;
for (i = 0; i < SYMBOLS; i++)
{
table[i].symbol = NULL;
table[i].position = 0;
}
}
int symbol(tok)
/* identifies a symbol:
A symbol is just a token that ends with a ':' */
tokenlist *tok;
{
char *t; /* token string */
t = tok -> token;
if ((t[strlen(t) - 1]) == ':') /* address last character */
return 1; /* is symbol declaration */
else
return 0;
}
/* inserts a token into a symbol table (without stripping the ':') -
Algorithm:
1) search until symbol table reads a NULL string or
the new symbol is equal to and old one.
2) if the new symbol is not a NULL, then error
otherwise, insert
3) if out of space, error
*/
int insert(tok, table, no)
tokenlist *tok; /* token */
tag1 table[]; /* symbol table */
int no; /* instruction number */
{
char *t; /* token string */
int i = 0; /* index on table */
t = tok -> token;
/* search for empty place in table */
for (; i < SYMBOLS && table[i].symbol != NULL &&
(strcmp(table[i].symbol,t) != 0); i++)
;
if (table[i].symbol != NULL)
{
printf("symbol %s already declared\n", t);
printf("--- insert\n");
exit(1);
}
table[i].symbol = t;
table[i].position = no;
}
/* tests whether instruction */
int instruction(tok)
tokenlist *tok;
{
char *t; /* token string */
t = tok -> token;
/* note that due to a quirk in strcmp (it returns a zero if the
strings are equal) this looks particularly convoluted, but
the logic is simple. */
return(! (strcmp (t,MOV) && strcmp (t,ADD) && strcmp (t,SUB) &&
strcmp (t,JMP) && strcmp (t,JMZ) && strcmp (t,JMN) &&
strcmp (t,DJN) && strcmp (t,CMP) && strcmp (t,SPL) &&
strcmp (t,DAT)));
}
/* return the number of parameters an instruction has */
int para(tok)
tokenlist *tok;
{
char *t; /* token string */
int i = 0; /* return value */
t = tok -> token;
/* use a multiple if-elseif statement */
if (!strcmp(t, MOV))
i = 2;
else if (!strcmp(t, ADD))
i = 2;
else if (!strcmp(t, SUB))
i = 2;
else if (!strcmp(t, JMP))
i = 1;
else if (!strcmp(t, JMZ))
i = 2;
else if (!strcmp(t, JMN))
i = 2;
else if (!strcmp(t, DJN))
i = 2;
else if (!strcmp(t, CMP))
i = 2;
else if (!strcmp(t, SPL))
i = 1;
else if (!strcmp(t, DAT))
i = 1;
else /* unrecognized instruction */
{
printf("%s is not an instruction\n", t);
printf("--- para\n");
exit(1);
}
return(i);
} /* para */
/* debugging section of parse.c */
/* code commented out --- given a clean bill of health by Dr. Na Choon Piaw
--- 11/15/88 */
/* declare tokenize */
/* extern tokenlist *tokenize(); */
/* declare symbol table */
/* tag1 table[SYMBOLS]; */
/* main(argc,argv)
int argc;
char *argv[];
{
tokenlist *head;
FILE *f;
int i;
f = fopen(argv[1], "r");
head = tokenize(f);
parse(head, table);
printf("%s\t%s\n", "SYMBOL", "POSITION");
for (i = 0; table[i].symbol != NULL; i++)
printf("%s\t%d\n", table[i].symbol, table[i].position);
} */
!E!O!F!
echo x - play.c
cat >play.c <<'!E!O!F!'
/* play.c ---- main program for the interpreter.
1. play player 1
2. play player 2
3. output
4. check deaths
5. repeat
--- 12/17/88 NCP */
#include <stdio.h>
#include "interp.h"
extern stream *exe[];
extern cell a[];
int dead(i)
int i;
{
if (exe[i])
return 0;
else
return 1;
}
int alive()
{
int i, j = 1;
for (i = 1; i < MAXPLAY; i ++)
{
if (!exe[i])
{
j = 0;
break;
}
}
return(j);
}
int play(cycles)
long cycles;
{
int i;
while (alive() && cycles)
{
for ( i = 1; i < MAXPLAY; i++)
{
execute(i); /* play player n */
#ifdef DEBUG
output();
#endif
#ifdef BIG
output(cycles);
#endif
}
#ifdef SMALL
if (!(cycles % 100))
output(cycles);
#endif
cycles --;
}
if (dead(1) && !dead(2))
return(2); /* process 2 won */
else if (dead(2) && !dead(1))
return(1); /* process 1 won */
else
return(0); /* nobody won */
}
execute(i)
int (i);
{
instr temp; /* instruction */
int x; /* cell to execute */
int pc;
if (exe[i] == NULL)
return;
correct(&(exe[i] -> pc));
x = pc = exe[i] -> pc;
temp = a[x].inst;
/* this really should have been a switch-case, but I'm using an
elongated if-else because the compiler doesn't accept it. */
if (temp == dat)
Dat(i);
else if (temp == mov)
Mov(x, &pc, i);
else if (temp == add)
Add(x, &pc, i);
else if (temp == sub)
Sub(x, &pc, i);
else if (temp == jmp)
Jmp(x, &pc);
else if (temp == jmz)
Jmz(x, &pc);
else if (temp == jmn)
Jmn(x, &pc);
else if (temp == djn)
Djn(x, &pc, i);
else if (temp == cmp)
Cmp(x, &pc);
else if (temp == spl)
Spl(x, &pc, exe[i]);
else
{
printf("Instruction not recognized\n");
printf("--- execute\n");
printf("opcode: %d", temp);
printf(" executing no: %d", pc);
printf(" process: %d\n", i);
exit(1);
}
if (temp != dat)
exe[i] -> pc = pc;
if (exe[i] && (temp != dat))
exe[i] = exe[i] -> next;
}
!E!O!F!
echo x - test.c
cat >test.c <<'!E!O!F!'
main()
{
int i, j;
for (i = 0; i <8000;)
{
for (j = 0; j < 10; j++, i++)
printf("%d", j);
}
}
!E!O!F!
echo x - tokenize.c
cat >tokenize.c <<'!E!O!F!'
/* Copyrighted (C) 1989 by Na Choon Piaw. All rights reserved */
/* This program and documentation is Public Domain, and may be */
/* distributed and copied by everyone provided this header */
/* remains intact */
/* tokenize ---- tokenizer for the assembler. It splits up all of the
tokens in the given input file, generate a linked list of such tokens,
and outputs the pointer to that linked list.
11/14 ----- NCP */
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <malloc.h>
#include "assem.h"
/* tokenize function:
separate input stream (infile) into tokens.
algorithm:
1) call nextoken to get next token.
2) if "null" then return the first pointer
3) otherwise, add the newtoken to the token list
4) go back to 1.
*/
tokenlist *tokenize(infile)
FILE *infile;
{
tokenlist *head, *tail, *newtail;
char *nextoken(), *newtoken;
head = tail = NULL;
while ((newtoken = nextoken(infile)) != NULL)
{
if (!(newtail = (tokenlist *)
malloc((unsigned) sizeof(tokenlist))))
{
printf("ran out of space for tokens: %s\n", newtoken);
printf("------ tokenize\n");
exit(1);
}
/* otherwise , set old stuff to this and move tail one up*/
newtail -> token = newtoken;
newtail -> next = NULL;
if (tail) /* tail already defined */
{
tail -> next = newtail; /* set previous ptr */
tail = tail -> next; /* move up list */
}
else
head = tail = newtail;
} /* end while */
return (head); /* return function value */
}
/* function next token:
return next token in the file.
Algorithm:
1) read until start of next token or EOF
2) if EOF then return NULL pointer
3) read new token into buffer
4) malloc new string
5) put next token into new string
6) change all characters into upper case
7) return pointer to string created in (4) */
/* BUG NOTE:
Due to the way it is written, the assembler will not process things like
"mov0 1" correctly, and neither will "mov 0 1;imp" work.
this is because the tokenize breaks everything down that isn't a
delimiter, and a ";" is not a delimiter, even though it's not in
the instruction set. NCP - 11/15/88 */
char *nextoken(infile)
FILE *infile;
{
char buffer[MAXBUFFER], /* string buffer */
*newtoken; /* new token pointer */
int c, /* character we read in one by one */
i = 0; /* integer counter */
while ((c = fgetc(infile)) != EOF)
{
if (!isspace(c))
break; /* not space, so process */
}
if (c == EOF)
return(NULL); /* no more!! */
if (c == COMMENT) /* handle comments */
{
while (((c = fgetc(infile)) != '\n') && c != EOF)
; /* read until end of the line */
if (c == EOF)
return(NULL);
/* process the rest of the file:
actually, we could have done this by using a goto
the beginning of this function, but I think this
is a lot more elegant --- CP */
return(nextoken(infile));
}
while ((!isspace(c)) && (c != EOF)) /* read until next space */
{
if (i >= MAXBUFFER) /* buffer out */
{
printf("buffer over extended\n");
printf("--- nextoken\n");
exit(1);
}
buffer[i++] = c;
c = fgetc(infile);
} /* end while */
buffer[i] = '\0'; /* terminate with a null */
if (!(newtoken = (char *) malloc( (unsigned) strlen(buffer) + 1)))
{
printf("not enough memory for token %s\n", buffer);
printf(" ------- nextoken\n");
exit(1);
}
strcpy(newtoken, buffer);
upcase(newtoken);
return(newtoken);
} /* end of nextoken */
/* upcase function -- translate string to upper case (don't trust toupper) */
upcase(str)
char *str;
{
while (*str)
{
if ((*str <= 'z') && (*str >= 'a'))
*str -= 'a' - 'A';
str++;
}
}
/* special main to test the above */
/* section commented out because code has been fully debugged
and given a clean bill of health CP - 11/14/88
main(argc,argv)
int argc;
char *argv[];
{
FILE *f;
tokenlist *head;
f = fopen(argv[1],"r");
head = tokenize(f);
while (head != NULL)
{
printf("%s\n", head -> token);
head = head -> next;
}
} */
!E!O!F!
echo x - bomb.rc
cat >bomb.rc <<'!E!O!F!'
start:
mov #0 @ptr
add #1 ptr
jmp start
ptr: dat #1
!E!O!F!
echo x - chang1.rc
cat >chang1.rc <<'!E!O!F!'
; chang 1 corewars program
mov #0 -1
jmp -1 ;;nothing
dat +9 ;complete tester
start: spl -2
spl 4
add #-16 -3 ; nothing
mov #5 @-4
help: jmp -4
spl 2
jmp -1
finish: next: odd: mov 0 1
finito:
!E!O!F!
echo x - commando.rc
cat >commando.rc <<'!E!O!F!'
;;; an implementation of a k dewdney's commando program
count: dat #14
ptr: dat #200
imps: mov #0 -1 ; imp stomper
jmp imps
mov #14 count
mov #100 ptr
start: mov imp 1000
spl 999
loop: mov @count @ptr
sub #1 ptr
djn loop count
add #4 ptr
spl @ptr
jmp imps
imp: mov 0 1
!E!O!F!
echo x - dwarf.rc
cat >dwarf.rc <<'!E!O!F!'
dat -1
start: add #5 -1
mov #0 @-2
JMP -2
!E!O!F!
echo x - dwarfgun.rc
cat >dwarfgun.rc <<'!E!O!F!'
;;; dwarfgun program.
;;; Choon Piaw
stomp: mov #0 -1
jmp stomp
start: spl init
jmp stomp
count: dat #4
ptr: dat #500
;;;; dwarf part
dwf: dat #5000
loop: mov #0 @dwf
djn loop dwf
;;; initialization
init: mov #-200 ptr2
mov #0 count2
mov #500 ptr
mov #4 count
;;; dwarf copy part
dwfcp: mov @count @ptr
sub #1 ptr
djn dwfcp count
add #3 ptr
spl @ptr ; leave dwarf running.
;;;; copy self upstream
selfcp: mov @count2 @ptr2
sub #1 count2
sub #1 ptr2
cmp count2 #-27
jmp selfcp
add #3 ptr2
jmp @ptr2
ptr2: dat #-200
count2: dat #0
!E!O!F!
echo x - gemini.rc
cat >gemini.rc <<'!E!O!F!'
dat #0
dat #99
start: mov @-2 @-1
cmp -3 #9
jmp 4
add #1 -5
add #1 -5
jmp -5
mov #99 93
jmp 93
!E!O!F!
echo x - imp.rc
cat >imp.rc <<'!E!O!F!'
start: mov 0 1
!E!O!F!
echo x - impstomp.rc
cat >impstomp.rc <<'!E!O!F!'
start: mov #0 -1
jmp start
!E!O!F!
echo x - mice.rc
cat >mice.rc <<'!E!O!F!'
; mouse program --- The First Core War tournament
ptr: dat #0 ;hell
start: mov #9 ptr ;you
loop: mov @ptr @7 ;know
sub #1 6
djn loop ptr ;i hate testing
add #1 4
spl @3 ;assemblers
add #653 2 ;like
jmz -7 -8 ;this
dat 833
!E!O!F!
echo x - selfcpy.rc
cat >selfcpy.rc <<'!E!O!F!'
imps: mov #0 -1
jmp imps
start: spl imps
jmp loop
count: dat #7
ptr: dat #57
mov #7 count
mov #57 ptr
loop: mov @count @ptr
sub #1 ptr
djn loop count
jmp 46
!E!O!F!
echo x - sit.rc
cat >sit.rc <<'!E!O!F!'
start: jmp start
!E!O!F!
echo x - testspl.rc
cat >testspl.rc <<'!E!O!F!'
start: spl after
mov #0 -3
jmp -1
after: mov 0 1
!E!O!F!
An Existentialist
c60a-3ci at wolf.berkeley.edu
%flames >/dev/null
"Do you think that if I stopped thinking so much I'd have less trouble?"
More information about the Alt.sources
mailing list