Whitespace
- Appeared in:
- 01 Apr 2003
- Paradigm:
- Typing discipline:
- File extensions:
- .ws
- Versions and implementations (Collapse all | Expand all):
Whitespace is a popular esoteric language, widely known for using only whitespace characters for source code.
Whitespace was created in 2003 by Edwin Brady and Chris Morris. Its specification is quite simple, and it has no practical value, so its only standard is the authors’ description. It hasn’t spawned dialects, since it itself is perfect in its domain. It is not known whether it is Turing-complete (looks like it is, but nobody yet has taken the bother to prove it).
Whitespace was created it an attempt to fix the injustice done to whitespace characters. See, most modern languages ignore them, and it’s unjust to ignore something just because it’s invisible. So, a new language would ignore all characters except for whitespace ones. Other characters can be used as comments, however, one has to be careful not to slip an extra space or linefeed between comments. Any development in it is possible only in an editor which marks tabs and spaces visible, or alternatively in hex editor.
Each command of the language consists of three kinds of characters: space (ASCII 32), tab (ASCII 9) and line feed (ASCII 10). This way the commands can be rather lengthy, and they are quite numerous; they are systematized by using prefix (called Instruction Modification Parameter) which notes the type of the command: Stack Manipulation, Arithmetic, Heap Access, Flow Control, I/O.
The virtual machine of the language has a stack and a heap. Both of them can process arbitrary-width integers as their elements; the stack is used to perform all operations, and heap is used as a permanent store of data.
The only data type used in the language is integer numbers in their binary representation. A number starts with sign token (Space for positive and Tab for negative), than the binary notation follows (Space for 0 and Tab for 1), and finally the number ends with a new line.
Labels are arbitrary lists of spaces and tabs, terminated with line feed. Labels are used in flow control commands, and thus should be unique within the program.
The commands of the language are the following (grouped by type and followed with the type of parameter it takes, if any):
Stack Manipulation
-
Space-Space-Number
: push the number on the stack
-
Space-LF-Space
: duplicate the element on top of the stack
-
Space-LF-Tab
: swap two top elements of the stack
-
Space-LF-LF
: pop the top element of the stack and discard it
-
Space-Tab-Space-Number
: copy the N-th item of the stack (index given by the argument) onto the top of the stack
-
Space-Tab-LF-Number
: “slide” N items off the stack while keeping the top item
Two last commands are actually an extension, available since Whitespace 0.3, introduced to ease the usage of recursive functions.
Arithmetic
-
Tab-Space-Space-Space
: addition -
Tab-Space-Space-Tab
: subtraction -
Tab-Space-Space-LF
: multiplication -
Tab-Space-Tab-Space
: division (integer) -
Tab-Space-Tab-Tab
: modulo remainder
The operation is applied to two topmost elements of the stack. Left operand of the operation is the deeper element of the stack (the one that was pushed first).
Heap Access
-
Tab-Tab-Space
: store the top element of the stack at the memory cell, the address of which is given in second-top element -
Tab-Tab-Tab
: retrieve the contents of memory cell, the address of which is given with top element of the stack, and push this contents on the stack
Flow Control
-
LF-Space-Space-Label
: put a label here -
LF-Space-Tab-Label
: call a subroutine -
LF-Space-LF-Label
: jump to the label -
LF-Tab-Space-Label
: if the top of the stack is zero, jump to the label -
LF-Tab-Tab-Label
: if the top of the stack is negative, jump to the label -
LF-Tab-LF
: end subroutine and pass control back to the caller -
LF-LF-LF
: end of program
I/O
-
Tab-LF-Space-Space/Tab
: output the top element of the stack as a character/number -
Tab-LF-Tab-Space/Tab
: read a character/number from input stream and put it to memory cell, the address of which is given in top element of the stack
Links:
Examples:
Hello, World!:
Example for versions Whitespacers (Ruby)This code is commented to simplify understanding it: letter means that next piece of whitespace pushes on the stack ASCII-code of this letter, and print means invoking the command of printing topmost element of the stack. The numbers that correspond to ASCII-codes are contained within brackets (except for the delimiting newline which is outside of the brackets for readability).
H { }
print
e { }
print
l { }
print
l { }
print
o { }
print
, { }
print
space { }
print
W { }
print
o { }
print
r { }
print
l { }
print
d { }
print
! { }
print
\n { }
print
end
Factorial:
Example for versions Whitespacers (Ruby)This example uses a slightly different method of commenting — each command is preceded with its literal description. Numbers and labels are enclosed in brackets.
The example works as follows: heap is used to store variables (1 — index of the first factorial which doesn’t need to be calculated, 2..5 — ASCII-codes of special characters used in printing, 6 and 7 — current number and its factorial), and stack is used to run commands). Factorial is calculated iteratively, on each iteration previously calculated values are printed, and new ones are calculated and stored to memory. After this, the newly calculated number is compared with contents of cell 1: if it is less, the loop continues, otherwise it halts.
A curious thing to note is that in Whitespace numeric system zero is “negative”: a number must have at least one Tab in its notation, and binary notation of zero has no 1s, so it has to be written as Tab (only sign bit).
push_1 { }
push_17 { }
store push_2 { }
push_33 { }
store push_3 { }
push_32 { }
store push_4 { }
push_61 { }
store push_5 { }
push_10 { }
store push_6 { }
push_0 { }
store push_7 { }
push_1 { }
store label
{ }
printing_block_push_6 { }
retrieve print_as_number
push_2 { }
retrieve print_as_char
push_3 { }
retrieve print_as_char
push_4 { }
retrieve print_as_char
push_3 { }
retrieve print_as_char
push_7 { }
retrieve print_as_number
push_5 { }
retrieve print_as_char
increase_counter_block_push_6 { }
push_6 { }
retrieve push_1 { }
add store calculate_next_factorial_block_push_7 { }
push_7 { }
retrieve push_6 { }
retrieve multiply
store conditional_return_block_push_6 { }
retrieve push_1 { }
retrieve subtract jump_if_negative
{ }
quit
end
Fibonacci numbers:
Example for versions Whitespacers (Ruby)This example is similar to factorial one, except for that it makes more use of stack data storage and duplicate command to avoid extra readings from memory cells. Also, in this case the counter is negative and increased at each iteration, as opposed to positive and compared to fixed number of iterations.
push_1 { }
push_-16 { }
store push_2 { }
push_44 { }
store push_3 { }
push_32 { }
store push_4 { }
push_0 { }
store push_5 { }
push_1 { }
store label
{ }
start_loop_push_5 { }
push_4 { }
retrieve push_4 { }
duplicate
push_5 { }
retrieve duplicate
print_as_number
push_2 { }
retrieve print_as_char
push_3 { }
retrieve print_as_char
store retrieve add store push_1 { }
duplicate
duplicate
duplicate
retrieve add store retrieve jump_if_negative
{ }
push_10 { }
push_46 { }
duplicate
duplicate
print_as_char
print_as_char
print_as_char
print_as_char
quit
end
CamelCase:
Example for versions Whitespacers (Ruby)push-1 { }
push-1 { }
save LOOP-START.label-0
{ }
push-2 { }
readchar
push-2 { }
load CHECK-WHETHER-IS-EOL.duplicate
push-10 { }
subtract if-0-goto-1
{ }
CONVERT-TO-LOWERCASE.duplicate
push-A { }
subtract if-neg-goto-2
{ }
duplicate
push-Z { }
swap
subtract if-neg-goto-2
{ }
push-32 { }
add label-2
{ }
CHECK-WHETHER-IS-LETTER.duplicate
push-a { }
subtract if-neg-goto-3
{ }
duplicate
push-z { }
swap
subtract if-neg-goto-3
{ }
ACTION-IF-LETTER.CHECK-WHETHER-LAST-WAS-SPACE.push-1 { }
load if-0-goto-4
{ }
push-32 { }
subtract label-4
{ }
print
push-1 { }
push-0 { }
save goto-0
{ }
label-3
{ }
ACTION-IF-NOT-LETTER.push-1 { }
push-1 { }
save goto-0
{ }
label-1
{ }
push-10 { }
print
end.memory:1-was-last-space,2-currentchar
Comments
]]>blog comments powered by Disqus
]]>