Whitespace
- Дата создания:
- 01 апреля 2003
- Парадигма:
- Типизация:
- Принятые расширения файлов:
- .ws
- Реализации и версии (свернуть все | развернуть все):
Whitespace — популярный эзотерический язык программирования, известный тем, что исходный код программы состоит только из непечатаемых символов.
Whitespace был создан в 2003 году Эдвином Брейди (Edwin Brady) и Крисом Моррисом (Chris Morris). Его спецификации достаточно просты, а сам язык не имеет практической ценности, поэтому авторское описание является единственным стандартом. Язык не породил диалектов, т.к. он сам по себе совершенен в своем роде.
Whitespace был создан как компенсация несправедливости по отношению к непечатаемым символам. Большинство современных языков их просто игнорирует, но ведь нечестно не принимать что-то во внимание лишь потому, что его не видно! Поэтому новый язык должен был игнорировать все символы, кроме невидимых. Видимые символы можно использовать в качестве комментариев, хотя при этом следует соблюдать осторожность и не вставить в комментариях лишний пробел или перевод строки. Написание кода на этом языке возможно либо в шестнадцатеричном редакторе, либо в среде разработки, которая обозначает пробелы и знаки табуляции видимым образом.
Все команды языка состоят из трех типов символов: пробел (Space, ASCII 32), табуляция (Tab, ASCII 9) и новая строка (LF, ASCII 10). Сами команды довольно длинные (обычно 3-4 символа), и их немало; они систематизированы посредством использования префикса (т.н. параметр модификации инструкции), который обозначает тип команды: операции со стеком, арифметика, доступ к куче, управление потоком выполнения программы, ввод/вывод.
Виртуальная машина языка оснащена стеком и кучей, которые могут обрабатывать целые числа произвольной разрядности. Стек используется для выполнения команд, а куча играет роль хранилища данных.
В языке используется только один тип данных — целые числа в двоичном представлении. Число начинается с задания его знака (Space — положительное, Tab — отрицательное), затем следует двоичная запись абсолютного значения числа (Space — 0, Tab — 1) и LF, сигнализирующий о конце числа.
Метка — это произвольный список пробелов и знаков табуляции, оканчивающийся переводом строки. Метки используются в управлении потоком выполнения программы, и должны быть уникальны в пределах программы.
Команды языка (сгруппированы по типу):
Операции со стеком
-
Space-Space-Number
: добавить число в стек
-
Space-LF-Space
: продублировать число на вершине стека -
Space-LF-Tab
: поменять местами два верхних элемента стека
-
Space-LF-LF
: извлечь из стека верхний элемент и выбросить его
-
Space-Tab-Space-Number
: скопировать N-ый элемент стека (индекс задается аргументом) на вершину стека -
Space-Tab-LF-Number
: “сдвинуть” со стека N элементов, сохраняя при этом верхний
Две последние команды — расширение, доступное с версии Whitespace 0.3, предназначенное для упрощения работы с рекурсивными функциями.
Арифметика
-
Tab-Space-Space-Space
: сложение -
Tab-Space-Space-Tab
: вычитание -
Tab-Space-Space-LF
: умножение -
Tab-Space-Tab-Space
: деление (целочисленное) -
Tab-Space-Tab-Tab
: остаток от деления
Операция применяется к двум верхним элементам стека. Левым операндом считается более ранний элемент стека (добавленный первым).
Доступ к куче
-
Tab-Tab-Space
: сохранить верхний элемент стека в ячейке памяти, адрес которой задан во втором сверху элементе -
Tab-Tab-Tab
: извлечь содержимое ячейки памяти, адрес которой задан в верхнем элементе стека, и поместить его на вершину стека
Управление потоком выполнения программы
-
LF-Space-Space-Label
: создать метку -
LF-Space-Tab-Label
: вызвать подпрограмму -
LF-Space-LF-Label
: перейти к метке -
LF-Tab-Space-Label
: перейти к метке, если верхний элемент стека равен нулю -
LF-Tab-Tab-Label
: перейти к метке, если верхний элемент стека отрицателен -
LF-Tab-LF
: закончить подпрограмму и передать управление вызвавшей ее программе -
LF-LF-LF
: закончить программу
Ввод/вывод
-
Tab-LF-Space-Space/Tab
: вывести верхний элемент стека на печать как символ/число -
Tab-LF-Tab-Space/Tab
: прочитать из потока символ/число и сохранить его в ячейку памяти, адрес которой задан в верхнем элементе стека
Следует отметить, что при использовании элементов стека в выполнении команд в большинстве случаев они удаляются из стека.
Ссылки:
Примеры:
Hello, World!:
Пример для версий Whitespacers (Ruby)Для простоты понимания код откомментирован: буква означает, что следующий фрагмент кода добавляет в стек ASCII-код этой буквы, а после print
следует команда вывода верхнего элемента стека на печать как символа. Последовательности символов, задающие ASCII-коды, заключены в фигурные скобки (за исключением перевода строки).
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
Факториал:
Пример для версий Whitespacers (Ruby)В этом примере используется другой метод комментирования — каждая команда предваряется ее словесным описанием. Числа и метки, кроме заключительного переноса строки, заключены в скобки.
Куча используется для хранения переменных: 1 — первое число, факториал которого не нужен, 2..5 — ASCII-коды символов, используемых при выводе на печать, 6 и 7 — текущее число и его факториал. Сам факториал вычисляется итеративно: на каждой итерации печатаются ранее вычисленное число и факториал, затем вычисляются и заносятся в память новые. После этого, новое число (ячейка 6) сравнивается с ячейкой 1: если число меньше, цикл повторяется, иначе прекращается.
Интересо, что в Whitespace ноль “отрицательный”: число должно содержать в записи хотя бы один Tab, в двоичной записи нуля единиц нет, поэтому приходится задавать знаковый бит и записывать ноль как Tab-LF.
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
Числа Фибоначчи:
Пример для версий Whitespacers (Ruby)Пример работает аналогично факториалу, но интенсивнее использует хранение данных в стеке и команду копирования верхнего элемента стека, чтобы избежать лишних обращений к памяти. Кроме того, в этом примере счетчик отрицательный и увеличивается на каждой итерации.
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:
Пример для версий 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
Комментарии
]]>blog comments powered by Disqus
]]>