Работа с переменными, константами и массивами

Активная работа с nnCron зачастую требует хранения различных значений в течение продолжительного времени. Для этого используются переменные, константы и массивы. nnCron предоставляет пользователям все средства работы с переменными, константами и массивами, которыми обладает язык программирования Форт (SP-Forth) и добавляет несколько собственных удобных инструментов.



Переменные

Переменные для хранения числовых значений создаются с помощью слова VARIABLE:

VARIABLE <var_name>

Определить переменную можно в самом начале задания, до раздела Action:, а заносить и извлекать из нее значение можно внутри раздела Action:. При создании переменной в нее заносится значение 0.

Пример:

#( test_variable
NoActive
VARIABLE my_var Time: * * * * * * Action: \ ... работаем со значением переменной my_var )#

Значение заносится в переменную с помощью слова ! (восклицательный знак):

<var_value> <var_name> !

Пример:

\ теперь переменная my_var содержит число '12'
12 my_var !

Чтобы "извлечь" значение переменной используется слово @:

<var_name> @

Пример:

\ прибавляем '10' к значению переменной my_var ('12')
\ результат - '22'
my_var @ 10 +

Обратите внимание, что слова @ и ! фактически работают с адресом переменной, который остается на стеке после указания (выполнения) ее имени: простое употребление имени переменной оставляет на стеке ее адрес в оперативной памяти компьютера.

Пример:

#( test_variable1
NoActive   \ будем запускать задание вручную
\ создаем две переменные
VARIABLE first_var
VARIABLE second_var
Action:
    \ заносим число '18' в переменную 'first_var'
    18 first_var !
    \ прибавляем '4' к значению переменной 'first_var' 
    \ и заносим результат в переменную 'second_var' 
    \ (4 + 18 = 22)
    4 first_var @ + second_var !
    \ выводим значение переменной 'second_var' на экран
    MSG: "second_var = %second_var @%"
)#

Существуют также специальные слова ON и OFF, которые облегчают использование переменных с условным оператором IF ... ELSE ... THEN. Слово ON присваивает указанной переменной значение -1, а OFF - значение 0:

\ устанавливаем переменной first_var значение -1
first_var ON
\ устанавливаем переменной first_var значение 0
first_var OFF

Пример:

#( test_variable2
NoActive
\ создаем переменную is_it_true?
VARIABLE is_it_true?
Action:
    \ присваиваем переменной значение '-1'
    is_it_true? ON
    \ извлекаем значение переменной
    \ и проверяем с помощью условного оператора
    is_it_true? @
    IF 
        MSG: "TRUE!"
    ELSE 
        MSG: "FALSE!"
    THEN
    \ присваиваем переменной значение '0'
    is_it_true? OFF
    \ извлекаем значение переменной
    \ и проверяем с помощью условного оператора
    is_it_true? @
    IF 
        MSG: "TRUE!"
    ELSE 
        MSG: "FALSE!"
    THEN
)#

Многие слова Форта и nnCron возвращают числа двойной длины. Для создания переменной, которая может хранить числа двойной длины, используется слово 2VARIABLE. Чтобы занести значение в такую переменную, используйте слово 2!. Чтобы "извлечь" значение, используйте слово 2@.

Примеры:

#( test_file_size1
NoActive
\ создаем переменную fsize, которая 
\ может хранить числа двойной длины
2VARIABLE fsize
Action:
    \ сохраняем размер файла mkisofs.exe в переменной fsize
    FILE-SIZE: "c:\temp\mkisofs.exe" fsize 2!
    \ выводим значение переменной fsize в сообщении
    MSG: "mkisofs.exe size = %fsize 2@ <# #S #>%"
)#

#( test_file_size2
NoActive
\ создаем переменную fsize2, которая 
\ может хранить числа двойной длины
2VARIABLE fsize2
Action:
    \ присваиваем переменной fsize2 значение двойной длины 10240
    10240. fsize2 2! 
    \ сравниваем содержимое переменной fsize2
    \ с размером файла mkisofs.exe
    fsize2 2@ FILE-SIZE: "c:\temp\mkisofs.exe" D<
    IF
        MSG: "<"
    ELSE
        MSG: ">"
    THEN
)#

См. также раздел Зона видимости переменных, констант и массивов.


VALUE-переменные

Числовые переменные можно создавать и с помощью слова VALUE:

<initial_value> VALUE <var_name>

Как видите, при использовании VALUE значение переменной записывается в нее прямо при создании:

10  VALUE first_var
100  VALUE second_var

Удобство VALUE-переменной заключается в том, что вам не надо использовать специальное слово для извлечения содержащегося в ней значения. Чтобы поместить значение VALUE-переменной на стек достаточно указать (выполнить) в программе ее имя:

#( test_value_var
NoActive
\ создаем переменную bingo, присваеваем ей значение '21' 21 VALUE bingo Action: \ выводим на экран значение переменной
MSG: "You are a winnner - %bingo%!" )#

Для записи нового значения в VALUE-переменную служит специальное слово TO. Вот как оно применяется:

<new_var_value> TO <var_name>

Пример:

#( test_value_var1
NoActive
\ создаем переменную counter_var, присваеваем ей значение '0' 0 VALUE counter_var Action:
\ выводим на экран значение переменной
MSG: "Initial value = %counter_var%"
\ присваиваем переменной новое значение '5' 5 TO counter_var \ выводим на экран новое значение переменной
MSG: "New value = %counter_var%" )#

См. также раздел Зона видимости переменных, констант и массивов.


Константы

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

Для создания константы используйте специальное слово CONSTANT:

<const_value> CONSTANT <const_name>

Чтобы поместить значение константы на стек достаточно указать (выполнить) в программе ее имя:

#( test_constant
NoActive
\ создаем константу one_o_one и присваиваем ей значение '101' 101 CONSTANT one_o_one Action: \ выводим значение константы на экран MSG: "One-O-One = %one_o_one%" \ используем константу в арифметическом действии MSG: "One-O-One - 1 = %one_o_one 1 -%" \ выводим значение константы снова, \ чтобы убедиться, что оно не изменилось MSG: "One-O-One = %one_o_one%" )#

См. также раздел Зона видимости переменных, констант и массивов.


Массивы

Массив - это специальная структура, которая позволяет хранить множество значений под одним именем. Одно из традиционных применений массивов в nnCron - это промежуточное хранение символьных строк. Способы работы со строками подробно изложены в "Неотложной помощи по Форту".

Для создания массива используется слово CREATE:

CREATE <array_name>

А для того, чтобы выделить под только что созданный массив нужное количество памяти используется слово ALLOT.

Пример:

#( test_array
NoActive
\ создаем массив test_arr, размером в 256 байт CREATE test_arr 256 ALLOT
Action:
\ помещаем строку в массив
S" this is our string" test_arr PLACE
\ считываем строку из массива \ и выводим ее на экран
MSG: "Array contents: %test_arr COUNT%"
)#

Разумеется, в массивах можно хранить не только строки, но любые другие значения. Массивы даже можно инициализировать прямо при создании, например:

\ создаем массив, содержащий пять чисел
CREATE numbers 1 , 2 , 3 , 4 , 5 ,

Детальное описание способов работы с массивами выходит за рамки документации nnCron. За дополнительной информацией обратитесь к документации языка программирования Форт.

См. также раздел Зона видимости переменных, констант и массивов.


Файловые и реестровые переменные

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

Специально для этой цели nnCron предоставляет набор слов для создания строковых переменных, которые никак не зависят от перезагрузок компьютера и nnCron. Речь идет о т. н. файловых и реестровых переменных, т. е. переменных, которые хранят свои значения не в оперативной памяти компьютера, а в специальных файлах или ключах registry.

fVAR <var_name> (file variable)
regVAR <var_name> (registry variable)

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

#( test_persistent_var
NoActive 
\ создаем одну файловую и одну реестровую переменную
fVAR file_var
regVAR reg_var
Action:
    \ присваиваем переменным строковые значения
    S" first string" TO file_var
    S" second string" TO reg_var
    \ выводим оба значения на экран
    MSG: "There are %file_var% and %reg_var%"
)#

Изначально файловые и реестровые переменные работают со строками, но если нужно сохранить в них не строки, а числа, то можно воспользоваться словами, которые преобразуют число в строку и наоборот (вопрос преобразования строк в числа и чисел в строки рассмотрен подробнее в "Неотложной помощи по Форту"):

\ преобразуем число в строку и записываем ее в файловую переменную
N>S TO file_var
\ считываем строку из файловой переменной и преобразуем ее в число file_var S>NUM

Для получения полной картины о работе файловых и реестровых переменных осталось разобраться - где же они хранятся. Каждая из файловых переменных хранится в одноименном файле в подкаталоге var того каталога, куда установлен nnCron. Реестровые переменные хранят свои значения в одноименных ключах registry в ветке HKEY_LOCAL_MACHINE\SOFTWARE\nnSoft\var\.

Существуют специальные слова, которые (в случае необходимости) позволят вам поменять место хранения файловых и реестровых переменных:

FileVarPath! ( a u -- )
RegVarPath! ( a u -- )

Задает путь к каталогу (ветку registry), где должны храниться файловые/реестровые переменные. Не забудьте поставить обратный слеш (\) в конце указанного пути.

S" c:\temp\var\" FileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" RegVarPath!

Обратите внимание, это слово предназначено для использования в nncron.ini. Его нельзя применять в тексте задач.

uFileVarPath! ( a u -- )
uRegVarPath! ( a u -- )

Задает путь к каталогу (ветку registry), где должны храниться файловые/реестровые переменные в пределах потока. Не забудьте поставить обратный слеш (\) в конце указанного пути.

S" c:\temp\var\" uFileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" uRegVarPath!

Слово предназначено для применения в тексте задач.

В случае необходимости вы можете программно удалить неиспользуемые файловые и реестровые переменные с помощью слов FILE-DELETE:/REG-DELETE-KEY:.

См. также раздел Зона видимости переменных, констант и массивов.


Зона видимости переменных, констант и массивов

Все пеpеменные (VARIABLE, VALUE), константы (CONSTANT) и массивы (CREATE ... ALLOT) являются глобальными, видны из дpугих задач и разделяются всеми экземплярами задач. Поэтому имеет смысл с особой тщательностью следить за уникальностью имени любой пеpеменной - во избежание дополнительной путаницы.

Вот кое-какие подpобности для особо любопытных: в пpинципе, хотя пеpеменные глобальны, каждая уникальная задача будет pаботать со своей пеpеменной. Дpугое дело констpукции вида: %VAR-NAME @% - они будут выводить только пеpеменную, использовавшуюся последней, вне зависимости от задания.

Пpимеp:

#( t1
VARIABLE V1
Action:
    1 V1 !
    MSG: "%V1 @%"
)#

#( t2
VARIABLE V1
Action:
    2 V1 !
    MSG: "%V1 @%"
)#

Вопpос: угадайте, что выведет пеpвая задача?

Ответ: это зависит от того, выполнялась втоpая или нет. Если да, то пеpвая выведет 2, а если нет, то 0 (начальное значение всех пеpеменных).

Можно создавать переменные и массивы, которые будут уникальными для каждого экземпляра задачи (сколько экземпляров задачи работает, столько и переменных). Для этого надо создавать переменные при помощи следующих слов:

USER var1
USER-CREATE var2 256 USER-ALLOT
USER-VALUE var3

Еще можно выделять память по ALLOCATE. В этом случае у каждой задачи тоже будет свой буфер:

#( vars
NoActive
USER buf
Action:
    256 ALLOCATE THROW buf !
    ACTIVE-WINDOW buf @ PLACE
    5000 PAUSE
    MSG: "%buf @ COUNT%"
)#