/
Author: Понятов Д.
Tags: программирование программное обеспечение языки программирования язык программирования фортран
Year: 2006
Text
FORTH
Spirit of Babylon
© RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
Содержание
1 Введение 5
1.1 версия 1 5
1.2 версия 2 6
1.3 О языке программирования Форт 6
1.4 Из [os] 7
1.5 Из [orange] 7
1.6 Из перевода [thinking] 9
1.7 © Ю. А. Семенов 9
1.8 © ИТФ Технофорт 11
1.9 Достоинства языка Форт (из [ans]) 12
2 История языка 13
2.1 Из [orange] 13
2.2 Из [ans] 15
2.3 Forth — The Early Years 15
2.3.1 Abstract 15
2.3.2 Forward 1999 15
2.3.3 Forth 15
2.3.4 MIT, SAG, 1958 16
2.3.5 Stanford, SLAC, 1961 17
2.3.6 Free-lance 18
2.3.7 Mohasco, 1968 19
2.3.8 NRAO, 1971 21
2.3.9 Moral 22
2.3.10 References 22
3 Основы языка 23
3.1 Учимся на практике 23
3.2 Форт-слово 26
3.2.1 Упражнения 28
3.2.2 Простая программа 29
3.2.3 Упражнения 33
3.2.4 Выводы 34
3.3 Что такое машинный язык ? 36
3.4 Что такое Форт ? Шитый код 38
3.4.1 Подпрограммный шитый код 39
3.4.2 Косвенный шитый код 39
3.4.3 Байт-код (свернутый шитый код) 40
3.5 Некоторая критика языка Форт 41
3.6 Стек 42
3.6.1 Что такое стек ? 43
3.6.2 Буфер ввода 43
3.6.3 Стек в арифметических операциях 44
3.6.4 Упражнения 46
3.6.5 Манипуляции в стеке 47
2
Содержание
3.6.6 Слово для просмотра содержимого стека 47
3.6.7 Слова для манипуляций в стеке 48
3.6.8 Упражнения 52
3.6.9 Выводы 53
3.7 Память, числа 53
3.7.1 Что такое память ? 54
3.7.2 Единицы измерения объема памяти 54
3.7.3 Системы счисления 55
3.7.4 Память Форта 55
3.7.5 Переключение системы счисления через переменную BASE 56
3.7.6 Упражнения 58
3.7.7 Выводы 58
3.7.8 Операции с битами 58
3.7.9 Упражнения 60
3.7.10 Положительные, отрицательные числа и числа без знака 60
3.7.11 Упражнения 62
3.7.12 Операции с байтами 62
3.7.13 Упражнения 63
3.8 Представление символьной информации 64
3.8.1 Кодировка текста ASCII 64
3.8.2 Ввод/вывод символов 65
3.8.3 Упражнения 65
3.9 Выводы 66
3.10 Арифметические операции 66
3.10.1 Операторы для работы с небольшими числами 67
3.10.2 Некоторые проблемы операции деления 67
3.10.3 Операции с величинами и знаками чисел 67
3.10.4 Почему используются целые числа ? 67
3.10.5 Масштабирование чисел 67
3.10.6 Числа двойной длины 67
3.10.7 Совместное применение чисел одинарной и двойной длины 67
3.10.8 trash 67
3.11 Хранение программ и данных 68
3.12 Методика программирования на Форте 68
4 Принципы работы форт-системы 69
4.1 Создание слов-определителей 69
4.2 Память Форта, словари и контекстные словари 69
4.2.1 Кодофайл 69
4.3 Интерпретация, компиляция и исполнение 69
5 Создание компиляторов и форт-систем 69
5.1 Создание собственных компиляторов 69
5.2 Целевая компиляция 70
5.2.1 Минимальный ЦК 70
5.2.2 Целевой компилятор для os 71
5.3 Как написать свой (кросс-)ассемблер 76
5.3.1 Введение 76
5.3.2 Зачем использовать ФОРТ ? 77
5.3.3 Простейший пример: ассемблирование NOP 77
5.3.4 Класс наследуемых опкодов 77
5.3.5 Обработка операндов инструкций 78
5.3.6 Обработка режимов адресации 79
5.3.7 Реализация структур управления 80
5.3.8 BEGIN, UNTIL, 81
5.3.9 BEGIN, AGAIN, 81
5.3.10 DO, LOOP, 81
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
Содержа,ние
3
5.3.11 IF, THEN, 82
5.3.12 IF, ELSE, THEN, 83
5.3.13 BEGIN, WHILE, REPEAT, 83
5.3.14 Заголовок ФОРТ-определения 84
5.3.15 Кросс-компиляция 84
5.3.16 Компиляция на диск 84
5.3.17 Безопасная компиляция 84
5.3.18 Метки 85
5.3.19 Табличный ассемблер 85
5.3.20 Префиксные ассемблеры 85
5.3.21 Вывод 86
5.4 Постфиксный форт-ассемблер для MCS-51 86
5.5 Реализация собственной форт-системы 86
6 Реализация ООП 86
6.1 Детальное описание mini-OOF 86
7 Плавающая точка 88
8 Сетевые протоколы 88
9 Операционная система os 88
9.1 О системе 89
9.2 Многослойная структура 91
9.2.1 Аппаратная платформа и ОС 91
9.2.2 Виртуальная машина (интерпретатор байт-кода) 91
9.2.3 Целевой компилятор 91
9.2.4 Библиотеки 91
9.2.5 Пользовательские расширения и прикладные программы 91
9.3 Архитектура ВМ 91
9.3.1 Память 91
9.3.2 Стек возвратов 91
9.3.3 Стек данных 91
9.3.4 Регистры 91
9.3.5 Стек циклов со счетчиком 91
9.4 Система команд 91
9.4.1 Базовые команды 92
9.4.2 Графический драйвер monoLCD 92
9.5 Библиотеки 92
9.5.1 Библиотека макросов 92
9.5.2 2D полноэкранная графика 92
9.6 Примеры программ 92
9.6.1 empty 92
9.6.2 blinker 92
9.6.3 liner 92
9.6.4 grdemo 92
9.6.5 pautov 92
9.6.6 cmdline
10 Заключение
10.1 Констактные адреса 92
10.2 Необходимый софт 93
10.3 Необходмые навыки 93
„ 04
Список литературы J
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
4
Содержание
Необходимо написание новой книги по языку — существующие книги давно устарели. Нужно
очень подробно, понятно и в то же время легко читаемо и без традиционной для российских книг
зауми (самый rulez в этом плане Броуди) описать сложные технологии форт-программирования:
написание ассемблеров, целевых компиляторов, форт-систем для специфических систем типа
самодельных компьютеров и промышленных контроллеров, парсеров и синтаксических анали¬
заторов, сложных расширений языка (например ООП), легко переносимых программ и т.д..
Также думаю стоит большое внимание уделить современным технологиям в железе, особенно
flcx-технологии "гибкой логики" с использованием ПЛИС (CPLD, FPGA) и систем на кристалле
(System on Chip, SoC).
Кто готов участвовать в проекте ? Не обязательно автором — нужны также самые начина¬
ющие для обкатки разделов начального обучения, рассказы о практическом применении форт-
тсхнологий.
Дслатся это все будет по той же лицензии, что и документация на Linux (вариант GNU GPL
для документации). Проект уже лежит в CVS, желающих участвовать в редактировании книги
welcome регистрироваться.
Группа SynergyOS давно предлагала создать CD с коллекцией материалов по Форту — думаю
он будет приложением к книге, там бу.нч коллекция форт-систем для нескольких ОС, снимок
этого сайта на момент выпуска диска, может быть фирмы, использующие Форт, тоже захотят
включить туда свои материалы (копии сайтов, оценочные версии ПО, прайсы и рекламные ма¬
териалы) .
Форт (С) RU FIG, Понятов Д.А. <forth<9km.ru> . public domain
версия 18 марта 2006 г.
1 Введение
5
1 Введение
1.1 версия 1
<forth@km.ru >
Язык программирования Форт1 широко известен многим современным хакерам, но не нашел
широкого применения на обычных компвютерах. Объясняется это достаточно просто: язык перво-
началвно был разработан как замена ассемблеру примерно в те же времена, что и язык C++2. Осо¬
бенности Форта — система строилась как языковая среда, включающая компилятор, редактор,
ассемблер, отладчик и средства операционной системы. Фактически классическая форт-система
является полнофункциональной ОС3 со встроенным компилятором и командной оболочкой.
Несмотря на то, что форт-система требовала очень мало аппаратных ресурсов (всего несколь¬
ко десятков Кб памяти), и язык достаточно полноценен, на обычных персоналках он большого
применения не нашел. Для начинающих программистов к сожалению выбрали BASIC, хотя Форт
еще проще и в то же время работает намного быстрее. Профессионалы предпочли использовать
С++, так как они изучали его при своем обучении, и решили что синтаксис Форта плохо читаем.
Основная сложность - язык Форт обладает уникальным свойством саморасширяемости, поэтому
для понимания исходных кодов чужих программ нужно понять, как автор программы расширил
язык.
Тем не менее во встраиваемых системах (системы управления различным оборудованием,
робототехника, бортовое и наземное оборудование в космических исследованиях NASA) Форт до
сих пор имеет достаточно широкое применение.
Если вы занимаетесь такими вещами как разработка различных цифровых систем и про¬
граммного обеспечения для них, вы можете столкнуться с ситуацией, когда вас не будет устра¬
ивать по каким-либо причинам обычно используемый в таких случаях инструментарий. Этими
причинами может оказаться его дороговизна, неудобство, отсутствие каких-либо утилит, или для
вашего железа не оказалось готовой ОС, компилятора и библиотек.
В этом случае хорошим решением может быть использование языка Форт в качестве мощного
макроассемблера или операционной системы.
К сожалению, последняя книга на русском языке вышла в 1993 году, существующей литерату¬
ры очень мало и она явно устарела. С другой стороны, в ней совсем нет примеров практического
использования Форта и сложных техник форт-программирования (целевой компиляции, ООП
расширений, написания ассемблеров, откомментированных исходников форт-систем для различ¬
ных платформ).
Очень часто возникают возражения типа "Форт слишком сложен в использовании", но он
проще чем ассемблер, который до сих пор используют очень част,о.
Цель написания этой книги — собрать разрозненную информацию по языку Форт и показать
как можно использовать этот язык в качестве мощного средства для создания программного обес¬
печения встраиваемых систем. Эта задача достаточно сложна, учитывая то что я нс форт-гуру,
но к сожалению гуру не хватает времени (а чаще желания) писать качественную документацию.
Надеюсь что они все же примут активное участие в написании этого руководства.
Буду очень рад, если кто-то захочет присоединится к работе над книгой: она изначально со¬
здавалась в on-line версии, для ее редактирования используется система управления контентом в
виде СУ34-сервера и простейшего скрипта, генерирующего сайт [akps]. Все мои работы по языку
также рассылаются через список рассылки comp.soft.prog.forth 5. Для работы над книгой необхо¬
димо участие начаинающих осваивать язык для обкатки учебных разделов, людей использующих
или наоборот не использующих Форт по каким-то причинам для написания разделов по практи¬
ческому применению форт-технологий, и вообще присылайте любые ваши вопросы, комментарии
и замечания — мне необходима обратная связь.
1 ФОРТ, Форт, Forth или FORTH
2 Си или C++
3 операционной системой, или OS
4 http://www.cvs.ru
5 http://www.subscribe.ru/lists/comp.soft.prog.forth
версия 18 марта 2006 г.
Форт (cl RU FIG, Понятов Д.А. <forth@km.ru> , public domain
6
1 Введение
1.2 версия 2
<forth@km.ru>
Эта книга — попытка объединить несколько основных книг по языку Форт, выпущенных на
русском языке. После 1995 года не было выпущено не одной книги об этом языке, но даже с
учетом того что язык мало распространен6 и развивается очень медленно, эти книги все равно
устарели.
Использовать Форт имеет смысл в достаточно узкой области, где используются маломощные
компьютеры с очень небольшими объемами памяти (8- 16 -битные процессоры, десятки и сотни
Кб ОЗУ). Язык очень низкоуровневый, поэтому если вам доступен полноценный компилятор
С++, лучше использовать его, а не Форт.
Применять Форт можно в том случае, если не доступен готовый компилятор С++ — Форт от¬
личается крайней простотой внутреннего устройства и синтаксиса, поэтому написать компилятор
Форта можно буквально за полчаса (см. [akps]).
Еще один вариант использования Форта — в качестве операционной системы, написав интер¬
активную форт-систему. При этом вы получаете командный интерфейс, встроенный компилятор
и набор runtime библиотек, объединенные в очень компактную операционную систему.
1.3 О языке программирования Форт
Если вы занимаетесь такими вещами как разработка различных цифровых систем7 и про¬
граммного обеспечения для них, вы можете столкнуться с ситуацией, когда вас не будет устра¬
ивать по каким-либо причинам обычно используемый в таких случаях инструментарий8. Этими
причинами может оказаться дороговизна инструментария, его неудобство, отсутствие каких-либо
утилит, или в особых случаях когда вы сами сляпали нечто, и для этой железки не оказалось
готовой ОС и библиотек.
К сожалению, методика целевой компиляции, применяемая при использовании Форта в таких
случаях, описана недостаточно подробно и понятно. В сети много введений для начинающих, но
очень мало материалов для опытных фортеров (программистов на Форте), и написание ассем¬
блеров, целевых компиляторов, форт-систем и различных расширений не описано в достаточной
степени. Многие разработчики слышали о языке Форт, но не используют его из-за отсутствия хо¬
рошей документации. Очень часто возникают возражения типа "Форт слишком сложен в исполь¬
зовании" , но он проще чем ассемблер, который используют очень часто. Малое распространение
Форта определяется двумя причинами:
1. отсутствие документации о программировании на Форте достаточно сложных программ
типа компиляторов или ООП-расширений и
2. отсутствие хорошо документированных наработок на Форте в виде его расширений (биб¬
лиотек) и исходных кодов форт-систем.
Учитывая возможности современных технологий программирования, существующих библио¬
тек и возможностей операционных систем, язык Форт имеет также смысл использовать в качестве
встраиваемого в программы языка, который удобно использовать для написания конфигураци¬
онных файлов и программирования пользователем. Естественно это имеет смысл только если
существуют ограничения на ресурсы, которые может использовать такое скрипт-расширение.
Если таких ограничений нет, правильнее использовать встраиваемые скрипт-языки с более удо¬
боваримым синтаксисом типа Python. Еще одна область применения — быстрое написание кросс¬
ассемблеров, которые более удобны чем традиционные в случаях, когда нужна мощная поддерж¬
ка макросов.
Достоинства Форта, которые могут определить его выбор:
• возможность реализации виртуальной машины в готовых программах на любых языках с
минимальными затратами;
6
хотя и широко известен
встраиваемые контроллеры для управления технологическим или лабораторным оборудованием
8ассемблер, компилятор С, линкер, симулятор, встраиваемые ОС
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
1 Введение
7
• минимальные требования к ресурсам;
• встроенный в ядро компилятор и опционально ассемблер;
• компактность» кода;
• расширяемость.
1.4 Из [os]
Язык Форт по своей идеологии очень минималистичен, так как был разработан для програм¬
мирования систем с очень ограниченными ресурсами — сейчас такие системы можно встретить
исключительно в виде блоков управления различным оборудованием. Даже компьютеры внутри
мобильников на порядок мощнее по доступным ресурсам — скорости, разрядности процессора,
объемам памяти, возможностям вывода графики.
Сам язык практически не защищает программиста от ошибок типа некорректной работы с
данными, не поддерживает типизацию, ООП, структуры данных и т.д.. Практически это ас¬
семблер стековой машины, и программирование на нем очень близко к программированию на
обычных ассемблерах — программист вынужден реализовывать все вручную, самостоятельно
отслеживая состояние стека, корректность адресов и указателей и т.д..
Если вы хотите иметь язык, выполняющий более серьезный контроль вашего кода, Форт для
вас не подходит.
С другой стороны у Форта есть одна особенность, которой многие другие языки не обладают,
и которая является ключевой — на Форте вы не столько программируете, сколько расширяете
язык через уже существующие в нем слова, определяя диалект под вашу задачу. Подробнее
см. [orange] и особенно [thinking]. Из-за этой особенности Форт нельзя назвать языком низкого
уровня — хотя его ядро и низкоуровневое9, но его расширение приводит к созданию диалектов
сверх-высокого уровня.
Другими словами: Форт — язык для конструирования проблемно-ориентированных языков,
работающих на очень простой виртуальной машине. Реализация такой стековой ВМ для реаль¬
ного железа также проста, поэтому эта ВМ легко и быстро реализуется на любом языке или даже
на аппаратном уровне в виде специализированных процессоров в FPGA или кремнии.
Кроме того, базовый Форт очень прост как в изучении, так и в самостоятельной реализации,
особенно если использовать методику целевой компиляции в интерпретируемый байт-код, опи¬
санной в этой книге, и любой чайник вполне в состоянии написать свой работающий вариант
Форта буквально за несколько часов для любой платформы и на любом языке.
Естественно при этом у него будут те же проблемы с низкоуровнсвостью языка и необходи¬
мостью расширять язык до приемлемого уровня, но тогда он всегда сможет сказать, что сам
написал для себя язык и средства разработки.
В этом случае нужно очень аккуратно следить за совместимостью вашей версии с версиями
других хакеров — лучше использовать чужие готовые наработки и делиться своими, чем вариться
в собственном соку, используя свой уникальный несовместимый диалект Форта.
1.5 Из [orange]
Материал книги построен для использования ее в качестве справочника так, чтобы охватить
весь набор средств и приемов и полный перечень слов и функций языка. Кроме того, приведены
примеры расширения языка и использования Форта в качестве средства разработки программ и
как операционной системы.
И все же многие утверждают, что Форт труден для изучения. Для этого имеется несколько
причин. Опытным программистам Форт зачастую дается труднее, чем новичкам, потому что он
отличается от других языков программирования по самой своей природе. Хотя в языке Форт нет
каких-либо присущих только ему сложностей, программисты с трудом отвыкают от переменных,
подпрограмм, многословного текста на исходном языке, алгебраических обозначений и прочих
атрибутов привычных им языков. Если вы знаете другие языки программирования, попробуйте
к языку Форт подойти с полной отдачей. Освойте понятия стека и определения слов, прежде чем
переходить к более сложным вопросам. Забудьте всякие предубеждения, которые у вас могут
9 и при этом платформетшо-независимое
версия 18 марта 2006 г.
Форт с RU FIG, Понятов Д.А. <forth<9km.ru> . public domain
8
1 Введение
возникнуть, вроде того, что для хорошего языка программирования обязательно нужна опера¬
ционная система и файловая поддержка. И нс беспокойтесь о блок-схеме, начните с небольших
задач, ваш опыт будет накапливаться постепенно. Форт может показаться трудным, так как это
достаточно мощное средство программирования.
Действительно, все возможности языка изучить трудно, но все они и нс потребуются, чтобы
писать очень полезные программы. На Форте можно научиться писать программы на уровне
хорошего программиста, пользующегося языками BASIC и FORTRAN, быстрее, чем на любом
другом языке. Так же несложно программирование на форт-асссмблерс (определение слов Фор¬
та в машинных кодах). Можно описать слова, которые будут создавать в словаре совершенно
новые типы данных, использовать Форт для модификации самого языка, для операций с боль¬
шими объемами данных в памяти компьютера и даже для того, чтобы реализовать новые языки
программирования. Конечно, изучение этих вопросов может быть трудным. И, хотя мы осветим
большую их часть, вы сможете хорошо программировать на языке Форт раньше, чем овладеете
ими всеми. Форт предоставляет вам мощные средства для управления работой компьютера, при¬
сущие другим языкам программирования, включая машинный язык, но вам эти мощные средства
скорее всего не потребуются.
Существует одна причина, из-за которой Форт иногда оказывается действительно трудным.
Дело в том, что в стандартах языка и в поставляемых потребителям реализациях языка от¬
сутствуют некоторые слова для выполнения основных или важных функций, предусмотренных
другими языками. В таких случаях программист вынужден сам написать слова, которые должны
выполнять эти важные функции. Например, старый стандартный Форт’83 нс содержит операций
над числами с плавающей запятой, в нем нет трансцендентных функций (тригонометрических,
логарифмической); не определены стандартами операции с символами и символьными строками
(например, извлечение отдельных слов из текста), работа с файлами данных, графические воз¬
можности. Нет в стандарте и слова, позволяющего вводить числа в процессе исполнения програм¬
мы. К счастью, во многих поставляемых реализациях Форта предусмотрены слова, позволяющие
преодолеть эти ограничения, а Форт настолько мощный, что позволяет самому написать такие
слова, если знать, как это сделать. И мы вас этому научим.
Кроме того, 1994 году вышел новый стандарт [ans], в который включена большая часть
из выше перечисленного. И в конце концов всегда остается доступ в Сеть, используя которую
вы можете найти исходные тексты программ, сразу подходящих для, решения, ваших задач
или требующих некоторой адаптации. Если эти программы не комплектуются, документацией
дост,ат,очного качества, свяжитесь с их авторами по электронной почте — в этом, случае вы,
может,е не только получить консультацию, но возможно появится новая версия, програ,ммы,
в создании которой вы сами примете участие. Именно в этом и включается, смысл движения
Open Source10 !
Подводя итог, можно сказать, что Форт — это в то же время мощный и неразвитый язык.
Мощный он потому, что программы, написанные на нем, занимают мало места в памяти и ис¬
полняются с такой же скоростью или быстрее, чем на других языках, он дает потенциально
неограниченные возможности управления компьютером, и писать и отлаживать программы до¬
вольно несложно. В то же время стандартный Форт неразвит, ввиду того что не предусматривает
выполнения некоторых важных функций, которые являются неотъемлемой частью других язы¬
ков или операционной системы и доступны для программиста, и кроме того в состав поставки не
включены мегабайты библиотек, как это делают поставщики современных коммерческих средств
разработки. Введение этих функций и создание библиотек предоставлено программисту, преду¬
сматривается в некоторых (коммерческих или расширенных) версиях Форта или просто доступно
в Сети в виде отдельных пакетов11.
Почему же стандартный Форт так бедно определен ? Чтобы понять это, надо немного по¬
знакомиться с историей его создания и естественно учесть что в его развитии не участвовала та
критическая масса програмистов и поставщиков коммерческого ПО, как это случилось с языками
типа C++, Python, Perl, Java и т.п.
10 http://www.fsf.org
11 возможно придется приложить некоторые усилия к их адаптации к вашей версии форт-системы
Форт © RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
1 Введение
9
1.6 Из перевода [thinking]
Уже несколько лет я использую для программирования язык Форт. С первой же встречи с ним
я был очарован и покорен его простотой, элегантностью и логичностью. К сожалению, в нашей
стране Форт знают и используют лишь считанные энтузиасты, чему в большой мере способствует
отсутствие сколько-нибудь доступной современной литературы и программного обеспечения.
Несколько книг по языку изданы более 10 лет назад, они дают достаточно информации для
начинающего фортера, но в них не описаны методы и приемы, разработанные и описанные ми¬
ровым сообществом фортеров.
Необходимо написание новой книги по языку: существующие книги давно устарели, необ¬
ходимо очень подробно, понятно и в то же время легко читаемо и без традиционной для рос¬
сийских книг зауми (самый rulez в этом плане Броуди) описать сложные технологии форт-
программирования: написание ассемблеров, целевых компиляторов, форт-систем для специфи¬
ческих систем типа самодельных компьютеров и промышленных контроллеров, парсеров и син¬
таксических анализаторов, сложных расширений языка (например ООП), написание легко пе¬
реносимых программ и т.п. Также возможно стоит уделить внимание современным технологиям
в железе, особенно flex-технологии "гибкой логики" с использованием ПЛИС (CPLD, FPGA) и
систем на кристалле (System on Chip, SoC).
В качестве базы я решил взять [starting, orange, thinking, green] и написать on-line книгу учи¬
тывая современное состояние языка. Первоначально это будет простая компиляция этих книг,
которая в дальнейшем будет редактироваться и модифицироваться, в том числе и с вашим уча¬
стием.
Форт является языком и операционной системой. Но это не все: он также и воплощение фи¬
лософии. Обычно философию не рассматривают как нечто, отдельное от Форта. Она не предше¬
ствовала Форту и не описывалась где-либо вне рассуждений о Форте, и даже нс имеет другого
имени, кроме как "Форт". Точнее даже сказать что это не философия, а (информационная) тех¬
нология и методика разработки программ.
Предлагаемая книга является одновременно учебником и справочником, позволяющим овла¬
деть Фортом независимо от того, начинающий вы программист или опытный.
Форт — достаточно мощный язык программирования, несмотря на его низкоуровневость, но
он наиболее эффективен для компьютерных систем с медленным процессором низкой разрядно¬
сти и неболлыпим объемом памяти (порядка нескольких Кб).
1.7 © Ю. А. Семенов
Статья является введением к книге: Семенов К). А., "Программирование на языке Форт,",
М., "Радио и связь", 1991 г.
В 1971 г. Чарльз Мур разработал язык для управления оптическим телескопом и, считая его
языком четвертого поколения, назвал FOURTH (четвертый). Однако на ЭВМ, на которой он ра¬
ботал, символьные имена могли иметь только пять букв. Так FOURTH стал FORTH (Форт).
Несмотря на конкуренцию других языков программирования, в частности языка С^+, Форт
мало-помалу стал завоевывать популярность, особенно при решении задач управления сложными
объектами в реальном масштабе времени.
Язык Форт использовался для математического обеспечения корабля многоразового исполь¬
зования типа Shuttle, разведывательного 1802 (Avco Inc.) и других искусственных спутников
Земли, для разработки тслсигр (GamcFORTH), при создании фильмов Star Wars, Batlle Beyond
the Stars и Star Trek, для системы управления полетами в аэропорту Эр-Рияда (400 ЭВМ и 36
ООО датчиков) [24].
В 1976 г. Комитет международного астрономического союза принял Форт в качестве стан¬
дартного языка программирования. Позднее Форт применялся для создания экспертных систем,
систем искусственного зрения, автоматизации анализа крови и кардиологического контроля, си¬
стем машинного перевода с 20 языков (Craig М100, карманный переводчик) и т.д..
В СССР этот язык используется для систем управления базами данных экономических задач,
для программ управления экспериментом, мониторинга состояния пациентов.
Несмотря на ощутимые успехи в использовании языка Форт, делать прогноз о беспредель¬
ном расширении сферы его применения вряд ли можно. В то же время, безусловно, существуют
версия 18 марта 2006 г.
Форт © R.U FIG, Понятов Д.А. <forth@km.ru> , public domain
10
1 Введение
области, где Форт имеет несомненные преимущества перед другими языками. Форт эффективен
прежде всего для управления неболвшими экпериментами и системами, при диагностике сложной
электронной аппаратуры с помощвю микроЭВМ или микропроцессоров, для создания дешевых
поисковых систем, программ машинной графики, трансляторов с других языков. Это, разуме¬
ется, не означает, что Форт неприменим в других областях, его возможности еще не раскрыты
полноствю.
Язвтк Форт иногда называют форт-системой, так как он содержит программы для работы
с внешними устройствами, файлами, средства обработки прерываний, редактор и т.д.. Преиму¬
щество Форта заключается прежде всего в скорости написания и отладки программ, а также
в их компактности. Если программу на Фортране или Паскале можно написатв и отладитв за
неделю, то такую же программу на Форте за несколько часов. По сравнению с Бейсиком и неко¬
торыми другими интерпретаторами Форт позволяет составить программу в несколько раз более
быстродействующую. Он проигрывает Ассемблеру по скорости исполнения программы не более
чем в 1.5-2 раза. Применение же форт-ассемблера позволяет получить еще больший выигрыш в
быстродействии.
Экономное использование оперативной памяти ЭВМ и внешней памяти (диска), возможность
автономного функционирования (в отсутствие операционной системы), интерактивный характер
делают Форт особенно привлекательным в небольших автоматизированных системах измерения
и контроля, хотя известны случаи использования Форта на ЕС ЭВМ для организации сложных
вычислительных процесс сов [36]. Хорошо написанная программа на Форте занимает в памя¬
ти меньше места, чем аналогичная, составленная на Ассемблере (здесь не учитывается место,
занимаемое процедурами базового словаря Форта).
Модульность интерпретатора и системы в целом позволяет легко адаптировать ее к новым
процессорам и задачам. По простоте обучения Форт соперничает с Бейсиком, что делает его
привлекательным для непрофессиональных программистов.
Какие же особенности обеспечили Форту шанс выжить в конкурентной борьбе с другими
системами ?
Для Форта, включая программы управления терминалом и диском, требуется 5-8 Кбайт опе¬
ративной памяти, а для Паскаля 48 Кбайт (здесь, правда, не учитывается место, занимаемое
операционной системой). С учетом этого выигрыш по памяти оказывается существенно больше.
При необходимости базовый словарь Форта может быть сокращен до 1 Кбайт. Программа на
Форте может быть исполнена сразу после написания, так как не требует редактора связей.
Форт допускает рекурсию, т.е. программа может обращаться к самой себе (что недопустимо
в Фортране).
После выполнения программы и возврата управления системе Форт сохраняется доступ к
любой переменной или массиву с помощью символьных имен, что не допускают многие другие
языки.
При работе с форт-ассемблером исполняемая программа практически идентична программе,
написанной в машинных кодах, но программист избавлен от длительной трансляции и редак¬
тирования связей (программа сразу готова к исполнению). Проигрыш по памяти и скорости
исполнения программы в этом случае не превышает 20-30%.
Список операторов Форта открыт для пользователя и может быть расширен по его усмотре¬
нию. Это касается самого Форта, форт-ассемблера, редактора и, разумеется, пакетов прикладных
программ.
При работе с многозадачным (многопользовательским) Фортом используется общий словарь
процедур для нескольких задач.
К недостаткам Форта относят:
• отсутствие в базовой версии операторов для работы с числами с плавающей точкой;
• недостаточные по современным требованиям средства диагностики ошибок (хотя это и ком¬
пенсируется отчасти другими возможностями, в частности доступностью этих средств для
пользователя);
• непривычная для многих обратная польская (постфиксная) нотация, широкое применение
стеков;
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
1 Введение
11
• отсутствие в базовой версии развитой системы для работы с файлами (отчасти устранен в
интерпретаторах для персональных ЭВМ).
Простота расширения списка операторов и легкость модификации интерпретатора сводят эти
недостатки к минимуму. Удобная мнемоника и хорошая адаптация ко вкусам программиста могут
сделать работу на Форте легким и даже приятным занятием. Далее будет рассматриваться в
основном версия FIG-FORTH, как наиболее распространенная.
форт-интерпретатор, как и многие другие, имеет несколько уровней:
• работа системы в качестве настольного калькулятора;
• программирование с использованием базового словаря Форта;
• создание с помощью редактора программ, сохраняемых на магнитном диске, которые могут
загружаться по мерс необходимости.
Принадлежность Форта четвертому поколению часто вызывает споры. С одной стороны, он
содержит структурные операторы типа DO...LOOP, BEGIN...UNTIL и т.д., с другой — допускает
работу с адресами, что характерно для языков низкого уровня. Главное — это баланс достоинств
и недостатков, а этот баланс, на мой взгляд, благоприятен для Форта.
В США создано общество пользователей Форта (FORTH Interest Group, FIG) и фирма FORTH
Inc. — главный поставщик программных продуктов Форт, в том числе многопользовательской
версии PolyFORTH-2.
Существует ряд стандартов: FORTH-79, FORTH-83 [18], FIG [17], MMS, MVP [25, 26]. В какой-
то мере этому способствует простота их создания, ведь мало кто решится переделывать или
расширять базовый словарь операторов Фортрана просто из-за чудовищной трудоемкости. На¬
метилась тенденция к созданию процессоров, ориентированных на Форт (фирмы Harris, Silicon
Composers, FORTH Inc. США и Институт кибернетики АН ЭССР).
Существуют версии языка Форт для отечественных ЭВМ СМ 1420, "Электроника-60", СМ
1810, ДВК, персональных ЭВМ ЕС1840, ЕС1841, ЕС 1842, микропроцессоров К580 и даже ЭВМ
серии ЕС.
1.8 © ИТФ Технофорт
Язык программирования Форт (от английского FORTH) был изобретен Чарльзом Муром в
70-х годах для создания программного обеспечения управляющих устройств. В настоящее время
Форт широко используется при решении следующих задач:
• разработка и тестирование встроенного оборудования;
• управление станками, роботами, медицинскими приборами;
• разработка трансляторов и операционных систем;
• системы управления базами данных;
• задачи машинной графики;
• экспертные системы, в том числе экспертные системы реального времени.
В отличие от других языков высокого уровня, Форт обеспечивает программисту полный
доступ к машине и не пытается оградить его от ошибок. Однако, модульность, а также расши¬
ряемость языка, позволяющая программисту вводить конструкции со встроенными средствами
контроля, дает возможность создавать высоконадежные программы.
Форт использует обратную польскую (постфиксную) запись, при которой операнды пред¬
шествуют операции. Хотя такая запись непривычна и может показаться неудобной, она суще¬
ственно уменьшает затраты на организацию вызовов подпрограмм и реализацию языка.
Код, получаемый компилятором Форта, исключительно компактен, даже по сравнению с
машинным кодом. Особенно это заметно на больших программах.
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
12
1 Введение
форт-система, в основном, написана на самом языке Форт. Она занимает от 8 до 16 Кбайт
в зависимости от предоставляемых возможностей (таких, как встроенный ассемблер, экранный
редактор, взаимодействие с файловой системой).
Программы на языке Форт реентерабельны, допускают рекурсию. Программист может напи¬
сать программу в машинных командах на встроенном в форт-систему ассемблере и в дальнейшем
использовать се как обычную подпрограмму. Вследствие этого, Форт можно применять для со¬
здания программ непосредственного управления аппаратурой.
форт-система — автономная система. Она может работать как на "голом" оборудовании, так
и под управлением операционной системы (например, СР/М, MS-DOS).
Форт является диалоговым языком, то есть команды выполняются форт-системой сразу, как
только Вы их введете с клавиатуры и нажмете клавишу ввода. Ответ "ок" является подтвержде¬
нием того, что запрос выполнен, и приглашением продолжать работу.
1.9 Достоинства языка Форт (из [ans])
Форт предоставляет интерактивную среду разработки (IDE). Его первые применения в науч¬
ных и промышленных приложениях таких как аппаратура, робототехника, управление процес¬
сами, графика и обработка изображений, искуственный интеллект и бинес-приложения. Прин¬
ципиальные достоинства Форта включают быструю интерактивную разработку программного
обеспечения и эффективное использование компьютерного железа.
О Форте часто говорят как о языке, так как это наиболее заметный аспект. Но фактически
Форт одновременно больше и меньше чем обычный язык программирования: больше так как
все возможности языка, обычно ассоциированные с большим набором отдельных программ12,
включены в язык, и меньше так как в языке (сознательно) отсутствуют сложные синтаксические
конструкции, характериныс для большинства языков высокого уровня.
Оригинальные реализации Форта были самостоятельными системами, включающими функ¬
циональность, обычно обеспечиваемую отдельно операционной системой, редакторами, компиля¬
торами, ассемблерами, отладчиками и другими утилитами. A single simple, consistent set of rules
governed this entire range of capabilities. Сегодня до сих пор продаются множество версий само¬
стоятельных13 форт-систем для многих процессоров, но при этом также существует множество
версий, работающих поверх обычных операционных систем типа MS-DOS или UNIX.
Форт не является ответвлением какого-либо другого языка. В результате его внешний вид
и внутренние характеристики могут показаться непривычными для новых пользователей. Но
простота Форта, его крайняя модульность и интерактивная природа отодвигают его начальную
непривычность, делая простым его изучение и использование. Новый фортер14 должен потратить
некоторое время на изучение большого набора команд языка. Примерно после месяца использо¬
вания Форта фортер может понять больше внутренних механизмов языка, чем это возможно для
обычных операционных систем и компиляторов.
Наиболее интересное свойство Форта — его расширяемость. Процесс программирования на
Форте состоит из определения новых слов — фактически новых команд языка. Они могут быть
определены в терминах ранее определенных слов, что сильно похоже на обучение ребенка объ¬
ясняя новые понятия через ранее изученные. Такие слова называются высокоуровневыми опре¬
делениями. С другой стороны, новые слова могут также быть определены на уровне машинных
команд, так как большинство реализаций Форта включают ассемблры для используемых процес¬
соров.
Эта расширяемость опеспечивает разработку специальных прикладных языков для конкрет¬
ных проблемных областей или дисциплин.
Расширяемость Форта дает больше чем добавление новых команд в язык. С той же простотой
вы можете также добавлять новые типы слов. Например, вы можете создать слово, которое са¬
мо будет определять слова. При создании таких определяющих слов программист может задать
особое поведение для создаваемых слов, которое будет эффективно во время компиляции, ис¬
полнения или в обоих случаях. Эта возможность позволяет вам определить специализированные
типы данных с полным контролем над их структурой и поведением. Так как поведение таких
12 компиляторами, редакторами и т.д.
13 stand-alone
14 программист на Форте
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
2 История языка
13
слов во время исполнения также может быть задано на высоком уровне или в машинном ко¬
де, созданные таким определяющим словом новые слова эквивалентны по производителвности
другим словам Форта. Так же просто добавитв новые компилирующие команды для реализации
особых видов циклов или других управляющих структур.
Большинство профессиональных реализаций Форта сами написаны на Форте. Многие форт-
системы включают мета-компилятор, который позволяет пользователю модифицировать вну¬
тренний код самой форт-системы.
2 История языка
2.1 Из [orange]
В отличие от других языков программирования Форт не является плодом коллективного тру¬
да какого-либо комитета или коллектива ученых, он родился в голове одного человека — Чарльза
X. Мура. В начале 60-х годов Мура стало все больше не удовлетворять время и затраты труда,
требовавшиеся для разработки программ на существовавших тогда ЭВМ. В течение нескольких
лет он создал основы прототипа языка Форт, пользуясь для этого такими языками, как Алгол,
Кобол, PL/I и ассемблер для IBM/360. Мур дал своему языку название FORTH, считая, что это
будет язык для ЭВМ четвертого (fourth) поколения, однако ему приходилось работать на ЭВМ,
которая допускала только пять букв названия, этим и объясняется такое необычное имя языка
Форт. В 1971 г. Мура пригласили на работу в Национальную Радиоастрономическую обсерва¬
торию для разработки программ сбора и обработки данных, получаемых с радиотелескопа. В
процессе этой работы и появилась первая современная реализация языка Форт (а вторым в мире
программистом на этом языке стала сотрудница Мура Элизабет Ратер), который был принят в
качестве основного языка программирования в Американском астрономическом обществе. К 1973
г. потребность в языке стала настолько большой, что Мур и Ратер создали новую фирму Forth
Inc., президентом которой стала Э. Ратер. Фирма разработала несколько версий языка Форт для
различных марок ЭВМ, мини- и микро-ЭВМ, в том числе наиболее современную версию под
названием PolyFORTH. По мнению специалистов фирмы Forth Inc., наиболее важные примене¬
ния языка Форт в настоящее время связаны с работой программно-управляемого оборудования
в реальном масштабе времени, хотя еще в 1974 г. фирма разработала на языке Форт админи¬
стративную систему для управления базой данных объемом 300 млн. бит информации. Сейчас
фирма Forth Inc. сосредоточила свои усилия на обработке изображений, робототехнике и управ¬
лении сервоприводами. Недавно появились программы для таких применений, как автоматиза¬
ция проверки накопителей на гибких магнитных дисках, для первого прототипа коммерческого
устройства по электрофорезному разделению биологических материалов на космическом кора¬
бле многоразового использования, для сервосистем роботов, управляемых голосом, а также для
контроля почти всех операций в новом главном аэропорте Саудовской Аравии.
Однако популярностью язык Форт обязан не только своим авторам Муру и Ратер и фирме
Forth Inc.. Базовый язык Форт общедоступен и бесплатно распространяется заинтересованной
группой FORTH Interest Groop (FIG), множество фирм поставляет различные по своим возмож¬
ностям коммерческие версии языка, но еще важнее то, что организована группа по стандартиза¬
ции языка Форт для того, чтобы написанные на нем программы могли бы работать на различных
компьютерах с минимальными затратами на их адаптацию. Группа FIG была создана в конце
70-х гг. активными программистами и почитателями языка, которые хотели сделать его еще
более популярным. Существует множество организаций, в том числе несколько отделений этой
группы в США и других странах мира, однако основная деятельность группы направлена на
распространение базового диалекта языка, FIGFORTH (которая реализована на многих мини-
и микроЭВМ) и издание журнала FORTH Dimensions, выходящего раз в два месяца. Содержа¬
ние журнала показывает, что редакция проявляет интерес как к модификации и расширению
самого языка, так и к решению прикладных задач. Кроме издания журнала и распространения
языка каждый год, начиная с 1980-го, группа FIG созывает конференцию под названием FORTH
Modification Laboratory (FORML), целью которой является встреча пользователей и системных
программистов для обсуждения вопросов дальнейшего развития языка. Кроме этой конференции
Институт прикладных исследований фирмы Applied FORTH Research ежегодно организует в Ро¬
честере (США) конференцию по применению Форта (Rochester FORTH Application Conference).
версия 18 марта 2006 г.
Форт (ср RU FIG, Понятов Д.А. <forth©km.ru> . public domain
14
2 История языка
Институт публикует труды конференции и, кроме того, профессиональный журнал Journal of
FORTH Application and Research, содержащий рефераты, библиографические ссылки на матери¬
алы по языку Форт и материалы студенческих исследований.
Группа по стандартизации первоначально возникла в рамках Международного объединения
астрономов. На встрече в Национальной обсерватории Китта (США) в мае 1977 г. был вырабо¬
тан глоссарий языка Форт под шифром AST.01, а после нескольких встреч в Европе, наконец,
в феврале 1978 г. в Утрехте (Голландия) был разработан стандарт 1977 г. (FORTH-77), адресо¬
ванный прежде всего пользователям микроЭВМ. В октябре 1979 г. встреча на острове Каталина
закончилась разработкой стандарта FORTH-79, который распространяется на ЭВМ всех типов.
Осенью 1983 г. состоялась встреча по разработке стандарта 1983 г, утвержденного в 1984 г, как
FORTH-83. Стандарт Форт-83 отличается от стандарта Форт-79 некоторыми деталями, но не от¬
личается от него по существу. Некоторые специалисты, в том числе и поставщики коммерческих
версий языка, считают, что изменения 1983 г. в лучшем случае не привели к совершенствованию
языка, в худшем же — внесли некоторую путаницу, поэтому как Форт-83, так и Форт-79 имеют
равное распространение, и мы рассматриваем здесь обе версии. Несмотря на то, что некоторые
изменения могут привести к смешению обеих версий, были все же некоторые разумные, хотя и
не очень важные причины внесения этих различий.
С момента издания книги был выпушен новый стандарт ANS FORTH ’94, и теперь ситуация
аналогична описанной выше — существуют множество форт-систем, полностью или частично
соответствующих стандарту 83 или 94. В новом стандарте было добавлено множество расширений
базового словаря (плавающая точка, файлы, динамическая память и т.д.), но до сих пор есть
множество фортеров, которых не устраивают какие-то особенности нового стандарта.
Целью стандартизации было создание единого набора слов (глоссария), чтобы можно бы¬
ло легко переносить программы с одного компьютера на другой (особенно если они сильно от¬
личаются по ОС и железу, например ПК на интеловских процессорах и ZX Spectrum). Стан¬
дарт определяет минимальный набор обязательных слов и необязательный набор расширяющих
слов, например ассемблер и слова из контролируемого списка, выполняющие точно определен¬
ные функции. К сожалению, в стандарте нет никаких указаний на такие важные компоненты,
как числа, символьные строки, на организацию файлов данных (см. замечание выше). Концеп¬
ции группы стандартизаторов частично были приведены в статье ее председателя У. Рэгсдейла:
"Самой трудной задачей разработки языка является принятие решения о том, что следует отбро¬
сить. Стандартизаторы сталкиваются с задачей установления равновесия между практически по¬
лезными функциями и простейшими функциями, обеспечивающими пользователю возможность
дополнить программные средства, чтобы решать прикладные задачи". В результате получилось
так, что во всех поставляемых версиях Форта возникает необходимость в добавлении собствен¬
ных функционально важных слов, что противоречит идее свободной переносимости программ
между различными компьютерами.
Почему же все-таки в Форт не включены слова для выполнения функций, безусловно пре¬
дусмотренных в других языках программирования ? Частично это объясняется традиционными
применениями языка, отчасти интересами группы FIG и многочисленных пользователей языка
Форт, в особенности любителей, и частично возражениями группы по стандартизации. Во-первых,
традиционной областью применения языка было управление установками в реальном масштабе
времени, где Форт подходит наилучшим образом. Операции со строковыми данными, ввод и вы¬
вод чисел, работа с файлами, связь с операционной системой и другие качества здесь не столь
важны, как при решении более практических задач, например при проведении инженерных рас¬
четов или в деловой сфере. Во-вторых, основной задачей группы FIG было распространение
простейшей версии языка FIGFORTH и, как отмечается в журнале FORTH Dimensions, боль¬
шинство членов FIG проявляет интерес скорее к модификациям языка, чем к применению его
в повседневной жизни, и поэтому не имеют побудительного толчка к снабжению Форта такими
функциями. Наконец, группа стандартизации предоставляет пользователю возможность само¬
му выполнить разработку дополнительных инструментальных средств, сведя к минимуму набор
стандартных слов. При этом бремя разработки возлагается на пользователей и поставщиков про¬
мышленных версий языка, лишь в последние три года некоторые необходимые функции были
введены в поставляемых реализациях Форта.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
15
2 История языка
2.2 Из [ans]
2.3 Forth — The Early Years
Chuck Moore: The Invention of Forth
© Chuck Moore
chipchuck@colorforth. com
1991
2.3.1 Abstract
Forth is a simple, natural computer language. It has achieved remarkable acceptance where efficiency
is valued. It evolved in the 1960s on a journey from university through business to laboratory. This
is the story of how a simple interpreter expanded its abilities to become a complete programming
language/operating system.
2.3.2 Forward 1999
This paper was written for the HOPL II (History of programming languages) conference. It was
summarily rejected, apparently because of its style. Much of the content was included in the accepted
paper [Rather 1993].
This HTML version was reformatted from the original typescript. Minimal changes were made to
the text. Examples of source code were suggested by reviewer Phil Koopman. They’ve not yet been
added.
2.3.3 Forth
Forth evolved during the decade of the 60s, across America, within university, business and labo¬
ratory, amongst established languages. During this period, I was its only programmer and it had no
name until the end. This account is retrieved from memory, prompted by sparse documentation and
surviving listings.
Forth is hardly original, but it is a unique combination of ingredients. I’m grateful to the people
and organizations who permitted me to develop it — often unbeknownst to them. And to you, for being
interested enough to read about it.
Forth is a simple, natural computer language. Today it is accepted as a world-class programming
language. That it has achieved this without industry, university or government support is a tribute to
its efficiency, reliability and versatility. Forth is the language of choice when its efficiency outweighs
the popularity of other languages. This is more often the case in real-world applications such as control
and communication.
A number of Forth organizations and a plethora of small companies provide systems, applications
and documentation. Annual conferences are held in North America, Europe and Asia. A draft ANSI
standard will soon be submitted [ANS 1991].
None of the books about Forth quite capture its flavor. I think the best is still the first, Starting
Forth by Leo Brodie [Brodie 1981]. Another window is provided by JFAR’s invaluable subject and
author index [Martin 1987].
The classic Forth we arc discussing provides the minimum support a programmer needs to develop
a language optimized for his application. It is intended for a work-station environment: keyboard,
display, computer and disk.
Forth is a text-based language that is essentially context-free. It combines ’words’ separated by
spaces, to construct new words. About 150 such words constitute a system that provides (with date of
introduction)
версия 18 марта 2006 г.
Форт (с) R.U FIG. Понятов Д.А. <forth@km.ru> , public domain
16
% История языка,
SAO
1958
Interpreter
SLAC
1961
Data stack
RSI
1966
Keyboard input
Display output, OK
Editor
Mohasco
1968
Compiler
Return stack
Dictionary
Virtual memory (disk)
Multiprogrammer
NRAO
1971
Threaded code
Fixed-point arithmetic
Such a system has 3-8К bytes of code compiled from 10-20 pages of source. It can easily be
implemented by a single programmer on a small computer.
This account necessarily follows my career. But it is intended to be the autobiography of Forth. I
will discuss the features listed above; and the names of the words associated with thorn. The meaning
of many words is obvious. Some warrant description and some are beyond the scope of this paper.
That portion of the Forth dictionary to be mentioned is summarized here:
Interpreter
WORD
NUMBER
INTERPET
ABORT
HASH
FIND
FORGET
BASE
OCTAL
DECIMAL
HEX
LOAD
EXIT
EXECUTE
Terminal
KEY
EXPECT
EMIT
CR
SPACE
SPACES
DIGIT
TYPE
DUMP
Data stack
DUP
DROP
SWAP
OVER
+
-
*
MOD
NEGATE
ABS
MAX
MIN
AND
OR
XOR
NOT
0<
0=
—
@
I
+!
C@
C!
SQRT
SIN.COS
ATAN
EXP
LOG
Return stack
PUSH
POP
I
Disk
BLOCK
UPDATE
FLUSH
BUFFER
PREV
OLDEST
Compiler
CREATE
ALLOT
SMUDGE
VARIABLE
CONSTANT
[
]
LITERAL
11
COMPILE
BEGIN
UNTIL
AGAIN
WHILE
REPEAT
DO
LOOP
+LOOP
IF
ELSE
THEN
2.3.4 MIT, SAO, 1958
October, 1957 was Sputnik — a most exciting time. I was a sophmore at MIT and got a part-time
job with SAO (Smithsonian Astrophysical Observatory, 14 syllables) at Harvard.
SAO was responsible for optical tracking of satellites — Moonwatch visual observations and Baker-
Nunn tracking cameras. Caught off-guard by Sputnik, they hired undergraduates to compute predicti¬
Форт R.U FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
2 История языка
17
ons with Fridcn desk calculators. John Gaustad told me about MIT’s IBM EDPM 704 and loaned me
his Fortran II manual. My first program, Ephemeris 4, eliminated my job [Moore 1958].
Now a Programmer, I worked with George Veis to apply his method of least-squares fitting to
determine orbital elements, station positions and ultimately the shape of Earth [Veis 1960]. Of course,
this part-time job was at least 40 hours, and yes, my grades went to hell.
At MIT, John McCarthy taught an incredible course on LISP. That was my introduction to
recursion, and to the marvelous variety of computer language. Wil Baden has noted that LISP is
to Lambda Calculus as Forth is to Lukasewcleicz Postfix.
APL was also a topical language, with its weird right-left parsing. Although I admire and emulate
its operators, I’m not persuaded they constitute an optimal set.
The programming environment in the 50s was more severe than today. My source code filled 2 trays
with punch cards. They had to be carried about to be put through machines, mostly by me. Compile
took 30 minutes (just like C) but limited computer time meant one run per day, except maybe 3rd
shift.
So I wrote this simple interpreter to read input cards and control the program. It also directed
calculations. The five orbital elements each had an empirical equation to account for atmospheric drag
and the non-sphorical Earth. Thus I could compose different equations for the several satellites without
re-compiling.
These equations summed terms such as P2 (polynomial of degree 2) and S (sine). 36-bit floating¬
point dominated calculation time so overhead was small. A data stack was unnecessary, and probably
unknown to me.
The Forth interpreter began here with the words
WORD NUMBER INTERPRET ABORT
They weren’t spelled that way because they were statement numbers.
INTERPRET uses WORD to read words separated by spaces and NUMBER to convert a word
to binary (in this case, floating-point). Such free-format input was unusual, but was more efficient
(smaller and faster) and reliable. Fortran input was formatted into specific columns and typographic
errors had caused numerous delays.
This interpreter used an IF .. .ELSE IF construct, coded in Fortran, finding a match on a single
character. Error handling consisted of terminating the run. Then, as now, ABORT asked the user what
to do. Since input cards were listed as they were read, you knew where the error was.
2.3.5 Stanford, SLAC, 1961
In 1961 I went to Stanford to study mathematics. Although Stanford was building its computer
science department, I was interested in real computing. I was impressed that they could (dared ?) write
their own Algol compiler. And I fatefully encountered the Burroughs B5500 computer.
I got another ’part-time’ job at SLAG (Stanford Linear Accelerator Center, 12 syllables) writing¬
code to optimize beam steering for the pending 2-niile electron accelerator. This was a natural appli¬
cation of my least-squares experience to phase-space. Hal Butler was in charge of our group and the
program, TRANSPORT, was quite successful.
Another application of least-squares was the program CURVE, coded in Algol (1964). It is a general-
purpose non-linear differential-corrections data-fitting program. Its statistical rigor provides insight into
agreement between model and data.
The data format and model equations were interpreted and a push-down stack used to facilitate
evaluation. CURVE was an impressive precursor to Forth. It introduced these words to provide the
capability to fit models much more elaborate than simple equations:
+
-
*
NEGATE
IF
ELSE
THEN
DUP
DROP
SWAP
VARIABLE
I
SIN
ATAN
EXP
LOG
Spelling was quite different:
версия 18 марта 2006 г.
Форт С' R.U FIG, Понятов Д.А. <forth©km.ru> , public domain
18
2 История языка
NEGATE was MINUS
DROP ;
SWAP
I <
VARIABLE DECLARE
; END
(...) COMMENT ...;
The interpreter used IF ... ELSE IF to identify a 6-character input word called ATOM (from LISP).
DUP DROP and SWAP are 5500 instructions; I’m surprised at the spelling change. The word : was
taken from the Algol label format, flipped for left-right parsing (to prevent the interpreter encountering
an undefined word):
Algol - LABEL:
CURVE — :LABEL
In fact, : marked a position in the input string to be interpreted later. Interpretation was stopped
by ; - A version of : was named DEFINE .
The store operator ( !) appeared in connection with VARIABLE . But fetching ( @ ) was automatic.
Note the input had become complex enough to warrant comments. The sometime-criticised postfix
conditional dates from here:
Algol — IF expression THEN true ELSE false
CURVE - stack IF true ELSE false THEN
True is interpreted if stack is non-zero. THEN provides unique termination, the lack of which always
confused me in Algol. Such expressions were interpreted: IF would scan ahead for ELSE or THEN.
The word < introduces the convention that relations leave a truth value on the stack, 1 for true
and 0 for false. The transcendental functions are, of course, library calls.
2.3.6 Free-lance
I left Stanford in 1965 to become a free-lance programmer in the New York City area. This was
not unusual, and I found work programming in Fortran, Algol, Jovial, PL/I and various assemblers. I
literally carried my card deck about and recoded it as necessary.
Minicomputers were appearing, and with them terminals. The interpreter was ideal for teletype
input, and soon included code to handle output. So we aquire the words
KEY EXPECT EMIT CR
SPACE SPACES DIGIT TYPE
EXPECT is a loop calling KEY to read a keystroke. TYPE is a loop calling EMIT to display a
character.
With the TTY came paper-tape and some of the most un-friendly software imaginable — hours of
editing and punching and loading and assembling and printing and loading and testing and repeating.
I remember a terrible Sunday in a Manhattan skyscraper when I couldn’t find splicing tape (nothing
else works) and swore that ’There must be a better way’.
I did considerable work for Bob Davis at Realtime Systems, Inc (RSI). I became a 5500 MCP
guru to support his time-sharing service (remote input to a mainframe) and wrote a Fortran-Algol
translator and file editing utilities. The translator taught me the value of spaces between words, not
required by Fortran.
The interpreter still accepted words with the first 6 characters significant (the 5500 had 48-bit
words). The words
LIST EDIT BEGIN AGAIN EXIT
appear, with BEGIN ... AGAIN spelled START ... REPEAT and used to bracket the editor
commands
Форт © RU FIG, Понятов Д.А. <forthOkm.ru> , public domain
версия 18 марта 2006 г.
2 История языка 19
Т TYPE I INSERT D DELETE F FIND
later used in NR AO’s editor. The word FIELD was used in the maimer of Mohasco and Forth,
Inc’s data-base management.
One of Forth’s distinctive features conies from here. The rule is that Forth acknowledge each line
of input by appending OK when interpretation is complete. This may be difficult, for when input is
terminated by CR a blank must be echoed, and the CR included with OK. At RSI, OK was on the
next line, but it still conveyed friendly reassurance over an intimidating communications line:
56 INSERT ALGOL IS VERY ADAPTABLE
OK
This postfix notation suggests a data stack, but it only had to be one deep.
2.3.7 Mohasco, 1968
In 1968 I transformed into a business programmer at Mohasco Industries, Inc in Amsterdam NY.
They are a major home-furnishing company — carpets and furniture. I had worked with Geoff Leach
at RSI and he persuaded me to follow him up-state. I had just married, and msterdam has a lovely
small-town atmosphere to contrast with NYC.
I rewrote my code in COBOL and learned the truth about business software. Bob Rayco was in
charge of Corporate data processing and assigned me two relevant projects:
He leased an IBM 1130 minicomputer with a 2250 graphic display. The object was to sec if computer
graphics helped design patterned carpets. The answer was ’not without color’ and the 1130 went away.
Meanwhile I had the latest minicomputer environment: 16-bit CPU, 8K RAM, disk (my first),
keyboard, printer, card reader/punch, Fortran compiler. The reader 'punch provided disk backup. I
ported my interpreter again (back to Fortran) and added a cross-assembler to generate code for the
2250.
The system was a great success. It could draw animated 3-D images when IBM could barely draw
static 2-D. Since this was my first real-time graphics, I coded Spacewar, that first video game. I also
converted my Algol chess program into Forth and was ducly impressed how much simpler it became.
The file holding the interpreter was labeled FORTH, for 4th (next) generation software — but the
operating system restricted Hie names to 5 characters.
This environment for programming the 2250 was far superior to the Fortran environment, so I
extended the 2250 cross-assembler into an 1130 compiler. This introduced a flock of words
DO LOOP UNTIL
BLOCK LOAD UPDATE FLUSH
BASE CONTEXT STATE INTERPRET DUMP
CREATE CODE ;CODE CONSTANT SMUDGE
@ OVER AND OR NOT 0
0<
They were still differently spelled
LOOP was CONTINUE
UNTIL
BLOCK
LOAD
TYPE
INTERPRET
CREATE
CODE
END
GET
READ
SEND
QUERY
ENTER
the cent symbol
The only use I’ve ever found for the cent symbol. The loop index and limit were on the data stack.
DO and CONTINUE were meant to acknowledge Fortran.
BLOCK manages a number of buffers to minimize disk access. LOAD reads source from a 1024-byte
block. 1024 was chosen as a nice modular amount of disk, and has proven a good choice. UPDATE
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
20
2 История языка
allows a block to be marked and later rewritten to disk, when its buffer is needed (or by FLUSH ). It
implements virtual memory and is concealed in store ( ! ) words.
BASE allows octal and hex numbers as well as decimal. CONTEXT was the first hint of vocabularies
and served to isolate editor words. STATE distinguished compiling from interpreting. During compila¬
tion, the count and first 3 characters of a word were compiled for later nterpretation. Strangely, words
could be terminated by a special character, an aberration quickly abandoned. The fetch operator ( @ )
ppeared in many guises, since fetching from variables, arrays and disk had to be distinguished. DUMP
became important for examining memory.
But most important, there was now a dictionary. Interpret code now had a name and searched a
linked-list for a match. CREATE constructs the classic dictionary entry:
link to previous entry
count and 3 characters
code to be executed
parameters
The code field was an important innovation, since an indirect jump was the only overhead, once
a word had been found. The value of the count in distinguishing words, I learned from the compiler
writers of Stanford.
An important class of words appeared with CODE . Machine instructions followed in the parameter
field. So any word within the capability of the computer could now be defined. ;CODE specifies the
code to be executed for a new class of words, and introduced what are now called objects.
SMUDGE avoided recursion during the interpretation of a definition. Since the dictionary would
be searched from newest to oldest definitions, recursion would normally occur.
Finally, the return stack appeared. Heretofor, definitions had not been nested, or used the data
stack for their return address. Altogether a time of great innovation in the punctuated evolution of
Forth.
The first paper on Forth, an internal Mohasco report, was written by Geoff and me [Moore 1970].
It would not be out of place today.
In 1970 Bob ordered a Univac 1108. An ambitious project to support a network of leased lines
for an order-entry system. I had coded a report generator in Forth and was confident I could code
order-entry. I ported Forth to the 5500 (standalone !) to add credibility. But corporate software was
COBOL. The marvelous compromise was to install a Forth system on the 1108 that interfaced with
COBOL modules to do transaction processing.
I vividly recall commuting to Schenectady that winter to borrow 1107 time 3rd shift. My TR4-A
lacked floor and window so it became a nightly survival exercise. But the system was an incredible
success. Even Univac was impressed with its efficiency (Les Sharp was project liason). The ultimate
measure was response time, but I was determined to keep it maintainable (small and simple). Alas, an
economic downturn led Management to cancel the 1108. I still think it was a bad call. I was the first
to resign.
1108 Forth must have been coded in assembler. It buffered input and output messages and shared the
CPU among tasks handling each line. Your classic operating system. But it also interpreted the input
and PERFORMed the appropriate COBOL module. It maintained drum buffers and packed/unpackcd
records. The words
BUFFER PREY OLDEST
TASK ACTIVATE GET RELEASE
date from here. BUFFER avoided a disk read when the desired block was known empty. PREY
(previous) and OLDEST are system variables that implement least-recently-used buffer management.
TASK defines a task at boot time and ACTIVATE starts it when needed. GET and RELEASE manage
shared resources (drum, printer). PAUSE is how a task relinquishes control of the CPU. It is included
in all I/O operations and is invisible to transaction code. It allows a simple round-robin scheduling
algorithm that avoids lock-out.
After giving notice, I wrote an angry poem and a book that has never been published. It described
how to develop Forth software and encouraged simplicity and innovation. It also described indirect-
threaded code, but the first implementation was at NRAO.
Форт (c) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
И История языка
21
I struggled with the concept of meta-language, language that talks about language. Forth could now
interpret an assembler, that was assembling a compiler, that would compile the interpreter. Eventually
I decided the terminology wasn’t helpful, but the term Meta-compile for recompiling Forth is still used.
2.3.8 NRAO, 1971
George Conant offered me a position at NRAO (National Radio Astronomy Observatory, 15
syllables). I had known him at SAO and he liked Ephemeris 4. So we moved to Charlottesville VA and
spent summers in Tucson AZ when the radio-telescope on Kitt Peak was available for maintainance.
The project was to program a Honeywell 316 minicomputer to control a new filter-bank for the
36’ millimeter telescope. It had a 9-track tape and Tektronix storage-tube terminal. George gave me a
free hand to develop the system, though he wasn’t pleased with the result. NRAO was a Fortran shop
and by now I was calling Forth a language. He was right in that organizations have to standardize on
a single language. Other programmers now wanted their own languages.
Anyhow, I had coded Forth in assembler on the IBM 360/50 mainframe. Then I cross-compiled
it onto the 316. Then I re-compiled it on the 316 (Although I had a terminal on the 360, response
time was terrible). The application was easy once the system was available. There were two modes of
observing, continuum and spectral-line. Spectral-line was the most fun, for I could display spectra as
they were collected and fit line-shapes with least-squares [Moore 1973].
The system was well-received in Tucson, where Ned Conklin was in charge. It did advance the state-
of-the-art in on-line data reduction. Astronomers used it to discover and map inter-stellar molecules
just as that became hot research.
Bess Rather was hired to provide on-site support. She had first to learn the Forth system and then
explain and document it, with minimal help from me. The next year I reprogrammed the DDP-116 to
optimize telescope pointing. The next, Bess and I replaced the 116 and 316 with a DEC PDP-11.
The development that made all this possible was indirect-threaded code. It was a natural deve¬
lopment from my work at Mohasco, though I later heard that DEC had used direct-threaded code
in one of their compilers. Rather than re-interpret the text of a definition, compile the address of
each dictionary entry. This improved efficiency for each reference required only 2 bytes and an address
interpreter could sequence through a definition enormously faster. In fact, this interpreter was a 2-word
macro on the 11:
: NEXT IP )+ W MOV W )+ ) JMP ;
Now Forth was complete. And I knew it. I could write code more quickly that was more efficient
and reliable. Moreover, it was portable. I proceeded to recode the 116 pointing the 300’ Green Bank
telescope, and the HP mini that was inaugurating VLBI astronomy. George gave me a ModComp and
I did Fourier transforms for interferometry and pulsar search (64K data). I even demonstrated that
complex multiply on the 360 was 20% faster in Forth than assembler.
NRAO appreciated what I had wrought. They had an arrangement with a consulting firm to
identify spin-off technology. The issue of patenting Forth was discussed at length. But since software
patents were controversial and might involve the Supreme Court, NRAO declined to pursue the matter.
Whereupon, rights reverted to me. I don’t think deas should be patentable. Hindsight agrees that
Forth’s only chance lay in the public domain. Where it has flourished.
Threaded-code changed the structure words (such as DO LOOP IF THEN ). They acquired an
elegant implementation with addresses on the data stack during compilation.
Now each Forth had an assembler for its particular computer. It uses post-fix op-codes and composes
addresses on the data stack, with Forth-like structure words for branching. The manufacturer’s mne¬
monics are defined as word classes by ;CODE . Might take an afternoon to code. An example is the
macro for NEXT above.
Unconventional arithmetic operators proved their value
M* */ /MOD SQRT
SIN.COS ATAN EXP LOG
M* is the usual hardware multiply of 2 16-bit numbers to a 32-bit product (arguments, of course,
on the data stack). */ follows that with a divide to implement rational arithmetic. MOD returns both
версия 18 марта 2006 г.
Форт <с4 RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
22
2 История языка
quotient and remainder and is ideal for locating records within a file. SQRT produces a 16-bit result
from a 32-bit argument. SIN.COS returns both sine and cosine as is useful for vector and complex
arithmetic (FFT). ATAN is its inverse and has no quadrant ambiguity. EXP and LOG were base 2.
These functions used fixed-point arithmetic — 14 or 30 bits right of a binary point for trig, 10 for
logs. This became a characteristic of Forth since it’s simpler, faster and more accurate than floating¬
point. But hardware and software floating-point are easy to implement.
I’d like to applaud the invaluable work of Hart [Hart 1978] in tabulating function approximations
with various accuracies. They have provided freedom from the limitations of existing libraries to those
of us in the trenches.
The word DOES> appeared (spelled ). It defines a class of words (like ;CODE ) by specifying
the definition to be interpreted when the word is referenced. It was tricky to invent, but particularly
useful for defining op-codes.
Nonetheless, I failed to persuade Charlottesville that Forth was suitable. I wasn’t going to be allowed
to program the VLA. Of any group, 25% like Forth and 25% hate it. Arguments can get violent and
compromise is rare. So the friendlies joined forces and formed Forth, Inc. And that’s another story.
2.3.9 Moral
The Forth story has the making of a morality play: Persistant young programmer struggles against
indifference to discover Truth and save his suffering comrades. It gets better: Watch Forth. Inc go head
to head with IBM over a French banking system.
I know Forth is the best language so far. I’m pleased at its success, especially in the ultra¬
conservative arena of Artificial Intelligence. I’m disturbed that people who should, don’t appreciate
how it embodies their own description of the ideal programming language.
But I’m still exploring without license. Forth has led to an architecture that promises a wonderful
integration of software and silicon. And another new programming environment.
2.3.10 References
[ANS 1991] Draft Proposed ANS Forth, document number X3.215-199x, available from Global
Engineering Documents, 2805 McGaw Ave., Irvine CA 92714.
[Brodie, 1981] Brodie, Leo, Starting FORTH, Englewood Cliffs NJ: Prentice-Hall, 1981, ISBN 0 13
842930 8.
[Hart, 1968] Hart, John F. et al, Computer Approximations. Malabar FL: Krieger, 1968; (Second
Edition), 1978, ISBN 0 88275 642 7.
[Martin, 1987] Martin, Thea, A Bibliography of Forth References, 3rd Ed, Rochester NY: Institute
for Applied Forth Research, 1987, ISBN 0 914593 07 2.
[Moore, 1958] Moore, Charles H. and Lautman, Don A., Predictions for photographic tracking
stations — APO Ephemeris 4, in SAO Special Report No. 11, Schilling G. F., Ed., Cambridge MA:
Smithsonian Astrophysical Observatory, 1958 March.
[Moore, 1970] — and Leach, Geoffrey C., FORTH — A Language for Interactive Computing,
Amsterdam NY: Mohasco Industries, Inc. (internal pub.) 1970.
[Moore, 1972] — and Rather, Elizabeth D., The FORTH program for spectral line observing on
NRAO’s 36 ft telescope, Astronomy & Astrophysics Supplement Series, Vol. 15, No. 3, 1974 June,
Proceedings of the Symposium on the Collection and Analysis of Astrophysical Data, Charlottesville
VA, 1972 Nov. 13-15.
[Moore, 1980] —, The evolution of FORTH, an unusual language, Byte, 5:8, 1980 August.
[Rather, 1993] Rather, Elizabeth D., Colburn, Donald R. and Moore, Charles H., The Evolution of
Forth, in History of Programming Languages-II, Bergin T. J. and Gibson, R. G., Ed., New York NY:
Addison-Wesley, 1996, ISBN 0-201-89502-1.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
23
[Veis, 1960] Veis, George and Moore, С. H., SAO differential orbit improvement program, in
Tracking Programs and Orbit Determination Seminar Proceedings, Pasadena CA: JPL, 1960 February
23-26.
3 Основы языка
Язык Форт сильно отличается от других языков программирования, но он даст возможность
программисту очень просто общаться с компьютером, и это облегчает его изучение. Форт немед¬
ленно реагирует на все, что вы вводите с клавиатуры, и изучать его лучше всего, непосредственно
работая на компьютере.
Чаще всего этот язык считают сложным опытные программисты, которые имеют сложив¬
шиеся представления о том, как должен работать язык программирования, они привыкли, что
сначала надо написать длинную программу, прежде чем проверить ее работу. Поэтому поста¬
райтесь забыть то, что вы знаете о других языках, садитесь за клавиатуру обычного ПК или
возьмите свой наладонник и давайте начнем.
3.1 Учимся на практике
Так же, как сложно научиться иностранному языку без его активного использования, труд¬
но изучить язык программирования без компьютера. Как тот, так и другой язык лучше всего
изучается на практике. Вы можете ознакомится с языком, пользуясь этой книгой, и без компью¬
тера, но хорошо программировать на нем вы нс сможете. Мы посвятим часть этого раздела тому,
чтобы вы, поэкспериментировав с языком, почувствовали бы себя увереннее, и преодолели порог
вхождения в освоение. Далее мы рассмотрим Форт более подробно, в том числе познакомимся с
тем, как он устроен. Итак, попробуем поработать на Форте.
Очевидно, для начала вам надо установить и запустить Форт, но компьютеров и версий языка
так много, что для того, чтобы узнать, как этой сделать, нужно пользоваться документацией на
вашу форт-систему.
Для выбора форт-системы воспользуйтесь Internet, я могу порекомендовать несколько вари¬
антов для различных компьютеров и ОС:
i386 ПК
Windows
SP-FORTH
http://spf.sf.net
i386 ПК
DOS
SMAL32
http://www.forth.ru
Linux
FICL
http://www.ficl.org
Linux
GNU Forth (gforth)
8086/286 ПК
DOS
GP-FORTH
http://www.forth.ru
КПК
PalmOS 3.5+
Dragon FORTH
PFE (Porable FORTH Environment)
Если вы готовы, напечатайте на клавиатуре
55 111 +
В качестве клавиши для запуска ст,роки введенной строки в Форте на ПК используется, кла¬
виша Enter. Для других типов компьютеров это может быть ее аналог, типа ВК (возврат,
каретки) на древних советских машинах, или специальная экранная кнопка. При вводе с клави¬
атуры вы как бы печатаете на машинке, поэтому в тексте слова "введите с клавиатуры," и
"напечатайте с клавиатуры" означают одно и то же.
Тогда на экране вы увидите Ок (все в порядке) или другое аналогичное сообщение (зависит от
версии форт-системы). Что произошло ? Вы ввели числа 55 и 111 и сложили их, но не увидели
результат, потому что не попросили вывести его. Форт напечатал Ок, поскольку он справился с
тем, что вы ввели. Сообщение Ок — это подсказка-приглашение, которая говорит вам о том, что
Форт готов принимать с клавиатуры новую информацию.
Теперь введите
версия 18 марта 2006 г.
Форт (С) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
24
3 Основы языка
Слово .15 просит компьютер выдать пиело на экран. Вы увидите
166 Ок
т.е. сумму чисел 55 и 11.
Теперь введите
5 6 *
и получится
30 Ок
Слово * — команда операции умножения.
А теперь попробуйте
55 111 + 2 * . .
На экране должно получиться
332
Форт сначала произвел сложение, затем было введено число 2, которое было перемножено с
суммой, и был напечатан результат. Теперь введите
60 5 / .
вы увидите
12 ок
Аналогично
60 5 - .
выдаст
55 Ок
Попробуйте теперь ввести такую последовательность
5 60 - .
вы получите
-55 ок
Очевидно, что порядок, в котором вводятся числа, небезразличен.
Попробуйте ввести
5 60 / .
вы получите
0 ок
1и точка
Форт <С5 RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
25
Что произошло ? Форт в минимальной поставке работает только с целыми числами, и, конеч¬
но, 5/60 представляет собой дробь, значение которой округляется до 0. Некоторые реализации
Форта могут обрабатывать числа с плавающей запятой и даже простые дроби, и мы об этом еще
узнаем в разделе 7. А в данный момент вам необходимо еще поэкспериментировать с арифмети¬
ческими действиями.
Многих может удивить, что в базовом языке нет поддержки плавающей точки. Объяснение
этому очень простое — Форт изначально был разработан для систем управления, для которых во
многих случаях поддержка плавающей арифметики не нужна. При необходимости используются
дополнительные библиотеки, обеспечивающие использование специализированного математиче¬
ского блока (FPU), входящего в состав процесора (для ПК начиная с Intel 486DX) или в виде
отдельной микросхемы. Если архитектура компьютера вообще не предусматривает возможность
использования FPU16, используется эмуляция такого блока с использованием целых чисел или
специальные методики программирования, описанные в разделе 7.
Явное использование стека (данных) — наиболее существенное отличие языка Форт от других
языков программирования. Представим себе стек как сложенные стопкой числа или колоду карт,
помеченных числами. Когда мы вводим число, завершая его нажатием клавиши Enter, мы гово¬
рим, что число кладется в стек, как будто бы в колоду сверху добавляется одна карта, а когда
производится такая операция, как . (т.е. печать числа), мы говорим, что число выталкивается из
стека, как будто бы карта снимается с колоды. В данном случае это делается при выводе числа.
Когда вы вводите
55 111 +
числа 55 и 111 кладутся в стек, а операция + изымает их из стека, складывает и полученную
сумму снова кладет в стек. Наши "карты" показаны на рис.3.1.
Рис. 1.1
Мы пользуемся нотацией "х у +", которая называется постфиксной (от англ, "post" — после),
поскольку символ операции (оператор) стоит после чисел. Привычная нам алгебраическая нота¬
ция "х + у" называется инфиксной. Постфиксную нотацию называют также обратной польской
нотацией, сокращенно ОПН. Мы расскажем еще о стеке и постфиксной нотации в разделе 3.6.
Одним из важных достоинств постфиксной нотации является то, что она не нуждается в скобках,
при этом порядок действий определен порядком следования операторов. Попробуйте напечатать
на клавиатуре
55 111 + * .
тогда вы увидите
332 ок
Форт берет из стека два верхних числа 55 и 111, складывает их, кладет сумму назад в стек,
поэтому в нем находятся
2 166
Оператор * затем умножает число 2 на 166, что дает 332, и кладет в стек результат, который
после этого печатается. Наша аналогия с картами показана на рис.3.1. Использование обратной
польской нотации в выражении
2 55 111 + *
16 практически все 8- и большая часть 16-битных систем
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
26
3 Основы языка,
эквивалентно
2 * (55 + 111)
в обычной алгебраической нотации. Если bbi набрали на клавиатуре
55 111 2 + *
то это эквивалентно вводу
55 * (111 + 2)
что, конечно же, отличается от предыдущего примера.
Рис. 1.2
Поначалу ОПН и стек немного смущают, но после небольшой практики вы будете считать ее по
меньшей мерс такой же естественной, как и обычная алгебраическая нотация. В следующей главе
у вас будет очень много практики, но вам уже сейчас хочется сделать что-нибудь самостоятельно.
3.2 Форт-слово
Давайте пока отложим в сторону детали, связанные со стеком и обратной польской записью,
перестанем использовать Форт как калькулятор и попробуем написать программу. Наберите сле¬
дующий текст:
: TIMES2 * . ;
и вы увидите только "ок", т.е. будто бы ничего не произошло. Но теперь, если вы напечатаете
5 TIMES2
то увидите
10 ок
Вы только что определили (описали) слово TIMES2 (умножить на 2) на языке Форт, которое
представляет собой крошечную программу: ее действие состоит в том, чтобы поместить в стек
число 2, умножить его на то значение, которое было в стеке раньше, и затем напечатать резуль¬
тат. : (двоеточие) дало Форту указание начать определение и принять слово TIMES2 (каждая
следующая порция ввода заканчивается пробелом) в качестве имени нового слова Форта. Три
символа (2, * и .) — ранее существовавшие слова Форта, которые рассказывают программе, что
она должна делать, затем ; (точка с запятой) указывает на то, что определение закончено. Обра¬
тите внимание, что в качестве слова в Форте может выступать один символ, как, например, в
английском языке слова "I" (я) и "а" (артикль).
Слова Форта можно использовать двояко: либо как команды, которые должны быть немед¬
ленно исполнены, примерами этого были наши арифметические упражнения, либо для описания
новых слов. Заметим, что ввод
5 TIMES2
приводит к такому же результату, как и ввод
5 2 *
Форт <cj RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
27
Ввод слов с клавиатуры обычно приводит к такому же эффекту, как и ввод их в определения,
хотя имеются и очень важные и необычные исключения.
Почти все, что вы приказываете Форту сделать, обозначается словом или числом. Учтите,
что между словами и числами должен быть по крайней мере один пробел. Операторы типа + , *
, / и . — это слова, и даже : и ; — это тоже слова, которые указывают начало и конец описания
слова.
Программа на языке Форт пишется путем составления описаний (определений) новых слов,
для которых используются ранее определенные слова, пока не будет определено главное слово,
т.е. то слово, которое нужно ввести, чтобы исполнить главную программу. Большинство слов
языка создается в виде так называемых определений через двоеточие, потому что их определение
начинается с : и заканчивается ; (точкой с запятой).
Программы на языке Форт фактически являются расширением самого языка за счет вклю¬
чения в него новых слов и операторов.
Когда слово, например TIMES2, описывается в форме определения через двоеточие, то гово¬
рят, что оно компилируется, (помещается, заносится) в словарь Форта , который и на самом деле
представляет собой словарь, т.е. комплект слов, описанных на языке, который может понимать
компьютер. Когда какое-либо слово выполняет свои действия, как, например, когда вы вводите
5 TIMES2
мы говорим, что слово исполняется. Компиляция и исполнение — это две основные задачи, ко¬
торые выполняет Форт. Если вы знакомы с другими языками программирования, то знаете, что
они компилируют или исполняют всю программу целиком, но не такие мелкие кусочки, как опи¬
сания слов (функций или процедур). Одной из причин того, что Форт так легко взаимодействует
с пользователем, является как раз то, что программа на нем может быть легко написана (и ском¬
пилирована) в виде набора небольших фрагментов, каждый из которых может быть опробован
(и исполнен) немедленно. Именно поэтому Форт так легко изучать экспериментально.
Хотя TIMES2 в буквальном смысле представляет собой настоящую программу, она настолько
незатейлива, что вы вряд ли написали бы что-нибудь подобное. Давайте сделаем немного более
сложную программу. Сможете ли вы догадаться, что делает следующая программа
: SQUARE DUP * ;
Слово DUP (стр. 49) делает копию (дубликат) числа, находящегося в стеке. Предположим,
что мы ввели
6 SQUARE .
результатом этого является
36 ок
Слово SQUARE делает копию числа 6 в стеке, оставляя 6 6, а затем перемножает эти два
одинаковых числа, получая 36. Очевидно, слово . (точка) выводит результат. Теперь мы можем
определить
: CUBE DUP SQUARE * :
для вычисления куба числа. Если вы знакомы с другими языками программирования, то
заметите, что наши слова похожи на подпрограммы и, возможно, запротестуете против написания
таких коротких подпрограмм. Например, вы бы предпочли определить слово CUBE иначе:
: CUBE DUP DUP * * :
но на языке Форт дополнительные затраты времени исполнения и компьютерной памяти бу¬
дут незначительны, если вы поделите длинные определения на более короткие (это называется
нормализацией — делением программы на части, которые могут использоваться далее в раз¬
ных местах программы), такие программы проще будет понимать и переделывать. Определения
нужно стремиться делать короткими. Приведем полный листинг программы:
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
28
3 Основы языка
: SQUARE ( nl -- n2 ) DUP * ; \ квадрат числа
: CUBE ( nl — n2 ) DUP SQUARE * ; \ куб числа
Мы добавили комментарии, чтобы программа стала более понятной. Любой текст, заключен¬
ные в круглые скобки (с обязательным пробелом после открывающей скобки) или после слова
до конца строки, игнорируется и считается комментарием. После имени слова в соответствии
с принятым для Форта соглашением помещается информация о состоянии стека в виде ( nl -
п2 ). Стековый комментарий показывает, что было в стеке до исполнения и что стало после
исполнения данного слова. Так, например, комментарий для * выглядит так: ( nl п2 - пЗ). Ком¬
ментарий необходим для всех, кроме самых коротких слов. Без него очень легко забыть, как
работает программа.
В следующем разделе мы напишем нетривиальную программу, которая будет строить на
экране столбиковую диаграмму, или так называемую гистограмму, но сначала вам нужно, чтобы
идеи, приведенные в этом разделе, усвоились, а для этого проделайте несколько упражнений.
3.2.1 Упражнения
Упражнения, которые будут приведены в этой книге, нс являются дополнительным приложе¬
нием к тексту. Они составляют его неотъемлемую часть и должны стать неотъемлемой частью
процесса освоения языка. Упражнения составлены так, чтобы служить четырем целям:
1. тренировке,
2. углублению понимания принципов, изложенных в этой книге,
3. развитию техники программирования,
4. иногда определению слов широкого практического применения.
Вы должны попытаться проделать все упражнения, но, если у вас возникнут затруднения, нс
стесняйтесь заглянуть в ответы приложения ??: некоторые задачи бросают вам вызов. Упраж¬
нения также помогут вам продвигаться в изучении языка. Мы предлагаем серию упражнений
после часа-двух интенсивного изучения текста. Наконец, попробуйте сами придумать собствен¬
ные упражнения, связанные с вашими личными интересами. Один из лучших способов изучения
какого-либо языка программирования — писать собственные упражнения и программы.
1. Определите в уме, что будет выведено на экран следующими операциями:
(a) 20 2 / .
(b) 2 20 / .
(c) 123**.
(d) 3 2 1 + / .
(e) 100 5 1)1.1’ * / .
2. Преобразуйте следующие выражения в обратную постфиксную форму:
(a) 1*2
(b) 1*2 / 2
(c) 1 + 2/3
(<П (12)3
(e) 3 / (2 + 1)
(f) (3 + 4) / (2 + 1)
3. Опишите слово POWER4 для возведения числа в четвертую степень, используя слово CUBE.J
4. Опишите слово NEWPOWER4 (возведение в четвертую степень) используя слово SQUARE
вместо CUBE.
Форт R.U FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
29
5. Согласно теореме Пифагора квадрат гипотенузы прямоугольного треугольника равен сумме
квадратов прилежащих сторон. Определите слово PYTHAGORUS для определения квад¬
рата гипотенузы по заданным в стеке длинам его сторон. Вам может потребоваться слово
SWAP /стр. ??/ (переставить), которое переставляет между собой два числа, находящиеся
на верху стека. Так, например,
4 5 SWAP
оставит два верхних числа:
5 4
6. Определите слово AREA (площадь), которое должно вычислять площадь круга, помножен¬
ную на 100, если задан радиус. Используйте число 314 вместо значения числа тг, помножен¬
ного на 100.
7. Используя слово AREA, определите слово VOLUME (объем) для вычисления объема ци¬
линдра, помноженного на 100. В стеке должны лежать значения радиуса — на вершине и
значение высоты цилиндра вторым сверху. Переделайте VOLUME в XVOLUME, которое
ожидает данные из стека в обратном порядке (высота цилиндра — на вершине, радиус —
вторым сверху). Какая программа имеет большую эффективность (с точки зрения быстро¬
действия) ?
3.2.2 Простая программа
Хотя из соображений удобства мы знакомим вас с языком Форт на примере арифметических
операций, нужно подчеркнуть, что компьютеры приносят большую пользу не только в мате¬
матике. Например, книга [orange], на основе которой написана эта книга, была подготовлена с
помощью программы обработки текстов, написанной на языке Форт. Одно из наиболее полезных
применений компьютера состоит в преобразовании огромного количества данных в такую форму,
которая егче воспринимается человеком. В частности один из лучших способов — представление
данных в графической форме. Несмотря на то, что многие языки программирования (вклю¬
чая некоторые версии форт-систем) имеют множество сложных графических команд, одним из
наиболее распространенных способов представления графических данных является "быстрый и
грубый" график, построенный из прямых линий или столбиков. Возможно, вы привыкли к пред¬
ставлению столбиков в виде сплошных вертикальных прямоугольников, однако неплохо выгля¬
дят также столбики, построенные из рядом стоящих букв, которые печатаются по горизонтали.
Например,
хххххххххх
ххххххххххххх
ХХХХХХХХХХХХХХХХ
ххххххххххх
ххххххх
представляет собой вполне наглядную гистограмму. Мы проследим весь процесс составления
программы для построения подобной гистограммы, а затем рассмотрим ее с точки зрения струк¬
туры Форта, после чего вы сможете модифицировать программу в следующей серии упражнений.
В самом начале определим слово
: TASK ;
TASK — это слово, которое ровным счетом ничего не делает, кроме того, что помечает позицию
в словаре. Но если ввести
FORGET TASK
версия 18 марта 2006 г.
Форт © RU FIG. Понятов Д.А. <forth@km.ru> , public domain
30
3 Основы языка
то слово TASK будет удалено из словаря вместе со всеми теми словами, которые были опре¬
делены после слова TASK. Поэтому, если вы сделали ошибку в программе и хотите начатв ее
сначала, достаточно ввести
FORGET TASK
чтобы снова оказатвея в том месте, с которого вы начали. Считается хорошей манерой начи¬
нать программу с подобного, не имеющего другого смысла слова, обычно для этого используется
именно слово TASK.
Теперь нам нужно описать слово, которое будет печатать на экране строку литер "X" или
"столбик". Мы будем традиционно считать, что ширина экрана равна 80 позициям, таким обра¬
зом, пределы длины столбика от 1 до 80.
Прежде всего нам нужно узнать, как напечатать один символ "X". Самый простой способ —
это использовать слово ." . Вначале определим слово, которое должтто печатать "X" один раз,
т.е.
: .X ." X" ;
В данном случае точкой в названии .X мы отмечаем, что это слово должно что-то напечатать,
это общепринятое соглашение в языке Форт.
Теперь определим следующее слово:
: TEST 40 О DO .X LOOP ;
и, когда вы введете TEST , вы увидите на экране
ХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ Ок
т.е. 40 букв "X", после которых выведено подтверждение. Слова DO и LOOP, предписывают
Форту повторить исполнение слов, находящихся между ними, причем число повторений опреде¬
ляется двумя числами, находящимися в стеке, когда встречается слово DO, в данном случае 40
раз. Зацикливание программы, или многократное исполнение набора инструкций, очень важная
возможность языка Форт, как и других компьютерных языков.
Но слово TEST — это еще не то, что нам нужно: оно печатает столбик из 40 литер "X",
а нам необходимо печатать столбики различной длины, в зависимости от числа, находящегося
на вершине стека. Чтобы сделать это, нужно просто вынести из определения число, задающее
верхний предел цикла DO-LOOP, т.е. мы можем определить слово
: BAR О DO .X LOOP CR ;
Так как для слова DO необходимо иметь в стеке два числа, то для исполнения слова BAR
(столбик) вам нужно задавать одно из них — предел цикла. Если вы введете 23 BAR, то на экране
увидите
ХХХХХХХХХХХХХХХХХХХХХХХ ок
Обратите внимание, что слово "отпечатается на следующей строке. Это результат действия
слова CR, которое производит перевод строки. Без слова CR все наши столбики будут выстроены
в ряд друг за другом, а не один под другим.
Теперь нам нужно напечатать несколько столбиков различной длины. Другими словами, мы
хотим повторить программу BAR несколько раз. Для этого нам потребуется еще один цикл DO.
Определим слово
: TESTGRAPH CR 4 О DO BAR LOOP ;
и теперь введем строчку
5 10 15 20 TESTGRAPH
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
31
Вы увидите гистограмму
хххххххххххххххххххх
ххххххххххххххх
хххххххххх
ххххх
Конечно, данное определение ov.ier исполняться только с четырьмя числами, поскольку в
TESTGRAPH задано только четыре повторения цикла.
Мы уже почти пришли к нашей программе построения гистограммы, но в нее нужно ввести
еще несколько усовершенствований. Во-первых, мы предполагали, что ширина экрана равна 80
позициям, поэтому число больше 80 недопустимо. Нам нужно как-то ограничить длину столбика.
Во-вторых, Форт должен каким-либо образом определить, сколько чисел находится в стеке и,
следовательно, сколько нужно построить столбиков. Поэтому число 4 в цикле 4 О DO в программе
TESTGRAPH нам не нужно. Будем вводить усовершенствования в программу по одному. Во-
первых, как можно ограничить длину столбика ? Вот программа, которая может выполнить это:
: LIMITBAR DUP 80 > IF DROP 80 THEN BAR ;
Рассмотрим, как она работает. Она делает копию числа, находящегося на вершине стека,
выражение 80 > сравнивает это число с числом 80, и если оно больше 80, то в стек возвращается
значение, которое слово IF интерпретирует как истину. Если слово IF встречает значение истина,
то исполняется та часть программы, которая находится между словами IF THEN, в данном
случае DROP 80, т.е. убрать из стека число, которое там находится, и положить вместо него
число 80. Если число в стеке меньше или равно 80, то выражение 80 > возвращает в стек значение
ложь, которое IF воспринимает как указание перейти на слово, следующее после THEN, в данном
случае BAR. Если число больше 80, т.е. исполняются слова между IF и THEN, то затем процесс
продолжается также после слова THEN, но слово BAR печатает 80 литер "X", т.е. столбик,
занимающий всю ширину экрана.
Этот пример требует некоторого осмысления, но главное, что мы хотели бы в нем подчеркнуть
— большая важность в языке Форт конструкции IF.. .THEN. Она позволяет программе разветв¬
ляться, т.е. производить выбор одной из двух возможностей, как, например, в данном случае:
печатать или не печатать столбик из 80 символов "X". Есть и другие способы разветвления про¬
граммы, но данная конструкция является основной. Ветвление — это важное свойство любого
языка программирования, поскольку оно обеспечивает программирования задач.
Если вы знакомы с другими языками программирования, то, вероятно, обнаружите, что кон¬
струкция языка IF-THEN рассматривает слова DUP и BAR как подпрограммы. Подпрограммы
(т.е. небольшие программы, находящиеся внутри больших программ) всегда определяются в Фор¬
те самостоятельными словами в том смысле, что форт-программа построена из большого числа
коротких подпрограмм.
Второе улучшение состоит в том, чтобы Форт сам определял, сколько чисел нужно отобразить
на гистограмме. Это делается с помощью слова DEPTH /стр. ??/ (глубина), которое возвращает
в стек количество чисел в стеке, и не разрушает стек. Например, если ввести
28943 DEPTH .
вы увидите
5 ок
на экране (а сами числа по-прежнему находятся в стеке). Вот теперь мы можем определить
слово GRAPH, которое будет строить гистограмму чисел, находящихся в стеке:
: GRAPH CR DEPTH О DO LIMITBAR LOOP ;
Теперь посмотрим на всю программу, собранную вместе и с добавленными комментариями:
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
32
3 Основы языка,
: TASK ; \ Слово, которое
\ должно забываться
\ при стирании программы
: .X X" ; \ Символ для печати
: BAR (n--)ODO.X LOOP CR ; \ Вывод столбика из X
: LIMITBAR ( n -- ) DUP 80 > IF DROP 80 THEN BAR ;
: GRAPH ( nl n2 n3 . . . )
\ Строит столбик из не более 80 символов
CR DEPTH 0 D0
LIMITBAR
LOOP
Чтобы запустить программу GRAPH, вы должны ввести несколько чисел и после этого —
слово GRAPH. Итак, считая, что вначале стек был пустым, после ввода
9 10 12 14 10 6 GRAPH
получаем гистограмму:
ххххххххх
хххххххххх
хххххххххххх
хххххххххххххх
хххххххххх
хххххх
Несмотря на свою краткость, эта программа демонстрирует несколько важных свойств языка
Форт. Во-первых, хотя числа в Форте могут храниться в виде констант и переменных, как и в дру¬
гих языках программирования, чаще всего это не требуется. Обычно достаточно использования
стека.
Во-вторых, форт-программа состоит из последовательности определений слов через предше¬
ствующие им слова, так, например, для слова GRAPH используется определение слова LIMITBAR,|
которое основано на определении слова BAR, использующем определение слова .X , в свою оче¬
редь, включающее определение слова ." , а последнее является первичным словом любой версии
языка Форт. Таким образом, для определения слов применяются ранее данные определения,
основанные на первоначально определенных словах языка.
В третьих, форт-программы компактны. Текст программы на Бейсике или Фортране, предна¬
значенной для решения этой задачи, будет намного длиннее, форт-программы обладают большим
быстродействием, хотя пока данное утверждение надо принять на веру.
В четвертых, форт-программа составлена из коротких слов или определений, каждое из кото¬
рых может быть проверено и отлажено отдельно, форт-программу сравнительно легко усовершен¬
ствовать и изменить без изменения большинства входящих в нес частей. Например, программа
GRAPH может быть переделана для экрана, имеющего ширину 64 позиций, простой заменой
числа 80 на 64 в слове LIMITBAR.
Наконец, форт-программу, как правило, проще понять, чем любую другую, просмотрев опре¬
деление последнего слова. Так, например, глядя на определение слова GRAPH, вы увидите, что
нужно понять определение слова LIMITBAR, которое в свою очередь, приводит к слову BAR, а
оно уже почти очевидно само по себе. Программы легко читаются (особенно если они снабжены
продуманными комментариями и удачно выбраны имена слов), правда, нс сверху вниз, как чи¬
таются программы на Бейсике, Фортране или Паскале, форт-рограмму прочитывают, начиная с
какого-либо важного слова, разбирая затем, для чего предназначено каждое слово, входящее в
его определение.
В заключение следует сказать несколько слов о методике программирования на языке Форт.
Прежде всего вы должны хорошо понять, что будет делать программа, а отсюда вы придете к
словам, которые для нее необходимо определить. Например, для программы GRAPH, очевидно,
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
33
необходимо слово BAR, а для него, в свою очередь, потребуется слово .X. Разработка программы
продвигается одновременно на двух уровнях: на системном уровне, когда на основе понимания
конечной цели определяются слова, которые нужно описатв, и на уровне подпрограмм, иначе
говоря, слов, когда описывается и проверяется каждое слово.
Программирование на языке Форт — это органический интуитивный и творческий процесс,
который завершается, как правило, эффективными программами как на уровне болвшой систе-
мв1, так и на уровне отдельных слов (подпрограмм).
3.2.3 Упражнения
Мы собираемся предложитв вам модифицировать нашу графическую программу. Проще всего
заниматься этим, если вы запишете ее на диск, а затем отредактируете, чтобы внести изменения
по условиям упражнения, форт-система обычно читает программы из простых текстовых фай¬
лов, но некоторые системы, работающие как самостоятельные операционные системы на различ¬
ном автоматизированном оборудовании, сохраняют программы в нумерованных блоках емкостью
1024 символа в каждом, что соответствует размеру экрана 16 строк по 64 символа, характерного
для компьютеров 80х годов.
Другой вариант — запись программы на магнитной ленте (на бобинах или аудиокассетах) с
установленного вручную места в виде закодированных в звуке данных. Этот способ хранения
характерен для всех бытовых компьютеров начала 90х, которые использовали для хранения дан¬
ных дешевый и доступный носитель. Любители таких компьютеров до сих пор иногда используют
подобную технику хранения данных, но вместо кассетного или катушечного магнитофона при¬
меняют современные мобильные аудиоустройства — шрЗ-плееры или дискмены, подключая их
с помощью спаянного из подручных материалов устройства сопряжения (в простейшем виде —
кабеля с разъемами).
Поскольку разные версии Форта отличаются способами хранения и редактирования про¬
грамм, рекомендуем обратиться к документации на вашу форт-систему, чтобы узнать, как со¬
хранить программу на диске. Для того чтобы ввести программы на диск, вы будете набирать ее
на клавиатуре и пользоваться редактором. Затем программу можно будет загрузить.
Для блочной загрузки нужно ввести номер блока и после него слово LOAD (загрузить), на¬
пример
68 LOAD
Эта команда вызовет интерпретацию слов, которые с помощью редактора были записаны на
диск или ленту, так же, как если бы их вводили с клавиатуры. Компьютер не знает и ему безраз¬
лично, откуда производится ввод, с клавиатуры или из блока на диске. Большое преимущество
этого состоит в том, что можно модифицировать или редактировать программу на диске, не
вводя ее каждый раз целиком с клавиатуры.
Старую скомпилированную программу можно забыть (т.е. удалить ее из памяти ЭВМ), если
ввести FORGET TASK перед вводом измененной программы словом LOAD.
Если вы пока не хотите обременять себя изучением редактора и способов загрузки, можете
каждый раз вводить ее с клавиатуры. Но нельзя просто ввести скорректированное определение
какого-либо слова с клавиатуры, если оно входило в определение какого-либо последующего сло¬
ва. Дело в том, что это слово было скомпилировано раньше совместно со старым определением
скорректированного вами слова.
Ввиду того, что многие редакторы, поставляемые со специализированными встроенными
форт-системами, достаточно примитивны, мы предложим вам специальный раздел, посвященный
написанию собственного редактора, который вы сможете адаптировать под себя. Однако вам все
же придется научиться пользоваться редактором вашей форт-системы или вспомогательными
программными средствами на персональном компьютере, чтобы написать этот редактор.
1. Введите целиком программу с диска, если у вас есть такая возможность, и забудьте ее.
Теперь снова введите. В чем преимущества ввода с диска ?
2. Модифицируйте программу GRAPH так, чтобы вместо "X" она печатала столбики черточ¬
ками (измените только один символ).
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
34
3 Основы языка
3. Модифицируйте программу так, чтобы гистограмму можно было рисовать на экране ши¬
риной 40 позиций. Снова измените программу на 80 позиций.
4. Измените программу так, чтобы в нее можно было вводить числа от 0 до 6400. Для этого в
подходящем месте программы LIMITBAR нужно поместить операцию 100 ,/. Назовите эту
программу LIMITBAR 1.
5. Переделайте LIMITBAR в LIMITBAR2 так, чтобы она могла принимать числа от 0 до 10000,
причем числу 10000 должен соответствовать столбик длиной 64 символа.
6. Измените программу GRAPH, чтобы она строила гистограмму нс более 16 чисел. Вам по¬
требуется оперативно применить конструкцию IF-THEN.
7. Измените слово BAR так, чтобы в конце столбика, которым представляется число, печата¬
лось это число. Вам потребуется вставить слова DUP и . в подходящих местах определения
BAR. Теперь измените LIMITBAR в LIMITBAR3 так, чтобы максимальное число литер
"X" было равно 50. Мы надеемся, что эти упражнения доказали вам, почему определение
программы через отдельные работы, задачи и слова позволяет особенно легко изменять ее
при необходимости.
3.2.4 Выводы
Основной структурной единицей языка является форт-слово (или просто слово), кооторое мо¬
жет быть составлено из любых символов, кроме пробела. Маленькая и большая буквы — это два
разных символа. Пробел разделяет слова в форт-программе. Максимально допустимое количе¬
ство символов в слове зависит от конкретной реализации форт-системы. Программирование на
языке Форт сводится к определению новых, специализированных для целей пользователя, слов
в терминах ранее введенных слов. Некоторый начальный набор слов написан непосредственно в
терминах машинного языка конкретного компьютера.
Программист может определять свои собственные операции, создавать специальные типы
данных и, таким образом, развивать язык в сторону конкретных приложений. Естественным
результатом программирования является создание приспособленного для решения задач поль¬
зователя языка, то есть создание проблемно-ориентированных DSL1' языков.
Обычно текст определения нового слова помещается в двух-трех строках экрана. После ввода
такое определение компилируется (это называется режимом компиляцгш). Успешно скомпили¬
рованное слово заносится в так называемый словарь. Теперь можно вводить с терминала его имя,
что задаст исполнение слова, то есть выполнение указанных им действий. Система при этом пе¬
реходит в режим исполнения. Обычный режим диалога — это режим исполнения. При попытке
исполнить еще нс определенное слово система печатает его имя с комментарием ’-?’ или аналогич¬
ным сообщением об ошиюке. Скомпилированное новое слово можно использовать в дальнейших
определениях.
Существует принятый международный стандарт языка, точнее несколько версий стандартов
с указанием номера — года его принятия, в частности FORTH-83, FORTH-94. Стандарт фиксиру¬
ет определенный набор слов, их имена и функции. Таким образом, программы, удовлетворяющие
стандарту, могут использоваться с любыми стандартными форт-системами. Конкретная реали¬
зация может отличаться от стандарта, что обычно указывается в документации. Список слов в
конкретной форт-системе, в том числе и вновь определенных, выводит на экран слово WORDS.
Вместе с именами слов иногда даются их адреса в словаре. Последнее определенное слово будет
верхним в распечатке.
Одно из главных достоинств языка Форт заключается в его расширяемости, то есть програм¬
мист может расширять базовый набор слов форт-системы, определяя новые слова через уже
определенные.
Слова, которые указывают форт-системе, что пользователь заводит новое слово, называются
ОПРЕДЕЛЯЮЩИМИ словами. Наиболее употребительное определяющее слово это (двоето¬
чие). Формально соответствующее определение (или описание) выглядит следующим образом:
17 Domain Specific Language
Форт <с) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 тларта 2006 г.
3 Основы языка,
35
: имя тело ;
• "имя" как раз и есть новое придуманное слово,
• "тело" представляет собой перечень через пробелы уже имеющихся в форт-системе слов;
совокупность их функций образует те действия, которые будут выполнены при исполнении
данного слова,
• наличие слова ";" (точка с запятой) обязательно, оно завершает определение.
Например, текст
: S2 DUP * SWAP DUP * + ;
определяет слово "S2", вычисляющее сумму квадратов двух чисел из стека
а b -->
S2
a*a+b*b
Если в теле определения встретятся слова, которых нет в словаре, система напечатает оши¬
бочное слово со знаком При этом вся наработанная информация о новом слове исчезает.
При разработке новых слов нужно внимательно следить за изменениями стека. Рекомендуется
писать комментарии. Комментарий начинается словом "(" (открывающая скобка), и система
пропускает следующий за ним текст до первого символа ")" (закрывающая скобка).
Скомпилированные слова сразу же могут использоваться и в вычислениях и в определении
других слов. Например, сумму четырех квадратов можно определить так:
S4 (abed --> a*a+b*b+c*c+d*d )
S2 -ROT S2 + ;
Можно отменить уже определенное слово ("забыть" его), но при этом забываются также и все
слова, определенные позже него. Для этого используется слово "FORGET". Например, действие
FORGET S2
"забудет" S2 и все определенные позже слова.
Прежде, чем заводить новое слово, стоит убедиться, что его еще нет в словаре. Одному и тому
же слову можно дать несколько определений с разным смыслом, но выполняться будет только
последнее введенное. Однако прежнее определение не уничтожается. Если теперь выполнить
слово "FORGET" с этим словом, то снова будет действовать прежнее определение. При отладке
больших программ полезно иногда применять слово "FORGET", чтобы избежать переполнения
словаря.
Надо помнить, что при вводе нового слова с клавиатуры его исходный текст пропадает. В
словаре запоминается только скомпилированная форма. Чтобы внести изменения в уже опре¬
деленное слово для перекомпиляции, приходится перенабирать его определение полностью или
использовать внешнюю память.
При завершении сеанса работы с форт-системой, что обычно задается словом "BYE", из сло¬
варя исчезают все новые слова, определенные в этом сеансе. Способ сохранения наработанной
версии форт-системы зависит от конкретной реализации.
Приведем еще пару примеров. Слово "8M0D" эквивалентно тексту "8 MOD", но использует
логические операции. Слово "LAST1" выделяет в двоичном разложении числа младшую единицу.
: 8M0D 7 AND ;
: LAST1 DUP DUP 1- XOR AND ;
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
36
3 Основы языка,
3.3 Что такое машинный язык ?
В доисторические программные времена, когда компьютеры были еще динозаврами, простой
факт того, что некий гений создал программу, которая правильно работает, вызывал великое
удивление. По мере роста цивилизованности ЭВМ это удивление слабело. Руководители желали
большего от программистов и их программ.
В то время, как стоимость аппаратуры устойчиво падала, стоимость программного обеспече¬
ния взмывала ввысь. Для программы было уже недостаточно хорошо просто правильно выпол¬
няться. Она должна была быть разработана быстро и обладать легкостью в управлении. Новое
качество наряду с корректностью стало важнейшим. Это недостающее качество было названо
"элегантностью".
Чтобы задать вопрос, почему Форт работает не так, как другие языки программирования,
надо сначала спросить, а что такое язык ЭВМ ? Компьютер — это машина, которая может
производить включение и выключение переключающих устройств18 с очень большой скоростью
(миллион или более раз в секунду). Каждое переключающее устройство может представлять "1"
(включено) или "О" (выключено), большая часть этих переключающих устройств находится в
памяти ЭВМ. Компьютер может хранить числа, буквы и другие данные в памяти, поскольку он
обладает способностью переводить их в последовательность из единиц и нулей (включенных и
выключенных состояний переключающих устройств). Так, например, буква R обычно хранится
в ЭВМ в виде 01010010, буква S — в виде 0101011, а буква г — как 01110010. Но еще важнее, что
и инструкции, которые указывают компьютеру, что он должен делать, также хранятся в памяти
в виде последовательности из единиц и нулей. Центральное процессорное устройство (ЦПУ) счи¬
тывает эти последовательности, определяя, что делать. Эта последовательность единиц и нулей,
на которую отзывается центральный процессор, представляет собой программу самого низкого
уровня, и фактически только такую программу процессор может непосредственно исполнять.
В отличие от компьютеров человек не обладает способностью мыслить категориями единиц
и нулей. Поэтому он нуждается в языке для общения с компьютером. Самый простой язык, ко¬
торый называется машинным языком, представляет собой попросту процессорные инструкции
в виде последовательностей из многоразрядных чисел, которые хранятся в компьютере пред¬
ставленными в виде единиц и нулей. Однако и такое представление трудно для человеческого
восприятия, поэтому пользуются языком более высокого уровня, в котором каждая инструкция
представляется некоторой аббревиатурой (или, как говорят, мнемоникой), которая, к примеру
может указывать, что компьютер должен переслать число из памяти в регистр ЦПУ. Каждая
мнемоническая инструкция, в свою очередь, ассемблируется (размещается) с помощью програм¬
мы, которая написана на машинном языке так, чтобы сформировать в памяти последователь¬
ность из единиц и нулей. Программа, предназначенная для этой цели, называется ассемблером,
а язык этого уровня также называется ассемблером, или языком ассемблера.
Язык ассемблера обладает тем достоинством, что он может управлять всеми доступными
данному процессору операциями и, кроме того, создает очень компактные программы, которые
эффективно используют запоминающее устройство и обеспечивают максимально возможную ско¬
рость работы ЭВМ. Недостатком же его является то, что программист должен описать действия
ЭВМ вплоть до самых мелких деталей. Например, нельзя на языке ассемблера дать команду
компьютеру перемножить два числа, необходимо расчленить процесс умножения на ряд более
простых шагов. Программа умножения двух чисел, записанная на языке ассемблера, может вы¬
литься в некоторое количество строчек. Поэтому на языке ассемблера обычно пишут те програм¬
мы, которые должны работать с максимально возможным быстродействием с учетом мельчайших
подробностей работы компьютера, например программы для управления запоминающим устрой¬
ством на магнитных дисках.
Язык ассемблера все же неудобен для решения большинства практических задач, поэтому в
основном его используют для написания других языков программирования, чтобы еще на одну
ступень подняться над машинным языком ЦПУ. Языки такого рода называют языками програм¬
мирования высокого уровня. К ним относятся Фортран, Бейсик, Кобол, АПЛ, Паскаль и тот,
который нас здесь больше всего интересует — Форт. Они преобразуют понятные человеку симво¬
лы (например, * — обозначение операции умножения двух чисел) в последовательность понятных
18
триггеров
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
37
компьютеру инструкций из единиц и нулей. Следовательно, языки высокого уровня выполняют
роль переводчиков между человеком и ЭВМ.
Языки высокого уровня традиционно разделяются на два класса: интерпретирующие и ком¬
пилирующие. Компилирующим языком называют такой язык, который целиком преобразует ис¬
ходную программу в машинный язык, исполняющуюся так же, как программа, написанная непо¬
средственно на машинном языке. Текст программы, написанный на языке близком к обычному
английскому, называется исходным кодом, инструкции на машинном языке — скомпилирован¬
ным кодом. Часто текст программы называют просто кодом, будь то язык машины, ассемблера
или язык высокого уровня. Компилирующие языки появились первыми, самыми старыми среди
них являются Фортран, Алгол и Кобол, которые еще и сейчас применяются преимущественно
на больших ЭВМ. Особенно это относится к Фортрану — для этого языка написано огромное
количество расчетных программ, поэтому он до сих пор очень активно используется в научных
расчетах.
Достоинство компилирующих языков состоит в том, что громадный исходный код программы
но нужно размещать в машине, она транслируется в машинный код один раз, а исполняемая
программа работает обычно очень быстро и для ее размещения требуется меньше места в памяти.
Недостаток же состоит в том, что сам процесс компиляции очень трудоемок, трудоемок также
процесс внесения исправлений и изменений в программу (отладки программы), потому что при
внесении любого изменения ее приходится заново компилировать целиком.
Интерпретирующий язык транслирует исходный код программны (интерпретирует) строчку
за строчкой при каждом исполнении программы. Интерпретирующим языком является Бейсик,
хотя также существуют и компилирующие версии этого языка. Очевидно что при исполнении
программы на интерпретацию расходуется время, поэтому интерпретирующие языки по своей
природе работают медленное, чем компилирующие. С другой стороны, исходный текст програм¬
мы можно легко изменить, потому что он всегда находится в компьютере, а скорректированную
программу можно быстро и просто проверить. Обычно интерпретирующие языки поощряют при
их изучении и программировании к применению метода проб и ошибок. Кстати, язык Бейсик
был первоначально разработан в Дартмутском колледже как раз для изучения компьютерных
языков. Интерпретирующие языки обычно общительны, в том смысле, что они делают общение
между программистом и программой (и, следовательно, компьютером) относительно несложным.
Собственно говоря, то что написано в этом разделе — бред ! Не надо путать язык и его
реализацию. Язык задает только внешний вид программы (синтаксис), доступные в языке и
дополнительных библиотеках возможности и поведение компьютера при выполнении выраже¬
ний (семантику). А вот реализация. — это как раз способ, каким, программа на языке (исходный
код) переводится в форму, выполняемую компьютером.. Перевод из исходного кода выполняет
компилятор, при. этом конечный результат компиляции это название не изменит.
Если на выходе получается нативный (native) машинный код. то выполнять его будет на¬
стоящий процессор компьютера. Если же на выходе получается промежуточное представление
программы в каком-нибудь странном виде, то программа будет выполняться интерпретатором.
Построчная интерпретация теста программы, как было описано выше, не используется
уже. лет 20. Кроме того, мощные современные интерпретаторы умеют генерировать натив¬
ный .машинный код на ходу19, что сильно покоряет работу прогрымм. Даже BASIC на старом
добром ZX Spectrum хранил программу в модифицированном виде — каждая команда языка заме¬
нялась числовым кодом (токеном), и при выполнении для каждого токена запускалась процедура
в машинном коде процессора Z80.
Диалоговый режим работы тоже с интерпретацией никак не связан — в качестве примера
см., языковые системы Java и Microsoft .NET — это интерпретаторы, но цикл разработки
программ для них тот же самый: редактирование, компиляция, отладка.
То же .можно сказать и про Форт. Есть форт-компиляторы, дающие на выходе нативный
машинный код с хорошей оптимизацией — SP-FORTH например, причем он умеет работать и
в диалоговом режиме. Есть компиляторы, переводящие программу в интерпретируемую форму
(байт-код или другие варианты интерпретируемого кода) — подавляющее большинство осталь¬
ных Фортов. В книге описан пример форт-компилятора,, который также компилирует в байт-
код, но сам. по себе представляет всего пару страниц программы на Форте, подгружаемой к
готовой форт-системе.
19 ЛТ-компиляция
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
38
3 Основы языка,
Но в Форте исторически сложилась терминология, отличающая от общсприянтой. Под
компиляцией подразумевается добавление в код форт-системы (нативный или интерпретиру¬
емый) нового кода и данных. Под интерпретацией — разбор (парсиннг) исходного текста, при
котором выделенный элемент языка (слово или число) выполняется немедленно.
3.4 Что такое Форт ? Шитый код
Из всего сказанного может показаться, что у нас есть только два выбора среди языков про¬
граммирования: либо быстрые, но громоздкие компиляторы, либо медленные, но зато общитель¬
ные интерпретаторы. К счастью, Форт является еще одной альтернативой. Программы, написан¬
ные на языке Форт, по быстродействию не уступают, а то и превосходят программы, написанные
на компилирующих языках20.
форт-программы очень легко изменяются и отлаживаются. Еще одним их достоинством явля¬
ется то, что они обычно занимают в памяти меньше места, чем программы на других, как компи¬
лирующих, так и интерпретирующих языках. Дополнительное преимущество языка заключается
в том, что он дает возможность программисту определить некоторые слова на языке ассембле¬
ра, когда требуется максимальное быстродействие, т.е. в нем совмещаются преимущества языка
высокого уровня и языка ассемблера. В определенном классе применений языка 21 форт-система
часто используется в качестве оболочки для запуска процедур в машинном коде, обладая при
этом функциональностью полноценного языка программирования, например используя проце¬
дуры форт-системы и ваши специфические процедуры в машинном коде можно задать новые
команды, выполняющие часто используемые пли длительные операции.
Чем объясняются все эти достоинства языка Форт ? Тем, что он является интерпретирующим
языком с шитым кодом. Чтобы разобраться, что это значит, нужно рассмотреть, что происходит
при определении форт-слова. В поставляемом потребителям виде базовая форт-система содер¬
жит множество слов, которые были определены не с помощью других слов, а непосредственно в
машинном коде (они составляют часть, называемую ядром языка). Эти слова используются для
описания других слов, и их называют примитивами. Примерами примитивов являются слова *,
+, DUP, SW и т.д.
Если вы компилируете слово SQUARE, вводя
: SQUARE DUP * ; <ВК>
в компьютер нс вводится никакого нового машинного кода, вы только предлагаете ему соединить
вместе коды слова DUP и * под именем SQL'ARE. Точно также и С.'ЕВЕ:
: CUBE DUP SQUARE * :
не вводит нового машинного кода. Аналогично и слово POWER,4, которое вы определили в одном
из упражнений.
Компиляция состоит как бы в протаскивании одной нити через различные определения с ис¬
полнением встречающихся по пути примитивов и машинных команд. Когда исполняется слово
POWER4, "нить" проходит так, как показано на рис.1.3. Все необходимые действия, кроме ввода
в память, были выполнены с помощью двух примитивов DI P и *, входящих в ядро и определен¬
ных в машинном коде. Если вы знакомы с компиляцией в других языках программирования, то
заметите, что Форт осуществляет ее совершенно по-другому. В гл.14 и 15 мы подробно рассмот¬
рим, как работает компилятор шитого кода. В книге Лулигера (1981) рассматриваются некоторые
теоретические вопросы разработки интерпретирующих языков, использующих шитый код.
рис. 1.3
Теперь мы можем понять причину многих достоинств языка Форт: программирование в диа¬
логовом режиме, гибкость, большая скорость, минимальные потребности памяти и такое же пол¬
ное управление оборудованием компьютера, какое доступно ассемблеру или машинному языку.
20
при условии что используется компиляция программ в реальный машинный код, а не в интерпретируемые
промежуточные представления программ типа байт-кода, адресов вложенных вызовов и других вариантов шитого
кода
21 встраиваемые системы, или embedded
Форт с R.U FIG, Понятов Д.А. <forth©km.ru> . public domain
версия 18 марта 2006 г.
3 Основы языка,
39
Вы уже убедились в больших возможностях общения с языком на примерах и упражнениях этой
главы.
Большое преимущество в скорости работы перед другими интерактивными языками объяс¬
няется тем, что последние, как правило, используют ресурсоемкие высокоуровневые фичи, типа
ООП и классов, динамическое распределение памяти под все переменные с автоматической сбор¬
кой мусора, динамическую типизацию, абстрактные типы данных типа списков, хэшей, массивов
переменной длины, многозадачное/многопоточное выполнение программ. В результате наклад¬
ные расходы на обеспечение работы этих механизмов сильно замедляют работу интерпретатора
байт-кода.
Еще раз повторюсь — современные интерпретирующие реализации языков компилируют ис¬
ходный код программы во внутреннее представление (байт-код), и только после этого интерпре¬
татор выполняет программно этот байт-код, а не сам исходный текст программы. В качестве
примера можно привести реализации QuickBASIC, Visual Basic, Python, Perl, Clipper, Lisp, и еще
десятки а может и сотни реализаций языков.
От них отличаются Java, .NET, OS Inferno — эти реализации используют разнесенные по
времени и компьютерам этапы компиляции и интерпретации: программа компилируется разра¬
ботчиком в байт-код и записывается в файлы (для Java это -jar). Пользователь запускает эти
файлы на своем компьютере или мобильнике, запуская их внутри интерпретатора байт-кода —
например виртуальной Java-машине.
В Inferno используется несколько измененный вариант — компилятор языка Limbo (клон СН—h
с дополнительными возможностями по распараллеливанию) работает как front-end22, компили¬
руя программу в платформенно-независимую промежуточную (упакованную) форму. Затем эта
промежуточная форма может быть выполнена в интерпретаторе, или откомпилирована в насто¬
ящий машинный код специальным back-endoM для конкретной целевой платформы. Архитекту¬
ра виртуальной машины DIS системы Inferno использует трехместные операции память-память-
память, а не стековые как Java и .NET CLR, и поэтому каждая команда промежуточного кода
компилируется для реальных регистровых процессоров в 2-3 команды нативного машинного кода
с хорошей оптимизацией.
Если найдутся желающие, они могут попытаться применить такой подход к байт-коду os ??,
описанному в этой книге, компилируя его в машинный код частично в процессе интерпретации
(JIT-компиляция) или полностью в машинный код (back-end).
3.4.1 Подпрограммный шитый код
Следует особенно выделить одну особенность языка Форт — его реализации используют
несколько типов кода, в который компилируется тексты программ.
Прежде всего это настоящий машинный код компьютера — для создания нити шитого кода
используются настоящий машинные команды типа CALL и RET, так что слово SQUARE будет
скомпилировано в машинный код, аналогичный следующему тексту на ассемблере:
SQUARE_header: db .... ; каждое слово в Форте имеет специальный
; заголовок, в котором хранится имя слова
; и служебная информация форт-системы
SUQARE_code:
call DUP_code
call mul_code
ret
; вызов машинного кода форт-слова DUP
; вызов машинного кода слова *
; машинный код, компилируемый словом ;
Некоторые форт-системы вместо компиляции вызова примитива типа DUP и * скомпилируют
непосредственно машинный код этих слов23, что даст экономию на времени работы команд CALL
и RET и при этом сильно увеличит размер машинного кода.
3.4.2 Косвенный шитый код
Больная часть скомпилированного кода форт-программ состоит из вложенных вызовов, по¬
этому для того чтобы уменьшить размер скомпилированного кода используют специальный ин¬
22 термин из компиляторостроения
23 inline компиляция
версия 18 марта 2006 г.
Форт RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
40
3 Основы языка,
терпретатор адресов и выполняют компиляцию не в машинный код, а просто компилируют
адреса вызываемых слов без самой команды CALL:
SQUARE_header: db ...
SQUARE_code:
call address_interpreter
SQUARE_packed:
dw DUP
dw *
dw NEXT
При запуске этого слова будет вызван адресный интерпретатор, который возьмет с аппарат¬
ного стека адрес SQUARE_packet и последовательно пробежится по списку адресов, выполняя
команду CALL для них. Вызов NEXT приведет к завершению работы текущего слова.
3.4.3 Байт-код (свернутый шитый код)
В приведенных примерах шитого кода как к том, так и в другом случае используется ре¬
альный машинный код, к которому кроме того есть доступ и из форт-программ, что уменьшает
надежность и естественно переносимость между разными типами компьютеров.
Более надежным является использование свернутого шитого кода, или байт-кода: байт-код
это машинный код виртуального компьютера, работа которого имитируется программно - ана¬
логично работают Java, Perl и множество других языков.
Байт-код выполняется интерпретатором виртуальной машины, который имитирует работу
процессора — получас! из массива, в котором находится байт-код, команды и в зависимости от
полученной команды выполняет определенное действие.
Чаще всего интерпретатор байт-кода пишется на С^+ или даже ассемблере, но если вы готовы
пожертвовать скоростью работы ваших программ, интерпретатор может быть написан на любом
языке программирования, способном прочитать двоичный файл в массив.
Основное достоинство использования байт-кода, которое покрывает значительную потерю
скорости по сравнению с машинным кодом — возможность программной реализации различных
вариантов многозадачности, зашиты памяти разных задач, отладки любой сложности, отслежи¬
вания характеристик работы программ, и особенно блокировка доступа к реальному компьютеру
из программ в байт-коде.
Кроме того учитывая появление в последнее время множества типов мобильных устройств,
которые на самом деле представляют из себя полноценные компьютеры, дополненные различ¬
ными специализированными модулями типа модулей GSM в мобильных телефонах, использова¬
ние очень простого интерпретатора байт-кода позволяет решить основную проблему для таких
устройств — их полную аппаратную несовместимость, что есть машинный код для одной модели
телефона или КПК невозможно запустить на остальных типах устройств.
Кстати, учитывая ограниченную производительность процессоров мобильных устройств и ма¬
лые объемы памяти, использование языка Форт компилируемого в байт-код кажется намного
эффективнее, чем использование монстров типа Java. Вот только существуют ли телефоны, для
которых есть исходный код их прошивок и простой механизм перепрограммирования, чтобы на
практике проверить эффективность использования Форта, зашив вместо стандартной прошивки
интерпретатор байт-кода ?
Поскольку интерпретация включает в себя преобразование кода программы в машинный код
строчка за строчкой во время исполнения программы, то и Форт, и любой другой компилирующий
язык должны работать намного быстрее. Скорость их работы складывается из нескольких ком¬
понент. Во-первых, использование стека позволяет сэкономить время на извлечение переменных
из памяти, если выполняются операции с числами (стек можно разместить в быстрой кэш-памяти
или разместить непосредственно в процессоре). Во-вторых, переход от примитива к примитиву
и от слова к слову также занимает очень мало времени. В-третьих, в процессе исполнения про¬
граммы Форт делает только минимальную проверку ошибок, поэтому не подключаются никакие
"скрытые" программы для их обнаружения, например, если вы пытаетесь разделить число на 0.
Проверка ошибок целиком возлагается на программиста. Поскольку форт-программ а составля¬
ется и отлаживается слово за словом, это может при отладке сильно мешать, поэтому проверку
Форт R.U FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
41
ошибок можно предусматривать "по обстоятельствам". Наконец, программируя на Форте, прихо¬
дится отчетливо представлять себе и учитывать, что и как делает компьютер, поэтому программа
получается более эффективной.
Очень малая потребность в памяти, присущая Форту, вызывается применением шитого ко¬
да и пресжде всего низкоуровневостью команд языка. В отличие от других интерпретирующих
языков не требуется, чтобы код исходной программы всегда находился в памяти. И в отличие от
любого компилирующего языка каждый примитив и процедуры, определенные на машинном язы¬
ке, хранятся в памяти в единственном экземпляре. Большинство же компиляторов добавляют к
программе блоки машинного кода примитивов при каждом обращении к ним. Когда компилятор
встречает в исходном коде вызов функции, он отыскивает в библиотеке определенные на машин¬
ном коде процедуры и размещает их в памяти, поэтому, если функция вызывается несколько раз,
то в память будет помещено несколько копий машинного кода процедуры. Интерпретирующий
язык с шитым кодом записывает процедуру в память только один раз и делает переход к ней
из любого места, где она потребуется. Поэтому форт-программа может занимать в памяти зна¬
чительно меньше места, чем эквивалентная программа, написанная, скажем, на Фортране. При
этом время вызова и возврата из процедуры чаще всего мало, и потеря скорости по сравнению с
inline-компиляцией этих процедур незначительна.
Наконец, Форт обладает потрясающей способностью управлять компьютером, поскольку на
нем довольно легко определить новые примитивы, т.е. процедуры в машинных кодах, при усло¬
вии что не используется виртуальная машина и байт-код. Если определение слова начинается с
CODE, то все, что следует после этого слова, описывается на языке ассемблера и при ассембли¬
ровании превращается в машинный код, который становится частью определения этого слова.
Описание вы найдете в гл. 16. Поскольку слова Форта можно легко комбинировать с мнемони¬
кой ассемблера, он обладает мощью ассемблера и удобством языка высокого уровня. Очевидно,
что программирование на форт-ассемблере не является обязательным, но приятно сознавать, что
такая возможность имеется при необходимости.
3.5 Некоторая критика языка Форт
Оппонентами языка Форт чаще всего бывают программисты, не сумевшие понять его об¬
щие идеи и большие возможности. Форт устроен так, чтобы обеспечить максимальную мощь и
гибкость языка высокого уровня при очень ограниченных вычислительных ресурсах (скорости
процессора, объему памяти). Это подразумевает, что функции, которые заранее определены в
других языках, в минимальных реализациях языка Форт могут отсутствовать.
Например, стандарт языка Форт описывает только простейшие методы обращения со стати¬
ческими символьными строками, не содержит процедур для работы с матрицами, векторами,
списками, очередями, многомерными массивами переменной длины, объектами и т.п., не обес¬
печивает чтение данных из файлов24, простейшие реализации не могут обращаться с числами с
плавающей запятой .
Кроме того, считается, что форт-программу трудно читать и понимать, потому что слова в
определениях могут быть названы короткими и загадочными именами. Ни одно из этих кри¬
тических замечаний в действительности не обосновано, поскольку они относятся к конкретным
реализациям и версиям Форта пли к программистам, работающим на этом языке.
Поскольку Форт допускает определение слов на языке ассемблера, буквально все, что можно
запрограммировать на других языках, может быть сделано и на Форте. Можно даже написать
на языке Форт другие языки программирования. А так как на языке Форт легко определяются
новые слова, то нетрудно написать процедуры либо на языке ассемблера, либо с помощью других
слов Форта, которые отсутствуют в стандарте, т.е., например, слова для работы с символьными
строками или матрицами.
Работая на языке Форт, вы можете сами определить новые слова, которые нужны для вашей
конкретной задачи. Например, если вы однажды определите слово для вычисления определителя
матрицы, то в дальнейшем вам не потребуется проделывать это снова. Оно станет частью вашего
варианта языка. Различные версии (диалекты) языка можно развивать для удовлетворения по¬
требностей каждого программиста. Форт не очень удобен для сложных действий с числами, если
24 поддержка файловой системы необязательна, и соответствующие слова вынесены в опциональный FILE
WORD SET
■u как, например, число 293.45, которое имеет целую и дробную части
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> . public domain
12
3 Основы языка,
не расширить его специальными словами, то же относится и к работе с символьными строками.
Но если уж вы введете эти расширения, то они будут как раз тем, что вам нужно, поскольку вы
сделали их сами.
В некоторых поставляемых версиях языка Форт Форт заранее определено больше слов, в
других — меньше. Основная цель этой книги состоит в том, чтобы показать вам, как можно
приспособить версию языка, с которой вы работаете, к вашим задачам, например, к обработке
символьных строк, а при необходимости написать свою собственную. Можно даже встроить Форт
в ваши программы на других языках, используя его для написания пользовательских скриптов
и конфигурационных файлов.
Верно, что читать чужую форт-программу может быть трудно. Но в этом вина програм¬
миста, а не Форта. Если вы применяете загадочные имена для своих слов или записываете их
определения очень плотно, нс предусматривая пробелов для выделения строк, подчеркивающих
логический поток программы, или слишком ленивы, чтобы включать комментарии, то можно
гарантировать, что ни вы и никто другой не сможет понять то, что написано.
Но если вы стараетесь дать каждому слову общепонятное имя, записываете определения, при¬
меняя, где нужно, пробелы, отступы и разбиение по строкам для улучшения удобочитаемости,
и, кроме того, побеспокоились о включении в программу комментариев и снабдили ее подроб¬
ной документацией как по использованию, так и по исходному коду26, то вашу форт-программу
можно будет прочитать так же просто, как обычную китайскую прозу.
Форт — это язык, который имеет огромную мощь, гибкость и потенциал к развитию. От
программиста же ожидается готовность приспособить базовый язык к своим индивидуальным
потребностям, а также глубокое продумывание и тщательное программирование, чтобы написан¬
ное вамп имело смысл, и было документировано, чтобы вы могли поделиться своими наработками
с другими фортерамп.
3.6 Стек
Хотя мы уже говорили, что компьютеры применяются не только для арифметической и ма¬
тематической обработки данных, но и во многих других областях, все равно работа производится
с числами в той или иной форме. Форт выполняет манипуляции с числами главным образом в
стеке данных. Как мы уже видели, прямая работа со стеком в Форте — это одно из необычных
средств языка Форт. Поначалу работа со стеком может показаться вам сложной и странной, одна¬
ко пользоваться стеком очень просто, если вы поймете, что это такое, как с ним можно работать
и почему он используется для упрощения работы форт-машины и разработки программ на Фор¬
те. Нельзя овладеть Фортом, не освоив сначала стек. Стек — это динамическая область памяти
для (целых) чисел, которая постоянно используется в форт-программах. В самом использовании
стека нет ничего особенно удивительного, поскольку многие языки также им пользуются (прав¬
да, незаметно для нас). Большая часть обрабатываемых данных, которые передаются из одного
слова в другое, проходят через стек. Большая часть выгод, присущих языку Форт, также связана
с постоянным использованием стека.
В языке Форт арифметическим стеком или просто стеком называется участок оперативной
памяти, используемый для размещения целых чисел — аргументов и результатов операций язы¬
ка. Этот стек также называют стеком пользователя, стеком параметров или стеком данных.
В действительности Форт использует еще один стек, который называется стеком возвратов и
применяется для специальных целей, о нем вы узнаете позже.
На каждое число в стеке отводится одно машинно слово2'. Числа на стоке могут воспри¬
ниматься различным образом в зависимости от того, какое слово их использует. Обычно они
трактуются как числа из диапазона от —215 до 215 — 1, но есть слова, которые воспринимают их
как числа от 0 до 216 — 1.
В этой главе мы объясним, что такое стек, как в нем реализуются арифметические операции,
как он используется в Форте, а также рассмотрим слова для перестановки чисел в стеке с целью
упрощения решения сложных задач.
■ используемые алгоритмы, приемы, ссылки на литературу
■' 2 байта для 16-битных систем типа Z80 или старых ПК па процессорах 8086, 80286, 4 байта для современных
32-битных систем
Форт <с) RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
43
3.6.1 Что такое стек ?
Можно представить стек как стопку чисел, положенных друг на друга, либо, если хотите,
как колоду карт. Первое число, которое было введено в стек, будет находиться на дне, последнее
введенное число — на вершине стека. Числа из стека можно брать только с вершины. В тексте
мы будем показывать стек в виде столбика чисел, положенного горизонтально, т.е. в строчку,
причем дно стека находится слева, а его вершина — справа. Загрузите Форт и введите
12 3
(обязательно отделите числа друг от друга пробелами, как показано).
Теперь в стеке находятся числа
3 (вершина )
2
1 (дно)
аналогия с картами представлена на рис.3.6.1. Можно представить этот стек таким образом:
Рис. 2.1
Теперь, если ввести
компьютер выдаст на экран
3 2 1 ок
Первым из стека было взято и напечатано число 3, затем то же самое было сделано с числом
2, а потом с числом 1. Теперь стек пуст. Обратите внимание, что числа на экране расположены в
обратном порядке по сравнению с тем, как они представлены в стеке. Вы поняли, почему ? Стек
языка Форт называется LIFO-стеком: "последним пришел — первым вышел".
Хранимые в стеке числа упорядочены по положению. Будем говорить, что при добавлении
числа оно заносится справа от имеющихся, начиная от дна стека; при удалении снимается крайнее
правое число с вершины стека.
Когда стек пуст, попробуйте ввести еще раз . (точка). Тогда вы увидите
хххх . ? Stack empty ! (стек пуст !)
Форт отреагировал сообщением об ошибке; вы попросили его что-то напечатать, а он нс знает,
что напечатать (хххх обычно бессмысленное число, а вид сообщения зависит от версии Форта,
с которой вы работаете. Обратите внимание, что Форт не выдаст сообщение "ок", потому что
выполнение вашей последней команды нс было завершено (а значит, нс все в порядке).
Еще раз нажмите [Enter], чтобы получить на экране новое приглашение "ок", хотя в этом ист
особой необходимости. Фактически Форт готов к вводу новой информации, даже если он нс дал
сообщение "ок".
3.6.2 Буфер ввода
В действительности числа, которые вы вводите, не попадают в стек сразу. Все, что вы вводите
с клавиатуры, сначала запоминается в небольшой области памяти, которая называется буфером
ввода, в том же виде, как вы потом видите на экране. Когда вы нажимаете клавишу [Enter],
буфер ввода интерпретируется, т.е. сканируется слева направо. Интерпретатор просматривает
каждую строчку символов, разделенных пробелами. Если он опознает символ(ы) как слово, он
принимает его и просматривает следующий набор символов. Если символы не опознаются как
слово, интерпретатор пробует, нс являются ли они числом, и, если это так, помещает в стек
число. Если же символы нс воспринимаются ни как слова, ни как числа, Форт выдаст сообщение
об ошибке. Попробуйте ввести
версия 18 марта 2006 г.
Форт © R.IJ FIG, Понятов Д.А. <forth<9km.ru> , public domain
44
3 Основы языка,
159 ZZZZZ
(либо другое бессмысленное слово). Вы увидите:
ZZZZZ ?
или какое-либо сообщение, свидетелвствующее о том, что Форт вас не понял. Если теперв вы
введете . (точку), Форт напечатает сообщение "Stack empty !" (стек пуст).
Когда Форт не может интерпретироватв слово, он производит очистку стека. Это необходимо
помнитв потому, что иначе bbi будете обескуражены результатом, а отчасти потому, что таким
путем удобно очищать стек. Помните также, что, если Форт встречает неизвестное ему слово, он
игнорирует все, что следует за ним в строке ввода.
Буфер ввода имеет определенную длину, которая зависит от используемой версии Форта. В
соответствии с требованиями стандартов буфер должен принимать не менее 80 символов.
3.6.3 Стек в арифметических операциях
Как вы уже видели, помещение чисел в стек означает попросту ввод их с клавиатуры через
пробел или несколько пробелов. Но ради простого помещения чисел в стек и его просмотра не
стоит использовать компьютер. Основная часть работы на компьютере связана с операциями над
числами, поэтому давайте попробуем проделать некоторые арифметические действия. Введите
3 + 5 .
и вы получите бессмысленный ответ. Форт не любит таких выражений. Для него нужно сна¬
чала поместить оба числа в стек, прежде чем произвести сложение. Попробуйте ввести
3 5 + .
теперь вы получите
8 ок
т.е. правильный результат. Как вы уже знаете, Форт использует не такую математическую
нотацию, как другие языки. Существуют три наиболее распространенные нотации для представ¬
ления действий с числами.
Префиксная нотация записывается так: "+ 3 5 ". Хотя она не получила распространения в
арифметике, фактически это самая обычная нотация, поскольку ее применяют в повседневной
речи. Когда вы говорите "сложите 3 и 5", вы фактически применяете префиксную нотацию. При
префиксной нотации оператор28 стоит перед числами (операндами).
Инфиксная нотация записывается так: "3 + 5 ". Это наиболее употребительная алгебраиче¬
ская нотация, при которой оператор располагается между числами-операндами.
В языке Форт используется постфиксная нотация. Например, в выражении "3 5 + "опера¬
тор стоит на последнем месте после чисел-операндов. Префиксная нотация называется иногда
польской, в честь польского математика Лукашевича, который предложил ее для формальной
логики. Постфиксная нотация обычно называется обратной польской записью29. Она использу¬
ется в калькуляторах фирмы Hewlett-Packard и некоторых других. Инженеры и ученые обычно
предпочитают такие калькуляторы, потому что, как мы далее увидим, не нужно беспокоиться о
скобках, как при инфиксной нотации. Если вы привыкли к алгебре, постфиксная нотация пона¬
чалу вам покажется странной. На самом деле в ней нет ничего странного. В школе вас, наверное,
приучили к решению задач на сложение в такой форме:
3
5 +
8
28 Оператор — это символ или инструкция, которая определяет операцию над одним или более числами, напри¬
мер +, -, х, "сложить", sin и log — это все операторы.
29 поскольку она обратна префиксной нотации
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
45
Но ведь это то же самое, что
3 5 + . 8 ок
Хотя учитель, возможно, читал это выражение как "три плюс пять равно восемь", запись
говорит вам другое: возьми 3 и 5, сложи их, получишь . Действительно это одна из форм стековой
нотации, причем числа 3 и 5 заменяются на 8. Стековая природа становится еще более очевидной
для скользящего итога, например:
5
2 +
7
3 -
4
где горизонтальная черта служит для того, чтобы показать изменяющееся состояние стека.
Совсем не случайно детей приучают к такой форме, она проще воспринимается, поэтому ариф¬
метика на языке Форт оказывается простой как для нас, так, так и для компьютера.
Может быть, это и очевидно, но вот что происходит в примере со скользящим итогом на языке
Форт. Когда вы ввели
5 2 + 3- .
интерпретатор поместил 5 и 2 в стек. Знак + снимает оба числа из стека, вычисляет их сумму
и помещает в стек 7. Затем число 3 из стека помещается сверху числа 7, а оператор - вынимает
из стека числа 7 и 3, производит вычитание и помещает в стек 4. Наконец оператор . (точка)
вынимает из стека число 4 и представляет его на экране. Другой способ выполнить последний
пример состоит в том, чтобы ввести
5 2 3 - +
Вы должны проделать все, что делает интерпретатор, и проследить, что получится в стеке,
чтобы понять, почему в обоих случаях получается одинаковый результат. Можете ли вы пере¬
строить числа и операторы в стеке по-другому, чтобы получился тот же самый результат ?
Какой бы ни была простой и изящной постфиксная запись на языке Форт, она может ис¬
пользоваться в контексте с алгебраической записью. Невозможно отрицать, что алгебраическая
запись полезна для выражения сложных формул, почему же тогда мы выступаем против нее в
компьютерном языке и применяем постфиксную запись ? По двум причинам. Алгебраическая
запись избыточна, а для постфиксной требуется меньше места в памяти, кроме того, она также
экономит и время компьютера.
Экономия места и памяти переходят в мощность ЭВМ. Вот пример неопределенности в алге¬
браической записи. Пусть имеется такая запись
2хЗ+4х5=?
Возможно несколько ответов в зависимости от порядка, в котором выполняются операции
умножения и сложения. Можно избежать неопределенности двумя способами: используя скобки
или приписывая операторам приоритет. На бумаге можно использовать скобки, например:
(2 х 3) + (4 х 5 ) = 26
или
(2 х 3 + 4 ) х 5 = 50
версия 18 марта 2006 г.
Форт (со RU FIG, Понятов Д.А. <forth@km.ru> , public domain
46
3 Основы языка,
Если Вы программируете на Бейсике, то наверняка знаете, что в нем разрешается пользовать¬
ся скобками. Если скобок нет, то и Бейсик, и большинство других языков программирования во
избежание двусмысленности приписывают операторам определенный приоритет, в данном случае
первыми производятся операции умножения, а затем операции сложения. Таким образом, если
не применять скобок, то результат приведенного примера на Бейсике будет равен 26.
Необходимость в скобках или порядке следования операции приводит к тому, что алгебраи¬
ческая нотация снижает скорость операций на ЭВМ. Чтобы сам компьютер решил, как интер¬
претировать выражение, ему требуется немалое дополнительное время, а для более подробного
указания компьютеру порядка его действий требуется дополнительная память для размещения
кода программы. В интерпретирующих языках типа Бейсика это время затрачивается при испол¬
нении программы. В компилирующих языках типа Фортрана или Паскаля это время тратится
во время компиляции. Если вы все еще не убедились в том, что постфиксная запись не приводит
к неопределенности, вам помогут несколько упражнений.
3.6.4 Упражнения
Прежде чем двигаться дальше, вы должны освоить применение Форта в качестве калькуля¬
тора. II не столько для того, чтобы освоить арифметические операции, сколько для того, чтобы
научиться прослеживать состояние стека в уме.
1. Переведите следующие выражения из алгебраической нотации в постфиксную и найдите
ответы с помощью компьютера. Нужно быть уверенным, что вы вводите числа в правильной
последовательности, и в некоторых случаях вы не сможете ввести все числа, не выполнив
сначала некоторых операций.
Зафиксируйте ваши ответы на бумаге по мере выполнения упражнений (записи потребу¬
ются для упражнения 2).
(a) 5 + 5 + 5
(b) 5 4
(c) (5 + 5) х 5
(<1) (5 + 5) / 5
(e) 0.5 х (5 + 5)
(f) 10 / (5 + 5) (наши числа целые... найдите выход)
(g) (5 + 4) / (5 + 5)
(11) 5х5+5х4+4х4
(i) (5 + 4) х (5 + 4)
Ci) (5 + 1)2
2. Проделайте примеры из упражнения 1 по-другому, т.е. перестроив числа и операторы.
3. Раскрывая алгебраическое выражение, нужно начать с выражения в скобках, которое нахо¬
дится в самой глубине этого выражения. Опишите последовательность, в которой вы будете
делать вычисление следующего выражения:
16 х (2 х ((3 + 5) / 4)) = ?
Например, первой операцией должно быть сложение 3 и 5. Теперь переведите вашу после¬
довательность действий в постфиксную форму и найдите решение на Форте. Вы убедитесь,
что постфиксная форма не приводит к неопределенности.
4. Оцените значение следующих выражений, как вы это делали в упражнении 3.
(a) (2 + (5 х (9 + 3) / 6)) 32 ?
(b) (32 х (2 х (3 х (5 + 6) х 3))) = ?
Форт <cj R.U FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
47
(с) 2 х ((22 х (5 + 4)) + (2 + 5 х 10))) = ?
5. Рассмотрим пример (к) из упражнений 1 и 2. Скорее всего, вы решали его следующим
образом:
5 4 + 5 4 + *
Как вы уже знаете, имеется слово DUP, которое делает копию числа, находящегося на
вершине стека, т.е.
4 3 DUP
приводит к тому, что в стеке останется
4 3 3
Можете ли вы сделатв упражнение, исполвзуя DUP и вводя только по одному разу числа
5 и 4 ? Можете ли вы использовать слово DUP в остальных упражнениях ? Слова для
манипуляций в стеке очень полезны, они упрощают операции, экономя время и память.
3.6.5 Манипуляции в стеке
Хотя Форт нетрудно использовать в качестве калькулятора, вы поняли из упражнений, что
было бы полезно иметь средства для перемещения чисел внутри стека. Эта потребность обеспе¬
чивается словами для стековых манипуляций, которые приведены в табл. 2.1. Все они в совокуп¬
ности позволяют вам перестраивать числа в стеке, как вы захотите.
Однако, прежде чем перейти к их изучению, полезно определить слово, которое позволит
просматривать содержимое стека, не разрушая его.
3.6.6 Слово для просмотра содержимого стека
В некоторых версиях языка Форт имеется служебное слово для представления содержимого
стека без разрушения. Будучи полезным для программирования, оно может быть просто необхо¬
димым для обучения пользования стеком. Приведенное ниже описание слова .S (печатать_стек)
предназначено для тех, у кого его нет в их версии форт-системы. Попробуйте ввести его (как оно
работает, вы поймете к концу этой главы).
: .S
DEPTH ?DUP 0= IF
." Stack empty"
ELSE
0 DO
DEPTH 1- ROLL DUP .
LOOP
THEN
Теперь, если вы введете
1 2 3 .S
то увидите на экране
1 2 3 ок
Введите теперь
версия 18 марта 2006 г.
Форт (с) R.U FIG, Понятов Д.А. <forth@km.ru> , public domain
48
3 Основы языка,
и вы увидите
3 2 1
т.е. убедитесь, что слово .S действительно ничего не изменяет в стеке. Если Вы введете .S,
когда стек пуст, то будет напечатано сообщение об ошибке, которое является частью определения
этого слова. Буква S часто используется в словах, относящихся к стеку. Поскольку . (точка)
означает "напечатать", слово .S имеет вполне логичное имя.
3.6.7 Слова для манипуляций в стеке
Каждое из слов, приведенных в табл. 2.1, рассматривается в этом разделе самостоятельно. В
конце раздела мы приводим несколько задач на употребление этих слов, которые будут полезны
для совершенствования ваших навыков в их использовании.
Прежде чем продолжить описание приведенных в таблице слов, обратим внимание на обозна¬
чения в скобках. Как вы уже видели в гл. 1, в Форте принято применять такие обозначения (они
называются диаграммой состояния стека), чтобы показать состояние стека до и после примене¬
ния какого-либо слова. Правило хорошего тона — помещать такую диаграмму сразу после имени
определяемого слова. Поскольку все, что заключено с двух сторон в скобки (если только после
открывающей скобки стоит пробел), Форт при вводе игнорирует, скобки можно использовать для
помещения комментариев к форт-словам. Вот, например, определение слова для сложения двух
чисел и умножения на третье число:
: +* ( nl п2 пЗ — п ) + * :
Слово
Состояние стека (до - после )
Действие
DROP
(а-)
Очищает вершину стека
DUP
( а - а а )
Делает копию числа на вершине стека
SWAP
( a b - b а )
Переставляет местами два числа
OVER
( a b - а b а )
Копирует второе число на вершину
i PICK
( nl ... - nl ... ni )
Кладет на вершину копию i-ro элемента
i ROLL
( nl ... - ... ni)
Перекладывает i-й элемент на вершину
?DUP
( n - n n ) или ( 0 - 0 )
Выполняет операцию DUP, если п == 0
DEPTH
( ... - n )
Возвращает в стек п - число элементов
ROT
( a b c - b c a )
-ROT
( a b c - c a b )
NIP
( a b c - a c )
PRESS
( a b c - a c )
TUCK
( a b - b a b )
2DUP
(ab-abab)
2SWAP
(abed-edab)
20VER
(abed-abedab)
Если мы вводим 3 4 5 + *, то до того, как слово будет исполнено, nl=3, п2 I. пЗ=5. По¬
сле операции умножения в стеке находится п, которое имеет значение 27. Перечень принятых
обозначений для содержимого стека приведен в табл. 2.2.
Символ
Значение
малая латинская буква
n, nl,
d, dl,...
u
nd
char или с
byte или Ь
флаг или f
addr, адр, адр1
$, $addr, $адр, str
значение в общем смысле
целое число одинарной длины
целое число двойной длины
число без знака одинарной длины
число без знака двойной длины
символ ASCII (в 8-битной кодировке ASCII)
8-разрядное число, байт
1 пли 0 — булев флаг
адреса памяти
адрес, где находится строка символов
Форт (с) RU FIG. Понятов Д.А. < forthOkm.ru> . public domain
версия 18 марта 2006 г.
3 Основы языка,
49
Если вы пока еще не усвоили эти обозначения, не огорчайтесь: они станут вам понятнее в
последующих главах и мы привели их для использования в последующих ссылках. Обычно ход
программы становится более понятным, если вы применяете более содержательные описатели
в диаграммах состояния стека. Например, скорость можно обозначить как "скор.", а адрес пе¬
ременной, содержащей значение скорости, — как "адр.скор." и т.д. Другой более полный набор
символов приведен в стандарте языка Форт, но лучше всего все-таки использовать содержатель¬
ные обозначения.
А теперь вернемся к рассмотрению каждого из слов для манипуляций в стеке. DROP — это
самое простое слово; оно просто очищает вершину стека, например, после ввода
123 DROP . S
мы получим
1 2 Ок
Помимо того, что слово DROP полезно для уничтожения неправильно введенных данных
при вычислениях (что-то вроде клавиши очистки регистра в калькуляторе), оно чаще всего ис¬
пользуется для того, чтобы убрать какие-либо числа из стека во время выполнения программы.
Очевидно, при пустом стеке мы получим
хххх DROP ? Stack EMPTY ! (стек пуст!)
или аналогичное сообщение об ошибке. Вас может удивлять, почему Форт не знает о том, что
стек пуст, и почему он не игнорирует слово DROP в этом случае. Дело в том, что проверка на
наличие ошибок и принятие решения, игнорировать их или не игнорировать, занимает немало
времени. В отличие от большинства других языков программирования Форт состоит из полу-
автономных процедур — слов языка Форт, каждое из которых оптимизировано с точки зрения
быстродействия. Если бы в каждое из них было включено принятие решений об ошибках, ис¬
полнение слов происходило бы с более низкой скоростью. В Форте принято, что программист, а
не язык несет ответственность за предотвращение ошибок. Форт дает вам полный контроль над
компьютером, но в то же время и всю полноту ответственности. С другой стороны, разрабаты¬
вая программу, вы будете отлаживать каждое ее слово, легко обнаруживая ошибки. И поэтому
Форт не нуждается в сложных и требующих больших затрат времени методах контроля ошибок,
необходимых другим языкам.
Нетрудно догадаться по названию, что слово DUP (по-англ. "DUPlicate" — копировать) делает
копию верхнего элемента стека.
9 DUP .S
приводит к тому, что в стеке окажется
9 9 ок
Слово DUP, пожалуй, одно из наиболее часто употребляемых слов для манипуляций в стеке.
Вы встречались с ним в одном из упражнений гл. 1. Часто программе требуется одно и то же зна¬
чение несколько раз. Слово SWAP также, судя по названию (от swap — обменивать), переставляет
местами два верхних элемента стека. Если ввести
3 18 .S
вы получите на экране
18 3 ок
версия 18 марта 2006 г.
Форт (G RU FIG, Понятов Д.А. <forth©km.ru> , public domain
50
3 Основы языка
что особенно полезно, если нужно сделать операцию вычитания или деления, но операнды
стоят в неправильном порядке. После слова DUP оно применяется наиболее часто. Однако не до¬
пускайте, чтобы это сделало вас ленивым. Иногда проще применить слово SWAP перед операцией
деления или вычитания вместо того, чтобы заранее предусмотреть в программе требуемый по¬
рядок следования чисел в стеке. Использование SWAP может ускорить составление программы,
но на этапе исполнения увеличит время работы программы.
Действие слова OVER не очевидно из его названия (через). Попробуйте ввести
1 2 OVER .S
и вы увидите
1 2 1 ок
Можно понять, что второе число в стеке было скопировано на вершину стека. Другими сло¬
вами, OVER как бы заставляет второй элемент стека "перепрыгнуть" через первый элемент на
вершину. Оно очень похоже на слово SWAP, но в отличие от него не удаляет второй элемент стека.
Слово может быть полезно во многих случаях, когда какое-либо число должно быть использовано
несколько раз. В следующем примере дублируются два верхних элемента стека:
1 2 OVER OVER .S
при этом получается
1 2 1 2 ок
Дублирование двух верхних элементов стека очень полезно, когда в стеке нужно оставить
для последующего использования два числа. Предположим, что вам нужно вывести на экран
одновременно и сумму, и произведение чисел 5 и 7.
5 7 OVER OVER + . *
выдает в результате
12 35 ок
Конструкция OVER OVER полезна также для сравнения двух чисел. Дальше мы узнаем, что
существует слово 2DUP, которое выполняет ту же функцию, что и OVER OVER,. Имеется целое
семейство слов, которые оперируют в стеке парами чисел, но, так как они используются главным
образом для операций с так называемыми числами двойной длины, мы их рассмотрим в гл.4.
Слово ROT (по-англ, "rotate—поворачивать) производит ротацию трех верхних чисел стека,
т.е. перекладывает третье сверху число в стеке на его вершину, так что
1 2 3 ROT .8
приводит к
2 3 1 Ок
Третье сверху число в стеке перемещается на вершину стека, а следующие два числа продви¬
гаются на одну позицию в глубь стека. Применения слова ROT поначалу не очевидны, но они
также важны. Предположим, что вы хотите определить значение выражения (5+2) х (7+3), если
в стеке находится 5 2 7 3.
Для решения введите
+ ROT ROT + х .
и вы получите
Форт © RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
51
70 ок
Действие некоторых комбинаций слов, вроде приведенных в этом примере, достаточно трудно
понять даже опытному программисту. Поэтому проследить, что происходит в стеке в последнем
примере, вам поможет следующая таблица:
Операция
( стек в начале )
Содержимое стека Содержимое стека Операция
( до - после ) (до - после )
( 5 2 7 3 - )
+
ROT
ROT
+ ( - Ю 7)
(-5210) х (- 70 ) .
( — 2105) ( - ) стек пуст
( - 10 5 2 )
Если требуется произвести сложные манипуляции в стеке вроде приведенного, составление
такой таблицы может оказаться полезным. Наиболее часто возникновение ошибок в определении
слова (программы) происходит при манипуляциях в стеке.
В отличие от предыдущих слов PICK требует аргумента — числа, которое указывает, какое по
счету число сверху вы хотите скопировать на вершину стека. Аргументом является номер числа,
за начало принимается вершина стека, а счет ведется по направлению в глубь стека начиная с О
(вершина стека).
1234564 PICK . S
приводят к результату
1234562 ок
Таким образом, выражение
0 PICK
приводит к такому же результату, что и DUP.
Таким образом, PICK, доставая число из глубины стека, нс производит в нем других измене¬
ний.
Слово ROLL похоже на PICK, но в отличие от него вынимаемое число при перемещении его
на вершину на старом месте удаляется. Например
1234565 ROLL . S
приведет к результату:
2 3 4 5 6 1 ок
Нумерация элементов в стеке аналогична PICK. Слова ROLL и PICK следует применять,
если невозможно использовать ничего другого, так как они работают значительно медленнее,
чем DUP, OVER и ROT30. К тому же слово ROLL работает значительно медленнее, чем PICK.
Чтобы избежать путаницы, нужно держать в стеке не более четырех чисел, которые используются
в данном слове, и, если вы будете придерживаться этого правила, вам редко потребуются слова
PICK и ROLL.
Слово 7DUP представляет собой специальный вариант слова DUP. Оно делает копию числа,
находящегося на вершине стека, если оно не равно нулю, и не копирует число, если оно равно
нулю, Например,
145 ?DUP . S
30 эти три слова определены не с помощью слов PICK и ROLL, а непосредственно в машинных кодах
версия 18 марта 2006 г.
Форт <с) RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
52
3 Основы языка
даст в стеке
1 4 5 5 ок,
в то время как
140 ?DUP .S
приводит в результате к
1 4 0 ок
Таким образом, в последнем случае слово 7DUP не производит никаких действий. Оно осо¬
бенно полезно вместе с конструкцией IF...THEN, примеры этого будут приведены в последующих
главах.
Последнее слово в табл. 2.1, DEPTH, не производит никаких перестановок в стеке. Вы уже
встречали его в гл. 1. Оно подсчитывает количество чисел в стеке и выдает его на вершину стека.
Если ввести
21 131 56 7 89 DEPTH
мы получим
5 ок
где 5 — это число элементов, находившихся в стеке перед исполнением слова DEPTH. Мы
увидим еще применение слова DEPTH в последующих упражнениях.
3.6.8 Упражнения
Они могут показаться вам вначале очень простыми, но потом будут усложняться. Если даже
они покажутся вам скучными, пожалуйста, проделайте их. Одной из самых важных компонент
изучения Форта является освоение работы со стеком настолько, чтобы вы чувствовали себя с
ним комфортно, а слова, связанные с манипуляциями в стеке, стали бы вашей второй натурой.
Затраченное вами время сторицей окупится впоследствии.
1. Напишите слово или слова, с помощью которых содержимое стека изменялось бы в соот¬
ветствии с заданием. Старайтесь обойтись минимумом слов. Мы пользуемся здесь буквами
вместо чисел, чтобы у вас возникла уверенность, что эти при меры пригодятся и в более
общих ситуациях.
До
После
До
После
До
После
(а)
а b
b а
(б)
а b
a b b
(в)
а b
aba
(г)
а b
а а b
(д)
а b
b b а
(е)
а b с
b с а
(ж)
а b с
а с b
(з)
а b с
с b а
(и)
а b с
b а с
(к)
а b с
cab
(л)
а b с
a b b с
(м)
а b с
а а b с
(н)
а b
a a b b
(о)
а b с
a a b b с с
2. Принимая содержимое стека таким, как показано, напишите слово или слова для вычисле¬
ния выражений. Снова старайтесь обойтись минимальным количеством слов.
Стек
Выражение
Стек
Выражение
(а)
а b
ab
(б)
а b
ab2
(в)
а b
а ■ b
(г)
а b
а b
(д)
а b
а2Ь3
(е)
а b
а(а + Ь)
(ж)
а b
а2 + 2ab 1 Ь2
(указание:
разложите
на множители)
(з)
а b с
(а + Ь)/с
(и)
а b с
(a+b)/(b+c)
(к)
а b с
(a+c)/(b 1 с)
(л)
а b с
(а+Ь)/(2с)
(м)
а b с
а/(2с)+Ь/(2с)
(н)
а b с
(b-a)(b-c)
(о)
abed
ab-Fac-l- йс1
(п)
abed
ab+abed
Не применяйте ROLL и PICK
Форт (с; RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
53
3. Напишите новое определение слова OVER (NEWOVER), используя другие слова.
4. Слово 2DUP выполняет следующие операции в стеке
( nl п2 - nl n2 nl п2 )
Оно применяется для чисел двойной длины. Напишите определение этого слова под именем
NEW2DUP, используя для этого только два слова.
5. Определите слова DUP и OVER, используя PICK. Проделайте это для обоих стандартов.
Дайте этим словам новые имена во избежание путаницы.
6. Определите ROT, используя слово ROLL. Дайте этому слову новое имя.
7. Слово 2SWAP выполняет в стеке следующие операции:
( nl n2 n3 п4 - n3 n4 nl п2)
8. Определите слово ROTSTACK, которое производило бы ротацию элементов стека незави¬
симо от его длины. Если в стеке находится а Ь с d е f, то после исполнения ROTSTACK в
нем должно быть Ь с d е f а. Используйте для этого только два слова.
9. Объем сферы выражается формулой • г3. Напишите слово для определения объема,
умноженного на 100, если в стеке задано значение г. Указание: используйте число к = 3.14,
умножив его на 100.
10. Определите слово, помещающее в стек произведение двух самых нижних чисел в стеке,
не разрушая содержимого стека. Все, что вам известно: в стеке находятся два или более
числа. На практике вы не должны допускать разрастание стека, чтобы нс приходилось
делать что-либо подобное.
11. Слово MOD дает остаток от деления нацело, т.е. 11 3 MOD выдает в результате 2. Дайте
определение слова MOD.
3.6.9 Выводы
При изучении языка Форт, возможно, наиболее важным является умение легко и быстро
работать со стеком. К данному моменту вы должны хорошо понимать, как работает стек и как
его можно перестроить, если это необходимо. После овладения операциями в стеке вам легче будет
освоить материал последующих глав. Если вы чувствуете, что вам нужно попрактиковаться еще,
вернитесь к разбору предыдущих упражнений или придумайте свои собственные задачи и решите
их. Конечно, у вас еще будет много практической работы со стеком в нескольких следующих
главах. Вскоре вы обнаружите, что сможете инстинктивно писать разумные программы, едва ли
задумываясь о состоянии стека.
3.7 Память, числа
Вы можете работать с языком Форт, даже очень мало понимая, как работает сам компьютер,
но это будет вам постоянно мешать. Чтобы понимать, что в нем происходит, вы должны по
крайней мере понимать, как работает память ЭВМ и как в ней хранятся данные. Это не так уж
сложно, как многие думают, а с помощью языка Форт и этой книги вы можете изучить не только
реализацию простых типов данных типа констант, переменных, строк и массивов, но и более
сложных — списков, многомерных массивов, очередей, структур данных переменной длины и т.п.
Не пропускайте эту главу, даже если у вас уже есть опыт работы с ЭВМ. Можно, если хотите,
бегло просмотреть более простые вопросы. Обратите, однако, внимание на возможности Форта,
касающиеся его обращения с системами счисления и операциями в памяти, которые являются его
привлекательными сторонами. Возможно, что у вас возникнет также желание узнать функции
слов BASE и DECIMAL.
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
54
3 Основы языка,
3.7.1 Что такое память ?
Представьте себе, что имеется 8 переключателей, каждый из которых может быть включен
или выключен. Можно их закодировать так, чтобы состояние переключателей представлялось
числами. Булем считать, что единице соответствует включенный переключатель, нулю — вы¬
ключенный. В табл. 3.1 показаны числа, построенные таким образом. Восемь переключателей
могут представлять до 256 чисел (от 0 до 255). Если немного подумать, вы сможете доказать,
что с помощью п переключателей можно запомнить 2" = 256 чисел.
С помощью 16 переключателей или двух банков по 8 переключателей могут быть представ¬
лены 21ь = 65536 чисел. Предполагается, что для чисел в стеке имеется два банка по 8 переклю¬
чателей. Вследствие этого наибольшее число, которое можно записать в стек 16-битной системы
и которое мы называем числом одинарной длины, равно 65535. Для представления чисел двой¬
ной длины нужно уже 32 переключателя, и диапазон представляемых чисел увеличивается до
65536 х 65536 = 4271406736. Для 32-битной системы слово одинарной длины имеет длину в 32
переключателя.
Итак, мы видим, что память компьютера — не что иное, как большое количество переклю¬
чателей, которые могут включаться и выключаться с огромной скоростью. Вот так. И все, и
ничего больше. Сложность здесь состоит в том, чтобы организовать переключатели для хране¬
ния чисел и, следовательно, данных. Алфавитно-цифровой текст также можно представить в
виде закодированных чисел. Например, латинская буква А представляется числом 65. Каждый
переключатель в памяти называется битом, от английского Binary digiT (двоичный разряд, а
почему — мы вскоре узнаем).
А теперь можете забыть о всяких переключателях, будем говорить только о битах. Если
значение содержимого бита равно 1, то говорят, что он взведен или установлен', если значение
равно 0, то говорят, что он сброшен пли выключен.
Старые недорогие ЭВМ31 используют процессор32, который работает с 8-разрядными числа¬
ми; их называют 8-разрядными машинами, они обеспечивают доступ к 65536 8-разрядным ячей¬
кам памяти, т.е. к 524288 битам. То же самое можно сказать и о современных микроконтроллерах
— MCS-51, AVR, PIC и менее распространенные виды.
Более дорогие 16-разрядные машины, например IBM ГС ХТ/АТ, работали с 16 разрядами
одновременно, имея доступ к тем же 64К (64 • 210) байтам памяти, но операции выполняются как
минимум в два раза быстрее.
Кроме того, на многих компьютерах применялся механизм страничной адресации или сегмен¬
тации, когда в адресное пространство 64К можно было подключать разные страницы памяти,
что позволяло работать с значительно большими объемами памяти. Во всех современных компью¬
терах применяется этот же принцип переключения страниц памяти, но операции выполняются с
32-битными числами, что позволяет работать с 4 Гб памяти без переключения страниц.
Объем памяти ограничивается потребностями пользователя, его финансовыми возможностя¬
ми, и ограничениями "железа" — например, увеличение объема памяти может привести к росту
потребления энергии и соответственно паразитному выделению тепла, что важно для аппаратуры
на космических аппаратах. Кроме того, увеличение разрядности приводит к сильному усложне¬
ния схемы и увеличению плотности, сложности и соответственно себестоимости печатной платы.
3.7.2 Единицы измерения объема памяти
8-разрядный элемент памяти называют байтом, в байтах принято оценивать емкость памяти.
В микропроцессорах самых ранних моделей за единицу емкости принималось четыре разряда
(nibble).
16 разрядов иногда называют машинным словом, однако, так как слово у больших ЭВМ и
современных компьютеров может быть 32-, 64- и более разрядным и, кроме того, понятие "слово"
в языке Форт имеет совсем другой смысл, будем называть 16-разрядное число просто числом.
Это число — целое, и используется для хранения в стеке чисел одинарной длины.
Для обозначения больших объемов памяти применяются слова с префиксами Кило (К) и Мега
(М), которые в стандартной метрической системе означают соответственно 103 = 1000 и 106 =
миллион. Например, километр — это 1000 метров, 1 МегаГерц — это 1000000 Гц, или 1 млн.
31 клопы ZX Spectrum, Микроша, Радио-86РК, Commodore 84, TRS-80, Apple II
32 ЦПУ, CPU
Форт R.U FKJ, Понятов Д.А. <forth©km.ru> . public domain
версия 18 марта 2006 г.
3 Основы языка,
55
колебаний/с. В вычислительной технике применяется система счисления с основанием 2, а не 10,
поэтому Килобайт (К) равен 210 = 1024 байта, а мегабайт 220 = 1024 • 1024 = 1048576 байт. Эти
числа близки к К и М в десятичной системе.
Килобайт - удобная единица для обозначения объема памяти старых компьютеров. Так, на¬
пример, ZX Spectrum 48К и Apple II обычно называют машинами с объемом памяти 64 Кбайта
или 64К машинами; они могут работать с памятью объемом 64 х 1024 — 65536 байт. Современные
компьютеры имеют на порядки большие объемы памяти, поэтому применяются обозначения М
и G (гигабайт, 1024М).
3.7.3 Системы счисления
Состояния
Число
переключателей
00000000 0
00000001 1
00000010 2
00000011 3
00000100 4
00000101 5
00000110 6
00000111 7
00001000 8
11111111 255
Кое-что об этом вы уже знаете. Двоичная запись — это попросту соглашение о записи чисел
с помощью только двух цифр 0 и 1 (отсюда двоичный разряд, или бит). Люди привыкли к
десятичной арифметике, которая использует 10 цифр (от 0 до 9) или так называемой десятичной
форме записи, но компьютеры имеют дело с единицами и нулями, т.е. с двоичной системой.
Как мы вскоре увидим, иногда удобно работать с числами, использующими для записи 16 цифр
(от 0 до 9 и от А до F), или так называемую шестнадцатеричную форму представления. В
шестнадцатеричной форме число 10 обозначается латинской буквой А, 11 — буквой В и т.д.,
число 15 - буквой F, число 16 обозначается как 10.
Посмотрите, сможете ли вы объяснить, почему для обращения с байтом оказывается удобной
шестнадцатеричная система (для этого продолжите таблицу до 16). Если вы нс догадались, то
через некоторое время это станет понятнее. Хорошее практическое обсуждение оснований систем
счисления и других аспектов представления чисел вы можете найти в книге Липшица "Арифме¬
тические основы компьютеров"(1982).
Количество различных цифр, используемых для представления чисел, называется основани¬
ем системы счисления или просто основанием. При двоичной записи основание равно 2, при
восьмеричной — 8, при десятичной — 10, при шестнадцатеричной — 16 (обозначение ее в Форте
HEX происходит от английского названия hexadecimal).
Прелесть Форта состоит в том, что, хотя все числа он хранит в двоичной форме, как и дру¬
гие языки, что определяется требованиями компьютера, он может принимать их и отображать с
любым основанием вплоть до 72. Нам потребуются некоторые слова Форта, которые позволяли
бы отображать числа из стека в различных системах счисления, но прежде чем мы с ними по¬
знакомимся, необходимо немного отвлечься, чтобы рассмотреть, как мы можем извлекать байты
и числа, которые хранятся в памяти.
3.7.4 Память Форта
С каждым байтом памяти сопоставляется число, начиная с нуля и больше, которое соответ¬
ствует его положению в памяти и называется адресом пли указателем на первый байт структуры
данных, занимающей больше одного байта. Таким образом, первый байт имеет 0-й адрес в памя¬
ти (0000 hex), в то время как для 8/16-раз рядной 64К ЭВМ адрес самого верхнего байта равен
65535 = 64К (FFFF hex).
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
56
3 Основы языка
Для осуществления доступа к содержимому указанного адреса в Форте предусмотрено несколь-|
ко слов. Наиболее важными из них являются @ (извлечь) и ! (занести, запомнить). Если в стеке
на вершине находится адрес, то слово @ замещает адрес машинным словом размером CELL33
байт, которое хранится по этому адресу. Если так же на вершине находятся число и адрес, то
оператор ! производит запоминание этого числа по указанному адресу.
Слово ! следует употреблять осмотрительно, так как можно изменить содержимое важной
части памяти или просто попортить ваши данные, если вы запишете не в то место памяти.
3.7.5 Переключение системы счисления через переменную BASE
Можно использовать слова @ и ! для того, чтобы узнать систему счисления или изменить ее
при вводе и выводе чисел. В памяти имеется ячейка (переменная размером CELL), в которой хра¬
нится основание системы счисления, которое действует в настоящий момент при вводе/выводе
чисел. Этот адрес выдается в стек словом BASE ( - addr ). Давайте его испытаем. Вначале дадим
компьютеру задание принимать и выводить числа в десятичной системе счисления с помощью
слова DECIMAL34 ( - ). Слово DECIMAL изменяет число, которое хранится по адресу, возвра¬
щаемому в стек словом BASE, на 10, включая десятичную систему счисления.
Теперь основание может быть сделано шестнадцатеричным (основание 16), если ввести
16 BASE !
Слово BASE помещает на вершину стека соответствующий адрес, затем в этот адрес записы¬
вается число 16.
Заметим, кстати, что слово BASE — это особая переменная. Вообще переменная — это область
в памяти, где может храниться число, и некоторое символьное имя, поставленное в соответствие
этой области. В Форте переменная — это слово, которое выдает адрес этой выделенной под пе¬
ременную области памяти. Использование переменных будет описано далее. Форт не нуждается
в большом количестве переменных, как другие языки программирования, так как он может хра¬
нить числа в стеке.
Теперь, когда компьютер использует шестнадцатеричную систему счисления, вы можете вве¬
сти
IB DECIMAL .
и получите
27 Ок
Число 27 в десятичной записи — это то же самое, что 1В в шестнадцатеричной. Следующий
пример произведет обратное действие:
28 16 BASE ! .
выдаст на экране 1С, т.е. шестнадцатеричный эквивалент числа 28.
Слово HEX, которое является стандартным, включено в большинство версий Форта. Оно
устанавливает шестнадцатеричную систему счисления так же, как DECIMAL устанавливает де¬
сятичную. Во многих версиях есть слова OCTAL и BINARY, которые устанавливают систему
счисления 8 и 2 соответственно.
Можно проиллюстрировать один важный момент с помощью следующих экспериментов. По¬
пробуем ввести
DECIMAL 2 BASE ! BASE @ .
потом
DECIMAL 8 BASE ! BASE @ .
33 специальная константа Форта, размер машинного слова в байтах
34
десятичный
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
57
и
DECIMAL 16 BASE BASE 0 .
Во всех случаях вы увидите 10. Почему ? Основание числа во всех случаях представляется
как 10, так как это — 2 в двоичной системе, 8 (десятичное) — это 10 в восьмеричной системе и 16
(десятичное) представляется так же, как 10 в шестнадцатеричной системе. Как же тогда узнать,
в какой системе мы находимся ? Вот слово, которое поможет это сделать:
: BASE? ( -- n ) BASE Ф DUP DECIMAL . BASE ! ;
Вы должны понимать, как оно работает. Если вы введете
16 BASE ! BASE?
то увидите, что на экране будет число 16, и после этого мы по прежнему останемся в шест¬
надцатеричной системе счисления. Вместе с тем, когда вы вводите
n BASE !
нужно быть внимательным и твердо знать, от какого основания мы переходим. Например,
если мы находимся в двоичной системе, то при вводе
10 BASE !
ничего не произойдет. 10 в двоичной системе — это десятичное число 2, но мы уже находимся
в двоичной системе. А что произойдет, если ввести
10 BASE !
в шестнадцатеричной системе ? Как снова вернуться к основанию 10 ? Если вы были в шест¬
надцатеричной системе, можете ввести
A BASE !
А — это шестнадцатеричное число, которое равно 10 (десятичное). Если вы забыли текущее
основание, то слово DECIMAL всегда возвратит вас к основанию 10, независимо от того, в какой
системе вы были до этого.
Приведем слово, которое показывает в двоичной системе счисления число, находящееся на
вершине стека. Обратите внимание, что при этом оно не изменяет содержимое стека:
: .BIN ( ... п -- ... n ) DUP BASE © 2 BASE ! SWAP . BASE ! ;
Вы должны догадаться, как оно работает.
В качестве упражнения (и для использования впоследствии) опишите три слова: .OCT, .DEC
и .HEX, которые будут печатать число из стека в восьмеричной, десятичной и шестнадцатеричной
системе соответственно. Для этого вам надо изменить в слове .BIN всего один символ.
Теперь мы сможем написать еще одно слово, которое даст возможность представить число в
стеке одновременно в двоичной, восьмеричной, десятичной и шестнадцатеричной системах:
: .NUMS ( n -- ) .BIN .OCT .DEC .HEX DROP ;
Слово .NUMS можно использовать для того, чтобы посмотреть, как различные числа пред¬
ставляются в различных системах счисления. Но давайте проделаем это в следующих упражне¬
ниях.
версия 18 марта 2006 г.
Форт <С! R.U FIG, Понятов Д.А. <forth<9km.ru> , public domain
58
3 Основы, языка,
3.7.6 Упражнения
1. Используйте .NUMS со следующими числами: 1, 3, 7, 15, 31, 63, 127 и 255. Подметили ли
вы общий рисунок ? Какая зависимость существует между числом 2, возведенным в полую
степень, и двоичным представлением ?
2. Теперь проделайте то же самое с числами 2, 4, 8, 16, 32, 64, 128 и 256. Видите ли вы, почему
шестнадцатеричное представление удобно для работы с байтами ?
3. Перейдите в двоичную систему и введите восьмиразрядное число с единицами во всех раз¬
рядах. Используйте .NUMS. Вы снова сможете убедиться в удобстве шестнадцатеричной
системы. Проделайте это упражнение для 16-разрядного числа. Вернитесь к десятичному
основанию.
4. Перейдите к основанию 16 и введите 1 плюс шестнадцатеричное число, которое эквива¬
лентно байту со всеми единицами в разрядах. Возведите это число в квадрат и выведите
его словом .NUMS. Сколько используется разрядов ? Почему ? Подумайте еще раз, почему
удобна шестнадцатеричная система ?
5. Определите слова HEX, OCTAL и BINARY.
6. Понятно ли вам, почему, если вы хотите использовать шестнадцатеричные числа, недопу¬
стимо давать имена такого типа: АА, А4, FF и т.д. и в то же время имя GG будет прием¬
лемым ?
3.7.7 Выводы
Некоторые программисты, которые много программируют на низком уровне, работают с чис¬
лами, представленными в двоичной, шестнадцатеричной или восьмеричной системах, и действи¬
тельно могут думать и выполнять арифметические действия в этих системах, однако большин¬
ство из нас на это неспособны. Одной из приятных особенностей, которую мы нс найдем в других
языках, является возможность производить преобразование в любых системах счисления. По ме¬
ре приобретения опыта вы убедитесь, что наиболее удобным основанием для работы с адресами
памяти является шестнадцатеричная система.
В некоторых форт-системах при вводе чисел можно явно указать шестнадцатеричную систему
счисления, как это делается в Си, Паскале и других языках — если Форт получает число, начи¬
нающееся с символа $ или Ох, то оно распознается как шестнадцатеричное число, при условии
что все его цифры корректны.
Чтобы избежать проблем, не используйте имена слов, начинающиеся с этих символов — если
вы определите например слово $3D, выполняющее кикие-то действия, а затем решите использо¬
вать константу (литерал) 3D hex в тексте программы, вы получите трудно уловимую ошибку,
если ваш Форт использует префикс $ для hex чисел.
3.7.8 Операции с битами
Иногда бывает необходимо изменить отдельные разряды в числе. Например, компьютер опре¬
деляет, занят ли принтер, по состоянию одного разряда, точно так же ЭВМ определяют состояние
связи через модем по состоянию (статусу) нескольких битов в трех байтах. Так, если один опре¬
деленный бит установлен в "1", то данные принимаются по телефонной линии, но если этот бит
сброшен в "О", то линия свободна и можно передавать данные. Поэтому зачастую полезно иметь
возможность просматривать состояние, а также изменять значения отдельных битов.
В оставшейся части этого раздела мы будем использовать компьютер для ввода и вывода
двоичных чисел, поэтому вам нужно установить двоичное основание, т.е. записать в переменную
BASE число 2. Если вашему компьютеру известно слово BINARY, то достаточно ввести это слово.
Если вы не уверены, попробуйте его, худшее, что может произойти — получение сообщения об
ошибке, ели слово BINARY у вас не работает, введите
2 BASE !
Форт © RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
59
Теперь, если вы попытаетесь ввести цифру больше 1, Форт будет отвергать ее как не имеющую
смысла в двоичной системе счисления.
Представим себе, что в стеке находится двоичное число 10011111 и вы хотите изменить третий
справа разряд в "0", т.е. вы хотите превратить это число в 10011011. Слово AND (И) позволит
вам сделать это. Слово AND сравнивает поразрядно два числа, и если в обоих (одном и другом)
эти разряды установлены в "1", то результат будет 1, иначе результатом будет 0. Попробуйте
ввести следующее предложение:
10011111 11111011 AND U.
и вы увидите следующий результат:
110011011 ок
Нагляднее всего проследить, что произойдет, если поместить числа одно под другим:
10011111
11111011 AND U.
это приведет к такому результату:
10011011 ок
Второе число, 11111011, называется разрядной (битовой) маской. Разрядная маска — это
всего-навсего число, которое сравнивается с другим числом с целью изменить значение отдельных
битов.
Теперь представим себе, что вы хотите снова изменить значение разряда 0 в 1. Слово AND
не сможет этого сделать. Вместо него мы используем слово OR (ИЛИ). Оно также производит
поразрядное сравнение двух чисел, но если хотя бы один из разрядов установлен в "1", то в
результате тоже будет "1". Попробуем установить в "Р'третпй разряд в последнем примере. Для
этого случая мы используем маску 00000100:
10011011
00000100 OR U.
что приводит к
10011111 0к
т.е. к исходному числу.
Третье полезное слово XOR (исключающее ИЛИ) также производит поразрядное сравнение.
Если два разряда различны, то в бите результата устанавливается "1", если одинаковы — то "О".
Пусть вы хотите изменить значения всех разрядов числа на противоположные, т.е. преобразовать
число 10011011 в 01100100. Попробуйте сделать так:
10011011
11111111 XOR U.
и получите
01100100 ок
Так как в маске все разряды были установлены в "l", то там, где в исходном числе была 1, в
результате стал 0, а если был 0 — стала 1.
Есть еще одно слово, NOT (НЕ), которое изменяет значение разрядов на противоположное.
Таким образом,
версия 18 марта 2006 г.
Форт с RU FIG, Понятов Д.А. <forth©km.ru> . public domain
60
3 Основы языка,
OOOOOOOO1O1O1O NOT и.
приведет к результату
11111111010101 ок
Операция NOT не эквивалентна вычитанию каждого разряда из двоичной единицы. Сможете
ли вы определить слово NOT, используя XOR ? Слова AND, OR, XOR и NOT имеют и другие
применения, с которыми мы познакомимся в упражнениях.
3.7.9 Упражнения
1. Подберите маску и подходящее слово для того, чтобы изменить приведенные числа, как
показано в таблице. Нс используйте XOR, если есть более простое решение.
Исходное
число
Преобразованное
число
Исходное
число
Преобразованное
число
(а)
10101011
10100011
(е) 10101111
00001111
(б)
10100011
10100111
(ж) 10100000
00001111
(в)
10100011
00000000
(з) 10101010
01010101
(г)
10100011
11111111
(и) 11110000
00001111
(д)
10101111
10100000
2. Опишите слово для преобразования любого слова, находящегося на вершине стека, в "О".
3. Слово = возвращает 11... 11, если два верхних числа в стеке равны. Иначе оно возвращает
00... 00. Определите слово =.
4. Слово О возвращает 11... 11, если два верхних числа не равны, и 00... 00 в противном
случае. Определите слово О двумя способами: с использованием слова - и без него.
5. Опишите слово NOT под именем NOT1, используя XOR. Опишите его, используя -.
6. Опишите слово, которое, если дана маска с определенными установленными в "1"разря-
дами, возвращает 1 в соответствующих разрядах второго сверху числа в стеке, если их
значение равно 1 и 0 в противном случае.
7. Опишите слово, которое, если задана маска с определенными разрядами, установленными
в "1", будет возвращать 1 соответствующих разрядах второго сверху числа, если они равны
0, и 0 в противном случае.
3.7.10 Положительные, отрицательные числа и числа без знака
Для представления чисел одинарной длины в Форте используются два байта, т.е. 16 битов
памяти. Поэтому возможно представить числа от 0 до 65535 (216 = 65536). Но, разумеется, если
нам не нужны отрицательные числа.
Попробуйте ввести с клавиатуры
65535 .
Результат получится такой:
-1 ок
Что произошло ? Очевидно, то, что Форт воспринимает число 65535 как отрицательное число.
Теперь попробуйте
65534 .
и получите
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
61
-2 Ок
Это кажется еще более странным. А теперь введите
32768 .
Форт выдаст
-32768 ок
В то же время, если ввести
32767 .
мы получим
32767 ок
Ужасная путаница, неправда ли ? В действительности же Форт работает с так называемыми
числами со знаком (signed) и числами без знака (unsigned). Все, что находится в диапазоне
32768-65535, Форт рассматривает как отрицательные числа, если вы не указываете, что они
положительные. Попробуйте ввести
65535 U.
Результат
65535 ок
получится таким, каким он и должен быть. Если вы испытаете слово U. с другими числа¬
ми, включая те, которые больше 32767, вы будете получать те же числа, что и ввели. Слово
U. предназначено для печати чисел, не принимая во внимание знак числа, т.е. "чисел без зна¬
ка" . Имеются также другие операторы для выполнения арифметических действий с числами без
знака, и мы бу. ie.\: работать с ними в гл. 4. Ну а теперь попробуйте ввести
-1 U.
в результате получится число 65535. Становится все хуже и хуже. А вот что происходит на
самом деле. Если вы вводите 65535 пли -1, Форт кладет в стек одно и то же число:
1111111111111111
В нем все 16 разрядов установлены в "1".
Числа 65534 и -2 вводятся в стек в виде
1111111111111110
и 65533 и -3 — как
1111111111111101
Поэтому, если числа больше 32767, Форт может рассматривать их и как отрицательные и как
числа без знака, в зависимости от ваших указаний. Числа 0-32767 (от 0 до 11111111111111, с 15
единицами) воспринимаются как положительные. Если число со знаком, т.е. если его 16-й разряд
равен 1, тогда число считается отрицательным, но это не совсем так, потому что оказывается, что
числа "больше" 32767 (как числа без знака) менее "отрицательные". Более понятно это станет
из упражнений.
Принятое в Форте соглашение об использовании чисел со знаком называется арифметикой с
дополнением по модулю два. Не вдаваясь в причины, укажем, что число в арифметике с допол¬
нением по модулю два получается путем вычитания каждого разряда из 1, а затем добавлением
ко всему числу 1. Образование числа с дополнением по модулю два попросту меняет его знак.
Так, -10 является дополнением по модулю два от 10, а 10 — дополнением по модулю два от -10.
Оказывается, что принятое соглашение упрощает работу ЦПУ при арифметических операциях.
В большинстве других языков также применяется целочисленная арифметика с дополнением до
2. Вспомните, что слово NOT эквивалентно вычитанию каждого разряда числа из 1, поэтому
версия 18 марта 2006 г.
Форт <cj RU FIG, Понятов Д.А. <forth©km.ru> , public domain
62
3 Основы языка,
10 NOT 1 + .
даст в результате -10. Стандартное слово NEGATE делает следующее: оно изменяет знак
числа, вычисляя его дополнение по модулю два. Дополнение чисел и дополнительная арифметика
подробно описаны в книге Липшуца (1982).
3.7.11 Упражнения
Убедитесь в том, что слово .BIN находится в вашей системе. Если это не так, снова введите
его (см. выше). Определите новое слово, которое печатает двоичные числа без знака следующим
образом:
: U.BIN DUP BASE @> 2 BASE ! SWAP U. BASE ! ;
В чем различие между .BIN и U.BIN ?
1. Напишите одно слово, которое показывает число, находящееся на вершине стека в виде
десятичного со знаком, десятичного без знака, двоичного со знаком и двоичного без знака.
2. Используйте слово U.BIN для того, чтобы подготовить на экране таблицу приведенных
ниже чисел, показывая их и виде чисел со знаком и без знака в двоичной и десятичной
системе: 1, 2, 3, 32766, 32767, 32768, 32769, 65533, 65534, 65535.
3. Глядя на таблицу из упражнения 2 (и если нужно, проведя дополнительные эксперименты),
напишите алгебраической выражение для преобразования отрицательных чисел в диапа¬
зоне -1-32768 в положительные числа, которые выводятся с помощью слова U.
4. Еще раз, просматривая таблицу из упражнения 2, напишите слово, которое будет менять
знак числа, находящегося и стеке, не используя -, а с помощью операций над битами (вы
уже описали слово NEGATE). Как это связано с дополнением исходного числа по модулю
два ?
5. Используя результаты упражнения 4 и операцию + , напишите определение слова - для
выполнения вычитания.
3.7.12 Операции с байтами
Иногда говорят о наиболее и наименее значащих разрядах десятичного числа. Например,
в числе 456 наиболее значащий разряд — 4, наименее значащий 6. Таким образом, 456 — это
400+50+6, где 4 указывает, сколько в числе содержится единиц самого старшего разряда, т.е.
сотен. Точно так же мы говорим о наиболее и наименее значащих разрядах двоичного числа. В
числе 10110 наименее значащий разряд — это самый правый разряд (0), а наиболее значащий —
первый слева (1).
Рассматривая байты, мы поступаем так же: разбиваем 16-разрядное число на два байта (числа
по 8 разрядов) — более значащий (старший) и менее значащий (младший). В шестнадцатеричном
числе 0х10А2 старший байт равен 10, младший — А2. Если число десятичное, то выделение байтов
производится не так просто. Для чисел больше 255 значение старшего байта можно найти из табл.
3.2.
Десятич.
число
Шестнадца-
терич.экв.
Старший
байт
Дес.
Шест.
Младший
байт
Дес.
Шест.
001
0001
000
00
001
01
255
00FF
000
00
255
FF
256
0100
001
01
000
00
257
0101
001
01
001
01
511
01FF
001
01
255
FF
512
0200
002
02
000
00
513
0201
002
02
001
01
767
02FF
002
02
255
FF
768
0300
003
03
000
00
769
0301
003
03
001
01
Форт © RU FIG. Понятов Д.А. <forth©km.ru> . public domain
версия 18 марта 2006 г.
3 Основы языка
63
Число 255, или OxFF — это наибольшее число, которое может находиться в младшем байте.
Если число больше 255, то в старший байт нужно добавить 1. Поэтому число 256 имеет 1 в
старшем байте и 0 — в младшем. Теперь заметим, что число 512, которое получается добавлением
еще одной 1 к старшему байту, в 2 раза больше 256, а 768 в 3 раза больше 256. Другими словами,
старший байт увеличивается на 1 каждый раз, когда число увеличивается на 256.
Теперь рассмотрим два слова С@ и С! для операций с отдельными байтами. Слово С@ похоже
на слово @, но оно извлекает значение только одного байта (буква С в имени происходит от слова
character, т.е. символ, потому что любой символ ASCII представляется одним байтом). После С@
старший байт в стеке должен быть равен 0. Понимаете ли вы, почему ?
Слово С! подобно !, но оно производит запись только младшего байта числа, находящегося
в стеке. Оно обычно используется, если число в стеке не превосходит 256. Проделаем несколько
экспериментов. Слово PAD (буфер, записная книжка) выдает в стек адрес в памяти, который
является началом буфера, где пользователь может хранить своп данные. Положите в стек число
257 и занесите его в PAD с помощью
257 PAD !
Теперь давайте посмотрим, что окажется в каждом байте по адресу PAD и PAD+1, для чего
введем
PAD С@ . PAD 1 + С© .
Вот что вы увидите:
1 1 ок
Теперь повторите то же самое с числами 255 и 256. Потом попробуйте числа из табл. 3.2. Вы
будете видеть раздельно младший и старший байты вводимых чисел. Понятно ли вам, почему ?
Вы записываете в PAD число целиком с помощью !, но извлекаете его в стек побайтно и поэтому
видите оба байта.
Порядок следования байтов может меняться от компьютера к компьютеру, в зависимости от
того, как хранятся старший и младший байты числа в памяти. В большинстве случаев старший
байт числа хранится в более старшем адресе. Дальнейшее рассмотрение операций над байтами
продолжим в упражнениях.
Следует специально обратить внимание, в каком порядке помешаются байты CELLa в память.
В зависимости от вашего процессора, по мере увеличения адреса байты могут хранится в памяти
начинаная с самого младшего (LSB, процессоры 80x86), или с самого старшего (MSB, процессоры
Motorola 68К, Alpha30). Когда вы будете работать со структурами данных и просто с частями
машинных слов (целых чисел), учитывайте этот порядок, особенно если хотите чтобы ваши про¬
граммы работали на всех типах компьютеров. В частности, интерпретатор os, описанный в этой
книге, использует порядок байт LSB.
3.7.13 Упражнения
1. Определите слово .LSB для печати младшего байта числа, находящегося в стеке. Не ис¬
пользуйте PAD и С@. (Подсказка: какое значение старших восьми разрядов должно иметь
число в стеке перед операцией . ? Как установить эти разряды в 0 ?).
2. Определите слово .MSB для печати старшего байта положительного числа, находящегося
в стеке. (Совет: вспомните, что к старшему айту числа добавляется 1 каждый раз, когда к
нему прибавляется 256, и что оператор / производит округление с уменьшением.)
3. Переопределите .LSB, пользуясь методом определения .MSB. (Указание: вы должны при¬
менить DUP к числу, находящемуся в стеке, и, кроме того, SWAP и -.)
4. Дайте новое определение .LSB и .MSB под именами .LSB2 и .MSB2, используя PAD и С@.
Очень часто одно и то же можно на Форте сделать разными способами. Наилучший метод
— это обычно компромисс между требуемыми ресурсами памяти и временем исполнения.
Какое из определений .LSB и .MSB будет самым быстрым ?
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
64
3 Основы языка
5. Напишите слово для деления числа без знака, находящегося на вершине стека, на 256, не
используя для этого никаких чисел.
6. Напишите слово для добавления числа 256 к числу на вершине стека путем прибавления 1
к чему-то.
3.8 Представление символьной информации
3.8.1 Кодировка текста ASCII
Кроме представления чисел разряды в памяти могут представлять алфавитно-цифровые сим¬
волы. Символы просто кодируются числами, при этом наиболее распространенным является Аме¬
риканский стандартный код для обмена информацией ASCII. Первоначально код ASCII предна¬
значался не для компьютеров, а для телетайпов. Это привело к тому, что некоторые коды имеют
странные названия. Например, код 736 предназначался для звонка в момент возврата каретки с
целью привлечения внимания оператора. Код 5 называется WRU3', предназначался для запроса
служебного позывного оператора па другом конце линии, код 25 — ЕМ38 может быть использован
для индикации конца телеграфной ленты. Хотя мы еще увидим в гл. 9, как Форт обращается со
строками символов, сейчас мы рассмотрим, как он воспринимает отдельные символы. Несмотря
на то, что код ASCII не предназначался для ЭВМ, символы в нем все же упорядочены логично
с точки зрения ЭВМ, т.е. в порядке расположения букв алфавита. Полный набор кодов ASCII
приведен в приложении Г. В табл. 3.3 показано только, как он организован.
От
Десятичный
Двоичный
До
Десятичный
Двоичный
Назначение
ООО
00000000
031
00011111
Коды управления ЭВМ
032
00100000
064
01000000
Цифры и знаки пунктуации
065
01000001
090
01011010
Буквы A-Z
091
01011011
096
01100000
Разные знаки
097
01100001
122
01111010
Буквы a-z
123
01111011
127
01111111
Разные символы
128
10000000
255
11111111
Кодами ASCII не являются,
содержат символы кириллицы
и специальные знаки типа рамок
Вы можете заметить, что в стандартном коде фактически используется только 7 разрядов
из байта. Это объясняется тем, что для телетайпов использовалась ссмидорожечная бумажная
лента с семью отверстиями поперек ленты. Она же использовалась для хранения программ и дан¬
ных до сравнительно недавнего времени, последние компьютеры использовали 8-битную ленту.
Числа с восьмым разрядом, установленным в 1 (128—255), не являются кодами ASCII, но исполь¬
зуются для локальнаых символьных кодировок типа кириллицы39, графических и специальных
символов.
Первые 31 код называются управляющими кодами. Хотя их назначение стандартизовано для
передачи данных, но в компьютерах они применяются для разных целей, т.е. стандарт наруша¬
ется. Тем не менее некоторые из них все же стандартизованы, как, например, 8 — код забоя
(возврата на позицию влево, backspace), 13 — возврат каретки CR, 10 — перевод строки LF.
В зависимости от операционной системы конец строки и переход на следующую отмечается: в
DOS Windows двумя символами CR LF, в UNIX — только CR.
Управляющие коды посылаются с клавиатуры путем нажатия клавиши [Ctrl] (управление,
иногда обозначается [Control]) и одновременно какой-то литерной клавиши, например для воз¬
врата влево на позицию — это [Ctrl-H]. Если на клавиатуре нет клавиши [Ctrl], то в вашей версии
Форта и компьютера должна быть предусмотрена какая-либо другая клавиша, которая действу¬
ет как [Ctrl], например на советском клоне PDP-11 (?) бытовом компьютере БК10/БК11М это
36 называемый BEL — звонок
37 от Who aRe yoU — кто там ?
38 End of Media — конец носителя
39 поставившей рекорд по кличеству кодировок — соответствия символов и их кодов: ср866, koi8-r, windows-1251,
mac, телеграфная кодировка МТК-2
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка
65
клавиша [Упр]. Вам нужно посмотреть по своей документации, какие управляющие коды исполь¬
зуются в вашей версии Форта и какую клавишу нужно использовать, если у вас нет клавиши
[Ctrl].
3.8.2 Ввод/вывод символов
Чтобы узнать, как в вашей версии Форта используются коды ASCII, воспользуйтесь двумя
словами EMIT и KEY.
Введите
65 EMIT
и на экране должно появиться
А ок
Слово EMIT берет число с вершины стека и посылает его ASCII-эквивалент на экран. Испы¬
тайте со словом EMIT другие числа, сравнивая получаемые результаты с таблицей в приложении
Г, чтобы получше прочувствовать, как ваше оборудование обращается с кодами ASCII. Некото¬
рые особые символы, такие как тильда -", "стрелка вверх" (), квадратные скобки [] на различных
компьютерах могут выглядеть по-разному, и то, что печатает ваш принтер, также может отли¬
чаться от того, что выводится на экране. Использование чисел меньше 32 может привести к
неожиданным результатам, так как это тс самые управляющие коды.
Если слово EMIT позволяет вывести символы ASCII, соответствующие числу, находящемуся
в стеке, то слово KEY позволяет выдать в стек код символа ASCII, вводимого с клавиатуры.
Введите слово
KEY
Ничего заметного при этом не случится, даже сообщение "ок" не появится. Теперь нажмите
клавишу [В], а потом . [Enter]. После этого вы увидите, что в стек было положено число 66.
Слово KEY приказало Форту приостановить то, что он делал, и подождать, когда будет нажата
какая-либо клавиша, тогда код, соответствующий символу клавиши, кладется в стек. Когда вы
нажали клавишу "В", вы поместили значение кода ASCII в стек и увидели этот код, когда ввели
. (точку). Что вы увидите, если введете с клавиатуры
KEY EMIT
Попробуйте после этого нажать какую-либо клавишу. Можете ли вы объяснить результат ?
Если v вас нет компьютера под рукой, то вот, что вы должны увидеть, если, скажем, нажмете
|Z.|:
z ok
Полезно уметь делать преобразования кодов ASCII, например, для представления вместо букв
нижнего регистра букв верхнего регистра и наоборот. Посмотрим, как это делается в упражне¬
ниях.
3.8.3 Упражнения
Наиболее удобно (и быстро) коды ASCII преобразуются с помощью операций над отдельными
битами, с которыми вы уже знакомы. Обратитесь к приложению Г для справки о значениях
разрядов, которые нужно преобразовать в приводимых заданиях.
1. Напишите слово, которое меняет любой код больше 127 на код меньше 127, но не влияет на
код меньше 127. Совет: измените один разряд из "1"в "О".
2. Напишите слово для преобразования любого управляющего кода в печатный символ. Сде¬
лайте это двумя способами: с помощью поразрядных операций и с помощью сложения.
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
66
3 Основы языка,
3. Напишите слово для преобразования символов нижнего регистра в символы верхнего реги¬
стра.
4. Напишите слово, которое делает обратное преобразование.
5. Напишите слово, которое позволяет выдать в стек адрес памяти, а затем печатает символ
ASCII, который находится по этому адресу.
6. Напишите слово, которое снимает символ с клавиатуры и помещает его по адресу, который
выдает в стек слово PAD.
3.9 Выводы
Теперв bbi должны хорошо представлятв себе, как хранятся числа в памяти, что такое двоич¬
ные, десятичные и шестнадцатеричные числа, как полвзоватвея словом BASE, чтобы посмотретв
числа в различных системах счисления и как обращатвея с отдельными разрядами чисел. Если вы
разобрались в этих вопросах достаточно хорошо, то вы уже знаете больше о работе компьютера,
чем многие программирующие на других языках.
Мы изложили эти вопросы в начале, чтобы заложить прочный фундамент. Но никто, кроме
программиста, который постоянно работает на уровне битов и байтов, не может точно сказать,
что делают операторы типа XOR и AND. Почти все мы вынуждены заглянуть в таблицу или
ввести что-то с клавиатуры, чтобы вспомнить, чему равен шестнадцатеричный эквивалент числа
245, а большинство из нас не смогли бы даже вспомнить, как хранится знак числа, если бы не
было этого краткого обзора.
Важно то, что если вы однажды поняли этот материал, то вам будет легко вспомнить его, если
потребуется. Поэтому не пытайтесь запомнить все детали этой части книги. Вы можете подумать,
что, хотя вы поняли представление алфавитно-цифровой информации кодами ASCII, вам это не
принесло практической пользы. Вы правы. Но уже скоро мы узнаем о том, что возможности
даже базового Форта в обработке символьной информации намного шире.
3.10 Арифметические операции
Наконец, в этом месте вы можете задать вопрос: должны ли мы работать только с целы¬
ми числами ? Сам по себе Форт, определенный в соответствии со стандартами, не применяет
арифметики с плавающей запятой.
Многие считают, что целочисленной арифметики вполне достаточно для разработки программ
управления оборудованием, автоматики, компьютерных игр и обработки текстовой информации.
Но для решения технических и научных задач этого явно недостаточно. Хотя действия с целы¬
ми числами выполняются быстрее, а в других языках программирования использованием чисел с
плавающей запятой иногда чрезмерно увлекаются, все же бывает, что целые числа при решении
практических задач оказываются неприменимыми. Далее будут рассмотрены приемы вычисле¬
ния с применением целых чисел, а также специальных аппаратных средств или их программной
замены. И, кроме, того узнаем значительно больше о других арифметических операциях в языке
Форт.
Мы уже не раз говорили о том, что компьютеры используются не только для вычислений, но и
во многих других областях, однако, что бы они ни делали, они имеют дело с числами. Эта большая
глава представляет собой что-то вроде попурри на тему чисел. Однако если в предыдущих и
большинстве следующих глав для любой серьезной работы по программированию был нужен
весь материал, то некоторые части этой главы потребуются вам только в том случае, если вы
будете заниматься "перемалыванием"чисел40, например обработкой результатов экспериментов
или моделированием.
Как минимум, вы должны изучить это введение и разделы 3.10.1, 3.10.2, 3.10.3. Если вы будете
работать с очень большими числами и дробями, вам нужно изучить разделы 3.10.4, 3.10.5, 3.10.6
и 3.10.7. А если вас интересует работа с числами с плавающей запятой, вы должны прочитать
раздел 7.
40 data crunching
Форт бс) RU FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
3 Основы языка,
67
К настоящему времени вы изучили четыре арифметические операции: сложение, вычитание,
умножение и деление и соответствующие слова Форта + , -, * и /. Нам остается мало что добавитв,
кроме как упомянутв о потенциалвно возможной проблеме арифметического переполнения.
Предположим, bbi складываете числа 36000 и 37000. Результат должен равняться 73000; т.е.
быть больше, чем 16-разрядное число, которое может быть в стеке 16-битного Форта. Анало¬
гичная ситуация возникает и в системах любой другой разрядности (32- и 64-) — только в этом
случае эти числа на многие порядки больше, поэтому вы можете и не столкнуться с такой си¬
туацией, если не пишете соответствующих программ для работы с такими большими числами.
Например, если вы пишете бухгалтерскую программу, выполняющую все вычисления в копейках
или десятичных долях копеек41, ваша программа будет нормально работать во всех мелких фир¬
мах типа Вася Пупкин и Ко, но при попытке ее использования какой-нибудь транснациональной
корпорацией с огромным бюджетом может вылезти ошибка переполнения.
Это и есть переполнение, которое приводит к неверному результату. Во всех 16-битных вер¬
сиях Форта в результате сложения 36000 и 37000 6v. ier получаться 7464, что, очевидно, неверно.
Переполнение может возникнуть также при операциях * и -. Некоторые языки могут обнару¬
жить ошибку переполнения и либо прекратить исполнение программы, либо выдать сообщение
об ошибке, Форт этого не сделает. Почему ? Потому что проверка на наличие ошибок занимает
время ЭВМ, и обычно немалое, поэтому, чтобы не снижать скорости работы, заботу об избежа¬
нии ошибок Форт предоставляет программисту. Вторая причина — желание, чтобы программа
работала, даже если произошла ошибка.
Нас интересует проверка возникновения переполнения и его предотвращение. Как быть, если
вы хотите работать с числами больше 32767 пли меньшими -32767, т.е. с числами больше 65535,
если не учитывать знака. Имеется два способа решения этой проблемы. Один из них — это
использование так называемых чисел двойной длины (или, как иногда говорят, двойной точности
или просто двойных чисел), которые представляются 32 разрядами. Другой — в использовании
чисел с плавающей запятой (при этом вы получите большую потерю точности, именно поэтому
использование таких чисел в финансовых расчетах воспрещается).
3.10.1 Операторы для работы с небольшими числами
В стандартах описываются несколько специальных операций для работы с небольшими чис¬
лами, типа Это 1+, 1-, 2+ и 2-, 2*, 2/ и т.п. Эти операции выполняют то, что и следует ожидать,
работая с числом, находящимся на вершине стека, т.е. производят умножение, деление, сложение
и
3.10.2 Некоторые проблемы операции деления
3.10.3 Операции с величинами и знаками чисел
3.10.4 Почему используются целые числа ?
3.10.5 Масштабирование чисел
3.10.6 Числа двойной длины
3.10.7 Совместное применение чисел одинарной и двойной длины
3.10.8 trash
Арифметический стек — основное поле для выполнения арифметических действий и хранения
промежуточных результатов вычислений. Надо только помнить, что знак операции (точнее сло¬
во, обозначающее операцию) пишется ПОСЛЕ того, как аргументы в стеке уже размещены.
Текст
13 3 -
помещает в стек число 10, так как слово -" (минус) извлекает из стека два числа, сперва
вычитаемое, потом уменьшаемое, и помещает в стек их разность:
41 чтобы не потерять деньги при начислении сложных процентов
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
68
3 Основы языка,
а b --> ... а-Ь
С другими операциями все обстоит аналогично
+
а
b
-->
а+Ь
*
а
b
-->
а*Ь
ABS
а
-->
... 1а|
NEGATE
а
-->
-а
/
а
b
-->
целая часть
MOD
а
b
-->
остаток
/MOD
а
b
-->
остаток целая часть
В трех последних словах имеются в виду остаток и целая часть частного от деления а на Ь.
Так, при делении 26 на 7 имеем:
26 7 / --> 3
26 7 MOD --> 5
26 7 /MOD --> 5 3
Имеются специальные слова для действий с 1 и 2 (они выполняются немного быстрее)
1+ ... а --> ... а+1
Аналогично работают "1-", "2+", "2-", "2*", "2/".
3.11 Хранение программ и данных
3.12 Методика программирования на Форте
Язык Форт по своей идеологии очень минималистичен, так как изначально был разработан
для программирования систем с очень ограниченными ресурсами — сейчас такие системы можно
встретить исключительно в виде блоков управления различным оборудованием. Даже компьюте¬
ры внутри мобильников во многие разы больше по доступным ресурсам (скорости, разрядности
процессора, объемам памяти, возможностям вывода графики и размерам носителей данных).
Сам язык практически не защищает программиста от ошибок типа некорректной работы
с данными, не поддерживает типизацию, ООП, структуры данных и т.п. Практически это ас¬
семблер стековой машины, и программирование на нем очень близко к программированию на
обычных ассемблерах — программист вынужден реализовывать все вручную, самостоятельно
отслеживая состояние стека, корреткность адресов и указателей и т.п.
Если вы хотите иметь язык, выполняющий серьезный контроль вашего кода, Форт для вас
не подходит.
С другой стороны у Форта есть одна особенность, которой многие языки не обладают, и
которая является ключевой — на Форте вы не столько программируете, сколько расширяете
язык через уже существующие в нем слова, определяя диалект под вашу задачу. Подробнее см
[orange, thinking]. Из-за этой особенности Форт нельзя называть языком низкого уровня — хотя
его ядро и низкоуровневое42, но его расширение приводит к созданию диалектов сверх-высокого
уровня.
Другими словами Форт — язык для конструирования проблемно-ориентированных языков,
работающих на очень простой виртуальной машине. Реализация такой стековой ВМ для реаль¬
ного железа также проста, поэтому эта ВМ легко и быстро реализуется на любом языке или
ассемлере, а программы на Форте переносятся либо вобще без изменений43 или с самыми мини¬
мальными правками, типа настройки программы под платформу и решаемые задачи.
42 по при этом все равно платформенно-независимое
4о признак правильно написанной форт-программы
Форт (с) R-U FIG. Понятов Д.А. <forth©km.ru> . public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем
69
4 Принципы работы форт-системы
4.1 Создание слов-определителей
4.2 Память Форта, словари и контекстные словари
4.2.1 Кодофайл
Кодофайлом будем называть участок памяти, в котором располагаются набор слов Форт-
системы и новые скомпилированные слова, написанные пользователем. Здесь же размещаются
константы и переменные. Память занимается в направлении возрастания адресов, при этом сво¬
бодная память находится в конце словаря. Иногда два соседних байта называют ячейкой. Тогда
адресом ячейки считается адрес младшего байта (то есть байта с меньшим адресом). Мы будем
называть ВЕРШИНОЙ СЛОВАРЯ первый свободный байт памяти. От программиста требуется
особая осторожность при работе с памятью: изменения, записанные в ячейку с ошибочным ад¬
ресом, могут нарушить функционирование Форт-системы так, что потребуется ее перезагрузка!
Вот некоторые стандартные слова для работы с кодофайлом:
HERE ... --> ... addr
На стек кладется адрес вершины кодофайла. С помощью этого слова можно определить,
какой объем памяти требуется для любого фрагмента Вашей программы - надо сравнить значения
HERE до компиляции и после нее.
ALLOT ... п --> ...
Резервируются п байтов свободной памяти: адрес вершины кодофайла увеличивается на и (а
при п<0 уменьшается).
, п. -->
Занятие двух байтов в кодофайле и запись туда п.
! ... a addr --> ...
Это слово (восклицательный знак, читается "запомнить") служит для записи значения по
данному адресу.
О ... addr --> ... а
Слово © (читается "взять") кладет в стек значение, хранящееся по адресу, лежащему на стеке.
Сам адрес из стека при этом убирается.
+! ... a addr -->
К числу, расположенному по адресу addr, прибавляется значение а. Результат сохраняется
там же.
4.3 Интерпретация, компиляция и исполнение
5 Создание компиляторов и форт-систем
5.1 Создание собственных компиляторов
Если вам приспичило написать собственный компилятор языка высокого или сверх-высокого
уровня, но при этом хочется это дело максимально упростить — используйте модификацию языка
Форт.
Форт — самый простой по синтаксису и реализации из ЯВУ, написать компилятор для Форта
сможет любой чайник, особенно если будет использовать эту книгу как справочник.
версия 18 марта 2006 г. Форт <с') R.U FIG, Понятов Д.А. <forth@km.ru> , public domain
70
5 Создание компиляторов и форт-систем
Именно простотой Форт и одновременно его крайне низкими требованиями к компьютеру
объясняется то, что созданы десятки компиляторов Форта для всех существующих компьютеров,
даже для самых хилых микроконтроллеров с ОЗУ всего несколько Кб.
В этой книге описана методика, которая упростит написание своего Форта на порядок — те¬
перь вам даже не нужно писать свой интерпретатор и стандартный набор слов, достаточно взять
готовую чужую форт-систему и добавить к ней простейший компилятор в байт-код, а интер¬
претатор байт-кода написать на любом другом языке, ассемблере или даже сделать собствен¬
ный стековый процессор, используя перепрограммируемые логические матрицы фирм Altera или
Xilinx.
5.2 Целевая компиляция
Значение термина компиляция в Форте отличается от его традиционного применения. Обычно
под компиляцией подразумевается обработка текстовых файлов с текстами программ и генера¬
ция машинного или байт-кода. В Форте компиляцией называется добавление байтов в словарь
в процессе определения новых слов и структур данных. Компилятором в Форте являются слова
С, и , , которые добавляют на вершину словаря соответственно байт или cell (машинное слово).
Остальные компилирующие слова Форта работают через эти слова.
Штатный компилятор ФОРТа способен только добавлять код к коду ФОРТ-системы. Более
интересная для разработчиков техника44 — целевая компиляция. Она используется в случаях
когда необходимо генерировать машинный код для другой архитектуры (кросс-компиляция) или
для той же самой, но нс включать в код ФОРТ-систему, то есть создавать объектный код с нуля.
При этом объем генерируемого кода можно значительно сократить, не включая в него никакой
дополнительной информации (словарей).
5.2.1 Минимальный ЦК
Механизм работы целевого компилятора (ЦК) полностью аналогичен обычному, отличие за¬
ключается в том что формируемый код компилируется не в память ФОРТ-системы, а в специ¬
ально выделенный буфер целевого компилятора. Текущую позицию компиляции в этом буфере
указывает value-перемененная THERE, аналогичная HERE в ФОРТ-системе.
0x10000 CONSTANT Msz \ размер буфера ЦК
CREATE М Msz ALLOT \ буфер ЦК
0 VALUE THERE \ указатель ЦК
(максимальный размер целевого кода)
Определяем основные слова ЦК. При этом нужно учитывать порядок байт в машинном сло¬
ве. Например, в архитектуре 80x86 первым в памяти находится младший байт, у MCS-51 и AVR
старший. В примере показаны слова для 80x86 и os, для MCS-51 нужно будет дополнительно вы¬
полнять переупорядочение байтов. Для упрощения понимания кода мы не будем переопределять
стандартные слова С, и , , а будем использовать для слов ЦК нестандартные имена.
ь, (
byte -- )
THERE М + С!
W, (
word -- )
THERE М + W!
d, (
dword --
) THERE М +
\ 32-
-битное слово
THERE 1 + ТО THERE ; \ скомпилировать байт
THERE 2 + ТО THERE ; \ скомпилировать слово
! THERE 4 + ТО THERE ; \ скомпилировать
Для сохранения наработанного кода в двоичный файл используем слово save" (также неплохо
было бы определить слово hex" для сохранения в формате Intel HEX для загрузки в симуляторы
и целевые системы)
: save" \ program.bin"
[CHAR] " WORD COUNT W/0 CREATE-FILE DROP \ открыть файл
М THERE ROT WRITE-FILE DROP
BYE
\ закрытием файла
\ записать код в файл
\ выход с автоматическим
44к сожалению, она плохо описана в русскоязычной литературе
Форт © RU FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем 71
Приведенные три секции кода являются минимальным целевым компилятором, на основе
которого пишутся компиляторы и форт-ассемблеры для любых платформ (с учетом порядка
байт в машинном слове см. выше). Использование техники целевой компиляции позволяет очень
быстро написать ассемблер с очень мошной поддержкой макросов40, но имеет значительный
недостаток, который может оказаться критичным при выборе между готовым ассемблером и
форт-ассемблером: при написании форт-ассемблера чаще всего используют постфиксный форт-
подобный синтаксис, так как его очень просто реализовать, но при этом возникает проблема
использования наработок с традиционным синтаксисом.
5.2.2 Целевой компилятор для os
Простейшим примером использования ЦК является ЦК для os. Его простота определяется
тем, что виртуальная машина os* 46 имеет всего два вида команд с простым форматом: опкод
имеет фиксированный размер в один байт, команды безоперандные или с одним операндом фик¬
сированного размера байт или 16-битное слово. В других архитектурах формат команды намного
сложнее из-за использования битовых полей, в которых кодируются операнды и режимы адреса¬
ции. Основную сложность в ЦК для os создают слова для формирования словарной структуры
и особенно слова, компилирующие управляющие структуры. Если у вас возникают вопросы, на¬
пишите мне чтобы я более подробно описал структуру кода управляющих структур и механизм
работы слов, компилирюущих этот код.
Эта версия ЦК написана для конкретной форт-системы, которая является регистро-чувстви¬
тельной, то есть отличает слова dup и DUP. Я пробовал использовать другие форт-системы, но
они не отличают регистр слов, поэтому этот вариант ЦК для них не годится.
Хорошим упраженением (которое вам все равно придется сделать, если строго следовать идео¬
логии os) будет написание ЦК для вашей любимой форт-системы.
Есть подводный камень — в примерах программ используются макросы, которые на самом
деле являются обычными форт-словами, поэтому они могут отказаться работать с вашей форт-
системой, и их тоже придется адаптировать.
Самый неприятный вариант, если вы решите написать целевой компилятор не на Форте, в
этом случае макросы работать вообще не будут, так как их работа целиком обеспечивается форт-
систем ой.
\ стековый ассемблер (целевой компилятор) для SP-FORTH 4 [http://spf.sf.net]
В этом варианте ЦК не используются словари, а этот код только убирает лишние предупре¬
ждения о переопределении слов.
VOCABULARY ТС ONLY FORTH ALSO ТС ТС DEFINITIONS
По молчанию ЦК компилирует байт-код с созданием словарной структуры (включением ме¬
таинформации с именами всех слов ваших программ). Если вам по какой-то причине нужно
выключить генерацию словаря, после загрузки ЦК нужно выполнить код О ТО ?VOC.
1 VALUE ?VOC \ флаг включения в байт-код словарной структуры
\ (по умолчанию влючен, для минимизации кода
\ после S" tc.4th" INCLUDED добавить О ТО 7V0C )
Мы компилируем код для 16-битной виртуальной машины, поэтому нужно переопределить
слова CELL и CELLS:
2 CONSTANT CELL
: CELLS CELL * ;
\ разрядность BM 8*cell бит
Этот код описан в примере минимального ЦК выше.
4идля определения макросов доступны все функции форт-системы
46 FVM, виртуальная форт-машина
версия 18 марта 2006 г.
Форт (<Ц RU FIG, Понятов Д.А. <forth©km.ru> , public domain
72
5 Создание компиляторов и форт-систем
0x10000 CONSTANT Msz \ максимальный размер программы, байт
CREATE М Msz ALLOT \ буфер компилятора
О VALUE THERE \ указатель компилятора
В начале байт-кода находятся несколько полей, адреса которых нам будут нужны в словах
ЦК (компиляцию этих полей см. последние строки ЦК)
По адресу 0000 в байт-коде находится команда перехода на точку входа jmp .entry:
1 CONSTANT .entry \ стартовый адрес
Затем идет 2-байтное поле с адресом последнего форт-слова в словаре, который представляет
собой односвязный список словарных статей (см. далее). Это поле используется для перехода на
начало этого списка.
.entry CELL + CONSTANT .latest \ адрес последнего слова в словаре
Последнее поле — значение указателя компиляции на момент сохранения байт-кода (аналог
значения, возвращаемого словом HERE для обычного Форта).
.latest CELL + CONSTANT .here \ адрес начала кучи (размер байт-кода +1)
Для чтения/записи буфера ЦК, компиляции байта, 16-битного слова и счетной байтной строки
определяются специальные слова, которые вы можете также использовать в своих макросах и
расширениях ЦК.
Записать бант, слово, прочитать слово:
: b! ( byte addr -- ) М + С! ;
: w! ( cell addr -- ) М + W! ;
: w0 ( addr -- cell ) M + W@ ;
Компилирующие слова
: b, THERE b! THERE 1+ TO THERE ; \ скомпилировать байт
: w, THERE w! THERE 2+ TO THERE ; \ 16-битное слово
Скомпилировать счетную строку
: s, ( addr n--) \ -"- счетную 8-битную строку
DUP Ь, 0 D0
DUP I + СО b,
LOOP DROP
Для завершения работы ЦК нужно выполнить слово save" filename", указав имя файла, в
который записать байт-код:
: save" \ program"
\ сохранить скомпилированный байт-код в файл и выйти из форт-системы
THERE .here w! \ сохранение размера кода
[CHAR] " WORD COUNT W/0 CREATE-FILE DROP \ открытие файла
M THERE ROT WRITE-FILE DROP BYE \ запись байт-кода и выход
В os используется два типа команд (Полное описание системы команд os см. раздел 9.4):
: Оор CREATE С, DOES> СО b, ;
: lop CREATE С, DOES> СО b, w, ;
\ безоперандные команды
\ команды с одним операндом (16 бит)
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем.
73
команды управления выполнением программы
0x00 Оор пор
0x01 lop jmp 0x02 lop ?jmp 0x03 lop call 0x04 Oop ret
0x05 lop lit : # lit ;
0x06 Oop exec
0x07 Oop bye
OxOF Oop cell
Самое сложное в ЦК - компиляция управляющих структур. Присылайте вопросы, если нужно
более подробное описание.
Циклы со счетчиком
0x08 Oop do 0x09 Oop loop 0х0А Oop i 0x0В Oop j ОхОС Oop к
: entry! THERE _entry w! ; \ модифицировать стартовый код (точку входа)
Слова для компиляции словарной статьи.
Каждое слово в словаре состоит из нескольких полей:
LFA
Поле связи
CELL
адрес следующего элемента списка словаря, 0 признак конца списка.
При компиляции LFA текущее значение указателя сохраняется в поле „latest, а его преды-
дещее значение компилируется.
: LFA, „latest THERE „latest w! w, ;
NFA
Поле имени
счетная строка
содержит имя слова.
Имя получается из входного потока, затем позиция во входном потоке восстанавливается.
: NFA, >IN 0 BL WORD COUNT s, >IN ! ;
AFA
Поле атрибутов слова
байт
Хранит флаги слова типа SMUDGE и IMMEDIATE, в ЦК не устанавливаются.
: AFA, 0 Ь, ;
Слово компилирует заголовок словарной статьи (LFA, NFA, AFA), если установлен флаг 7V0C.
: HEADER, \ скомпилировать заголовок слова если 7V0C != 0
?VOC IF
LFA, NFA, AFA,
THEN
Начало определения слова
Компилируется заголовок словарной статьи, текущая позиция компиляции (поле кода, CFA)
запоминается в виде специального слова в словаре форт-системы. При выполнении этого слова
будет скомпилирована команда call на запомненный CFA.
версия 18 марта 2006 г.
Форт <с) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
74
5 Создание компиляторов и форт-систем
: { HEADER, entry! CREATE THERE , DOES> @ call ; \ начало определения
Конец определения слова
Просто компилируется команда ret.
: } ret ; \ конец О определения
Определение константы 0x1234 const А
Компилируется слово А, которое при выполнении положит на стек указанную константу ко¬
мандой lit.
: const (n--){(n)#}; \ определить константу
Определение переменной 0x5678 var В
Компилируется слово В и следом (PFA, поле параметров) начальное значение переменной.
Слово будет класть на стек адрес поля параметров.
: var ( п — ) { THERE 4+#}(n)w, ; \ переменную
Скомпилировать буфер размером п байт 0x120 buffer С
Работа аналогична var, но поле параметров - компилируется 0 байт указанное число раз.
: buffer CREATE THERE , 0 ?D0 0 b, LOOP DOES> ® # ;
Управляющая структура if else then
if комплирует команду условного перехода на фиктивный адрес -1, запоминая адрес параметра
команды на стеке.
: if -1 ?jmp THERE CELL - ;
then берет co стека адрес, и записывает по этому адресу текущее значение указателя компиля¬
ции. адрес указывает на параметр команды jmp или ?jmp (метод backpatching при однопроходной
компиляции)
: then THERE SWAP w! ;
: else -1 jmp THERE CELL - SWAP then ;
в итоге из
a (flag ) if b else c then d
должен скомпилироваться код
a
:if ?jmp else
b
jmp then
:else
c
:then
d
Циклы с условием
Реализация аналогична if else then
Форт (c) RU FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем
75
: begin THERE ;
: again jmp ;
: until ?jmp ;
: while if ;
: repeat SWAP jmp THERE SWAP w! ;
Остальные команды описываются элементарно через слова Оор и lop.
Если вы будете добавлять в систему команд ВМ свои команды, дописывайте их на опкоды
F0..FF, можно также использовать многобайтные команды, включая дополнительные наборы
опкодов командой-префиксом (в качестве примера см. графическое расширение).
стек
0x10 Oop dup
0x11 Oop drop 0x12 Oop swap 0x13 Oop over
память
Для использования слова @ из форт-системы (оно переопределяется новым словом 0 компи¬
лирующим соответствующубю команду) сначала определяется новое алиасное слово
0x20 Oop с@
0x21 Оор с!
: ~0 0 ;
0x22 Оор ®
0x23 Оор !
арифметика
. + •
0x30 Оор +
0x31 Оор -
0x32 Оор *
0x33 Оор /
0x34 Оор */
0x35 Оор rnd
логика и битовые операции
0x40 Оор =
0x41 Оор <>
0x42
Оор >
0x43 Оор <
0x48 Оор not
0х4С Оор Ishift
консольный ввод
0x70 Оор key
0x72 Оор ?кеу
0x49 Оор or
0x4D Оор rshift
/вывод
0x71 Оор emit
0x73 Оор ?emit
0х4А
Оор and
0x4В Оор хог
интерфейс к отладчику
0x80 Оор s.
0x83 Оор •
0x81 Оор h-
0x84 Оор и.
0x82 Оор dumP
строки
0x90 Оор (")
0x91 Оор count
0x92 Оор РГ1П
,, тт „ гтппкя" используются макросы:
для компиляции " строка И . вывод строки
(") [CHAR] " WORD COUNT s, ;
и " print ;
Быстрый поиск в словаре
0хА0 Oop find
д <forth@km.ru> , public domain
Форт (с) RU FIG, Понятов Д.А- ’ *
версия
18 марта 2006 г.
76
5 Создание компиляторов и форт-систем
Так как у нас опкод команды занимает всего один байт, общее число команд не может превы¬
шать 256 команд, что явно недостаточно даже для Форта во встраиваемой системе. Чтобы расши¬
рить диапазон команд, используются специальные однобайтные команды-модификаторы (пре¬
фиксы), после выполнения которых в виртуальной машине запускается дополнительный цикл
выборки/выполнения команды, при этом опкод этой команды декодируется по другой (расши¬
ренной) таблице соответствия опкод-команда. Используя один или несколько команд-префиксов,
мы получаем неограниченное количество команд ВМ.
В качестве иллюстрации — расширенный набор команд графического драйвера, встроенного
в виртуальную машину:
\ графическое расширение -- драйвер mono LCD
Для определения gr/ команд используем слово, аналогичное Оор, но компилирующее перед
опкодом префикс включения графического расширения системы команд (gr/ не использует ко¬
манды формата lop):
: gr CREATE С, DOES> OxFO b, C@ b, ;
0x00 gr gr/on 0x01 gr gr/off
0x02 gr gr/Xsz 0x03 gr gr/Ysz
0x04 gr gr/set 0x05 gr gr/clr 0x06 gr gr/get
0x07 gr gr/pointer 0x08 gr gr/?pointer
Соответственно команда gr/on скомпилирует два байта: F0 00.
Этот код скомпилирует заголок байт-кода (стартовый jmp и поля _here и .latest)
-1 jmp \ jmp .entry
0 w, \ .latest
0 w, \ .here
5.3 Как написать свой (кросс-/ассемблер
© Brad Rodriguez
5.3.1 Введение
В предыдущем выпуске журнала я описал как "загрузить" себя на новый процессор используя
простой отладочный монитор. Но как вы сможете писать код для этого нового процессора, если
вы нс можете найти ассемблер пли он вас не устраивает ? Напишите свой !
ФОРТ — идеальный язык для этого. Для TSM320 например я написал кросс-ассемблер всего
за два часа, включая длинный обеденный перерыв. Обычно это занимает около двух дней, но
для одного из процессоров (Zilog Supcr8) потребовалось пять дней. Но когда у вас больше времен
чем денег, это не важно.
В части 1 этой статьи я опишу основные принципы ФОРТ-ассемблеров — структурирован¬
ные, однопроходные, постфиксные. Многое из этого применимо для любого процессора, и это
концепции почти любого ФОРТ-ассемблера.
В части 2 я покажу как писать ассемблер для специфичного процессора Motorola 6809. Этот
ассемблер прост но не тривиален, занимает 15 страниц исходного кода. Кроме всего прочего,
этот пример покажет как реализовывать инструкции с множественными режимами адресации.
Изучив этот пример, вы сможете понять как использовать особенности вашего процессора.
Форт ©) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем 77
5.3.2 Зачем использовать ФОРТ ?
Мне кажется что ФОРТ - простейший язык для написания ассемблера. Прежде всего ФОРТ
имеет текстовый интерпретатор для разбора текстовых строк и выполнения соответствующих
команд. Преобразование текстовых строк в байты кода - как раз и есть задача ассемблера. Опе¬
ранды и режимы адресации также реализуются через ФОРТ-слова.
ФОРТ также включает определяющие слова, которые позволяют легко описать большие на¬
боры слов с общим действием. Эта возможность очень полезна при определении мнемоник ас¬
семблера.
Так как при работе ассемблера доступны все слова ФОРТ а, они могут быть использованы при
использовании ассемблера не только для вычисления адресов и операндов, и и для выполнения
более сложных действий.
В общем так как ассемблер полностью реализуется через слова ФОРТ а, определения ФОРТ
а аналогичны макро-определениям.
5.3.3 Простейший пример: ассемблирование NOP
Для понимания того как ФОРТ транслирует мнемоники в машинный код, рассмотрим про¬
стейший случай: инструкцию NOP (0x12 для 6809, 0x90 для 80x86).
Обычный ассемблер при нахождении строки "NOP" должен добавить соответствующий байт
в выходной файл и увеличить указатель на 1. Операнды и комментарии игнорируются. Я также
пока бу. iy игнорировать метки.
В ФОРТ е выходным файлом обычно является словарь в памяти или при кросс-ассемблиро¬
вании блок памяти: образ памяти целевой системы. Так, определим слово NOP соответствующим
образом: "скомпилировать опкод NOP и увеличить указатель".
: NOP, 0x12 С, ;
Обратите внимание что в этом примере используется возможность SP-FORTH воспринимать
числа с префиксом Ох (шестнадцатеричные числа) независимо от текущей системы счисления,
заданной в переменной BASE. Если ваша ФОРТ-система не имеет такой возможности, для удоб¬
ства в начале кода ассемблера можно использовать слово HEX. Также следует обратить внимание
на то, что при использовании целевого компилятора для кросс-разработки слово С, должно быть
переопределено так, чтобы оно компилировало байт в образ памяти целевой системы.
Для ассемблерных опкодов часто задаются имена ФОРТ-слов имеющие в конце символ ",",
как это сделано выше. Это делается из-за того что многие ФОРТ-слова (например AND, XOR,
OR) конфликтуют с мнемониками ассемблера. Простейшее решение - слегка изменить мнемоники
(символ "," в ФОРТ е обозначает что что-то компилируется (добавляется) в словарь).
5.3.4 Класс наследуемых опкодов
Большинство процессором имеют много инструкций подобных NOP, которые не требуют опе¬
рандов. Все они могут быть определены в ФОРТ о через двоеточие, но это значительно увели¬
чивает объем исходного кода. Намного более эффективным является использование механизма
определяющих слов для того, чтобы задать для всех таких слов общее поведение. В терминах
ООП это значит создание экземпляров сдинственног класса.Это далется с использованием слов
CREATE и DOES . В приведенном примере параметр (разный для каждого созданного слова)
обычный опкод, который должен быть скомпилирован для каждой инструкции.
: cmdOops
CREATE
с,
(
byte --
)
DOES>
(
-- addr
)
С@
(
addr --
byte)
с,
(
byte --
)
\ определение имени класса команды без опреандов
\ этот код выполняется при создании слов
\ сохранить байт для нового определяющего слова
\ этот код определяющего слова (общее действие)
\ получить сохраненный при создании слова опкод
\ скомпилировать опкод
Примеры использования определяющего слова cmdOops:
версия 18 марта 2006 г.
Форт Cj RU FIG, Понятов Д.А. <forth@km.ru> , public domain
78
5 Создание компиляторов и форт-систем
0x12 cmdOops NOP,
ОхЗА cmdOops АВХ,
0x3D cmdOops MUL,
Обратив особое внимание на то, что этот пример дан для обычного форт-ассемблера, а не
кросс-ассемблера, то есть генерируемый код компилируется в основной словарь форт-системы.
При кросс-компиляции (использовании целевого компилятора) нужно сделать несколько финтов
ушами — например нужно использовать разные варианты слова С, в блоках CREATE и DOES>
слова cmdOops, которые должны компилировать опкод соответственно в словарь форт-системы и
в область памяти целевой системы.
Эта техника дает некоторую экономию памяти почти без потери скорости, но реальное удоб¬
ство будет видно при определении сложных инструкций, которые требуют параметры и модифи¬
каторы режимов адресации.
5.3.5 Обработка операндов инструкций
Большинство команд ассемблера требуют один или более операндов. Для этих команд ас¬
семблер должен быть способен разбирать текст из входного потока и интерпретировать его как
операнды. Для постфиксного ФОРТ-ассемблера используется более простой способ, использую¬
щий готовый механизм интерпретации ФОРТ-систсмы.
Итак ФОРТ будет использоваться для разбора операндов. Числа обрабатываются как обыч¬
но (в любой системе счисления), для EQU выражений могут использоваться обучные константы
ФОРТ CONSTANT. Так как операнды определяют формат ассемблируемой команды, они долж¬
ны быть обработаны до команды ассемблера. Результаты разбора операндов обычно оставляются
на стеке данных и используются командами ассемблера для определения формата команды и ис¬
пользуемого оп-кода. Для ФОРТ-ассемблера используется уникальный4" постфиксный формат
команд: операнды, за которыми следует команда ассемблера.
Для примера рассмотрим инструкцию ORCC процессора 6809, которая использует простой
числовой параметр:
: ORCC, OxlA С, С, ; \ пример использования: 0x34 ORCC,
Выполнение этой команды состоит из двух этапов:
1. компилируется опкод инструкции OR.CC 0x1 А;
2. компилируется параметр инструкции 0x34, взятый со словаря.
Эта команда предполагает что на стеке уже лежит числовой параметр, полученный в резуль¬
тате разбора операндов, которые в нашем случае имеют вид простого hex числа 0x34 в исходном
коде.
Достоинство такого ассемблера - доступна вся мощь ФОРТ а, которая может быть исполь¬
зована для формирования операндов, например:
ONSTANT CY-FLAG \ используем константы ФОРТа для задания операндов
0x02 CONSTANT OV-FLAG
0x04 CONSTANT Z-FLAG
CY-FLAG Z-FLAG + ORCC, \ команда ORCC проверит флаги CY и Z
Из примера видно что расширение разбора операндов для определяющих слов ассемблера
достаточн просто.
41 ну не совсем уникальный - GNU assembler тоже постфиксный
Форт (с) RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем
79
5.3.6 Обработка режимов адресации
Для современных процессоров для одной команды используется несколько форматов и раз¬
личные оп-коды в зависимости от режима адресации. ФОРТ-ассемблеры решают эту проблему
несколькими способами в зависимости от типа процессора. Все эти способы используют методо¬
логию ФОРТ а: операторы определения режима адресации являются ФОРТ-словами. Когда эти
слова исполняются, они изменяют формат ассемблируемой инструкции. 1 помещение дополни¬
тельных параметров на стек.
Это наиболее удобно если всегда должен указываться режим адресации. Слова режима адре¬
сации оставляют на стеке некоторые константы, которые обрабатываются словами ассемблера.
Иногда эти значения могут быть "магическим числом", добавляемым к опкоду для изменения
режима адресации команды. Кодга это неприменимо, используется выбор формата команды в
блоке CASE. В общем случае скомпилированные инструкции могут иметь разнуб длину в зави¬
симости от режима адресации.
2 установка флагов или значений в фиксированных переменных.
Это наиболее удобно если режим адресации опционален. Не зная что был указан режим ад¬
ресации, вы не можете знать что значение на стеке "магическое число" или просто значение
операнда. Решение этой пролемы: режим адресации указывать помещая соответствующую ему
константу в определенную переменную (часто называемую MODE). После выполнения каждой
команды ассемблера эта переменная инийиализируется значением по умолчанию. Если использу¬
ется команда ассемблера, у которой может быть несколько режимов адресации, то она определяет
содержимое этой переменной.
3 модификация значений параметров непосредственно на стеке.
Это иногда возможно для реализации слов указывающих режим адресации, которые работают
модифицируя значения операндов. Этот метод используется редко.
Все эти три метода я использовал с некоторыми расширениями для реализации ассемблера
6809.
Для большинства процессоров имена регистров задаются обычными константами Форта, и
оставляют на стеке свои значения. Для некоторых процессоров также удобно иметь имена ре¬
гистров, определяющие режим "регистровой адресации". Это легко сделать, определяя имена
регистров как определяющие слова, которые создают слова, устанавливающие режим адресации
(а стеке или в переменной MODE).
Некоторые процессоры позволяют использовать несколько режимов адресации в одной ин¬
струкции. Если чисто режимов адресации фиксировано, они могут оставляться на стеке. Если
чисто переменное, необходимо знать сколько их был указано, и нужно использовать несколько
переменных MODE,,. Для процессора Super8 я должен был отслеживать не только сколько режи¬
мов адресации указано, но и сколько операндов. Я сделал это сохраняя позицию стека отдельно
для каждого режима адресации.
Рассмотрим инструкцию 6809 ADD. Для упрощения игнорируем индексированные режимы
адресации, и реализуем только три режима: непосредственный (immediate), прямой (direct) и
расширенный (extended):
исходный код ассемблируется как
immediate <число> # ADD, 8В пп
direct <адрес> <> ADD, 9В пп
extended <адрес> ADD, ВВ аа аа
Так как режим extended не имеет оператора режима адресации, режим адресации оказывается
уже определенным. Слова ФОРТ а Д и О устанавливают режим адресации. Рассмотрим систему
команд 6809. Если опкод immediate является основным значением, то опкод в direct режиме равен
базовому +0x10, в indexed режиме +0x20 и в extended режиме +0x30. Это справедливо для почти
всех инструкций, использующих эти режимы адресации. Исключение составляют те опкод, для
которых опкоды в режиме direct имяют форму 0x0?.
Такие особенности системы команд нужно использовать. Это общее правило при написании
ассемблеров: найдите или сделайте сами таблицу опкодов, и найдите закономерности - особенно
те, которые применимы для режимов адресации или других модификаторов инструкций (таких
как коды условий).
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
80
5 Создание компиляторов и форт-систем
В нашем случае нужно использовать следующие значения переменной MODE:
VARIABLE MODE
: # 0x00 MODE ! ;
: <> 0x10 MODE ! ;
: RESET 0x30 MODE ! ; \ значение по умолчанию
Значение по умолчанию 0x30 (extended режим) устанавливается словом RESET. Это слово
будет использоваться после того как будет ассемблирована каждая инструкция.
Теперь может быть написана команда ассемблера ADD,. Давайте посмотрим ее старую версию
и напишем определяющие слова для создания команд ассемблера.
: GENERAL-OP ( <базовый опкод> -- )
CREATE С,
DOES> \ ( <операнд> -- )
СО \ получить базовый опкод
MODE 0 + \ добавляем "магическое число"
С, \ ассемблируем опкод
MODE 0 CASE
0x00 OF С, END0F \ операнд байт
0x10 OF С, END0F \ операнд байт
0x30 OF , END0F \ операнд слово (2 байта)
ENDCASE
RESET \ выбор режима адресации по умолчанию
8В GENERAL-OP ADD,
Каждый экземпляр GENERAL-OP будет иметь различный базовый опкод. Когда ADD, вы¬
полняется, он будет получать этот базовый опкод, добавлять к нему значение MODE, и компли-
ровать полученный байт. Дате он будет брать операнд, находящийся на стеке, и компилировать
его в зависимости от выбранного режима адресации как байт или слово. В конце MODE бу¬
дет сброшен в значение по умолчанию. Отметим что уже определен весь код, который нужно
использовать для определения инструкций того же семейства что и ADD:
0x89 GENERAL-OP ADC,
0x84 GENERAL-OP AND,
0x85 GENERAL-OP BIT,
Сохранение памяти при использовании определяющих слов по сравнению с обучными сло¬
вами определенными через двоеточие очевидно. Все команды ассемблера, приведенные выше,
используют единственный блок кода после DOES>, вызов которого из этих слов занимает всего
несколько байт.
На самом деле это не мой код реального ассемблера 6809 - существуют дополнительные особые
случаи, которые необходимо реализовать. Но он показывает что сохраняя что достаточно сделать
чтобы сохранить информацию о режиме и как свободно использовать конструкцию CASE чтобы
реализовать наиболее простые наборы команд.
5.3.7 Реализация структур управления
Структурное программирование наделало очень много шума, и было написано множество
макропакетов "структурного ассемблирования" для распространенных ассемблеров. Но ФОВТ-
ассемблерам изначально присущи такие свойства как отсутствие меток, структурный ассемблер¬
ный код, что объяснятся той причиной что на, ФОРТ е проще реализовать структурный ассем¬
блер чем метки.
Структуры, обычно включаемые в ФОРТ-ассемблеры, аналогичны структурам высокоуровне¬
вого ФОРТ а. Для их отличия к ним добавляется запятая, как это было сделано для ассемблерных
команд.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем
81
5.3.8 BEGIN, UNTIL,
Эта самая простая для понимания ассемблерная структура. Ассемблерный код должен за-
щиклиться до метки BEGIN до того как будет удовлетворено некоторое условие. Синтаксис для
ФОРТ- ассемблера:
BEGIN, <код> <условие> UNTIL,
Код условия предположительно определен как операнд или режим адресации для интсрукции
перехода.
Очевидно, что UNTIL должен комплировать условный переход. Условия перехода должны быть
инвертированы так, что, если условие удовлетворяется, то переход игнорируется, в отличие от
перехода, когда условие ложно. Ассемблерный код для обычного ассемблера должен иметь вид:
ххх: ...
JR ~сс,ххх \ ~сс то же что и NOT(cc)
Существует два свойства, помогающие реализовать эту струткуру. Слово HERE48 возвращает
текущий указатель компиляции. Числа могут храниться на стеке не влияя на реботу ФОРТ а, и
доставаться по необходимости.
Итак BEGIN, должен запоминать позицию указателя компиляции помещая ее в стек, a UNTIL,
будет ассемблировать условный переход по запомненному на стеке адресу.
: BEGIN, ( -- а ) HERE ;
: UNTIL, ( а сс -- ) NOTCC JR, ; \ флаг перехода инвертируется
Как видно по стековой нотации BEGIN, оставляет на стеке текущий адрес, и UNTIL, ис¬
пользует запомненный адрес и код условия для компиляции условного перехода. Слово NOTCC
предварительно инвертирует код условия. Слово JR, использует адрес перехода и (инвертиро¬
ванный) код условия для формирования соответствущего кода условного перехода 6809.
Такая реализация позволяет использовать вложенные условные циклы:
BEGIN,
BEGIN,
сс UNTIL,
сс UNTIL,
Вложенный UNTIL, ссылается на вложенный BEGIN,, формпруая код цикла внутри кода
охватывающего цикла.
5.3.9 BEGIN, AGAIN,
ФОРТ также поддерживает конструкцию бесконечного цикла BEGIN AGAIN. Определение
этой конструкции для ассемблера аналогично, за тем исключением что код условия не использу¬
ется, и компилируется безуслоный переход на начало цикла.
5.3.10 DO, LOOP,
Многие процессоры предоставляют некоторые инструкции цикла. Так как их нет у 6809,
расмотрим Zilog Super8. Он имеет инструкцию DJNZ (декремент и переход если не ноль), ко¬
торая может использовать любой из 16 регистров как счетчик цикла. Для процессора 80x86 эта
инструкция работает только с регистром (Е)СХ. Цикл на структурном ассемблере будет иметь
вид:
48THERE для при целевой компиляции
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
82
5 Создание компиляторов и форт-систем
DO, ... г LOOP,
где г регистр используемый как счетчик цикла.
: DO, ( -- a) HERE ;
: LOOP, (ar--) DJNZ, ;
В некоторых ФОРТ-ассемблерах DO, также ассемблирует код инициализации счетчика цикла,
но это уменьшает гибкость.
5.3.11 IF, THEN,
Эта конструкция - простейшая конструкция, использующая ссылки вперед. Если условие
истинно, она должна выполняться, иначе управление передастся на первую инструкцию после
THEN,.
Ассемблерный код для ФОРТ-синтаксиса
сс IF, THEN,
будет иметь вид
JP ~сс,ххх
ххх:
Обратите внимание что код условия должен быть инвертирован аналогично UNTIL,.
В однопроходном ассемблере необходимый переход вперед нс может быть скомпилирован сра¬
зу, так как адрес перехода еще неизвестен. Эта проблема решается путем ассемблирования пу¬
стого перехода типа JMP 0 и помещения на стек адреса операнда команды JMP. Позже слово
THEN, сможет взять этот адрес и пропатчить скомплирированный JMP, соотвстствующм обра¬
зом модифицировав его операнд.
: IF, (сс -- а)
NOT О SWAP JP, \ условный переход
HERE 2 - \ помещаем на стек НЕИЕ-<размер операнда>
>
: THEN, (а --)
HERE SWAP ! \ запоминаем по адресу операнда JP текущий
HERE
IF, инвертирует код условия и компилирует условный переход на нулевой адрес, кладя адрес
операнда на стек. После компиляции условного перехода HERE указывает на байт после него, по¬
этом нужно вычесть размер операнда условного перехода. THEN, затем модифицирует команду
условного перехода, изменяя адрес перехода на реальный.
Приведенный вариант THEN, — самый простой вариант для процессоров, использующих ус¬
ловный переход по абсолютному 16-битному адресу. У многих процессоров есть только команда
условного перехода по относительному адресу ±127 байт от адреса команды перехода. В этом
случае размер операнда равен одному байту, a THEN, должен предварительно вычесть из HERE
адрес на стеке.
Форт © RU FIG, Понятов Д.А. <forth@km.ru > , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и фюрт-еистем
83
5.3.12 IF, ELSE, THEN,
Улучшенный вариант IF, THEN, дополняется блоком кода, выполняемом если условие не
выполняется:
сс IF, ELSE, THEN,
Ассемблерный код этой конструкции имеет вид:
JP ~сс,ххх
; код "если"
Jp УУУ
ххх: ...
; код "иначе"
УУУ:
ELSE, должен модифицировать действия IF, и THEN, следующим образом:
1 переход вперед в IF, долей быть модифицирован чтобы выполнялся переход на начало блока
ELSE, ("ххх");
2 адрес, положенный на стек THEN, должен быть записан в операнд безусловного перехода
в конце блока IF, ("JP ууу").
ELSE, также должен компилировать безусловный переход.
: ELSE (а -- а)
О Т JP,
HERE 2
SWAP
HERE
\ безусловный переход
\ поместить в стек адрес операнда перехода для THEN,
\ получить адрес перехода IF,
SWAP ! \ заменить его на текущий адрес
Условие перехода Т обозначает TRUE, то есть безусловный переход. При определении ELSE,
может быть использован код IF, и THEN, если таже определено условие F FALSE:
: ELSE (а -- a) F IF, SWAP THEN, ;
SWAP адресов в стеке инвертирует последовательность модификации инструкций перехода
так, что THEN, модифицирует переход внутри кода ELSE,:
IF,(1) ... IF,(2) THEN,(1) ... THEN,(2)
\ /
внутри ELSE,
5.3.13 BEGIN, WHILE, REPEAT,
Наиболее сложной ассемблернй структурой является цикл ПОКА, в котором условие прове¬
ряется в начале цикла, а не в конце.
BEGIN, <код> сс WHILE, <код цикла> REPEAT,
На практике между BEGIN, и WHILE, может быть вставлен любой код, а нс только задание
условия.
WHILE, должен скомпилировать условный переход по инверсному условию на код за REPE¬
AT,. Если код условия сс удовлетворяется, этот переход должен игнорироваться и выполняться
код цикла.
REPEAT, должен компилировать безусловный переход на BEGIN,.
BEGIN,(1) ... сс IF,(2) ... AGAIN,(1) THEN,(2)
Это может быть сделано с использованием существующих слов:
: WHILE, (а сс -- a a) IF, SWAP ;
: REPEAT, (а а -- ) AGAIN, THEN, ;
версия 18 марта 2006 г.
Форт © R.U FIG, Понятов Д.А. <forth<9km.ru> , public domain
84
5 Создание компиляторов и форт-систем
5.3.14 Заголовок ФОРТ-определения
В большинстве приложений машинный код, созданный ФОРТ-ассемблером, помещается в сло¬
варь с помощью CODE имя . который создает словарную статью с именем имя и связывает
ее со словарным списком.
Слово CODE получает имя слова из входного потока, создает определение в словаре с этим
именем, и настраивает указатель словаря на начало поля кода этого имени.
Стандартный ФОРТ использует слово CODE не только для выделения начала ассемблерного
определения в словаре, но и дополнительной инициализации ассемблера (установке переменных
типа MODE).
5.3.15 Кросс-компиляция
До сих пор мы предполагали что в словарь компилируется машинный код системы, на которой
и исполняется.
Для кросс-компиляции обычно выполняется компиляция в отдельную область памяти. Эта об¬
ласть может иметь или не иметь словарной структуры, но она отделена от словаря хост-машины,
и скомплированный код не может быть исполнен.
Чаще всего для этого используется набор слов для доступа к целевому пространству памяти
по аналогии с обычным доступом к памяти в Форте. Для этого могут быть использованы обычные
слова с префиксом "Т":
TDP указатель компиляции DP целевой системы
THERE аналог HERE для целевой системы
(если VALUE-переменная, TDP не нужен)
ТС,
ТС@
ТС!
Т@
Т!
Иногда вместо использования префиска "Т" эти слова определяются в отдельном словаре
целевого компилятора. Словарная структура ФОРТ а позволяет иметь несколько наборов совпа¬
дающих по имени слов с различным действием.
5.3.16 Компиляция на диск
Целевая компиляция также может выполняться сразу на диск (в файл) без использования
буфера памяти целевой системы, но из-за использования прямого побайтного доступа к файлу это
может значительно замедлить работу компилятора. Особенно это заметно если не используется
кеширование дисковых операций.
5.3.17 Безопасная компиляция
Некоторые реализации ФОРТ а используют безопасную компиляцию, которая пытяется от¬
ловить ошибки типа несбалансированных структур управления типа
IF, ... сс UNTIL,
В этом примере UNTIL, некорректно использует адрес, помещенный на стек IF,.
Обычный метод проверки сбалансированности структур управления - помещение на стек
данных пли на отдельный стек констант, уникальных для каждого управляющего слова, которые
проверяются другими словами:
IF, помещает 1;
THEN, проверяет на 1;
ELSE, проверяет на 1 и оставляет 1;
BEGIN, оставляет 2;
UNTIL, проверяет 2;
AGAIN, проверяет 2;
WHILE, проверяет 2 и оставляет 3;
Форт <с4 R.U FIG, Понятов Д.А. <forth@km.ru > , public domain
версия 18 марта 2006 г.
5 Создание компиляторов и форт-систем
85
REPEAT, оставляет 3
DO, оставляет 4;
LOOP, проверяет 4.
Стоимость такой безопасности - увеличение сложности манипуляций со стеком в таких словах
как ELSE, и WHILE,. ТАкже программист может захотеть последовательность в которой управ¬
ляющие структуры are resolved вручную манипулируя стеком. Безопасность делает это более
сложным.
5.3.18 Метки
Даже в эру структурного программирования некоторые программисты используют метки в
ассемблерном коде.
Принципиальная проблема с именоваными метками в ФОРТ-ассемблере - так как метки это
ФОРТ-слова, они должны быть скомпилированы в словарь во время незавершенной компиляции
другого слова в машинном коде, например:
CODE TEST ... <машиннный код>
HERE CONSTANT LABEL1
<машинный код>
LABEL1 NZ JP,
Как видно из примера определение метки LABEL 1 должно создавать словарную статью вну¬
три серидины CODE. Вот несколько решений 1 метки определяются только вне машинного кода. 2
используются некие предопределенные переменные для временного хранения меток. 3 для меток
используется отдельное словарное пространство, например как это сделано по схеме TRANSIENT
0'3
. 4 для машинного кода используется отдельное пространство словаря. Это наиболее часто исполь¬
зуемый метод при мета-компиляции. Большинство мета-компиляторов ФОРТ а поддерживают
метки с некоторыми сложностями.
5.3.19 Табличный ассемблер
Большинство ФОРТ-ассемблеров могут отрабатывать режимы адресации и инструкции ис¬
пользуя структуры типа CASE. Их можно назвать процедурными ассемблерами.
Некоторые процессоры типа 68000 имеют настолько сложные наборы инструкций и режимов
адресации, что становится сложным строить деревья выбора при ассемблеировании их команд. В
таких случаях более подходящим является использование таблиц, что уменьшает используемую
память и процессорное время.
Я не буду описывать такие процессоры - табличные ассемблеры писать намного сложнее49.
5.3.20 Префиксные ассемблеры
Иногда использование префиксных ассемблеров необходимо. Например мне однажды при¬
шлось переводить многие килобайты ассемблерного кода для Super8 для обычного ZilogOBCKoro
ассемблера для ФОРТ-ассемблера. Существует трюк позволяющий имитировать префиксный ас¬
семблер при использовании методов, описанных в этой статье.
В основном этот трюк можно определить как отложенное выполнение ассемблирования после
того как были обработаны операнды. Это делается следующим словом ассемблера.
Так каждое слово ассемблера модифицируется так что оно
1 сохраняет свой код или адрес кода, компилирующего команду;
2 выполняет компилирующий команду код для предыдущего слова ассемблера.
... JP operand ADD operands
49пример такого ассемблера приведен в следующем разделе
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
86
6 Реализация ООП
JP сохраняет указатель на свой код в какой-либо переменной. Далее обрабатываются опе¬
ранды. ADD берет информацию, запомненную JP и выполняет действие JP, которое использует
операнды на стеке. Когда код JP завершается, ADD сохраняет свой адрес, и процесс продолжа¬
ется.
Особо должны отрабатываться первые и последние команды в ассемблерном блоке. Если
используются переменные режима, то их сохранение и восстановление станоится кошмаром.
5.3.21 Вывод
Я рассмотрел наиболее простые методики используемые в ФОРТ-ассемблерах. Изучение го¬
тового ассемблера может дать вам информацию как писать собственный ассемблер, но лучший
способ изучения - действие.
5.4 Постфиксный форт-ассемблер для MCS-51
5.5 Реализация собственной форт-системы
6 Реализация ООП
6.1 Детальное описание mini-OOF
© Bernd Paysan
Объектно-ориентированные (00) системы с поздним связыванием обычно используют метод
VTABLE: первая переменная00 в каждом объекте01 является указателем на описание класса в
виде таблицы указателей на функции* 51 52 53. Эта VTABLE может также содержать некоторую другую
информацию, например статические переменные.
Объект
vtable-ptr
переменная
переменная
число переменных
число методов
xt метода
Во-первых, определим методы:
: method ( m v -- m+1 v )
CREATE
OVER , SWAP CELL+ SWAP
DOES> ( ... о --- .... )
© OVER © + © EXECUTE
При декларации метода co стека берется общее число методов и переменных класса, method
создает один метод и увеличивает на 1 число методов. Для исполнения метода берется объект,
из него получается указатель на VTABLE, добавляется смещение, и выполняется xtoJ метода,
который находится по полученному адресу. Каждый метод определяет объект, для которого он
вызывается, по адресу на стеке — указателю this. Метод должен работать с объектом самостоя¬
тельно и удалять this со стека перед выходом из метода.
Теперь мы должны определить переменные класса
: var ( m v size -- m v+1 )
CREATE
OVER , +
DOES> ( о -- addr )
© +
поле
51
экзмемпляре класса
52 методы класса
53 execution token, обычно адрес поля кода CFA слова
Форт ©) RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
6 Реализация ООП
87
так ка, как и method, слово создается с текущим смещением. Переменные могут иметь раз¬
личные размеры04, так что все что мы делаем — берем размер и добавляем его к смещению. Ес¬
ли ваша машина имеет требования по выравниванию00, перед переменной добавляем требуемые
выравнивающие байты словами ALIGNED или FALIGNED, также корректирующими смещение
переменной. Именно по этой причине смещение находится на вершине стека.
Для начала определения объекта нам нужно задать начальное состояние06 и выполнить неко¬
торые дополнительные действия:
CREATE object 1 CELLS , 2 CELLS ,
: class ( class -- class methods vers )
DUP 20
3
Для наследования при декларации нового наследуемого07 класса должна быть скопирова¬
на VTABLE родительского объекта. Это копирование даст все методы родительского объекта,
которые далее могут быть переопределены.
: end-class ( class methods vars -- )
CREATE
HERE >R
\ (1)
( vars ) , ( methods ) , DUP ,
( methods ) 2 CELLS ?D0
[’] NOOP ,
1 CELLS +LOOP
\ (2)
CELL+ DUP CELL+ R> ( here ) ROT @ 2 CELLS /STRING MOVE
3
(1) создает VTABLE, инициализированную ХООРами:
(2) реализует механизм наследования — из родительской VTABLE копируются xt методов.
У нас все еще нет способа определения новых методов, поэтому определим слово
: defines ( xt class -- )
’ >BODY 0 + !
3
Для выделения памяти под новый объект нам также нужно слово
: new ( class -- о )
HERE OVER ® ALLOT SWAP OVER !
3
Многда дочерние классы требуют доступа к методам родительского класса. Существует два
способа сделать это в этом варианте реализации OOF: вы можете
1. использовать именованные слова;
2. использовать их xt из VTABLE родительского класса.
: :: ( class "name" -- )
’ >BODY 0 + 0 COMPILE,
целые, числа с плавающей точкой одинарной и двойной точности. символы и т.п.
например па границу машинного слова
пустой объект
дочернего
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
88
9 Операционная система OS
Пример Ничто не может быть лучше чем хороший пример, так что вот он. Для начала опре¬
делим текстовый объект (налес называемый button), который хранит текст и позицию:
object class
cell var text
veil var len
cell var x
cell var у
method init
method draw
end-class button
Теперь реализуем два метода:
:NONAME ( о ) >R R@ х © R© у © AT-XY R@ text © R> len © TYPE ;
button defines draw
:N0NAME ( addr u о ) >R 0 R@ x ! 0 R@ y! R@ len ! R> text ! ;
button defines init
В качестве примера наследования определим класс bold-button без новых переменных и ме¬
тодов
button class
end-class bold-button
: bold 27 EMIT ." [Im" ;
: normal 27 EMIT ." [Om" ;
:NONAME bold [ button :: draw ] normal ;
bold-button defines draw
II наконец некоторый код, демонстрирующий создание объектов и применение методов:
button new CONSTANT foo
s" thin foo" foo init
foo draw
bold-button new CONSTANT bar
s" fat bar" bar init
bar draw
7 Плавающая точка
8 Сетевые протоколы
9 Операционная система os
Этот раздел книги является документацией к проекту [os]. Документация исключена из про¬
екта, чтобы нс делать двойную работу, дублируя одни и те же темы в документации проекта и
книге. Кроме того, как раз [os] является хорошим подробным примером использования Форта и
практически не описанного в литературе метода целевой компиляции.
Форт © RU FIG, Понятов Д.А. <forthOkm.ru> , public domain
версия 18 марта 2006 г.
9 Операционная система OS
89
9.1 О системе
В последние несколько лет производительность компьютеров настолько возрасла, что появил¬
ся интерес к реализациям языков программирования, использующих интерпретацию. Самый рас¬
пространенный подход при реализации таких систем программирования — компиляция программ
с одного или нескольких ЯВУ в более или менее низкоуровневый промежуточный код, который
затем интерпретируется при работе программ в run-time.
Вид такого промежуточного кода может отличаться системой команд и возможностями вир¬
туальной машины (ВМ), их кодированием, но чаще всего такой код называется байт-кодом.
Соответственно интерпретатор байт-кода, называют также виртуальной машиной (ВМ), движ¬
ком или (интерпретирующим) ядром.
Для ускорения работы интерпретатора часто58 59 используются методы частичной компиляции
байт-кода в нативный*9 машинный код реального компьютера.
У меня еще с институтских времен была мечта написать свою операционную систему на
Форте, но обдумав требования к такой системе я остановился на варианте интерпретатора байт¬
кода, который может работать на всех платформах и ОС, которые я использую (Windows, Linux
и DOS на i386 ПК, наладонник Palm Шхе, мобильный телефон с виртуальной машиной Java).
Кроме того, я планирую заняться встраиваемыми системами на 8-битных микроконтроллерах, и
есть вариант использовать чисто интерпретируемый вариант Форта для части кода, который не
требует высокой скорости работы.
В течение нескольких месяцев экспериментов и была создана [os]: ОС для встраиваемых си¬
стем, построенная на основе виртуальной стековой машины, система команд которой оптимизи¬
рована под язык программирования Форт.
Текущий вариант os искуственно сделан 16-битным, чтобы программы для нее могли работать
на самодельных специализированных маломощных управляющих компьютерах. Кроме того, это
одновременно является экспериментом — даст ли использование языка Форт ту компактность
программ, о которой часто говорят фортеры.
Использование интерпретирующего движка имеет несколько важных достоинств:
• крайне высокая переносимость между разными компьютерами и ОС — ядро системы (ин¬
терпретатор байт-кода) переписывается под любую хост-систему всего за несколько часов;
• ядро может быть легко написано на любом языке программирования или ассемблере;
• ядро элементарно встраивается внутрь любых других программ, что позволяет добавить
в программы программирование пользователем — в систему команд ВМ добавляются ко¬
манды для взаимодействия с программной ("ручки"), а пользователь может писать свои
скрипты и расширения и компилировать их в байт-код;
• еще один вариант (пока нереализованный) — вместо двухступенчатого процесса компиляции
пользовательских скриптов в байт-код и их последующего выполнения внутри основной
программы на встроенном интерпретаторе использовать форт-систему в байт-кодс; в этом
случае пользовательские скрипты на Форте будут загружаться непосредственно в текстовом
виде без предварительной компиляции в байт-код;
• программы, скомпилированные в байт-код, выполняются без перекомпиляции (правильно
написанные программы) или с минимальной настроечной модификацией исходного кода
под конкретную хост-систему или требования пользователя;
• неограниченные возможности отладки — отладочный код добавляется в исходный код ядра
или в целевой компилятор;
• за счет чистой интерпретации возможно использовать любые типы многозадачности, защи¬
ты данных, контроля работы программ в процессе выполнения.
Вообще использование интерпретации одинакового для всех хост-систем байт-кода позволяет
применять методики, не работающие для традиционной компиляции в машинный код
58 особенно в тяжелых коммерческих языковых системах типа Java или .NET
59 , ■
native
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
90
9 Операционная система, OS
• самомодификация программ;
• использование метаданных об исходном коде программ, также скомпилированных в байт-
код60;
• разнообразные виды многозадачности с защитой задач друг от друга, в том числе и на хост-
системах, не поддерживающих ее аппаратно, типа 8086 и 8-битных микроконтроллеров;
• ресурсы хост-системы (файловая система, сетевые функции, память, устройства ввода/вы-
вода и т.д.) либо ввобще недоступны для программ в байт-коде, либо доступ обеспечива¬
ется с помощью специализированных команд виртуальной машины, поэтому программы
выполняются в изолированной среде и не имеют возможности повлиять на работу других
программ и системы, а интерпретатор при этом может отслеживать и ограничивать исполь¬
зование всех ресурсов в процессе выполнения программ;
• полная независимость формата байт-кода от платформы и его изолированность позволяет
выполнять программы на гетерогенных распределенных сетях, состоящих из разнотипных
компьютеров, соединенных между собой любым способом — можно повысить надежность
программно-аппаратных систем, повысить эффективность их использования и масштаби¬
руемость за счет распределения нагрузки.
Основное средство разработки — ассемблер стековой машины (целевой компилятор, ЦК),
написанный в видее расширения форт-системы SP-FORTH61. Система команд стековой машины
естественно заточена под Форт.
К сожалению пока (?) не нашлось компиляторщика, способного и желающего написать для
os компиляцию в байт-код с других языков программирования, особенно С'++. С другой строны,
если будет написан компилятор С*++, в сообщество хакеров-разработчиков os набежится ламерье
и любители высокоуровневых языковых примочек типа ООП, динамических структур данных и
сборщиков мусора, и получится еще одна Java.
При необходимости вы можете написать собственную версию целевого компилятора, который
будет вместо байт-кода генерировать настоящий машинный код целевой платформы, при условии
что ваши программы не работают напрямую с байт-кодом и словарем.
Это условие не выполняется для самомодифицирующихся программ, в том числе и для ин¬
терактивной форт-системы, которая в дальнейшем возможно кем-то будет написана. Если напи¬
сать такую форт-систему, она совместит в себе интерфейс командной строки, монитор, средство
on-board разработки, загрузчик конфигурационных файлов (если движок их поддерживает) и
скриптов и т.д..
В процессе развития системы она естественно будет постепенно распухать, но я надеюсь все
же сохранить ее простоту за счет многослойности.
Самый лучший способ освоения os — полностью написать с нуля ее клон, сохранив совмести¬
мость.
Для движка желательно использовать один или несколько языков программирования и биб¬
лиотек, которые вам больше всего нравятся или лучше подходят для решаемых задач. В рос¬
сийских ВУЗах особенно популярен в этом плане Pascal, ну и конечно найдется масса народа,
желающего написать движок на ассемблере.
Еще один кандидат на переписывание - целевой компилятор, так как он заточен на регистро¬
зависимый SP-FORTH, и не будет работать на большинстве форт-систем, не различающих слова
dup и DUP. Кроме того, в новом стандарте появился раздел по целевой компиляции, а ЦК в
дистрибутиве os ему совершенно не соответствует.
Собственно говоря os — это специфическая методика программирования на Форте с исполь¬
зованием целевой компиляции в байт-код и интерпретации, и по большей части написана как
иллюстрация этой методики. То, что эта методика оказывается более эффективной, чем тради¬
ционное программирование на Форте с раскруткой системы от уровня машинного кода, просто
60 см. reflection в Java и пример использования cmdline.4th в дистрибутиве [os] (поиск по словарю)
61 http://spf.sf.net
Форт бсб R.U FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
9 Операционная система OS
91
побочный эффект. Жаль только, что мне не попалось хорошего описания целевой компиляции
типа статьи Brad Rodriguez лет этак 10 назад.
Будущее покажет, но если вдруг методика os окажется популярной, нам опять придется ре¬
шать основную Вавилонскую проблему языка Форт — расползание на десятки частично несов¬
местимых диалектов Форта, появление программ, зависимых от особенностей конкретных форт-
систем, и самое главное проблемы понимания кодов чужих программ из-за языкового перенасы¬
щения (см. ??).
9.2 Многослойная структура
Система имеет многослойную архитектуру:
9.2.1 Аппаратная платформа и ОС
Текущий вариант дистрибутива работает только в гостевом режиме поверх DOS на ПК с
процессорами 80x86.
DOS дает ощущение встраиваемой системы — низкая разрядность62), прямой доступ к желе¬
зу63, отсутствие многих библиотек64.
os разрабатывалась как гостевая ОС, работающая поверх хост-ОС, но никто не запрещает
взять в руки ассемблер и/или компилятор С++ и линкер, способный генерировать бинарный
файл с машинным кодом, и написать движок os, который будет загружаться как stand-alone ОС
и работать напрямую с железом. Правда при этом вам придется вложить в это чудо несколько
человеко-лет кодинга, чтобы написать драйвера, сетевые протоколы, библиотеки программ и т.д..
Если вы хотите работать в привычной среде, но при этом экспериментировать с системным
программированием, есть более простой вариант — напишите ВМ, которая будет эмулировать
низкоуровневый доступ к устройствам, и пишите свою ОС на Форте.
9.2.2 Виртуальная машина (интерпретатор байт-кода)
Написан на С++ с использованием левого нелицензионного компилятора Borland C++ 3.1.
Распространяется в исходных текстах в качестве примера для написания вашего собственного
интерпретатора байт-кода на любом языке или ассемблере, очень желательно без нарушений
лицензионности.
9.2.3 Целевой компилятор
Принципы целевой компиляции и подробное описание 16-битного ЦК для os подробно описано
в разделе 5.2.
9.2.4 Библиотеки
9.2.5 Пользовательские расширения и прикладные программы
9.3 Архитектура ВМ
9.3.1 Память
9.3.2 Стек возвратов
9.3.3 Стек данных
9.3.4 Регистры
9.3.5 Стек циклов со счетчиком
9.4 Система команд
os использует подпрограммный шитый код, причем используются не машинные команды,
выполняемые аппаратно, а команды виртуальной машины (байт-код). Эта технология также ис¬
е2 16 бит
видео, контроллеры периферии
64 сеть, базы данных, GUI
версия 18 марта 2006 г.
Форт © RU FIG, Понятов Д.А. <forth@km.ru> , public domain
92
10 Заключение
пользуется некоторыми форт-спстемамп, и называется tokenized threaded code (ТТС) или switched
threaded code.
Набор команд и архитектура ВМ оптимизирована для языка Форт, в частности все коман¬
ды выполняют действия, аналогичные небольшому набору слов из CORE WORDSET стандарта
языка.
9.4.1 Базовые команды
Управление выполеннием программы
Память
Стек
Целочисленная арифметика
Логика и битовые операции
9.4.2 Графический драйвер monoLCD
9.5 Библиотеки
9.5.1 Библиотека макросов
9.5.2 2D полноэкранная графика
9.6 Примеры программ
9.6.1 empty
9.6.2 blinker
9.6.3 liner
9.6.4 grdemo
9.6.5 pautov
9.6.6 cmdline
10 Заключение
Работа над книгой ведется постоянно, поэтому та версия, которую вы сейчас читаете, может
оказаться не самой свежей.
Последнюю версию этой книги и другие материалы по Форту и разработке железа вы можете
скачать с [akps].
10.1 Констактные адреса
Пожалуйста, направляйте ваши замечания и предложения:
Dmitry Ponyatov <forth@km.ru>
FidoNet: 2:5057/18.29 или в конференцию SU.FORTH
Лучше всего если вы присоединитель к работе над книгой и другими материалами сайта — это
могут быть как ваши письма с описанием различных методик, исходными текстами программ и
т.д., так и полноценная on-line работа над материалами используя доступ с использованием CVS
(см. http://www.cvs.ru).
Форт (с) RU FIG, Понятов Д.А. <forth<9km.ru> , public domain
версия 18 марта 2006 г.
Ю Заключение
93
10.2 Необходимый софт
• Любая Форт-система для вашей ОС. Примеры приведены для форт-систем, соответству¬
ющих стандартам FORTH-83 и ANS FORTH ’94. Для Win я использую SP-FORTH. См.
подробный список форт-систем. В книгу планируется включить разделы, посвященные ис¬
пользованию нескольких самых распространенных форт-систем (в смысле использования
специфичных для каждой системы возможностей).
• Реальное железо или эмуляторы не-80х86 платформ (Palm, ZX Spectrum, средства разработ¬
ки для встраиваемых систем на микроконтроллерах или нс-80х86 процессорах611, симулятор
VHDL).
• Компилятор С(++), ассемблер, компилятор или языковая среда для вашего любимого язы¬
ка - для написания интерпретирующего движка FVM и т.п. Для DOS-движка я использую
Borland C++ 3.1. Из скриптовых языков очень рекомендую Python.
• Клиент для CVS-сервера, если хотите участвовать в реадктировании книги или другого
раздела сайта. Для win качайте cvsnt/WinCVS пли evs-sfx .
• Редактор, способный работать с текстами в кодировках DOS ср866, win-1251 и koi8-r — я
пользуюсь средой DOS Navigator и редактором vim.
10.3 Необходмые навыки
• Для работы над текстом книги — владение издательской системой 1+1] уХ, желательно под
любым UNIXom (Linux, *BSD).
• Для работы над кодом — владение С(++), стандартным FORTH и (или) диалектом FVM.
e°AVR, MCS-51, PIC, и т.п.
версия 18 марта 2006 г.
Форт (с) RU FIG, Понятов Д.А. <forth©km.ru> , public domain
94
Список литературы
Список литературы
[os]
16-битная OS для встраиваемых систем
система построена на базе интерпретатора байт-кода
архитектура виртуальной машины и система команд взяты из Форта
http://akps.ssau.ru/forth/os/
[rufig]
сайт, группы RU FIG (Russian FORTH Interests Group)
http://www.forth.org.ru
[akps]
сайт Лаборатории аэрокосмического приборостроения (АКПС) СГАУ
http://akps.ssau.ru
[orange]
М. Келли, Н.Спайс
Язык программирования ФОРТ
Перевод с английского Е. В. Куркова, Ю. А. Семенова
Москва, "Радио и связь", 1993
http://akps.ssau.ru/forth/orange/
[green]
С.Н. Баранов, Н.Р. Ноздрунов
Язык Форт и его реализации
Лениград, "Машиностроение" Ленинградское отделение, 1988
http: //a kps.ssa u. ru/forth/green /
[starting]
Лео Броуди
Начальный курс программирования на языке Форт
Перевод с английского В.А. Кондратенко
Под редакцией Б.А. Кацова, В.А. Кириллина
Предисловие И.В. Романовского
Москва, "Финансы и статистика", 1990
[thinking]
Лео Броуди
Способ мышления — Форт. Язык и философия для решения задач
Перевод с английского С.Н. Дмитренко
Москва, 1993
http://akps.ssau.ru/forth/thinking/
[ans]
American National Standard for Information Systems
Programming Languages
Forth
Computer and Business Equipment Manufacturers Association
Approved: March 24, 1994
American National Standards Institute, Inc.
© 1994 by Technical Committee X3J14 HTML
оригинал http://akps.ssau.ru/forth/ans/en/DPANS.HTM
перевод http://akps.ssau.ru/forth/ans/ru/DPANS.HTM
Форт (cj RU FIG, Понятов Д.А. <forth©km.ru> , public domain
версия 18 марта 2006 г.