For programming a hosted Forth with a GUI interface and for other significant styles of programming, the ANS Forth specification of local variables is inadequate. VFX Forth and other modern Forth systems provide an alternative notation with more functionality and better readability. A subset of this notation became the basis of the Forth200x local variables proposal. The ANS locals mechanism is supported in VFX Forth for backwards compatibility.
The MPE extended local syntax provides a number of significant benefits to the ANS standard.
In this implementation, locals are allocated as a frame on the return stack. Note that the word's return address is no longer available.
The following example shows a code extract from a WINPROC, there are the traditional 4 inputs, a local array storing a temporary structure and one output.
: WndProc {: hWnd uMsg wParam lParam | clientrect[ RECT ] -- res :}
uMessage WM_SIZE =
if
hWnd clientrect[ GetClientRect drop \ Get client rect
hWndChild @ \ useto resize child
#0
#0
clientrect[ RECT.right @
clientrect[ RECT.bottom @
TRUE MoveWindow drop
0 exit
then
...... Other Messages ....
hWnd uMessage wParam lParam DefWindowProc \ Msg default.
;
The following syntax for named inputs and local variables is used.
The sequence:
{: ni1 ni2 ... | lv1 lv2 ... -- o1 o2 :}
defines named inputs, local variables, and outputs. The named inputs are automatically copied from the data stack on entry. Named inputs and local variables can be referenced by name within the word during compilation. The output names are dummies to allow a complete stack comment to be generated.
For compatibility with previous implementations, { is accepted in place of {: and } in place of :}. The change to {: ... :} took place as a result of the Forth200x standard.
Named inputs and locals return their values when referenced,
and must be preceded by ->
or TO
to perform a
store, or by ADDR
to return the address.
Arrays may be defined in the form:
arr[ n ]
Any name ending in the '[' character will be treated as an array, the expression up to the terminating ']' will be interpreted to provide the size of the array. Arrays only return their base address, all operators are ignored.
In the example below, a and b are named inputs, a+b and a*b are local variables, and arr[ is a 10 byte array.
: foo {: a b | a+b a*b arr[ 10 ] -- :}
a b + -> a+b
a b * -> a*b
cr a+b . a*b .
;
Floating point arguments (inputs) and temporaries are
declared by placing F:
before the name, but not for
arrays of floats, which should be declared as above.
Floating point locals use the CPU's native FP (80x87) stack,
and so are most suitable for use with the %lib%/x86/ndp387.fth
floating point package. Floating point locals are stored in
the extended 80 bit (10 byte) format. This is the default
for the %lib%/x86/ndp387.fth code. The default action of
an FP local is to return its value. The following operators
can be applied:
TO
or ->
- store to the local,ADDR
- return the address of the data,ADD
or +TO
- add to the value,SUB
or -TO
- subtract from the value.
: foo2 {: a f: f1 b f: f2 | f: f3 f: f4 c d e -- :}
...
;
The arguments a and b above are integer arguments taken from the Forth data stack. The arguments f1 and f2 are FP arguments taken from the floating point unit. Local values f3 and f4 are FP locals and the others are integer locals. An example of using FP locals follows:
: foo3 {: f: f1 | f: f2 f: f3 -- :}
0e0 -> f2 10e0 -> f3 ( noop )
f1 add f2 f1 sub f3 ( noop )
f2 f. f3 f.
;
: { \ --
The start of the traditional brace notation { ... }.
: {: \ --
The Forth200x name to start the extended local variable
notation. Use in the form:
{: ni1 ni2 ... | lv1 lv2 ... -- o1 o2 :}
The ANS locals definitions are provided for use with ANS standard compliant code. The ANS locals system offers limited functionality.
: (LOCAL) \ Comp: c-addr u -- ; Exec: -- x
When executed during compilation, defines a local variable
whose name is given by c-addr/u. If u is zero, c-addr is ignored
and compilation of local variables is assumed to finish.
When the word containing the local variable executes, the local
variable is initialised from the stack. When the
local variable executes, its value is returned. The local variable
may be written to by preceding its name with TO
.
The word (LOCAL)
is intended for the construction of
user-defined local variable notations. It is only provided
for ANS compatibility.
: LOCALS| \ "<name1> ... <namen> |" --
Create named local variables <name1>
to <namen>
.
At run time the stack effect is ( xn..x1 -- )
, such
that <name1>
is initialised to x1
and <namen>
is initialised to xn
. Note that this means that the
order of declaration is the reverse of the order used in stack
comments! When referenced, a local variable returns its value.
To write to a local, precede its name with TO
. All locals
created by LOCALS|
are single-cell integers.
In the example below, a and b are named inputs.
: foo \ a b --
locals| b a |
a b + cr .
a b * cr .
;
variable LVCOUNT \ -- addr
Holds the offset in the frame for the next local integer variable.
: FRADJUST \ size -- offset
Adjust the size of the current local values frame. Used
by words that create additional local variables outside a
LOCALS| ... |
or { ... } notation.