VALUEs and Lexically Scoped Local Variables - tabemann/zeptoforth GitHub Wiki

Full builds of zeptoforth have support for value, 2value, and lexically-scoped local variables. All of these may be set with to and added to/subtracted from with +to.

Values declared with value and 2value, along with setting these values with to, are shown below:

2 value foo  ok
2,5 2value bar  ok
foo . 2  ok
bar f. 2,5  ok
3 to foo  ok
3,75 to bar  ok
foo . 3  ok
bar f. 3,75  ok
: foo! ( x -- ) to foo ;  ok
: bar! ( d -- ) to bar ;  ok
4 foo!  ok
4,875 bar!  ok
foo . 4  ok
bar f. 4,875  ok

Here we see that the word foo declared with value returns a single-cell value when called, and to when setting it takes a single-cell value. Similarly the word bar declared with 2value returns a double-cell value when called, and to when setting it takes a double-cell value. Hence to takes both single-cell and double-cell values depending on what it is called against

Words compiled with value and 2value can be compiled to flash and are initialized with the values specified when they are created on bootup. Afterwards, their values can be changed, unlike with constant and 2constant, but are reset to their initial values after rebooting. This can be seen in the following:

compile-to-flash  ok
3 value foo  ok
3,25 2value bar  ok
reboot 
Welcome to zeptoforth
Built for rp2040, version 0.48.2, on Sat Nov 19 06:46:41 PM CST 2022
zeptoforth comes with ABSOLUTELY NO WARRANTY: for details type `license'
 ok
foo . 3  ok
bar f. 3,25  ok
4 to foo  ok
4,5 to bar  ok
foo . 4  ok
bar f. 4,5  ok
: foo! ( x -- ) to foo ;  ok
: bar! ( d -- ) to bar ;  ok
5 foo!  ok
5,75 bar!  ok
foo . 5  ok
bar f. 5,75  ok
reboot 
Welcome to zeptoforth
Built for rp2040, version 0.48.2, on Sat Nov 19 06:46:41 PM CST 2022
zeptoforth comes with ABSOLUTELY NO WARRANTY: for details type `license'
 ok
foo . 3  ok
bar f. 3,25  ok

Adding to/subtracting from values and 2values with +to is shown below:

1 value foo  ok
1,25 2value bar  ok
2 +to foo  ok
1,5 +to bar  ok
foo . 3  ok
bar f. 2,75  ok
: +foo! ( x -- ) +to foo ;  ok
: +bar! ( d -- ) +to bar ;  ok
2 +foo!  ok
1,75 +bar!  ok
foo . 5  ok
bar f. 4,5  ok

Here we see that +to functions like to except that it adds to/subtracts from the value or 2value rather than setting it.

For a simple example of local variables in action in zeptoforth consider the following:

: foo { x -- x' } x x * 2 x * + 1 + ;

Afterwards, execute:

0 foo . 1  ok
1 foo . 4  ok
2 foo . 9  ok
3 foo . 16  ok

Here foo defines a polynomial f(x) = x^2 + 2x + 1, and we evaluate f(0), f(1), f(2), and f(3). Note that the contents between { and }, which may cross multiple input lines, defines local variables to be taken off the data stack, starting from the last local variable defined, which is taken off the top of the data stack. Note that the text after -- and before } is a comment intended for documenting the return value(s) of word and has no actual effect upon the code.

For an example of a simple loop using local variables, consider the following:

: foo { limit i -- } begin i limit < while i . 1 +to i repeat ;

Afterwards, execute:

10 0 foo 0 1 2 3 4 5 6 7 8 9  ok

Here we pull the loop counter i, which shadows the standard do loop variable i, and the loop limit limit off the data stack and place them in the so-named local variables. Then we loop until i is greater than or equal to limit, printing the current value of i and incrementing i with +to for each iteration. Note that local variables may also be set with to.

For a more elaborate example of using local variables combined with begin ... until loops, consider the following:

: foo { multiplier limit i -- } 0 { acc } begin i multiplier * { im } 1 +to i im +to acc im limit >= until acc ;

Afterwards, execute:

3 100 1 foo . 1785  ok

Here we create local variables both outside and inside the loop and access them both inside the loop and outside the loop, after the loop has completed, showing that local variables created before the loop began can be accessed after the end of the loop.

For an example of using local variables together with do loops, consider the following:

: foo ( increment limit i -- ) rot { increment } ?do i . increment +loop ;

Afterwards, execute:

2 20 0 foo 0 2 4 6 8 10 12 14 16 18  ok

Here we create a local variable increment and execute a do loop, where we use the value of increment to increment the do loop counter.

For another example of using local variables together with do loops, consider the following:

: foo ( multiplier limit i ) rot { multiplier } ?do i multiplier * { xi } i xi + . loop ;

Afterwards, execute:

3 10 0 foo 0 4 8 12 16 20 24 28 32 36  ok

Here we create local variables both outside and inside the do loop and refer to them both within the do loop while simultaneously accessing i.

Currently local variables are always single cell, so if one wants to place a multi-cell value in local variables one will need separate local variables for each cell.