Hanoi Love

Appeared in:
30 Apr 2001
Influenced by:
Typing discipline:
File extensions:
Versions and implementations (Collapse all | Expand all):
Programming language

Hanoi Love is a minimalistic esoteric programming language.

Hanoi Love was created in 2001 by Jeffry Johnston; and his implementation remains a de facto standard. Its specification is as simple as 8 instructions, so it hasn’t passed standardization. Unlike Brainfuck, it’s not widely known, so reference implementation stays about the only one, and the language has no dialects.

Hanoi Love was invented in an attempt to create a minimal Turing-complete stack-based language; its name comes from “Towers of Hanoi” game, in which the player operates disks on three rods — actually three stacks of disks.

Hanoi Love uses the following machine model:

  • program is a sequence of one-character language commands and (optionally) other characters which are ignored;
  • there are three data stacks (labeled A, B, C) and one instruction stack (labeled D). If pop instruction is performed when current stack is empty, stack A returns 1, B and C — 0, and D doesn’t return a value. Initially all stacks are empty, and stack A is set as current.
  • an internal register (initially set to 0) allows operations between stacks.
  • stack D is used for storing the locations of instructions. When a push operation is performed here, the previous instruction location (current location minus one) is pushed onto the stack. When a pop operation is performed, the new instruction location is popped from the stack. If a “;” or “`” instruction is performed on this stack, the instruction location is popped, but no further action is taken (this is useful for breaking out of loops). Popping from stack D doesn’t influence the contents of the register, but instead returns the instruction pointer to the location that was stored. To organize a loop, one has to push instruction location to stack D, run the loop body and pop instruction location from D.
  • each instruction line is processed in the normal left to right fashion. The instruction pointer starts to the left of the first instruction. A loop is formed: The instruction pointer is incremented. Then the current instruction is executed. This process repeats until the “!” instruction is reached or there are no more instructions to execute.

The commands of the language are the following:

  • . : Selects the next stack in alphabetic sequence (will loop to stack A).
  • ' : Copies the byte in the register and pushes it onto the stack.
  • , : Pops a byte from the stack and moves it into the register.
  • ; : Pops a byte from the stack and adds it to the register.
  • ` : Pops a byte from the stack and subtracts it from the register.
  • " : I/O mode prefix. The next instruction will pop from the standard input or push to the standard output rather than to a stack.
  • : : If the register is 0, any following instructions are skipped until matching ! instruction is reached.
  • ! : Does nothing if matching a :, otherwise exits the program.

Any Brainfuck program can be translated to Hanoi Love using the following sequences of codes:

  • > -> ..,...'...
  • < -> .,.'..
  • + -> ,.;'...
  • — -> .,…`.’…
  • . -> .,'"'...
  • , -> .,",'...
  • [ -> ...'..,'...:
  • ] -> ...,!...;.

Note that this translation is universal but long, because it doesn’t assume anything. Each BF instruction starts when pointing to empty A stack; B and C stacks imitate memory and data pointer, and stack D is used only for organizing loops.


Hello, World!:

Example for versions Hanoi Love

This example is a translation of Brainfuck example. All stacks are empty, and all calculations are done in the register. Stack A is used as a source of constant 1: since it’s empty, pop operation on it returns 1. This way, ; and ` operations become “increment register by 1” and “decrement register by 1”, i.e., they are equivalent to + and - Brainfuck commands. "' pushes the contents of the register to standard out, i.e., is equivalent to . in Brainfuck.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;; "'
;;; "'
``````````````````````````````````````````````````````````````````` "'
```````````` "'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;;;;;;;;;;;;;;;;;;; "'
;;; "'
`````` "'
```````` "'
``````````````````````````````````````````````````````````````````` "'

Fibonacci numbers:

Example for versions Hanoi Love

This example uses iterative definition of Fibonacci numbers. Stack A is empty (used for popping 1 from it) and is used for temporary storages. Stack B holds printable characters (comma and space) and two last Fibonacci numbers. Stack C holds a 1 for each Fibonacci number to be printed (6 1’s to print 6 numbers). On each iteration one number is popped from C. If it is positive, top number f2 from stack B is popped, converted to ASCII character of the corresponding digit and printed. After this number f1 is popped from stack B and added to f2. Finally, numbers f2 and f1+f2 are pushed back in stack B. A low-level description of the example is given in the comments.

Hanoi Love interpreter uses byte variables to store values of memory cells, so a maximum of 13 Fibonacci numbers can be printed. However, printing multi-digit numbers in Hanoi Love is rather similar to Brainfuck, so only first six single-digit numbers are printed.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .'                   B (space) regr = ASCII for space
...;;;;;;;;;;;;.'                                     B (space comma) reg = ASCII for comma
...,                                                  A (empty) reg = 1
..''''''                                              C (6 ones for 6 numbers to print) reg = 1
..`.'...;.'                                           B (space comma 0 1) reg = 1
.,                                                    C (pop number to reg) reg = 1
.'...                                                 D (remembered this place)
:                                                     if this number is positive print top number in B and move to next Fibonacci number
...,                                                  B (space comma f1) reg = f2
.'                                                    C (f2) reg = f2
..;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "' A (empty) reg = f2 in ASCII (printed)
.,                                                    B (space comma) reg = f1
.'                                                    C (f2 f1) reg = f2
..., "'                                               B (space) reg = comma (printed)
.'                                                    C (f2 f1 comma) reg = comma
..., "' '                                             B (space) reg = space (printed)
.,...'                                                B (space comma) reg = comma
.,                                                    C (f2) reg = f1
..'                                                   A (f1) reg = f1
..,                                                   C (empty) reg = f2
...'                                                  B (space comma f2) reg = f2
...;                                                  A (empty) reg = f1+f2
.'                                                    B (space comma f2 f1+f2)
.,                                                    C (pop number to reg)
.,                                                    D (get previous command location)
...,,,...;; "' "' "'                                  pop everything from B and convert comma to point (printed three times)