30e43b5003
FossilOrigin-Name: 1c6eca0832d1523e9756f4c24b1a5407088b942803aabb8152994ce211977799
106 lines
3 KiB
Forth
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
|
|
prefix 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---
|
|
:prefix:: 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 ;
|
|
> }}
|