Search › A-Z › F › ><> (Fish) Interpreter
><> (Fish) Interpreter
A clean, from-scratch ><> (Fish) interpreter written for emulators.org and running entirely in your browser. ><> (pronounced "fish") is a two-dimensional stack esolang published on esolangs.org in 2009, a playful cousin of Befunge: a program is a 2D codebox of instruction cells, an instruction pointer walks it in one of four directions executing each cell, and a stack of stacks holds the data. Mirrors such as /, \ and # bend the pointer, and the p and g commands write and read the codebox itself, so a program can rewrite its own code as it runs.
The view is the whole machine at once: the codebox with the current instruction-pointer cell highlighted, its direction, the stack, and the output line. It boots running a bouncing "Hello, World!", and plugs into the shared debugger so you can pause, single-step one grid cell at a time, set breakpoints on any (x,y) cell, and watch the stack or a self-modified cell. Any unknown command or an empty-stack pop is the ><> runtime error "something smells fishy...", which is how many ><> programs terminate.
><> (Fish) language specification ↗
Runs on: Web browser
><> (Fish) Interpreter Online Emulator
Play ><> (Fish) Interpreter using JavaScript directly in your browser.
Controls
Configurations
| Configuration | Emulator | Machine | OS | Legal | |
|---|---|---|---|---|---|
| Hello, World! | ><> (Fish) Interpreter | open | Open ⛶ | ||
| Echo input | ><> (Fish) Interpreter | open | Open ⛶ |
Chips
Notes
Embedding
><> (Fish) is authored here from scratch, so embedding is just three small files: the VM (fish.js), the canvas view (fish-render.js), and a boot shim that owns the loop. There is no CPU and no ROM. The "machine" is a 2D codebox of instruction cells plus a stack of stacks.
Boot. Create the VM, load a program, wire a renderer, and run your own loop built on vm.step() (execute exactly one grid cell):
var vm = new Fish();
vm.load('"!dlroW ,olleH">o<'); // bounces and prints Hello, World!
var view = new FishRender(canvas, vm);
(function loop(){
for (var i = 0; i < 200 && !vm.halted; i++) vm.step(); // one cell each
view.draw();
if (!vm.halted) requestAnimationFrame(loop);
})();
The machine is plain objects. Everything the debugger needs is a live field; there is no wasm heap:
| Member | Kind | What it does |
|---|---|---|
vm.step() | method | Execute exactly one grid cell (the current IP cell), then move the IP. The single-step primitive; returns {ok}, {halted} or {waiting}. |
vm.grid | field | The codebox as an Int32Array (row-major, y*96 + x). Poke it to edit the program live. |
vm.stack | field | The active stack (a JS array; top is the last element). vm.stacks is the full stack of stacks. |
vm.ip / vm.dir | field | The instruction pointer {x,y} and its travel direction {x,y}. |
vm.stringMode | field | The active quote (' or ") while in string mode, else null (each cell is pushed as its code instead of executed). |
vm.queueInput(v) | method | Feed stdin for i (input character): pass a string or a number. |
vm.load(text) / vm.reset() | method | Parse a program into the codebox / clear the machine to its initial state. |
Debugger integration
Because the VM is ordinary JavaScript and vm.step() is one grid cell, the debugger drives it directly. The boot shim publishes window.EMU_BOOT with a transport whose stepInsn(n) runs n cells, and a run loop that checks the current IP against a breakpoint set every cell:
function runBatch(){
for (var i = 0; i < speed; i++){
var idx = vm.ip.y * 96 + vm.ip.x; // linear cell address
if (bps.has(idx) && !justResumed) return 'bp'; // break when IP reaches (x,y)
var ev = vm.step();
if (ev.halted) return 'halt';
if (ev.waiting) return 'wait'; // blocked on i input
}
}
Breakpoints are (x,y) cells, stored as the linear address y*96 + x - the same address pc() returns and the disasm/hex views use, so clicking the gutter next to a cell sets a breakpoint there. Watchpoints cover a written grid cell (via the p path) and the stack (any push/pop). The "registers" are the real machine state: IPX, IPY, direction, string mode and stack depth.
The disassembler is unusual: ><> has no linear instruction stream, so /debugger/src/cpus/fish.js decodes each grid cell as its one-cell command (with the cell's (x,y) and a description). That annotates the codebox-as-memory view without pretending the grid is executed top-to-bottom.
Architecture
><> (Fish) is a two-dimensional stack esolang (esolangs.org, 2009), a playful cousin of Befunge:
- The codebox - a 2D grid of instruction cells. The instruction pointer walks it in one of four directions and wraps at the edges of the content box.
- The stack - a stack of integers (in fact a stack of stacks); every operator pushes and pops it. Division makes floating-point values.
- Mirrors -
/\|_#bend the pointer,xsends it a random way, and> < ^ vsteer it outright. - String mode -
'and"each toggle pushing every cell's code until the matching quote returns. - Self-modification -
p(put) writes a cell andg(get) reads one, so a program can rewrite its own code as it runs. That is why the codebox is the memory the debugger shows. - I/O and halting -
o/noutput a character/number,ireads one,;halts, and any unknown command or empty-stack pop is the runtime error "something smells fishy...".
This interpreter is a faithful clean-room implementation of that public specification. The ><> language is public domain. There is no external code to trust. The entire machine is a couple of hundred lines of readable JavaScript, which is exactly what makes it a clear debugging target.