FORTH: ЯЗЫК ХАКЕРОВ
Автор: Эллиот Уильямс
Translator: Bereg Oldmyth
Начнем с неоднозначного утверждения: Форт — это язык программирования для хакеров. Программирование на Форте немного похоже на интерактивное написание кода на ассемблере для странной архитектуры процессора, которой не существует. Форт — это виртуальная машина, интерпретируемая командная строка и компилятор в одном флаконе. И все это настолько просто, что может уместиться в нескольких килобайтах памяти. Если ваш код на языке Форт написан правильно, он читается как предложение на естественном языке, но для этого нужно решить небольшую головоломку.Forth - это то, что вы получили бы, если бы Python работал на языке ассемблера: интерактивный, выразительный и без синтаксического багажа, но все еще очень близкий к металлу. Это язык высокого уровня или язык низкого уровня? Да! Или, скорее, это кратчайший путь от одного к другому. Вы можете и должны заглядывать непосредственно в память в Forth, но вы также можете создать корпус высокоуровневого кода достаточно быстро, чтобы не возражать. На мой взгляд, такое сочетание живого программирования и близости к оборудованию делает Forth отличным инструментом для изучения новых микроконтроллеров или использования их в ваших проектах. На этом языке интересно писать уровень аппаратной абстракции.
Но Форт — это еще и хождение по канату: если Си дает вам достаточно веревки, чтобы повеситься, то Форт — это огнемет, кишащий кобрами. Здесь нет ни проверки типов, ни области видимости, ни разделения данных и кода. Вы можете делать ужасные вещи, например переопределить 2 как функцию, которая будет возвращать семь, и тогда ваша математика перестанет работать. (Но зачем вам это?) Вы можете легко перейти к некорректным участкам памяти и вызвать сбой системы. Вам нужно будет хорошо представлять, какие данные находятся в стеке в любой момент времени, иначе вы столкнетесь с проблемами. Если вы хотите, чтобы компилятор заботился о безопасности кода, обратите внимание на Rust, Аду или Java. Здесь вы этого не найдете. Форт — это простота и гибкость.
Простота и гибкость также подразумевают расширяемость. В большинстве систем Forth по умолчанию почти ничего нет. Например, если вам нравится объектно-ориентированное программирование, в Gforth есть не менее трех различных объектных фреймворков, и вы можете выбрать тот, который лучше всего подходит для решения вашей задачи или соответствует вашему стилю программирования. Вы можете модифицировать сам компилятор или интерпретатор Forth, так что, если вам нужна проверка типов, вы можете ее добавить. Некоторые реализации Forth написаны всего с двадцатью или тридцатью функциями на нативном ассемблере или C, а остальное реализовано на Forth. Faster Forths полностью реализован на языке ассемблера с некоторыми оптимизациями на этапе компиляции, благодаря чему он работает почти так же быстро, как и любой другой язык, даже несмотря на то, что компилируется по мере ввода на самом целевом микроконтроллере.
Форт, вероятно, не тот язык, который вам стоит изучать, если вы разрабатываете бэкенд для корпоративного банковского сервиса. С другой стороны, цепочка мигающих светодиодов, запускающая физическое моделирование, — это не «корпоративный» продукт. Форт — это язык хакеров, как в положительном, так и в отрицательном смысле. Я не уверен, что он вообще поможет вам в «настоящей работе», так что, возможно, вам, как инженерам, лучше уйти. Но если вы хотите доработать сам язык, или использовать его для управления оборудованием, или просто поиграть, то Forth — отличный выбор. Во мне говорит хакер, и я считаю, что это очень весело и идеально подходит для небольших проектов с микроконтроллерами.
Краткий курс по языку Форт: раздел теории
Форт — самый простой язык после ассемблера. Форт в высшей степени процедурный — программа на Форте на самом деле представляет собой цепочку подпрограмм, которые на жаргоне Форта называются «словами». Синтаксиса нет, все слова разделяются пробелами и анализируются слева направо. За исключением нескольких слов, используемых при компиляции, все слова выполняются прямо сейчас, поэтому интерпретатору Форта не нужно заглядывать вперед, чтобы понять, какое слово будет следующим. run this code!действует далее, если вы уже определили слова run, this и code! и оно вызывает каждое из трех слов в том порядке, который вы ожидаете.
Простота и обратная польская нотация
Следствием этой простой настройки является то, что Forth использует так называемую обратную польскую нотацию (RPN). Если интерпретатор Forth собирается выполнить + слово прямо сейчас, у него должны быть два числа, которые будут добавлены, уже в стеке. В противном случае ему пришлось бы ждать следующего числа, чтобы завершить сложение. Прочтите это еще раз и вдумайтесь. Это отличается от того, к чему вы привыкли, и это важно.
Любой другой порядок или синтаксис излишне сложен. То, что вы считаете «естественным» способом записи математических выражений, на самом деле является безумием в том смысле, что опережающий характер оператора + требует использования либо скобок, либо «порядка выполнения операций» для однозначности. Посмотрите на 2 + 3 * 4. В том, чтобы получить здесь 14, нет ничего естественного — это результат запутанного синтаксиса с неявными правилами. Сначала нужно прочитать все «предложение», найти *, запомнить, что оно имеет приоритет над +, сначала вычислить его, а затем вернуться к сложению, чтобы завершить операцию, даже если + — второе слово в предложении. Компьютер не хочет знать о «порядке операций», он просто хочет сложить два числа, желательно те, которые уже находятся в регистрах арифметико-логического устройства. Не верите? Посмотрите машинный код.
В Форте и обратной польской записи это записывается как 2 3 4 * + или 3 4 * 2 +. В любом случае оператор работает с теми числами, которые уже есть. Если вы не воспринимаете это как «обратную запись», «полировку» или даже «нотацию», то вы на верном пути. Вы просто записываете действия в том порядке, в котором они должны выполняться. (Разве это не безумие?!)
Мне нравится думать, что RPN — это вычислительный эквивалент mis en place; прежде чем приступить к готовке, нужно разложить все ингредиенты. Именно так работает код на языке Форт: get.broccoli chop.broccoli get.beef slice.beef get.oyster-sauce stir.fry Некоторые элементы взаимозаменяемы — можно взять и нарезать говядину до того, как будет готова брокколи, — но общий порядок важен для процедуры, и вам вряд ли захочется возвращаться к брокколи, пока говядина уже в воке. Но именно это вы и делаете, когда настаиваете на написании 3 + 4 вместо 3 4 +.
Компиляция и запуск
Новые слова определяются и компилируются с помощью : для входа в режим компиляции и ; для выхода из него. Компиляция, какой бы она ни была, происходит мгновенно. Интерпретатор Forth ищет каждое слово, которое вы используете в определении, и просто объединяет их в цепочку. Единственным исключением из этого правила является само имя функции, как вы сейчас увидите.
Скомпилируйте свое первое слово на языке Форт: : seven 3 4 + ;. Оно не очень полезное, но создает слово под названием seven, которое помещает в стек числа 3 и 4, а затем запускает слово сложения. «Результат» заключается в том, что теперь в стеке будет число 7, а не то, что было там раньше. Оптимизирующий компилятор Форта просто поместит в стек число 7.
Суть программирования в том, чтобы разбивать сложные задачи на фрагменты разумного размера. Понятие «разумного» размера зависит от языка, стиля программиста и духа времени. Выполнение слова в Форте требует гораздо меньше ресурсов, чем вызов функции в C, а следование логике длинного кода может оказаться сложной задачей даже для опытных фортеров, поэтому определения слов в Форте, как правило, очень короткие и обычно состоят из одной строки, включая комментарии. Вам придется часто компилировать код.
Стек
Сердце и душа языка Forth — это стек данных, или просто «стек». Forth — это язык, основанный на стеке, и пока вы не поработаете с ним какое-то время, вы не сможете в полной мере оценить, что это значит и как мысли о стеке начинают доминировать в вашей кодовой жизни. Слова в Forth не принимают аргументов и не возвращают значений, вместо этого они работают с любыми данными, находящимися в стеке на момент их вызова.
Начало FORTH
Стек — это лучшая и худшая часть языка Форт. Когда содержимое стека соответствует словам, которые с ним работают, получается невероятно красивый и эффективный код. Когда же они не совпадают, вы начинаете задаваться вопросом, не правы ли сторонники объектно-ориентированного программирования и не стоит ли все-таки связать данные с методами.
Хитрость программирования на языке Форт заключается в том, чтобы определить, что нужно поместить в стек, с помощью одного слова, и убедиться, что слово, использованное непосредственно перед этим, оставляет в стеке то, что нужно. В этом смысле программист на Форте определяет слова, но должен мыслить фразами, в которых содержимое стека сначала пустое, а в конце снова становится пустым. Это похоже на то, как в языке Си используется стек в области видимости функции: локальные переменные сохраняются только до тех пор, пока функция не завершит свою работу, а затем перезаписываются.
В качестве конкретного примера такой цепочки представьте слово gpio-set, которое устанавливает высокий уровень на выводе GPIO. Для выполнения этой задачи, скорее всего, потребуется указать и порт, и номер вывода. В Форти это можно реализовать следующим образом: определить слово для каждого вывода на плате, которую вы собираетесь использовать: : PA3 PORTA 3 ; Затем вы можете зажечь светодиод на выводе A3 с помощью PA3 gpio-set. В C сначала нужно определить структуру, включающую порт и номер вывода, а затем определить gpio-set для работы со структурой такого типа. В языке Форт это подразумевается: вы следите за тем, чтобы слова, отвечающие за работу с контактами, помещали номер порта и контакта в стек, а затем эти слова ожидали их появления. Это небезопасно, но зато просто.
Жонглирование стеком
Своп-своп, талисман Форта, из Starting FORTH
Самое ужасное в Форте — это манипуляции со стеком. Обычно люди начинают изучать Форт с манипуляций со стеком, и они действительно важны, но довольно тривиальны. Такие слова, как swap, drop, и dup позволяют перемещать элементы в стеке, но слишком большое количество «жонглирований стеком» в одном слове, скорее всего, говорит о плохом коде на Форте, а не о хорошем. Вы наверняка будете использовать эти слова, но не в них суть.
Скорее, стек — это место, где между этапами обработки находится минимальное количество данных. Разумеется, количество элементов должно быть достаточно небольшим, чтобы не исчерпать конечное пространство стека. Но вторая причина заключается в том, что вам просто сложно удерживать в голове слишком много элементов стека. По мере того как вы будете привыкать к языку Форт, количество элементов стека, которые вы сможете удерживать в памяти, может увеличиться с трех до пяти или семи, но если вы позволите стеку расти без ограничений, то запутаетесь.
Итак, Форт — это катастрофа. Это язык, в котором вам приходится самостоятельно управлять стеком, и единственная надежда не запутаться в бесконечных манипуляциях со стеком — делать все как можно проще. Сторонники Форта утверждают, что в этом и заключается его главное достоинство: нужно всегда стремиться к простоте и ясности, потому что в противном случае в ваш код проникнут ошибки, которые будет невозможно исправить, и вы сойдете с ума. Не знаю, то ли это стокгольмский синдром, то ли я в душе минималист, то ли мне нравится преодолевать трудности, но на самом деле это одна из причин, почему Forth такой классный.
Другие языки программирования позволяют работать с десятками переменных, потому что компилятор отслеживает различные области видимости и глубину каждой (локальной) переменной в стеке. В Форте такого нет. А это значит, что вам нужно думать о порядке выполнения операций. Форт заставляет вас самостоятельно выполнять оптимизацию, которую за вас сделал бы идеальный компилятор. Это может привести как к очень компактному коду, так и к головной боли. Все зависит от программиста и задачи.
По моему опыту, благодаря простому синтаксису, удобному для компьютера порядку и, как следствие, акценту на прозрачности и простоте, в Форте на удивление легко делать все правильно.
The Sweet Spot
Но хватит философствовать о Форте. Если вам это интересно, вы можете найти множество материалов на эту тему. (См. глоссарий ниже.) Есть три причины, по которым Форт сейчас интересен аппаратным хакерам как никогда. Первая причина заключается в том, что Форт был разработан для компьютеров конца 1970-х — начала 1980-х годов, а именно такой уровень мощности и сложности сейчас можно найти в каждом микроконтроллере за 3 доллара...