Colon definitions and compiler
The last story marked the end of epic 2, I decided to have another retro in which I read the team the riot act about sticking to standards and not trying to gaslight their glorious leader.
I also flagged up that we’d agreed to split the massive monolithic test thread getting antforth.asm but done precisely bugger all about it. This resulted in us inserting a new story (3.0) before doing any other epic 3 work, and I got them to agree that any new tests should be in Forth, using our REPL, wherever possible.
With all that out of the way, we can move onto story 3.1 which is another exciting milestone: the ability to define our own “colon words” in AntForth!
In this sprint we will gain:
:to let us start defining a colon word, and;to let us stack_ops[and]to let us switch between compile and interpret modes in a colon word definitionLITERALto allow us to compile literal values into code word definitions- the ability to call new words that we define
- error handling in compile mode
These will be a pretty hard test of our hasing and dictionary handling code, so if there are any gremlins remaining in there this story will almost certainly shake them out.
compiler.asm
Previously this file was an empty stub, now it’s full of meaty goodness. First we
have the mighty : word, which is what let’s us define new words. Its implementation
is too big to include here, but basically it:
- parses the name of the new word
- creates a new dictionary entry for it in the next free slot
- sets the SMUDGE bit (more on this later)
- sets the CFA for the new word, which will be
JP DOCOL
; has a much simpler implementation:

Here we turn the SMUDGE bit off, add EXIT to the word list in the parameter field of
our new word, and switch back to interpret mode.
[ and ] look like this:

They’re pretty simple: they just set STATE accordingly. Their application effectively
allows you to use Forth as a pre-processor for itself, which is pretty cool.
LITERAL looks like this:

This allows you to compile into your word a value that was dynamically evaulated,
and hence it’s usually used with [ and ], for example:
: calculate-result ( -- n )
[ 25 4 * ] LITERAL ; \ 100 is computed at compile-time and compiled into the word
(optimistically using a “Forth” tag in that code-fence block, let’s see how well that works out!)
SMUDGE bit?
Every word in the dictionary has a SMUDGE bit. This bit is set when the word is in the process of being defined, and cleared when that word’s definition has been completed.
SMUDGE controls whether a word is visible to FIND: FIND cannot see smudged
words.
What this means in practice is, you can re-define a word, and in your new definition call the old definition, without it all going a bit Rick and Morty.
Here’s an example:

Here I define DUP, then redefine DUP using the previous definition of
DUP! Come on, you gotta love Forth! :-)
outer_interpreter.asm
A tonne of code got added to the outer-interpreter to introduce the concept of compilation. Basically the parser needs to add parsed words to the current definition in progress, rather than evaluating them immediately. It also has to suppress its usual “ok” output until we’re back in interpret mode.
bootstrap.asm
This is another empty stub that got fleshed out. In here we’re storing all words
that are defined with DEFWORD - which is the assembly language equivalent of
:. Claude’s implemented NEGATE, ABS, MIN, and MAX for us, which is a
pretty random selection but I guess the goal was to demonstrate DEFWORD in
action as it hasn’t been available until now, so fair enough.
I’ll just show you NEGATE:

The implementation is pretty obvious, but some of the plumbing might not be.
DEFWORD creates a dictionary entry for us, handles the hashing, inserts
the code-field JP DOCOL and then returns. The calling code then appends
the body. The w_NEGATE_cd EQU w_NEGATE_body -3 business is to get the
address (CFA) of the CF, i.e. the JP DOCOL.
Note that these are COLON words not CODE words, so some of them might
have benefited from IF conditionals…but unfortunately we haven’t
implemented those yet, so it’s fallen back to the lower-level ?BRANCH.