mixal-1.08.orig/ 42775 1750 1750 0 6655574132 11254 5ustar ajkajkmixal-1.08.orig/Makefile100664 1750 1750 3430 6653203624 13000 0ustar ajkajk# UNIX makefile for the MIX interpreter # Must be changed in the spec file as well. V=1.08 CFLAGS = -g CSRCS = asm.c cell.c charset.c driver.c io.c main.c parse.c run.c symbol.c HSRCS = asm.h cell.h charset.h driver.h io.h mix.h parse.h run.h symbol.h SOURCES = Makefile opcodes op2c.awk $(CSRCS) $(HSRCS) DOCS = READ.ME NOTES TEST = elevator.mix prime.mix mystery.mix prime.out mystery.out mixtest ops.inc MISC = mixal.spec DOSFILES = makefile.dos test.bat DISTRIBUTION = $(SOURCES) $(DOCS) $(TEST) $(MISC) $(DOSFILES) OBJS = asm.o cell.o charset.o driver.o io.o main.o parse.o run.o symbol.o mixal: $(OBJS) $(CC) $(OBJS) -o mixal clean: rm -f *.o mixal ops.inc mnemonic mixal.shar core.mix *.tar.gz *.rpm *~ dist: mixal-$(V).tar.gz mixal-$(V).tar.gz: $(DISTRIBUTION) @ls $(DISTRIBUTION) | sed "s:^:mixal-$(V)/:" >MANIFEST @(cd ..; ln -s mixal mixal-$(V)) (cd ..; tar -czvf mixal/mixal-$(V).tar.gz `cat mixal/MANIFEST`) @(cd ..; rm mixal-$(V)) RPMROOT=/usr/src/redhat RPM = rpm RPMFLAGS = -ba rpm: dist cp mixal-$(V).tar.gz $(RPMROOT)/SOURCES; cp mixal.spec $(RPMROOT)/SPECS cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) mixal.spec cp $(RPMROOT)/RPMS/`arch|sed 's/i[4-9]86/i386/'`/mixal-$(V)*.rpm . cp $(RPMROOT)/SRPMS/mixal-$(V)*.src.rpm . shar: shar $(DISTRIBUTION) >mixal.shar ops.inc: opcodes sort ops.inc asm.o: asm.c mix.h cell.h asm.h run.h cell.o: cell.c mix.h cell.h symbol.o: symbol.c mix.h cell.h asm.h symbol.h charset.o: charset.c mix.h cell.h charset.h driver.o: driver.c mix.h cell.h asm.h driver.h parse.h symbol.h ops.inc main.o: main.c mix.h cell.h asm.h driver.h parse.h run.h symbol.h parse.o: parse.c mix.h cell.h asm.h charset.h parse.h symbol.h run.o: run.c mix.h cell.h asm.h charset.h io.h run.h io.o: io.c mix.h cell.h charset.h io.h run.h mixal-1.08.orig/NOTES100664 1750 1750 10074 6636310726 12200 0ustar ajkajk Notes on MIXAL, the MIX assembly language It should be pretty obvious if you've coded in assembler before and if you've read the instruction-set description. A few things that may not be obvious: Spaces aren't allowed in the operand field. (That's why you can put comments after the operand field, without any special comment character.) Forward references are not allowed in expressions. An expression is evaluated strictly left-to-right, with no operator precedence. In line 12 of prime.mix: ld1 =1-L= the =1-L= denotes a memory location automatically placed by the assembler after your code, containing the value 1-L. Syntactically, =1-L= is like a forward reference. (Note that ent1 1-L is equivalent but more efficient.) The character * in the operand field denotes the current address of assembly. Thus, jmp * is a one-instruction infinite loop. The funny two-letter labels starting with a digit are local labels: In an instruction like jmp 2F the 2F refers to the next occurrence of 2H as a label; in jmp 2B the 2B refers to the last occurrence of 2H as a label. There's more, but that should be enough to get by with until you procure a copy of Knuth. I'm awfully sick of typing. Sorry. Larry Gately's notes begin here: The version of cell.c in MIXAL 1.06 had problems with both the multiply and divide functions. ---------------------- Divide function The divide function has the simpler error. The lines r <<= 1; if (q & (1L << 30)) ++r; q = (q << 1) & ((1L << 30) - 1); view r and q as a sixty bit register (r is the upper thirty, a is the lower thirty). They do a shift left one bit on the register. The line if (q & (1L << 30)) should test the upper bit of q (to shift it into r), but it is actually testing the sign bit of q. The line should read if (q & (1L << 29)) As a test, the following MIX program calculates (2 ^ 30 + 5) / 10. (1073741829). A CON 1 B CON 5 C CON 10 START LDA A LDX B DIV C HLT END START The new version of MIXAL gets the correct answer of 107374182r9. The old version of MIXAL gets a wrong answer of 107374182r4. An example of a division where both the product and the remainder are wrong is (2 ^ 30 + 2 ^ 29) / 3. See the folowing program. A CON 1 B CON 536870912 2 ^ 29 C CON 3 START LDA A LDX B DIV C HLT END START The new version of MIXAL gets the correct answer of 536870912r0. The old version of MIXAL gets a wrong answer of 357913941r1. ---------------------- Multiply function The multiply function breaks both factors into 2 pieces, one of which is 16 bits and the other 14 bits. It then does multiplies the parts. To calculate the lower 30 bits of the product, it uses this line: unsigned long low_sum = x0 * y0 + (low16(partials) << 16); There are two things wrong with this. Firstly, the addition can overflow. For example, this happens when both factors are (2 ^ 17 - 1). Secondly, even when it doesn't overflow, there can be significant bits in two upper bits of low_sum, which need to be carried over into high_sum. For example, this happens when both factors are (2 ^ 30 - 1 ). The following line accounts one, but not both. unsigned long high_sum = x1 * y1 + (partials >> 16) + (low_magnitude != low_sum); I have replaced the multiply algorithm with one that breaks both factors into three pieces, each 10 bits. This requires calculating more terms, of course. There is a commentary in the code, showing why the new version should not overflow. The program below calculates (2 ^ 30 - 1) ^ 2. A CON 1073741823 2 ^ 30 - 1 START LDA A MUL A HLT END START The new version of MIXAL gets the correct answer of 17777777760000000001 (Base 8). The old version of MIXAL gets a wrong answer of 17777777770000000001 (Base 8). The program below calculates (2 ^ 17 - 1) ^ 2. A CON 131071 2 ^ 17 - 1 START LDA A MUL A HLT END START The new version of MIXAL gets the correct answer of 177777000001 (Base 8). The old version of MIXAL gets a wrong answer of 37777000001 (Base 8). mixal-1.08.orig/READ.ME100664 1750 1750 7312 6652051562 12302 0ustar ajkajk READ.ME FILE FOR THE MIXAL DISTRIBUTION This is an assembler and interpreter for Donald Knuth's mythical MIX computer, defined in: Donald Knuth, _The Art of Computer Programming, Vol. 1: Fundamental Algorithms_. Addison-Wesley, 1973 (2nd ed.) This implementation was designed and written by Darius Bacon , then ported to UNIX and debugged by Eric S. Raymond . Corrections to multiplication and division by Larry Gately ; see Notes. Copyright (c) 1994 by Darius Bacon. Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. HOW TO USE IT The program is a load-and-go assembler. To run the prime-numbers example, for instance, type mix prime.mix and it will assemble and run the program. There are no special debugging facilities yet, not even a core dump. It does print out the processor registers upon termination. DIFFERENCES FROM `STANDARD' MIXAL There is one significant difference in the assembler format: Knuth puts fields at fixed offsets on a line, while I separate them by whitespace. (Purists may wish to fix this obvious bug.) Since the ALF directive, which defines constant strings, becomes ambiguous when delimited by whitespace, there's a new syntax to achieve the same effect: instead of ALF rime use CON " rime" IMPLEMENTATION NOTES The tape devices are currently unimplemented. (Use the 'card punch' and 'printer' devices if you don't need mass storage. They're automatically connected to standard input and output. (They could easily be connected to named files, too, but I haven't put that in yet.)) Floating-point instructions aren't implemented either. They weren't covered in Volume I, which is all I've got so far. This MIX is a binary machine. I think that was a mistake -- decimal would make debugging enough nicer to compensate for the decreased efficiency. When dumping internal values, it prints them in octal, so you can get the field values by inspection. Things to do are marked by a comment starting with **. The program still needs more testing. PORTING AND TESTING The code is written in pure ANSI C. It is known to work in the following environments: OS Compiler ----------- ------------ BSD/386 gcc AIX-3.2.5 gcc DOS Watcom C DOS Borland C You can regression-test the interpreter with mixtest (under UNIX) or test.bat (under DOS). FILES asm.[ch] A Silly Module cell.[ch] Operations on MIX words (Cells) charset.[ch] The character set driver.[ch] Assemble a single source line elevator.mix Sample code from Knuth vol. 1 io.[ch] Simulate MIX I/O devices main.c Main program Makefile Makefile for Unix makefile.dos Makefile for Borland C++ under MS-DOS manifest Guess! mix.h Header for things needed all over the program mixtest Regression-testing shell script mystery.mix Sample program mystery.out Its output NOTES Notes on the MIX assembly language op2c.awk Converts the table of instructions into a C array opcodes The table of instructions ops.inc The same, as a C array, for the awkless parse.[ch] Parse an operand field prime.mix Sample program, with notes on MIX assembly language prime.out Its output READ.ME General info run.[ch] Simulate the MIX machine symbol.[ch] The symbol table test.bat Regression-testing DOS batch file mixal-1.08.orig/asm.c100664 1750 1750 2120 6652053643 12262 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" #include "run.h" /* for memory[] */ /* --- The assembly buffer --- */ Address here = 0; Cell asm_fetch_field(Address address, unsigned L, unsigned R) { assert(address < memory_size); return field(make_field_spec(L, R), memory[address]); } #include void asm_store_field(Address address, unsigned L, unsigned R, Cell cell) { assert(address < memory_size); if (VERBOSE) { char temp[12]; unparse_cell(temp, cell); printf("%4o(%u,%u): %s\n", address, L, R, temp); } memory[address] = set_field(cell, make_field_spec(L, R), memory[address]); } void assemble(Cell cell) { if (VERBOSE) { char temp[12]; unparse_cell(temp, cell); printf("%4o: %s\n", here, temp); } if (here < memory_size) memory[here] = cell; else error("Address out of range"); ++here; } Address entry_point; void set_entry_point(Address address) { assert(address < memory_size); if (VERBOSE) printf("entry point: %4o\n", address); entry_point = address; } mixal-1.08.orig/asm.h100664 1750 1750 616 6636306357 12264 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef ASM_H #define ASM_H #include "cell.h" /* --- The assembly buffer --- */ extern Address here; Cell asm_fetch_field(Address address, unsigned L, unsigned R); void asm_store_field(Address address, unsigned L, unsigned R, Cell cell); extern Address entry_point; void set_entry_point(Address address); void assemble(Cell cell); #endif mixal-1.08.orig/cell.c100664 1750 1750 16340 6652063032 12443 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ /* Corrections to multiply and divide, Nov. 1998, Larry Gately */ #include "mix.h" #include Cell ulong_to_cell(unsigned long n) { if (CELL_MAX < n) { warn("Value out of range: %lu", n); return CELL_MAX; } else return n; } /* --- Field operations --- */ Byte get_byte(unsigned F, Cell cell) { assert(F != 0); return (Byte) field(make_field_spec(F, F), cell); } Cell set_byte(Byte value, unsigned F, Cell into) { assert(F != 0); return set_field((Cell) value, make_field_spec(F, F), into); } static Flag bad_field[64]; /* 64 = number of byte values */ static unsigned shift[64]; static long mask[64]; Cell field(Byte F, Cell cell) { if (bad_field[F]) error("Bad field spec: %02o", F); if (F < 8) /* if F is of the form (0:R), retain the sign of -cell- */ return ((cell & mask[F]) >> shift[F]) | sign_bit(cell); else return (cell & mask[F]) >> shift[F]; } Cell set_field(Cell value, Byte F, Cell into) { long m = mask[F]; if (bad_field[F]) error("Bad field spec: %02o", F); if (F < 8) /* if F is of the form (0:R), use the sign of -value- */ return (into & ~m & ~the_sign_bit) | ((value << shift[F]) & m) | sign_bit(value); else return (into & ~m) | ((value << shift[F]) & m); } void precompute_field_data(void) { unsigned L, R; for (L = 0; L < 8; ++L) for (R = 0; R < 8; ++R) { unsigned F = 8 * L + R; bad_field[F] = R < L || 5 < R; if (bad_field[F]) shift[F] = 0, mask[F] = 0; else { unsigned width = R - (L == 0 ? 1 : L) + 1; shift[F] = 6 * (5 - R); mask[F] = ((1L << (6 * width)) - 1) << shift[F]; } } } Byte make_field_spec(unsigned L, unsigned R) { unsigned F = 8 * L + R; assert(!bad_field[F]); return F; } void assert_valid_field(Cell field_spec) { if (is_negative(field_spec) || 64 <= magnitude(field_spec) || bad_field[(unsigned)magnitude(field_spec)]) { char buffer[12]; unparse_cell(buffer, field_spec); error("Invalid field specifier: %s", buffer); } } /* --- Arithmetic --- */ Flag overflow = false; Cell add(Cell x, Cell y) { /* This is kinda clumsy. Should I combine code at the cost (?) of speed */ /* and functional style? */ if (sign_bit(x) == sign_bit(y)) { long sum = magnitude(x) + magnitude(y); long magnitude_of_sum = magnitude(sum); if (magnitude_of_sum != sum) overflow = true; return sign_bit(x) | magnitude_of_sum; } else { long diff = magnitude(x) - magnitude(y); return diff < 0 ? sign_bit (y) | -diff : sign_bit (x) | diff; } } Cell sub(Cell x, Cell y) { return add(x, negative(y)); /* should inline this, maybe */ } void multiply(Cell x, Cell y, Cell *high_word, Cell *low_word) { unsigned long sign = sign_bit(x) ^ sign_bit(y); /* x = x0 + x1 * 2 ^ 10 + x2 * 2 ^ 20 y = y0 + y1 * 2 ^ 10 + y2 * 2 ^ 20 x0, x1, x2, y0, y1, y2 are < 2 ^ 10 */ unsigned long x0 = (x & 0x000003FF); unsigned long x1 = (x & 0x000FFC00) >> 10; unsigned long x2 = (x & 0x3FF00000) >> 20; unsigned long y0 = (y & 0x000003FF); unsigned long y1 = (y & 0x000FFC00) >> 10; unsigned long y2 = (y & 0x3FF00000) >> 20; /* x * y = partial0 + partial1 * 2 ^ 10 + partial2 * 2 ^ 20 + partial3 * 2 ^ 30 + partial4 * 2 ^ 40 partial0 and partial4 are < 2 ^ 20 partial1 and partial3 are < 2 ^ 21 partial2 is < 3 * 2 ^ 20 */ unsigned long partial0 = x0 * y0; unsigned long partial1 = x0 * y1 + x1 * y0; unsigned long partial2 = x0 * y2 + x1 * y1 + x2 * y0; unsigned long partial3 = x1 * y2 + x2 * y1; unsigned long partial4 = x2 * y2; /* sum1 has a place value of 1 and is < 2 ^ 32 */ unsigned long sum1 = partial0 + (partial1 << 10); unsigned long carry1 = (sum1 & 0xFFF00000) >> 20; /* sum2 has a place value of 2 ^ 20 and is < 2 ^ 32 */ unsigned long sum2 = partial2 + (partial3 << 10) + carry1; unsigned long carry2 = (sum2 & 0xFFF00000) >> 20; /* sum3 has a place value of 2 ^ 40 and is < 2 ^ 20 */ unsigned long sum3 = partial4 + carry2; sum1 &= ~0xFFF00000; sum2 &= ~0xFFF00000; /* Now paste the three values back into two. */ *low_word = sum1 | ((sum2 & 0x000003FF) << 20); *low_word |= sign; *high_word = ((sum2 & 0x000FFC00) >> 10) | (sum3 << 10); *high_word |= sign; } Cell mul(Cell x, Cell y) { Cell lo, hi; multiply(x, y, &hi, &lo); if (magnitude(hi) != 0) overflow = true; return lo; } void divide(Cell n1, Cell n0, Cell d, Cell *quotient, Cell *remainder) { long magn1 = magnitude(n1); long magd = magnitude(d); if (magd == 0) { overflow = true; *quotient = *remainder = zero; /* just so they have -some- valid value */ } else if (magn1 == 0) { /* special-cased for speed */ *quotient = (sign_bit(n1) ^ sign_bit(d)) | (magnitude(n0) / magd); *remainder = sign_bit(n1) | (magnitude(n0) % magd); } else if (magd <= magn1) { overflow = true; *quotient = *remainder = zero; } else { long q = magnitude(n0); long r = magn1; unsigned i; for (i = 30; i != 0; --i) { r <<= 1; if (q & (1L << 29)) ++r; q = (q << 1) & ((1L << 30) - 1); if (magd <= r) ++q, r -= magd; } *quotient = (sign_bit(n1) ^ sign_bit(d)) | q; *remainder = sign_bit(n1) | r; } } Cell slash(Cell x, Cell y) /* the name 'div' is taken... */ { Cell quotient, remainder; divide(sign_bit(x), x, y, "ient, &remainder); return quotient; } /* --- Shift operations --- */ void shift_right(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX) { *pX = sign_bit(X); *pA = sign_bit(A); if (count < 5) { *pA |= magnitude(A) >> (6 * count); *pX |= CELL_MAX & (magnitude(X) >> (6 * count)) & (A << (30 - 6 * count)); } else if (count < 10) *pX |= magnitude(A) >> (6 * count - 30); else ; } void shift_left(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX) { *pX = sign_bit(X); *pA = sign_bit(A); if (count < 5) { *pX |= CELL_MAX & (X << (6 * count)); *pA |= CELL_MAX & (A << (6 * count)) & (magnitude(X) >> (30 - 6 * count)); } else if (count < 10) *pA |= CELL_MAX & (X << (6 * count - 30)); else ; } /* Pre: count < 10 */ void shift_left_circular(Cell A, Cell X, unsigned count, Cell *pA, Cell *pX) { Cell A1 = count < 5 ? A : X; Cell X1 = count < 5 ? X : A; unsigned c = 6 * (count < 5 ? count : count - 5); *pX = sign_bit(X) | (CELL_MAX & (X1 << c) & (magnitude(A1) >> (30 - c))); *pA = sign_bit(A) | (CELL_MAX & (A1 << c) & (magnitude(X1) >> (30 - c))); } /* --- Printable representation --- */ void print_cell(Cell cell) { printf("%s%010lo", sign_bit(cell) == 0 ? " " : "-", magnitude(cell)); } void unparse_cell(char *buffer, Cell cell) { sprintf(buffer, "%s%010lo", sign_bit(cell) == 0 ? " " : "-", magnitude(cell)); } /* --- Addresses --- */ Cell address_to_cell(Address addr) { return addr; } Address cell_to_address(Cell cell) { if ((sign_bit(cell) != 0 && magnitude(cell) != 0) || memory_size <= magnitude(cell)) { char buffer[12]; unparse_cell(buffer, cell); error("Value is not an address: %s", buffer); return 0; } return (Address) magnitude(cell); } mixal-1.08.orig/cell.h100664 1750 1750 6347 6652472343 12447 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #ifndef CELL_H #define CELL_H /* --- Call this before anything else --- */ void precompute_field_data(void); /* * MIX values --- * * Currently represented as a long. (A long must have >= 31 bits.) * Bit 30 is the sign, higher bits are 0, and bits 0-29 are the magnitude. * (If we made the high bit the sign, would it be a little faster to check?) * Each MIX 'byte' is a 6-bit substring of the magnitude. * * Other reps which might make sense: * array of bytes * pair (sign, magnitude) * 1's-complement??? * (a kind of halfway house between 2's-complement and sign/magnitude) * (alas, field operations would be more work...) * Unfortunately, in several places I've made the convenient assumption that * the magnitude of a MIX cell can be converted to a C long int; that would * be wrong for, e.g., a decimal MIX machine if a long int is only 32 bits. */ typedef long Cell; typedef unsigned Byte; /* 0..63 */ /* These are to allow symbol.c to convert a Cell to or from a unique string representation. We could just as easily use unparse() if we defined a complementary parse() function. */ #define cell_to_long(c) (c) #define long_to_cell(l) (l) /* Largest possible magnitude of a Cell */ #define CELL_MAX ((1L << 30) - 1) /* Largest possible magnitude of an index register (i.e., 2 bytes) */ #define INDEX_MAX ((1L << 12) - 1) #define zero ((Cell) 0) #define the_sign_bit (1L << 30) #define negative(cell) ( (cell) ^ the_sign_bit ) #define sign_bit(cell) ( (cell) & the_sign_bit ) #define magnitude(cell) ( (cell) & (the_sign_bit - 1) ) #define is_negative(cell) ( sign_bit(cell) != 0 ) Cell ulong_to_cell(unsigned long n); Byte make_field_spec(unsigned L, unsigned R); void assert_valid_field(Cell field_spec); /*** should separate into fast/safe versions */ Cell field(Byte field_spec, Cell cell); Cell set_field(Cell value, Byte field_spec, Cell into); Byte get_byte(unsigned field, Cell cell); Cell set_byte(Byte value, unsigned field, Cell into); extern Flag overflow; Cell add(Cell x, Cell y); Cell sub(Cell x, Cell y); void multiply(Cell x, Cell y, Cell *high_word, Cell *low_word); Cell mul(Cell x, Cell y); void divide(Cell n1, Cell n0, Cell d, Cell *quotient, Cell *remainder); Cell slash(Cell x, Cell y); /* the name 'div' is taken... */ void shift_left(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX); void shift_right(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX); void shift_left_circular(Cell A, Cell X, unsigned count, Cell *pA, Cell *pX); /* Break a cell into its component fields. */ #define destructure_cell(cell, A, I, F, C) \ do { \ Cell temp_ = (cell); \ Cell sign_ = sign_bit(temp_); \ C = temp_ & 63; \ F = (temp_ >>= 6) & 63; \ I = (temp_ >>= 6) & 63; \ A = sign_ | (4095 & (temp_ >> 6)); \ } while (0) /* --- Printable representation --- */ void print_cell(Cell cell); void unparse_cell(char *buffer, Cell cell); /* Pre: 12 <= sizeof(buffer) */ /* --- Addresses --- */ typedef unsigned Address; Cell address_to_cell(Address addr); Address cell_to_address(Cell cell); #endif mixal-1.08.orig/charset.c100664 1750 1750 1023 6652057007 13132 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "charset.h" #include #include #include static const char mix_chars[65] = " abcdefghi^jklmnopqr^^stuvwxyz0123456789.,()+-*/=$<>@;:'???????"; char mix_to_C_char(Byte mix_char) { assert((unsigned)mix_char < sizeof mix_chars); return mix_chars[(unsigned)mix_char]; } Byte C_char_to_mix(char c) { const char *s = strchr(mix_chars, tolower(c)); if (!s) return 63; return (Byte) (s - mix_chars); } mixal-1.08.orig/charset.h100664 1750 1750 241 6652055221 13114 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef CHARSET_H #define CHARSET_H char mix_to_C_char(Byte mix_char); Byte C_char_to_mix(char c); #endif mixal-1.08.orig/driver.c100664 1750 1750 11360 6652470646 13031 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" #include "driver.h" #include "parse.h" #include "symbol.h" #include #include #include #include /* --- Attributes of the current instruction or directive --- */ static char label[max_identifier_length+1]; static Byte the_C, default_F; static Flag F_must_be_default; /* --- Handlers for each type of directive --- */ /* Each must parse the operand field; see assemble_line(). */ static void do_opcode(void) { assemble(set_byte(the_C, 5, parse_operand(F_must_be_default, default_F))); } static void do_con(void) { assemble(parse_W()); } static void do_alf(void) { error("Use CON instead of ALF"); } static void do_end(void) { set_entry_point(cell_to_address(parse_W())); } static void do_equ(void) { define_symbol(string_to_symbol(label), parse_W()); if (VERBOSE) { print_cell(symbol_value(string_to_symbol(label))); printf("\n"); } } static void do_orig(void) { here = cell_to_address(parse_W()); } /* --- The opcode/directive table --- */ typedef const struct OpDef { const char *name; void (*handler)(void); Byte C, F; Flag is_extended; } OpDef; #define extended true #define def_opcode(name, C, F, is_ext) { name, do_opcode, C, F, is_ext } #define def_directive(name, handler) { name, handler, 0, 0, 0 } static OpDef op_table[] = { #include "ops.inc" }; /* --- The main driver --- */ static int delta_C; /* Compare strings a la strcmp, ignoring case, and allowing a `-' in pattern to stand for any general register. Pre: pattern is all lowercase and contains at most one `-'. Post: if they match, delta_C is set to the register number of the register. (delta_C unspecified if there was no `-'.) */ static int compare_mnemonics(const char *datum, const char *pattern) { unsigned my_delta_C = 0; for (; *pattern; ++pattern, ++datum) { char d = tolower(*datum); if (*pattern == '-') { static const char legals[] = "a123456x"; const char *temp = strchr(legals, d); if (temp) my_delta_C = temp - legals; else break; } else if (*pattern == d) ; else break; } { int result = tolower(*datum) - *pattern; if (result == 0) delta_C = my_delta_C; return result; } } typedef void (*Handler)(void); /* I'd prefer something faster than a linear search here. Maybe have op2c.awk expand out the `-' characters so we only need look for a string equal to mnemonic. */ static Handler lookup_mnemonic(const char *mnemonic) { unsigned i; delta_C = 0; for (i = 0; i < sizeof op_table / sizeof op_table[0]; ++i) { if (compare_mnemonics(mnemonic, op_table[i].name) == 0) { the_C = op_table[i].C + delta_C; default_F = op_table[i].F; F_must_be_default = op_table[i].is_extended; return op_table[i].handler; } } return NULL; } static const char *skip_blanks(const char *s) { return s + strspn(s, " \t"); } typedef const char *const_char_ptr; static void eat_identifier(char *buffer, const_char_ptr *s) { const char *scan = buffer; size_t size, truncated_size; for (scan = *s; !isspace (*scan) && *scan != '\0'; ++scan) ; size = scan - *s; { /* ensure it's a legal identifier */ Flag alpha = false, non_alphanum = false; for (scan = *s; scan < *s + size; ++scan) { if (isalpha(*scan)) alpha = true; else if (!isalnum (*scan)) non_alphanum = true; } if ((!alpha && size != 0) || non_alphanum) { error ("Ill-formed label or mnemonic: %*.*s", size, size, *s); buffer[0] = '\0'; *s += size; return; } } if (max_identifier_length < size) { warn ("Truncated long label or mnemonic: %*.*s", size, size, *s); truncated_size = max_identifier_length; } else truncated_size = size; memcpy(buffer, *s, truncated_size); buffer[truncated_size] = '\0'; *s += size; } void assemble_line(const char *line) { char mnemonic[max_identifier_length+1]; const char *scan = line; if (*skip_blanks(scan) == '*') /* the comment character */ return; eat_identifier(label, &scan); /* eat label if any */ scan = skip_blanks(scan); eat_identifier(mnemonic, &scan); /* eat mnemonic */ scan = skip_blanks(scan); setup_scanner(scan); /* prepare to parse operand field */ { Handler handler = lookup_mnemonic(mnemonic); if (handler != do_equ && label[0] != '\0') define_symbol(string_to_symbol(label), address_to_cell(here)); if (handler) { handler(); done_parsing(); /* this goes here since *all* handlers parse an operand field */ } else if (mnemonic[0] != '\0') error("Unknown instruction: %s", mnemonic); else ; } } mixal-1.08.orig/driver.h100664 1750 1750 206 6636306357 12772 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef DRIVER_H #define DRIVER_H void assemble_line(const char *line); #endif mixal-1.08.orig/io.c100664 1750 1750 20425 6652471423 12141 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "charset.h" #include "io.h" #include "run.h" #include #include /* --- Device tables --- */ /* Device types: */ enum DeviceType { tape, disk, card_in, card_out, printer, console }; /* The device table: */ static struct { const enum DeviceType type; FILE *file; long position; /* used by random-access devices */ /* const char *filename; */ } devices[] = { {tape}, {tape}, {tape}, {tape}, {tape}, {tape}, {tape}, {tape}, {disk}, {disk}, {disk}, {disk}, {disk}, {disk}, {disk}, {disk}, {card_in, stdin}, {card_out, stdout}, {printer, stdout}, {console} }; #define num_devices ( sizeof devices / sizeof devices[0] ) /* add an assign_file(device, filename) operation, too */ /* and unassign? */ typedef void IOHandler(unsigned, Cell, Address); typedef void IOCHandler(unsigned, Cell); static IOHandler tape_in, disk_in, text_in, console_in, no_in; static IOHandler tape_out, disk_out, text_out, console_out, no_out; static IOCHandler tape_ioc, disk_ioc, no_ioc, printer_ioc; /* The device-class table: */ /*** need to distinguish read/write permission... */ static const struct Device_attributes { const char *base_filename; unsigned block_size; IOHandler *in_handler; IOHandler *out_handler; IOCHandler *ioc_handler; } methods[] = { /* tape */ { "tape", 100, tape_in, tape_out, tape_ioc }, /* disk */ { "disk", 100, disk_in, disk_out, disk_ioc }, /* card_in */ { NULL, 16, text_in, no_out, no_ioc }, /* card_out */ { NULL, 16, no_in, text_out, no_ioc }, /* printer */ { NULL, 24, no_in, text_out, printer_ioc }, /* console */ { NULL, 14, console_in, console_out, no_ioc } }; static const struct Device_attributes *attributes (unsigned device) { return &methods[devices[device].type]; } static unsigned block_size(unsigned device) { return attributes(device)->block_size; } static FILE *assigned_file(unsigned device) { return devices[device].file; } static char *device_filename(Byte device) { static char filename[FILENAME_MAX]; sprintf(filename, "%s%02d", attributes(device)->base_filename, device); return filename; } static void ensure_open(Byte device) { if (num_devices <= device) error("Unknown device - %02o", device); if (!assigned_file(device)){ if (attributes(device)->base_filename) { const char *filename = device_filename(device); if (!(devices[device].file = fopen(filename, "r+b")) && !(devices[device].file = fopen(filename, "w+b"))) error("%s: %s", filename, strerror(errno)); devices[device].position = 0; } else error("No file assigned to device %02o", device); } } void io_control(Byte device, Cell argument) { ensure_open(device); attributes(device)->ioc_handler(device, argument); } void do_input(Byte device, Cell argument, Address buffer) { ensure_open(device); attributes(device)->in_handler(device, argument, buffer); } void do_output(Byte device, Cell argument, Address buffer) { ensure_open(device); attributes(device)->out_handler(device, argument, buffer); } /* --- Unsupported input or output --- */ static void no_ioc(unsigned device, Cell argument) { error("IOC undefined for device %02o", device); } static void no_in(unsigned device, Cell argument, Address buffer) { error("Input not allowed for device %02o", device); } static void no_out(unsigned device, Cell argument, Address buffer) { error("Output not allowed for device %02o", device); } /* --- Text devices --- */ /* Read a line from -file- into memory[buffer..buffer+size). (Big-endian byte order, padded with 0 bytes if the line is less than -size- cells long. The signs of the cells are set to '+'. If the line is longer than 5*size bytes, only the first 5*size bytes get read. */ static void read_line(FILE* file, Address buffer, unsigned size) { unsigned i, b; Flag past_end = false; for (i = 0; i < size; ++i) { Cell cell = zero; if (memory_size <= buffer + i) /*** I think we need memory_fetch() and memory_store() functions... */ error("Address out of range"); for (b = 1; b <= 5; ++b) { Byte mix_char; if (past_end) mix_char = (Byte) 0; else { int c = fgetc(file); if (c == '\n' || c == EOF) past_end = true, mix_char = (Byte) 0; else mix_char = C_char_to_mix((char) c); } cell = set_byte(mix_char, b, cell); } memory[buffer + i] = cell; } } static void write_cell(Cell cell, FILE *outfile, Flag text) { unsigned i; if (!text) fputc(is_negative(cell) ? '-' : ' ', outfile); for (i = 1; i <= 5; ++i) fputc(mix_to_C_char(get_byte(i, cell)), outfile); } static void write_line(FILE *file, Address buffer, unsigned size, Flag text) { unsigned i; for (i = 0; i < size; ++i) { if (memory_size <= buffer + i) error("Address out of range"); write_cell(memory[buffer + i], file, text); } fputc('\n', file); } static void printer_ioc(Byte device, Cell argument) { if (magnitude(argument) != 0) error("IOC argument undefined for printer device %02o", device); fputc('\f', assigned_file(device)); } static void text_in(Byte device, Cell argument, Address buffer) { read_line(assigned_file(device), buffer, block_size(device)); } static void text_out(Byte device, Cell argument, Address buffer) { write_line(assigned_file(device), buffer, block_size(device), true); } /* --- Block devices --- */ /*** Make this section more robust. */ /*** And either these errors should be fatal errors or we need to think about recovery. */ static void set_file_position(Byte device, unsigned block, Flag writing) { if (fseek(assigned_file(device), (long) block * (6 * block_size(device) + 1), SEEK_SET)) error("Device %02o: %s", device, strerror(errno)); } /* Read a block from -device- into memory[buffer..buffer+block_size(device)). (Big-endian byte order, with words represented by 6 native C characters: the sign ('-' or ' '), followed by 5 characters whose MIX equivalents code for the corresponding bytes.) The block should end with a '\n'. */ static void read_block(Byte device, Address buffer) { FILE *file = assigned_file(device); unsigned size = block_size(device); unsigned i, b; for (i = 0; i < size; ++i) { int c; Cell cell = zero; if (memory_size <= buffer + i) error("Address out of range -- read_block"); c = fgetc(file); if (c == EOF) error("Unexpected EOF reading from device %02o", device); else if (c == '-') cell = negative(cell); for (b = 1; b <= 5; ++b) { c = fgetc(file); if (c == EOF) error("Unexpected EOF reading from device %02o", device); cell = set_byte(C_char_to_mix((char) c), b, cell); } memory[buffer + i] = cell; } fgetc(file); /* should be '\n' */ } /* The inverse of read_block. */ static void write_block(Byte device, Address buffer) { write_line(assigned_file(device), buffer, block_size(device), false); } /* --- Tapes --- */ static void tape_ioc(unsigned device, Cell offset) { error("Unimplemented"); } static void tape_in(unsigned device, Cell argument, Address buffer) { error("Unimplemented"); } static void tape_out(unsigned device, Cell argument, Address buffer) { error("Unimplemented"); } /* --- Disks --- */ static void disk_ioc(Byte device, Cell offset) { if (magnitude(offset) != 0) error("IOC argument undefined for disk device %02o", device); } static void disk_in(Byte device, Cell argument, Address buffer) { unsigned block_num = (unsigned) field(make_field_spec(4, 5), argument); set_file_position(device, block_num, false); read_block(device, buffer); } static void disk_out(Byte device, Cell argument, Address buffer) { unsigned block_num = (unsigned) field(make_field_spec(4, 5), argument); set_file_position(device, block_num, true); write_block(device, buffer); } /* --- The console (typewriter/paper tape) --- */ /* Always connected to stdin/stdout, for simplicity. */ static void console_in(Byte device, Cell argument, Address buffer) { read_line(stdin, buffer, block_size(device)); } static void console_out(Byte device, Cell argument, Address buffer) { write_line(stdout, buffer, block_size(device), true); } mixal-1.08.orig/io.h100664 1750 1750 416 6636306357 12111 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef IO_H #define IO_H #include "mix.h" void io_control(Byte device, Cell argument); void do_input(Byte device, Cell argument, Address buffer); void do_output(Byte device, Cell argument, Address buffer); #endif mixal-1.08.orig/main.c100664 1750 1750 6710 6652403376 12441 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" #include "driver.h" #include "parse.h" #include "run.h" #include "symbol.h" #include #include #include #include #include #include #include static const char *current_file = NULL; static unsigned line_number; static unsigned num_errors = 0; void fatal_error(const char *message, ...) { va_list args; if (current_file) /*** of course, the error may not have anything to do with the file... */ fprintf(stderr, "FATAL ERROR (%s, line %u): ", current_file, line_number); else fprintf(stderr, "FATAL ERROR: "); va_start(args, message); vfprintf(stderr, message, args); va_end(args); fprintf(stderr, "\n"); exit(1); } static void (*error_handler)(const char *, va_list) = NULL; void install_error_handler(void (*handler)(const char *, va_list)) { error_handler = handler; } void error(const char *message, ...) { va_list args; ++num_errors; va_start(args, message); if (error_handler) error_handler(message, args); else fatal_error("No error handler installed"); va_end(args); } void warn(const char *message, ...) { va_list args; if (current_file) fprintf(stderr, "WARNING (%s, line %u): ", current_file, line_number); else fprintf(stderr, "WARNING: "); va_start(args, message); vfprintf(stderr, message, args); va_end(args); fprintf(stderr, "\n"); } /* --- Miscellany --- */ static FILE *open_file(const char *filename, const char *mode) { if (strcmp(filename, "-") == 0) { assert(mode[0] == 'r' || mode[0] == 'w'); return mode[0] == 'w' ? stdout : stdin; } else { FILE *result = fopen(filename, mode); if (!result) fatal_error("%s: %s", filename, strerror(errno)); return result; } } /* --- Main program --- */ static void assembler_error(const char *message, va_list args) { if (current_file) fprintf(stderr, "ERROR (%s, line %u): ", current_file, line_number); else fprintf(stderr, "ERROR: "); vfprintf(stderr, message, args); fprintf(stderr, "\n"); } static void assemble_file(const char *filename) { FILE *infile = open_file(filename, "r"); char line[257]; current_file = filename, line_number = 0; while (fgets(line, sizeof line, infile)) { ++line_number; assemble_line(line); if (line[strlen(line) - 1] != '\n') { if (!fgets(line, sizeof line, infile)) break; /* the file's last line had no '\n' */ else { error("Line length exceeds 256 characters"); /* Skip the rest of the line */ while (line[strlen(line) - 1] != '\n') if (!fgets(line, sizeof line, infile)) break; } } } if (ferror(infile)) error("%s: %s", filename, strerror(errno)); fclose(infile); current_file = NULL; } int main(int argc, char **argv) { precompute_field_data(); /* Assemble the input: */ install_error_handler(assembler_error); if (argc == 1) assemble_file("-"); else { int i; for (i = 1; i < argc; ++i) assemble_file(argv[i]); } resolve_generated_futures(); if (num_errors != 0) { fprintf(stderr, "%u errors found\n", num_errors); exit(1); } /* Now run it: */ set_initial_state(); { clock_t finish, start = clock(); run(); finish = clock(); fprintf(stderr, "%g seconds elapsed\n", (float)(finish - start) / CLOCKS_PER_SEC); } print_CPU_state(); return 0; } mixal-1.08.orig/makefile.dos100664 1750 1750 1340 6636306357 13632 0ustar ajkajk# Make file for Borland C++ .c.obj: bcc -c -v {$< } OBJS = asm.obj cell.obj charset.obj driver.obj io.obj main.obj parse.obj run.obj symbol.obj mix.exe: $(OBJS) bcc -v -emix $(OBJS) clean: del *.obj del *.exe mix.h: cell.h touch mix.h ops.inc: opcodes sort mnemonic mawk -f op2c.awk mnemonic >ops.inc asm.obj: asm.c mix.h asm.h run.h cell.obj: cell.c mix.h symbol.obj: symbol.c mix.h asm.h symbol.h charset.obj: charset.c mix.h charset.h driver.obj: driver.c mix.h asm.h driver.h parse.h symbol.h ops.inc main.obj: main.c mix.h asm.h driver.h parse.h run.h symbol.h parse.obj: parse.c mix.h asm.h charset.h parse.h symbol.h run.obj: run.c mix.h asm.h charset.h io.h run.h io.obj: io.c mix.h charset.h io.h run.h mixal-1.08.orig/mix.h100664 1750 1750 1170 6652054020 12276 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef MIX_H #define MIX_H #include #include /* Some standard stuff all or most modules have in common. */ typedef enum { false, true } Flag; /* Dump helpful debugging info if true: */ #define VERBOSE false #define not_reached false #define NOT_REACHED assert(not_reached) void install_error_handler(void (*handler)(const char *, va_list)); void warn(const char *message, ...); void error(const char *message, ...); void fatal_error(const char *message, ...); #define max_identifier_length 32 #define memory_size 4000 #include "cell.h" #endif mixal-1.08.orig/mixal.spec100664 1750 1750 1041 6653203633 13322 0ustar ajkajkName: mixal Version: 1.08 Release: 1 Source: locke.ccil.org:/pub/esr/mixal-1.07.tar.gz Copyright: distributable Group: Development/Languages Summary: load-and-go assembler for Donald Knuth's MIX language %description Mixal is an assembler and interpreter for Donald Knuth's mythical MIX computer, defined in: Donald Knuth, "The Art of Computer Programming", Vol. 1: Fundamental Algorithms_. Addison-Wesley, 1973 (2nd ed.) %prep %setup %build make %install rm -f /usr/bin/mix cp mix /usr/bin %files %doc READ.ME MIX.DOC NOTES /usr/bin/mix mixal-1.08.orig/mixtest100775 1750 1750 350 6652052062 12736 0ustar ajkajk: 'UNIX script to check MIX program correctness' echo "Regression test on prime.mix:" ./mixal foo diff -c prime.out foo echo "Regression test on mystery.mix:" ./mixal foo diff -c mystery.out foo rm -f foo mixal-1.08.orig/mystery.out100664 1750 1750 27735 6653203532 13641 0ustar ajkajk aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa A: 0000000000 I1: 0113 I2:-0000 I3: 0000 I4: 0000 I5: 0000 I6: 0000 X: 0101010101 J: 5711 PC: 5712 Flags: equal 14772 elapsed mixal-1.08.orig/op2c.awk100664 1750 1750 546 6652403600 12667 0ustar ajkajk/^#/ { next } # comment { mnemonic = $1; C = $2; F = $3; is_extended = $4 if (F == "") F = 5 # default field: (0:5) flags = is_extended ? "extended" : "0" if (C == "x") printf("\tdef_directive(\"%s\", do_%s),\n", mnemonic, mnemonic) else printf("\tdef_opcode(\"%s\", %d, %d, %s),\n", mnemonic, C, F, flags) } mixal-1.08.orig/opcodes100664 1750 1750 2046 6652403710 12716 0ustar ajkajk# Opcodes and mnemonics of MIXAL. # From the endpapers in Knuth. # # A `-' in the mnemonic stands for any of the general # registers (A, X, and 1 through 6). The C value then # is the opcode for register A; the other opcodes are # at a constant offset for each register. # # C is the opcode, or `x' for directives. # # F is the default F value for operands ((0:5) if blank). # # An `x' in `field?' means the operand to an intruction # of the given type must NOT specify the F value, because # F is hardwired. # # OP C F field? #----------------------------- nop 00 0 add 01 sub 02 mul 03 div 04 num 05 0 x char 05 1 x hlt 05 2 x sla 06 0 x sra 06 1 x slax 06 2 x srax 06 3 x slc 06 4 x src 06 5 x move 07 1 ld- 08 ld-n 16 st- 24 stj 32 2 stz 33 jbus 34 0 ioc 35 0 in 36 0 out 37 0 jred 38 0 jmp 39 0 x jsj 39 1 x jov 39 2 x jnov 39 3 x jl 39 4 x je 39 5 x jg 39 6 x jge 39 7 x jne 39 8 x jle 39 9 x j-n 40 0 x j-z 40 1 x j-p 40 2 x j-nn 40 3 x j-nz 40 4 x j-np 40 5 x inc- 48 0 x dec- 48 1 x ent- 48 2 x enn- 48 3 x cmp- 56 orig x equ x alf x con x end x mixal-1.08.orig/ops.inc100664 1750 1750 3310 6653203541 12627 0ustar ajkajk def_opcode("add", 1, 5, 0), def_directive("alf", do_alf), def_opcode("char", 5, 1, extended), def_opcode("cmp-", 56, 5, 0), def_directive("con", do_con), def_opcode("dec-", 48, 1, extended), def_opcode("div", 4, 5, 0), def_directive("end", do_end), def_opcode("enn-", 48, 3, extended), def_opcode("ent-", 48, 2, extended), def_directive("equ", do_equ), def_opcode("hlt", 5, 2, extended), def_opcode("in", 36, 0, 0), def_opcode("inc-", 48, 0, extended), def_opcode("ioc", 35, 0, 0), def_opcode("j-n", 40, 0, extended), def_opcode("j-nn", 40, 3, extended), def_opcode("j-np", 40, 5, extended), def_opcode("j-nz", 40, 4, extended), def_opcode("j-p", 40, 2, extended), def_opcode("j-z", 40, 1, extended), def_opcode("jbus", 34, 0, 0), def_opcode("je", 39, 5, extended), def_opcode("jg", 39, 6, extended), def_opcode("jge", 39, 7, extended), def_opcode("jl", 39, 4, extended), def_opcode("jle", 39, 9, extended), def_opcode("jmp", 39, 0, extended), def_opcode("jne", 39, 8, extended), def_opcode("jnov", 39, 3, extended), def_opcode("jov", 39, 2, extended), def_opcode("jred", 38, 0, 0), def_opcode("jsj", 39, 1, extended), def_opcode("ld-", 8, 5, 0), def_opcode("ld-n", 16, 5, 0), def_opcode("move", 7, 1, 0), def_opcode("mul", 3, 5, 0), def_opcode("nop", 0, 0, 0), def_opcode("num", 5, 0, extended), def_directive("orig", do_orig), def_opcode("out", 37, 0, 0), def_opcode("sla", 6, 0, extended), def_opcode("slax", 6, 2, extended), def_opcode("slc", 6, 4, extended), def_opcode("sra", 6, 1, extended), def_opcode("srax", 6, 3, extended), def_opcode("src", 6, 5, extended), def_opcode("st-", 24, 5, 0), def_opcode("stj", 32, 2, 0), def_opcode("stz", 33, 5, 0), def_opcode("sub", 2, 5, 0), mixal-1.08.orig/parse.c100664 1750 1750 13552 6652472257 12655 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" /* for 'here' */ #include "charset.h" #include "parse.h" #include "symbol.h" #include /* #include */ #include #include /* --- The scanner --- */ static const char *the_string, *token_start; /* Token types */ #define defined_sym 'd' #define future_sym 'f' #define number '0' #define slash_slash '%' /* the // operator */ #define eos 'z' /* end of string */ /* The current token: */ static char token; static Cell token_value; static Symbol token_symbol; /* Scan the next token. */ static void advance(void) { char token_text[max_identifier_length + 1]; if (isspace(the_string[0]) || the_string[0] == '\0') token = eos; else if (isalnum(the_string[0])) { /* symbol or number */ size_t length; const char *start = the_string; do { ++the_string; } while (isalnum(the_string[0])); length = the_string - start; if (sizeof token_text - 1 < length) { warn("Atom truncated: %*.*s", length, length, start); length = sizeof token_text - 1; } memcpy(token_text, start, length); token_text[length] = '\0'; if (strspn(token_text, "0123456789") == length) { /* a number */ token = number; token_value = ulong_to_cell(strtoul(token_text, NULL, 10)); } else { /* token is a symbol, either defined or future */ token_symbol = string_to_symbol(token_text); token = is_defined(token_symbol) ? defined_sym : future_sym; } } else if (the_string[0] == '/' && the_string[1] == '/') { the_string += 2; token = slash_slash; } else if (the_string[0] == '"') { /* a quoted string */ token = number; token_value = zero; ++the_string; { const char *end = strchr(the_string, '"'); if (!end) { error("Missing '\"'"); the_string += strlen (the_string); } else { unsigned length = end - the_string; if (5 < length) { warn("String doesn't fit in a machine word"); length = 5; } { unsigned i; for (i = 0; i < length; ++i) token_value = set_byte(C_char_to_mix(the_string[i]), i+1, token_value); } } the_string = end + 1; } } else token = *the_string++; } static void expect(char expected_token) { if (token != expected_token) error ("Expected '%c', not '%*.*s'", expected_token, the_string - token_start, the_string - token_start, token_start); advance(); } void setup_scanner(const char *s) { the_string = s; advance(); } /* --- The parser for the operand field --- */ /* future ::= future_sym | '=' expr '=' */ static Flag is_future(void) { return token == future_sym || token == '='; } static Cell parse_future(void) { Symbol symbol; if (token == future_sym) { symbol = token_symbol; advance(); } else { Cell value; expect('='); value = parse_W(); expect('='); symbol = generate_future_sym(value); } forward_reference(symbol, here); return zero; /* The real value will be filled in when symbol is defined */ } /* atomic ::= '*' | number | defined */ static Flag is_atomic(void) { return token == '*' || token == number || token == defined_sym; } static Cell parse_atomic(void) { Cell result; switch (token) { case '*': result = address_to_cell(here); break; case number: result = token_value; break; case defined_sym: result = symbol_value(token_symbol); break; default: error("Expected an atomic value"); } advance(); return result; } /* expr ::= [+-]? atomic ( bin-op atomic )* */ static Flag is_expr(void) { return token == '+' || token == '-' || is_atomic(); } typedef Cell BinOp(Cell, Cell); /* The : and // operators: (other operators are defined in cell.c) */ static Cell colon(Cell L, Cell R) { return add(mul(ulong_to_cell(8), L), R); } static Cell double_slash(Cell x, Cell y) { Cell quotient, remainder; divide(x, zero, y, "ient, &remainder); return quotient; } /* (Clobbers -overflow-.) */ static Cell parse_expr(void) { Cell sign = ulong_to_cell(1); if (token == '+' || token == '-') { if (token == '-') sign = negative(sign); advance(); } overflow = false; { static const char ops[] = "+-*/%:"; static BinOp * const handlers[] = { add, sub, mul, slash, double_slash, colon }; Cell cell = mul(sign, parse_atomic()); for (;;) { const char *s = strchr(ops, token); if (s) { advance(); cell = handlers[s - ops](cell, parse_atomic()); } else { if (overflow) warn("Overflow in evaluation of expression"); return cell; } } } } /* A ::= expr | future | '' */ static Cell parse_A(void) { if (is_future()) return parse_future(); else if (is_expr()) return parse_expr(); else return zero; } /* F ::= '(' expr ')' | '' */ static Cell parse_F(Cell default_F) { if (token == '(') { Cell result; advance(); result = parse_expr(); expect(')'); return result; } else return default_F; } /* I ::= ',' expr | '' */ static Cell parse_I(void) { if (token == ',') { advance(); return parse_expr(); } else return zero; } /* operand := A F I */ Cell parse_operand(Flag F_must_be_default, Byte default_F) { Cell A = parse_A(); Cell I = parse_I(); Cell F = parse_F((Cell)default_F); if (F_must_be_default && F != (Cell)default_F) error("Illegal operand to extended-opcode instruction"); return set_field(A, make_field_spec(0, 2), set_field(I, make_field_spec(3, 3), set_field(F, make_field_spec(4, 4), zero))); } /* W ::= expr F ( ',' expr F )* */ Cell parse_W(void) { Cell result = zero; for (;;) { Cell expr = parse_expr(); Cell F = parse_F(5); assert_valid_field(F); result = set_field(expr, (Byte) F, result); if (token != ',') break; advance(); } return result; } void done_parsing(void) { if (token != eos) error("Bad syntax in operand field"); } mixal-1.08.orig/parse.h100664 1750 1750 463 6636306357 12616 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef PARSE_H #define PARSE_H #include "mix.h" /* --- The scanner --- */ void setup_scanner(const char *s); /* --- The parser --- */ Cell parse_operand(Flag F_must_be_default, Byte default_F); Cell parse_W(void); void done_parsing(void); #endif mixal-1.08.orig/prime.out100664 1750 1750 14265 6653203512 13231 0ustar ajkajk first five hundred primes 0002 0233 0547 0877 1229 1597 1993 2371 2749 3187 0003 0239 0557 0881 1231 1601 1997 2377 2753 3191 0005 0241 0563 0883 1237 1607 1999 2381 2767 3203 0007 0251 0569 0887 1249 1609 2003 2383 2777 3209 0011 0257 0571 0907 1259 1613 2011 2389 2789 3217 0013 0263 0577 0911 1277 1619 2017 2393 2791 3221 0017 0269 0587 0919 1279 1621 2027 2399 2797 3229 0019 0271 0593 0929 1283 1627 2029 2411 2801 3251 0023 0277 0599 0937 1289 1637 2039 2417 2803 3253 0029 0281 0601 0941 1291 1657 2053 2423 2819 3257 0031 0283 0607 0947 1297 1663 2063 2437 2833 3259 0037 0293 0613 0953 1301 1667 2069 2441 2837 3271 0041 0307 0617 0967 1303 1669 2081 2447 2843 3299 0043 0311 0619 0971 1307 1693 2083 2459 2851 3301 0047 0313 0631 0977 1319 1697 2087 2467 2857 3307 0053 0317 0641 0983 1321 1699 2089 2473 2861 3313 0059 0331 0643 0991 1327 1709 2099 2477 2879 3319 0061 0337 0647 0997 1361 1721 2111 2503 2887 3323 0067 0347 0653 1009 1367 1723 2113 2521 2897 3329 0071 0349 0659 1013 1373 1733 2129 2531 2903 3331 0073 0353 0661 1019 1381 1741 2131 2539 2909 3343 0079 0359 0673 1021 1399 1747 2137 2543 2917 3347 0083 0367 0677 1031 1409 1753 2141 2549 2927 3359 0089 0373 0683 1033 1423 1759 2143 2551 2939 3361 0097 0379 0691 1039 1427 1777 2153 2557 2953 3371 0101 0383 0701 1049 1429 1783 2161 2579 2957 3373 0103 0389 0709 1051 1433 1787 2179 2591 2963 3389 0107 0397 0719 1061 1439 1789 2203 2593 2969 3391 0109 0401 0727 1063 1447 1801 2207 2609 2971 3407 0113 0409 0733 1069 1451 1811 2213 2617 2999 3413 0127 0419 0739 1087 1453 1823 2221 2621 3001 3433 0131 0421 0743 1091 1459 1831 2237 2633 3011 3449 0137 0431 0751 1093 1471 1847 2239 2647 3019 3457 0139 0433 0757 1097 1481 1861 2243 2657 3023 3461 0149 0439 0761 1103 1483 1867 2251 2659 3037 3463 0151 0443 0769 1109 1487 1871 2267 2663 3041 3467 0157 0449 0773 1117 1489 1873 2269 2671 3049 3469 0163 0457 0787 1123 1493 1877 2273 2677 3061 3491 0167 0461 0797 1129 1499 1879 2281 2683 3067 3499 0173 0463 0809 1151 1511 1889 2287 2687 3079 3511 0179 0467 0811 1153 1523 1901 2293 2689 3083 3517 0181 0479 0821 1163 1531 1907 2297 2693 3089 3527 0191 0487 0823 1171 1543 1913 2309 2699 3109 3529 0193 0491 0827 1181 1549 1931 2311 2707 3119 3533 0197 0499 0829 1187 1553 1933 2333 2711 3121 3539 0199 0503 0839 1193 1559 1949 2339 2713 3137 3541 0211 0509 0853 1201 1567 1951 2341 2719 3163 3547 0223 0521 0857 1213 1571 1973 2347 2729 3167 3557 0227 0523 0859 1217 1579 1979 2351 2731 3169 3559 0229 0541 0863 1223 1583 1987 2357 2741 3181 3571 A: 3636363636 I1:-0000 I2: 6763 I3: 0023 I4: 3763 I5: 0000 I6: 0000 X: 3636404047 J: 5722 PC: 5726 Flags: less 186398 elapsed mixal-1.08.orig/run.c100664 1750 1750 21707 6652061041 12331 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" /* for entry_point */ #include "charset.h" #include "io.h" #include "run.h" #include #include #include #include static void stop(const char *message, va_list args) { fprintf(stderr, "RUNTIME ERROR: "); vfprintf(stderr, message, args); fprintf(stderr, "\n"); print_CPU_state(); exit(1); } /* --- Execution statistics --- */ static unsigned long elapsed_time = 0; /* in Tyme units */ /* --- The CPU state --- */ Cell memory[memory_size]; #define A 0 #define X 7 #define J 8 static Cell r[10]; /* the registers; except that r[9] == zero. */ static int comparison_indicator; /* the overflow toggle is defined in cell.c */ static Address pc; /* the program counter */ void set_initial_state(void) { overflow = false; comparison_indicator = 0; { unsigned i; for (i = 0; i < 10; ++i) r[i] = zero; } pc = entry_point; /*** need to check for no entry point */ } void print_CPU_state(void) { printf ("A:"); print_cell (r[A]); printf ("\t"); { /* Print the index registers: */ unsigned i; for (i = 1; i <= 6; ++i) printf ("I%u:%s%04lo ", i, is_negative (r[i]) ? "-" : " ", magnitude (r[i])); } printf ("\nX:"); print_cell (r[X]); printf ("\t J: %04lo", magnitude (r[J])); /* (it's always nonnegative) */ printf (" PC: %04o", pc); printf (" Flags: %-7s %-8s", comparison_indicator < 0 ? "less" : comparison_indicator == 0 ? "equal" : "greater", overflow ? "overflow" : ""); printf (" %11lu elapsed\n", elapsed_time); } /* --- The interpreter --- */ /* --- I've followed Knuth's MIX interpreter quite closely. */ static jmp_buf escape_k; /* continuation to escape from interpreter */ /* C, F, M, and V as defined in Knuth: */ static Byte C; static Byte F; static Cell M; static Cell get_V(void) { return field(F, memory[cell_to_address(M)]); } /* do_foo performs the action of instruction type foo. */ static void do_nop(void) { } static void do_add(void) { r[A] = add(r[A], get_V()); } static void do_sub(void) { r[A] = sub(r[A], get_V()); } static void do_mul(void) { multiply(r[A], get_V(), &r[A], &r[X]); } static void do_div(void) { divide(r[A], r[X], get_V(), &r[A], &r[X]); } static void do_special(void) { switch (F) { case 0: { /* NUM */ unsigned i; Cell num = zero; Cell ten = ulong_to_cell(10); for (i = 1; i <= 5; ++i) num = add(mul(ten, num), (Cell)(get_byte(i, r[A]) % 10)); for (i = 1; i <= 5; ++i) num = add(mul(ten, num), (Cell)(get_byte(i, r[X]) % 10)); r[A] = is_negative(r[A]) ? negative(num) : num; break; } case 1: { /* CHAR */ unsigned long num = magnitude(r[A]); unsigned z = (unsigned) C_char_to_mix('0'); unsigned i; for (i = 5; 0 < i; --i, num /= 10) r[X] = set_byte((Byte) (z + num % 10), i, r[X]); for (i = 5; 0 < i; --i, num /= 10) r[A] = set_byte((Byte) (z + num % 10), i, r[A]); break; } case 2: /* HLT */ longjmp(escape_k, 1); default: error("Unknown extended opcode"); } } static void do_shift(void) { Cell ignore; unsigned long count = magnitude(M); if (is_negative(M) && count != 0) error("Negative shift count"); switch (F) { case 0: /* SLA */ shift_left(zero, r[A], count, &ignore, &r[A]); break; case 1: /* SRA */ shift_right(r[A], zero, count, &r[A], &ignore); break; case 2: /* SLAX */ shift_left(r[A], r[X], count, &r[A], &r[X]); break; case 3: /* SRAX */ shift_right(r[A], r[X], count, &r[A], &r[X]); break; case 4: /* SLC */ shift_left_circular(r[A], r[X], (unsigned)(count % 10), &r[A], &r[X]); break; case 5: { /* SRC */ unsigned c = (10 - count % 10) % 10; /* -count modulo 10 */ shift_left_circular(r[A], r[X], c, &r[A], &r[X]); break; } default: error("Unknown extended opcode"); } } static void do_move(void) { Address from = cell_to_address(M); Address to = cell_to_address(r[1]); unsigned count = F; for (; count != 0; --count) { if (memory_size <= from + count || memory_size <= to + count) error("Address out of range"); memory[to + count] = memory[from + count]; elapsed_time += 2; } r[1] = address_to_cell(to + count); } static void do_lda(void) { r[A] = get_V(); } static void do_ldx(void) { r[X] = get_V(); } static void do_ldi(void) { Cell cell = get_V(); if (INDEX_MAX < magnitude(cell)) error("Magnitude too large for index register: %10o", magnitude(cell)); r[C & 7] = cell; } static void do_ldan(void) { r[A] = negative(get_V()); } static void do_ldxn(void) { r[X] = negative(get_V()); } static void do_ldin(void) { Cell cell = get_V(); if (INDEX_MAX < magnitude(cell)) error("Magnitude too large for index register: %10o", magnitude(cell)); r[C & 7] = negative(cell); } static void do_store(void) { Address a = cell_to_address(M); memory[a] = set_field(r[C-24], F, memory[a]); } static void jump(void) { r[J] = address_to_cell(pc); pc = cell_to_address(M); } static void branch(unsigned condition, int sign) { switch (condition) { case 0: jump(); break; case 1: pc = cell_to_address(M); break; case 2: if (overflow) jump(); overflow = false; break; case 3: if (!overflow) jump(); overflow = false; break; case 4: if (sign < 0) jump(); break; case 5: if (sign == 0) jump(); break; case 6: if (sign > 0) jump(); break; case 7: if (sign >= 0) jump(); break; case 8: if (sign != 0) jump(); break; case 9: if (sign <= 0) jump(); break; default: error("Bad branch condition"); } } static void do_jump(void) { branch(F, comparison_indicator); } static int sign_of_difference(Cell difference) { return magnitude(difference) == 0 ? 0 : is_negative(difference) ? -1 : 1; } static void do_reg_branch(void) { branch(F + 4, sign_of_difference(r[C & 7])); } static void do_jbus(void) { /* no channel is ever busy, because we're using C's blocking I/O */ } static void do_jred(void) { jump(); /* conversely, all channels are always ready */ } static void do_ioc(void) { io_control(F, M); } static void do_in(void) { do_input(F, r[X], cell_to_address(M)); } static void do_out(void) { do_output(F, r[X], cell_to_address(M)); } static void do_addr_op(void) { Cell cell; unsigned reg = C & 7; switch (F) { case 0: cell = add(r[reg], M); break; case 1: cell = sub(r[reg], M); break; case 2: cell = M; break; case 3: cell = negative(M); break; default: error("Unknown extended opcode"); cell = zero; } if (reg - 1 < 6) /* same as: 1 <= reg && reg <= 6 */ if (INDEX_MAX < magnitude(cell)) error("Magnitude too large for index register: %10o", magnitude(cell)); r[reg] = cell; } static void do_compare(void) { Flag saved = overflow; Cell difference = sub(field(F, r[C & 7]), field(F, memory[cell_to_address(M)])); comparison_indicator = sign_of_difference(difference); overflow = saved; } static const struct { void (*action)(void); unsigned clocks; } op_table[64] = { { do_nop, 1 }, { do_add, 2 }, { do_sub, 2 }, { do_mul, 10 }, { do_div, 12 }, { do_special, 1 }, { do_shift, 2 }, { do_move, 1 }, { do_lda, 2 }, { do_ldi, 2 }, { do_ldi, 2 }, { do_ldi, 2 }, { do_ldi, 2 }, { do_ldi, 2 }, { do_ldi, 2 }, { do_ldx, 2 }, { do_ldan, 2 }, { do_ldin, 2 }, { do_ldin, 2 }, { do_ldin, 2 }, { do_ldin, 2 }, { do_ldin, 2 }, { do_ldin, 2 }, { do_ldxn, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_store, 2 }, { do_jbus, 1 }, { do_ioc, 1 }, { do_in, 1 }, { do_out, 1 }, { do_jred, 1 }, { do_jump, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_reg_branch, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_addr_op, 1 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, { do_compare, 2 }, }; void run(void) { install_error_handler(stop); if (setjmp(escape_k) != 0) return; for (;;) { /* print_CPU_state(); */ if (memory_size <= pc) error("Program counter out of range: %4o", pc); { Byte I; destructure_cell(memory[pc++], M, I, F, C); if (6 < I) error("Invalid I-field: %u", I); if (I != 0) M = add(M, r[I]); /* (the add can't overflow because the numbers are too small) */ op_table[C].action(); elapsed_time += op_table[C].clocks; } } } mixal-1.08.orig/run.h100664 1750 1750 315 6652056064 12277 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef RUN_H #define RUN_H #include "mix.h" extern Cell memory[]; void set_initial_state(void); void print_CPU_state(void); void run(void); #endif mixal-1.08.orig/symbol.c100664 1750 1750 13405 6652466522 13043 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #include "mix.h" #include "asm.h" /* this is a sign of bad factoring */ #include "symbol.h" #include #include #include #include /* Here's the theory on forward references. We need to handle 3 sorts of references: ordinary symbols, local symbols like 7B and 7F, and implicit constants like =123=. First let's discuss ordinary symbols. Any symbol that's been referred to but not yet defined has a list of all locations, in the object program built so far, that refer to it. That list is added to by the forward_reference() function. When the symbol is defined, we fix up all the references to it, using the list. After assembly is done, we check if there are any unresolved references, in resolve_generated_futures() (whose main job I'll get to shortly). A minor problem: we don't hold onto the source-line number of a reference, so if it's unresolved we get a misleading error message. The forward_reference() function returns a meaningless value just for historical reasons: originally the list of unresolved references for a symbol was threaded through the simulated memory locations themselves, and so forward_reference() had to return the value to put in the latest referencing location to maintain the list. Now that I've come to my senses, I suppose I should get rid of the return value. Local symbols work just like regular ones, except that a reference to, say, 7B, gets the value defined in the latest definition of 7H, and similarly a reference to 7F is always a forward ref to the next definition of 7H. This can be arranged by having define_symbol() adjust 7B and 7F appropriately when it sees 7H. We handle implicit constants like =123= by generating a unique symbol for each value that occurs in such a constant. (It's of the form "=123", which can't conflict with ordinary or local symbols.) Then a reference to such a constant is simply a forward reference to the generated symbol. After assembly is complete resolve_generated_futures() resolves all the generated symbols with appropriate addresses. Note that this scheme uniquifies the constant references for free. */ /* Pre: size != 0 */ static void *allot(size_t size) { void *result = malloc(size); if (!result) fatal_error("Out of heap space"); return result; } static int stricmp(const char *s, const char *t) { while (*s && *t) if (tolower(*s) != tolower(*t)) return 1; else s++, t++; return tolower(*s) != tolower(*t); } /* --- The symbol table --- */ static Symbol symbol_table[17]; /* Apply proc to each symbol in the symbol table. */ static void for_each_symbol(void (*proc)(Symbol)) { unsigned i; for (i = 0; i < sizeof symbol_table / sizeof symbol_table[0]; ++i) { Symbol s = symbol_table[i]; for (; s; s = s->next) proc(s); } } static unsigned hash(const char *s) { unsigned h = 0; for (; *s; s++) h = (h << 5) - h + toupper(*s); return h % (sizeof symbol_table / sizeof symbol_table[0]); } Symbol string_to_symbol(const char *name) { Symbol *bucket = symbol_table + hash(name); Symbol p = *bucket; for (; p; p = p->next) if (stricmp(name, p->name) == 0) return p; { /* Symbol doesn't exist yet. */ Symbol result = allot(sizeof(struct Symbol)); strcpy(result->name = allot(strlen(name) + 1), name); result->defined = false; result->references = NULL; result->next = *bucket; result->cell = zero; *bucket = result; return result; } } Flag is_defined(Symbol symbol) { return symbol->defined; } Cell symbol_value(Symbol symbol) { assert(symbol->defined); return symbol->cell; } void forward_reference(Symbol symbol, Address address) { assert(!symbol->defined); { AddressList refs = allot(sizeof(struct AddressList)); refs->address = address; refs->next = symbol->references; symbol->references = refs; } } /* Pre: !is_defined(symbol) Set the address field of each cell in symbol's set of references to definition. Frees the set of references. */ static void resolve_references(Symbol symbol, Cell definition) { AddressList refs, rest; assert(!symbol->defined); for (refs = symbol->references; refs; refs = rest) { asm_store_field(refs->address, 0, 2, definition); rest = refs->next; free(refs); } } void define_symbol(Symbol symbol, Cell cell) { { /* handle local symbols */ const char *name = symbol->name; if (isdigit(name[0]) && strlen(name) == 2) { char c = toupper(name[1]); if (c == 'F' || c == 'B') { error("Definition of local ref: %s", name); return; } else if (c == 'H') { char new_name[3]; Symbol nB, nF; strcpy(new_name, name); new_name[1] = 'B'; nB = string_to_symbol(new_name); nB->defined = true, nB->cell = cell; new_name[1] = 'F'; nF = string_to_symbol(new_name); resolve_references(nF, cell); nF->defined = false, nF->references = NULL; return; } else ; /* not a local; fall through */ } } if (symbol->defined) warn("'%s' multiply-defined", symbol->name); else resolve_references(symbol, cell); symbol->defined = true, symbol->cell = cell; } Symbol generate_future_sym(Cell value) { char name[12]; sprintf(name, "=%ld", cell_to_long(value)); return string_to_symbol(name); } static void resolve_if_dangling(Symbol symbol) { if (symbol->defined) return; if (symbol->name[0] == '=') { /* it's a generated symbol */ define_symbol(symbol, address_to_cell(here)); assemble(long_to_cell(atol(symbol->name + 1))); } else { /* it's a user symbol */ if (symbol->references) error("Unresolved reference: %s", symbol->name); /* it would be nice to print the reference list, too */ } } void resolve_generated_futures(void) { for_each_symbol(resolve_if_dangling); } mixal-1.08.orig/symbol.h100664 1750 1750 2774 6652055563 13036 0ustar ajkajk/* MIX simulator, copyright 1994 by Darius Bacon */ #ifndef SYMBOL_H #define SYMBOL_H #include "mix.h" typedef struct AddressList { struct AddressList *next; Address address; } *AddressList; /* --- Symbols --- */ typedef struct Symbol { struct Symbol *next; char *name; Flag defined; Cell cell; AddressList references; } *Symbol; /* * If sym->defined, then sym->cell is the symbol's value. * If !sym->defined, then sym->references is the set of * references to sym. When the symbol is finally defined, * the address field (0:2) of each cell in sym->references * gets set to the defined value. */ /* Return the symbol named; if it doesn't exist, create it, initially undefined. */ Symbol string_to_symbol(const char *name); Flag is_defined(Symbol symbol); /* Pre: is_defined(symbol) */ Cell symbol_value(Symbol symbol); /* Pre: !is_defined(symbol) Post: address has been adjoined to symbol's references. */ void forward_reference(Symbol symbol, Address address); /* Post: symbol_value(symbol) == cell If symbol was undefined, then all refs to it are resolved. If symbol was already defined, and non-local, then gives a warning. */ void define_symbol(Symbol symbol, Cell cell); /* Return a symbol, distinct from all symbols defined in the source program, whose value will be set, when resolve_generated_futures() is called, to the address of a cell which contains value. */ Symbol generate_future_sym(Cell value); void resolve_generated_futures(void); #endif mixal-1.08.orig/test.bat100664 1750 1750 231 6636306357 12773 0ustar ajkajkrem Mess-DOS batch file to check program correctness mix foo echo n | comp prime.out foo mix foo echo n | comp mystery.out foo