Как стать автором
Обновить

Комментарии 48

Универсальный DSL

Таки универсальный или specific?

Сам язык конечно же заточен под задачу, но движок универсален. Дефолтный язык движка может быть использован как есть, в качестве универсального инструмента, или для удобства сконфигурирован под конкретный синтаксис с некоторыми ограничениями
Да, оксюморон получается. Но, наверное, к форту вполне это определение подходит, сам форт язык универсальный, но программирование на нём обычно сводится к определению новых слов и конструкций, специфичных для решения конкретной задачи.
А при чем здесь тэг DSL. Это совсем из другой области.
Неплохо было бы дать определение этого термина: Предметно-ориентированный язык — domain-specific language (DSL).
Но всё же тэг DSL предполагает другое определение: digital subscriber line (DSL) — цифровая абонентская линия.
Поправил
кстати относительно digital subscriber line можно сказать точно так же, на хабре есть публикации с тэгом DSL и описанием domain-specific language
Это да). Форт древний и вездесущий, для .net их тьма реализована. У меня это 5 версия). Суть статьи скорее в популяризации и объяснении принципов утилитарного фортостроения. Тема форта в интернете не раскрыта, много кто этим занимается, а вот с публикациями и пошаговыми мануалами как оно работает и как реализовать с нуля совсем плохо. Достаточно материалов типа: «2 dup *. — вуаля», а вот как строить форты не особо. Лично мне в свое время пришлось собирать по крупицам знание как реализовать форт.
Не знаю что за фильтр на картинках, но печатаю вслепую(ослепшим) на данный момент.
В смысле? Картинки понравились?)
прошло минут 15, и до сих пор все плавает перед глазами( теперь термин «вырвиглазно» не столь философский как ранее казался
Интересная у вас реакция. А это на какую-то конкретную картинку? Фильтры везде разные.
Нее, я туда не вернусь..) Почти все
Из-за отсутствия избыточных конструкций всего несколько строк на DSL могут реализовать довольно сложный функционал, что приводит к положительным следствиям: увеличивается скорость разработки, сокращается количество ошибок, упрощается тестирование системы.

Все эти плюсы довольно мифические. Скорость, ошибки и прочее улучшаются только одним способом — нахождением общего решения проблемы и последующим программированием решения. Всё остальное — паллиатив.
Выход видится в создании DSL для построения DSL

Нет там выхода. Когда вы просто разделяете строку на слова, используя пробелы в качестве разделителя — это одно. Но когда вы пытаетесь понять, а потом исправить, всю ту галиматью, которую нарисовал вам юзер, и при этом не в виде строки с простейшими разделителями, а в виде очень нетривиальной структуры данных (да, предметная область такая), то одно вылавливание потенциальных ошибок юзера выливается в мега-квест, я уж не говорю про проблемы всей остальное работы со сложными структурами данных.

Тут либо всё упрощать, что сразу убивает предметную область (или по другому — делает DSL бесполезным), либо долго и нудно сочинять нечто сложное и по сути решающее задачу за пользователя.

Где-то посередине иногда можно найти приемлемые варианты, но это редкость. Если всё просто, то язык не нужен, легче всё подать в стандартном графическом стиле, а если сложно, то..., как бы это не было удивительно, всё именно сложно.

Хотя можно пообсуждать примеры реально используемых DSL. Правда всегда это использование очень узкое, никому кроме рассказывающего неизвестное.
Ну вот вам пример. Благодаря использованию DSL, разработка качественных настольных игр стала доступна даже школьникам. Что не замедлило сказаться на количестве разработанных игр.
Скорость, ошибки и прочее улучшаются только одним способом — нахождением общего решения проблемы и последующим программированием решения.

Не знаю что вы имеете ввиду под общим решением. Для целенаправленной разумной деятельности необходимо формирование в сознании модели явления или понимание. Для себя понимание определяю как выявление значимых связей явления и удержания их в сознании. У человека объем внимания ограничен, именно внимание отвечает за активацию смыслов, связей. Когда задача перестает помещаться единомоментно в сознании, тогда и происходит резкое увеличение количества ошибок и падает производительность. Здесь ключевым моментом является компактность представления знания. Чем больше букв, тем сложнее это удержать в сознании, консолидировать и оперировать. По вашей логике не важно на чем писать на ассемблере x86 или на Java, ведь есть общее решение, чтобы это не значило. На деле мы видим зависимость от уровня языка и производительностью разработки на нем. DSL априори более высокоуровневый по сравнению с языком общего назначения, позволяет бизнес логику описывать компактно. И как следствие то, что написано в статье.

Но когда вы пытаетесь понять, а потом исправить, всю ту галиматью, которую нарисовал вам юзер

По хорошему юзеру это понимать и исправлять. Вообще-то DSL не решает всех проблем, только помогает, компенсирует сложность, конечно даже на DSL можно описать крайне громоздкую и сложную логику, но на языке общего назначения та же самая логика выглядела бы еще хуже.

Конечно можно долго рассуждать имеет смысл вводить DSL или нет, но важно помнить, что лучшая проверка любой теории это практика.
>> Здесь ключевым моментом является компактность представления знания

Не компактность, а понятность. Это очень разные вещи. Компактность достигается выкидыванием из языка всех конструкций длиннее одной буквы, а понятность достигается структурой языка и форматированием. Вот последнее для некой предметной области будет либо очень нетривиальным, либо элементарным. Простые варианты банально вызывают некие библиотеки, которые и реализуют нужный функционал, но стоит захотеть расширить набор функций, как придётся всё реализовывать вручную на недо-языке. Если же мы встраиваем в язык возможности для программирования сложной логики, то сразу получаем относительно сложный для неподготовленного юзера универсальный язык программирования.

В целом дать пользователю какой-нибудь JavaScript и написать для него библиотеки будет много проще, чем возиться с DSL. Либо если по сути нужно заполнять какие-то шаблоны (выше пример с играми), то здесь вполне подходит обычное решение на GUI — просто собираем данные для шаблона и выполняем над ними необходимые действия. Сложной логики здесь никакой, а потому требования к пользователям низкие. Но если помимо шаблона нужна сложная логика игры — вот и приехали, придётся переходить на универсальный язык программирования.

>> На деле мы видим зависимость от уровня языка и производительностью разработки на нем

Уровень языка никак не относится к делению на DSL и универсальные языки. Это всё высокоуровневые языки программирования. Но в DSL обычно присутствует некий набор функций, характерный для предметной области. То есть отличие двух высокоуровневых языков, один из которых DSL, а другой — универсальный язык, состоит в том, что в DSL сразу присутствует специфический функционал, который в универсальном языке может быть добавлен в виде библиотеки, но отсутствует в дефолтной реализации.

>> По хорошему юзеру это понимать и исправлять.

Что бы юзер понял, ему нужно всё объяснить в знакомых терминах. Если ошибка будет выдаваться в виде «в строке Х около символа на позиции У присутствует синтаксическая ошибка», то юзер долго будет пытаться понять о чём вообще речь. Но даже при таком простом описании ошибок уже сложно как-то передать проблему в структуре данных, а не в синтаксисе. Например — в предметной области есть деревья, пользователь их описывает на DSL, с точки зрения синтаксиса всё корректно, но вот структура дерева кривая. Теперь вопрос — сколько видов кривизны структуры дерева может быть? Не отвечайте сразу, сначала добавьте в модель зависимости между узлами дерева, а потом попробуйте описать это всё коротко на DSL.

>> даже на DSL можно описать крайне громоздкую и сложную логику, но на языке общего назначения та же самая логика выглядела бы еще хуже.

Как раз наоборот. DSL не содержит никаких хитрых универсальных логических конструкций. Все хитрые универсальные логические конструкции давно включены в универсальные языки программирования. И если вам нужна именно сложная логика, то именно на универсальных языках она реализуется проще всего.

Либо вы путаете универсальную логику с заранее подготовленными решениями для конкретной предметной области. Тогда я выше уже говорил — на универсальном языке просто реализуем необходимые библиотеки и далее обеспечиваем к ним доступ пользователей. Доступ обеспечивается тремя способами — (1) обычный GUI, (2) DSL и (3) напрямую на универсальном языке. Способ №1 очень прост и давно отработан, но там сложно с добавлением логики, поэтому приходится делать решения со скриптовыми языками, имеющими доступ к введённым пользователем данным. Способ №2 отличается от №1 тем, что заставляет пользователя самостоятельно представлять в голове всё то, что в №1 ему даётся в GUI, а в остальном логика работает идентично, кроме чисто субъективных отличий DSL от скриптового языка. Ну и способ №3 отличается от №2 тем, что вообще нет необходимости делать ничего, кроме написания библиотеки. То есть способ №3 самый экономный. А раз уж мы знаем, что пользователь в любом случае будет учить язык программирования, то пусть уж учит универсальный и дёргает оттуда библиотеку.
Компактность достигается выкидыванием из языка всех конструкций длиннее одной буквы, а понятность достигается структурой языка и форматированием.

В целом дать пользователю какой-нибудь JavaScript и написать для него библиотеки будет много проще, чем возиться с DSL.

Ну смотрите, вы же наверняка использует регулярные выражения, конечно можно ту же логику описать на JavaScript, но так обычно не делают. На SQL web сервер не напишешь, но это мало кого беспокоит. Применение сценарных языков тоже имеет место, от DSL отличается тем, что последние описывают логику в терминах предметной области, за счет чего и достигает компактность и понятность(RegExp, SQL, awk, TeX, lex/yacc).

Очевидно, что можно найти ситуации когда dsl не подходит, так ни кто и не говорит, что нужно его везде применять. Нужно сохранять адекватность и действовать в соответствии со временем, местом и обстоятельствами. Хотя помню был(или есть) проект операционной системы, написанной на DSL. Для каждой задачи создавался DSL и на нем задача решалась, в результате исходник получился компактным и легко читаемым. К сожалению не помню названия и ссылки нет, попробую поискать.
Регулярные выражения это специфическая функция из предметной области «работа с шаблонами в произвольных последовательностях». То есть если стоит задача работать с последовательностями, то логично написать на универсальном языке некую библиотеку, которая и будет выполнять основные функции по работе с последовательностью. Далее эту функцию можно напрямую выставить в виде API в том же языке, на котором она разрабатывалась. Это просто, быстро, эффективно с точки зрения работы с дополнительной логикой, с которой универсальный язык легко справляется.

И второй вариант — сочиняем DSL. Ну вот сочинили, и прикрутили к нему всё ту же выше показанную библиотеку. Но в добавок сочиняем ещё и правила текстового взаимодействия с этой библиотекой. Ладно если почти весь требуемый функционал хорошо ложится именно на регулярки, но если где-то требуется слегка отличающаяся от шаблонов логика? Сразу получаем очень негибкое решение, нацеленное на очень узкую группу задач.

А теперь сравните затраты пользователей. Они учат какой-то новый язык (DSL), а внутри в любом случае учат эти самые регулярные выражения. То есть учатся два раза. И что мешает учиться сразу в сторону универсальности? То есть вместо DSL учим JavaScript. При чём не весь, а только простейшую логику — условные операторы, циклы, функции. А внутри пишем что-то вроде «var result=apply('[1-9,a-z]','Long string from our specific domain')». Можно написать это чуть короче на неком вымученном DSL, но зачем? Что это даст? Объяснить, что «сюда суёшь регулярку, а сюда последовательность» в случае того же JavaScript очень просто, так зачем тогда DSL? Что он даст пользователю?
И кроме того, универсальный язык уже дает готовые отладчики и прочие инструменты, включая хорошие сообщения об ошибках. Для DSL все это придется писать с нуля, и качеством оно будет явно хуже.

Поэтому в моей практике от чисто текстовых DSL никогда не было особого проку. Визуальные DSL — это интереснее, поскольку понятнее непрограммистам, плохо умеющим в абстракции.

Например, очень хорошо зашел DSL, выглядящий как таблица, нарисованная псевдографикой, — для выбора некоего значения в зависимости от условий.
Альтернативный вариант — использование макропроцессора поверх более универсального языка, как правило, интерпретирующего. Собственно, по классу грамматики (регулярная) Форт и макропроцессор эквивалентны.
Пример для SQL
Несмотря на простоту, в таком подходе есть свои недостатки, поэтому если ресурсы позволяют, то я предпочту написать транслятор КС-грамматики и стековую виртуальную машину исполнения (а ля Форт, кстати).
У форта неограниченная грамматика: все части форт-системы (даже такие как интерпретатор и компилятор) являются самыми обычнымм определениями на равне с другими форт-словами и могут быть изменены, переопределены и вызваны в любой момент, также исходный текст программы и состояние интерпретатора доступны прямо во время исполнения для чтения и изменения. Возможно придумать любой синтаксис на какой только хватит фантазии программиста и памяти системы.

Например здесь синтаксис зависит от введёного символа:
: PARSE&TYPE  ( c "ccc<char>" -- c-addr u )
    ." PARSED: " PARSE TYPE CR ;

: AAA ." AAA CALLED" CR ;
: BBB ." BBB CALLED" CR ;

\ ограничитель - символ '1'
.( TEST 1:) CR
CHAR 1 PARSE&TYPE AAA 1 BBB 2 CR

\ ограничитель заранее не известен
.( TEST 2:) CR
KEY PARSE&TYPE AAA 1 BBB 2 CR
.( TEST 3:) CR
KEY PARSE&TYPE AAA 1 BBB 2 CR

BYE

Try it online!


Форт также может быть сам себе препроцессором и так иногда делают, но часто проще сразу скомпилировать нужный код чем заниматься подстановкой текста.
Синтаксис Форта описывается регулярной грамматикой (отсюда простота разбора входного текста). Вы же говорите о семантике, а не о синатаксисе.
В форте семантика влияет на синтаксис. Форт не регулярный язык, его нельзя разобрать конечным автоматом.

Пример попроще:
( это комментарий, транслятор его игнорирует, а вернее это делает слово "(" )
: ( ;  \ переопределение слова "("
( такого синтаксиса для комментария у нас больше нет, никто ничего не пропустил, и интерпретатор попытается выполнить эти слова, и произойдёт ошибка)


Вы сможете описать это хоть какой-нибудь грамматикой?
Я же говорю, вы смешиваете синтаксис и семантику. Синтаксис по-прежнему простенький и разбирается КА или регулярными выражениями, а вот терминалы могут изменяться динамически по ходу трансляции. В макропроцессоре ровно все то же самое: можно переопределять символы до морковкина заговения. Если посмотреть на тонкие манипуляции с Си-шным препроцессором или с древним, но супермощным M4, то там подобной эзотерики очень много.
Синтаксис тоже может меняться в процессе трансляции Форт от потребностей и если дальше закрыть возможности доступа к Форт ядру, то мы и получаем произвольно созданный DSL поверх универсального Форт языка.

P.S. Разбирать синтаксис-семантику транслируемого начального кода потребуется, в этом случае, в рамках воссоздания понимания расширяемой Форт семантики и синтаксиса!
А, предыдущий пример, действительно достаточно прост для KA.

И, что в таком случае, понимать под терминалом для KA?

В Форт даже ввели термин XT — выполнимый токен, некая сущность (сопоставленная однозначно со словом при его поиске в словаре) которую можно выполнить например с помощью EXECUTE или использовать например сформировав их в массиве для доступа.
+ ещё разделили семантику СЛОВА на период компиляции и выполнения
и ввели слово POSTPONE <СЛОВО> (добавить к определению семантику времени выполнения слова) помимо уже ранее существовавшего исторически COMPILE, (помимо и других эффективных элементов языка, зря что ли Форт язык зачастую называют Форт-системой? :)

Те же EBNF есть и в реализации обычного синтаксиса Форт, но это никак не характеризует Форт в его уникальном дизайне как языкового инструментария.

Изменение синтаксиса это, например, если вместо слова PARSE&TYPE после каких-то переопределений можно будет писать PARSE AND TYPE, при этом это остается одним словом, а не тремя.
Из форт программы доступна вся форт система, соответственно можно написать ридер который анализирует хоть естественный язык и в стихах описать GUI, потом опять вернуться к форту. Причем это будет цельный и монолитный листинг. Понятно, что так вряд ли кто-то будет делать, хотя это технически возможно. Кстати есть проект по реализации AI на форте, называется MindForth, по этой теме можно много интересного материала нагуглить.
Зачем расширять тему? Мы говорим о конкретных вещах: лексический/синтаксический анализатор (семантический опускаю) и генератор кода для подсистемы исполнения (runtime VM). Если вы утверждаете, что синтаксис меняется по ходу исполнения, то соответствующий анализатор тоже должен меняться. Вот собственно и все.
Конечно можно, почему нет? Судя по всему вы спорите о том, чего не знаете.

Как я уже сказал, в форте есть полный контроль над разбором текста прямо во время этого самого разбора, это слова:
  • SOURCE — адрес и длина текущей интерпретируемой строки;
  • >IN — переменная (доступна и для чтения и для изменения) хранящая смещение первого непросмотренного символа от начала строки;
  • REFILL — прочитать следующую строку из входного источника.


Мне кажется уже этого достаточно для того, чтобы придумать синтаксис какой только в голову взбредёт.

В добавок есть слова для парсинга: WORD PARSE
для создания словарей: WORDLIST VOCABULARY
для поиска слов: FIND SEARCH-WORDLIST
для управления контекстом поиска: GET-ORDER SET-ORDER ALSO ONLY PREVIOUS
В свою очередь я должен спросить, уверены ли вы, что знаете про синтаксис и грамматики? Если грамматики нет, то что разбирает анализатор?
Граматики Форт «нет» (хотя есть договорённости по соглашениям взаимодействия Форт-слов в стандартах языка — что то подобие распределённого компилятора-транслятора, а то как бы в Форт возможно было бы использовать высокоуровневые управляющие конструкции), ровно до того момента, когда её захочется использовать.

Как пример разбора Паскаль синтаксиса Форт-словами Let's Build a Compiler и при этом перекомпилировать ядро Форт-системы нет необходимости, чтобы загрузить (как «плагин» на языке Форт), необходимый лексикон слов для этого.

P.S. Не совсем могу понять, какую мысль в своих сообщениях, относительно Форт или нет пытаетесь донести.
То, что можно взять (переключится на) соответствующий специализированный транслятор-компилятор при работе с отличным от Форт синтаксисом? Да, с определёнными накладными расходами можно, а можно то же самое осуществить в рамках самого Форт языка сделав соответствующее расширение (или также отдельный транслятор-компилятор).
Есть и Форт расширения по пониманию в рамках Форт языка и обычных формул и ООП и преобразований C->Forth, Forth->C…

Можно даже, в рамках какого то приложения (инструментария) написанного на произвольном языке — внутрь его добавить Форт. :)

COMPARE слово тоже есть.

mail.ru счётчик популярности-активности посещений рускоязычного Форт форума. (понимаю, что информацию в IT «анализируют» не только рускоязычные счётчики)
Ну, понятно. Грамматики нет, а синтаксический разбор, причем базового уровня (КА без МП или регулярные выражения) есть.
Не совсем могу понять, какую мысль в своих сообщениях, относительно Форт или нет пытаетесь донести.

Вы знакомы с теорией формальных языков?
А стоит ли теорию формальных языков применять к форт? В языках типа Си, phyton, js и др. грамматика задана и не может быть изменена. В форте грамматика есть, но она не постоянная, что не ложится на теорию формальных языков. По ходу интерпретации программы грамматику можно изменить, поэтому можно сказать что ее нет совсем. Конечно можно придумать автомат описывающий форт, но это и будет реализация форта, разве нет?
А стоит ли теорию формальных языков применять к форт?

Его транслятор же как-то работает?
Грамматика у него простая как три копейки: программа состоит из слов, которые следуют друг за другом. БНФ можно написать двумя правилами.
Интерпретация слов и всё, что Вы можете изменить — это уже более высокий слой абстракции. Не грамматика, как её понимают в теории формальных языков.
Именно это пытается донести cross_join
Грамматика у него простая как три копейки: программа состоит из слов, которые следуют друг за другом.

Про любой язык можно сказать, что программа на нём состоит из лексем (слов) следующих друг за другом. ;)

Например есть слова которые начинают какую-либо конструкцию и сответствующие им завершающие слова, типа : NAME ... ;, CODE name ... ENDCODE и управляющие конструкции, разве они в совокупности не образуют синтаксические конструкции?

В добавок и лексическое строение в виде слов, разделяемых пробелами, нарушается уже стандартными словами для строковых литералов, комментариев и т.п. слов, захватывающих произвольную часть исходника, что уж говорить о пользовательских словах.
Про любой язык можно сказать, что программа на нём состоит из лексем (слов) следующих друг за другом.

Но в случае Форта — это действительно так и есть. Потому что всё более сложное в нём вынесено на уровень интерпретации.

Ну а особое управление комментариями — не новость в мировой культуре.
Весь вопрос лишь только в том, на каком уровне понимания Форт-системы появляется «грамматика» языка. :)

Cогласно следующей схеме (немного другое изображение приведённой в статье диаграммы) базового цикла транслятора Форт-системы,

image

на данной схеме вообще нет никакой информации по граматике языка. Есть только поиск СЛОВ в текущем контексте словарей, анализ признаков найденных СЛОВ ( IMMEDIATE -активное слово для немедленного выполнения, остальные компиляция, если режим компиляции или интерперетации при выполнении.) не нашли СЛОВО, пробуем его понять как число и если успех кладём его на стэк, или напечатать при соответствующем состоянии системы, иначе ошибка.
Всё!
Вся остальная специфика СЛОВ языка оговаривается в стандарте или Сам разработчик определяет из своих предпочтений и.др., но обычно с определёнными следованиями уже существующими решениями дизайна Форт-систем. Даже в выборе названий СЛОВ, не достаточно употребимых, могут быть отхождения по их семантике.

Подход с КА при этом должен будет учитывать специфику заложенную в Форт-языке и не будет никак проще приведённой выше картинки работы транслятора Форт-языка.
В этой схеме даже не специфицированы детали поиска слов в Форт-системе, который отдаётся на «откуп» разработчику инструментария.

P.S. Дальнейшее «само-раскручивание» Форт-системы происходит на уровне построения вариантов внутренней структуры Форт-системы (как разновидности шитого кода или нативного построения СЛОВ Форт языка, здесь же могут быть проведены и какие то оптимизации)
Это уровень «кухни» Форт-системы, обычно скрывается внутри Форт-системы, но пишется зачастую или на ассемблере или на Форт. Наиболее проста, конечно, классика Форт-систем при использовании механики шитого кода.

т.е. подытоживая формальная теория языков программирования, в общем варианте, не сможет понять логику «право-применения» найденного слова периода исполнения и компиляции сформированную программистом.
Типа даже гипотетически Форт конструкцию CREATE… DOES>

А формальное знание факта, что в начальной основе языка лежат СЛОВА разделённые пробелом, формально же даёт возможность проверки на общность Форт-систем правилам данной граматики, но не более, т.к. должны быть и более значимые результаты сего формализма.

image :)
Здесь, среди прочих книг по Форту, есть книга за авторством С.Н.Баранова Н.Р. Ноздрунова «Язык Форт и его реализации» (может помочь в понимании, например, как построена amForth система для AVR и других Фортов для контроллеров реализующих шитый код)
понимания Форт-системы появляется «грамматика» языка

Что значит «появляется»? Она была использована на этапе разработки форт-системы. В этапах же работы оной — она не «появляется».

А Вы опять смешиваете всё в кучу, как философ, честное слово.
Примерно это подразумевается под словом «появляется».
Обрабатываем данные встроенные в исходник Форта
Скрытый текст
VARIABLE aDump
VARIABLE Length
: >DI 
        0. BL WORD COUNT >NUMBER 2DROP D>S ( DUP . BL EMIT )  
;
: dump-read? HERE aDump ! BASE @  
    CR HEX 0x401000
    BEGIN
	REFILL
    WHILE
             >DI OVER - ?DUP IF DUP ALLOT + ( DUP . KEY DROP ) THEN \ PLACE
             >DI C, >DI C, >DI C, >DI C, >DI C, >DI C, >DI C, >DI C, 
             >DI C, >DI C, >DI C, >DI C, >DI C, >DI C, >DI C, >DI C,
           BL WORD DROP ( COUNT TYPE CR )
        0x10 + 
    REPEAT
    ." length ="  0x401000 - .
    HERE aDump @  - DUP .  Length !  
    BASE !
    aDump @ Length @ DUMP
;
HEX
dump-read?
00401000  28 10 00 00 00 00 00 00  00 00 00 00 48 10 00 00  (...........H...
00401010  38 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  8...............
00401020  00 00 00 00 00 00 00 00  5C 10 00 00 6C 10 00 00  ........\...l...

Тыц

При запуске данный пример выведет в консоль встроенные данные в файле (перехватили управление в Форт исходнике входным потоком — обработки данных добавленных в файл) Структура данных при обработке может быть произвольно сложной.

Граматики Форт «нет»

"Грамматики нет" — это и значит "грамматика тривиальна". Т.е. любая программа на форт — это просто линейная последовательность терминальных токенов. При этом терминальным токеном является любой символ, а любая последовательность символов — корректной форт-программой. нетерминалов же в грамматике форта не существует.

На самом деле, грамматика языка, в котором процедура, может читать входную строку дальше и обрабатывать прочитанное по своему, не поддаётся формализации.

Кроме Форта и Лиспа еще есть Ребол.
REBOL умер же, к нему на смену пришёл Red. Правда ещё немножко недопиленный.
Спасибо за ссылку на мое описание форт-машины, но она была бы неполной, если не добавить к ней вторую, высокоуровневую, часть: rigidus.ru/lrn/forth/jonesforth-2.html
Вам спасибо, добавил ссылку.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий