Язык Форт и его реализации

         

Локальные переменные


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

Для упрощения работы желательно закрепить за локальным объектами внутри определения некоторые постоянные имена, через которые и осуществлять доступ к ним.

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

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

Простейшая надстройка над языком Форт, которая позволяет работать с локальными переменными, выглядит так:

100 ALLOT HERE CONSTANT LP0 ( НАЧАЛО ЛОК. СТЕКА) VARIABLE LP ( ТЕКУЩАЯ ВЕРШИНА ЛОКАЛЬНОГО СТЕКА) : INIT ( ->) LP0 LP ! ; INIT : LOC ( N:СЧЕТЧИК->) 1+ 2* LP @ OVER - DUP LP ! ! ; : UNLOC ( ->) LP @ @ LP +! ; : @@ ( N:СМЕЩ->) CREATE , DOES> ( PFA->A) @ LP @ + @ ; : !! ( N:СМЕЩ->) CREATE , DOES> ( A,PFA->) @ LP @ + ! ; 2 @@ @1 4 @@ @2 6 @@ @3 8 @@ @4 10 @@ @5 ( И Т.Д.) 2 !! !1 4 !! !2 6 !! !3 8 !! !4 10 !! !5 ( И Т.Д.)

Вначале отводится область объемом 100 байт и адрес ее конца запоминается как константа LP0. Эта область будет использоваться как локальный стек, растущий в сторону убывания адресов. Переменная LP хранит указатель на текущую вершину локального стека, ее инициализацию выполняет слово INIT, которое присваивает ей значение LP0.
Слово LOC резервирует в этом стеке память на N двухбайтных значений, дополнительно отводя еще одну ячейку, в которую засылает значение N — длину всей области. Обратное действие — освобождение памяти — выполняет слово UNLOC, которое использует сохраненное значение N. Слова @@ и !! являются определяющими для двух рядов слов, выполняющих разыменование локальных объектов и присваивание им нового значения. Каждый локальный объект в пределах одного определения идентифицируется своим номером, который включен в имя операций разыменования и присваивания для работы с ним. В качестве примера рассмотрим определение слова 5INV, переставляющего 5 верхних элементов стека данных в обратном порядке:

: 5INV ( A,B,C,D,E -> E,D,C,B,A) 5 LOC !1 !2 !3 !4 !5 @1 @2 @3 @4 @5 UNLOC ;

Приведенная реализация локальных переменных предельно упрощена. Ее очевидным усовершенствованием является, например, введение контроля за переполнением и исчерпанием локального стека и включение действий LOC и UNLOC в семантику входа в высокоуровневое определение и выхода из него; при этом подсчет числа локальных объектов может выполняться автоматически, аналогично определению адреса перехода в структурах управления.

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

Введение локальных переменных не только упрощает программирование, освобождая программиста от необходимости тщательно отслеживать все изменения на стеке, но и сокращает размер скомпилированной программы, поскольку из нее исчезают сложные последовательности из слов OVER, DUP, ROT, PICK и других, обычно используемых для доступа к локальным значениям.Такое неожиданное сочетание приятного с полезным — одна из многих удивительных сторон языка Форт, которые открываются программисту при знакомстве с ним.


Содержание раздела