]]> ]]>
Править | Обсудить | История

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

]]>

Работа программистам