In which I try to unify the defining expressions.
There are a number of ways to add words to the dictionary. These include: :
, create
, constant
, and variable
. It seems to me that the “primitive” should really be to just add the word to the dictionary and then each of the above words can be defined in terms of other words. For example :
creates a new word in the dictionary and then goes into compile mode and we already have a word to do that: ]
. create
, on the other hand, starts a definition, aligns the data space pointer and copies it to the word’s data field. It then sets the definition of the word to do a >body
followed by two .nop
s.
The .startDefinition
word whose name was :
has now been changed so that it no longer sets the state to .compiling
. All it does is fly the interpreter into the .needsWord
state and, when the word is supplied, starts a new definition and flips the state back to whatever it was before. :
is then defined in terms of .startDefinition
and ]
(the latter puts the machine into .compiling
state. The definition of :
is a bit tricky, because we can’t define it using :
. So, we effectively hand compile its definition, which is only two words anyway. Here it is:
.startDefinition : ( Need to bootstrap : )
\(CompiledWord.startDefinition.rawValue) compile,
\(CompiledWord.enterCompilingState.rawValue) compile,
In the switch
for executing primitives, .startDefinition
now has the almost identical semantics to all the other primitives that need a word name, so we can merge the cases.
create
is a little more difficult. What does it do apart from create a definition?
- align the data space pointer
- copy the data space pointer to the data field of the current definition
- create a body for the current word that retrieves the data field for the currently executing word (which is the one that is currently being defined)
For generality, there are three new primitives:
>datafield ( xt a-addr -- )
copies the top word to the data field of the execution token that is the second word on the stack
.definingWordNumber> ( -- xt )
puts the execution token for the currently being defined word on the stack.
.executingWordNumber> ( -- xt )
puts the execution token for the currently executing word on the stack.
With these three new primitives, we can eliminate create
as a primitive. That may not seem like a saving, but these primitives are much more basic and seem less like magic.
The code with create
and :
as non primitives is tagged blog-1306-1.
constant
is simpler than create
. It’s the same principle, but we simple append the code that pushes the current stack top (as of defining the word) onto the stack.
variable
is simpler still: it can be defined entirely in terms of create
i.e
: variable create 0 , ;
The code for these changes is tagged blog-1306-2.