Next: Structure Naming Convention, Previous: Why explicit structure support?, Up: Structures
You can define a structure for a (data-less) linked list with:
struct cell% field list-next end-struct list%
With the address of the list node on the stack, you can compute the
address of the field that contains the address of the next node with
list-next
. E.g., you can determine the length of a list
with:
: list-length ( list -- n ) \ "list" is a pointer to the first element of a linked list \ "n" is the length of the list 0 BEGIN ( list1 n1 ) over WHILE ( list1 n1 ) 1+ swap list-next @ swap REPEAT nip ;
You can reserve memory for a list node in the dictionary with
list% %allot
, which leaves the address of the list node on the
stack. For the equivalent allocation on the heap you can use list%
%alloc
(or, for an allocate
-like stack effect (i.e., with ior),
use list% %allocate
). You can get the the size of a list
node with list% %size
and its alignment with list%
%alignment
.
Note that in ANS Forth the body of a create
d word is
aligned
but not necessarily faligned
;
therefore, if you do a:
create name foo% %allot drop
then the memory alloted for foo%
is guaranteed to start at the
body of name only if foo%
contains only character,
cell and double fields. Therefore, if your structure contains floats,
better use
foo% %allot constant name
You can include a structure foo%
as a field of
another structure, like this:
struct ... foo% field ... ... end-struct ...
Instead of starting with an empty structure, you can extend an existing structure. E.g., a plain linked list without data, as defined above, is hardly useful; You can extend it to a linked list of integers, like this:1
list% cell% field intlist-int end-struct intlist%
intlist%
is a structure with two fields:
list-next
and intlist-int
.
You can specify an array type containing n elements of
type foo%
like this:
foo% n *
You can use this array type in any place where you can use a normal
type, e.g., when defining a field
, or with
%allot
.
The first field is at the base address of a structure and the word for
this field (e.g., list-next
) actually does not change the address
on the stack. You may be tempted to leave it away in the interest of
run-time and space efficiency. This is not necessary, because the
structure package optimizes this case: If you compile a first-field
words, no code is generated. So, in the interest of readability and
maintainability you should include the word for the field when accessing
the field.
[1] This feature is also known as extended records. It is the main innovation in the Oberon language; in other words, adding this feature to Modula-2 led Wirth to create a new language, write a new compiler etc. Adding this feature to Forth just required a few lines of code.