INTERCAL, an abbreviation for Compiler Language With No Pronounceable Acronym, was created in 1972, thus probably making it the first ever esoteric programming language. (See Prehistory of Esoteric Languages for an alternate view.) Donald R. Woods and James M. Lyon invented it with the goal of creating a language with no similarities whatsoever to any existing programming languages. The language largely succeeds in this goal, apart from its use of an assignment statement. It also suffers from being one-dimensional, and the original version uses binary (but TriINTERCAL was created as a modern ternary version).
INTERCAL was also the first language to have a wimpmode devised for it, due to its unusual I/O requirements.
It has new operators, Mingle and Select operators, and unary XOR operators. Also, the symbols are called by different names: . is a spot, : a two-spot, , is a tail and ; is a hybrid. Newer INTERCAL compilers/interpreters have some new commands, such as COME FROM, and Quantum INTERCAL, etc.
INTERCAL consists of a list of statements. Each statement is preceded by an optional line label (a number in brackets), followed by DO, PLEASE, or PLEASE DO. (Proposed extensions allow other statement identifiers such as MAYBE.) The politesse of a program's statement identifiers is checked to make sure it stays within certain limits (1/3 to 1/5 of the statements must be polite). DON'T, DO NOT, PLEASE DON'T, and PLEASE DO NOT (as well as some less elegant versions like PLEASEN'T) can be used to write a statement that has no effect unless REINSTATED. (If the statement is unlabeled and does not resemble an INTERCAL statement, it never has any effect at all; thus, PLEASE NOTE is a common way to start an INTERCAL comment (the extra E is a deliberate syntax error that makes the line impossible to REINSTATE)). An execution chance for a command can be given using the double-oh-seven operator, like this:
DO %50. Syntax errors happen at run time, and only if the line containing them is executed.
INTERCAL-72 is the name given to the traditional version (i.e. the version with no extensions). A summary of INTERCAL-72 statements follows (DO could be PLEASE or PLEASE DO in any of these):
assignment statement (called CALCULATE, but that keyword is never used) DO variable <- expression STASH (push variables on their own stacks) DO STASH variable + variable + ... + variable RETRIEVE (pop variables from their own stacks) DO RETRIEVE variable + variable + ... + variable NEXT (jump to command, save return address on an 80-address stack) DO (label) NEXT RESUME (pop <expression> return addresses, jump to the last one popped) DO RESUME expression FORGET (pop <expression> return addresses and discard them) DO FORGET expression ABSTAIN (don't execute the referenced line / lines) DO ABSTAIN FROM (label) or DO ABSTAIN FROM something + something + ... + something (as in DO ABSTAIN FROM CALCULATING) REINSTATE (cancel out an ABSTAIN or DON'T) DO REINSTATE (label) or DO REINSTATE something + something + ... + something IGNORE (make a variable read-only, silently ignoring writes) DO IGNORE variable + variable + ... + variable REMEMBER (cancel out an IGNORE) DO REMEMBER variable + variable + ... + variable WRITE IN (input, using digits spelled out as words) DO WRITE IN variable READ OUT (output, in butchered Roman numerals) DO READ OUT variable
C-INTERCAL also accepts keywords in Latin.
Variables and Constants
INTERCAL has four types of variables:
- The 16-bit unsigned integer, written with a spot (.) followed by a number
- The 32-bit unsigned integer, written with a two-spot (:) followed by a number
- The array of 16-bit unsigned integers, written with a tail (,) followed by a number
- The array of 32-bit unsigned integers, written with a hybrid (;) followed by a number
Variables do not have to be declared. An array can be dimensioned by assigning a number to it, and dereferenced using the SUB keyword (as in
,1 SUB .1). Arrays are based at 1. Dimensioning an array clobbers its contents, and arrays must be STASHed or RETRIEVEd as a block.
Constants are written with a mesh (#) followed by a number. Only 16-bit unsigned constants are permitted; larger constants must be constructed using operators.
INTERCAL has five operators (not counting SUB). Symbols for the operators vary; the following symbols are the ASCII versions (INTERCAL was originally written for EBCDIC).
- ~ (binary, called select)
Only bits in the left operand corresponding to set bits in the right operand are used to affect the result, and these bits are justified towards the least significant and padded with zeros. For instance,
#12 ~ #5(1100 and 101 in binary) is 10 (the 22 and 20 bits of #12). The return type of select is supposed to be 16 bits wide if there were fewer than 16 bits selected, and 32 bits wide otherwise. However, some compilers simply copy the type of the right-hand operand, so portable INTERCAL code should ensure it works in both cases.
- $ (binary, called mingle)
Bits are alternated from the left and right operands, with the least significant bit of the right operand becoming the least significant bit of the output. The return type is always 32 bits wide; an error results on overflow. (The sign for cent (¢: c, backspace, /) was used in EBCDIC; at least one modern compiler accepts a much wider range of currency symbols).
- V (unary OR)
- ? (unary XOR; EBCDIC ∀: V, backspace, -)
- & (unary AND)
There are three unary logic operators. Each operates on consecutive bits of the input; the 20 and 21 bits give the 20 bit of the output, and so on. The most significant bit of the output, which is as wide as the input, is obtained by combining the most and least significant bits of the input with the appropriate logical operation.
The unary operators must be placed one character later than in normal programming languages (just after the punctuation mark identifying a variable, or just inside a grouped expression they apply to).
There is no operator precedence in INTERCAL; operators must be grouped by using sparks (') and rabbit-ears ("). An appropriate grouping character must be chosen to avoid ambiguity.
INTERCAL has been expanded over the years to add new features. The most notable of these is the COME FROM statement.
COME FROM (time-reversed GOTO) DO COME FROM (label)
Whenever the line that the COME FROM refers to is executed, if control would transfer to the next line it instead transfers to the COME FROM statement, unless the COME FROM statement has been ABSTAINed FROM. An attempt to COME FROM a nonabstained NEXT will cause control of the program to go to the NEXT's target, as usual, but an attempt to RESUME the return address will transfer control to the COME FROM. Implementations differ as to what happens when two COME FROMs aim at the same line; the most interesting interpretation is to multithread Brainfork-style and transfer control to both.
Other modern extensions include support for different bases (TriINTERCAL), auto-abstaining lines (to synchronize multithread applications), binary I/O, and a wimpmode (to input/output numbers as digits).
- Threaded INTERCAL
- Backtracking INTERCAL
- Quantum INTERCAL
- INTERCAL Turing-completeness proof
- The INTERCAL Resources Page
- INTERCAL Revised Reference Manual
- INTERCAL Resources on the Web, a comprehensive collection by Brian Raiter
- intercal.org.uk download page, including downloads for both the CLC-INTERCAL and C-INTERCAL compilers
- alt.lang.intercal newsgroup
- INTERCAL implementation of Unlambda
- INTERCAL on Interstates, a web framework
- INTERCAL-72 interpreter and compiler targeting LLVM