Befunge
- Дата создания:
- 1993
- Создан под влиянием:
- Парадигма:
- Типизация:
- Реализации и версии (свернуть все | развернуть все):
Befunge — один из самых старых и самых известных двухмерных эзотерических языков программирования.
Befunge был придуман в 1993 Крисом Пресси (Chris Pressey). Он задался целью создать язык с максимально сложной компиляцией. В последующие годы появился ряд реализаций этого языка, а также несколько диалектов и модификаций под общим названием “фунгеоиды”. Два главных диалекта языка — оригинальный Befunge-93 и более поздний Befunge-98.
Исходная спецификация языка ограничивала максимальный размер поля (80x25), поэтому в отличие от многих других эзотерических языков, Befunge — не тьюринг-полный язык. Так же, как и другие эзотерические языки, он не имеет практической ценности.
Программа на Befunge — двухмерное поле фиксированного размера. Изначально его ячейки заполнены командами программы. Befunge позволяет модифицировать код программы в процессе ее выполнения, поэтому ячейки поля можно использовать и в качестве памяти произвольного доступа (правда, с ограниченными возможностями: хранить можно только числа до 255). Поле сворачивается в тор: при переходе через его край указатель инструкций попадает на противоположный край, сохраняя при этом свое направление.
Программа выполняется при помощи счетчика программы (диалект -93) или указателя инструкций (-98). В начале выполнения он находится в верхней левой клетке поля и направлен вправо. Он двигается в направлении, в котором он указывает, на одну ячейку за раз. Когда указатель попадает в клетку с командой, она выполняется. Команды могут влиять на направление указателя (в Befunge-98 добавлены инструкции, которые могут изменять и положение указателя).
Основной структурой данных в Befunge является стек; все операции используют его для получения аргументов и записи результатов. Единственный тип данных — целое число. Символы можно использовать для ввода/вывода данных и для более удобного представления строковых констант внутри самой программы; при этом они обрабатываются как соответствующие ASCII-коды.
В Befunge-93 определен следующий набор команд:
-
+ — * / %
Выполнить соответствующую операцию над двумя верхними элементами стека; нижний элемент стека используется в качестве первого операнда, верхний — в качестве второго -
!
Логическое НЕТ - ` Больше, чем
-
< > ^ v
Изменить направление указателя инструкций: влево, вправо, вверх, вниз -
?
Изменить направление указателя инструкций на случайное -
_ |
Горизонтальное/вертикальное ЕСЛИ. Обе команды извлекают верхний элемент из стека; если он равен 0, выполняется команда> v
, иначе выполняется< ^
-
"
Переключить строковый режим. В строковом режиме каждый встреченный символ добавляет свой ASCII-код в стек -
:
Продублировать верхний элемент стека -
\
Поменять местами два верхних элемента стека -
$
Удалить верхний элемент стека -
. ,
Вывести верхний элемент стека как число/как символ -
#
Мост: пропустить следующую команду -
g
Получить значение в ячейке программы про ее координатам -
p
Поместить значение в ячейку программы с заданными координатами -
& ~
Прочитать число/символ и поместить его (или его ASCII-код) в стек -
0
..9
Поместить соотвествующее значение в стек -
@
Закончить выполнение программы
При работе команд g
и p
с координатами ячейки из стека вначале извлекается y-координата (строка), затем — x-координата (столбец). Обе координаты начинаются с 0 (так, (0, 0) — верхняя левая ячейка программы). Команда p
, которая записывает значение в ячейку программы, извлекает его из стека после координат ячейки.
Примеры:
Hello, World!:
Пример для версий befungee 0.2.0Первая часть примера (до пробела) размещает в стеке нужные значения. 25*
помещает в стек значение 10 (ASCII-код перевода строки), затем "
переводит программу в строковый режим: каждый следующий символ (до вторых кавычек) добавляет в стек свой ASCII-код.
Вторая часть примера — цикл, выводящий на печать все значения в стеке, начиная с самых верхних. >
возвращает указатель инструкций к движению вправо (после конца одной итерации). :
копирует верхний элемент стека (т.е. текущий символ), из-за моста #
выполняется только при движении вправо. ,
выводит верхний элемент стека (выполняется только при движении влево). _
пропускает указатель инструкций к @
(концу программы), если верхний элемент стека — 0, и отражает его влево в противном случае. Последовательность действий в одной итерации следующая:
- скопировать верхний элемент стека,
- проверить, равен ли он 0; если равен, выйти из цикла (при этом в любом случае копия элемента удаляется из стека),
- напечатать верхний элемент стека.
25*"!dlroW ,olleH" >:#,_@
Hello, World!:
Пример для версий befungee 0.2.0Этот пример более прямолинеен — ASCII-коды символов заносятся в стек в численном виде, и символы выводятся на печать сразу после попадания кодов в стек, так что цикл не нужен.
89*,45*99*+,39*99*+::,,56*99*+,29+4*,48*,92+8*1-,56*99*+:,3+,,25*:*,56*3+,25*,@
Факториал:
Пример для версий befungee 0.2.0Программа состоит из двух циклов — первый вычисляет числа от 16 до 1, второй — собственно факториалы.
Прежде всего в стек заносится 16 (как 4*4) — максимальное число, факториал которого нужно вычислить. Затем следует первый цикл, выполняющийся по часовой стрелке. За одну итерацию в стек дописывается число, равное предыдущему, уменьшенному на 1. Когда это число становится нулем, цикл прерывается (_
во второй строке), и указатель инструкций направляется вправо.
Перед входом во второй цикл из стека удаляется верхний элемент (0) и добавляется 1 (текущее значение факториала). Затем следует второй цикл, выполняющийся против часовой стрелки. За одну итерацию происходит следующее:
-
\
— два верхних элемента (ранее вычисленный факториал и следующее число) стека меняются местами (число становится верхним элементом). Если в стеке всего один элемент, поверх него записывается 0. -
:_
— если следующее число — 0 (или стек пуст), цикл прерывается. -
.
— следующее число выводится на печать (копия остается в стеке). -
блок
,,,,"! = "
— помещает в стек символы строки и сразу же их выводит. Строка проходится справа налево, но и символы выводятся от самого верхнего к нижним, так что для программиста строка выглядит так же, как на печати. -
.:*
— вычисляется новый факториал и выводится на печать (копия остается в стеке). -
,*25
— вывод перевода строки.
44* >:1-:v v ,*25 .:* ,,,,"! = ".:_ @
^ _ $1 > \: ^
Числа Фибоначчи:
Пример для версий befungee 0.2.0Используется итеративное определение чисел Фибоначчи.
В этом примере используются команды p
и g
, предназначенные для модификации исходного кода программы в процессе выполнения, — они записывают заданный символ в заданную клетку программы и считывают его оттуда в стек, соответственно. В данном случае это используется для хранения вычисленных чисел Фибоначчи (счетчик цикла все время хранится в стеке). При записи чисел как ASCII-кодов символов большие числа искажаются, поэтому выводятся только первые 13 штук.
031p132p 94+ > 31g 32g :. + 32g v
| :-1,,", "p23 p13 <
> "."::,,,25*,@
CamelCase:
Пример для версий befungee 0.2.0Программа реализует посимвольную обработку введенной строки. Код снаружи цикла 152p
записывает в ячейку программы (5,2) значение 1, соответствующее логическому true
— начало строки считается пробелом.
Основная часть программы — цикл. В одной итерации цикла считывается (~
) и обрабатывается один символ. Выход из цикла осуществляется, если ASCII-код введенного символа равен 10 (: 25*- #v_ @
), в противном случае указатель инструкций отправляется во вторую строку (команда v
). Если символ — буква нижнего регистра, он переводится в верхний — для единообразия последующей обработки (часть программы до первого квадратного блока и сам блок). Затем аналогичным способом проверяется, является ли символ буквой верхнего регистра. Если нет (переход в первую строку), в ячейку (5,2) снова записывается 1, символ удаляется из стека, и цикл заканчивается. Если да (переход в третью строку), выполняется еще одна проверка — на значение ячейки (5,2), в зависимости от которого символ остается собой или переводится в нижний регистр. Наконец, символ выводится, и цикл заканчивается.
152p > ~ : 25*- #v_ @ >48*-v >152p $ v
> :: "`"` \"{"\` * | > :: "@"` \"["\` * ! | > v
> ^ >52g | >052p,v
>48*+^
^ <
( )
|
was last character a space? (5,2)
Комментарии
]]>blog comments powered by Disqus
]]>