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

StatementWhat It Does
DO .1 <- #42Assign (CALCULATE)
DO (100) NEXTCall subroutine at label 100
DO RESUME #1Return from subroutine
DO FORGET #1Drop 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 .1Save .1 on its stash stack
DO RETRIEVE .1Restore .1 from its stash stack
DO IGNORE .1Make .1 read-only
DO REMEMBER .1Make .1 writable again
DO READ OUT .1Print value (yes, READ OUT writes)
DO WRITE IN .1Read input (yes, WRITE IN reads)
PLEASE GIVE UPExit program

Operators

OperatorNameWhat It Does
$mingleInterleave bits of two values. Sets up a binary operation.
~selectExtract bits using a mask. Right-justifies the result.
&ANDUnary AND of adjacent bit pairs. Apply to mingled value for binary AND.
VORUnary OR of adjacent bit pairs. Apply to mingled value for binary OR.
?XORUnary XOR of adjacent bit pairs. Apply to mingled value for binary XOR.