6.11.2 Value-Flavoured and Defer-Flavoured Fields

In addition to the variable-flavoured fields that produce an address (see Standard Structures), Gforth also provides varue-flavoured fields. Like all fields, varue-flavoured fields consume the start address of the struct, but they produce their value and you can apply to, +to and addr on them. E.g., we can do something like the intlist definition (see Standard Structures):

0
  value: intlist>next ( intlista -- intlista1 )
  value: intlist>val  ( intlista -- n )
constant intlista ( -- u )

This means that there are the following ways of accessing intlist>val:

intlist>val ( intlista -- n )
->intlist>val ( n intlista -- ) \ aka  to intlist>val
+>intlist>val ( n intlista -- ) \ aka +to intlist>val
addr intlist>val ( intlista -- addr )

And here’s the earlier example (see Standard Structures) rewritten to use intlista:

intlista allocate throw constant my-intlista1
0 my-intlista1 to intlist>next
5 my-intlista1 to intlist>val

intlista allocate throw constant my-intlista2
my-intlista1 my-intlista2 to intlist>next
7            my-intlista2 to intlist>val

: intlista-sum ( intlista -- n )
\ "intlista" is a pointer to the first element of a linked list
\ "n" is the sum of the intlist>val fields in the linked list
    0 BEGIN ( intlista1 n1 )
        over
    WHILE ( list1 n1 )
        over intlist>val +
        swap intlist>next swap
    REPEAT
    nip ;

my-intlista2 intlista-sum . \ prints "12"

Depending on the type of the field, the value can be something different than a single cell.

value: ( u1 "name" – u2  ) gforth-experimental “value:”

Name is a varue-flavoured field; in-memory-size: cell; on-stack: cell

cvalue: ( u1 "name" – u2  ) gforth-experimental “cvalue:”

Name is a varue-flavoured field; in-memory-size: char; on-stack: unsigned cell

wvalue: ( u1 "name" – u2  ) gforth-experimental “wvalue:”

Name is a varue-flavoured field; in-memory-size: 16 bits; on-stack: unsigned cell

lvalue: ( u1 "name" – u2  ) gforth-experimental “lvalue:”

Name is a varue-flavoured field; in-memory-size: 32 bits; on-stack: unsigned cell

scvalue: ( u1 "name" – u2  ) gforth-experimental “scvalue:”

Name is a varue-flavoured field; in-memory-size: char; on-stack: signed cell

swvalue: ( u1 "name" – u2  ) gforth-experimental “swvalue:”

Name is a varue-flavoured field; in-memory-size: 16 bits; on-stack: signed cell

slvalue: ( u1 "name" – u2  ) gforth-experimental “slvalue:”

Name is a varue-flavoured field; in-memory-size: 32 bits; on-stack: signed cell

2value: ( u1 "name" – u2  ) gforth-experimental “2value:”

Name is a varue-flavoured field; in-memory-size: 2 cells; on-stack: 2 cells; +to performs double-cell addition (d+).

fvalue: ( u1 "name" – u2  ) gforth-experimental “fvalue:”

Name is a varue-flavoured field; in-memory-size: float; on-stack: float

sfvalue: ( u1 "name" – u2  ) gforth-experimental “sfvalue:”

Name is a varue-flavoured field; in-memory-size: 32-bit float; on-stack: float

dfvalue: ( u1 "name" – u2  ) gforth-experimental “dfvalue:”

Name is a varue-flavoured field; in-memory-size: 64-bit float; on-stack: float

zvalue: ( u1 "name" – u2  ) gforth-experimental “zvalue:”

Name is a varue-flavoured field; in-memory-size: 2 floats; on-stack: 2 floats; +to performs componentwise addition.

$value: ( u1 "name" – u2  ) gforth-experimental “$value:”

Name is a varue-flavoured field; in-memory-size: cell; on-stack: c-addr u (see $tring words); ( c-addr u ) +to name appends c-addr u to the string in the field.

Gforth also has field words for dealing with dynamically-sized arrays. A field for such an array contains just a cell that points to the actual data, and this cell has to be set to 0 before accessing the array the first time. When accessing the field (without operator, or with to or +to), there has to be the index and the structure address on the stack, with the structure address on top. Any further items consumed by to or +to are below the index on the stack. The array expands to the size given by the maximum access; any unset elements are 0; for $value[] accessing them produces a 0-length (i.e., empty) string.

Here is a usage example:

0
  value[]:  bla>x[]
  $value[]: bla>$y[]
constant bla

bla allocate throw constant mybla
mybla bla erase \ set all fields to 0

5 2 mybla to bla>x[] \ access at index 2
7 0 mybla to bla>x[] \ access at index 0
2 mybla bla>x[] . \ prints "5"
3 mybla bla>x[] . \ prints "0"
"foo" 2 mybla to bla>$y[]  \ access at index 2
"bla" 1 mybla to bla>$y[]  \ access at index 1
"bar" 2 mybla +to bla>$y[] \ access at index 2
0 mybla bla>$y[] . . \ prints "0 0"
1 mybla bla>$y[] type \ prints "bla"
2 mybla bla>$y[] type \ prints "foobar"
value[]: ( u1 "name" – u2  ) gforth-experimental “value[]:”
$value[]: ( u1 "name" – u2  ) gforth-experimental “$value[]:”

Finally, you can define defer-flavoured fields. Here is a usage example:

0
  defer: foo'bar
constant foo

foo allocate throw constant my-foo
:noname ." test" ; my-foo is foo'bar
my-foo foo'bar                   \ prints "test"
my-foo addr foo'bar @ execute   \ prints "test"
my-foo action-of foo'bar execute \ prints "test"
my-foo `foo'bar defer execute   \ prints "test"
:noname ." test1" ; my-foo `foo'bar defer!
my-foo foo'bar                   \ prints "test1"
defer: ( u1 "name" – u2  ) gforth-experimental “defer:”

Name is a defer-flavoured field

For documentation of is, action-of, defer@, defer!, see See Deferred Words. Note however, that when used on defer-flavoured fields, all these words consume the start address of the structure, unlike for words defined with defer.