The usage of structure definitions is quite commonplace
among forth implementors. The actual implementation
techniques vary as widely as the resulting capabilities
of the resulting structure-"types".

During the years, a common minimum characteristics can
be deduced from the implementations that manifest
themselves in the three words

> STRUCTURE ( "structname" -- xx end_offset )
> ENDSTRUCTURE ( xx end_offset -- )
> SIZEOF ( "structname" -- sizeof_it )

short description:
The words STRUCTURE and ENDSTRUCTURE are always used
in pairs. In the text between them, the top-of-stack
hold a value that is both the sizeof-struct and the
current-offset. ENDSTRUCTURE will save the last value in
the "structname" parameterpart CREATEd by STRUCTURE, 
and SIZEOF will fetch the value from the "structname" 
(so, SIZEOF is state-smart).

When the "structname" is executed later it will in turn
CREATE a new word - followed by an ALLOT with the
size-value saved by ENDSTRUCTURE. The created word
behaves just like a VARIABLE. This is called a

The access of the various parts of the struct-instance
and the modifications to the endoffset-value is
very different among implementations, but in general
they create offsetwords with a global namespace.

intro example:
2 CELLS NEWFIELD ->first_2_cells
2 CHARS NEWFIELD ->next_2_chars

SIZEOF newtype . ( prints probably 10 in a 32-bit forth)
0 ->first_2_cells . ( prints probably 0 )
0 ->next_2_cells . ( prints probably 8 in a 32-bit forth)

newtype myvar ( myvar is otherwise just a VARIABLE)
HERE myvar - . ( the sizeof myvar's body is... 10)

myvar ->next_2_cells C@ ( to get the first of the 2 chars )

quick n dirty implementation:
: STRUCTURE   ( "name" -- xx offset )
      HERE    ( leave the address of the following sizeof-comma )
      0 DUP , ( initial size is zero and left on the stack )
    DOES>     ( has the address of the sizeof-comma )
      CREATE  ( make a variable )
      @ ALLOT ( and make the variable that long )

: ENDSTRUCTURE ( xx offset -- )
    SWAP !    ( store the last endoffset into the sizeof-comma )

: SIZEOF ( "name" -- size )
    ' >BODY @ ( get the sizeof ... some implementations need also >DOES )

: NEWFIELD ( offset field_size "name" -- offset' )
      OVER , ( store the current end_offset )
      +      ( increase the end_offset by the field_size )
      @ +    ( add the memorized offset of the field)
The generic name for an offset-word is totally different
among forth implementations (if it exists anyway), I chose
NEWFIELD because it has never been used anywhere before.
(see also the example implementation in 
structure.fs )

The words STRUCTURE and ENDSTRUCTURE are always used
in pairs - ENDSTRUCTURE is supposed to clean up 
everything that the STRUCTURE word has changed in the
environment. A portable script may not make any
assumptions about the additional depth of the

The final offset is saved as the size of the struct,
but some implementations do also some alignement,
either during storage of the value or on instantiation,
so that the values do sometimes differ (instead of
being the contant 10 in the example). The actual
address of the sizevalue inside of the DOES-parameter
is not fixed either. Some implemenations put a
type-id in there too.

A generic NEWFIELD-like word does often not exists
because the STRUCTURE fields are only declared with
words that do also memorize a type-id to be checked
on access to the fields. An example usage would be
> STRUCTURE typename
>    CHAR: ->first_char
>    CELL: ->probably_aligned_before
>    CHAR: ->aligned_good_enough

The sizeof-value (on a 32bit system) could be 6, 7, 9, 10 or 12. 
The same applies to the HERE-difference on instantiation of 
the typename, so you better do not make assumptions if the
current structure-implemenation is packed or not.

On the other hand, you are free to increase the offset-value
at will, which is somehow that same as an ALLOT after a call
to CREATE, i.e. "CHAR: ->my_chars 10 CHARS +" is always the
same as a "11 CHARARRAY: ->my_chars". This should be widely
used to make descriptive names of field by creating new
offsetword-declarators, e.g.
> : CELLARRAY:   >R CELL: R> CELL- + ;

1 5 1