Working with Variables, Constants and Arrays
Active usage of nnCron often requires to store various data for long periods of time. Variables, constants and arrays can be used for this purpose. Beside allowing to use all the tools for handling variables, constants and arrays provided by Forth programing language (SP-Forth), nnCron also privides some convenient tools of its own.
Variables inteneded for storing numerical values are created (declared) with word VARIABLE:
VARIABLE <var_name>
Variable should be declared in the beginning of a task, before the Action: section; operations of assigning/fetching values to and from variables should be performed inside of Action: section. When a variable is created, it is assigned a value of 0.
Example:
#( test_variable NoActive
VARIABLE my_var Time: * * * * * * Action: \ ... working with value of my_var )#
In order to assign a value to a variable, use word ! (exclamation point) :
<var_value> <var_name> !
Example:
\ now variable my_var contains a numerical value of 12
12 my_var !
To get (retreive) a value from a variable, use word @:
<var_name> @
Example:
\ adding 10 to the value of my_var (12) \ the sum is 22
my_var @ 10 +
Example:
#( variable_task NoActive \ we are going to start this task manualy \ creating two variables VARIABLE first_var VARIABLE second_var Action: \ assigning value of 18 to first_var 18 first_var ! \ adding 4 to the value of first_var \ and storing the result in second_var \ (4 + 18 = 22) 4 first_var @ + second_var ! \ diaplaying the value of second_var MSG: "second_var = %second_var @%" )#
There are also special words ON and OFF which facilitate use of variables with IF ... ELSE ... THEN construct . Word ON sets the value of a variable to -1, and OFF to 0:
\ setting first_var to -1 first_var ON \ setting first_var to 0 first_var OFF
Example:
#( test_variable2 NoActive \ creating a variable is_it_true? VARIABLE is_it_true? Action: \ assigning a value of -1 to is_it_true? is_it_true? ON \ fetching the value of this variable \ checking it with a conditional construct is_it_true? @ IF MSG: "TRUE!" ELSE MSG: "FALSE!" THEN \ assigning a value of 0 to is_it_true? is_it_true? OFF \ fetching the value of this variable \ checking it with a conditional construct is_it_true? @ IF MSG: "TRUE!" ELSE MSG: "FALSE!" THEN )#
Some of words used in Forth and in nnCron return so called double numbers. A variable, that can hold the double number is declared using the word 2VARIABLE. To assign a value to this variable use 2!. To fetch a value use 2@.
Examples:
#( test_file_size1 NoActive \ creating a variable fsize which can hold double numbers 2VARIABLE fsize Action: \ saving the mkisofs.exe file size to fsize FILE-SIZE: "c:\temp\mkisofs.exe" fsize 2! \ displaying the fsize contents in a message MSG: "mkisofs.exe size = %fsize 2@ <# #S #>%" )# #( test_file_size2 NoActive \ creating a variable fsize2 which can hold double numbers 2VARIABLE fsize2 Action: \ assigning a double number 10240 to fsize2 10240. fsize2 2! \ comparing the fsize2 contents with mkisofs.exe file size fsize2 2@ FILE-SIZE: "c:\temp\mkisofs.exe" D< IF MSG: "<" ELSE MSG: ">" THEN )#
See also Variables, Constants and Arrays Visibility Scope
Self-fetching Variables (VALUE)
Another way to create a somewhat different type of numerical variables (so-called self-fetching variables) is to use word VALUE:
<initial_value> VALUE <var_name>
As you can see, a self-fetching variable is assigned some value at the moment when it is created:
10 VALUE first_var 100 VALUE second_var
One of the convenient features of self-fetching variables is that you can fetch their values without using a special word. All that you need to do in order to place a value of a self-fetching variable on stack is just to use its name in a program:
#( test_value_var NoActive
\ declaring a variable bingo and setting its value to 21 21 VALUE bingo Action: \ displaying its value
MSG: "You are a winnner - %bingo%!" )#
To assign a value to a self-fetching variable, use word TO. Here is and example of its use:
<new_var_value> TO <var_name>
Example:
#( test_value_var1 NoActive \ declaring a variable counter_var and setting its value to 0 0 VALUE counter_var Action: \ displaying its value MSG: "Initial value = %counter_var%" \ assigning a new value to it ( 5) 5 TO counter_var \ displaying the new value of our variable
MSG: "New value = %counter_var%" )#
See also Variables, Constants and Arrays Visibility Scope
Sometimes it is necessary to create a "variable" whose numerical value should not change later. Such a "variable" is called a constant.
To create a constant, use a special word CONSTANT:
<const_value> CONSTANT <const_name>
All that you need to do in order to place a value of a constant on stack is just to use its name in a program:
#( test_constant NoActive
\ creating a constant one_o_one and setting its value to 101 101 CONSTANT one_o_one Action: \ displaying the value of our constant MSG: "One-O-One = %one_o_one%" \ using the constant in an arithmetical operation MSG: "One-O-One - 1 = %one_o_one 1 -%" \ displaing the constant again, \ to make sure it has not changed MSG: "One-O-One = %one_o_one%" )#
See also Variables, Constants and Arrays Visibility Scope
Array is a special type of structure that allows to store multiple values under a single name. One of the traditional uses for arrays in nnCron is to temporarily store strings in them. Methods of handling strings are described in detail in "Forth First Aid".
In order to create an array, use word CREATE:
CREATE <array_name>
To allocate a required memory space for the new massive, use word ALLOT.
Example:
#( test_array
NoActive
\ creating an array test_arr 256 byte in size CREATE test_arr 256 ALLOT
Action:
\ placing a string to our array
S" this is our string" test_arr PLACE
\ reading a string from the array \ and displaying it
MSG: "Array contents: %test_arr COUNT%"
)#
Of course, arrays can be used to store any kind of values, not just strings. It is even possible to initialize arrays right at the monent of their creation, e.g.:
\ ñreating an array containing five integers CREATE numbers 1 , 2 , 3 , 4 , 5 ,
It is not a purpose of nnCron documentation to provide a more detailed desription of using arrays. For additional information, consult documentation of Forth programing language.
See also Variables, Constants and Arrays Visibility Scope
The main drawback of variables, constants and arrays discussed above is that they store their values in computer memory, and, therefore, these values will be lost after the computer is turned of or after nnCron is unloaded from the memory. But what if we want to save a value of a variable, constant or array during the period when computer is off or nnCron is not running?
Just for this purpose nnCron provides a number of words for creating string variables which are not affected by restart of a computer or of nnCron. These are so-called file variables and registry varibiables, i. e. variables which store their values not in computer memory, but in special files and registry keys.
fVAR <var_name> (file variable)
regVAR <var_name> (registry variable)
When file/registry variable is created, it is initialized with an empty string. To store your string in such a variable, use word TO. To access the current value of a variable, just use its name in a program:
#( test_persistent_var NoActive \ creating a file variable and a registry variable fVAR file_var regVAR reg_var Action: \ assigning string values to variables S" first string" TO file_var S" second string" TO reg_var \ displaying both variables on screen MSG: "There are %file_var% and %reg_var%" )#
As told above, file and registry variables are used to store strings, but if you want to use them to store numbers rather then strings, you can use special words which convert a number to a string and vice versa (coverting numbers to strings and strings to numbers is discussed in detail in "Forth First Aid"):
\ converting a number to a string and storing it in a file variable
N>S TO file_var
\ reading a string from a file variable and converting it to string file_var S>NUM
If we want to get a complete idea about using file and registry variables, we have yet to talk about out where they are stored. Each file variable is stored in a file with the same name; this files are located in subdirectory var of the nnCron installed directory. Registry variables store their values in registry keys which have the same name as variables and are located in a registry branch HKEY_LOCAL_MACHINE\SOFTWARE\nnSoft\var\.
If it is necessary to change storage locations of file and registry variables, there are special words which can be used for that purpose:
FileVarPath! ( a u
-- )
RegVarPath! ( a u -- )
These words specify the path to directory or registry branch where file/registry variables should be stored. Don't forget a backslash (\) at the end of the specified path.
S" c:\temp\var\" FileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" RegVarPath!
Please note that these words are intended for use in nncron.ini. They cannot be used in tasks.
uFileVarPath! ( a u
-- )
uRegVarPath! ( a u -- )
These words specify the path to directory or registry branch where file/registry variables should be stored. Don't forget a backslash (\) at the end of the specified path.
S" c:\temp\var\" uFileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" uRegVarPath!
These words are intended for use in tasks.
If required, you can delete unnecessary file or register variables with words FILE-DELETE:/REG-DELETE-KEY:.
See also Variables, Constants and Arrays Visibility Scope
Visibility Scope of Variables, Constants and Arrays
All variables (VARIABLE, VALUE), constants (CONSTANT) and arrays(CREATE ... ALLOT) are global, they can be seen from other tasks and are shared by all instances of any given task. Therefore, in order to avoid unnecessary confusion, one should take a great care to ensure that all variable names are unique.
Here are some details for most curious ones: although theoretically all variables are global, each unique task will work with its own variable. Constructs of %VAR-NAME @% type, however, will always return the value of variable which was used last.
Example:
#( t1 VARIABLE V1 Action: 1 V1 ! MSG: "%V1 @%" )# #( t2 VARIABLE V1 Action: 2 V1 ! MSG: "%V1 @%" )#
Now, a question: what message will contain the message box displayed by the first task?
It depends on whether or not the second one has been executed. If it has, the first one will output 2, otherwise, it will output 0 (the initial value of all variables).
It is possible to create arrays and variable which will be unique for each instance of a task (there will be as many variables as there are instances of task running). In order to achieve this result, create variables with these words:
USER var1 USER-CREATE var2 256 USER-ALLOT USER-VALUE var3
You can also allocate memory using word ALLOCATE. In this case each task will also have its own buffer:
#( vars NoActive USER buf Action: 256 ALLOCATE THROW buf ! ACTIVE-WINDOW buf @ PLACE 5000 PAUSE MSG: "%buf @ COUNT%" )#