Отчасти, по этой же причине, возникли эзотерические языки программирования. Brainfuck, Befunge и прочие весьма хорошо разгружают мозг после умственной работы, да и просто позволяют интересно и с пользой провести время. Да, именно с пользой, ведь они развивают нестандартное программистское мышление, ставя его в сложное положение жестких ограничений возможностей языка, операторов, и, как правило, ужасного нечитабельного синтаксиса. Да, они неприменимы в реальной практике, но, тем не менее, большинство из них обладают тьюринговской полнотой, следовательно, вполне могут считаться полноценными языками программирования.
Кстати, в ближайшее время планируется серия постов по некоторым эзотерическим языкам.
Однако, в данный момент меня заинтересовало немного другое. Итак, многим из вас наверняка известен арифметический пакет dc, на всякий случай приведу цитату с википедии:
dc — пакет для арифметических вычислений с произвольной точностью в unix-системах. Обычно он оперирует в десятичной системе счисления с целыми числами, однако можно задать системы счисления для ввода и вывода, а также точность вычислений. Общая структура dc — стековый калькулятор, использующий обратную польскую запись.
В вышеприведенной цитате мы видим волшебное слово – стек. И да, действительно, в dc реализована полноценная стековая машина, с возможностью сохранения и извлечения значений из именованных регистров, условиями, переходами. Хм, а что нам мешает попробовать программировать на этом? Поехали! (© Гагарин Ю. Н.).
dc имеет ограниченный набор команд, перечислять их здесь не вижу смысла, желающие могут ознакомиться с ним все там же.
Итак, как уже было сказано выше, dc использует обратную польскую запись, что значит, что в отличии от привычной инфиксной записи, сначала задаются операнды, а потом операция для них. Парочка примеров обратной польской записи с указанием эквивалентных им инфиксных записей:
2 2 * <=> 2 * 2
5 3 7 + * <=> 5 * (3 + 7)
Думаю, все должно быть понятно.
Вы уже наверняка ознакомились по вышеприведенной ссылке с синтаксическими конструкциями dc. Нетрудно догадаться, что использование [...] совместно с sx, а в дальнейшем lx совместно с x, позволяет нам эмулировать поведение функций. Ну а параметры им можно передавать посредством помещения в стек.
Для выполнения приведенного в посте кода, достаточно в консоли набрать команду
dc -e «код»
Например:
dc -e «2 3^p»
В дальнейшем, буду приводить лишь код. Для удобства, дабы можно было разбивать код на логические блоки и комментировать его, где необходимо, буду приводить код в многострочном виде. Для его выполнения есть несколько способов:
dc -f «имя_файла_куда_сохранили_код»
- dc -e «2 \2 \+p»
И да, комментарии я буду оформлять в C-стиле – //. Они, разумеется, в код попасть не должны.
Итак, попробуем, для начала, написать что-нибудь простенькое. Например, выведем числа от 1 до 10.
- [ // начало цепочки символов
- lap // печатаем содержимое регистра a
- 1+sa // инкрементируем регистр a
- 10la!>f // сравниваем содержимое регистра a с 10,
- // если меньше или равно десяти - продолжаем выполнение,
- // рекурсивно вызывая на выполнение содержимое регистра f
- ]sf // конец символьной цепочки, помещаем ее в регистр f
- 1sa // задаем начальное значение регистру a
- lfx // выполняем содержимое регистра f
Небольшое примечание. Оператор “!>” эквивалентен “<=”, поскольку “!>” интерпретируется как “не больше”, а раз не больше, то меньше либо равно. В остальном же, все должно быть понятно из комментариев.
Инлайн версия:
[lap1+sa10la!>f]sf1salfx
Чуть усложним пример. Пускай верхнюю границу диапазона выводимых чисел задает пользователь. Таким образом, будем выводить числа в диапазоне [1..n], где n – число, введенное пользователем. Да, и добавим проверку: работаем только если n >= 1. Следует, конечно, вывести еще какое-нибудь сообщение об ошибке, но это сделаем чуть позже.
- [
- lap
- 1+sa
- lnla!>f // теперь сравниваем не с 10, а с содержимым регистра n
- ]sf
- 1sa
- ?sn // помещаем пользовательский ввод в регистр n
- laln!<f // если n >= a, вызываем f
Инлайн версия:
[lap1+salnla!>f]sf1sa?snlaln!<f
Таки добавим теперь обещанный вывод текстовых сообщений: приглашение к вводу верхней границы выводимых чисел и сообщение об ошибке (если n < a):
- [
- lap
- 1+sa
- lnla!>f
- ]sf
- [
- [Error! N must be greater or equal than a register value!]P
- 10P // перевод на новую строку (как мы помним, \n = 10)
- q // прекращаем выполнение
- ]se // «функция» вывода сообщения об ошибке
- 1sa
- [Enter max number for print: ]P // печатаем приглашение для ввода
- ?sn
- laln<e // если n < a, вызываем e
- lfx // успешно прошли предыдущую проверку, вызываем f
Инлайн версия:
[lap1+salnla!>f]sf[[Error! N must be greater or equal than a register value!]P10Pq]se1sa[Enter max number for print: ]P?snlaln<elfx
Ну, и напоследок, еще один пример. Пусть требуется вывести n первых чисел Фибоначчи, где n, как и в предыдущем примере, задается путем ввода пользователем и должно принадлежать диапазону [0..∞]. Задача поставлена, пишем.
- // функция вывода сообщения об ошибке (в случае, если n < 0)
- [
- [Error! N must be greater or equal than zero!]P10P // печатаем...
- q // … и выходим
- ]se
- // функция выхода
- [
- q
- ]sQ
- // выводит первое число Фибоначчи
- [
- 0p
- q
- ]sZ
- // выводит два первых числа Фибоначчи
- [
- 0p1p
- q
- ]sO
- // выводит [2..n] числа Фибоначчи
- [
- lfls+p // суммируем два предыдущих числа
- // и выводим результат
- // меняем два предыдущих числа
- lssf
- ss
- lc1+sc // инкрементируем счетчик
- lnlc<I // если не достигли n - рекурсивно вызываем I
- ]sI
- [
- // всякие условия, все очевидно
- 0ln=Q
- 1ln=Z
- 2ln=O
- 0psf
- 1pss
- 2sc
- lnlc<I
- ]sF
- [Enter the count of Fibonacci numbers to print: ]P // приглашение ввода n
- ?sn // считываем пользовательский ввод и сохраняем его в n
- 0ln<e // если n < 0, выводим соответствующее сообщение
- lFx // вызываем F
Инлайн версия:
[[Error! N must be greater or equal than zero!]P10Pq]se[q]sQ[0pq]sZ[0p1pq]sO[lfls+plssfsslc1+sclnlc<I]sI[0ln=Q1ln=Z2ln=O0psf1pss2sclnlc<I]sF[Enter the count of Fibonacci numbers to print: ]P?sn0ln<elFx
Магия, не иначе.
Тема программирования на dc, несомненно, будет продолжена мною, ибо интересна. В ближайшее время также ожидаются посты по эзотерическим языкам Brainfuck и Befunge. Совсем скоро…
Источник: Хабрахабр - Ненормальное программирование
Оригинальная страница: [Из песочницы] Программируем в dc (desktop calculator)
Комментариев нет:
Отправить комментарий