Whitespace is a strange language. Its tokens are space, line-feed, and tab — everything else is comment. It's stack based, has console i/o, and an associative store. Yes, it's Turing complete. Yes, you'd be insane to use it. It belongs to the venerable tradition of languages like Brainf*ck, Shakespeare, and Unlambda.
Here's my Whitespace interpreter, written in Ruby. It's nothing to be proud of, but hey, what do you expect at 4 a.m.?
I stayed up for the better part of a night writing this. Why? Crazy, I guess.
Here's my whitespace assembler, also written in Ruby.
This test program prints the alphabet: alphabet.wsa
To assemble it, run whitespace-asm like this:
./whitespace-asm alphabet.wsa
That should generate alphabet.ws.
Then run it:
./whitespace alphabet.ws
ABCDEFGHIJKLMNOPQRSTUVWXYZ
A "#" anywhere on a line starts a comment. The rest of the line is ignored. Blank lines are ignored.
You can use this alternate syntax for a label if you wish:
unsigned-number:
Opcode Operand Description Stack Manipulation push signed-number Push a number onto the stack dup Push top of stack into the stack again swap Swap two topmost numbers on stack discard Pop & discard number on top of stack Arithmetic add Pop two numbers, add, push result sub Pop two numbers, subtract, push result mul Pop two numbers, multiply, push result div Pop two numbers, integer divide, push result mod Pop two numbers, modulo, push result Heap Access store Pop value and address; store value on heap at that address retrieve Pop address; push onto stack the heap value at that address Flow Control label unsigned-number Target for other flow-control ops call unsigned-number Call subroutine jump unsigned-number Unconditional jump jz unsigned-number Pop top of stack; jump if it's zero jn unsigned-number Pop top of stack; jump if it's negative ret Return from subroutine exit Exit interpreter I/O outchar Pop top of stack; print it as ascii character outnum Pop top of stack; print it as decimal number readchar Read character from stdin & push it onto stack readnum Read integer from stdin & push it onto stack
Here's my whitespace disassembler. It's nothing more than a cheap hack of my interpreter.
Yes, there's too much duplicated code between these three programs. No, I'm not going to fix it tonight. Maybe tomorrow.