Идеи языка Форт

Эмблемка Forth

Идеи, положенные в основу языка Форт:

  1. Расширяемость и гибкость
  2. Простейший единообразный синтаксис
  3. Объединение среды разработки и исполнения программы в единой "виртуальной машине" с двумя режимами - компиляции и интерпретации
  4. Открытость компилятора для модификации программистом
  5. Компактное микроядро
  6. Независимость ядра от конкретной платформы

Если же попытаться выразить основную идею Форта одним предложением, то это на мой взгляд будет: максимальная расширяемость и гибкость. Остальные идеи - это уже скорее следствия ориентации на эту базовую линию.

Пишущий на Форте программист (далее "фортер") в результате решения конкретной прикладной задачи получает два продукта:

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

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

Такой идеологии разработки подчинены все остальные идеи Форта. Рассмотрим теперь их более подробно.

Расширяемость и гибкость. Язык Форт представляет собой набор слов-процедур. Все новые именованные объекты языка также представляют собой подобные слова, определяемые на основе уже имеющихся слов. Все слова в Форт-системе совершенно равноправны: как правило транслятор Форта не делает разницы между своими "родными" словами и словами, добавленными программистом. Причем, в Форте не существует ни одного ключевого или системного слова. В синтаксические конструкции языка входят традиционные для всех языков слова (IF, THEN, ELSE, WHILE, REPEAT, BEGIN и т.д.), но они не являются ключевыми и подчиняются общим правилам - они могут быть переопределены программистом и иметь любой смысл как в момент компиляции, так и в момент исполнения. Новые слова добавляются в общий древовидный словарь Форт-системы и могут на равных использоваться для определения других слов. Ядро Форта оперирует низкоуровневыми понятиями и ориентировано в основном на поддержку процесса расширения самого себя в любую предметную сторону. Это в чем-то напоминает разум маленького ребенка - он еще ничего не умеет, но самое главное "оптимизирован" на развитие и обучение. Добавляя новые слова в систему, программист обучает Форт новым понятиям и новым лексиконам, постепенно добиваясь ситуации, когда обученный предметной области Форт становится "профессионалом" в этой области и понимает "учителя-программиста" с полуслова. С другой стороны, это означает, что если программист толком не знает, что хочет добиться, то у него ничего и не выйдет - такому Форт покажется непробиваемым тугодумом...

Простой синтаксис. Можно сказать, что синтаксические правила Форта настолько просты, что практически напрочь отсутствуют. Исходный текст программы представляет собой последовательность слов, разделенных пробелами или переводами строки. И так же по одному слову Форт и поглощает этот текст для компиляции либо интерпретации (режим динамически переключается уже самими словами). Никакого "забегания вперед", синтаксического и семантического анализа транслятор Форта не производит. При жесткой необходимости это уже могут взять на себя сами слова входного потока. Т.е. вся власть отдана народу (словам), а руководство (транслятор) заботится лишь о том, чтобы давать этому народу пожить - берет их по одному, и транслирует. Транслятор Форта делает во время работы буквально следующее: берет строку из входного потока (из файла, либо с клавиатуры, как его частного случая), выделяет очередное слово до ближайшего пробела, ищет его в словаре уже имеющихся слов и транслирует. Когда строка кончается, берет следующую и делает с ней то же вплоть до исчерпания входного потока. Если слово в словаре ранее определенных слов не найдено и не опознано как литерал (число), то Форт выдает недоуменный вопрос, прерывает трансляцию и ждёт дальнейших распоряжений.

Вот реализация транслятора строки (здесь и далее примеры из СП-Форта 3.07):

:INTERPRET
 BEGIN 
    BL WORD DUP C@ \ выделяем слова, пока не исчерпаем строку 
 WHILE 
    FIND ?DUP \ ищем в словаре 
    IF
       STATE @ = \ в зависимости от состояния компилируем или выполняем 
       IF COMPILE, ELSE EXECUTE THEN 
    ELSE 
       ?LITERAL \ если не нашли, то проверяем "на литеральность" 
    THEN 
    ?STACK 
 REPEAT DROP 
; 

Разберемся в сущности трансляции, как её понимает Форт. Результатом поиска в словаре слова, выделенного из входного потока, является "выполнимый токен", на деле представляющий собой ссылку на ранее скомпилированный код этого слова (т.е. на тело процедуры с таким именем). Транслятор может сделать с найденным словом две вещи: либо немедленно запустить его на выполнение, прямо в процессе приема исходного текста программы (как поступают классические интерпретаторы), либо отложить его выполнение на будущее, скомпилировав вызов этого слова-процедуры в словарь (как поступают классические компиляторы). Что конкретно сделает транслятор, зависит от его текущего состояния: интерпретация либо компиляция. В состоянии интерпретации все найденные слова немедленно запускаются. В состоянии компиляции - компилируются вызовы этих слов. Запущенное на выполнение в режиме интерпретации слово может собственноручно переключить состояние транслятора (оно хранится в глобальной переменной) в режим компиляции, заставляя транслятор переводить весь последующий текст с языка Форт в машинный код (либо шитый код, либо в байт-код, либо любой другой, что зависит от конкретной реализации транслятора). Чтобы иметь возможность влиять на компиляцию (например выйти из режима компиляции) пришлось ввести одно исключение из правила трансляции в режиме компиляции: слова, имеющие призак немедленного исполнения (обычно флажок, связанный с этим словом в словаре), немедленно запускаются на выполнение независимо от текущего состояния транслятора. Именно так работает, например, слово IF - оно запускается в режиме компиляции и _само_ компилирует код условного перехода вслед за скомпилированными ранее вызовами слов, предшествующих IF в исходном тексте. На компиляторы других языков программирования возлагается обязанность выискивать в тексте ключевые слова, подобные IF, и обрабатывать их специальным способом. Транслятор Форта от такого бремени свободен и обрабатывает IF по тем же правилам, что и любое другое слово, а уж слово IF само вольно распоряжаться своим использованием. Программист может сам определить новый вариант IF, установить ему признак немедленного исполнения , и отныне Форт будет использовать его способ компиляции. Либо можно даже сочинить свои новые средства компиляции. Программисты, использующие С++, 10 лет ждали реализации конструкции выхода из цикла на метку (вместо break), и наконец дождались её... в языке Java. Если бы мне потребовалась такая конструкция в Форте (к слову, она мне не нужна :), я бы добавил её в Форт за 5 минут. Так же поступил бы любой другой фортер с любым транслятором Форта. Дело это тривиальное: реализация того же IF тоже уместится в одну строку программы на Форте:

: IF ?COMP HERE ?BRANCH, >MARK 1 ; IMMEDIATE 

Форт учится новым конструкциям с легкостью, причем обучается не транслятор (он все так же тупо берет слова, ищет и исполняет/компилирует), а некое "надтрансляторное существо", называемое словарем Форта. Это даже заставляет подозревать наличие у Форта чего-то вроде души. Повторюсь, что от рождения Форт, как ребенок, не умеет ничего, кроме обучения. И как ребенок накапливает и структурирует знания, поступающие извне (для Форта это поступающий извне поток слов).

Транслируемые слова настолько вольны в своем поведении, что даже могут отнимать у транслятора часть его работы - часть входного потока. Будучи запущенными в момент трансляции, такие слова могут "забегать вперед", выделяя последующие слова или даже строки как часть своих параметров. Можно даже рекурсивно вызывать транслятор и временно переключать входной поток на другой источник. Не запрещено ничего - транслятор считает, что программисту в любом случае виднее, что делать. Именно через "забегание вперед" реализованы слова для определения новых слов: они берут следующее слово из входного потока и добавляют его в словарь как имя нового слова. Слова для условной компиляции и комментариев также могут забегать вперед на несколько слов и строк. Переключение входного потока и вызов "вложенного" транслятора используется для реализации включаемых файлов. Таким образом вводятся элементы привычных синтаксических конструкций, но это нисколько не усложняет транслятор, а лишь добавляет знания в словарь.

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

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

Как уже упоминалось, Форт может принимать исходный текст как из файлов, так и с клавиатуры, и имеет режимы компиляции и интерпретации. Наличие режима интерпретации позволяет программисту сразу же протестировать только что скомпилированное слово в диалоговом режиме. Простота транслятора обеспечивает мгновенную инкрементальную компиляцию: уже отлаженный код можно сохранить в файле вместе со всей Форт-системой, и более не перекомпилировать его исходный текст, а запускать этот словарь и докомпилировать. (Программисты, писавшие на языках Lisp и Smalltalk, наверняка заметили тут знакомые черты - возможность сохранения словаря и диалоговой отладки; любопытно, что Lisp на 11 лет старше Форта, Smalltalk на 9 младше).

Другой особенностью Форта является нетребовательность к аппаратно-программному окружению. Полнофункциональные трансляторы Форта созданы практически для всех платформ, существовавших с конца 60-х годов по наши дни. Форт является единственным языком, стандартный транслятор которого можно реализовать на слабейших микроЭВМ (например, 8-разрядных с 16Кбайтами памяти) и при этом даже оставить место для экранного редактора исходных текстов (написанного на Форте), встроенного ассемблера (тоже написанного на Форте) и прикладной программы. Еще одно подтверждение аскетичности Форта - он может обходиться без операционной системы, являясь фактически удобной операционной системой для разработчика, работающей на любой платформе. У Форта существует даже стандартизированное раширение для работы с устройствами массовой памяти на поблочной основе, без организации файловой системы, служащее для переноса данных и текстов программ на предельно слабые аппаратные платформы. Как правило, в Форт-системах бывают и встроенные ассемблеры машинного языка (Форт-транслятор успешно обрабатывает при этом "чуждый" ассемблерный текст, который с его точки зрения является обычной Форт-программой - слова, слова, слова...).

Принятый в 1994м году очередной стандарт языка Форт значительно повысил "абстрагированность" языка от аппаратной платформы и операционной системы и позволил писать реально переносимые (на уровне исходных текстов) программы, использующие стандартные множества слов Форта. Сам по себе транслятор Форта пишется как правило на Форте и тоже может быть легко переносим между платформами. Исключение составляют самые низкоуровневые наборы слов, которые для повышения эффективности обычно пишутся на Форт-ассемблерах для конкретной архитектуры и не могут переноситься без изменений. Так при переносе СП-Форта с платформы DOS на платформу Win32 сохранено не менее 90% исходного текста Форт-системы.

Понятно, что при учете возможности работы на предельно слабых машинах, в Форте не стандартизированы и не могли быть стандартизированы средства программирования пользовательского интерфейса (кроме средств организации текстового диалога), в отличие от языков Smalltalk и Java. И хотя создание для Форта единого лексикона для организации графического интерфейса, одинаково функционирующего на различных графических платформах, не представляет существенной трудности, это врядли будет сделано в обозримом будущем, т.к. "география" форт-приложений намного шире парка настольных ПК...


Первая страница узла

Моя первая страница

Моя первая страница
Назад

Вперёд

© Андрей Черезов