This was the first publicly visible version.
(This is a retrospective comment.)
--- /dev/null
+ 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.
--- /dev/null
+# 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
+
+
--- /dev/null
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/****************************************************************************
+
+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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* $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.");
+}
+
--- /dev/null
+/* 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 */
--- /dev/null
+/*****************************************************************************
+
+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 */
--- /dev/null
+
+
+
+
+
+
+ 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"{"'. 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.
+
--- /dev/null
+% -*- 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
+}
+
--- /dev/null
+% -*- 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"{"'|. 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}
+
--- /dev/null
+%{
+#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);
+}
+
--- /dev/null
+/*
+ * 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 */
+
+
--- /dev/null
+/* 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 */
+
+
+
--- /dev/null
+ 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