Хотите довести до дурки любимого преподавателя компьютерных наук или навсегда прослыть «особенным» среди коллег сразу после (немедленного) увольнения?
Читайте ниже про патентованный метод.
Что это за дичь
Ладно, допустим вы не имеете прямого отношения к ИТ‑индустрии или не занимаетесь непосредственно разработкой ПО.
Возможно вы начинающий веб‑разработчик, умеющий (пока) только в лендинги и сайты‑визитки — словом вы никогда прежде не слышали о экзотерических языках программирования и об их ярчайшем представителе:
Brainfuck — один из эзотерических языков программирования, придуман Урбаном Мюллером (нем. Urban Müller) в 1993 году, известен своим минимализмом. Название языка можно перевести на русский как вынос мозга, оно напрямую образовано от английского выражения brainfuck (brain — мозг, fuck — вынос), т. е. заниматься ерундой. Язык имеет восемь команд, каждая из которых записывается одним символом. Исходный код программы на Brainfuck представляет собой последовательность этих символов без какого-либо дополнительного синтаксиса.
Понимаю, тяжело сразу воспринять фразу «экстремальный минимализм» по отношению к языку программирования, поэтому вот небольшая иллюстрация:
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]
<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.>++++++++++.
Да это исходный код. Еще это запредельный треш и ужас, созданный специально для выноса мозга программистам:
>++.
в ячейке 1 добавление 2 к 70 и вывод на печать ASCII-кода 72, т.е. буквы «Н».
>+.
в ячейке 2 добавление 1 к 100 = 101, печать буквы «e»
+++++++..
в этой же ячейке добавление 7 к 101 = 108, печать «l» дважды
+++.
в этой же ячейке добавление 3 к 108 = 111, печать «o»
И так далее и тому подобное:
Brainfuck почти не используется для практического программирования (за исключением работ отдельных энтузиастов), а используется преимущественно для головоломок и задач для соревнований.
Вот вам обучающее видео, для большего погружения:
Теперь (если вы занимаетесь разработкой и более‑менее подкованы) — вернитесь обратно к скриншоту в начале статьи и задумайтесь что именно автор для вас приготовил:)
Транспилеры, интерпретаторы и компиляторы
Минутка матчасти, прежде чем мы с вами погрузимся в адскую бездну разработки, для лучшего хоть какого-то понимания темы.
Начнем с транспилера:
A source-to-source translator, source-to-source compiler (S2S compiler), transcompiler, or transpiler is a type of translator that takes the source code of a program written in a programming language as its input and produces an equivalent source code in the same or a different programming language. A source-to-source translator converts between programming languages that operate at approximately the same level of abstraction, while a traditional compiler translates from a higher level programming language to a lower level programming language.
Максимально упрощая, можно сказать что транспилер — такой специальный компилятор, для превращения исходного кода на одном языке в исходный код на другом языке.
Очень часто используется на практике, в том числе в современных и сверхпопулярных языках вроде Java или.NET.
Чаще всего такую технику применяют для выдачи «желаемого за действительное», например с помощью транспилера реализованы генерики и замыкания в Java.
Теперь про интерпретатор:
In computer science, an interpreter is a computer program that directly executes instructions written in a programming or scripting language, without requiring them previously to have been compiled into a machine language program.
По‑сути это такой «гастробайтер от мира ПО», который сам ничего не умеет кроме махания метлой, но зато отлично выполняет последовательные команды.
И наконец «его величество» компилятор:
In computing, a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language). The name «compiler» is primarily used for programs that translate source code from a high-level programming language to a low-level programming language (e.g. assembly language, object code, or machine code) to create an executable program.[1][2]
Да это «та самая программа с помощью которой создаются другие программы», в изначальном смысле этого слова.
Практически любой компилятор — очень сложно устроенная программа, даже просто использование которой требует определенной подготовки. А задача создания компилятора с нуля — предмет для изучения в высших технических заведениях и удел исключительно опытных профессионалов.
Теперь совместите в вашем воображении безумный эзотерический язык программирования и связку из транспилера и компилятора — для запуска и демонстрации.
Объясню чуть подробнее:
программировать на самом Brainfuck безумно тяжело и ничего дальше «Hello, World» у вас не выйдет
пока вы не рехнетесь, но вот если использовать транспилер, — становится возможно писать код уже на Си (или Си‑подобном языке) и гораздо более интересные вещи.
Например можно взять ваше домашнее задание по числам Фибоначчи:
include "std.bfx"
function main()
{
prints("f[0] = ");
let a = scand();
prints("f[1] = ");
let b = scand();
prints("Up to n = ");
let n = scand();
prints("0: "); printd(a); endl();
for (let i = 0; i != n - 1; ++i)
{
printd(i + 1); prints(": ");
printd(b); endl();
let tmp = b;
b += a;
a = tmp;
}
printd(n); prints(": ");
printd(b); endl();
}
И сдать его в таком виде (фрагмент):
>>>[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>[-]++++++++++++++++++++++++++++++++++++++++++++++++.>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>[-]++++++++++++++++++++++++++++++++.>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>[-]++++++++++++++++++++++++++++++++.<<<[-]+>>[-]>[-]>[-]+>[-]+>[-]+>[-]>[-]>[-]+>[-]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>[>>>>>[-]>>[-]>[-]<<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<<[-]>>>[-]<<<<<[>>+>>>+<<<<<-]>>>>>[<<<<<+>>>>>-]<<<[>[<<[-]+>>[-]]<[-]]>>>>[-]>[-]<<<<<<[>>>>>+>+<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]>[-]+>[-]>[-]<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<[-]>[-]]<<<[>>>>>[-]>>[-]>[-]<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>+>+<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>-]<<[-]>>>[-]<<<<<<<<<<<<<<<[>>>>>>>>>>>>+>>>+<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>-]<<<[>[<<[-]+>>[-]]<[-]]>>>>[-]>[-]<<<<<<[>>>>>+>+<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]>[-]+>[-]>[-]<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<[-]>[-]]<<<[>>>>>[-]+>[-]+>[-]>>[-]>[-]<<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<<[-]>>>[-]<<<<<[>>+>>>+<<<<<-]>>>>>[<<<<<+>>>>>-]<<<[>[<<[-]+>>[-]]<[-]]>>>>[-]>[-]<<<<<<[>>>>>+>+<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]>[-]+>[-]>[-]<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<[-]>[-]]<<<[>>>>>,>[-]>[-]<<[>+>+<<-]>>[<<+>>-]<<<<<<<[-]]>>[[-]]<<<<<<<<<[-]>[-]>>>>>>>>>>>>[<<<<<<<<<<<<<+>+>>>>>>>>>>>>-]<<<<<<<<<<<<[>>>>>>>>>>>>+<<<<<<<<<<<<-]<<<<<<[-]]>>[[-]]>>>>>[-]>>[-]>[-]<<<
Полный вариант занимает ~1.6Mb одной строкой, представляте как обрадуется любимый преподаватель такой оригинальной работе?
Главное чтобы вас потом не нашли.
Гримуар
Поскольку программисты по большей части ребята «особенные», оказалось что для языка Brainfuck реализовано очень много всякого разного и интересного. Ниже будет небольшой обзор самых отбитых инструментов, которые мы и будем использовать во имя Луны для тестового проекта.
Bfpy
Автор этого замечательного проекта объявил личный джихад здравому смыслу:
BFPY is an alternative Python runtime that uses Brainfuck as a bytecode.
Для тех кто еще не оценил всю мощь по одной цитате выше, приведу небольшой пример кода:
#!/usr/bin/env python3.4
# coding: utf-8
from bfpy.instruction import Instruction
from bfpy.bytecode import Bytecode
from bfpy.machine import Machine
def test(x,y):
return x + y
def main():
bc = Bytecode.from_function(test, x=40,y=2) #42
print(bc)
vm = Machine(bc)
vm.run()
print(vm.current)
if __name__ == '__main__':
main()
Вот так это выглядит в работе:
Теперь немного разберем логику, для лучшего понимания. Вот эта замечательная строка генерирует код Brainfuck из байткода Python(!):
bc = Bytecode.from_function(test, x=40,y=2) #42
Что вы и видите на скриншоте выше, вывод на печать делает данная инструкция:
print(bc)
Дальше этот блок интерпритирует код на Brainfuck и выводит на печать:
vm = Machine(bc)
vm.run()
print(vm.current)
Вся эта радость отлично встраивается например в Python‑скрипт работающий с нейросетями, тем самым добавляя новую грань смысла слову «blackbox», которым так любят прикрывать свои провалы ML‑разработчики.
К сожалению этот проект очень далек до завершения:
For instance, BFPY can only translate arithmetic operations (addition, subtraction, multiplication, floor division and power). There is still a lot of features to implement for it to be a proper Python runtime alternative
Поэтому если у вас есть лишний $1млн и ненависть к человечеству — можете проинвестировать в этот замечательный проект. Деньги пойдут автору на лечение в лучшей дурке.
Brainfix
Следующий проект зашел немного дальше в своем безумии, поэтому именно с его помощью мы с вами и сделаем тестовое приложение:
BrainFix is a compiler/language that takes a C-style language (although the syntax slowly evolved to something very close to Javascript for some reason) and compiles this into BrainF*ck, an esoteric programming language consisting of only 8 operations.
Забираем исходный код и пробуем собрать:
git clone https://github.com/jorenheit/brainfix
cd brainfix
make
К сожалению при сборке появится такая ошибка:
Чтобы ее исправить достаточно закомментировать условие выбора:
ifeq ($(GAMING_MODE_AVAILABLE),1)
Результат должен быть таким:
CC=g++
CFLAGS= -c -O3 -Wall --std=c++2a -fmax-errors=2 #-Wfatal-errors
SOURCES=interpreter/bfint.cc interpreter/main.cc
OBJECTS=$(SOURCES:.cc=.o)
EXECUTABLE=bfint
all: $(SOURCES) $(EXECUTABLE)
#ifeq ($(GAMING_MODE_AVAILABLE),1)
#$(EXECUTABLE):$(OBJECTS)
# $(CC) $(OBJECTS) -o ../$@ -lncurses
#
#.cc.o:
# $(CC) $(CFLAGS) -DUSE_CURSES lt; -o $@
#
#else
$(EXECUTABLE):$(OBJECTS)
$(CC) $(OBJECTS) -o ../$@
.cc.o:
$(CC) $(CFLAGS) lt; -o $@
#endif
После правки сборка успешно завершается:
В результате сборки в корневом каталоге появится готовый бинарник bfx, запускаем:
Пробуем собрать тестовый пример:
./bfx -o program.bf -O1 -I ./std -t int16 bfx_examples/hello.bfx
Вот так выглядит результат:
Для проверки корректности, вставляем полученный код Brainfuck в онлайн-интерпретатор:
Там еще много интересных примеров, но большие программы будут ощутимо долго компилироваться в код Brainfuck, имейте ввиду.
Но это еще далеко не конец.
BFC
Как лаконично описывает свой проект автор: «an industrial‑grade Brainfuck compiler» и он при этом совсем не врет:
bfc includes an extensive range of optimisations. This page discusses the techniques used, and gives examples of BF programs that are transformed in each case.
Написана эта штука разумеется на Rust (неужели вы сомневались?) и сейчас мы будем ее использовать.
Забираем исходники:
git clone https://github.com/Wilfred/bfc.git
Собирается вот такой командой:
RUSTFLAGS='-L /usr/local/lib' cargo build --release
Поскольку дело происходит на FreeBSD (неужели я забыл об этом упомянуть?), с помощью переменной окружения RUSTFLAGS необходимо указать путь /usr/local/lib, который почему‑то не учитывается сборщиком cargo. Также на машине должен быть сам Rust и 14я версия LLVM.
Зато теперь вы тоже знаете как использовать Rust на FreeBSD, надеюсь эти знания помогут вам построить успешную карьеру в ИТ-индустрии
а не наставят на путь экстремального терроризма.
В результате успешной сборки в каталоге ./target/debug
появится готовый к использованию бинарник bfc:
Что же мы будем делать с оптимизирующим компилятором Brainfuck?
Разумеется использовать для всего хорошего и замечательного:
./target/release/bfc /opt/work/tmp/brainfix/program.bf
Это тот самый пример с «Hello world!» сгенерированный выше из С‑подобного кода, который с помощью замечательного оптимизирующего компилятора превратился в настоящий бинарник:
Итого
Повторим еще раз всю цепочку для лучшего запоминания:
Код на С‑подобном языке → транспилер Brainfix → компилятор Bfc → готовый бинарник
В чем отличие от обычной разработки:
Вы спокойно сдаете
в качестве лабыкод на Brainfuck, который будет компилироваться в запускаемый бинарник и вполне себе подпадать под термин «исходный код».
Разумеется ваш любимый преподаватель будет в полном восторге, пытаясь в этом коде разобраться а вы никаких сложностей даже не увидите, поскольку настоящий код с читаемой логикой останется на уровне транспилера.
Правда весело?
Из-за таких милых шалостей мои бывшие преподаватели до сих пор меня помнят и резко бледнеют услышав фамилию.
Ну а если вас попросят написать тестовое задание, с дуру вставив в постановку фразу «на любом известном вам языке программирования» — теперь вы знаете как и на чем его сдавать. Работу вы врядли получите, зато повеселитесь от души.
P.S.
Это сильно отцензурированная версия статьи, трешевый оригинал которой доступен в нашем блоге.
Само собой вся изложенная информация приведена исключительно в развлекательных целях, не стоит применять подобные технологии на практике в реальной жизни.
Но если так вышло что подобные методы применили против вашего проекта или компании — пишите и мы поможем.
0x08 Software
Мы небольшая команда ветеранов ИТ‑индустрии, создаем и дорабатываем самое разнообразное программное обеспечение, наш софт автоматизирует бизнес‑процессы на трех континентах, в самых разных отраслях и условиях.
Оживляем давно умершее, чиним никогда не работавшее и создаем невозможное — затем рассказываем об этом в своих статьях.