> > Ruvim
> Great ! :)
>
> thank's a lot
Here is code that brings ANS-Forth up to the level of Forth-83 (see the
SET-CONTEXT word that does what storing a vocno into CONTEXT did
in Forth-83). There are other features provided. This is from my novice package.
----------------------------------------------------------------------------------------------------------------
\ ******
\ ****** Some word-list stuff.
\ ******
: set-forth ( -- ) \ sets default configuration
only forth definitions ;
: <get-context> ( -- wid ) \ like CONTEXT @ in Forth-83 (ANS-Forth already provides GET-CURRENT)
get-order dup 1 < abort" *** GET-CONTEXT given empty search-order ***"
over >r \ r: -- top-wid
0 do drop loop \ --
r> ;
: <push-context> { wid -- }
get-order
wid swap 1+ \ put WID on top of whatever is there
set-order ;
\ <PUSH-CONTEXT> always pushes WID, even if WID is already the 1st. It has to be consistent in always pushing, so <POP-CONTEXT> can pop what was pushed.
: <pop-context> ( -- wid ) \ undo PUSH-CONTEXT and return the wid
get-order dup 1 < abort" *** POP-CONTEXT given empty search-order ***"
swap >r 1-
set-order
r> ;
: <drop-context> ( -- )
<pop-context> drop ;
\ <GET-CONTEXT> <PUSH-CONTEXT> <POP-CONTEXT> and <DROP-CONTEXT> don't take into consideration LOCALVARS# being in the way.
\ VFX pushes a wid called LOCALVARS onto the search order in colon words that have locals, then pops it off again at the semicolon.
\ It is in the way. If you set the 1st value to a replacement wid, you will replace LOCALVARS rather than the wid you thought you were replacing (which is now 2nd).
\ This is a gross violation of the ANS-Forth standard (13.3.3-1):
\ "...if the Search-Order word set is present, local identifiers shall always be searched before any of the word lists in any definable search order,
\ and none of the Search-Order words shall change the locals’ privileged position in the search order."
\ Note: Stephan Pelc fixed the bug mentioned above in version 4.71.3523 of Oct.8,2014.
\ The following definition of SET-CONTEXT works around the bug in VFX, and will also work in Forths that don't have the bug.
false value localvars# \ this is the wid that is 1st in the search-order inside of colon words that have local variables
marker temporary
false value expected# \ this is the wid that we are expecting to be 1st
: fill-localvars# ( -- ) \ this fills <LOCALVARS> at compile-time for use by <SET-CONTEXT> --- it doesn't do anything at run-time
true abort" *** FILL-LOCALVARS# is not to be run, it fills LOCALVARS# at compile-time ***"
[ <get-context> to expected# ]
1 2 3 locals| x y z |
[
<get-context> expected# <> [if]
<pop-context> to localvars#
<get-context> expected# <> [if] .( *** FILL-LOCALVARS# can't find EXPECTED# ***) abort [then]
localvars# <push-context> [then]
] ;
\ FILL-LOCALVARS# doesn't have to run --- it fills LOCALVARS# at compile-time.
temporary \ discard this code that fills LOCALVARS# at compile-time --- it is never needed again
: push-underneath { wid -- } \ push WID underneath whatever is 1st so WID becomes 2nd, leaving 1st as 1st
<pop-context> \ hold 1st
<get-context> wid <> if
wid <push-context> then \ don't push WID on top of itself (if WID was 2nd originally)
<push-context> ; \ push 1st back on top
: replace-1st ( wid -- )
push-underneath <drop-context> ; \ use PUSH-UNDERNEATH so WID is not duplicated if it already 2nd
: <set-context> { wid anchor -- }
<get-context> anchor = if \ if ANCHOR is 1st
wid anchor = if exit then \ WID is already 1st, so we are done
wid <push-context> \ push WID on top of ANCHOR, rather than replace ANCHOR
exit then
<get-context> localvars# = if \ if LOCALVARS# is 1st
<pop-context> \ -- localvars#
<get-context> anchor = if \ if ANCHOR is 2nd
wid <push-context> \ push WID on top of ANCHOR, rather than replace ANCHOR
else
wid replace-1st then \ else, replace 2nd with WID
<push-context> \ restore LOCALVARS# as 1st
exit then
wid replace-1st ; \ 1st was neither ANCHOR nor LOCALSVAR#, so we just replace 1st with WID (now GET-CONTEXT will give us WID)
: set-context ( wid -- )
forth-wordlist <set-context> ;
\ FORTH-WORDLIST SET-CONTEXT would do the same thing that FORTH does.
\ The following PUSH-CONTEXT POP-CONTEXT and DROP-CONTEXT take into account LOCALVARS#.
\ Use xxx PUSH-CONTEXT rather than ALSO xxx SET-CONTEXT because everything goes haywire if the ANCHOR is the 1st wid.
\ All in all, ALSO is a screw-ball idea because it involves making a duplicate on the search-order, which makes no sense.
\ Forth is supposed to be context-free, but ALSO only makes sense when it is followed by SET-CONTEXT (but not when the anchor is 1st).
\ In this 1993 comp.lang.forth thread:
https://groups.google.com/forum/#!topic/comp.lang.forth/olO-VHXJa1Q
\ Ray Duncan (who sold UR/Forth back then), described ONLY/ALSO as "severely brain-damaged."
\ Apparently he had zero influence over ANS-Forth design though, because he gave up on Forth after ANS-Forth came out in 1994.
: get-context ( -- wid )
<get-context> \ -- 1st
dup localvars# = if drop \ --
<pop-context> <get-context> \ -- 1st 2nd
swap <push-context> then ; \ -- 2nd
: definitions ( -- ) \ the VFX version of DEFINITIONS has a bug in that it doesn't take LOCALVARS into consideration
get-context set-current ;
: push-context { wid -- }
<get-context> localvars# = if
<pop-context> wid <push-context> \ -- 1st
<push-context> \ --
else
wid <push-context> then ;
: pop-context ( -- wid ) \ undo PUSH-CONTEXT and return the wid
<pop-context> \ -- 1st
dup localvars# = if
<pop-context> \ -- 1st 2nd
swap <push-context> then ; \ -- 2nd
: drop-context ( -- )
pop-context drop ;
char & comment \ this is for testing the word-list stuff
wordlist constant test1# \ used only by TEST that follows
wordlist constant test2# \ used only by TEST that follows
: test ( -- ) \ this tests SET-CONTEXT
[ cr .( TEST1# = ) test1# u. ]
[ cr .( TEST2# = ) test2# u. ]
[ cr .( FORTH-WORDLIST = ) forth-wordlist u. ]
[ set-forth order ]
[ get-context cr .( context = ) u. order ]
[ forth-wordlist set-context order ]
[ test1# set-context order ]
1 2 3 locals| x y z | [ order ]
[ get-context cr .( context = ) u. order ]
[ test1# push-context order ]
[ drop-context order ]
[ test1# set-context order ]
[ test2# set-context order ]
[ test1# push-context order ]
[ drop-context order ]
;
order
set-forth
: test-forth ( -- ) \ this tests FORTH that is supposed to be the same as FORTH-WORDLIST SET-CONTEXT
[ set-forth cr .( test-forth) order ]
[ forth order ]
1 2 3 locals| x y z | [ order ]
[ forth order ] \ this fails under VFX
;
order
set-forth
&
VFX? [if] \ We have >NAME so error-checking will be done. This code may work in other ANS-Forth systems as well.
: in-wordlist? ( xt wid -- 0|1|-1 ) \ we return 0 for not-found, 1 for immediate and -1 for non-immediate
over >name count rot search-wordlist \ -- xt 0 | xt found-xt 1 | xt found-xt -1
>r
r@ 0= if drop r> exit then \ it wasn't found
= if r> exit then \ it was found and it is the same
r> drop 0 ; \ it was found but it wasn't the same (it had the same name, but was a different word)
[else] \ We can't be sure that >NAME will be available except in VFX, so error-checking won't be done.
: in-wordlist? ( xt wid -- 0|1|-1 )
true abort" *** IN-WORDLIST? is not available except in VFX" ;
immediate
[then]
\ Problems may arise when using PUSH-CONTEXT and POP-CONTEXT if two wids are supposed to have words of the same name.
\ The user does a PUSH-CONTEXT of one of the wids, but the other wid is already in the search-order.
\ The user then looks up a word name. Unfortunately, the wid on top that is supposed to have that name doesn't have it, and so the name is found in the other wid.
\ Because of this problem, it is best to check every xt with IN-WORDLIST? to make sure that it was defined in the expected word-list.
\ Unfortunately, IN-WORDLIST? doesn't always work because it depends upon >NAME that is not ANS-Forth (some ANS-Forth systems, such as VFX, have it though).
: this-before-that? { this that | this-first? that-first? -- ? }
false to this-first?
false to that-first?
get-order 0 ?dup do
dup this = if that-first? 0= if true to this-first? then then \ don't set THIS-FIRST? if we have already found THAT
that = if this-first? 0= if true to that-first? then then \ don't set THAT-FIRST? if we have already found THIS
loop
this-first? ;
\ THIS-BEFORE-THAT? may be more useful than GET-CONTEXT because it searches the entire search-order.
----------------------------------------------------------------------------------------------------------------