In which I try to unify the defining expressions.
There are a number of ways to add words to the dictionary. These include:
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
.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
] (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,
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
: 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
: variable create 0 , ;
The code for these changes is tagged blog-1306-2.