]> thyrsus.com Git - intercal.git/commitdiff
Intercal 0.3 prerelease, Sat May 12 12:24:39 EDT 1990.
authorEric S. Raymond <esr@thyrsus.com>
Sat, 12 May 1990 20:24:39 +0000 (16:24 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 26 Aug 2010 00:34:08 +0000 (20:34 -0400)
This was the first publicly visible version.

(This is a retrospective comment.)

18 files changed:
BUGS [new file with mode: 0644]
Makefile [new file with mode: 0644]
READ.ME [new file with mode: 0644]
THEORY [new file with mode: 0644]
cesspool.c [new file with mode: 0644]
cesspool.h [new file with mode: 0644]
feh.c [new file with mode: 0644]
fiddle.c [new file with mode: 0644]
ick-wrapper.c [new file with mode: 0644]
ick.h [new file with mode: 0644]
ick.y [new file with mode: 0644]
intercal.man [new file with mode: 0644]
intercal.sty [new file with mode: 0644]
intercal.tex [new file with mode: 0644]
lexer.l [new file with mode: 0644]
lose.c [new file with mode: 0644]
lose.h [new file with mode: 0644]
sample.i [new file with mode: 0644]

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..56d50c4
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,57 @@
+               NEW FEATURES IN C-INTERCAL
+
+1. As a convenience to all you junior birdmen out there, `NINER' is accepted as
+   a synonym for `NINE' in INTERCAL input.
+
+2. The COME FROM statement is now compiled. You may write
+
+   PLEASE COME FROM (n) 
+
+   and the effect will be that whenever execution reaches statement label n,
+   it will immediately transfer control to the statement following the
+   COME FROM. Conditional COME FROM is possible; ABSTAIN FROM COMING FROM and
+   REINSTATE COMING FROM are both valid. DON'T COME FROM is a no-op (until
+   reinstated). Finally; NEXTING to the label `target' of an un-abstained
+   COME FROM *will* cause control to be transferred to the statement following
+   the COME FROM.
+
+                       BUGS
+
+1) INTERCAL would be intrinsically a crock even if it worked right.
+
+2) The INTERCAL-72 handling of invalid statements isn't implemented; instead
+   they raise a normal compile-time error. This is because I haven't figured
+   out how to force YACC to do the needed thing yet. It means C-INTERCAL
+   can't compile the INTERCAL-72 system library yet. Isn't compatibility
+   wonderful? I may have to go to a handcrafted LL(1) parser to fix this...
+
+3) Error-checking could be improved. Not all the errors listed in the
+   manual are actually detected (of those listed in lose.h, E123, E621, E632,
+   E562, E579, E436, E017, E275, E182, E129, E139, and E778 are implemented).
+   In this respect C-INTERCAL follows nobly in the tradition of many production
+   compilers.
+
+4) Proper C code is generated for array operations, but the runtime-library
+   hooks for the dynamic memory management needed to make the code work are
+   stubbed out. I'm poor at array-bashing. Rachel Millian has promised to
+   implement this for the next release.
+
+5) The Roman-numeral output from INTERCAL isn't quite as butchered as it ought
+   to be, because neither I nor the implementor could figure out what the frotz
+   the note in the INTERCAL-72 manual about modulo 4000 and I and M and all
+   that was really supposed to mean.
+
+6) The manual is mangled in spots. I'm in touch with the INTERCAL-72 authors
+   and we'll try to fix this in the next release, assuming there *is* a next
+   release.
+
+                       TO DO
+
+1. Test this loser on something other than the sample program.
+
+2. Add more optimization templates, esp. the idioms for &, |, ^, ~.
+
+3. Input format internationalization -- allow WRITE IN input digits in
+   major languages such as Nahuatl, Tagalog, Sanskrit, and Basque.
+
+4. Forget this @!%$#! crock and take a long vacation.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..451f2a3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+# Makefile for the INTERCAL compiler
+
+YDEBUG = -v -t
+SYSTYPE = -DATT                # -DBSD for Berkeley systems
+CFLAGS = -I. $(SYSTYPE) -g
+LDFLAGS = -lg
+
+DOCS = READ.ME intercal.man intercal.tex intercal.sty BUGS THEORY
+SOURCES = cesspool.[ch] feh.c fiddle.c ick.[yh] lose.[ch] lexer.l
+
+all: ick libick.a
+
+ick: y.tab.o lexer.o feh.o lose.o fiddle.o
+       $(CC) y.tab.o lexer.o feh.o lose.o fiddle.o $(LDFLAGS) -o ick
+
+y.tab.h y.tab.c: ick.y
+       @echo "expect 13 shift/reduce conflicts"
+       yacc -d $(YDEBUG) ick.y
+
+lextest: y.tab.h lexer.c ick.h
+       $(CC) -DMAIN lexer.c -ll -o lextest
+
+y.tab.o: y.tab.c ick.h lose.h
+lexer.o: lexer.c y.tab.h ick.h
+feh.o: feh.c y.tab.h ick.h lose.h
+cesspool.o: cesspool.c cesspool.h lose.h
+lose.o: lose.h
+
+libick.a: cesspool.o lose.o fiddle.o
+       ar cr libick.a cesspool.o lose.o fiddle.o
+
+install:
+       cp cesspool.h /usr/include
+       cp libick.a /usr/lib
+       cp ick /usr/bin
+
+clean:
+       rm -f yacc.* y.tab.* y.output *~ *.[oa] lexer.c lextest ick
+       rm -f sample.c sample ick.shar Part1.sh Part2.sh
+
+shar:
+       shar $(DOCS) Makefile $(SOURCES) ick-wrapper.c sample.i >ick.shar
+
+mailable:
+       shar $(DOCS) Makefile >Part1.sh
+       shar  $(SOURCES) ick-wrapper.c sample.i >Part2.sh
+
+
diff --git a/READ.ME b/READ.ME
new file mode 100644 (file)
index 0000000..bf70684
--- /dev/null
+++ b/READ.ME
@@ -0,0 +1,50 @@
+                       C-INTERCAL (v 0.3)
+
+       NOTE! THIS IS A PRE-RELEASE VERSION WITH SOME KNOWN BUGS!
+       SEE THE `BUGS' FILE FOR DETAILS, AND EARN THE ETERNAL GRATITUDE
+       OF THE HUGE, BUSTLING INTERCAL COMMUNITY BY FIXING THEM!
+
+This package is an implementation of the language INTERCAL designed by Don
+Woods and James Lyon, who have since spent most of twenty years trying to
+live it down.
+
+The implementation was created by Eric S. Raymond (...!uunet!snark!eric)
+during a fit of lunacy from which he has since mostly recovered. The files
+included are:
+
+READ.ME                -- this file
+intercal.man   -- The INTERCAL manual (read this next!)
+intercal.tex   -- TeX source form
+intercal.sty   -- TeX style file
+THEORY         -- some notes on the internals of the INTERCAL compiler
+BUGS           -- notes pertaining to this release
+
+Makefile       -- makefile for the INTERCAL compiler
+lexer.l                -- the lexical analyzer specification (in LEX)
+ick.y          -- the grammar specification (in YACC)
+ick.h          -- compilation types and defines
+feh.c          -- INTERCAL-to-C code generator
+fiddle.c       -- the INTERCAL operators
+lose.[ch]      -- INTERCAL compile- and run-time error handling
+ick-wrapper.c  -- the driver for generated C-from-INTERCAL code
+cesspool.c     -- the INTERCAL runtime support code
+cesspool.h     -- interface fr. generated code to the INTERCAL runtime support
+
+sample.i       -- a sample INTERCAL program (from the manual)
+
+You want a man page? Man pages are for wimps. To compile an INTERCAL
+program `foo.i' to executable code, just do
+
+       ick foo.i
+
+There's a -d option that leaves the generated `foo.c' in place for
+inspection (suppressing compilation to machine code), and an -O option
+that enables the (hah!) optimizer. Other than that, yer on yer own.
+
+One other switch affects C-intercal's runtime behavior. The `-C'
+option forces output in "clockface" mode, for superstitious users who
+believe writing "IV" upside-down offends IVPITER and would rather
+see IIII.
+
+Report bugs, if you absolutely must, to the author. Or post them to
+alt.lang.intercal. Or something.
diff --git a/THEORY b/THEORY
new file mode 100644 (file)
index 0000000..f08b592
--- /dev/null
+++ b/THEORY
@@ -0,0 +1,51 @@
+               INTERCAL IMPLEMENTOR'S NOTES
+
+This C-INTERCAL compiler is a very conventional implementation using YACC and
+LEX. Each line of INTERCAL is translated into a C if()-then; the guard part
+is used to implement abstentions and RESUMES, and the arm part translates the
+`body' of the corresponding INTERCAL statement.
+
+The generated C code is plugged into the template file ick-wrapper.c inside
+main(). It needs to be linked with cesspool.o, fiddle.o and lose.o. Cesspool.o
+is the code that implements the storage manager; fiddle.o implements the
+INTERCAL operators; and lose.o is the code that generates INTERCAL's error
+messages.
+
+The abstain[] array in the generated C is used to track line and label
+abstentions; if member i is on, the statement on line i is being abstained
+from. Labels are mapped to line numbers in the code checker, just before
+optimization.
+
+The gerund variables at the top of the template file are used to implement
+gerund abstentions (ABSTAIN FROM CALCULATING etc). The guard part of each
+generated C statement checks the appropriate variable.
+
+RESUMES are implemented  by setting skipto to the location at which execution
+is to resume, then jumping to the top of the program and skipping all the
+guard/arm pairs before the proper NEXT.
+
+The parser builds an array of tuples, one for each INTERCAL statement. Most
+tuples have node trees attached. Once all tuples have been generated,
+the compile-time checker and optimizer phases can do consistency checks
+and expression-tree rewrites. Finally, the tuples are ground out as C code
+by the emit() function.
+
+The optimizer does constant folding for all five operators. It also checks
+for the idiom for `test for nonzeroness'.
+
+Calculations are fully type-checked at compile time; they have to be because
+(as I read the manual) the 16- and 32-bit versions of the unary ops do
+different things. The only potential problem here is that the typechecker
+has to assume that :m ~ :n has the type of :n (32-bit) even though the
+result might fit in 16 bits. At run-time everything is calculated in 32
+bits. When INTERCAL-72 was designed 32 bits was expensive; now it's cheap.
+Really, the only reason for retaining a 16-bit type at all is for the
+irritation value of it (yes, C-INTERCAL *does* enforce the 16-bit limit
+on constants).
+
+Note that the spectacular ugliness of INTERCAL syntax requires that the lexical
+analyzer have two levels. One, embedded in the input() function, handles
+logical-line continuation and the ! abbrev, and stashes each logical line away
+in a buffer accessible to the code generator (this is necessary for the *
+construct to be compiled correctly). The upper level is generated by lex(1) and
+does normal tokenizing for YACC.
diff --git a/cesspool.c b/cesspool.c
new file mode 100644 (file)
index 0000000..94fbcb9
--- /dev/null
@@ -0,0 +1,404 @@
+/* cesspool.c -- storage management and runtime support for INTERCAL */
+/* LINTLIBRARY */
+#include <stdio.h>
+#include "cesspool.h"
+#include "lose.h"
+
+/**********************************************************************
+ *
+ * The following functions manipulate the nexting stack
+ *
+ *********************************************************************/
+
+#define MAXNEXT        80
+
+int next[MAXNEXT];
+int nextindex = 0;
+
+void pushnext(n)
+int n;
+{
+    if (nextindex < MAXNEXT)
+       next[nextindex++] = n;
+    else
+       lose(lineno, E123);
+}
+
+unsigned int popnext(n)
+int n;
+{
+    while (n--)
+       if (nextindex > 0)
+           nextindex--;
+    return(nextindex ? next[nextindex - 1] : -1);
+}
+
+unsigned int resume(n)
+unsigned int n;
+{
+    if (n == 0)
+       lose(lineno, E621);
+    else if ((n = popnext(n)) == -1)
+       lose(lineno, E632);
+    else
+       return(n);
+}
+
+/**********************************************************************
+ *
+ * The following functions implement the INTERCAL I/O model
+ *
+ *********************************************************************/
+
+unsigned int pin(width)
+int width;
+{
+    char               buf[BUFSIZ], *cp, *strtok();
+    unsigned int       result = 0;
+
+    if (fgets(buf, BUFSIZ, stdin) == (char *)NULL)
+       lose(lineno, E562);
+
+    cp = strtok(buf, " ");
+    do {
+       int     digit;
+
+       if (strcmp(cp, "OH") == 0 || strcmp(cp, "ZERO") == 0)
+           digit = 0;
+       else if (strcmp(cp, "ONE") == 0)
+           digit = 1;
+       else if (strcmp(cp, "TWO") == 0)
+           digit = 2;
+       else if (strcmp(cp, "THREE") == 0)
+           digit = 3;
+       else if (strcmp(cp, "FOUR") == 0)
+           digit = 4;
+       else if (strcmp(cp, "FIVE") == 0)
+           digit = 5;
+       else if (strcmp(cp, "SIX") == 0)
+           digit = 6;
+       else if (strcmp(cp, "SEVEN") == 0)
+           digit = 7;
+       else if (strcmp(cp, "EIGHT") == 0)
+           digit = 8;
+       else if (strcmp(cp, "NINE") == 0 || strcmp(cp, "NINER") == 0)
+           digit = 9;
+       else
+           lose(lineno, E579);
+
+       result = result * 10 + digit;
+    } while
+       (cp = strtok((char *)NULL, " "));
+
+    if (width = 16 && result > 0xffff)
+       lose(lineno, E579);
+}
+
+/**********************************************************************
+ *
+ * Butchered Roman numerals implemented by
+ * Michael Ernst, mernst@theory.lcs.mit.edu. May 7, 1990
+ *
+ * The INTERCAL manual hints that 3999 should translate to MMMIM
+ * (compare MMMCMXCIX) without specifying what the translation is.
+ * That may be a typo; in any case, this implementation isn't that
+ * butchered.
+ *
+ *********************************************************************/
+
+#define MAXDIGITS      10              /* max base 10 digits */
+#define MAXROMANS      (MAXDIGITS*4+1) /* max chars in translation */
+
+/*
+ * The first column tells how many of the succeeding columns are used.
+ * The other columns refer to the columns of br_equiv and br_overbar.
+ */
+static int br_trans[10][5] =
+{
+    {0, 0, 0, 0, 0},
+    {1, 0, 0, 0, 0},
+    {2, 0, 0, 0, 0},
+    {3, 0, 0, 0, 0},
+    {2, 1, 2, 0, 0},        /* or use {4, 0, 0, 0, 0} */
+    {1, 2, 0, 0, 0},
+    {2, 2, 1, 0, 0},
+    {3, 2, 1, 1, 0},
+    {4, 2, 1, 1, 1},
+    {2, 1, 3, 0, 0}
+};
+
+/*
+ * butcher places in the string result the "butchered" Roman numeral for val.
+ * This string should be printed at the beginning of a line; it spans two
+ * lines and already contains newlines.
+ */
+
+static void butcher(val, result)
+unsigned long val;
+char   *result;
+{
+    int i, j;
+    int digitsig, digitval;
+    char res[MAXROMANS], ovb[MAXROMANS];
+
+    /* We need FOUR columns because of the odd way that M and I interact. */
+    static char br_equiv[MAXDIGITS][4] =
+    {
+       {'I', 'I', 'V', 'X'}, {'X', 'X', 'L', 'C'},
+       {'C', 'C', 'D', 'M'}, {'M', 'I', 'V', 'X'},
+       {'X', 'X', 'L', 'C'}, {'C', 'C', 'D', 'M'},
+       {'M', 'i', 'v', 'x'}, {'x', 'x', 'l', 'c'},
+       {'c', 'c', 'd', 'm'}, {'m', 'i', 'v', 'x'},
+    };
+
+    static char br_overbar[MAXDIGITS][4] =
+    {
+       {' ', ' ', ' ', ' '},
+       {' ', ' ', ' ', ' '},
+       {' ', ' ', ' ', ' '},
+       {' ', '_', '_', '_'},
+       {'_', '_', '_', '_'},
+       {'_', '_', '_', '_'},
+       {'_', ' ', ' ', ' '},
+       {' ', ' ', ' ', ' '},
+       {' ', ' ', ' ', ' '},
+       {' ', '_', '_', '_'},
+    };
+
+    if (val == 0)
+       (void) strcpy(result, "_\n \n");
+    else
+    {
+       res[MAXROMANS-1] = 0;
+       ovb[MAXROMANS-1] = 0;
+       i = MAXROMANS-1;
+
+       /* the significance of the current digit is 10 ** digitsig */
+       for (digitsig = 0; (digitsig < MAXDIGITS) && (val > 0); digitsig++)
+       {
+           digitval = val % 10;
+           for (j = br_trans[digitval][0]; j > 0; j--)
+           {
+               /* printf("In j loop: %d %d\n", j, i); */
+               res[--i] = br_equiv[digitsig][br_trans[digitval][j]];
+               ovb[i] = br_overbar[digitsig][br_trans[digitval][j]];
+           }
+           val = val / 10;
+       }
+
+       j = i;
+       while (*result++ = ovb[j++])
+           continue;
+       *--result = '\n';
+
+       j = i;
+       while (*++result = res[j++])
+           continue;
+       *result++ = '\n';
+       *result = '\0';
+    }
+}
+
+void clockface(mode)
+/* enable or disable clockface mode (output IIII instead of IV) */
+bool mode;
+{
+    if (mode)
+    {
+       /* clockface mode */
+       br_trans[4][0] = 4;
+       br_trans[4][1] = 0;
+       br_trans[4][2] = 0;
+    }
+    else
+    {
+       /* normal mode */
+       br_trans[4][0] = 2;
+       br_trans[4][1] = 1;
+       br_trans[4][2] = 2;
+    }
+}
+
+void pout(val)
+/* output in `butchered' Roman numerals; see manual, part 4.4.13 */
+unsigned int val;
+{
+    char       result[2*MAXROMANS+1];
+
+    butchar(val, result);
+    (void) puts(result);
+}
+
+/**********************************************************************
+ *
+ * The following functions implement the INTERCAL array model
+ *
+ *********************************************************************/
+
+/*VARARGS3*/
+unsigned int aget(type, index, dim)
+/* return the value of the array location given by the 4th-nth args */
+unsigned int   type, index;
+int            dim;
+{
+    /*
+     * The function may abort if no resize() has been executed for the
+     * array, or if any member of the tuple is zero.
+     */
+}
+
+/*VARARGS4*/
+void aput(value, type, index, dim)
+/* set the value of an array location given by the 5th-nth args */
+unsigned int   value, type, index;
+int            dim;
+{
+    /*
+     * The function may abort if no resize() has been executed for the
+     * array, or if any member of the tuple is zero.
+     */
+}
+
+/*VARARGS3*/
+void resize(type, index, dim)
+/* resize an array to the shape of the 4th-nth args */
+unsigned int   type, index;
+int            dim;
+{
+    /*
+     * The function may abort if any member of the tuple is zero.
+     * If the array being resized exists, it should preserve the contents
+     * of whatever sub-volume remains in the resized version.
+     */
+}
+
+static void arraycopy(type, index, target, source)
+/* stash away an array variable's value */
+unsigned int   type, index;
+char   **target, *source;
+{
+}
+
+/**********************************************************************
+ *
+ * The following functions implement save/retrieve
+ *
+ * If you want a more sophisticated dynamic allocation strategy,
+ * go ahead and implement one! *I'm* sure not stopping you...
+ *
+ *********************************************************************/
+
+#define MAXSAVE        100
+
+typedef struct         /* this is a save-stack element */
+{
+    int        type;           /* variable type */
+    int index;         /* variable's index within the type */
+    int depth;         /* depth of stash */
+    union              /* the data itself */
+    {
+       short   onespot;
+       int     twospot;
+       short   *tail;
+       int     *hybrid;
+    } save;
+}
+stashbox;
+
+static stashbox stashes[MAXSAVE];
+
+void stashinit()
+{
+    memset(stashes, sizeof(stashes));
+}
+
+static stashbox *fetch(type, index)
+/* restore the value of a variable from the save stack */
+unsigned int   type, index;
+{
+    stashbox *sp, *tp = (stashbox *)NULL;
+    int depthfound = 0;
+
+    for (sp = stashes; sp < stashes + MAXSAVE; sp++)
+       if (sp->type == type && sp->index == index && sp->depth > depthfound)
+       {
+           depthfound = sp->depth;
+           tp = sp;
+       }
+
+    return(tp);
+}
+
+void stash(type, index, from)
+/* stash away the variable's value */
+char           *from;
+unsigned int   type, index;
+{
+    stashbox *sp, *op = fetch(type, index);
+
+    for (sp = stashes; sp < stashes + MAXSAVE; sp++)
+       if (sp->type == 0)
+       {
+           if (op)
+               sp->depth = op->depth + 1;
+           else
+               sp->depth = 0;
+           if (type == ONESPOT)
+               memcpy((char *)&sp->save.onespot, from,sizeof(unsigned short));
+           else if (type == TWOSPOT)
+               memcpy((char *)&sp->save.twospot, from, sizeof(unsigned int));
+           else if (type == TAIL)
+               arraycopy((char **)&sp->save.tail, from);
+           else if (type == HYBRID)
+               arraycopy((char **)&sp->save.hybrid, from);
+           return;
+       }
+    lose(E222);
+}
+
+void retrieve(to, type, index)
+char           **to;
+unsigned int   type, index;
+{
+    stashbox   *sp;
+
+    if ((sp = fetch(type, index)) == (stashbox *)NULL)
+       lose(E436);
+    else
+    {
+       if (type == ONESPOT)
+           memcpy(to, (char *)&sp->save.onespot, sizeof(unsigned short));
+       else if (type == TWOSPOT)
+           memcpy(to, (char *)&sp->save.twospot, sizeof(unsigned int));
+       else if (type == TAIL)
+       {
+           free(to);           /* free storage allocated for array copy */
+           *to = (char *)&sp->save.tail;
+       }
+       else if (type == HYBRID)
+       {
+           free(to);           /* free storage allocated for array copy */
+           *to = (char *)&sp->save.hybrid;
+       }
+       sp->type = 0;   /* mark this stashbox free */
+    }
+}
+
+/**********************************************************************
+ *
+ * The following function is used for random error generation
+ *
+ *********************************************************************/
+
+unsigned int roll(n)
+/* return TRUE on n% chance, FALSE otherwise */
+unsigned int n;
+{
+#ifdef USG
+   return(lrand48() % 100 < n);
+#else
+   return(rand() % 100 < n);
+#endif /* UNIX */
+}
+
+/* cesspool.c ends here */
diff --git a/cesspool.h b/cesspool.h
new file mode 100644 (file)
index 0000000..44251a4
--- /dev/null
@@ -0,0 +1,18 @@
+/* cesspool.h -- interface to INTERCAL storage manager and runtime support */
+
+typedef int bool;
+#define TRUE   1
+#define FALSE  0
+
+extern unsigned int aget(), pin(), roll(), popnext(), resume();
+extern void pushnext(), resize(), stashinit(), stash(), retrieve(), aput();
+extern void clockface(), pout();
+
+extern int lineno;
+
+#define ONESPOT        0
+#define TWOSPOT        1
+#define TAIL   2
+#define HYBRID 3
+
+/* cesspool.h ends here */
diff --git a/feh.c b/feh.c
new file mode 100644 (file)
index 0000000..83597ed
--- /dev/null
+++ b/feh.c
@@ -0,0 +1,936 @@
+/****************************************************************************
+
+NAME
+   feh.c -- code-generator back-end for ick parser
+
+DESCRIPTION
+   This module provides storage manglement and code degeneration
+for the INTERCAL compiler.
+
+****************************************************************************/
+/*LINTLIBRARY */
+#include <stdio.h>
+#include <signal.h>
+#include "ick.h"
+#include "y.tab.h"
+#include "lose.h"
+
+extern unsigned int mingle(), select();
+extern unsigned int and16(), or16(), xor16(), and32(), or32(), xor32();
+
+extern char linebuf[];
+extern int  yydebug, yylineno;
+
+/* compilation options */
+static bool dooptimize;        /* do optimizations? (controlled by -O) */
+static bool clockface; /* set up output to do IIII for IV */
+
+#define SKELETON       "ick-wrapper.c"
+
+int lineno;    /* current source line number; lose() uses it */
+
+int yyerror()
+{
+    lose(yylineno, E017);
+}
+
+/*************************************************************************
+ *
+ * Node allocation functions.
+ *
+ * Nodes are used to represent expresion trees. The emit() function
+ * deallocates them.
+ *
+ **************************************************************************/
+
+node *newnode()
+/* allocate and zero out a new expression node */
+{
+    return((node *)calloc(sizeof(node), 1));
+}
+
+node *cons(type, car, cdr)
+int type;
+node *car, *cdr;
+{
+    node *np = newnode();
+
+    np->opcode = type;
+    np->lval = car;
+    np->rval = cdr;
+}
+
+/*************************************************************************
+ *
+ * Variable-name mapping
+ *
+ * This permits us to optimize use of variable storage at runtime
+ *
+ **************************************************************************/
+
+/* this maps the `external' name of a variable to an internal array index */
+typedef struct
+{
+    int        type;
+    int extindex;
+    int intindex;
+}
+atom;
+
+static atom oblist[MAXSTASHES], *obdex;
+static int nonespots, ntwospots, ntails, nhybrids;
+
+unsigned int intern(type, index)
+{
+    atom       *x;
+
+    /* if it's already on the oblist, return its intindex */
+    for (x = oblist; x < obdex; x++)
+       if (x->type == type && x->extindex == index)
+           return(x->intindex);
+
+    /* else we must intern a new symbol */
+    if (obdex >= oblist + MAXSTASHES)
+       lose(yylineno, E333);
+    obdex->type = type;
+    obdex->extindex = index;
+    if (type == ONESPOT)
+       obdex->intindex = nonespots++;
+    if (type == TWOSPOT)
+       obdex->intindex = ntwospots++;
+    if (type == TAIL)
+       obdex->intindex = ntails++;
+    if (type == HYBRID)
+       obdex->intindex = nhybrids++;
+    ++obdex;
+
+    return(obdex[-1].intindex);
+}
+
+/*************************************************************************
+ *
+ * Tuple allocation functions.
+ *
+ **************************************************************************/
+
+static tuple tuples[MAXLINES];
+
+static void treset()
+{
+    memset(tuples, '\0', sizeof(tuple) * MAXLINES);
+    nonespots = ntwospots = ntails = nhybrids = 0;
+    obdex = oblist;
+    lineno = 0;
+}
+
+tuple *newtuple()
+/* allocate and zero out a new expression tuple */
+{
+    if (lineno >= MAXLINES)
+       lose(yylineno, E666);
+    else
+       return(tuples + lineno++);
+}
+
+/*************************************************************************
+ *
+ * The typecaster
+ *
+ * The theory here is that we associate a type with each node in order to
+ * know what widths of unary-logical operator to use.
+ *
+ **************************************************************************/
+
+static void typecast(np)
+node *np;
+{
+    /* recurse so we typecast each node after all its subnodes */
+    if (np == (node *)NULL)
+       return;
+    else if (np->lval != (node *)NULL)
+       typecast(np->lval);
+    if (np->rval != (node *)NULL)
+       typecast(np->rval);
+
+    /*
+     * This is an entire set of type-deducing machinery right here.
+     */
+    if (np->opcode == MESH || np->opcode == ONESPOT || np->opcode == TAIL)
+       np->width = 16;
+    else if (np->opcode==TWOSPOT ||np->opcode==HYBRID ||np->opcode==MINGLE)
+       np->width = 32;
+    else if (np->opcode == AND || np->opcode == OR || np->opcode == XOR)
+       np->width = np->rval->width;
+    else if (np->opcode == SELECT)
+       np->width = np->rval->width;    /* n-bit select has an n-bit result */
+    else if (np->opcode == SUB)
+       np->width = np->rval->width;    /* tpe of the array */
+}
+
+/*************************************************************************
+ *
+ * The codechecker
+ *
+ * This checks for nasties like mismatched types in assignments that
+ * can be detected at compile time -- also for errors that could cause
+ * the compilation of the generated C to fail, like generated gotos to
+ * nonexistent labels or duplicate labels.
+ *
+ **************************************************************************/
+
+static void codecheck()
+{
+    tuple      *tp, *up;
+
+    /* check for assignment type mismatches */
+    for (tp = tuples; tp < tuples + lineno; tp++)
+       if (tp->type == GETS)
+           if (tp->u.node->lval->width == 16 && tp->u.node->lval->width == 32)
+               lose(tp - tuples + 1, E275);
+
+    /* check for duplicate labels */
+    for (tp = tuples; tp < tuples + lineno; tp++)
+       if (tp->label)
+           for (up = tuples; up < tuples + lineno; up++)
+               if (tp != up && tp->label == up->label)
+                   lose(tp - tuples + 1, E182);
+
+    /*
+     * Check that every NEXT, ABSTAIN, REINSTATE and COME_FROM actually has a
+     * legitimate target label.
+     */
+    for (tp = tuples; tp < tuples + lineno; tp++)
+       if (tp->type == NEXT
+           || tp->type == ABSTAIN || tp->type == REINSTATE
+           || tp->type == COME_FROM)
+       {
+           bool        foundit = FALSE;
+
+           for (up = tuples; up < tuples + lineno; up++)
+               if (tp->u.target == up->label)
+               {
+                   foundit = TRUE;
+                   break;
+               }
+           if (!foundit)
+           {
+               if (tp->type == NEXT)
+                   lose(tp - tuples + 1, E129);
+               else if (tp->type == COME_FROM)
+                   lose(tp - tuples + 1, E444);
+               else
+                   lose(tp - tuples + 1, E139);
+           }
+           /* this substitutes line numbers for label numbers */
+           else if (tp->type != NEXT)
+           {
+               if (tp->type == COME_FROM)
+                   if (up->comefrom)
+                       lose(yylineno, E555);
+                   else
+                       up->comefrom = tp - tuples + 1;
+               tp->u.target = up - tuples + 1;
+           }
+       }
+}
+
+/*************************************************************************
+ *
+ * Optimizer code.
+ *
+ * It's not a very good optimizer, is it?
+ *
+ **************************************************************************/
+
+/* optimizer node codes -- must make sure these don't collide with y.tab.h */
+#define TESTNZ 300     /* test for non-zero */
+
+#define ISCONSTANT(np, v)      (np->opcode == MESH && np->constant == v)
+
+static void rfree(np)
+/* recursively free the given node and all nodes underneath */
+node   *np;
+{
+    if (np->lval != (node *)NULL)
+       rfree(np->lval);
+    if (np->rval != (node *)NULL)
+       rfree(np->rval);
+    free(np);    
+}
+
+static int requal(mp, np)
+/* do two node trees represent the same expression? */
+node *mp, *np;
+{
+    if (mp == (node *)NULL && np == (node *)NULL)
+       return(TRUE);
+    else if (mp == (node *)NULL || np == (node *)NULL)
+       return(FALSE);
+    else if (mp->opcode != np->opcode || mp->constant != np->constant)
+       return(FALSE);
+    else if (!requal(mp->lval, np->lval) || !requal(mp->lval, np->lval))
+       return(FALSE);
+    else
+       return(TRUE);
+}
+
+static void optimize(np)
+node *np;
+{
+    /* recurse so we simplify each node after all its subnodes */
+    if (np == (node *)NULL)
+       return;
+    else if (np->lval != (node *)NULL)
+       optimize(np->lval);
+    if (np->rval != (node *)NULL)
+       optimize(np->rval);
+
+    /* check for non-zeroness test */
+    if (np->opcode == SELECT && ISCONSTANT(np->rval, 1) && requal(np->lval->rval, np->lval->lval))
+    {
+       rfree(np->rval);
+       np->rval = np->lval->rval;
+       rfree(np->lval->lval);
+       np->lval = (node *)NULL;
+       np->opcode = TESTNZ;
+       np->width = 16;
+    }
+
+    /* fold MINGLE operations on constants */
+    if (np->opcode==MINGLE && (np->lval->opcode==MESH&&np->rval->opcode==MESH))
+    {
+       np->opcode = MESH;
+       np->constant = mingle(np->lval->constant, np->rval->constant);
+       free(np->lval);
+       free(np->rval);
+    }
+
+    /* fold SELECT operations on constants */
+    if (np->opcode == SELECT && (np->lval->opcode==MESH && np->rval->opcode==MESH))
+    {
+       np->opcode = MESH;
+       np->constant = select(np->lval->constant, np->rval->constant);
+       free(np->lval);
+       free(np->rval);
+    }
+
+    /* fold AND operations on constants */
+    if (np->opcode == AND && np->rval->opcode == MESH)
+    {
+       np->opcode = MESH;
+       np->constant = and16(np->lval->constant, np->rval->constant);
+       free(np->rval);
+    }
+
+    /* fold OR operations on constants */
+    if (np->opcode == OR && np->rval->opcode == MESH)
+    {
+       np->opcode = MESH;
+       np->constant = or16(np->lval->constant, np->rval->constant);
+       free(np->rval);
+    }
+
+    /* fold XOR operations on constants */
+    if (np->opcode == AND && np->rval->opcode == MESH)
+    {
+       np->opcode = MESH;
+       np->constant = xor16(np->lval->constant, np->rval->constant);
+       free(np->rval);
+    }
+}
+
+/*************************************************************************
+ *
+ * Code generation
+ *
+ * The theory behind this crock is that we've been handed a pointer to
+ * a tuple representing a single INTERCAL statement, possibly with an
+ * expression tree hanging off it and twisting slowly, slowly in the wind.
+ *
+ * Our mission, should we choose to accept it, is to emit C code which,
+ * when linked to the INTERCAL run-time support, will do something
+ * resembling the right thing.
+ *
+ **************************************************************************/
+
+typedef struct
+{
+    int        value;
+    char *name;
+}
+assoc;
+
+/*
+ * If the order of statement-token defines in ick.y ever changes,
+ * this will need to be resolved.
+ */
+static char *enablers[] =
+{
+    /* GETS      */    "calculating",
+    /* RESIZE    */    "calculating",
+    /* NEXT      */    "nexting",
+    /* FORGET    */    "forgetting",
+    /* RESUME    */    "resuming",
+    /* STASH     */    "stashing",
+    /* RETRIEVE  */    "retrieving",
+    /* IGNORE    */    "ignoring",
+    /* REMEMBER  */    "remembering",
+    /* ABSTAIN   */    "abstaining",
+    /* REINSTATE */    "reinstating",
+    /* DISABLE   */    "abstaining",
+    /* ENABLE    */    "reinstating",
+    /* GIVE_UP   */    "givingup",     /* never used */
+    /* READ_OUT  */    "readingout",
+    /* WRITE_IN  */    "writingin",
+    /* COME_FROM */    "comingfrom",
+};
+
+static assoc vartypes[] =
+{
+    ONESPOT,   "ONESPOT",
+    TWOSPOT,   "TWOSPOT",
+    TAIL,      "TAIL",
+    HYBRID,    "HYBRID",
+    0,         (char *)NULL
+};
+
+static assoc forgetbits[] =
+{
+    ONESPOT,   "oneforget",
+    TWOSPOT,   "twoforget",
+    TAIL,      "tailforget",
+    HYBRID,    "hyforget",
+    0,         (char *)NULL
+};
+
+static assoc varstores[] =
+{
+    ONESPOT,   "onespot",
+    TWOSPOT,   "twospot",
+    TAIL,      "tails",
+    HYBRID,    "hybrids",
+    0,         (char *)NULL
+};
+
+static assoc typedefs[] =
+{
+    ONESPOT,   "short",
+    TWOSPOT,   "int",
+    TAIL,      "unsigned short *",
+    HYBRID,    "unsigned int *",
+    0,         (char *)NULL
+};
+
+static char *nameof(value, table)
+/* return string corresponding to value in table */
+int    value;
+assoc  table[];
+{
+    assoc      *ap;
+
+    for (ap = table; ap->name; ap++)
+       if (ap->value == value)
+           return(ap->name);
+    return((char *)NULL);
+}
+
+static void prvar(np, fp)
+/* print out args to pass to storage manager for reference */
+node   *np;
+FILE   *fp;
+{
+    node       *sp;
+    int                dim;
+
+    switch (np->opcode)
+    {
+    case ONESPOT:
+       (void) fprintf(fp, "onespots[%d]", np->constant);
+       break;
+
+    case TWOSPOT:
+       (void) fprintf(fp, "twospots[%d]", np->constant);
+       break;
+
+    case TAIL:
+       (void) fprintf(fp, "TAIL, %d", np->constant);
+       break;
+
+    case HYBRID:
+       (void) fprintf(fp, "HYBRID, %d", np->constant);
+       break;
+
+    case SUB:
+       dim = 0;
+       for (sp = np->rval; sp; sp = sp->rval)
+           dim++;
+       (void) fprintf(fp, "%s, %d, %d, ",
+                      nameof(np->lval->opcode, vartypes),
+                      np->lval->constant,
+                      dim);
+       for (np = np->rval; np; np = np->rval)
+       {
+           extern void prexpr();
+
+           prexpr(np->lval, fp);
+           (void) fprintf(fp, ", ");
+        }
+       (void) fprintf(" 0");
+       break;
+    }
+}
+
+static void prexpr(np, fp)
+/* print out C-function equivalent of an expression */
+FILE   *fp;
+node   *np;
+{
+    switch (np->opcode)
+    {
+    case MINGLE:
+       (void) fprintf(fp, "mingle(");
+       prexpr(np->lval, fp);
+       (void) fprintf(fp, ", ");
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+    case SELECT:
+       (void) fprintf(fp, "select(");
+       prexpr(np->lval, fp);
+       (void) fprintf(fp, ", ");
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+    case AND:
+       (void) fprintf(fp, "and%d(", np->width);
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+    case OR:
+       (void) fprintf(fp, "or%d(", np->width);
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+    case XOR:
+       (void) fprintf(fp, "or%d(", np->width);
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+    case MESH:
+       (void) fprintf(fp, "0x%x", np->constant);
+       break;
+
+    case ONESPOT:
+    case TWOSPOT:
+       prvar(np, fp);
+       break;
+
+    case SUB:
+       (void) fprintf(fp, "aget(%s");
+       prvar(np, fp);
+       (void) fprintf(fp, ")");
+       break;
+
+       /* cases from here down are generated by the optimizer */
+    case TESTNZ:
+       (void) fprintf(fp, "(");
+       prexpr(np->rval, fp);
+       (void) fprintf(fp, " != 0)");
+       break;
+    }
+
+    (void) free(np);
+}
+
+void emit(tn, fp)
+/* emit code for the given tuple */
+tuple  *tn;
+FILE   *fp;
+{
+    node *np, *sp;
+    int        dim;
+
+    if (yydebug)
+       (void) fprintf(fp, "    /* line %03d: %s */\n",
+                  tn - tuples + 1,
+                  textlines[tn-tuples+1]);
+
+    if (tn->label)
+       (void) fprintf(fp, "L%d:\n", tn->label);
+
+    if (tn->type == COME_FROM)
+    {
+       (void) fprintf(fp, "C%d:\n", tn - tuples + 1);
+       return;
+    }
+
+    /* emit conditional-execution prefixes */
+    if (tn->type == NEXT)
+    {
+       (void) fprintf(fp, "    if (skipto == %d) skipto = 0; else\n", tn-tuples+1);
+       (void) fprintf(fp, "    if (!skipto && ");
+    }
+    else
+       (void) fprintf(fp, "    if (!skipto && ", tn - tuples + 1);
+    if (tn->exechance && tn->exechance < 100)
+       (void) fprintf(fp, "roll(%d) && ", tn->exechance);
+    if (tn->type == GIVE_UP)
+       (void) fprintf(fp, "!abstained[lineno = %d])\n", tn - tuples + 1);
+    else
+       (void) fprintf(fp, "!abstained[lineno = %d] && %s)\n",
+                 tn-tuples + 1, enablers[tn->type-GETS]);
+    (void) fprintf(fp, "    {\n");
+
+    if (tn->comefrom)
+       (void) fprintf(fp,
+              "\tif (!abstained[%d] && comingfrom)\t/* COME FROM */\n\t    goto C%d;\n",
+              tn->comefrom, tn->comefrom);
+
+    /* now emit the code for the statement body */
+    switch(tn->type)
+    {
+    case GETS:
+       np = tn->u.node;
+       (void) fprintf(fp,"\tif (!%s[%d])\n\t    ",
+                      nameof(np->lval->opcode, forgetbits),
+                      np->constant);
+       if (np->opcode == ONESPOT || np->opcode == TWOSPOT)
+       {
+           prvar(np->lval, fp);
+           (void) fprintf(fp, " = ");
+           prexpr(tn->u.node->rval, fp);
+       }
+       else
+       {
+           (void) fprintf("aput(");
+           prexpr(tn->u.node->rval, fp);
+           (void) fprintf(", ");
+           prvar(np->lval, fp);
+           (void) fprintf(fp, ")");
+       }
+       (void) fprintf(fp, ";\n");
+       break;
+
+    case RESIZE:
+       (void) fprintf(fp, "\tresize(");
+       prvar(tn->u.node->lval, fp);
+       dim = 0;
+       for (sp = np->rval; sp; sp = sp->rval)
+           dim++;
+       (void) fprintf(fp, " %d,", dim);
+       for (np = np->rval; np; np = np->rval)
+       {
+           prexpr(np->lval, fp);
+           fprintf(fp, ", ");
+        }
+       (void) fprintf(fp, "0");
+        (void) fprintf(fp, ");\n");
+       break;
+
+    case NEXT:
+       (void) fprintf(fp, "\tpushnext(%d); goto L%d;\n",tn - tuples + 1,tn->u.target);
+       break;
+
+    case RESUME:
+       (void) fprintf(fp, "\tskipto = resume(");
+       prexpr(tn->u.node, fp);
+       (void) fprintf(fp, "); goto top;\n");
+       break;
+
+    case FORGET:
+       (void) fprintf(fp, "\tpopnext(");
+       prexpr(tn->u.node, fp);
+       (void) fprintf(fp, ");\n");
+       break;
+
+    case STASH:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp, "\tstash(%s, %d, %s[%d]);\n",
+                         nameof(np->opcode, vartypes),
+                         np->constant,
+                         nameof(np->opcode, varstores), np->constant);
+       break;
+
+    case RETRIEVE:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp, "\tretrieve(&%s[%d], %s, %d);\n",
+                         nameof(np->opcode, varstores), np->constant,
+                         nameof(np->opcode, vartypes),
+                         np->constant);
+       break;
+
+    case IGNORE:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp,"\t%s[%d] = TRUE;\n",
+                      nameof(np->lval->opcode, forgetbits),
+                      np->constant);
+       break;
+
+    case REMEMBER:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp,"\t%s[%d] = FALSE;\n",
+                      nameof(np->lval->opcode, forgetbits),
+                      np->constant);
+       break;
+
+    case ABSTAIN:
+       (void) fprintf(fp, "\tabstained[%d] = FALSE;\n", tn->u.target);
+       break;
+
+    case REINSTATE:
+       (void) fprintf(fp, "\tabstained[%d] = TRUE;\n", tn->u.target);
+       break;
+
+    case ENABLE:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp, "\t%s = TRUE;\n", enablers[np->constant-GETS]);
+       break;
+
+    case DISABLE:
+       for (np = tn->u.node; np; np = np->rval)
+           (void) fprintf(fp, "\t%s = FALSE;\n", enablers[np->constant-GETS]);
+       break;
+
+    case GIVE_UP:
+       (void) fprintf(fp, "\treturn(0);\n");
+       break;
+
+    case WRITE_IN:
+       for (np = tn->u.node; np; np = np->rval)
+       {
+           np = tn->u.node;
+           (void) fprintf(fp,"\tif (!%s[%d])\n\t    ",
+                          nameof(np->lval->opcode, forgetbits),
+                          np->constant);
+           if (np->opcode == ONESPOT || np->opcode == TWOSPOT)
+           {
+               prvar(np->lval, fp);
+               (void) fprintf(fp, " = pin()");
+           }
+           else
+           {
+               (void) fprintf("aput(pin(), ");
+               prvar(np->lval, fp);
+               (void) fprintf(fp, ")");
+           }
+           (void) fprintf(fp, ";\n");
+       }
+       break;
+
+    case READ_OUT:
+       for (np = tn->u.node; np; np = np->rval)
+       {
+           (void) fprintf(fp, "\tpout(");
+           prexpr(np->lval, fp);
+           (void) fprintf(fp, ");\n");
+       }
+       break;
+
+    case SPLATTERED:
+       (void) fprintf(fp,
+                      "(void) puts(\"%s\");\n", textlines[tn - tuples]);
+       (void) fprintf(fp,
+                      "exit(%d);\n", tn - tuples);
+       break;
+
+    default:
+       lose(tn - tuples + 1, E778);
+       break;
+    }
+
+    (void) fprintf(fp, "    }\n");
+}
+
+/*************************************************************************
+ *
+ * Driver code
+ *
+ **************************************************************************/
+
+void abend()
+{
+    lose(yylineno, E778);
+}
+
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+    extern char        *optarg;        /* set by getopt */
+    extern int optind;         /* set by getopt */
+    char       buf[BUFSIZ], buf2[BUFSIZ];
+    tuple      *tp;
+    atom       *op;
+    int        c;
+
+    while ((c = getopt(argc, argv, "dOC")) != EOF)
+    {
+       switch (c)
+       {
+       case 'd':
+           yydebug = 1;
+           break;
+
+       case 'C':
+           clockface = TRUE;
+           break;
+
+       case 'O':
+           dooptimize = TRUE;
+           break;
+       }
+    }
+
+    (void) signal(SIGSEGV, abend);
+    (void) signal(SIGBUS, abend);
+
+    for (; optind < argc; optind++)
+       if (freopen(argv[optind], "r", stdin) == (FILE *)NULL)
+           lose(0, E777);
+       else
+       {
+           FILE        *ifp, *ofp;
+           int         maxabstain;
+
+           /* zero out tuple and oblist storage */
+           treset();
+
+           /* compile tuples from current input source */
+           yyparse();  
+
+           /* 
+            * Now propagate type information up the expression tree.
+            * We need to do this because the unary-logical operations
+            * are sensitive to the type widths of their operands, so
+            * we have to generate different code depending on the
+            * deducible type of the operand.
+            */
+           for (tp = tuples; tp < tuples + lineno; tp++)
+               if (tp->type == GETS || tp->type == RESIZE)
+                   typecast(tp->u.node);
+
+           codecheck();        /* check for compile-time errors */
+
+           /* perform optimizations */
+           if (dooptimize)
+               for (tp = tuples; tp < tuples + lineno; tp++)
+                   if (tp->type == GETS || tp->type == RESIZE)
+                       optimize(tp->u.node);
+
+           /* strip off the file extension */
+           argv[optind][strlen(argv[optind]) - 2] = '\0';
+
+           /* set up the generated C output file name */
+           (void) strcpy(buf, argv[optind]);
+           (void) strcat(buf, ".c");
+           if ((ofp = fopen(buf, "w")) == (FILE *)NULL)
+               lose(0, E888);
+
+           /* now substitute in tokens in the skeleton */
+           if ((ifp = fopen(SKELETON, "r")) == (FILE *)NULL)
+               lose(0, E999);
+           buf[strlen(buf) - 2] = '\0';
+
+           while ((c = fgetc(ifp)) != EOF)
+               if (c != '$')
+                   (void) fputc(c, ofp);
+               else switch(fgetc(ifp))
+               {
+               case 'A':                       /* source name stem */
+                   (void) fputs(buf, ofp);
+                   break;
+
+               case 'B':                       /* # of source lines */
+                   (void) fprintf(ofp, "%d", lineno);
+                   break;
+
+               case 'C':                       /* initial abstentions */
+                   maxabstain = 0;
+                   for (tp = tuples; tp < tuples + lineno; tp++)
+                       if (tp->exechance == 0 && tp - tuples + 1 > maxabstain)
+                           maxabstain = tp - tuples + 1;
+                   if (maxabstain)
+                   {
+                       (void) fprintf(ofp, " = {");
+                       for (tp = tuples; tp < tuples + maxabstain; tp++)
+                           (void) fprintf(ofp, "%d, ", !tp->exechance);
+                       (void) fprintf(ofp, "}");
+                   }
+                   break;
+
+               case 'D':                       /* extern to intern map */
+                   if (nonespots)
+                   {
+                       (void) fprintf(ofp,
+                                      "static unsigned int onespots[%d];\n",
+                                      nonespots);
+                       (void) fprintf(ofp,
+                                      "static bool oneforget[%d];\n",
+                                      nonespots);
+                   }
+                   if (ntwospots)
+                   {
+                       (void) fprintf(ofp,
+                                      "static unsigned int twospots[%d];\n",
+                                      ntwospots);
+                       (void) fprintf(ofp,
+                                      "static bool twoforget[%d];\n",
+                                      ntwospots);
+                   }
+                   if (ntails)
+                   {
+                       (void) fprintf(ofp,
+                                      "static unsigned int *tails[%d];\n",
+                                      ntails);
+                       (void) fprintf(ofp,
+                                      "static bool tailforget[%d];\n",
+                                      ntails);
+                   }
+                   if (nhybrids)
+                   {
+                       (void) fprintf(ofp,
+                                      "static unsigned int *hybrids[%d];\n",
+                                      nhybrids);
+                       (void) fprintf(ofp,
+                                      "static bool hyforget[%d];\n",
+                                      nhybrids);
+                   }
+                   if (yydebug)
+                       for (op = oblist; op < obdex; op++)
+                           (void) fprintf(ofp, "/* %s %d -> %d */\n",
+                                          nameof(op->type, vartypes),
+                                          op->extindex,
+                                          op->intindex);
+                   break;
+
+               case 'E':
+                   if (clockface)
+                       (void) fprintf(ofp, "clockface(TRUE);");
+                   break;
+
+               case 'F':                       /* degenerated code */
+                   for (tp = tuples; tp < tuples + lineno; tp++)
+                       emit(tp, ofp);
+                   break;
+               }
+
+           (void) fclose(ifp);
+           (void) fclose(ofp);
+
+           /* OK, now sic the C compiler on the results */
+           if (!yydebug)
+           {
+               (void) sprintf(buf2, "cc %s.c -I. -L. -lick -o %s", buf, buf);
+               (void) system(buf2);
+               (void) strcat(buf, ".c");
+               (void) unlink(buf);
+           }
+       }
+}
+
+/* feh.c ends here */
diff --git a/fiddle.c b/fiddle.c
new file mode 100644 (file)
index 0000000..0e51670
--- /dev/null
+++ b/fiddle.c
@@ -0,0 +1,124 @@
+/*
+ * fiddle.c -- functions that implement the five INTERCAL operators
+ *
+ * We link these to the compiler, too, in order to do constant folding
+ */
+
+#define BIT(n, q)      (((q) & (1 << (n))) != 0)
+
+unsigned int mingle(r, s)
+unsigned int r, s;
+{
+    return (
+       (BIT(15, r) << 31) |
+       (BIT(15, s) << 30) |
+       (BIT(14, r) << 29) |
+       (BIT(14, s) << 28) |
+       (BIT(13, r) << 27) |
+       (BIT(13, s) << 26) |
+       (BIT(12, r) << 25) |
+       (BIT(12, s) << 24) |
+       (BIT(11, r) << 23) |
+       (BIT(11, s) << 22) |
+       (BIT(10, r) << 21) |
+       (BIT(10, s) << 20) |
+       (BIT( 9, r) << 19) |
+       (BIT( 9, s) << 18) |
+       (BIT( 8, r) << 17) |
+       (BIT( 8, s) << 16) |
+       (BIT( 7, r) << 15) |
+       (BIT( 7, s) << 14) |
+       (BIT( 6, r) << 13) |
+       (BIT( 6, s) << 12) |
+       (BIT( 5, r) << 11) |
+       (BIT( 5, s) << 10) |
+       (BIT( 4, r) <<  9) |
+       (BIT( 4, s) <<  8) |
+       (BIT( 3, r) <<  7) |
+       (BIT( 3, s) <<  6) |
+       (BIT( 2, r) <<  5) |
+       (BIT( 2, s) <<  4) |
+       (BIT( 1, r) <<  3) |
+       (BIT( 1, s) <<  2) |
+       (BIT( 0, r) <<  1) |
+       (BIT( 0, s) <<  0));
+}
+
+unsigned int select(r, s)
+unsigned int r, s;
+{
+    int        i, n = 0, result = 0;
+
+    for (i = 0; i < 32; i++)
+       if (BIT(i, s))
+           result |= ((1 << n++) & r);
+    return(result);
+}
+
+unsigned int and16(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x8000;
+
+    return(m & n);
+}
+
+unsigned int or16(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x8000;
+
+    return(m | n);
+}
+
+unsigned int xor16(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x8000;
+
+    return(m ^ n);
+}
+
+unsigned int and32(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x80000000;
+
+    return(m & n);
+}
+
+unsigned int or32(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x80000000;
+
+    return(m | n);
+}
+
+unsigned int xor32(n)
+unsigned int n;
+{
+    unsigned int m = (n >> 1);
+
+    if (n & 1)
+       m |= 0x80000000;
+
+    return(m ^ n);
+}
+
+/* fiddle.c */
diff --git a/ick-wrapper.c b/ick-wrapper.c
new file mode 100644 (file)
index 0000000..915eedd
--- /dev/null
@@ -0,0 +1,49 @@
+/* $A.c -- generated C-code file for INTERCAL program $A.i */
+
+#include <cesspool.h>
+
+extern unsigned int interleave(), select();
+extern unsigned int and16(), or16(), xor16(), and32(), or32(), xor32();
+
+int lineno;
+
+static int abstained[$B]$C;
+$D
+
+main()
+{
+    /* declare and initialize gerund variables */
+    int        calculating = TRUE;
+    int        nexting = TRUE;
+    int        forgetting = TRUE;
+    int        resuming = TRUE;
+    int        stashing = TRUE;
+    int        retrieving = TRUE;
+    int        ignoring = TRUE;
+    int        remembering = TRUE;
+    int        abstaining = TRUE;
+    int        reinstating = TRUE;
+    int        readingout = TRUE;
+    int        writingin = TRUE;
+    int comingfrom = TRUE;
+
+    int skipto = 0;
+
+    /* set seed for random error generation */
+#ifdef USG
+    srand48(time((long *)0) + getpid());
+#else
+    srand(time((long *)0));
+#endif /* UNIX */
+
+    /* set up stash storage */
+    stashinit();
+
+    $E
+
+top:
+    /* degenerated code */
+$F
+    lose($B+1,"633 Execution has passed beyond the last statment of the program.");
+}
+
diff --git a/ick.h b/ick.h
new file mode 100644 (file)
index 0000000..09af25b
--- /dev/null
+++ b/ick.h
@@ -0,0 +1,50 @@
+/* ick.h -- compilation types for intercal parser */
+
+typedef int    bool;
+#define TRUE   1
+#define FALSE  0
+
+/*
+ * We choose this value for maximum number of possible source lines on
+ * the theory that no human mind could grok more lines of INTERCAL than
+ * this and still retain any vestige of sanity.
+ */
+#define MAXLINES       1000
+
+/*
+ * Similarly for maximum number of variable stashes
+ */
+#define MAXSTASHES             100
+
+typedef struct node_t
+{
+    int                        opcode;         /* operator or type code */
+    unsigned int       constant;       /* constant data attached */
+    int                        width;          /* is this 32-bit data? */
+    struct node_t      *lval, *rval;   /* attached expression nodes */
+} node;
+
+/* unary-op types -- values for token of type UNARY */
+#define AND    0
+#define OR     1
+#define XOR    2
+
+typedef struct tuple_t
+{
+    unsigned int       label;          /* label # of this statement */
+    unsigned int       comefrom;       /* if NZ, a COME FROM touches this */
+    unsigned int       exechance;      /* chance of execution */
+    unsigned int       type;           /* statement type */
+#define SPLATTERED     -1              /* it's undecodeable */
+    union
+    {
+       unsigned int    target;         /* for NEXT statements */
+       node            *node;          /* attached expression node(s) */
+    } u;
+} tuple;
+
+/* the lexical analyzer keeps copies of the source logical lines */
+extern char *textlines[MAXLINES];
+extern int yylineno;
+
+/* ick.h ends here */
diff --git a/ick.y b/ick.y
new file mode 100644 (file)
index 0000000..9041032
--- /dev/null
+++ b/ick.y
@@ -0,0 +1,273 @@
+/*****************************************************************************
+
+NAME
+    ick.y -- grammar for the INTERCAL language
+
+DESCRIPTION
+   This YACC grammar parses the INTERCAL language by Don R. Woods and
+James M. Lyon.
+
+*****************************************************************************/
+
+%{
+#include <stdio.h>
+#include "ick.h"
+#include "lose.h"
+
+extern node *newnode(), *cons();
+extern tuple *newtuple();
+extern unsigned int intern();
+extern int yylineno;
+
+static node *rlist;    /* pointer to current right-hand node list */
+static node *llist;    /* pointer to current left-hand node list */
+static node *np;       /* variable for building node lists */
+
+#define ACTION(x, nt, nn)      x = newtuple(); x->type = nt; x->u.node = nn
+#define TARGET(x, nt, nn)      x = newtuple(); x->type = nt; x->u.target = nn
+%}
+
+%start program
+
+%union
+{
+    int                numval;         /* a numeric value */
+    tuple      *tuple;         /* a code tuple */
+    node       *node;          /* an expression-tree node */
+}
+
+/*
+ * Don't change this statement token list gratuitously!
+ * Some code in feh.c depends on GETS being the least
+ * statement type and on the order of the ones following.
+ */
+%token GETS RESIZE NEXT FORGET RESUME STASH RETRIEVE IGNORE REMEMBER ABSTAIN
+%token REINSTATE DISABLE ENABLE GIVE_UP READ_OUT WRITE_IN COME_FROM
+
+%token DO PLEASE NOT MESH ONESPOT TWOSPOT TAIL HYBRID
+%token MINGLE SELECT SPARK EARS SUB BY GERUND BADCHAR
+
+%token <numval> NUMBER UNARY OHOHSEVEN GERUND LABEL
+%token <node> INTERSECTION
+
+%token NEWLINE
+
+%type <node> expr varlist outlist variable constant lvalue inlist outlist
+%type <node> subscr byexpr scalar array initem outitem sublist
+%type <tuple> perform
+%type <numval> please
+
+%%     /* beginning of rules section */
+
+/* A program description consists of a sequence of statements */
+program        :    /* EMPTY */
+       |    program statemnt NEWLINE
+       ;
+
+statemnt:    command
+       |    error
+               {splat();}
+       ;
+
+/*
+ * Each command consists of an optional label, followed by a preamble,
+ * followed by the statement body
+ */
+command        :    /* EMPTY */        /* blank line is OK */
+       |    please perform
+               {$2->label = 0; $2->exechance = $1;}
+       |    please OHOHSEVEN perform
+               {$3->label = 0; $3->exechance = $2;}
+       |    LABEL please perform
+               {$3->label = $1; $3->exechance = $2;}
+       |    LABEL please OHOHSEVEN perform
+               {$4->label = $1; $4->exechance = $2;}
+       ;
+
+/* There are several forms of preamble */
+please :    DO                 {$$ = 100;}
+       |    NOT                {$$ = 0;}
+       |    DO NOT             {$$ = 0;}
+       |    PLEASE             {$$ = 100;}
+       |    DO PLEASE          {$$ = 100;}
+       |    PLEASE DO          {$$ = 100;}
+       |    PLEASE NOT         {$$ = 0;}
+       ;
+
+/* Here's how to parse statement bodies */
+perform :    lvalue GETS expr          {ACTION($$, GETS,cons(GETS,$1,$3));}
+       |    array GETS byexpr          {ACTION($$,RESIZE,cons(RESIZE,$1,$3));}
+       |    LABEL NEXT                 {TARGET($$, NEXT,      $1);}
+       |    FORGET expr                {ACTION($$, RESUME,    $2);}
+       |    RESUME expr                {ACTION($$, RESUME,    $2);}
+       |    STASH varlist              {ACTION($$, STASH,     rlist);}
+       |    RETRIEVE varlist           {ACTION($$, RETRIEVE,  rlist);}
+       |    IGNORE varlist             {ACTION($$, IGNORE,    rlist);}
+       |    REMEMBER varlist           {ACTION($$, REMEMBER,  rlist);}
+       |    ABSTAIN LABEL              {TARGET($$, ABSTAIN,   $2);}
+       |    ABSTAIN gerunds            {ACTION($$, DISABLE,   rlist);}
+       |    REINSTATE LABEL            {TARGET($$, REINSTATE, $2);}
+       |    REINSTATE gerunds          {ACTION($$, ENABLE,    rlist);}
+       |    WRITE_IN inlist            {ACTION($$, WRITE_IN,  $2);}
+       |    READ_OUT outlist           {ACTION($$, READ_OUT,  $2);}
+       |    GIVE_UP                    {ACTION($$, GIVE_UP,   0);}
+       |    COME_FROM LABEL            {TARGET($$, COME_FROM, $2);}
+       |    error                      {splat();}
+       ;
+
+/* gerund lists are used by ABSTAIN and REINSTATE */
+gerunds        :   GERUND
+               {rlist = np = newnode(); np->constant = $1;}
+       |   gerunds INTERSECTION GERUND
+               {
+                   np->rval = newnode();
+                   np = np->rval;
+                   np->constant = $3;
+               } 
+       ;
+
+/* OK, here's what a variable reference looks like */
+variable:    scalar | array;
+   
+lvalue :    scalar | subscr;
+
+scalar :    ONESPOT NUMBER
+               {
+                   $$ = newnode();
+                   $$->opcode = ONESPOT;
+                   $$->constant = intern(ONESPOT, $2);
+               }
+       |    TWOSPOT NUMBER
+               {
+                   $$ = newnode();
+                   $$->opcode = TWOSPOT;
+                   $$->constant = intern(TWOSPOT, $2);
+               }
+       ;
+
+array  :    TAIL NUMBER
+               {
+                   $$ = newnode();
+                   $$->opcode = TAIL;
+                   $$->constant = intern(TAIL, $2);
+               }
+       |    HYBRID NUMBER
+               {
+                   $$ = newnode();
+                   $$->opcode = HYBRID;
+                   $$->constant = intern(HYBRID, $2);
+               }
+       ;
+
+/* And a constant looks like this */
+constant:   MESH NUMBER
+               {
+                   /* enforce the 16-bit constant constraint */
+                   if ($2 > 0xffff)
+                       lose(yylineno, E017);
+                   $$ = newnode();
+                   $$->opcode = MESH;
+                   $$->constant = $2;
+               }
+       ;
+
+/* variable lists are used in STASH, RETRIEVE, IGNORE, REMEMBER */
+varlist :   variable                           {rlist = np = $1;}
+       |   varlist INTERSECTION variable       {np = np->rval = newnode();}
+       ;
+
+/* scalars and subscript exprs are permitted in WRITE IN lists */
+initem :    scalar | subscr;
+inlist :    initem INTERSECTION inlist         {$$=cons(INTERSECTION,$1,$3);}
+       |    initem                             {$$=cons(INTERSECTION,$1,0);}
+
+/* scalars, subscript exprs & constants are permitted in READ OUT lists */
+outitem        :    scalar | subscr | constant;
+outlist        :    outitem INTERSECTION outlist       {$$=cons(INTERSECTION,$1,$3);}
+       |    outitem                            {$$=cons(INTERSECTION,$1,0);}
+       ;
+
+/* Now the gnarly part -- expression syntax */
+
+/* Support array subscripts (as lvalues) */
+subscr  :   array SUB sublist          {$$ = cons(SUB, $1, $3);}
+       ;
+sublist :   expr sublist               {$$ = cons(INTERSECTION, $1, $2);}
+       |   expr                        {$$ = cons(INTERSECTION, $1, 0);}
+       ;
+
+/* Support array dimension assignment */
+byexpr :   expr BY byexpr              {$$ = cons(BY, $1, $3);}
+       |   expr                        {$$ = cons(BY, $1, 0);}
+       ;
+
+/* here goes the general expession syntax */
+preftype:    MESH | ONESPOT | TWOSPOT | TAIL | HYBRID;
+
+expr   :   variable    {$$ = $1;}
+       |   constant    {$$ = $1;}
+
+       /* deal with the bizarre unary-op syntax */
+       |    preftype UNARY NUMBER
+               {
+                   $$ = newnode();
+                   $$->opcode = $2;
+                   $$->rval = newnode();
+                   $$->rval->opcode = MESH;
+                   $$->rval->constant = $3;
+               }
+
+       /* Now deal with the screwy unary-op interaction with grouping */
+       |    SPARK UNARY expr SPARK
+               {
+                   $$ = newnode();
+                   $$->opcode = $2;
+                   $$->rval = $3;
+               }
+       |    EARS UNARY expr EARS
+               {
+                   $$ = newnode();
+                   $$->opcode = $2;
+                   $$->rval = $3;
+               }
+
+       |    expr SELECT expr           {$$ = cons(SELECT, $1, $3);}
+       |    expr MINGLE expr           {$$ = cons(MINGLE, $1, $3);}
+       |    SPARK expr SPARK           {$$ = $2;}
+       |    EARS expr EARS             {$$ = $2;}
+       |    subscr                     {$$ = $1;}
+       ;
+
+%%
+
+tuple *splat()
+/* try to recover from an invalid statement. */
+{
+    extern FILE        *yyin;
+    tuple      *sp;
+
+    /* we're going to do our own resynchronization */
+    yyerrok;
+    yyclearin;
+
+    /*
+     * This is called "weird sex with the lexical analyzer". The idea
+     * here is to skip to the next newline, but to do it with our
+     * private getc() in order to save the line's characters.
+     *
+     * With a bit more effort we could implement the full, hideous
+     * semantics of splat, i.e. that another statement identifier
+     * (DO or PLEASE) in the statement takes us back to normal parsing.
+     * But I'm not feeling that twisted just now.
+     */
+#undef getc
+    while (getc(yyin) != '\n')
+       continue;
+    ungetc('\n', yyin);
+
+    /* generate a placeholder tuple for the text line */
+    TARGET(sp, SPLATTERED, 0);
+    return(sp);
+}
+
+/* ick.y ends here */
diff --git a/intercal.man b/intercal.man
new file mode 100644 (file)
index 0000000..88407a0
--- /dev/null
@@ -0,0 +1,1294 @@
+
+
+
+
+
+
+                       THE INTERCAL PROGRAMMING LANGUAGE
+                               REFERENCE MANUAL
+
+
+                       Donald R. Woods & James M. Lyon
+
+               Copyright Donald R. Woods & James M. Lyon  1973
+
+\f
+
+
+
+
+
+                               INTERCAL
+
+1. INTRODUCTION
+
+The names you are about to ignore are true. However, the story has been changed
+significantly. Any resemblance of the programming language portrayed here
+to other programming languages, living or dead, is purely coincidental.
+
+1.1 ORIGIN AND PURPOSE
+
+The INTERCAL programming language was designed the morning of May 26, 1972
+by Donald R. Woods and James M. Lyon, at Princeton University. Exactly when
+in the morning will become apparent in the course of this manual. It was 
+inspired by one ambition; to have a compiler language which has nothing at 
+all in common with any other major language. By 'major' was meant anything
+with which the authors were at all familiar, e.g., FORTRAN, BASIC, COBOL,
+ALGOL, SNOBOL, SPITBOL, FOCAL, SOLVE, TEACH, APL, LISP, and PI/I. For the
+most part, INTERCAL has remained true to this goal, sharing only the basic
+elements such as variables, arrays, and the ability to do I/O, and eschewing 
+all conventional operations other than the assignment statement (FORTRAN
+"=").
+
+1.2 ACRONYM
+
+The full name of the compiler is "Compiler Language With No Pronounceable
+Acronym", which is, for obvious reasons, abbreviated "INTERCAL".
+
+1.3 ACKNOWLEDGMENTS
+
+The authors are deeply indebted to Eric M. Van and Daniel J. Warmenhoven,
+without whose unwitting assistance this manual would still have been
+possible.
+
+
+\f
+
+
+
+
+
+2. FUNDAMENTAL CONCEPTS
+
+In this section an attempt is made to describe how and why INTERCAL may be
+used; i.e., what it is like and what it is good for.
+
+2.1 SAMPLE PROGRAM
+
+Shown below is a relatively simple INTERCAL program which will read in 32-bit
+unsigned integers, treat them as signed, 2's-complement numbers, and print out 
+their absolute values. The program exits if the absolute value is zero. Note
+in particular the inversion routine (statements 6 through 14), which could
+be greatly simplified if the subroutine library (see section 5) were used.
+
+A more detailed analysis of a program is made in section 6 of this manual.
+
+       DO (5) NEXT
+    (5) DO FORGET #1
+       PLEASE WRITE IN :1
+       DO .1 <- 'V":1~'#32768$#0'"$#1'~#3
+       DO (1) NEXT
+       DO :1 <- "'V":1~'#65535$#0'"$#65535'
+               ~'#0$#65535'"$"'V":1~'#0$#65535'"
+               $#65535'~'#0$#65535'"
+       DO :2 <- #1
+       PLEASE DO (4) NEXT
+    (4) DO FORGET #1
+       DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535
+               $#0'"'~'#0$#65535'"$"'V":1~'#0
+               $#65535'"$":2~'#65535$#0'"'~'#0$#65535'"
+       DO (1) NEXT
+       DO :2 <- ":2~'#0$#65535'"
+               $"'":2~'#65535$#0'"$#0'~'#32767$#1'"
+       DO (4) NEXT
+    (2) DO RESUME .1
+    (1) PLEASE DO (2) NEXT
+       PLEASE FORGET #1
+       DO READ OUT :1
+       PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3
+       DO (3) NEXT
+       PLEASE DO (5) NEXT
+    (3) DO (2) NEXT
+       PLEASE GIVE UP
+
+2.2 USES FOR INTERCAL
+
+INTERCAL's main advantage over other programming languages is its strict
+simplicity. It has few capabilities, and thus there are few restrictions to
+be kept in mind. Since it is an exceedingly easy language to learn, one
+might expect it would be a good language for initiating novice programmers.
+Perhaps surprising, than, is the fact that it would be more likely to
+initiate a novice into a search for another line of work. As it turns out,
+INTERCAL is more useful (which isn't saying much) as a challenge to
+professional programmers.  Those who doubt this need only refer back to the
+sample program in section 2.1. This 23-statement program took somewhere
+from 15 to 30 minutes to write, whereas the same objectives can be achieved
+by single-statement programs in either SNOBOL;
+
+       PLEASE INPUT POS(0) ('-' ! '')
+       + (SPAN('0123456789') $ OUTPUT)
+       + *NE(OUTPUT) :S(PLEASE)F(END)
+
+or APL;
+
+       [1] >\b-0=\b/?<\b-?
+
+Admittedly, neither of these is likely to appear more intelligible to
+anyone unfamiliar with the languages involved, but they took roughly 60
+seconds and 15 seconds, respectively, to write. Such is the overwhelming
+power of INTERCAL!
+
+The other major importance of INTERCAL lies in its seemingly inexhaustible
+capacity for amazing one's fellow programmers, confounding programming shop
+managers, winning friends, and influencing people. It is a well-known and
+oft-demonstrated fact that a person whose work is incomprehensible is held
+in high esteem. For example, if one were to state that the simplest way to
+store a value of 65535 in a 32-bit INTERCAL variable is:
+
+       DO :1 <- #0?#256
+
+any sensible programmer would say that that was absurd. Since this is
+indeed the simplest method, the programmer would be made to look foolish in
+front of his boss, who would of course happened to turn up, as bosses are
+wont to do. The effect would be no less devastating for the programmer
+having been correct.
+
+\f
+
+
+
+
+
+3. DESCRIPTION
+
+The examples of INTERCAL programming which have appeared in the preceding
+sections of this manual have probably seemed highly esoteric to the reader
+unfamiliar with the language. With the aim of making them more so, we
+present here a description of INTERCAL.
+
+
+3.1 VARIABLES
+
+INTERCAL allows only 2 different types of variables, the 16-bit integer
+and the 32-bit integer. These are represented by a spot (.) or two-spot
+(:), respectively, followed by any number between 1 and 65535, inclusive.
+These variables may contain only non-negative numbers; thus they have the
+respective ranges of values: 0 to 65535 and 0 to 4294967295. Note: .123 and
+:123 are two distinct variables. On the other hand, .1 and .0001 are
+identical.  Furthermore, the latter may NOT be written as 1E-3.
+
+3.2 CONSTANTS
+
+Constants are 16-bit values only and may range from 0 to 65535. They are
+prefixed by a mesh (#). Caution! Under no circumstances confuse the mesh
+with the interleave operator, except under confusing circumstances!
+
+3.3 ARRAYS
+
+Arrays are represented by a tail (,) for 16-bit values, or a hybrid (;) for
+32-bit values, followed by a number between 1 and 65535, inclusive. The
+number is suffixed by the word SUB, followed by the subscripts, separated
+optionally by spaces. Subscripts may be any expressions, including those
+involving subscripted variables. This occasionally leads to ambiguous
+constructions, which are resolved as discussed in section 3.4.3.  Definition
+of array dimensions will be discussed later in greater detail, since
+discussing it in less detail would be difficult. As before, ,123 and ;123
+are distinct.  In summary, .123, :123, #123, ,123, and :123 are all
+distinct.
+
+3.4 OPERATORS
+
+INTERCAL recognizes 5 operators--2 binary and 3 unary. Please be kind to 
+our operators: they may not be very intelligent, but they're all we've got.
+In a sense, all 5 operators are binary, as they are all bit-oriented, but
+it is not our purpose here to quibble about bits of trivia.
+
+
+\f
+******* proofread versus the paper copy only this far !!!! ************
+
+
+
+
+3.4.1 BINARY OPERATORS
+
+The binary operators are INTERLEAVE (also called MINGLE) and SELECT, which
+are represented by a change (c\b/) and a sqiggle [sic] (~), respectively.
+
+The interleave operator takes two 16-bit values and produces a 32-bit result
+by alternating the bits of the operands. Thus, #65535c\b/#0 has the 32-bit
+binary form 101010....10 or 2863311530 decimal, while #0c\b/#65535 = 
+0101....01 binary = 1431655765 decimal, and #255c\b/#255 is equivalent to
+#65535.
+
+The select operator takes from the first operand whichever bits correspond
+to 1's in the second operand, and packs these bits as the right in the result.
+Both operands are automatically padded on the left with zeros to 32 bits
+before the selection takes place, so the variable types are unrestricted.
+If more than 16 bits are selected, the result is a 32-bit value, otherwise
+it is a 16-bit value. For example, #179~#201 (binary value 10110011~11001001)
+selects from the first argument the 8th, 7th, 4th, and 1st from last bits,
+namely, 1001, which = 9. But #201~#179 selects from binary 11001001 the 8th,
+6th, 5th, 2nd, and 1st from last bits, giving 10001 = 17. #179~#179 has the
+value 31, while #201~#201 has the value 15.
+
+Perhaps a simpler way of understanding the operation of the select operator
+would be to examine the logic diagram on the following page (Figure 1), which
+performs the select operation upon two 8-bit values, A and B. The gates used
+are Warmenhovian logic gates, which means the outputs have four possible
+values: low, high, undefined (value of an uninitialized flip-flop), and
+oscillating (output of a NOR gate with one input low and the other input
+connected to the output). These values are represented symbolically by '0',
+'1', '2', and 'F'. Note in particular that, while NOT-0 is 1 and NOT-2 
+is 0 as in two-valued logic, NOT-? is ? and NOT-F is F. The functions 
+of the various gates are listed on Table 1.
+
+\f
+
+
+
+
+
+3.4.2 UNARY OPERATORS
+
+The unary operators are & (logical AND), V (logical OR), and V\b- (logical
+XOR). This last character is obtained by overpunching a worm (-) on a V
+(V).  The operator is inserted between the spot, two-spot, mesh, or
+what-have-you, and the integer, thus: .&123, #V123. Multiple unary
+operators may not be concatenated, thus the form #V&123 is invalid. This
+will be covered later when precedence is discussed. These operators perform
+their respective logical operations on all pairs of adjacent bits, the
+result from the first and last bits going into the first bit of the result.
+The effect is that of rotating the operand one place to the right and
+ANDing, ORing, or XORing with its initial value. Thus, #&77 (binary =
+1001101) is binary 0000000000000100 = 4, #V77 is binary 1000000001101111 =
+32879, and #V77 is binary 1000000001101011 = 32875.
+
+3.4.3 PRECEDENCE
+
+Precedence of operators is as follows:
+
+
+
+
+
+
+
+
+
+
+
+                                                            [1]
+(The remainder of this page intentionally left blank)
+
+
+
+
+
+
+
+
+
+
+
+
+
+_________________
+1) Keep in mind that the aim in designing INTERCAL was to have no 
+   precedents.
+
+\f
+
+
+
+
+
+This precedence (or lack thereof) may be overruled by grouping expressions
+between pairs of sparks (') or rabbit-ears ("). Thus '#165c\b/#203'~#358 
+(binary value '10100101c11001011'~101100110) has the value 15, but
+#165c\b/'#203~#358' has the value 34815, and #165c\b/#203~#358 is invalid
+syntax and is completely valueless (except perhaps as an educational tool
+to the programmer). A unary operator is applied to a sparked or rabbit-eared
+expression by inserting the operator immediately following the opening spark
+or ears. Thus, the invalid expression #V&123, which was described earlier,
+could be coded as 'V#&123' or 'V"&#123"'. Note: In the interests of 
+simplifying the sometimes overly-complex form of expressions, INTERCAL allows
+a spark-spot combination ('.) to be replaced with a wow (!). Thus '.1~.2'
+is equivalent to !1~.2', and 'V.1c.2' is equivalent to "V!1c.2'".
+
+Combining a rabbit-ears with a spot to form a rabbit (V) is not permitted,
+although the programmer is free to use it should he find an EBCDIC reader
+which will properly translate a 12-3-7-8 punch.
+
+Sparks and/or rabbit-ears must also be used to distinguish among such
+otherwise ambiguous subscripted and multiply-subscripted expressions as:
+
+       ,1 SUB #1 ~ #2
+       ,1 SUB ,2 SUB #1 #2 #3
+       ,1 SUB " ,2 SUB " ,3 SUB #1 " #2 " " #3 "
+
+The third case may be isolated into either of its possible interpretations
+by simply changing some pairs of rabbit-ears to sparks, instead of adding
+more ears (which would only confuse the issue further). Ambiguous cases are
+defined as those for which the compiler being used finds a legitimate
+interpretation which is different from that which the user had in mind. See
+also section 8.1.
+
+
+
+
+
+
+4. STATEMENTS
+
+In this section is described the format of INTERCAL statements.
+
+4.1 GENERAL FORMAT
+
+Statements may be entered in 'free format'. That is, more than one statement
+may occur on a single card, and a statement may begin on one card and end
+on a later one. Note that if this is done, all intervening cards and portions
+thereof must be part of the same statement. That this restriction is necessary
+is immediately apparent from the following example of what might occur if
+statements could be interlaced.
+
+       DO .1 <- ".1c\b/'&:51~"#V1c!12~;&75SUB"V'V.1~
+       DO .2 <- '"!1c\b/"&';V79SUB",&7SUB:173"'~!V9c
+       .2'c,&1SUB:5~#33578"'"'"~'#65535c\b/"V'V#&85'"'
+       #8196'"'~.1"c.2'~'#&5c\b/"'#1279c\b/#4351'~#65535"'
+
+The above statements are obviously meaningless. (For that matter, so are
+the statements
+
+       DO .1 <- ".1c\b/"&:51~"#V1C\b!12~;&75SUB"V'V.1~
+       .2'C,&1SUB:5~/333578"'"'"~#65535c\b/"V'V#&85'"'
+       DO .2 <- '"!1c\b/"&';V79SUB",&7SUB:173"'~!V9c
+       #8196'"'~.1"c.2'~'#&5c\b/"'#1279c!4351'~#65535"'
+
+but this is not of interest here.)
+
+Spaces may be used freely to enhance program legibility (or at least reduce
+program illegibility), with the restriction that no word of a statement
+identifier (see section 4.3) may contain any spaces.
+
+4.2 LABELS
+
+A statement may begin with a LOGICAL LINE LABEL enclosed in wax-wane pairs
+(()). A statement may not have more than one label, although it is possible
+to omit the label entirely. A line label is any integer from 1 to 65535,
+which must be unique within each program. The user is cautioned, however,
+that many line labels between 1000 and 1999 are used in the INTERCAL System
+Library functions.
+
+4.3 IDENTIFIERS AND QUALIFIERS
+
+After the line label (if any), must follow one of the following statement
+identifiers: DO, PLEASE, or PLEASE DO. These may be used interchangeably to
+improve the aesthetics of the program. The identifier is then followed by
+either, neither, or both of the following optional parameters (qualifiers):
+(1) either of the character strings NOT or N'T, which causes the statement
+to be automatically abstained from (see section 4.4.9) when execution
+begins, and (2) a number between 0 and 100, preceded by a double-oh-seven
+(%), which causes the statement to have only the specified percent chance
+of being executed each time it is encountered in the course of execution.
+
+\f
+
+
+
+
+
+4.4 STATEMENTS
+
+Following the qualifiers (or, if none are used, the identifier) must occur
+one of the 13 valid operations. (Exception: see section 4.5.) These are 
+described individually in sections 4.4.1 through 4.4.13.
+
+4.4.1 CALCULATE
+
+The INTERCAL equivalent of the half-mesh (=) in FORTRAN, BASIC, PL/I, and
+others, is represented by an angle (<) followed by a worm (-). This
+combination is read 'gets'. 32-bit variables may be assigned 16-bit values,
+which are padded on the left with 16 zero bits. 16-bit variables may be
+assigned 32-bit values only if the value is less than 65535. Thus, to
+invert the least significant bit of the first element of 16-bit
+2-dimensional array number 1, one could write:
+
+       ,1SUB#1#1 <- 'V,1SUB#1#1c\b/#1'~'#0c\b/#65535'
+
+Similarly to SNOBOL and SPITBOL, INTERCAL uses the angle-worm to define the
+dimensions of arrays. An example will probably best describe the format. 
+To define 32-bit array number 7 as 3-dimensional, the first dimension being
+seven, the second being the current value of 16-bit variable number seven,
+and the third being the current value of the seventh element of 16-bit array
+number seven (which is one-dimensional) mingled with the last three bits of
+32-bit variable number seven, one would write (just before they came to take
+him away):
+
+       ;7 <- #7 BY .7 BY ",7SUB#7"c\b/':7~#7'
+
+This is, of course, different from the statement:
+
+       ;7 <- #7 BY .7 BY ,7SUB"#7c\b/':7~#7'"
+
+INTERCAL also permits the redefining of array dimensioning, which is done 
+the same way as is the initial dimensioning. All values of items in an array
+are lost upon redimensioning, unless they have been STASHed (see section
+4.4.5), in which case restoring them also restores the old dimensions.
+
+\f
+
+
+
+
+
+4.4.2 NEXT
+
+The NEXT statement is used both for subroutine calls and for unconditional
+transfers. This statement takes the form:
+
+       DO (label) NEXT
+
+(or, of course,
+
+       PLEASE DO (label) NEXT
+
+etc.), where (label) represents any logical line label which appears in the
+program. The effect of such a statement is to transfer control to the
+statement specified, and to store in a push down list (which is initially
+empty) the location from which the transfer takes place. Items may be
+removed from this list and may be discarded or used to return to the
+statement immediately following the NEXT statement. These operations are
+described in sections 4.4.3 and 4.4.4 respectively. The programmer is
+generally advised to discard any stack entries which he does not intend to
+utilize, since the stack has a maximum depth of 79 entries. A program's
+attempting to initiate an 80th level of NEXTing will result on the fatal
+error message, "PROGRAM HAS DISAPPEARED INTO THE BLACK LAGOON."
+
+4.4.3 FORGET
+
+The statement PLEASE FORGET exp, where exp represents any expression
+(except colloquial and facial expressions), causes the expression to be
+evaluated, and the specified number of entries to be removed from the
+NEXTing stack and discarded. An attempt to FORGET more levels of NEXTing
+than are currently stacked will cause the stack to be emptied, and no error
+condition is indicated. This is because the condition is not considered to
+be an error. As described in section 4.4.2, it is good programming practice
+to execute a DO FORGET #1 after using a NEXT statement as an unconditional
+transfer, so that the stack does not get cluttered up with unused entries:
+
+       DO (123) NEXT
+       .
+       .
+  (123) DO FORGET #1
+
+4.4.4 RESUME
+
+The statement PLEASE RESUME exp has the same effect as FORGET, except that
+program control is returned to the statement immediately following the NEXT
+statement which stored in the stack the last entry to be removed. Note that
+a rough equivalent of the FORTRAN computed GO TO and BASIC ON exp GO TO is
+performed by a sequence of the form:
+
+       DO (1) NEXT
+       .
+       .
+    (1) DO (2) NEXT
+       PLEASE FORGET #1
+       .
+       .
+    (2) DO RESUME .1
+
+Unlike the FORGET statement, an attempt to RESUME more levels of NEXTing than
+been stacked will cause program termination. See also section 4.4.11.
+
+
+4.4.5 STASH
+
+Since subroutines are not explicitly implemented in INTERCAL, the NEXT and
+RESUME statements must be used to execute common routines. However, as
+these routines might use the same variables as the main program, it is
+necessary for them to save the values of any variables whose values they
+alter, and later restore them. This process is simplified by the STASH
+state ment, which has the form DO STASH list, where list represents a
+string of one or more variable or array names, separated by intersections
+(+). Thus
+
+       PLEASE STASH .123+:123+,123
+
+stashes the values of two variables and one entire array. The values are
+left intact, and copies thereof are saved for later retrieval by (what else?)
+the RETRIEVE statement (see section 4.4.6). It is not possible to STASH
+single array items.
+
+4.4.6 RETRIEVE
+
+PLEASE RETRIEVE list restores the previously STASHed values of the variables
+and arrays named in the list. If a value has been stashed more than once,
+the most recently STASHed values are RETRIEVEd, and a second RETRIEVE will
+restore the second most recent values STASHed. Attempting to RETRIEVE a
+value which has not been STASHed will result in the error message, "THROW
+STICK BEFORE RETRIEVING."
+
+4.4.7 IGNORE
+
+The statement DO IGNORE list causes all subsequent statements to have no 
+effect upon variables and/or arrays named in the list. Thus, for example, 
+after the sequence
+
+       DO .1 <- #1
+       PLEASE IGNORE .1
+       DO .1 <- #0
+
+16-bit variable number 1 would have the value 1, not 0. Inputting (see
+section 4.4.12) into an IGNOREd variable also has no effect. The condition
+is annulled via the REMEMBER statement (see section 4.4.8). Note that, when
+a variable is being IGNOREd, its value, though immutable, is still
+available for use in expressions and the like.
+
+4.4.8 REMEMBER
+
+PLEASE REMEMBER list terminates the effect of the IGNORE statement for all
+variables and/or arrays named in the list. It does not matter if a variable
+has been IGNOREd more than once, nor is it an error if the variable has not
+been IGNOREd at all.
+
+4.4.9 ABSTAIN
+
+INTERCAL contains no simple equivalent to an IF statement or computed GO
+TO, making it difficult to combine similar sections of code into a single
+routine which occasionally skips around certain statements. The IGNORE
+statement (see section 4.4.7) is helpful in some cases, but a more viable
+method is often required. In keeping with the goal of INTERCAL having
+nothing in common with any other language, this is made possible via the
+ABSTAIN statement.
+
+This statement takes on one of two forms. It may not take on both at any one
+time. DO ABSTAIN FROM (label) causes the statement whose logical line label
+is (label) to be abstained form. PLEASE ABSTAIN FROM gerund list causes all
+statements of the specified type(s) to be abstained from, as in
+
+       PLEASE ABSTAIN FROM STASHING
+       PLEASE ABSTAIN FROM IGNORING + FORGETTING
+       PLEASE ABSTAIN FROM NEXTING
+     or PLEASE ABSTAIN FROM CALCULATING
+
+Statements may also be automatically abstained from at the start of
+execution via the NOT or N'T parameter (see section 4.3).
+
+
+If, in the course of execution, a statement is encountered which is being
+abstained from, it is ignored and control passes to the next statement in
+the program (unless it, too, is being abstained from).
+
+The statement DO ABSTAIN FROM ABSTAINING is perfectly valid, as is DO ABSTAIN
+FROM REINSTATING (although this latter is not usually recommended). However,
+the statement DO ABSTAIN FROM GIVING UP is not accepted, even though DON'T
+GIVE UP is.
+
+4.4.10 REINSTATE
+
+The REINSTATE statement, like the ABSTAIN, takes as an argument either a 
+line label or a gerund list. No other form of argument is permitted. For
+example, the following is an invalid argument:
+
+       Given: x=\b/0, y=\b/0,  Prove: x+y=0
+       Since x=\b/0, then x+1=\b/1, x+a=\b/a, x+y=\b/y.
+       Thus x+y =\b/ anything but 0.
+       Since x+y cannot equal anything but 0, x+y=0.
+
+                                                                   Q.E.D.
+
+REINSTATEment nullifies the effects of an abstention. Either form of
+REINSTATEment can be used to "free" a statement, regardless of whether the
+statement was abstained from by gerund list, line label, or NOT. Thus,
+PLEASE REINSTATE REINSTATING is not necessarily an irrelevant statement,
+since it might free a DON'T REINSTATE command or a REINSTATE the line label
+of which was abstained from. However, DO REINSTATE GIVING UP is invalid,
+and attempting to REINSTATE a GIVE UP statement by line label will have no
+effect. Note that this insures that DON'T GIVE UP will always be a
+"do-nothing" statement.
+
+4.4.11 GIVE UP
+
+PLEASE GIVE UP is used to exit from a program. It has the effect of a PLEASE
+RESUME #80. DON'T GIVE UP, as noted in section 4.4.10, is effectively a null
+statement.
+
+4.4.12 Input
+
+Input is accomplished with the statement DO WRITE IN list, where list
+represents a string of variables and/or elements or arrays, separated by
+intersections. Numbers are represented on cards, each number on a separate
+card, by spelling out each digit (in English) and separating the digits
+with one or more spaces. A zero (0) may be spelled as either ZERO or OH.
+Thus the range of (32-bit) input values permissible extends from ZERO (or
+OH) through FOUR TWO NINE FOUR NINE SIX SEVEN TWO NINE FIVE.
+
+Attempting to write in a value greater than or equal to SIX FIVE FIVE THREE
+SIX for a 16-bit variable will result in the error message, "DON'T BYTE OFF
+MORE THAN YOU CAN CHEW."
+
+4.4.13 Output
+
+Values may be output to the printer, one value per line, via the statement
+DO READ OUT list, where the list contains variables, array elements, and/or
+constants.  Output is in the form of "extended" Roman numerals (also called
+                                               _
+"butchered" Roman numerals), with an overline ( ) indicating the value below
+is "times 1000", and lower-case letters indicating "times 1000000". Zero
+is indicated by an overline with no character underneath. Thus, the range 
+                                           _         __      _______
+of (32-bit) output values possible is from   through ivccxcivCMLXVIICCXCV.
+Note: For values whose residues modulo 1000000 are less than 4000, M is
+used to represent 1000; for values whose residues are 4000 or greater, I is
+                                                                       __
+used. Thus #3999 would read out as MMMIM while #4000 would read out as IV.
+                                  _                                   _     _
+Similar rules apply to the use of M and i for 1000000, and to that of m and i
+for 1000000000.
+
+\f
+
+
+
+
+
+4.5 Comments
+
+Unrecognizable statements, as noted in section 7, are flagged with a splat
+(*) during compilation, and are not considered fatal errors unless they
+are encountered during execution, at which time the statement (as input at 
+compilation time) is printed and execution is terminated. This allows for 
+an interesting (and, by necessity, unique) means of including comments in 
+an INTERCAL listing. For example, the statement:
+
+*      PLEASE NOTE THAT THIS LINE HAS NO EFFECT
+
+will be ignored during execution due to the inclusion of the NOT qualifier.
+User-supplied error messages are also easy to implement:
+
+*      DO SOMETHING ABOUT OVERFLOW IN ;3
+
+as are certain simple conditional errors:
+
+* (123)        DON'T YOU REALIZE THIS STATEMENT SHOULD ONLY BE ENCOUNTERED
+               ONCE?
+       PLEASE REINSTATE (123)
+
+This pair of statements will cause an error exit the second time they are
+encountered. Caution!! The appearance of a statement identifier in an
+intended comment will be taken as the beginning of a new statement. Thus,
+the first example on the preceding page could not have been:
+
+*      PLEASE NOTE THAT THIS LINE DOES NOTHING
+
+The third example, however, is valid, despite the appearance of two cases 
+of D-space-O, since INTERCAL does not ignore extraneous spaces in statement
+identifiers.
+\f
+
+
+
+
+
+5. SUBROUTINE LIBRARY
+
+INTERCAL provides several built-in subroutines to which control can be
+transferred to perform various operations. These operations include many
+useful functions which are not easily representable in INTERCAL, such as
+addition, subtraction, etc.
+
+5.1 Usage
+
+In general, the operands are .1, .2, etc., or :1, :2, etc., and the result(s)
+are stored in what would have been the next operand(s). For instance, one
+routine adds .1 to .2 and store the sum in .3, with .4 being used to indicate
+overflow. All variables not used for results are left unchanged.
+
+5.2 Available Functions
+
+At the time of this writing, only the most fundamental operations are offered
+in the library, as a more complete selection would require prohibitive time
+and coree to implement. These functions, along with their corresponding entry
+points (entered via DO (entry) NEXT) are listed below.
+
+ (1000)        .3 <- .1 plus .2, error exit on overflow
+ (1009)        .3 <- .1 plus .2
+       .4 <- #1 if no overflow, else .4 <- #2
+ (1010)        .3 <- .1 minus .2, no action on overflow
+ (1020)        .1 <- .1 plus #1, no action on overflow
+ (1030)        .3 <- .1 times .2, error exit on overflow
+ (1039)        .3 <- .1 times .2
+       .4 <- #1 if no overflow, else .4 <- #2
+ (1040)        .3 <- .1 divided by .2
+       .3 <- #0 if .2 is #0
+ (1050) .2 <- :1 divided by .1, error exit on overflow
+       .2 <- #0 if .1 is #0
+
+ (1500) :3 <- :1 plus :2, error exit on overflow
+ (1509) :3 <- :1 plus :2
+       :4 <- #1 if no overflow, else :4 <- #2
+ (1510) :3 <- :1 minus :2, no action on overflow
+ (1520) :1 <- .1 concatenated with .2
+ (1525) This subroutine is intended solely for internal
+       use within the subroutine library and is therefore
+       not described here. Its effect is to shift .3
+       logically 8 bits to the left.
+ (1530) :1 <- .1 times .2
+ (1540)        :3 <- :1 times :2, error exit on overflow
+ (1549)        :3 <- :1 times :2
+       :4 <- #1 if no overflow, else :4 <- #2
+ (1550)        :3 <- :1 divided by :2
+       :3 <- #0 if :2 is #0
+
+ (1900)        .1 <- uniform random no. from #1 to #65535
+ (1910) .2 <- normal random no. from #0 to .1, with
+             standard deviation .1 divided by #12
+
+\f
+
+
+
+
+
+6. PROGRAMMING HINTS
+
+For the user looking to become more familiar with the INTERCAL language, we
+present in this section an analysis of a complex program, as well as some
+suggested projects for the ambitious programmer.
+
+Considering the effort involved in writing an INTERCAL program, it was 
+decided in putting together this manual to use an already existing program 
+for instructive analysis. Since there was only one such program available,
+we have proceeded to use it. It is known as the "INTERCAL System Library."
+
+6.1 Description
+
+The program listing begins on the second page following. It is in the same
+format as would be produced by the Princeton INTERCAL compiler in FORMAT
+mode with WDITH=62 (see section 8). For a description of the functions
+performed by the Library, see section 5.2.
+
+6.2 Analysis
+
+We shall not attempt to discuss here the algorithms used, but rather we
+shall point out some of the general techniques applicable to a wide range
+of problems.
+
+Statements 10, 14, 15, and 26 make up a virtual "computed GO TO". When
+statement 10 is executed, control passes eventually to statement 16 or 11,
+depending on whether .5 contains #1 or #2, respectively. The value of .5
+is determined in statement 9, which demonstrates another handy technique.
+To turn an expression, exp, with value #0 or #1, into #1 or #2 (for use in
+a "GO TO"), use "V'exp'c\b/#1"~#3. To reverse the condition (i.e., convert #0
+to #2 and leave #1 alone) use "V'exp'c\b/#2"~#3.
+
+Certain conditions are easily checked. For example, to test for zero,
+select the value from itself and select the bottom bit (see statement 54).
+To test for all bits being 1's, select the value from itself and select the
+top bit (see statement 261). The test to greater than, performed in
+statements 192 and 193 on 32-bit values, employs binary logical operations,
+which are performed as follows:
+
+       'V.1c.2'~'#0c\b/#65535'
+
+for 16-bit values or, for 32-bit values:
+
+       "'V":1~'#65535c30'"c\b/":2~'#65535c\b/#0'"'~'#0
+       c\b/#65535'"c\b/"'V":1~'#0c\b/#65535'"c\b/":2~'#0
+       c\b/#65535'"'~'#0c\b/#65535'"
+
+(The proofs are left as an exercise to the reader.)
+
+Testing for greater-than with 16-bit values is somewhat simpler and is done
+with the pair of statements:
+
+       DO .C <- 'V.Ac.B'~'#0c\b/#65535'
+       DO .C <- '&"'.A~.C'~'"V'V.C~.C'c\b/#32768"
+               ~"#0c\b/#65535"'"c\b/".C~.CZ''ZZZ`#1
+
+This sets .C (a dummy variable) to #1 if .A > .B, and #0 otherwise. The
+expression may be expanded as described above to instead set .C to #1 or
+#2.
+
+Note also in statement 220 the occurrence of ~"#65535c65535". Although
+these operations select the entire value, they are not extraneous, as they
+ensure that the forthcoming Vs will be operating on 32-bit values.
+
+In several virtual computed GO TOs the DO FORGET #1 (statement 15 in the
+earlier example) has been omitted, since the next transfer of control would
+be a DO RESUME #1.  By making this a DO RESUME #2 instead, the FORGET may
+be forgotten.
+
+In statement 64, note that .2 is STASHed twice by a single statement. This
+is perfectly legal.
+
+Lastly, note in statements 243 and 214 respectively, expressions for
+shifting 16- and 32-bit variables logically one place to the left.
+Statement 231 demonstrates right-shifting for 32-bit variables.
+
+MIKE GETS TO INSERT THE PROGRAM HERE!
+\f
+6.3 Program Listing
+
+    1  (1000)  PLEASE IGNORE .4
+    2          PLEASE ABSTAIN FROM (1005)
+    3  (1009)  DO STASH .1 + .2 + .5 + .6
+    4          DO .4 <- #1
+    5          DO (1004) NEXT
+    6  (1004)  PLEASE FORGET #1
+    7          DO .3 <- 'V.1c.2'~'#0c\b/#65535'
+    8          DO .6 <- '&.1c.2'~'#0c\b/#65535'
+    9          PLEASE DO .5 <- "V!6~#32768'c\b/#1"~#3
+   10          DO (1002) NEXT
+   11          DO .4 <- #2
+   12  (1005)  DO (1006) NEXT
+*  13  (1999)  DOUBLE OR SINGLE PRECISION OVERFLOW
+   14  (1002)  DO (1001) NEXT
+   15  (1006)  PLEASE FORGET #1
+   16          DO .5 <- 'V"!6~.6'~#1"c\b/#1'~#3
+   17          DO (1003) NEXT
+   18          DO .1 <- .3
+   19          DO .2 <- !6c\b/#0'~'#32767c\b/#1'
+   20          DO (1004) NEXT
+   21  (1003)  DO (1001) NEXT
+   22          DO REINSTATE (1005)
+   23  (1007)  PLEASE RETRIEVE .1 + .2 + .5 + .6
+   24          DO REMEMBER .4
+   25          PLEASE RESUME #2
+   26  (1001)  DO RESUME .5
+   27  (1010)  DO STASH .1 + .2 + .4
+   28          DO .4 <- .1
+   29          DO .1 <- 'V.2c\b/#65535'~'#0c\b/#65535'
+   30          DO (1020) NEXT
+   31          PLEASE DO .2 <- .4
+   32          PLEASE DO (1009) NEXT
+   33          DO RETRIEVE .1 + .2 + .4
+   34          PLEASE RESUME #1
+   35  (1020)  DO STASH .2 + .3
+   36          DO .2 <- #1
+   37          PLEASE DO (1021) NEXT
+   38  (1021)  DO FORGET #1
+   39          DO .3 <- "V!1~.2'c\b/#1"~#3
+   40          PLEASE DO .1 <- 'V.1c.2'~'#0c\b/#65535'
+   41          DO (1022) NEXT
+   42          DO .2 <- !2c\b/#0'~'#32767c\b/#1'
+   43          DO (1021) NEXT
+   44  (1023)  PLEASE RESUME .3
+   45  (1022)  DO (1023) NEXT
+   46          PLEASE RETRIEVE .2 + .3
+   47          PLEASE RESUME #2
+   48  (1030)  DO ABSTAIN FROM (1033)
+   49          PLEASE ABSTAIN FROM (1032)
+   50  (1039)  DO STASH :1 + .5
+   51          DO (1530) NEXT
+   52          DO .3 <- :1~#65535
+   53          PLEASE DO .5 <- :1~'#65280c\b/#65280'
+   54          DO .5 <- 'V"!5~.5'~#1"c\b/#1'~#3
+   55          DO (1031) NEXT
+   56  (1032)  DO (1033) NEXT
+   57          DO (1999) NEXT
+   58  (1031)  DO (1001) NEXT
+   59  (1033)  DO .4 <- .5
+   60          DO REINSTATE (1032)
+   61          PLEASE REINSTATE (1033)
+   62          DO RETRIEVE :1 + .5
+   63          PLEASE RESUME #2
+   64  (1040)  PLEASE STASH .1 + .2 + .2 + :1 + :2 + :3
+   65          DO .2 <- #0
+   66          DO (1520) NEXT
+   67          DO STASH :1
+   68          PLEASE RETRIEVE .2
+   69          DO .1 <- .2
+   70          DO .2 <- #0
+   71          PLEASE DO (1520) NEXT
+   72          DO :2 <- :1
+   73          DO RETRIEVE .1 + .2 + :1
+   74          DO (1550) NEXT
+   75          PLEASE DO .3 <- :3
+   76          DO RETRIEVE :1 + :2 + :3
+   77          DO RESUME #1
+   78  (1050)  PLEASE STASH :2 + :3 + .5
+   79          DO :2 <- .1
+   80          PLEASE DO (1550) NEXT
+   81          DO .5 <- :3~'#65280c\b/#65280'
+   82          DO .5 <- 'V"!5~.5'~#1"c\b/#1'~#3
+   83          DO (1051) NEXT
+   84          DO (1999) NEXT
+   85  (1051)  DO (1001) NEXT
+   86          DO .2 <- :3
+   87          PLEASE RETRIEVE :2 + :3 + .5
+   88          DO RESUME #2
+   89  (1500)  PLEASE ABSTAIN FROM (1502)
+   90          PLEASE ABSTAIN FROM (1506)
+   91  (1509)  PLEASE STASH :1 + .1 + .2 + .3 + .4 + .5 + .6
+   92          DO .1 <- :1~#65535
+   93          PLEASE DO .2 <- :2~#65535
+   94          DO (1009) NEXT
+   95          DO .5 <- .3
+   96          PLEASE DO .6 <- .4
+   97          DO .1 <- :1~'#65280c\b/#65280'
+   98          DO .2 <- :2~'#65280c\b/#65280'
+   99          DO (1009) NEXT
+  100          DO .1 <- .3
+  101          PLEASE DO (1503) NEXT
+  102          DO .6 <- .4
+  103          DO .2 <- #1
+  104          DO (1009) NEXT
+  105          DO .1 <- .3
+  106          DO (1501) NEXT
+  107  (1504)  PLEASE RESUME .6
+  108  (1503)  DO (1504) NEXT
+  109  (1501)  DO .2 <- .5
+  110          DO .5 <- 'V"'&.6c.4'~#1"c\b/#2'~#3
+  111          DO (1505) NEXT
+  112  (1506)  DO (1502) NEXT
+  113          PLEASE DO (1999) NEXT
+  114  (1505)  DO (1001) NEXT
+  115  (1502)  DO :4 <- .5
+  116          DO (1520) NEXT
+  117          DO :3 <- :1
+  118          PLEASE RETRIEVE :1 + .1 + .2 + .3 + .4 + .5 + .6
+  119          DO REINSTATE (1502)
+  120          DO REINSTATE (1506)
+  121          PLEASE RESUME #3
+  122  (1510)  DO STASH :1 + :2 + :4
+  123          DO :1 <- "'V\b/":2~'#65535c\b/#0'"c\b/#65535'~'#0c\b/#6553
+           5'"c\b/"'V":2~'#0c\b/#65535'"c\b/#65535'~'#0c65535
+           '"
+  124          DO :2 <- #1
+  125          DO (1509) NEXT
+  126          PLEASE RETRIEVE :1
+  127          DO :2 <- :3
+  128          PLEASE DO (1509) NEXT
+  129          DO RETRIEVE :2 + :4
+  130          PLEASE RESUME #1
+  131  (1520)  PLEASE STASH .3 + .4
+  132          DO .3 <- .1~#43690
+  133          DO (1525) NEXT
+  134          PLEASE DO .4 <- 'V.3c\b/".2~#43690"'~'#0c\b/#65535'
+  135          DO .3 <- .1~#21845
+  136          PLEASE DO (1525) NEXT
+  137          DO :1 <- .4c\b/"'V.3c\b/".2~#21845"'~'#0c\b/#65535'"
+  138          PLEASE RETRIEVE .3 + .4
+  139          DO RESUME #1
+  140  (1525)  DO .3 <- '"'"'"!3c\b/#0'~'#32767c\b/#1'"c\b/#0'~'#32767
+           c\b/#1'"c\b/#0'~'#16383c\b/#3'"c\b/#0'~'#4095c\b/#15'
+  141          PLEASE RESUME #1
+  142  (1530)  DO STASH :2 + :3 + .3 + .5
+  143          DO :1 <- #0
+  144          DO :2 <- .2
+  145          DO .3 <- #1
+  146          DO (1535) NEXT
+  147  (1535)  PLEASE FORGET #1
+  148          DO .5 <- "V!1~.3'c\b/#1"~#3
+  149          DO (1531) NEXT
+  150          DO (1500) NEXT
+  151          DO :1 <- :3
+  152          PLEASE DO (1533) NEXT
+  153  (1531)  PLEASE DO (1001) NEXT
+  154  (1533)  DO FORGET #1
+  155          DO .3 <- !3c\b/#0'~'#32767c\b/#1'
+  156          DO :2 <- ":2~'#0c\b/#65535'"c\b/"'":2~'#32767c\b/#0'"c\b/#
+           0'~'#32767c\b/#1'"
+  157          PLEASE DO .5 <- "V!3~.3'c\b/#1"~#3
+  158          DO (1532) NEXT
+  159          DO (1535) NEXT
+  160  (1532)  DO (1001) NEXT
+  161          PLEASE RETRIEVE :2 + :3 + .3 + .5
+  162          DO RESUME #2
+  163  (1540)  PLEASE ABSTAIN FROM (1541)
+  164          DO ABSTAIN FROM (1542)
+  165  (1549)  PLEASE STASH :1 + :2 + :4 + :5 + .1 + .2 + .5
+  166          DO .1 <- :1~#65535
+  167          PLEASE DO .2 <- :2~'#65280c\b/#65280'
+  168          DO .5 <- :1~'#65280c\b/#65280'
+  169          DO (1530) NEXT
+  170          DO :3 <- :1
+  171          DO .2 <- :2~#65535
+  172          PLEASE DO (1530) NEXT
+  173          DO :5 <- :1
+  174          DO .1 <- .5
+  175          DO (1530) NEXT
+  176          DO :4 <- :1
+  177          PLEASE DO :1 <- ":3~'#65280c\b/#65280'"c\b/":5~'652
+           80c\b/#65280'"
+  178          DO .5 <- ':1~:1'~#1
+  179          DO .2 <- :2~'#65280c\b/#65280'
+  180          DO (1530) NEXT
+  181          PLEASE DO .5 <- '"':1~:1'~#1"c.5'~#3
+  182          DO .1 <- :3~#65535
+  183          DO .2 <- #0
+  184          DO (1520) NEXT
+  185          PLEASE DO :2 <- :1
+  186          PLEASE DO .1 <- :4~#65535
+  187          DO (1520) NEXT
+  188          DO (1509) NEXT
+  189          DO .5 <- !5c\b/":4~#3"'~#15
+  190          DO :1 <- :3
+  191          DO :2 <- :5
+  192          DO (1509) NEXT
+  193          PLEASE DO .5 <- !5c\b/"4~#3"'~#63
+  194          DO .5 <- 'V"!5~.5'~#1"c\b/#1'~#3
+  195          PLEASE RETRIEVE :4
+  196  (1541)  DO :4 <- .5
+  197          DO (1543) NEXT
+  198  (1542)  DO (1544) NEXT
+  199          PLEASE DO (1999) NEXT
+  200  (1543)  DO (1001) NEXT
+  201  (1544)  DO REINSTATE (1541)
+  202          PLEASE REINSTATE (1542)
+  203          PLEASE RETRIEVE :1 + :2 + :5 + .1 + .2 + .5
+  204          DO RESUME #2
+  205  (1550)  DO STASH :1 + :4 + :5 + .5
+  206          DO :3 <- #0
+  207          DO .5 <- 'V"':2~:2'~#1"c\b/#1'~#3
+  208          PLEASE DO (1551) NEXT
+\f
+
+
+
+
+
+6.4 Programming Suggestions
+
+For the novice INTERCAL programmer, we provide here a list of suggested 
+INTERCAL programming projects:
+
+Write an integer exponentiation subroutine.  :1 <- .1 raised to the .2 power.
+
+Write a double-precision sorting subroutine. Given 32-bit array ;1 of size
+:1, sort the contents into numerically increasing order, leaving the results
+in ;1.
+
+Generate a table of prime numbers.
+
+Put together a floating-point library, using 32-bit variables to represent
+floating-point numbers (let the upper half be the mantissa and the lower
+half be the characteristic).  The library should be capable of performing 
+floating-point addition, subtraction, multiplication, and division, as well
+as the natural logarithm function.
+
+Program a Fast Fourier Transform (FFT).  This project would probably entail
+the writing of the floating-point library as well as sine and cosine functions.
+
+Calculate, to :1 places, the value of pi.
+
+\f
+
+
+
+
+
+7. ERROR MESSAGES
+
+Due to INTERCAL's implementation of comment lines (see section 4.5), most
+error messages are produced during execution instead of during compilation.
+All errors except those not causing immediate termination of program execution
+are treated as fatal.
+
+7.1 Format
+
+All error messages appear in the following form:
+
+       ICLnnnI (error message)
+               ON THE WAY TO STATEMENT nnnn
+               CORRECT SOURCE AND RESUBMIT
+
+The message varies depending upon the error involved.  For undecodable
+statements the message is the statement itself.  The second line tells
+which statement would have been executed next had the error not occurred.
+Note that if the error is due to 80 attempted levels of NEXTing, the
+statement which would have been executed next need not be anywhere near the
+statement causing the error.
+
+7.2 Messages
+
+Brief descriptions of the different error types are listed below according
+to message number.
+
+    000 An undecodable statement has been encountered in the course of
+       execution. Note that keypunching errors can be slightly disastrous,
+       since if 'FORGET' were misspelled F-O-R-G-E-R, the results would 
+       probably not be those desired. Extreme misspellings may have even 
+       more surprising consequences. For example, misspelling 'FORGET' 
+       R-E-S-U-M-E could have drastic results.
+
+    017 An expression contains a syntax error.
+
+    079 Improper use has been made of statement identifiers.
+
+    099 Improper use has been made of statement identifiers.
+
+    123 Program has attempted 80 levels of NEXTing.
+
+    129 Program has attempted to transfer to a non-existent line label.
+
+    139 An ABSTAIN or REINSTATE statement references a non-existent line label.
+
+    182 A line label has been multiply defined.
+
+    197 An invalid line label has been encountered.
+
+    200 An expression involves an unidentified variable.
+
+    240 An attempt has been made to give an array a dimension of zero.
+
+    241 Invalid dimensioning information was supplied in defining or using
+       an array.
+
+    275 A 32-bit value has been assigned to a 16-bit variable.
+
+    436 A retrieval has been attempted for an unSTASHed value.
+
+    533 A WRITE IN statement or interleave (c) operation has produced a
+       value requiring over 32 bits to represent.
+
+    562 Insufficient data.
+
+    579 Input data is invalid.
+
+    621 The expression of a RESUME statement evaluated to #0.
+
+    632 Program execution was terminated via a RESUME statement instead of
+       GIVE UP.
+
+    633 Execution has passed beyond the last statement of the program.
+
+    774 A compiler error has occurred (see section 8.1).
+
+    778 An unexplainable compiler error has occurred (see J. Lyon or B. Woods).
+
+\f
+
+
+
+
+                               [3]
+                       TONSIL A
+
+
+
+The Official INTERCAL Character Set
+
+Tabulated on page XX are all the characters used in INTERCAL, excepting
+letters and digits, along with their names and interpretations. Also
+included are several characters not used in INTERCAL, which are presented
+for completeness and to allow for future expansion.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+_____________________
+3) Since all other reference manuals have Appendices, it was decided that
+the INTERCAL manual should contain some other type of removable organ.
+
+4) This footnote intentionally unreferenced.
+
+
+
+
+
+
+_______________________________________________________________________
+|                                                                     |
+|Character     Name                    Use (if any)                  |
+|                                                                     |
+|    .         spot                    identify 16-bit variable      |
+|    :                 two-spot                identify 32-bit variable      |
+|    ,         tail                    identify 16-bit array         |
+|    ;         hybrid                  identify 32-bit array         |
+|    #         mesh                    identify constant             |
+|    =         half-mesh                                             |
+|    '         spark                   grouper                       |
+|    `         backspark                                             |
+|    !         wow                     equivalent to spark-spot      |
+|    ?                 what                    unary exlusive OR (ATARI only)|
+|    "         rabbit-ears             grouper                       |
+|    !`                rabbit                  equivalent to ears-spot       |
+|    |         spike                                                 |
+|    %         double-oh-seven         percentage qualifier          |
+|    -         worm                    used with angles              |
+|    <         angle                   used with worms               |
+|    >         right angle                                           |
+|    (         wax                     precedes line label           |
+|    )         wane                    follows line label            |
+|    [         U turn                                                |
+|    ]         U turn back                                           |
+|    {         embrace                                               |
+|    }         bracelet                                              |
+|    *         splat                   flags invalid statements      |
+|    &         ampersand[5]            unary logical AND             |
+|    V         V                       unary logical OR              |
+|              (or book)                                             |
+|    V\b-               bookworm                unary exclusive OR            |
+|              (or universal qualifier)                              |
+|    $         big money                                             |
+|    c\b|               change                  binary mingle                 |
+|    ~         sqiggle                 binary select                 |
+|    _         flat worm                                             |
+|              overline                indicates "times 1000"        |
+|    +         intersection            separates list items          |
+|    /         slat                                                  |
+|    \         backslat                                              |
+|    @         whirlpool                                             |
+|    -\b'               hookworm                                              |
+|    ^         shark                                                 |
+|              (or simply sharkfin)                                  |
+|    #\bI\b[\b]           blotch                                                |
+|_____________________________________________________________________|
+
+
+               Table 2 (top view). INTERCAL character set.
+
+__________________________________
+
+5) Got any better ideas?
+
+\f
+NOTES ON THE ATARI IMPLEMENTATION
+
+The Atari implementation of INTERCAL differs from the original Princeton
+version primarily in the use of ASCII rather than EBCDIC. Since there is no
+"change" sign (c) in ASCII, we have substituted the "big money" ($) as the
+mingle operator. We feel that this correctly represents the increasing cost
+of software in relation to hardware. (Consider that in 1970 one could get
+RUNOFF for free, to run on a $20K machine, whereas today a not quite as
+powerful formatter costs $99 and runs on a $75 machine.)  We also feel that
+there should be no defensible contention that INTERCAL has any sense.
+Also, since overpunches are difficult to read on the average VDT, the
+exclusive-or operator may be written ?.  This correctly expresses the
+average person's reaction on first encountering exclusive-or, especially on
+a PDP-11.  Note that in both of these cases, the over-punched symbol may
+also be used if one is masochistic, or concerned with portability to the
+Princeton compiler.  The correct over-punch for "change" is "c<backspace>/"
+and the correct over-punch for V is "V<backspace>-".  These codes will be
+properly printed if you have a proper printer, and the corresponding EBCDIC
+code will be produced by the /IBM option on the LIST command.
+
diff --git a/intercal.sty b/intercal.sty
new file mode 100644 (file)
index 0000000..7f1a036
--- /dev/null
@@ -0,0 +1,137 @@
+% -*- Mode: TeX -*- 
+% for LaTeX
+
+% This is the file ick.sty:  macros for typesetting the INTERCAL Manual.
+
+\setlength{\textwidth}{6.5in}
+\setlength{\oddsidemargin}{0in}
+\setlength{\evensidemargin}{0in}
+\setlength{\textheight}{9in}
+\setlength{\topmargin}{0in}
+\setlength{\headsep}{0in}
+\setlength{\headheight}{0in}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SPECIAL INTERCAL CHARACTERS
+%
+
+% Save ``regular'' characters.
+\def\backslat{\backslash}
+\def\embrace{\verb|{|}
+\def\bracelet{\verb|}|}
+\def\doubleohseven{\%}
+\def\ampersand{\&}
+\def\sqiggle{\~{}}
+\def\bigmoney{\$}
+\def\shark{\verb|^|}
+\def\flatworm{\verb|_|}
+\def\mesh{\#}
+\def\spot{.}
+\def\what{?}
+
+% \newcommand{\mathify}[1]{\ifmmode{#1}\else\mbox{$#1$}\fi}
+% \def\bookworm{\mathify{\forall}}
+\def\bookworm{\rlap V-}
+\def\change{\rlap c/}
+%\def\altchange{\rlap /c}
+\def\zero{\={}}
+\def\spike{\verb+|+}
+\def\althookworm{-\llap '}
+\def\hookworm{'\llap -}
+\def\blotch{\#\llap I\llap [\llap ]}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INTERCAL CODE ENVIRONMENT
+%
+
+% Just surround the code with vertical bars.
+
+
+\catcode`|=\active  %  The `|' is active from now on.
+\def|{\ifmmode\vert%
+        \else\bgroup\tt\usespecials\def|{\null\egroup}%
+        \fi}
+
+% To get backslat, embrace, or bracelet in a | | environment, use the
+% respective macros.
+% I might want to translate $ and ? as in the verbatim macros.
+\def\activatespecials{%
+  \catcode`\%=\active
+  \catcode`\&=\active
+  \catcode`\~=\active
+  \catcode`\$=\active
+  \catcode`\^=\active
+  \catcode`\_=\active
+  \catcode`\#=\active}
+
+{% Add new comment character
+ \catcode`+=14
+ \activatespecials
+ \gdef\usespecials{+
+  \activatespecials
+  \def%{\doubleohseven}+
+  \def&{\ampersand}+
+  \def~{\sqiggle}+
+  \def${\bigmoney}+
+  \def^{\shark}+
+  \def_{\flatworm}+
+  \def#{\mesh}}}
+
+% Typeset a one-line INTERCAL example.  This is pretty gross.
+\def\IConeline#1{\vspace\topsep\par\noindent{\tt\ \ \ \ \ \ \ \ }#1\vspace\topsep}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERBATIM FILE LISTING
+%
+
+% --- The macros are based on those distributed with Sunil Podar's
+% --- `EPIC.STY' macro package, attributed to Tim Morgan,
+% --- modified to keep internal macros internal by Adrian F. Clark,
+% --- alien@uk.ac.essex.ese
+% --- ---and further latexification by Chris Rowley,
+% --- ca_rowley@uk.ac.open.acs.vax.
+% And finally, modified for INTERCAL by Michael Ernst.
+
+\def\verbatimfile#1{\begingroup
+                    \@verbatim \frenchspacing \@vobeyspaces
+                    \input#1 \endgroup
+}
+
+\newcounter{lineno}
+
+\newif\ifcontinuationchar
+% Say \continuationchartrue if the ends of continued program lines are
+% flagged by slash-newline.
+% This implementation doesn't allow backslashes elsewhere; it would be
+% better to make \, clobbered by \@verbatim, the escape character again,
+% and then define a whole wad of escape sequences, with \^^M being one.
+
+\newif\ifnonumber
+
+\def\activateverbspecials{%
+  \catcode`$=\active
+  \catcode`?=\active}
+
+{\activateverbspecials
+ \catcode`|=0
+ \catcode`\\=\active
+ |gdef|useverbspecials{%
+  |def\{|nonumbertrue}%
+  |def${|change}%
+  |def?{|bookworm}%
+  |activateverbspecials}}
+
+\def\ICverbatimlisting#1{\setcounter{lineno}{0}%
+    \begingroup \@verbatim \frenchspacing \@vobeyspaces \parindent=20pt
+    \everypar{\ifnonumber\nonumberfalse
+               \else\stepcounter{lineno}%
+                     \llap{{\footnotesize\rm\thelineno\ \ \ }}%
+               \fi}%
+    \ifcontinuationchar\catcode`\\=\active\fi
+    \useverbspecials
+    \input#1
+    \endgroup
+}
+
diff --git a/intercal.tex b/intercal.tex
new file mode 100644 (file)
index 0000000..31eb276
--- /dev/null
@@ -0,0 +1,1074 @@
+% -*- Mode: TeX -*- 
+% for LaTeX
+\documentstyle[ick]{article}
+
+\title{                 The INTERCAL Programming Language \\
+                                Reference Manual}
+\author{                        Donald R. Woods \& James M. Lyon}
+\date{                Copyright Donald R. Woods \& James M. Lyon 1973}
+
+\begin{document}
+
+\maketitle
+\thispagestyle{empty}
+\newpage
+
+\tableofcontents
+\thispagestyle{empty}
+\newpage
+\setcounter{page}{1}
+
+\section{Introduction}
+
+The names you are about to ignore are true.  However, the story has been
+changed significantly.  Any resemblance of the programming language
+portrayed here to other programming languages, living or dead, is purely
+coincidental.
+
+\subsection{Origin and Purpose}
+
+The INTERCAL programming language was designed the morning of May 26, 1972
+by Donald R. Woods and James M. Lyon, at Princeton University.  Exactly
+when in the morning will become apparent in the course of this manual.  It
+was inspired by one ambition; to have a compiler language which has nothing
+at all in common with any other major language.  By 'major' was meant
+anything with which the authors were at all familiar, e.g., FORTRAN, BASIC,
+COBOL, ALGOL, SNOBOL, SPITBOL, FOCAL, SOLVE, TEACH, APL, LISP, and PI/I.
+For the most part, INTERCAL has remained true to this goal, sharing only
+the basic elements such as variables, arrays, and the ability to do I/O,
+and eschewing all conventional operations other than the assignment
+statement (FORTRAN ``|=|'').
+
+\subsection{Acronym}
+
+The full name of the compiler is ``Compiler Language With No Pronounceable
+Acronym'', which is, for obvious reasons, abbreviated ``INTERCAL''.
+
+\subsection{Acknowledgments}
+
+The authors are deeply indebted to Eric M. Van and Daniel J. Warmenhoven,
+without whose unwitting assistance this manual would still have been
+possible.
+
+
+\f
+
+
+
+
+
+\section{Fundamental Concepts}
+
+In this section an attempt is made to describe how and why INTERCAL may be
+used; i.e., what it is like and what it is good for.
+
+\subsection{Sample Program}
+
+Shown below is a relatively simple INTERCAL program which will read in
+32-bit unsigned integers, treat them as signed, 2's-complement numbers, and
+print out their absolute values.  The program exits if the absolute value
+is zero.  Note in particular the inversion routine (statements 6 through
+14), which could be greatly simplified if the subroutine library (see
+section 5) were used.
+
+A more detailed analysis of a program is made in section 6 of this manual.
+
+\continuationchartrue % sample.i uses the continuation character convention
+\ICverbatimlisting{sample.i}
+
+
+\subsection{Uses For INTERCAL}
+
+INTERCAL's main advantage over other programming languages is its strict
+simplicity.  It has few capabilities, and thus there are few restrictions
+to be kept in mind.  Since it is an exceedingly easy language to learn, one
+might expect it would be a good language for initiating novice programmers.
+Perhaps surprising, than, is the fact that it would be more likely to
+initiate a novice into a search for another line of work.  As it turns out,
+INTERCAL is more useful (which isn't saying much) as a challenge to
+professional programmers.  Those who doubt this need only refer back to the
+sample program in section 2.1.  This 23-statement program took somewhere
+from 15 to 30 minutes to write, whereas the same objectives can be achieved
+by single-statement programs in either SNOBOL;
+
+\begin{verbatim}
+        PLEASE INPUT POS(0) ('-' ! '')
+        + (SPAN('0123456789') $ OUTPUT)
+        + *NE(OUTPUT) :S(PLEASE)F(END)
+\end{verbatim}
+\noindent or APL;
+
+\IConeline{|[1] >\llap -0=\llap /?<\llap -?|}
+
+Admittedly, neither of these is likely to appear more intelligible to
+anyone unfamiliar with the languages involved, but they took roughly 60
+seconds and 15 seconds, respectively, to write.  Such is the overwhelming
+power of INTERCAL!
+
+The other major importance of INTERCAL lies in its seemingly inexhaustible
+capacity for amazing one's fellow programmers, confounding programming shop
+managers, winning friends, and influencing people.  It is a well-known and
+oft-demonstrated fact that a person whose work is incomprehensible is held
+in high esteem.  For example, if one were to state that the simplest way to
+store a value of 65535 in a 32-bit INTERCAL variable is:
+
+\begin{verbatim}
+        DO :1 <- #0?#256
+\end{verbatim}
+any sensible programmer would say that that was absurd.  Since this is
+indeed the simplest method, the programmer would be made to look foolish in
+front of his boss, who would of course happened to turn up, as bosses are
+wont to do.  The effect would be no less devastating for the programmer
+having been correct.
+
+\f
+
+
+
+
+
+\section{Description}
+
+The examples of INTERCAL programming which have appeared in the preceding
+sections of this manual have probably seemed highly esoteric to the reader
+unfamiliar with the language.  With the aim of making them more so, we
+present here a description of INTERCAL.
+
+
+\subsection{Variables}
+
+INTERCAL allows only 2 different types of variables, the 16-bit integer
+and the 32-bit integer.  These are represented by a spot (|.|) or two-spot
+(|:|), respectively, followed by any number between 1 and 65535, inclusive.
+These variables may contain only non-negative numbers; thus they have the
+respective ranges of values: 0 to 65535 and 0 to 4294967295.  Note: |.123|
+and |:123| are two distinct variables.  On the other hand, |.1| and |.0001|
+are identical.  Furthermore, the latter may NOT be written as |1E-3|.
+
+\subsection{Constants}
+
+Constants are 16-bit values only and may range from 0 to 65535.  They are
+prefixed by a mesh (|#|).  Caution! Under no circumstances confuse the mesh
+with the interleave operator, except under confusing circumstances!
+
+\subsection{Arrays}
+
+Arrays are represented by a tail (|,|) for 16-bit values, or a hybrid (|;|)
+for 32-bit values, followed by a number between 1 and 65535, inclusive.
+The number is suffixed by the word |SUB|, followed by the subscripts,
+separated optionally by spaces.  Subscripts may be any expressions,
+including those involving subscripted variables.  This occasionally leads
+to ambiguous constructions, which are resolved as discussed in section
+3.4.3.  Definition of array dimensions will be discussed later in greater
+detail, since discussing it in less detail would be difficult.  As before,
+|,123| and |;123| are distinct.  In summary, |.123|, |:123|, |#123|,
+|,123|, and |:123| are all distinct.
+
+\subsection{Operators}
+
+INTERCAL recognizes 5 operators---2 binary and 3 unary.  Please be kind to
+our operators: they may not be very intelligent, but they're all we've got.
+In a sense, all 5 operators are binary, as they are all bit-oriented, but
+it is not our purpose here to quibble about bits of trivia.
+
+
+\f
+% ******* proofread versus the paper copy only this far !!!! ************
+
+
+
+
+\subsubsection{Binary Operators}
+
+The binary operators are INTERLEAVE (also called MINGLE) and SELECT, which
+are represented by a change (|\change|) and a sqiggle (|~|), respectively.
+
+The interleave operator takes two 16-bit values and produces a 32-bit
+result by alternating the bits of the operands.  Thus, |#65535c#0| has the
+32-bit binary form 101010....10 or 2863311530 decimal, while |#0c#65535| =
+0101....01 binary = 1431655765 decimal, and |#255c#255| is equivalent to
+|#65535|.
+
+The select operator takes from the first operand whichever bits correspond
+to 1's in the second operand, and packs these bits as the right in the
+result.  Both operands are automatically padded on the left with zeros to
+32 bits before the selection takes place, so the variable types are
+unrestricted.  If more than 16 bits are selected, the result is a 32-bit
+value, otherwise it is a 16-bit value.  For example, |#179~#201| (binary
+value 10110011|~|11001001) selects from the first argument the 8th, 7th,
+4th, and 1st from last bits, namely, 1001, which = 9.  But |#201~#179|
+selects from binary 11001001 the 8th, 6th, 5th, 2nd, and 1st from last
+bits, giving 10001 = 17.  |#179~#179| has the value 31, while |#201~#201|
+has the value 15.
+
+Perhaps a simpler way of understanding the operation of the select operator
+would be to examine the logic diagram on the following page (Figure 1),
+which performs the select operation upon two 8-bit values, A and B.  The
+gates used are Warmenhovian logic gates, which means the outputs have four
+possible values: low, high, undefined (value of an uninitialized
+flip-flop), and oscillating (output of a NOR gate with one input low and
+the other input connected to the output).  These values are represented
+symbolically by '|0|', '|1|', '{\tt ?}', and '|F|'.  Note in particular that,
+while NOT-|0| is |1| and NOT-|1| is |0| as in two-valued logic, NOT-{\tt ?} is
+{\tt ?} and NOT-|F| is |F|.  The functions of the various gates are listed in
+Table 1.
+\stepcounter{table}
+
+
+\f
+
+
+
+
+
+\subsubsection{Unary Operators}
+
+The unary operators are |&| (logical AND), |V| (logical OR), and
+|\bookworm| (logical XOR).  This last character is obtained by overpunching
+a worm (|-|) on a V (|V|).  The operator is inserted between the spot,
+two-spot, mesh, or what-have-you, and the integer, thus: |.&123|, |#V123|.
+Multiple unary operators may not be concatenated, thus the form |#V&123| is
+invalid.  This will be covered later when precedence is discussed. These
+operators perform their respective logical operations on all pairs of
+adjacent bits, the result from the first and last bits going into the first
+bit of the result.  The effect is that of rotating the operand one place to
+the right and ANDing, ORing, or XORing with its initial value.  Thus,
+|#&77| (binary = 1001101) is binary 0000000000000100 = 4, |#V77| is binary
+1000000001101111 = 32879, and |#V77| is binary 1000000001101011 = 32875.
+\typeout{typo here}
+
+\subsubsection{Precedence}
+
+Precedence of operators is as follows:
+
+
+\vspace{2 in}
+\hspace{4 in}
+\footnote{Keep in mind that the aim in designing INTERCAL was to have no
+precedents.}
+\stepcounter{footnote}
+\vspace{1 in}
+
+(The remainder of this page intentionally left blank.)
+
+\newpage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\f
+
+
+
+
+
+This precedence (or lack thereof) may be overruled by grouping expressions
+between pairs of sparks (|'|) or rabbit-ears (|"|).  Thus
+|'#165c#203'~#358| (binary value |'|10100101|c|11001011|'~|101100110) has
+the value 15, but |#165c'#203~#358'| has the value 34815, and
+|#165c#203~#358| is invalid syntax and is completely valueless (except
+perhaps as an educational tool to the programmer).  A unary operator is
+applied to a sparked or rabbit-eared expression by inserting the operator
+immediately following the opening spark or ears.  Thus, the invalid
+expression |#V&123|, which was described earlier, could be coded as
+|'V#&123'| or |'V"&#123"'|.  Note: In the interests of simplifying the
+sometimes overly-complex form of expressions, INTERCAL allows a spark-spot
+combination (|'.|) to be replaced with a wow (|!|).  Thus |'.1~.2'| is
+equivalent to |!1~.2'|, and |'V.1c.2'| is equivalent to |"V!1c.2'"|.
+
+Combining a rabbit-ears with a spot to form a rabbit (|V|\typeout{Rabbit?})
+is not permitted, although the programmer is free to use it should he find
+an EBCDIC reader which will properly translate a 12-3-7-8 punch.
+
+Sparks and/or rabbit-ears must also be used to distinguish among such
+otherwise ambiguous subscripted and multiply-subscripted expressions as:
+
+\begin{verbatim} 
+        ,1 SUB #1 ~ #2
+        ,1 SUB ,2 SUB #1 #2 #3
+        ,1 SUB " ,2 SUB " ,3 SUB #1 " #2 " " #3 "
+\end{verbatim}
+
+The third case may be isolated into either of its possible interpretations
+by simply changing some pairs of rabbit-ears to sparks, instead of adding
+more ears (which would only confuse the issue further).  Ambiguous cases
+are defined as those for which the compiler being used finds a legitimate
+interpretation which is different from that which the user had in mind.
+See also section 8.1.
+
+
+
+
+
+
+\section{Statements}
+
+In this section is described the format of INTERCAL statements.
+
+\subsection{General Format}
+
+Statements may be entered in ``free format.''  That is, more than one
+statement may occur on a single card, and a statement may begin on one card
+and end on a later one.  Note that if this is done, all intervening cards
+and portions thereof must be part of the same statement.  That this
+restriction is necessary is immediately apparent from the following example
+of what might occur if statements could be interlaced.
+
+\begin{verbatim} 
+        DO .1 <- ".1c'&:51~"#V1c!12~;&75SUB"V'V.1~
+        DO .2 <- '"!1c"&';V79SUB",&7SUB:173"'~!V9c
+        .2'c,&1SUB:5~#33578"'"'"~'#65535c"V'V#&85'"'
+        #8196'"'~.1"c.2'~'#&5c"'#1279c#4351'~#65535"'
+\end{verbatim} 
+The above statements are obviously meaningless.  (For that matter, so are
+the statements
+
+\begin{verbatim}
+        DO .1 <- ".1c"&:51~"#V1C\b!12~;&75SUB"V'V.1~
+        .2'C,&1SUB:5~/333578"'"'"~#65535c"V'V#&85'"'
+        DO .2 <- '"!1c"&';V79SUB",&7SUB:173"'~!V9c
+        #8196'"'~.1"c.2'~'#&5c"'#1279c!4351'~#65535"'
+\end{verbatim}
+but this is not of interest here.)
+
+Spaces may be used freely to enhance program legibility (or at least reduce
+program illegibility), with the restriction that no word of a statement
+identifier (see section 4.3) may contain any spaces.
+
+\subsection{Labels}
+
+A statement may begin with a LOGICAL LINE LABEL enclosed in wax-wane pairs
+(|()|).  A statement may not have more than one label, although it is
+possible to omit the label entirely.  A line label is any integer from 1 to
+65535, which must be unique within each program.  The user is cautioned,
+however, that many line labels between 1000 and 1999 are used in the
+INTERCAL System Library functions.
+
+\subsection{Identifiers and Qualifiers}
+
+After the line label (if any), must follow one of the following statement
+identifiers: |DO|, |PLEASE|, or |PLEASE DO|.  These may be used
+interchangeably to improve the aesthetics of the program.  The identifier
+is then followed by either, neither, or both of the following optional
+parameters (qualifiers):
+\begin{enumerate}
+\item either of the character strings |NOT| or |N'T|, which causes the statement
+to be automatically abstained from (see section 4.4.9) when execution
+begins, and
+\item a number between 0 and 100, preceded by a double-oh-seven
+(|%|), which causes the statement to have only the specified percent chance
+of being executed each time it is encountered in the course of execution.
+\end{enumerate}
+
+\f
+
+
+
+
+
+\subsection{Statements} 
+
+Following the qualifiers (or, if none are used, the identifier) must occur
+one of the 13 valid operations.  (Exception: see section 4.5.) These are
+described individually in sections 4.4.1 through 4.4.13.
+
+\subsubsection{Calculate}
+
+The INTERCAL equivalent of the half-mesh (|=|) in FORTRAN, BASIC, PL/I, and
+others, is represented by an angle (|<|) followed by a worm (|-|).  This
+combination is read ``gets.''  32-bit variables may be assigned 16-bit
+values, which are padded on the left with 16 zero bits.  16-bit variables
+may be assigned 32-bit values only if the value is less than 65535.  Thus,
+to invert the least significant bit of the first element of 16-bit
+2-dimensional array number 1, one could write:
+
+\begin{verbatim}
+        ,1SUB#1#1 <- 'V,1SUB#1#1c#1'~'#0c#65535'
+\end{verbatim}
+
+Similarly to SNOBOL and SPITBOL, INTERCAL uses the angle-worm to define the
+dimensions of arrays.  An example will probably best describe the format.
+To define 32-bit array number 7 as 3-dimensional, the first dimension being
+seven, the second being the current value of 16-bit variable number seven,
+and the third being the current value of the seventh element of 16-bit
+array number seven (which is one-dimensional) mingled with the last three
+bits of 32-bit variable number seven, one would write (just before they
+came to take him away):
+
+\begin{verbatim}
+        ;7 <- #7 BY .7 BY ",7SUB#7"c':7~#7'
+\end{verbatim}
+This is, of course, different from the statement:
+
+\begin{verbatim}
+        ;7 <- #7 BY .7 BY ,7SUB"#7c':7~#7'"
+\end{verbatim}
+
+INTERCAL also permits the redefining of array dimensioning, which is done
+the same way as is the initial dimensioning.  All values of items in an
+array are lost upon redimensioning, unless they have been |STASH|ed (see
+section 4.4.5), in which case restoring them also restores the old
+dimensions.
+
+\f
+
+
+
+
+
+\subsubsection{Next}
+
+The |NEXT| statement is used both for subroutine calls and for
+unconditional transfers.  This statement takes the form:
+
+\IConeline{|DO ({\em label}) NEXT|}
+
+\noindent
+(or, of course,
+\IConeline{|PLEASE DO ({\em label}) NEXT|}
+
+\noindent
+etc.), where |({\em label})| represents any logical line label which
+appears in the program.  The effect of such a statement is to transfer
+control to the statement specified, and to store in a push down list (which
+is initially empty) the location from which the transfer takes place.
+Items may be removed from this list and may be discarded or used to return
+to the statement immediately following the |NEXT| statement.  These
+operations are described in sections 4.4.3 and 4.4.4 respectively.  The
+programmer is generally advised to discard any stack entries which he does
+not intend to utilize, since the stack has a maximum depth of 79 entries.
+A program's attempting to initiate an 80th level of |NEXT|ing will result
+on the fatal error message, ``PROGRAM HAS DISAPPEARED INTO THE BLACK
+LAGOON.''
+
+\subsubsection{Forget}
+
+The statement |PLEASE FORGET| {\em exp}, where {\em exp} represents any
+expression (except colloquial and facial expressions), causes the
+expression to be evaluated, and the specified number of entries to be
+removed from the |NEXT|ing stack and discarded.  An attempt to |FORGET|
+more levels of |NEXT|ing than are currently stacked will cause the stack to
+be emptied, and no error condition is indicated.  This is because the
+condition is not considered to be an error.  As described in section 4.4.2,
+it is good programming practice to execute a |DO FORGET #1| after using a
+|NEXT| statement as an unconditional transfer, so that the stack does not
+get cluttered up with unused entries:
+
+\begin{verbatim}
+        DO (123) NEXT
+        .
+        .
+  (123) DO FORGET #1
+\end{verbatim}
+
+\subsubsection{Resume}
+
+The statement |PLEASE RESUME| {\em exp} has the same effect as |FORGET|,
+except that program control is returned to the statement immediately
+following the |NEXT| statement which stored in the stack the last entry to
+be removed.  Note that a rough equivalent of the FORTRAN computed |GO TO|
+and BASIC |ON| {\em exp} |GO TO| is performed by a sequence of the form:
+
+\begin{verbatim}
+        DO (1) NEXT
+        .
+        .
+    (1) DO (2) NEXT
+        PLEASE FORGET #1
+        .
+        .
+    (2) DO RESUME .1
+\end{verbatim}
+
+Unlike the |FORGET| statement, an attempt to |RESUME| more levels of
+|NEXT|ing than been stacked will cause program termination.  See also
+section 4.4.11.
+
+
+\subsubsection{Stash}
+
+Since subroutines are not explicitly implemented in INTERCAL, the |NEXT|
+and |RESUME| statements must be used to execute common routines.  However,
+as these routines might use the same variables as the main program, it is
+necessary for them to save the values of any variables whose values they
+alter, and later restore them.  This process is simplified by the |STASH|
+state ment, which has the form |DO STASH| {\em list}, where {\em list}
+represents a string of one or more variable or array names, separated by
+intersections (|+|).  Thus
+
+\begin{verbatim}
+        PLEASE STASH .123+:123+,123
+\end{verbatim}
+stashes the values of two variables and one entire array.  The values are
+left intact, and copies thereof are saved for later retrieval by (what
+else?)  the |RETRIEVE| statement (see section 4.4.6).  It is not possible
+to |STASH| single array items.
+
+\subsubsection{Retrieve}
+
+|PLEASE RETRIEVE| {\em list} restores the previously |STASH|ed values of
+the variables and arrays named in the list.  If a value has been
+stashed more than once, the most recently |STASH|ed values are |RETRIEVE|d,
+and a second |RETRIEVE| will restore the second most recent values
+|STASH|ed.  Attempting to |RETRIEVE| a value which has not been |STASH|ed
+will result in the error message, ``THROW STICK BEFORE RETRIEVING.''
+
+\subsubsection{Ignore}
+
+The statement |DO IGNORE| {\em list} causes all subsequent statements to
+have no effect upon variables and/or arrays named in the list.  Thus, for
+example, after the sequence
+
+\begin{verbatim}
+        DO .1 <- #1
+        PLEASE IGNORE .1
+        DO .1 <- #0
+\end{verbatim}
+16-bit variable number 1 would have the value 1, not 0.  Inputting (see
+section 4.4.12) into an |IGNORE|d variable also has no effect.  The
+condition is annulled via the |REMEMBER| statement (see section 4.4.8).
+Note that, when a variable is being |IGNORE|d, its value, though immutable,
+is still available for use in expressions and the like.
+
+\subsubsection{Remember}
+
+|PLEASE REMEMBER| {\em list} terminates the effect of the |IGNORE|
+statement for all variables and/or arrays named in the list.  It does not
+matter if a variable has been |IGNORE|d more than once, nor is it an error
+if the variable has not been |IGNORE|d at all.
+
+\subsubsection{Abstain}
+
+INTERCAL contains no simple equivalent to an |IF| statement or computed |GO
+TO|, making it difficult to combine similar sections of code into a single
+routine which occasionally skips around certain statements.  The |IGNORE|
+statement (see section 4.4.7) is helpful in some cases, but a more viable
+method is often required.  In keeping with the goal of INTERCAL having
+nothing in common with any other language, this is made possible via the
+|ABSTAIN| statement.
+
+This statement takes on one of two forms.  It may not take on both at any
+one time.  |DO ABSTAIN FROM ({\em label})| causes the statement whose
+logical line label is |({\em label})| to be abstained form.  |PLEASE
+ABSTAIN FROM| {\em gerund list} causes all statements of the specified
+type(s) to be abstained from, as in
+
+\begin{verbatim}
+        PLEASE ABSTAIN FROM STASHING
+        PLEASE ABSTAIN FROM IGNORING + FORGETTING
+        PLEASE ABSTAIN FROM NEXTING
+        PLEASE ABSTAIN FROM CALCULATING
+\end{verbatim}
+
+
+Statements may also be automatically abstained from at the start of
+execution via the |NOT| or |N'T| parameter (see section 4.3).
+
+
+If, in the course of execution, a statement is encountered which is being
+abstained from, it is ignored and control passes to the next statement in
+the program (unless it, too, is being abstained from).
+
+The statement |DO ABSTAIN FROM ABSTAINING| is perfectly valid, as is |DO
+ABSTAIN FROM REINSTATING| (although this latter is not usually
+recommended).  However, the statement |DO ABSTAIN FROM GIVING UP| is not
+accepted, even though |DON'T GIVE UP| is.
+
+\subsubsection{Reinstate}
+\newlength{\QEDlen}\settowidth{\QEDlen}{Q.E.D.}\newlength{\lastlinelen}
+\settowidth{\lastlinelen}{Since $x+y$ cannot equal anything but 0, $x+y=0$.}
+\addtolength{\lastlinelen}{-1\QEDlen}
+
+The |REINSTATE| statement, like the |ABSTAIN|, takes as an argument either
+a line label or a gerund list.  No other form of argument is permitted.
+For example, the following is an invalid argument:
+\begin{quote}
+        Given: $x\neq0$, $y\neq0$,  Prove: $x+y=0$. \\
+        Since $x\neq0$, then $x+1\neq1$, $x+a\neq a$, $x+y\neq y$. \\
+        Thus $x+y \neq$ anything but 0. \\
+        Since $x+y$ cannot equal anything but 0, $x+y=0$. \\
+       \hspace*{\lastlinelen} Q.E.D.
+\end{quote}
+
+|REINSTATE|ment nullifies the effects of an abstention.  Either form of
+|REINSTATE|ment can be used to ``free'' a statement, regardless of whether
+the statement was abstained from by gerund list, line label, or |NOT|.
+Thus, |PLEASE REINSTATE REINSTATING| is not necessarily an irrelevant
+statement, since it might free a |DON'T REINSTATE| command or a |REINSTATE|
+the line label of which was abstained from.  However, |DO REINSTATE GIVING
+UP| is invalid, and attempting to |REINSTATE| a |GIVE UP| statement by line
+label will have no effect.  Note that this insures that |DON'T GIVE UP|
+will always be a ``do-nothing'' statement.
+
+\subsubsection{Give Up}
+
+|PLEASE GIVE UP| is used to exit from a program.  It has the effect of a
+|PLEASE RESUME #80|.  |DON'T GIVE UP|, as noted in section 4.4.10, is
+effectively a null statement.
+
+\subsubsection{Input}
+
+Input is accomplished with the statement |DO WRITE IN| {\em list}, where
+{\em list} represents a string of variables and/or elements or arrays,
+separated by intersections.  Numbers are represented on cards, each number
+on a separate card, by spelling out each digit (in English) and separating
+the digits with one or more spaces.  A zero (0) may be spelled as either
+|ZERO| or |OH|.  Thus the range of (32-bit) input values permissible
+extends from |ZERO| (or |OH|) through |FOUR TWO NINE FOUR NINE SIX SEVEN
+TWO NINE FIVE|.
+
+Attempting to write in a value greater than or equal to |SIX FIVE FIVE
+THREE SIX| for a 16-bit variable will result in the error message, ``DON'T
+BYTE OFF MORE THAN YOU CAN CHEW.''
+
+\subsubsection{Output}
+
+Values may be output to the printer, one value per line, via the statement
+|DO READ OUT| {\em list}, where the list contains variables, array
+elements, and/or constants.  Output is in the form of ``extended'' Roman
+numerals (also called ``butchered'' Roman numerals), with an overline
+(\zero) indicating the value below is ``times 1000'', and lower-case
+letters indicating ``times 1000000''.  Zero is indicated by an overline
+with no character underneath.  Thus, the range of (32-bit) output values
+possible is from \zero\ through \=i\=vccxciv\=C\=M\=L\=X\=V\=I\=ICCXCV.
+Note: For values whose residues modulo 1000000 are less than 4000, M is
+used to represent 1000; for values whose residues are 4000 or greater, \=I
+is used.  Thus |#3999| would read out as MMMIM while |#4000| would read out
+as \=I\=V.  Similar rules apply to the use of \=M and i for 1000000, and to
+that of \=m and \=i for 1000000000.
+\typeout{Do they really mean MMMIM and not MMMCMXCIX??}
+
+\f
+
+
+
+
+
+\subsection{Comments}
+
+Unrecognizable statements, as noted in section 7, are flagged with a splat
+(|*|) during compilation, and are not considered fatal errors unless they
+are encountered during execution, at which time the statement (as input at
+compilation time) is printed and execution is terminated.  This allows for
+an interesting (and, by necessity, unique) means of including comments in
+an INTERCAL listing.  For example, the statement:
+
+\begin{verbatim}
+*       PLEASE NOTE THAT THIS LINE HAS NO EFFECT
+\end{verbatim}
+will be ignored during execution due to the inclusion of the NOT qualifier.
+User-supplied error messages are also easy to implement:
+
+\begin{verbatim}
+*       DO SOMETHING ABOUT OVERFLOW IN ;3
+\end{verbatim}
+as are certain simple conditional errors:
+
+\begin{verbatim}
+* (123) DON'T YOU REALIZE THIS STATEMENT SHOULD ONLY BE ENCOUNTERED
+                ONCE?
+        PLEASE REINSTATE (123)
+\end{verbatim}
+This pair of statements will cause an error exit the second time they are
+encountered.  Caution!!  The appearance of a statement identifier in an
+intended comment will be taken as the beginning of a new statement.  Thus,
+the first example on the preceding page could not have been:
+
+\begin{verbatim}
+*       PLEASE NOTE THAT THIS LINE DOES NOTHING
+\end{verbatim}
+The third example, however, is valid, despite the appearance of two cases
+of |D|-space-|O|, since INTERCAL does not ignore extraneous spaces in
+statement identifiers.
+\f
+
+
+
+
+
+\section{Subroutine Library}
+
+INTERCAL provides several built-in subroutines to which control can be
+transferred to perform various operations.  These operations include many
+useful functions which are not easily representable in INTERCAL, such as
+addition, subtraction, etc.
+
+\subsection{Usage}
+
+In general, the operands are |.1|, |.2|, etc., or |:1|, |:2|, etc., and the
+result(s) are stored in what would have been the next operand(s).  For
+instance, one routine adds |.1| to |.2| and store the sum in |.3|, with
+|.4| being used to indicate overflow.  All variables not used for results
+are left unchanged.
+
+\subsection{Available Functions}
+
+At the time of this writing, only the most fundamental operations are
+offered in the library, as a more complete selection would require
+prohibitive time and coree to implement.  These functions, along with their
+corresponding entry points (entered via |DO ({\em entry}) NEXT|) are listed
+below.
+
+\begin{verbatim}
+ (1000) .3 <- .1 plus .2, error exit on overflow
+ (1009) .3 <- .1 plus .2
+        .4 <- #1 if no overflow, else .4 <- #2
+ (1010) .3 <- .1 minus .2, no action on overflow
+ (1020) .1 <- .1 plus #1, no action on overflow
+ (1030) .3 <- .1 times .2, error exit on overflow
+ (1039) .3 <- .1 times .2
+        .4 <- #1 if no overflow, else .4 <- #2
+ (1040) .3 <- .1 divided by .2
+        .3 <- #0 if .2 is #0
+ (1050) .2 <- :1 divided by .1, error exit on overflow
+        .2 <- #0 if .1 is #0
+
+ (1500) :3 <- :1 plus :2, error exit on overflow
+ (1509) :3 <- :1 plus :2
+        :4 <- #1 if no overflow, else :4 <- #2
+ (1510) :3 <- :1 minus :2, no action on overflow
+ (1520) :1 <- .1 concatenated with .2
+ (1525) This subroutine is intended solely for internal
+        use within the subroutine library and is therefore
+        not described here.  Its effect is to shift .3
+        logically 8 bits to the left.
+ (1530) :1 <- .1 times .2
+ (1540) :3 <- :1 times :2, error exit on overflow
+ (1549) :3 <- :1 times :2
+        :4 <- #1 if no overflow, else :4 <- #2
+ (1550) :3 <- :1 divided by :2
+        :3 <- #0 if :2 is #0
+
+ (1900) .1 <- uniform random no. from #1 to #65535
+ (1910) .2 <- normal random no. from #0 to .1, with
+              standard deviation .1 divided by #12
+\end{verbatim}
+
+\f
+
+
+
+
+
+\section{Programming Hints}
+
+For the user looking to become more familiar with the INTERCAL language, we
+present in this section an analysis of a complex program, as well as some
+suggested projects for the ambitious programmer.
+
+Considering the effort involved in writing an INTERCAL program, it was 
+decided in putting together this manual to use an already existing program 
+for instructive analysis.  Since there was only one such program available,
+we have proceeded to use it.  It is known as the ``INTERCAL System Library.''
+
+\subsection{Description}
+
+The program listing begins on the second page following.  It is in the same
+format as would be produced by the Princeton INTERCAL compiler in FORMAT
+mode with WDITH=62 (see section 8).  For a description of the functions
+performed by the Library, see section 5.2.
+
+\subsection{Analysis}
+
+We shall not attempt to discuss here the algorithms used, but rather we
+shall point out some of the general techniques applicable to a wide range
+of problems.
+
+Statements 10, 14, 15, and 26 make up a virtual ``computed |GO TO|''.  When
+statement 10 is executed, control passes eventually to statement 16 or 11,
+depending on whether |.5| contains |#1| or |#2|, respectively.  The value
+of |.5| is determined in statement 9, which demonstrates another handy
+technique.  To turn an expression, {\em exp}, with value |#0| or |#1|, into
+|#1| or |#2| (for use in a ``|GO TO|''), use |"V'{\em exp}'c#1"~#3|.  To
+reverse the condition (i.e., convert |#0| to |#2| and leave |#1| alone) use
+|"V'{\em exp}'c#2"~#3|.
+
+Certain conditions are easily checked.  For example, to test for zero,
+select the value from itself and select the bottom bit (see statement 54).
+To test for all bits being 1's, select the value from itself and select the
+top bit (see statement 261).  The test to greater than, performed in
+statements 192 and 193 on 32-bit values, employs binary logical operations,
+which are performed as follows:
+
+\begin{verbatim}
+        'V.1c.2'~'#0c#65535'
+\end{verbatim}
+for 16-bit values or, for 32-bit values:
+
+\begin{verbatim}
+        "'V":1~'#65535c30'"c":2~'#65535c#0'"'~'#0
+        c#65535'"c"'V":1~'#0c#65535'"c":2~'#0
+        c#65535'"'~'#0c#65535'"
+\end{verbatim}
+(The proofs are left as an exercise to the reader.)
+
+Testing for greater-than with 16-bit values is somewhat simpler and is done
+with the pair of statements:
+
+\begin{verbatim}
+        DO .C <- 'V.Ac.B'~'#0c#65535'
+        DO .C <- '&"'.A~.C'~'"V'V.C~.C'c#32768"
+                ~"#0c#65535"'"c".C~.CZ''ZZZ`#1
+\end{verbatim}
+This sets |.C| (a dummy variable) to |#1| if |.A| $>$ |.B|, and |#0|
+otherwise.  The expression may be expanded as described above to instead
+set |.C| to |#1| or |#2|.
+
+Note also in statement 220 the occurrence of |~"#65535c65535"|.  Although
+these operations select the entire value, they are not extraneous, as they
+ensure that the forthcoming |V|s will be operating on 32-bit values.
+
+In several virtual computed |GO TO|s the |DO FORGET #1| (statement 15 in the
+earlier example) has been omitted, since the next transfer of control would
+be a |DO RESUME #1|.  By making this a |DO RESUME #2| instead, the |FORGET| may
+be forgotten.
+
+In statement 64, note that .2 is |STASH|ed twice by a single statement.  This
+is perfectly legal.
+
+Lastly, note in statements 243 and 214 respectively, expressions for
+shifting 16- and 32-bit variables logically one place to the left.
+Statement 231 demonstrates right-shifting for 32-bit variables.
+
+% MIKE GETS TO INSERT THE PROGRAM HERE!
+\f
+\subsection{Program Listing}
+
+\continuationchartrue % syslib.i uses the continuation character convention
+\ICverbatimlisting{syslib.i}
+\typeout{Where's line 1551?  1900?  1910?}
+\f
+
+
+
+
+
+\subsection{Programming Suggestions}
+
+For the novice INTERCAL programmer, we provide here a list of suggested 
+INTERCAL programming projects:
+
+Write an integer exponentiation subroutine.  |:1 <- .1| raised to the |.2| power.
+
+Write a double-precision sorting subroutine.  Given 32-bit array |;1| of
+size |:1|, sort the contents into numerically increasing order, leaving the
+results in |;1|.
+
+Generate a table of prime numbers.
+
+Put together a floating-point library, using 32-bit variables to represent
+floating-point numbers (let the upper half be the mantissa and the lower
+half be the characteristic).   The library should be capable of performing 
+floating-point addition, subtraction, multiplication, and division, as well
+as the natural logarithm function.
+
+Program a Fast Fourier Transform (FFT).   This project would probably entail
+the writing of the floating-point library as well as sine and cosine functions.
+
+Calculate, to |:1| places, the value of pi.
+
+\f
+
+
+
+
+
+\section{Error Messages}
+
+Due to INTERCAL's implementation of comment lines (see section 4.5), most
+error messages are produced during execution instead of during compilation.
+All errors except those not causing immediate termination of program execution
+are treated as fatal.
+
+\subsection{Format}
+
+All error messages appear in the following form:
+
+\begin{verbatim}
+        ICLnnnI (error message)
+                ON THE WAY TO STATEMENT nnnn
+                CORRECT SOURCE AND RESUBMIT
+\end{verbatim}
+
+The message varies depending upon the error involved.  For undecodable
+statements the message is the statement itself.  The second line tells
+which statement would have been executed next had the error not occurred.
+Note that if the error is due to 80 attempted levels of |NEXT|ing, the
+statement which would have been executed next need not be anywhere near the
+statement causing the error.
+
+\subsection{Messages}
+
+Brief descriptions of the different error types are listed below according
+to message number.
+
+\begin{description}
+\def\ttitem#1{\item[{\tt #1}]}
+
+\ttitem{000} An undecodable statement has been encountered in the course of
+        execution.  Note that keypunching errors can be slightly disastrous,
+        since if `|FORGET|' were misspelled F-O-R-G-E-R, the results would 
+        probably not be those desired.  Extreme misspellings may have even 
+        more surprising consequences.  For example, misspelling `|FORGET|' 
+        R-E-S-U-M-E could have drastic results.
+
+\ttitem{017} An expression contains a syntax error.
+
+\ttitem{079} Improper use has been made of statement identifiers.
+
+\ttitem{099} Improper use has been made of statement identifiers.
+
+\ttitem{123} Program has attempted 80 levels of |NEXT|ing.
+
+\ttitem{129} Program has attempted to transfer to a non-existent line label.
+
+\ttitem{139} An |ABSTAIN| or |REINSTATE| statement references a non-existent line label.
+
+\ttitem{182} A line label has been multiply defined.
+
+\ttitem{197} An invalid line label has been encountered.
+
+\ttitem{200} An expression involves an unidentified variable.
+
+\ttitem{240} An attempt has been made to give an array a dimension of zero.
+
+\ttitem{241} Invalid dimensioning information was supplied in defining or using
+        an array.
+
+\ttitem{275} A 32-bit value has been assigned to a 16-bit variable.
+
+\ttitem{436} A retrieval has been attempted for an un|STASH|ed value.
+
+\ttitem{533} A |WRITE IN| statement or interleave (|\change|) operation has
+produced a value requiring over 32 bits to represent.
+
+\ttitem{562} Insufficient data.
+
+\ttitem{579} Input data is invalid.
+
+\ttitem{621} The expression of a |RESUME| statement evaluated to |#0|.
+
+\ttitem{632} Program execution was terminated via a |RESUME| statement instead of
+        |GIVE UP|.
+
+\ttitem{633} Execution has passed beyond the last statement of the program.
+
+\ttitem{774} A compiler error has occurred (see section 8.1).
+
+\ttitem{778} An unexplainable compiler error has occurred (see J. Lyon or B. Woods).
+\end{description}
+
+\f
+
+
+\section*{Tonsil\footnote{Since all other reference manuals
+have Appendices, it was decided that the INTERCAL manual should contain
+some other type of removable organ.} A:  The Official INTERCAL Character Set}
+
+
+
+
+
+
+Tabulated on page 18 are all the characters used in INTERCAL, excepting
+letters and digits, along with their names and interpretations.  Also
+included are several characters not used in INTERCAL, which are presented
+for completeness and to allow for future expansion.
+\stepcounter{footnote}
+\footnotetext{This footnote intentionally unreferenced.}
+
+{\catcode`.=\active \catcode`|=12  % Use . instead of | for code mode
+\def.{\bgroup\tt\usespecials\def.{\null\egroup}}
+\begin{table}
+\begin{minipage}{\textwidth} % so the footnote works out.
+\begin{tabular}{|r|l|p{3in}|}
+\hline
+Character &    Name &                  Use (if any) \\
+\hline
+.\spot.        &       spot &                  identify 16-bit variable      \\
+.:.    &       two-spot &              identify 32-bit variable      \\
+.,.    &       tail &                  identify 16-bit array         \\
+.;.    &       hybrid &                identify 32-bit array         \\
+.\#.   &       mesh &                  identify constant             \\
+.=.    &       half-mesh &                                           \\
+.'.    &       spark &                 grouper                       \\
+.`.    &       backspark &                                           \\
+.!.    &       wow &                   equivalent to spark-spot      \\
+\verb|?|&      what &                  unary exlusive OR (ASCII)     \\
+.".    &       rabbit-ears &           grouper                       \\
+{\verb|!`|}&   rabbit &                equivalent to ears-spot       \\
+{\verb+|+}&    spike &                                               \\
+.\%.   &       double-oh-seven &       percentage qualifier          \\
+.-.    &       worm &                  used with angles              \\
+.<.    &       angle &                 used with worms               \\
+.>.    &       right angle &                                         \\
+.(.    &       wax &                   precedes line label           \\
+.).    &       wane &                  follows line label            \\
+.[.    &       U turn &                                              \\
+.].    &       U turn back &                                         \\
+.\{.   &       embrace &                                             \\
+.\}.   &       bracelet &                                            \\
+.*.    &       splat &                 flags invalid statements      \\
+.\&.   &       ampersand\footnotemark & unary logical AND            \\
+.V.    &       V (or book) &           unary logical OR              \\
+.\bookworm. &  bookworm (or universal qualifier) & unary exclusive OR      \\
+.\$.   &       big money &             binary mingle (ASCII)         \\
+.\change.&     change &                binary mingle                 \\
+.\~{}. &       sqiggle &               binary select                 \\
+.\_.   &       flat worm &                                           \\
+.\zero.        &       overline &              indicates ``times 1000''      \\
+.+.    &       intersection &          separates list items          \\
+./.    &       slat &                                                  \\
+{\verb|\|}&    backslat &                                              \\
+.@.    &       whirlpool &                                           \\
+.\hookworm.& hookworm &                                               \\
+{\verb|^|}&    shark (or simply sharkfin) &                          \\
+.\blotch.&     blotch                                                \\
+\hline
+\end{tabular}
+\catcode`.=12
+\caption{                INTERCAL character set (top view).}
+\typeout{What does Rabbit really look like?}
+\def\thempfootnote{\arabic{mpfootnote}}
+\footnotetext[\thefootnote]{Got any better ideas?}
+\label{character-set}
+\end{minipage}
+\end{table}
+}
+
+\f
+\section*{Tonsil B: 
+Notes On The Atari Implementation}
+
+The Atari implementation of INTERCAL differs from the original Princeton
+version primarily in the use of ASCII rather than EBCDIC.  Since there is
+no ``change'' sign (|\change|) in ASCII, we have substituted the ``big
+money'' (|$|) as the mingle operator.  We feel that this correctly
+represents the increasing cost of software in relation to hardware.
+(Consider that in 1970 one could get RUNOFF for free, to run on a \$20K
+machine, whereas today a not quite as powerful formatter costs \$99 and
+runs on a \$75 machine.)  We also feel that there should be no defensible
+contention that INTERCAL has any sense.  Also, since overpunches are
+difficult to read on the average VDT, the exclusive-or operator may be
+written ?.  This correctly expresses the average person's reaction on first
+encountering exclusive-or, especially on a PDP-11.  Note that in both of
+these cases, the over-punched symbol may also be used if one is
+masochistic, or concerned with portability to the Princeton compiler.  The
+correct over-punch for ``change'' is ``c{\sc
+$\langle$backspace$\rangle$}/'' and the correct over-punch for |\bookworm|
+is "V{\sc $\langle$backspace$\rangle$}-".  These codes will be properly
+printed if you have a proper printer, and the corresponding EBCDIC code
+will be produced by the |/IBM| option on the |LIST| command.
+
+\end{document}
+
diff --git a/lexer.l b/lexer.l
new file mode 100644 (file)
index 0000000..fabdc4e
--- /dev/null
+++ b/lexer.l
@@ -0,0 +1,171 @@
+%{
+#include <stdio.h>
+#include <ctype.h>
+#include "ick.h"
+#include "y.tab.h"
+
+#ifdef MAIN
+YYSTYPE        yylval;
+#endif /* MAIN */
+
+char *textlines[MAXLINES];
+
+static char linebuf[YYLMAX];
+static char *lineptr = linebuf;
+
+/*
+ * The spectacular ugliness of INTERCAL syntax requires that the lexical
+ * analyzer have two levels. One, embedded in the getc() function, handles
+ * logical-line continuation and the ! abbrev, and stashes each logical
+ * line away in a buffer accessible to the code generator (this is necessary
+ * for the * construct to be interpreted correctly). The upper level is
+ * generated by lex(1) and does normal tokenizing.
+ */
+
+#undef getc
+int getc(fp)
+FILE   *fp;
+{
+    bool bangflag = FALSE;
+
+    if (bangflag)
+    {
+       bangflag = FALSE;
+       *lineptr++ = '!';
+       return('.');
+    }
+    else
+    {
+       int c = fgetc(fp);
+
+       if (feof(yyin))
+       {
+           *lineptr = '\0';
+           return(EOF);
+       }
+       else if (c == '\\')
+       {
+           do {
+               c = fgetc(fp);
+           } while
+               (c != '\\' && isspace(c));
+       }
+
+       if (c == '!')
+       {
+           *lineptr++ = '!';
+           bangflag = TRUE;
+           return(c = '\'');
+       }
+       else if (c == '\n')
+       {
+           extern char *strdup();
+
+           *lineptr = '\0';
+           lineptr = linebuf;
+           textlines[yylineno] = strdup(linebuf);
+           return('\n');
+       }
+       else
+       {
+           if (islower(c))
+               c = toupper(c);
+           return(*lineptr++ = c);
+       }
+    }
+}
+
+%}
+
+W      [\ \t\n]*
+D      [0-9][0-9]*
+
+%%
+
+[0-9][0-9]*    {yylval.numval = atoi(yytext); return(NUMBER);}
+\.             {return(ONESPOT);}
+\:             {return(TWOSPOT);}
+\,             {return(TAIL);}
+\;             {return(HYBRID);}
+\#             {return(MESH);}
+
+\$             {return(MINGLE);}
+\~             {return(SELECT);}
+
+\&             {yylval.numval = AND; return(UNARY);}
+V              {yylval.numval = OR; return(UNARY);}
+\?             {yylval.numval = XOR; return(UNARY);}
+
+\'             {return(SPARK);}
+\"             {return(EARS);}
+
+\({D}\)                {yylval.numval = atoi(yytext + 1); return(LABEL);}
+
+DO             {return(DO);}
+PLEASE         {return(DO);}
+PLEASE{W}DO    {return(DO);}
+NOT            {return(NOT);}
+DON\'T         {return(NOT);}
+
+\%{D}          {yylval.numval = atoi(yytext + 1); return(OHOHSEVEN);}
+SUB            {return(SUB);}
+BY             {return(BY);}
+
+\<-            {return(GETS);}
+CALCULATING    {yylval.numval = GETS; return(GERUND);}
+
+NEXT           {return(NEXT);}
+NEXTING                {yylval.numval = NEXT; return(GERUND);}
+FORGET         {return(FORGET);}
+FORGETTING     {yylval.numval = FORGET; return(GERUND);}
+RESUME         {return(RESUME);}
+RESUMING       {yylval.numval = RESUME; return(GERUND);}
+STASH          {return(STASH);}
+STASHING       {yylval.numval = STASH; return(GERUND);}
+RETRIEVE       {return(RETRIEVE);}
+RETRIEVING     {yylval.numval = RETRIEVE; return(GERUND);}
+IGNORE         {return(IGNORE);}
+IGNORING       {yylval.numval = IGNORE; return(GERUND);}
+REMEMBER       {return(REMEMBER);}
+REMEMBERING    {yylval.numval = REMEMBER; return(GERUND);}
+ABSTAIN{W}FROM {return(ABSTAIN);}
+ABSTAINING     {yylval.numval = ABSTAIN; return(GERUND);}
+REINSTATE      {return(REINSTATE);}
+REINSTATING    {yylval.numval = REINSTATE; return(GERUND);}
+\+             {return(INTERSECTION);}
+GIVE{W}UP      {return(GIVE_UP);}
+READ{W}OUT     {return(READ_OUT);}
+WRITE{W}IN     {return(WRITE_IN);}
+COME{W}FROM    {return(COME_FROM);}
+COMING{W}FROM  {yylval.numval = COME_FROM; return(GERUND);}
+
+[\ \t][\ \t]*  ;
+\n             {return(NEWLINE);}
+.              {yylval.numval = yytext[0]; return(BADCHAR);}
+
+
+%%
+
+#ifdef MAIN
+int yyerror()
+{
+    (void) printf("lextest: lexer error.\n");
+}
+
+main()
+{
+       int     t;
+
+       while ((t = yylex()) > 0)
+       {
+               (void) printf("%03d %09d\n", t, yylval.numval);
+               yylval.numval = 0;
+       }
+}
+#endif /* MAIN */
+
+static int yywrap()
+{
+    return(EOF);
+}
+
diff --git a/lose.c b/lose.c
new file mode 100644 (file)
index 0000000..ef9f043
--- /dev/null
+++ b/lose.c
@@ -0,0 +1,20 @@
+/*
+ * lose.c -- report INTERCAL compile- or run-time error
+ */
+/*LINTLIBRARY*/
+#include <stdio.h>
+
+void lose(n, m)
+int    n;
+char   *m;
+{
+    (void) fprintf(stderr,
+                  "ICL%c%c%cI %s\n        ON THE WAY TO STATEMENT %04d\n",
+                  m[0], m[1], m[2], m+4, n);
+    (void) fprintf(stderr, "        CORRECT SOURCE AND RESUBMIT\n");
+    exit(atoi(m));
+}
+
+/* lose.c ends here */
+
+
diff --git a/lose.h b/lose.h
new file mode 100644 (file)
index 0000000..b77c0a4
--- /dev/null
+++ b/lose.h
@@ -0,0 +1,52 @@
+/* lose.h --- error message strings
+
+/*
+ * These error messages are documented in the INTERCAL-72 manual.
+ */
+#define E000 "000 An undecodable statement has been encountered in the course of execution."
+#define E017 "017 CAN'T YOU SPELL, YOU HOPELESS DWEEB?\n\
+        (An expression contains a syntax error.)"
+#define E079 "079 Improper use has been made of statement identifiers."
+#define E099 "099 Improper use has been made of statement identifiers."
+#define E123 "123 YOUR PROGRAM HAS VANISHED INTO THE BLACK LAGOON!\n\
+        (Program has attempted 80 levels of NEXTing.)"
+#define E129 "129 Program has attempted to transfer to a non-existent line label."
+#define E139 "139 An ABSTAIN or REINSTATE statement references a non-existent line label."
+#define E182 "182 A line label has been multiply defined."
+#define E197 "197 An invalid line label has been encountered."
+#define E200 "200 An expression involves an unidentified variable."
+#define E240 "240 An attempt has been made to give an array a dimension of zero."
+#define E241 "241 Invalid dimensioning information was supplied in defining or using an array."
+#define E275 "275 DON'T BYTE OFF MORE THAN YOU CAN CHEW\n\
+        A 32-bit value has been assigned to a 16-bit variable."
+#define E436 "436 THROW STICK BEFORE RETRIEVING!\n\
+        (A retrieval has been attempted for an unSTASHed value)."
+#define E533 "533 A WRITE IN statement or interleave ($) operation has produced value requiring over 32 bits to represent."
+#define E562 "562 Insufficient data."
+#define E579 "579 Input data is invalid."
+#define E621 "621 The expression of a RESUME statement evaluated to #0."
+#define E632 "632 THE NEXT STACK RUPTURES. ALL DIE. OH, THE EMBARRASSMENT!\n\
+        (Program execution terminated via a RESUME statement instead of GIVE UP)."
+#define E633 "633 YOU HAVE FALLEN OFF THE EDGE OF THE WORLD. BYE-BYE!\n\
+        (Execution has passed beyond the last statement of the program.)"
+#define E774 "774 A compiler error has occurred (see section 8.1)."
+#define E778 "778 An unexplainable compiler error has occurred (see J. Lyon or B. Woods)."
+
+/*
+ * These errors are unique to C-INTERCAL
+ */
+#define E222 "222 Out of stash space."
+#define E333 "333 Too many variables."
+#define E444 "444 A COME FROM statement references a non-existent line label."
+#define E555 "555 More than one COME FROM references the same label."
+#define E666 "666 Too many source lines."
+#define E777 "777 No such source file."
+#define E888 "888 Can't open C output file"
+#define E999 "999 Can't open C skeleton file."
+
+extern void lose();
+
+/* lose.h ends here */
+
+
+
diff --git a/sample.i b/sample.i
new file mode 100644 (file)
index 0000000..364eec7
--- /dev/null
+++ b/sample.i
@@ -0,0 +1,27 @@
+        DO (5) NEXT
+    (5) DO FORGET #1
+        PLEASE WRITE IN :1
+        DO .1 <- 'V":1~'#32768$#0'"$#1'~#3
+        DO (1) NEXT
+        DO :1 <- "'V":1~'#65535$#0'"$#65535' \
+                ~'#0$#65535'"$"'V":1~'#0$#65535'" \
+                $#65535'~'#0$#65535'"
+        DO :2 <- #1
+        PLEASE DO (4) NEXT
+    (4) DO FORGET #1
+        DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535 \
+                $#0'"'~'#0$#65535'"$"'V":1~'#0 \
+                $#65535'"$":2~'#65535$#0'"'~'#0$#65535'"
+        DO (1) NEXT
+        DO :2 <- ":2~'#0$#65535'" \
+                $"'":2~'#65535$#0'"$#0'~'#32767$#1'"
+        DO (4) NEXT
+    (2) DO RESUME .1
+    (1) PLEASE DO (2) NEXT
+        PLEASE FORGET #1
+        DO READ OUT :1
+        PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3
+        DO (3) NEXT
+        PLEASE DO (5) NEXT
+    (3) DO (2) NEXT
+        PLEASE GIVE UP