Defining Forth

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 .nops.

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.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.