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:
(see Values) A value-flavoured local (defined with W:
,
D:
etc.) produces its value and can be changed with TO
.
(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.
(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 ;
(see Deferred Words) A defer-flavoured local (defined with
XT:
or XTA:
) execute
s 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: