I am using the interpreter directives (non ANS standard) control structures of Gforth as described in the manual section 5.13.4 Interpreter Directives. I basically want to use the loop words to create a dynamically sized word containing literals. I came up with this definition for example:
: foo
[ 10 ] [FOR]
1
[NEXT]
;
Yet this produces an Address alignment exception after the [FOR]
(yes, I know you should not use a for loop in Forth at all. This is just for an easy example).
In the end it turned out that you have to write loops as one-liners in order to ensure their correct execution. So doing
: foo [ 10 [FOR] ] 1 [ [NEXT] ] ;
instead works as intended. Running see foo
yields:
: foo
1 1 1 1 1 1 1 1 1 1 1 ; ok
which is exactly what I want.
Is there a way to get new lines in the word definition? The words I would like to write are way more complex, and for a presentation I would need them better formatted.
It would really be best to use an immediate word instead. For example,
: ones ( n -- ) 0 ?do 1 postpone literal loop ; immediate
: foo ( -- ten ones ) [ 10 ] ones ;
With SEE FOO
resulting in the same as your example. With POSTPONE
, especially with Gforth's ]] .. [[
syntax, the repeated code can be as elaborate as you like.
A multiline [FOR]
would need to do four things:
Use REFILL
to read in subsequent lines.
Save the read-in lines, because you'll need to evaluate them one by one to preserve line-expecting parsing behavior (such as from comments: \
).
Stop reading in lines, and loop, when you match the terminating [NEXT]
.
Take care to leave >IN right after the [NEXT]
so that interpretation can continue normally.
You might still run into issues with some code, like code checking SOURCE-ID
.
For an example of using REFILL to parse across multiple lines, here's code from a recent posting from CLF, by Gerry:
: line, ( u1 caddr2 u2 -- u3 )
tuck here swap chars dup allot move +
;
: <text> ( "text" -- caddr u )
here 0
begin
refill
while
bl word count s" </text>" compare
while
0 >in ! source line, bl c, 1+
repeat then
;
This collects everything between <text>
and a </text>
that's on its own line, as with a HERE document, while also adding spaces. To save the individual lines for [FOR]
in an easy way, I'd recommend leaving 0 as a sentinel on the data stack and then drop SAVE-MEM
'd lines on top of it.