Работа с переменными, константами и массивами реализуется с помощью следующих слов:
@ ( word index --> value ) (взятие значения элемента с индексом index из списка переменных слова с кодом word и размещение его в стеке)
! ( value word_num index --> ) ( помещение value из стека в элемент с индексом index из списка переменных слова с кодом word)
COUNT (word_num index --> count ) (Количество элементов в списке переменных слова word_num, начиная с index, если index = 0, то полное количество элементов)
, ( константа --> ) (, - запятая выбирает константу из стека и добавляет ее в список переменных последнего определенного слова)
VARIABLE ( --> ) ( DOES> --> word_num 0 ) ( определение переменной )
CONSTANT ( value --> ) ( DOES> --> value ) (определение константы)
ARRAY ( num_elements --> ) ( DOES> index --> word_num index ) (определение массива)
ALLOT (count --> ) ( Увеличивает количество элементов списка переменных последнего определенного слова на count элементов )
Здесь запись вида ARRAY( num_elements --> ) ( DOES> index --> word_num index ) означает следующее: во время выполнения слова ARRAY в стеке должно находиться количество элементов. Верхний элемент стека снимается. Это слово - определяющее. Определенное ARRAY слово при выполнении должно получать на стеке индекс требуемого элемента массива, после выполнения на стеке оказываются номер слова и индекс элемента. С помощью этой пары и слова "@" можно выбрать значение элемента массива на стек, так же как со словом VARIABLE.
Определение переменной:
VARIABLE наименование_слова_переменной
Сохранение из стека в переменную:
слово_переменная !
Разыменование переменной, то есть вытаскивание значения из переменной в стек:
слово_переменная @
Слово VARIABLE определено в модуле "system.sf". Делает оно следуещее: определяется новое слово с именем, следующим за VARIABLE, в список переменных этого слова добавляется 0 (см. далее); в качестве действия ему полагается во время выполнения сделать следующее: положить в стек собственный номер слова и значение 0.
Слово @ берет из стека эту пару, обращается к слову с этим номером и из списка переменных выбирает значение элемента с индексом 0 и ложит на стек.
Слово ! также берет из стека эту пару, обращается к слову с этим номером, выбирает элемент списка переменных с индексом 0 и присваивает ему значение, взятое из стека и лежащее глубже (третьим сверху).
То есть слова @ и ! почти всегда используется совместно со словом-переменной, определенной VARIABLE. Переменная может быть любого типа. Определяется каждый раз в зависимости от того, какой тип имеет сохраняемое значение, и во время работы может меняться.
Пример работы с переменными:
"system.sf" REQUIRE
"utils.sf" REQUIRE
"Определение переменной" .
VARIABLE v
: VARIABLE_test
"Начальное значение переменной" .
v @
ITERATE_STACK_PRINT
"Присвоение значения из стека переменной" .
14 v !
ITERATE_STACK_PRINT
"Разыменование переменной" .
v @
ITERATE_STACK_PRINT
;
VARIABLE_test
Результат работы:
Начальное значение переменной
0
Присвоение значения из стека переменной
Разыменование переменной
14
Execute Ok!
Замечание: для каждого слова, определенного в словаре, имеется список команд. Он определяется словами ":" и ";". Также для каждого слова определен список переменных. Слово VARIABLE, определенное в "system.sf" добавляет в список переменных слова один элемент, к которому и можно обратиться, зная код слова и смещение элемента в списке переменных. Стандарный Форт предусматривает, что и память под коды команд в слове, и памятьть под переменные выделяется и используется одна и та же. Поэтому собственно, Форт и может оперировать только целыми однобайтовыми числами (точнее говоря, работа с типами плавающей точки и пр. возможна, но требует дополнительного программирования). Решая задачу расширения Форта для работы различными типами данных, я решил разделить списки кодов команд и список переменных. Также поэтому в стандартном Форте присутсвуют слова работу с двойными словами, которые не реализованы в данной версии ввиду ненужности.
Поэтому слова работы с переменными, константами и массивами отличаются по действию от тех же слов стандартного Форта.
Слово VARIABLE использует определяющее слово CREATE. Что такое определяющие слова, что делает в частности CREATE и как их использовать, см. далее.
Определение константы:
размещение_значения_в_стеке CONSTANT наименование_слова_константы
Слово VARIABLE определено в модуле "system.sf".
Используется следующим образом. Введите код:
"system.sf" REQUIRE
"utils.sf" REQUIRE
220 CONSTANT VOLTS
10 VOLTS *
"Мощность тока в 10 А = (W)" . .
Результат работы:
Мощность тока в 10 А = (W)
2200
Execute Ok!
Как видно, можно проводить произвольные вычисления с использованием ранее определенных переменных, констант и слов. Результат должен быть положен в стек и будет использован при определении константы.
Константы с помощью слова CONSTANT следует определять в модуле, не в определении слов, т.е. глобально. Константы видны во всех словах, определяемых позднее, чем константа. Как это работает, см. в модуле "CONSTANT_test.sf". Повторное определение константы с тем же именем вызовет ошибку.
Определение массива
размещение_количества_элементов_на_стеке ARRAY имя_массива
Доступ к элементу массива:
размещение_индекса_на_стеке имя_массива @
Помещение значения в элемент массива:
размещение_значения_на_стеке размещение_индекса_на_стеке имя_массива !
Пример работы с массивом (с одиночными элементами):
5 CONSTANT NUM_ELEMENTS
NUM_ELEMENTS ARRAY CLAPAN
6 3 CLAPAN !
0 CLAPAN @ .
3 CLAPAN @ .
3 CLAPAN @ 4 + 3 CLAPAN !
3 CLAPAN @ . ITERATE_STACK_PRINT
Результат работы:
6
10
Execute Ok!
Слово ARRAY определено в модуле "system.sf" с помощью определяющих слов.
Слово-потомок ARRAY берет на стеке индекс, ложит на стек свой номер и затем - индекс. В результате на стеке лежит пара номер-индекс, с которым в дальнейшем можно работать.
С помощью слова ALLOT можно увеличить список переменных последнего определенного слова на некоторое количество элементов. Словом "запятая" можно занести один или несколько значений со стека в список переменных последнего определенного слова. В качестве примера см. реализацию алгоритма сортировки пузырьком.
Чтобы иметь возможность работать с произвольными структурами данных, например структурами в понимании Delpi и С++, многомерными массивами, необходимо изучить главу "Определяющие слова".
В принципе, можно уже программировать множество алгоритмов на уже определенном ранее инструментарии. Однако наибольшую мощь Forth проявляет как раз при использовании определяющих слов. Идеологии определяющих слов другие языки не имеют, либо имеют крайне усеченно и однобоко. Вышеприведенные слова - CONSTANT, VARIABLE, ARRAY не зашиты жестко в код форт-машины, они определены в модуле "system.sf" с помощью определяющих слов CREATE и пр. Ничто не мешает Вам самим определять произвольны слова работы с произвольными структурами данных. Структуры, массивы, классы, "живые данные" - все это можно определить самим и сделать их мощнее, чем в других жестких языках.
Единственное пока ограничение - все данные глобальны. Но это временно. Мы работаем над этим.
Системные слова ! и @ могут рабоать с любыми словами, которые вы укажете в стеке (см. нотацию для них). Однако, если вы зададите index для этого слова, выходящий за пределы списка переменных слова word_num (или список переменных у слова word_num будет пустой), то возникнет ошибка и выполнение скрипта прервется. Отвественность за правильность применения этих слов лежит на программисте.
Никто не мешает определить слова для работы с переменной v вроде этих: v! и v@.
Следует хорошо понимать, что константы и переменные, определяемые с помощью слов CONSTANT, VARIABLE, ARRAY - просто слова, так же как сами CONSTANT, VARIABLE, ARRAY являются словами, определенными в модуле "system.sf".
Переменные, константы, массивы и прочие структуры данных, определенных с помощью определяющих слов следует определять в модуле, не в определении слова, т.е. глобально. Форт не предусматривает области видимости переменных. Все переменные глобальные, видны во всех определенных позднее слов. Локальных переменных нет. Освобождения памяти нет (по крайней мере пока я не сделал). Для работы с локальными данными предназначен стек. Повторное определение переменной с тем же именем, вызовет ошибку.