Digest #35 2018-06-07
Contributions
My email address was withdrawn from use by EE about a year ago and I no longer receive the digest. I can find no way on this website to change my email address. Can you do it for me?
Change it to gwj@qlikz.org (was gerry@jackson9000.fsnet.co.uk)
Or must I re-register under a different user name and let the old one fester?
Better still add a way of doing it in 'Settings' next to change password
Replies
I can see the point of centralising the optimising of default words in COMPILE,
because that allows the action to take place within a definition, apart from the compiling loop. If no optimisation is set, it compiles a call, which results in code that produces the same output, if more slowly.
But what should xt NDCS,
do?
In particular, what should it do if presented with an xt that has no explicit compiling action?
It would seem most sensible to compile it - which is after all 'performing its compilation semantics'. But in that case, the whole of the compiler, form the point of obtaining a valid token, is bundled in the one word.
NDCS,
is equivalent to NAME>COMPILE EXECUTE
The more import question is: does this token have an explicit compiling action set, and if so, what is it? With name tokens, that is simple:
: EXPLICIT? ( nt -- int-xt 0 | comp-xt -1 )
NAME>COMPILE ['] EXECUTE = ;
amforth has FIND-NAME since ever and FIND-NAME-IN under the name SEARCH-NAME following SEARCH-WORDLIST ( c-addr u wid -- 0 | xt 1 | xt -1 ).
If I've got this right, a definition of FIND
using FIND-NAME
:
: EXPLICIT? ( nt -- int-xt 0 | comp-xt -1 )
NAME>COMPILE ['] EXECUTE = ;
: FIND dup count parse-name find-name dup IF
( c-addr nt ) nip dup name>interpret swap
( int-xt nt ) explicit? IF
( int-xt comp-xt ) state @ IF nip ELSE drop THEN
1 ELSE
nip -1 THEN ;
Should be:
: EXPLICIT? ( nt -- int-xt 0 | comp-xt -1 )
NAME>COMPILE ['] EXECUTE = ;
: FIND dup count parse-name find-name dup IF
( c-addr nt ) nip dup name>interpret swap
( int-xt nt ) explicit? IF
( int-xt comp-xt ) state @ IF nip ELSE drop THEN
1 ELSE
drop -1 THEN
THEN ;
Why not have FIND-NAME return both the interpretation and compilation XTs simultaneously, then you can simply DROP or NIP to keep the XT that you're interested in:
FIND-NAME ( c-addr u -- compXT|0 intXT|0 )
Now, we don't need NAME>INTERPRET and NAME>COMPILE at all.
Additionally, NAME>INTERPRET and NAME>COMPILE are erroneously named, since you don't pass a name to them. The "name" (in the form of addr u) is passed into FIND-NAME. NAME>INTERPRET and NAME>COMPILE both take an execution token, so they should be named XT>INTERPRET and XT>COMPILE.
However, as noted above, it seems much simpler to have FIND-NAME return both tokens, and the programmer DROP or NIP as appropriate.
Regards
Mark Wills
NAME>COMPILE is a standard way to get at the compilation semantics, and it works for all words. There is no need for NDCS, as a standard interface. Some systems may have it as internal factor, however.
But that's for a discussion on replacing FIND, and is not relevant to the present proposal on clarifying FIND.
ChangeLog
2018-05-29: Specify FIND for words without interpretation semantics, and loosen it for TO IS ACTION-OF. Added Remarks section for a rationale of these additions.
2018-05-23: Initial version
Problem
The existing specification of FIND is unclear wrt what xts are returned under what conditions. It also uses a different notion of immediacy from the one in the Definition of Terms. From the rationale of FIND, it is obvious that cmForth inspired the idea that two different xts can be returned. The rationale of COMPILE, shows that the intention is that FIND can be usable for the user-defined text interpreter. But FIND as specified does not guarantee that. This proposal would fix this problem; it is also phrased in a way that includes systems like cmForth and Mark Humphries' system.
Proposal
Replace the text in the specification of FIND with:
Find the definition named in the counted string at c-addr. If the definition is not found, return c-addr and zero. If the definition is found, return xt 1 or xt -1. The returned values may differ between interpretation and compilation state. In interpretation state, EXECUTEing the returned xt performs the interpretation semantics of the word. In compilation state, the returned values represent the compilation semantics: if xt 1 is returned, then EXECUTEing xt performs the compilation semantics; if xt -1 is returned, then COMPILE,ing xt performs the compilation semantics.
In interpretation STATE, FIND may produce c-addr 0 if the definition has no interpretation semantics; if it produces xt 1 or xt -1, the returned xt represents a system-dependent action.
If the definition if for a word for which POSTPONE is ambiguous, it is ambiguous to perform the xt returned by FIND in a STATE different from the STATE during FIND.
In 4.1.2 Ambiguous conditions, add the ambiguous condition above, and remove "6.1.1550 FIND" from
attempting to obtain the execution token, (e.g., with 6.1.0070 ', 6.1.1550 FIND, etc. of a definition with undefined interpretation semantics;
Remarks
The removal of FIND from the clause in 4.1.2 ensures that we can text-interpret (in compile STATE) words without interpretation semantics, such as IF. The description of the behaviour of FIND for these words in interpretation STATE allows implementations that do not find such words, implementations that return the xt for an error, implementations that return the xt for the compilation semantics, and implementations that return the xt for some system-specific interpretation semantics.
The ambiguous condition allows STATE-smart implementations of TO, IS and ACTION-OF (as Forth-94 and Forth-2012 do).
Note that this does not allow STATE-smart implementations of words without interpretation semantics (e.g., IF), but then, that's already forbidden by POSTPONE and [COMPILE].
I would implement FIND
using FIND-NAME
as follows (untested):
: find ( c-addr -- c-addr 0 | xt 1 | xt -1 )
dup find-name dup if
nip state @ if
name>compile ' execute = if 1 else -1 then
else
name>interpret 1
then
then ;
This assumes that NAME>COMPILE returns the xt of EXECUTE or that of COMPILE, on the TOS. If NAME>COMPILE can also return other xts on the TOS, FIND may need to be implemented in a different way. Whether interpretive FIND returns 1 or -1 does not play a role for the classical text interpreter. However, if other applications need it, one might extract the proper value from NAME>COMPILE; an application that relies on the flag returned in interpret state is also likely to rely on the corresponding xt as representing a part of the compilation semantics, and that does not work for all words on all systems (it might be good enough for a specific system or a specific set of words, though).
As for a word that returns an interpretation xt and a compilation xt: It has no existing practice, in contrast to FIND-NAME. It's also bad factoring, because it does two things at once while we usually need only one of them. The wisdom of having a name token (nt) and factoring these operations into FIND-NAME, NAME>INTERPRET and NAME>COMPILE is demonstrated by the introduction of TRAVERSE-WORDLIST, which also produces nts, that then can be processed with NAME>INTERPRET. Another problem of the suggested word is that it returns just one xt for the compilation semantics, which would require a costly production of these xts for many words. Finally, such a word would also be harder to write and read, because both writer and reader would have to look up how NIP and DROP correspond to interpretation and compilation semantics.
Editing suggestion:
In interpretation state, EXECUTEing the returned xt performs the interpretation semantics of the word. If the definition has no interpretation semantics FIND may produce c-addr 0; if it produces xt 1 or xt -1, the returned xt represents a system-dependent action.
In compilation state, the returned values represent the compilation semantics: if xt 1 is returned, then EXECUTEing xt performs the compilation semantics; if xt -1 is returned, then COMPILE,ing xt performs the compilation semantics.
If the definition is for a word for which POSTPONE is ambiguous, it is ambiguous to perform the xt returned by FIND in a STATE different from the STATE during FIND.
NAME >INTERPRET returns 0 for a compile-only word that the system has marked as such. That's not a valid output for FIND.
That does seem to imply that in any interface which sets a secondary NDCS xt, that xt should represent the whole of the compilation semantics.
To cover that (but with the other assumptions as above), FIND
would look as follows:
: find ( c-addr -- c-addr 0 | xt 1 | xt -1 )
dup find-name dup if
state @ if
nip name>compile ['] execute = if 1 else -1 then
else
name>interpret dup if nip 1 then
then
then ;
Yes, that would be the sub-xt ['] EXECUTE case. NAME>COMPILE could also return sub-xt ['] COMPILE,, but at least for the currently standardized dual-semantics words (S" S\" TO IS ACTION-OF
), this would be wrong (COMPILE, must not parse).
It's not mandatory, though, only pretty compelling: One can think of clever ways to implement FIND in systems where NAME>COMPILE works differently, but AFAICS, these ways only increase complexity without offering an advantage, and there is a danger of introducing gotchas in corner cases.
Viewed differently: You have to have a find-comp-xt to be returned by FIND anyway, so you can just return it (and ['] EXECUTE or (unlikely) ['] COMPILE,) with NAME>COMPILE instead of returning something else. BTW, for a word X for which NAME>COMPILE would return something else, the find-comp-xt would be of the following word (and it would go with ['] EXECUTE):
:noname postpone X ;
I now have an NDCS version of VFX Forth that passes all of Gerry Jackson's test suite, plus the previous tests for [COMPILE]. The NDCS VFX works fine with FIND. The sole reason for FIND-NAME is to allow for multiple words with the same xt, i.e. the nt identifies a named word and xts identify the actions. We have to recognise that people with xt-based systems are not going to abandon them, they will simply use FIND-WORD or some such that returns an xt. I really feel that we should slow down and resolve issues such as NDCS words before we redesign the text interpreter. Given recognisers, this may be too late, but we need to work our way through the issues before we make changes that we may regret. Note that the compilation issues caused by NDCS ("non-default compilation semantics") have taken 20+ years to emerge.