Learn INTERCAL in 17 Steps
Each lesson is a tiny program designed to be stepped through in the debugger. Open the file, set a breakpoint on line 1, press F5, and watch the variables panel.
Tip: Open the Variables panel and Watch panel side by side. The DO NOTE comments in each program tell you exactly what to look for as you step.
01
Hello World
Turing tape output encoding
02
Variables & Constants
Spots, two-spots, four-spots, meshes, fences, stockades
03
Mingle ($)
Bit interleaving — the core operator
04
Select (~)
Bit extraction with masks
05
Unary Operators
AND, OR, XOR on adjacent bit pairs
06
Calculate
Assignment and nested expressions
07
NEXT & RESUME
Subroutine calls and returns
08
FORGET
Dropping the return address
09
ABSTAIN & REINSTATE
Disabling and re-enabling statements
10
COME FROM
The opposite of GOTO
11
STASH & RETRIEVE
Saving and restoring state
12
IGNORE & REMEMBER
Read-only variables
13
Politeness
The compiler demands manners
14
Arrays
Tails, hybrids, and SUB indexing
15
System Library
ADD, MINUS, TIMES, DIVIDE via NEXT
16
Input
WRITE IN reads. Yes, really.
17
COME FROM Loops
The fundamental iteration pattern
Common INTERCAL Idioms
Once you understand the individual statements, you need to learn how they combine. INTERCAL has no if, no while, no for. These idioms are how you build those constructs from the primitives.
Mingle + Unary = Binary Logic
The key insight that makes INTERCAL operators make sense
The unary operators (& V ?) seem pointless when applied to a single value. They make sense when you realize they're meant to be used on mingled pairs. Mingle two values to interleave their bits into adjacent pairs. Then apply a unary operator — it performs the binary operation on each pair. Mingle is the setup. Unary is the execution.
DO NOTE Binary AND of .1 and .2:
DO :1 <- .1 $ .2 DO NOTE mingle: bits are now in adjacent pairs
DO .3 <- '&:1' ~ '#0$#0' DO NOTE unary AND on pairs, select result bits
DO NOTE This is how the syslib implements all binary logic.
DO NOTE Mingle = "set up the operation". Unary = "execute it".
The Zero Test
INTERCAL has no comparison operators. This is how you test for zero.
Subtract two values using the syslib. If the result is zero, the values are equal. But how do you branch on zero? You can't — there's no if. Instead, use the result as a RESUME depth. Zero means RESUME #0 (illegal), non-zero means RESUME #N (pops N entries). The trick is setting up the NEXT stack so the right thing happens either way.
DO NOTE Is .1 equal to .2?
DO (1010) NEXT DO NOTE .3 = .1 - .2
DO NOTE .3 is 0 if equal, nonzero if different.
DO NOTE Use .3 to index into a dispatch table or as a RESUME depth.
The Double-NEXT Trampoline
Conditional branching inside COME FROM loops
INTERCAL has no if/else. The double-NEXT trampoline provides it. Push two return addresses onto the NEXT stack, then RESUME to one of them based on a computed value. The "unused" address is cleaned up by a FORGET. This pattern was discovered during the beer.i implementation and became the standard for all conditional branching in COME FROM loops.
DO (1000) NEXT DO NOTE call syslib, result in .3
DO (110) NEXT DO NOTE push "true" return address
DO (120) NEXT DO NOTE push "false" return address
DO RESUME .3 DO NOTE .3 = 1 → true path, .3 = 2 → false path
(110) DO FORGET #1 DO NOTE true path: discard false address
DO NOTE ... true branch code ...
DO RESUME #1
(120) DO FORGET #1 DO NOTE false path: discard true address
DO NOTE ... false branch code ...
DO RESUME #1
The COME FROM Loop
Stack-free iteration that doesn't corrupt the NEXT stack
COME FROM creates a back-edge: after the target line executes, control jumps to the COME FROM statement. Combined with ABSTAIN to break, this is INTERCAL's while loop. Unlike NEXT/RESUME loops, COME FROM loops don't touch the NEXT stack — so they can run for any number of iterations without hitting the 79-entry stack limit.
(10) DO COME FROM (20) DO NOTE loop back-edge
DO NOTE ... loop body ...
DO NOTE To exit: DO ABSTAIN FROM (10)
(20) DO NOTE COME FROM fires after this line
DO NOTE Execution continues here only after ABSTAIN
ABSTAIN as Conditional Execution
INTERCAL's if statement: disable the code you don't want to run
ABSTAIN a statement to skip it. REINSTATE to re-enable it. This is how INTERCAL implements conditional output, optional computation, and loop exit. ABSTAIN a READ OUT and the value is silently not printed. ABSTAIN a COME FROM and the loop stops. REINSTATE it and it starts again.
DO NOTE Print .1 only if some condition is met:
DO ABSTAIN FROM (50) DO NOTE disable the print
DO NOTE ... check condition, REINSTATE (50) if true ...
(50) PLEASE READ OUT .1 DO NOTE only fires if reinstated
DO NOTE This is COME FROM + ABSTAIN = conditional loop pattern.
DO NOTE It's what for(...) { if(...) print(...); } looks like in INTERCAL.
Select as Right-Shift
INTERCAL has no shift operator. It doesn't need one.
Select with a contiguous high-bit mask extracts the top N bits and right-justifies them. That's a logical right-shift. .1 ~ #65280 selects the top 8 bits of a 16-bit value and packs them into bits 0-7. Discovered during the Knight's Tour implementation.
DO NOTE Right-shift .1 by 8 positions:
DO .2 <- .1 ~ #65280 DO NOTE select top 8 bits, right-justified
DO NOTE #65280 = 0xFF00 = 1111111100000000 binary
DO NOTE The selected bits pack to the right automatically.
What's Next
After the lessons and idioms, try these programs in order of increasing difficulty:
Beginner
FizzBuzz
ABSTAIN/REINSTATE for conditional logic
The classic interview problem. If INTERCAL can do FizzBuzz, it can do anything. (It can barely do FizzBuzz.)
Beginner
Collatz Conjecture
Conditional branching with syslib arithmetic
Apply 3n+1 until you reach 1. Simple loop, real arithmetic, good debugger practice.
Intermediate
ROT13
Bit manipulation via mingle and select
Character transformation using the mingle+unary pattern. Real bit surgery.
Intermediate
99 Bottles of Beer
The double-NEXT trampoline pattern
This is where the trampoline was invented. The program that changed how INTERCAL loops work.
Advanced
Prime Sieve
Iterative division — syslib stress test
Trial division for every candidate. Exercises the full syslib arithmetic pipeline.
Expert
Knight's Tour
Bitboards, 64-bit arithmetic, the full algorithm
The most complex INTERCAL program ever written. If you can read this, you can read anything.
Quick Reference
Statements
| Statement | What It Does |
DO .1 <- #42 | Assign (CALCULATE) |
DO (100) NEXT | Call subroutine at label 100 |
DO RESUME #1 | Return from subroutine |
DO FORGET #1 | Drop return address |
DO COME FROM (100) | Hijack control after label 100 |
DO ABSTAIN FROM (100) | Disable statement at label 100 |
DO REINSTATE (100) | Re-enable statement at label 100 |
DO STASH .1 | Save .1 on its stash stack |
DO RETRIEVE .1 | Restore .1 from its stash stack |
DO IGNORE .1 | Make .1 read-only |
DO REMEMBER .1 | Make .1 writable again |
DO READ OUT .1 | Print value (yes, READ OUT writes) |
DO WRITE IN .1 | Read input (yes, WRITE IN reads) |
PLEASE GIVE UP | Exit program |
Operators
| Operator | Name | What It Does |
$ | mingle | Interleave bits of two values. Sets up a binary operation. |
~ | select | Extract bits using a mask. Right-justifies the result. |
& | AND | Unary AND of adjacent bit pairs. Apply to mingled value for binary AND. |
V | OR | Unary OR of adjacent bit pairs. Apply to mingled value for binary OR. |
? | XOR | Unary XOR of adjacent bit pairs. Apply to mingled value for binary XOR. |