← На главную

Даг Хойт сделал не‑Flub Forth поверх Flub на макросах Common Lisp

26.07.2026 17:37 · hackernews

Даг Хойт строит реализацию Forth на Common Lisp, используя исключительно макросы. Forth — язык, который Чак Мур создал для собственных задач в астрономии и проектировании железа, без академической или корпоративной поддержки. Он выглядит странно, но странность осознанная, как и в Lisp: она даёт управление компиляцией и метапрограммированием. В реализации Хойта ключевые абстрактные регистры машины Forth — pstack, rstack, pc, dict, compiling, dtable — хранятся в списке forth-registers. Два раздельных стека, параметров и возврата, сделаны через push/pop на cons-ячейках.

Словарь Forth — односвязный хронологический список структур forth-word со слотами name, prev, immediate и thread. Поиск слова ведёт функция forth-lookup: она идёт от последнего добавленного слова по указателю prev. Главная «фишка» — потоки исполнения, или threaded code. Вместо косвенного или прямого шитого кода Хойт вводит cons threaded code: каждый cons-узел содержит в car функцию, вложенный cons (вызов слова) или атом. Внутренний интерпретатор — макрос forth-inner-interpreter — разворачивается в цикл, который идёт по цепочке: если встречает функцию, выполняет её; если cons — сохраняет текущий pc в rstack и переходит по новому потоку; иначе атом кладётся на pstack.

Примитивы задаются через def-forth-prim, который помещает код в глобальный список forth-prim-forms. Обычный def-forth-prim сам продвигает pc вперёд, а def-forth-naked-prim оставляет это программисту. Восемь базовых примитивов (nop, *, drop, dup, swap, print, >r, r>) манипулируют стеками, не захватывая функций Common Lisp, потому что символы лишь метят записи в списке.

Вся среда собирается макросом new-forth. Он раскрывается в замыкание, построенное макросом alet: сначала связываются регистры, затем forth-install-prims вставляет код примитивов, после чего в окружение через funcall загружается стандартная библиотека из списка forth-stdlib. Само замыкание — plambda, pandoric-лямбда, которая экспортирует регистры наружу, позволяя, например, через with-pandoric читать pstack. Выполнять код удобно макросом go-forth: он оборачивает последовательность слов в вызовы замыкания.

Хойт подчёркивает: Forth не является Flub-языком — он не завязан только на подпрограммный шитый код (subroutine threaded code), в отличие от C или многих реализаций Common Lisp. Но макросы Lisp могут превратить Flub-реализацию в не-Flub, вернув контроль над компиляцией. Вводится понятие дуальности синтаксиса — способности менять форму кода, сохраняя суть, — и теория краткости: чем короче программа, тем меньше усилий на её написание, хотя настоящая сила макросов не в сжатии, а в возможности безболезненно перестраивать проект по мере понимания задачи.

Читать оригинал →