retroforth/example/reforth.retro
crc 6a4aaf8eac prefix: namespace is now sigil:, rename words, update examples, update docs
FossilOrigin-Name: 25cf19660ab7728d7bfee2722ea826a8a438faf92b2504b28d922d2958906aed
2021-03-30 11:58:25 +00:00

106 lines
3 KiB
Forth

Reforth by Sean Pringle has some interesting concepts. This implements
some of these within RETRO.
# Local Variables
> Supporting random numbers of local variables in Forth makes for
> complex handling of the return stack at run-time, or a complex
> compiler, or both.
>
> Reforth supports precisely two local variables: at and my
>
> at is designed to hold an address and is set with at!. It is
> like the A register from Chuck's later work, except it does
> not have to be saved and restored when calling words that also
> use it for their own purposes. The words @+ and !+ use and
> increment it automatically. It also works well (and importantly,
> reads well) as a pointer for relative addressing.
>
> my is a general purpose bucket set with my!. It fills the same
> sort of role as >r, r@, and r>, but is faster, uses less code,
> and doesn't need to be cleaned up.
I haven't implemented anything using these yet, but here's a
quick implementation. (The actual preseve/restore using the
`v:preserve` combinator is done a bit later)
~~~
'At var
'My var
:at! !At ;
:at @At ;
:my! !My ;
:my @My ;
~~~
# Subwords
> Word definitions may be nested.
>
> : hiphip ( -- )
> : cheer "hip hip, hooray!" type ;
> cheer cheer cheer
> ;
> Ok, so one could do the above with a loop. But there is more to it:
>
> Sub-words are private and scoped so they are only visible in the
> current definition, avoiding namespace pollution. Above, one could
> not call cheer outside the definition of hiphip.
>
> Smaller definitions are a good thing for code clarity and maintenance.
> Go ahead and break up those long definitions into sub-words. Try using
> a sub-words instead of a nested code blocks.
>
> Private sub-words solve half the problem with vocabularies. More on
> this later.
I'm not comfortable with this as it does add some overhead. The colon
sigil is extended to add a jump around word entries, so that nesting
can work properly. This also extends the colon and semicolon words to
add support for preserving the `my` and `at` variables.
~~~
{{
'Scope var
'Nest var
:def
here n:inc #0 compile:jump swap
d:create &class:word reclass
@Nest n:zero? [ @Dictionary !Scope ] if &Nest v:inc
@Compiler &Compiler v:on '&At_[_&My_[ s:evaluate ;
:-def
']_v:preserve_]_v:preserve s:evaluate compile:ret
!Compiler here swap store
&Nest v:dec @Nest n:zero? [ @Scope !Dictionary ] if ; immediate
---reveal---
:sigil:: def ; immediate
:; |-def -def immediate
#0 !Nest
}}
~~~
Sean also extends this further, adding in support for using the
subwords as a vocabulary of sorts. I'm *not* implementing this in
RETRO as I rather dislike it. On the whole, I'd rather throw the
words into a namespace, such that:
> :hiphip (-)
> :cheer 'hip_hip,_hooray! s:put nl ;
> cheer cheer cheer
> ;
Would be:
> :hiphip:cheer 'hip_hip,_hooray! s:put nl ;
>
> :hiphip (-)
> hiphip:cheer hiphip:cheer hiphip:cheer ;
Or, if the `cheer` isn't needed later:
> {{
> :cheer 'hip_hip,_hooray! s:put nl ;
> ---reveal---
> :hiphip (-) cheer cheer cheer ;
> }}