Информация

Сайт в стадии реконструкции. Пользуйтесь форумами.

Принципы Форта

Атомы Форта

В Форте с точки зрения программирования нет деления на процедуры, функции, переменные, константы и т.п. - всё это называется "словами". Слова обычно выполняются строго одно за другим, забегания вперёд "по тексту" нет практически никогда.

Форт-система может находиться в двух основных состояниях:

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

Стек

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

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

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

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

Стеки в Форте

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

В Форте также есть второй стек - стек данных. Он является основным средством обмена данными между словами. Каждое слово что-то берёт со стека (исходные данные) и что-то на него помещает (результаты). В отличие от большинства классических ЯВУ, слово может возвращать более одного объекта в результате.

Примеры работы со словами

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

Перейдём к практике. Для тестов можно использовать, например, вот этот простенький интерпретатор на Java (апплет):

В нижней строчке пишем выражение, жмём Enter, оно выполняется. Интерпретатор чрезвычайно простенький и бедный, но оценить основные принципы можно.

Начнём с простого. Напишем "

2 2 * .

". В результате получим "4". Когда транслятор встретит первую двойку, он распознает её как число и поместит в стек. Аналогично поступит и со второй двойкой. В стеке окажется уже две двойки. Увидев слово "*" он исполнит его. Это слово берёт (снимает) со стека два числа, перемножает их и помещает результат в стек. Вместо исходных двух чисел там окажется одно, являющееся их произведением. Слово "." (точка) снимает со стека число и выводит его на экран. После этого стек остаётся пуст.

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

Чуть более сложный пример: "

5 4 3 * +

". Сперва на стек будут помещены 5, 4 и 3. На вершине стека будет тройка, а в самой глубине - первая занесённая пятёрка. Слово умножения снимет верхние два числа (4 и 3), перемножит и поместит 12 в стек. Слово сложения снимет имеющиеся в стеке 5 и 12, сложит и поместит туда 17. Можно оставить его для следующих вычислений, можно напечатать "точкой".

Слова работы со стеком

Поскольку стек штука в Форте чрезвычайно интенсивно используемая, то и нужно уметь оперировать объектами, в нём хранящимися. Для этого служит целая куча разных слов, некоторые из которых мы тут и рассмотрим. * DUP - дублирует число в стеке. Часто слово снимает со стека значение, а оно нам нужно будет когда-то дальше. Можно сделать его копию. Тогда исполняемое слово снимет только копию, оставив в стеке ещё один экземпляр. Например, в стеке лежат числа "1 2 3". После выполнения слова "DUP", там будут лежать "1 2 3 3". Т.е. последняя (на вершине стека) тройка продублируется * SWAP - меняет местами два верхних числа. Из "1 2 3" получится "1 3 2". Нужно обычно когда требуется взять число, лежащее за вершиной. * DROP - просто удаляет верхнее число. Например, когда оно нам не нужно. Из "1 2 3" получится "1 2". * OVER - более сложное число. Чем-то похоже на DUP, но на вершину стека помещается не копия текущей вершины, а число, лежащее под ним. Из "1 2 3" получится "1 2 3 2". Используется, когда нужно вытащить именно копию второго числа со стека.

Пример: "7 8 + 45 SWAP /". Семь. Восемь прибавить. 45 на полученное разделить. Результат - 3. Слово деления делит более старое число в стеке на число на вершине ("30 10 / ." -> "3"), но у нас перед делением оказываются сперва 15, потом 45, а нужно наоборот. Пользуемся словом SWAP, чтобы их поменять.

Создание новых слов

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

Определение нового слова производится так. Сперва пишется "двоеточие" (":") (самостоятельное слово, поэтому, как обычно, должно быть отделено от других), после него идёт имя нового слова. Потом - текст этого слова. Завершается описание словом "точка с запятой" (";"). Пример:

: SQUARE  DUP * ;

Слово возведения числа в стеке в квадрат. Теперь, каждый раз, когда мы напишем SQUARE, реально исполнится последовательность "DUP *".

5 SQUARE . -> 25