Top: Forth Index Prev: Doing It Again & Again Next: Floating Point


A variable refers to an address in the computer's memory where space is alloted to hold information. To define a variable, you need to give it a name and allocate a specific number of bytes.

    ok variable \volume
    ok variable \name 16 allot
Here we have created two variables, one named \volume and another named \name. We happen to prefix variables with a backslash to distinguish them from words and other storage types. Upon creation, \volume is automatically alloted one cell, enough to store a number between -2^31 and 2^31. A cell is made up of bytes, in the case of our 32 bit Forth, a cell is 4 bytes. A 64 bit Forth may define a cell to be 8 bytes and a 16 bit Forth might use 2 byte cells.

\name gets created exactly the same way as \volume, except that we tell Forth to set aside 16 more bytes for storage for storage purposes. This method is commonly used to store strings.

To store and retrieve numbers to a variable, we have two commands at our disposal: ! and @, respectively called store and fetch. These two words operate on memory addresses. If you place a variable on the stack, its location in memory is left on the stack as a positive integer. You can store or fetch the variable's value with ! and @.

    ok name .s  \ .s shows the contents of the stack.
    ok 10 swap .s !
    10 119920
    ok .s
    ok name @ .s
variable ( "name" -- ) Create a variable with name "name".

allot ( n -- ) Allocate n bytes of memory for the most recently created variable.

! ( n addr -- ) Store n at memory location addr.

@ ( addr -- n ) Fetch the value stored at addr.


Constants are used to store values which do not change within a program (actually their value can be changed, but that is another story for another time). Constants do not act like variables in that you do not have to fetch the value after typing the constant's name. This is done automatically for you.

    ok 4096 constant #step.resolution \ # of steps/Volt.
    ok #step.resolution .s
Most of our code prefixes constant names with a "#" for much the same reason as we prefix variable names with "\". Most of our older code has not undergone this change, though.

constant ( n "name" -- ) Define a constant "name" with value n.


A string is a group of printable characters for which there are two types: a normal string which only contains the characters themselves, and packed strings (or counted strings) which store the length of the string at the beginning.

    ok " This is a typical string." .s
    119921 24   \ The 1st number is the address, the 2nd is the length.

    ok p" This is a packed string." .s
    119921 24 119920

    ok count .s \ count extracts the length of the packed string.
    119921 24 119921 24

    ok type     \ display the first n characters from address.
    This is a packed string.

    ok type
    This is a packed string.

    ok .s
Something interesting and important has happened here. If you look carefully, we created two different strings, a normal string and a packed string, but when we printed each string out the same string was displayed. This happened because there is one specific address where temporary strings are stored, in this example the address is 119920. So, in order to maintain multiple strings we need to have a way of storing them.

    ok variable pstring 80 allot    \ To hold an 80 char packed string.
    ok variable nstring 80 allot    \ To hold an 80 char normal string.
    ok p" This is a packed string."
    ok pstring "copy
    ok pstring ".                   \ ". is a synonym for COUNT TYPE.
    This is a packed string.

    ok " This is a normal string." nstring swap cmove
    ok nstring 24 type
    This is a normal string.
Here we use "copy to copy the contents of a packed string address into another address and cmove to copy just the string itself to an address. We end up with two variables each containing different strings. You can easily convert a normal string to a packed string.

    ok " This will be a packed string."
    ok pstring pack
    ok ".
    This will be a packed string.
"copy ( addr1 addr2 -- ) copies the packed string at addr1 to addr2.

cmove ( addr1 addr2 n -- ) copies n bytes from addr1 to addr2.

pack ( addr1 n addr2 -- addr2 ) makes a packed string out of addr1 for n bytes and stores it in addr2.

place ( addr1 n addr2 -- ) Same as pack except that addr2 is not left on the stack.

count ( pstr -- addr len ) Converts a packed string into an address and a length.


Some examples of output:

    ok 10 .                 \ "dot"

    ok 10 20 .s             \ "dot-s"
    10 20

    ok : test-dot-quote     \ "dot-quote"
            ." This is a string."  ;
    ok test-dot-quote
    This is a string.

    ok .( Print this now!)  \ "dot-paren"
    Print this now!
type ( addr len -- ) displays len bytes from addr.

. ( n -- ) displays the top stack item, removing it in the process.

.s ( -- ) displays the current contents of the stack.

." ( "string<quote>" -- ) display the string located between ." and " during runtime (i.e. when a word is executed).

.( ( "string<paren>" -- ) display the string bounded by .( and ) immediately.

Fields - Not Required Reading

Fields are a creation of a previous NIR lab programmer named Dan Briotta. A field is a data structure which groups similar variables and strings together. For instance, we have a field named det which holds the name of the detector file, the clocking and data acquisition program file names, the number of detector outputs and so on. This method will eventually be replaced with a more complex data structure which will keep track of the size of each entry as well as include a description of the variable or string. Currently, a field structure looks sort of like this:

    76 constant detsize                     \ #  bytes in det structure
    create  (det)        detsize allot      \ det structure for running system
    create  (dummydet)   detsize allot      \ det structure for loading files
    defer   det     \ det structure itself - can be assigned to either of above
    ' (det) is det  \ Default: det set for running
        0   field   det \detname   \ detector file name
       12   field   det \clockpgm  \ dsp 56k clock program file name
       24   field   det \datapgm   \ dsp 56k data acquisition program
        4   field   det \nout      \ detector outputs        
There is no way of knowing how space is reserved for a string, so using a string entry correctly is difficult. A new data structure method devised by Nat Cowen, which you need not concern yourself with just yet, will look something like:

    struct-type: {}(det)   is" Detector Parameters"
        12 strfield:  \detfile    is" (file) detector parameters"
        12 strfield:  \clockpgm   is" (file) dsp clock program"
        12 strfield:  \datapgm    is" (file) dsp data program"
           intfield:  \nout       is" # detector outputs"

    struct: {}(det)   {}det       is" Running System (not loading from file)"
Each {}det structure will be made up of new data types strfield: and intfield: from which information about each variable or string can be extracted.
Top: Forth Index Prev: Doing It Again And Again Next: Floating Point