6.22.1 Gforth locals

Locals can be defined with

{: local1 local2 ... -- comment :}

or

{: local1 local2 ... :}

or

{: local1 local2 ... | ulocal0 ulocal1 -- comment :}

E.g.,

: max {: n1 n2 -- n3 :}
 n1 n2 > if
   n1
 else
   n2
 endif ;

The similarity of locals definitions with stack comments is intended. A locals definition often replaces the stack comment of a word. The order of the locals corresponds to the order in a stack comment and everything after the -- is really a comment.

This similarity has one disadvantage: It is too easy to confuse locals declarations with stack comments, causing bugs and making them hard to find. However, this problem can be avoided by appropriate coding conventions: Do not use both notations in the same program. If you do, they should be distinguished using additional means, e.g. by position.

The name of the local may be preceded by a type specifier, e.g., F: for a floating point value:

: CX* {: F: Ar F: Ai F: Br F: Bi -- Cr Ci :}
\ complex multiplication
 Ar Br f* Ai Bi f* f-
 Ar Bi f* Ai Br f* f+ ;

Gforth currently supports cells (W:, WA:, W^), doubles (D:, DA:, D^), floats (F:, FA:, F^), characters (C:, CA:, C^), and xts (xt:, xta:) in several flavours:

value-flavoured

(see Values) A value-flavoured local (defined with W:, D: etc.) produces its value and can be changed with TO.

varue-flavoured

(see Varues) A varue-flavoured local l (defined with WA: etc.) behaves exactly like a value-flavoured local, except that you can use addr l to get its address (which becomes invalid when the variable’s scope is left). Currently there is no performance difference, but in the long run value-flavoured locals will be significantly faster, because they can reside in registers.

variable-flavoured

(see Variables) A variable-flavoured local (defined with W^ etc.) produces its address (which becomes invalid when the variable’s scope is left). E.g., the standard word emit can be defined in terms of type like this:

: emit {: C^ char* -- :}
    char* 1 type ;
defer-flavoured

(see Deferred Words) A defer-flavoured local (defined with XT: or XTA:) executes the xt; you can use action-of (see Deferred Words) to get the xt out of a defer-flavoured local. If the local is defined with xta:, you can use addr to get the address (valid until the end of the scope of the local) where the xt is stored. E.g., the standard word execute can be defined with a defer-flavoured local like this:

: execute {: xt: x -- :}
  x ;

A local without type specifier is a W: local. You can allow or disallow the use of addr with:

default-wa: ( ) gforth-experimental “default-wa:”

Allow addr on locals defined without a type specifyer. On other words, define locals without a type specifyer using wa:.

default-w: ( ) gforth-experimental “default-w:”

Forbid addr on locals defined without a type specifyer. On other words, define locals without a type specifyer using w:.

All flavours of locals are initialized with values from the data or (for FP locals) FP stack, with the exception being locals defined behind |: Gforth initializes them to 0; some Forth systems leave them uninitialized.

Gforth supports the square bracket notation for local buffers and data structures. These locals are similar to variable-flavored locals, the size is specified as a constant expression. A declaration looks name[ size ]. The Forth expression size is evaluated during declaration, it must have the stack effect ( -- +n ), giving the size in bytes. The square bracket [ is part of the defined name.

Local data structures are initialized by copying size bytes from an address passed on the stack; uninitialized local data structures (after | in the declaration) are not erased, they just contain whatever data there was on the locals stack before.

Example:

begin-structure test-struct
  field: a1
  field: a2
end-structure

: test-local {: foo[ test-struct ] :}
    foo[ a1 !  foo[ a2 !
    foo[ test-struct dump ;

Gforth allows defining locals everywhere in a colon definition. This poses the following questions: