Hanoi Love
- Дата создания:
- 30 апр 2001
- Создан под влиянием:
- Парадигма:
- Типизация:
- Принятые расширения файлов:
- .hl
- Реализации и версии (свернуть все | развернуть все):
Hanoi Love — минималистический эзотерический язык программирования.
Hanoi Love был создан в 2001 году Jeffry Johnston. В отличие от Brainfuck, он малоизвестен, поэтому существует только одна его реализация — авторская, она же стандарт де-факто.
Hanoi Love был изобретен как минимальный Тьюринг-полный стековый язык; его имя происходит от игры “Ханойские башни”, в которой игрок имеет дело с дисками на трех стержнях — фактически тремя стеками дисков.
Hanoi Love использует следующую модель вычислений:
программа является последовательностью односимвольных команд языка и, возможно, других символов (игнорируемых при обработке).
программа оперирует тремя стеками данных (A, B и C) и одним стеком инструкций (D). При попытке получить элемент из пустого стека стек A возвращает 1, стеки B и C — 0, D не возвращает ничего. В начале выполнения программы все стеки пусты, и текущим является стек A.
операции между стеками выполняются при помощи внутреннего регистра (в начале выполнения программы хранящего значение 0).
стек D используется для хранения не самих инструкций, а указателей на инструкции программы. При выполеннии операции “добавить элемент в стек D” добавляется указатель на предыдущую инструкцию. При выполнении операции “извлечь элемент из стека D” указатель на текущую инструкцию сдвигается в позицию, которая хранилась в стеке. Инструкции “;” и “`” извлекают позицию из стека D, но не сдвигают указатель на текущую инструкцию (это используется для выхода из циклов). Выполнение операций над стеком D не изменяет значение, хранящееся в регистре. Для организации цикла следует добавить позицию начала цикла в стек D, выполнить тело цикла и извлечь позицию начала цикла из стека D, вернувшись в нее.
строка инструкций обрабатывается слева направо; указатель на текущую инструкцию начинает с самой левой инструкции, и инструкции выполняются по одной, с возможным сдвигом указателя командами “:” и операциями над стеком D, пока список инструкций не заканчивается или пока не появляется инструкция “!”, не являющаяся парой к “:”.
Список инструкций языка:
-
.
: Текущим становится следующий по алфавиту стек (следующим после стека D считается стек A). -
'
: Добавляет значение регистра в текущий стек (содержимое регистра не изменяется). -
,
: Извлекает элемент из стека и заменяет содержимое регистра этим значением. -
;
: Извлекает элемент из стека и прибавляет его к значению в регистре. -
`
: Извлекает элемент из стека и вычитает его из значения в регистре.
-
"
: Префикс переключения в режим ввода-вывода. Следующая инструкция будет использовать вместо стека поток стандартного ввода/вывода. Так, пара инструкций",
читает один байт из потока стандартного ввода в регистр, а пара"'
записывает содержимое регистра в поток стандартного вывода. -
:
: Если значение в регистре 0, все следующие инструкции до парной!
пропускаются. -
!
: Если эта инструкция является парной к:
, не делает ничего, иначе завершает выполнение программы.
Любая программа на Brainfuck может быть записана на Hanoi Love при помощи следующих замен кодов:
-
> -> ..,...'...
-
< -> .,.'..
-
+ -> ,.;'...
- — -> .,…`.’…
-
. -> .,'"'...
-
, -> .,",'...
-
[ -> ...'..,'...:
-
] -> ...,!...;.
Следует отметить, что эти коды универсальные и поэтому достаточно длинные (при перекодировании не делается никаких допущений). Перед началом каждой инструкции Brainfuck текущим стеком является стек A. Стек А остается пустым, стеки B и C имитируют ленту данных и указатель данных, стек D используется только для организации циклов.
Ссылки:
Примеры:
Hello, World!:
Пример для версий Hanoi LoveЭтот пример является фактически переводом примера на Brainfuck. Все стеки пусты, и все вычисления проводятся в регистре. Стек A используется как источник константы 1: поскольку он пуст, примененная к нему операция pop
возвращает значение 1. Таким образом, команды ;
и backtick
становятся командами “увеличить значение в регистре на 1” и “уменьшить значение в регистре на 1”, соответственно, и эквивалентны командам +
и -
на Brainfuck. Пара команд "'
записывает содержимое регистра в стандартный поток вывода, и эквивалентна команде .
на Brainfuck.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;; "'
"'
;;; "'
``````````````````````````````````````````````````````````````````` "'
```````````` "'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; "'
;;;;;;;;;;;;;;;;;;;;;;;; "'
;;; "'
`````` "'
```````` "'
``````````````````````````````````````````````````````````````````` "'
Числа Фибоначчи:
Пример для версий Hanoi LoveВ примере используется итеративное определение чисел Фибоначчи.
Стек A большую часть времени пуст и используется для получения константы 1; иногда используется для временного хранения значений (по тому же принципу, что и в оригинальной задаче о Ханойских башнях). Стек B содержит символы, выводимые на печать (запятую и пробел) и два последних числа Фибоначчи из вычисленных программой. Стек C содержит значение 1 для каждого числа Фибоначчи, которое нужно напечатать (в данном случае шесть единиц для печати 6 чисел).
На каждой итерации одно число извлекается из стека C. Если оно положительно (т.е. нужно вычислить и напечатать еще одно число Фибоначчи), верхнее число f2
из стека B извлекается, преобразуется в ASCII-код соответствующей цифры и выводится на печать вместе с запятой и пробелом. После этого следующее число f1
извлекается из стека B и прибавляется к числу f2
. Наконец, числа f2
и f1+f2
возвращаются в стек B. Низкоуровневое описание примера приводится в комментариях.
Интерпретатор Hanoi Love использует переменные типа byte
для хранения значений в регистре и стеках, поэтому принципиально возможно вычислить только первые 13 чисел Фибоначчи. В действительности пример выводит только первые 6 чисел Фибоначчи, чтобы не усложнять программу печатью двух- и трехзначных чисел (которая выполняется по тому же принципу, что и в Brainfuck, но сложнее).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .' 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)
Комментарии
]]>blog comments powered by Disqus
]]>