+ You can see that >DFA is easily defined in FORTH just by adding 4 to the result of >CFA.
+*/
+
+ defword ">DFA",4,,TDFA
+ .int TCFA // >CFA (get code field address)
+ .int INCR4 // 4+ (add 4 to it to get to next word)
+ .int EXIT // EXIT (return from FORTH word)
+
+/*
+ COMPILING ----------------------------------------------------------------------
+
+ Now we'll talk about how FORTH compiles words. Recall that a word definition looks like this:
+
+ : DOUBLE DUP + ;
+
+ and we have to turn this into:
+
+ pointer to previous word
+ ^
+ |
+ +--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT |
+ +---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+
+ ^ len pad codeword |
+ | V
+ LATEST points here points to codeword of DUP
+
+ There are several problems to solve. Where to put the new word? How do we read words? How
+ do we define the words : (COLON) and ; (SEMICOLON)?
+
+ FORTH solves this rather elegantly and as you might expect in a very low-level way which
+ allows you to change how the compiler works on your own code.
+
+ FORTH has an INTERPRET function (a true interpreter this time, not DOCOL) which runs in a
+ loop, reading words (using WORD), looking them up (using FIND), turning them into codeword
+ pointers (using >CFA) and deciding what to do with them.
+
+ What it does depends on the mode of the interpreter (in variable STATE).
+
+ When STATE is zero, the interpreter just runs each word as it looks them up. This is known as
+ immediate mode.
+
+ The interesting stuff happens when STATE is non-zero -- compiling mode. In this mode the
+ interpreter appends the codeword pointer to user memory (the HERE variable points to the next
+ free byte of user memory -- see DATA SEGMENT section below).
+
+ So you may be able to see how we could define : (COLON). The general plan is:
+
+ (1) Use WORD to read the name of the function being defined.
+
+ (2) Construct the dictionary entry -- just the header part -- in user memory:
+
+ pointer to previous word (from LATEST) +-- Afterwards, HERE points here, where
+ ^ | the interpreter will start appending
+ | V codewords.
+ +--|------+---+---+---+---+---+---+---+---+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL |
+ +---------+---+---+---+---+---+---+---+---+------------+
+ len pad codeword
+
+ (3) Set LATEST to point to the newly defined word, ...
+
+ (4) .. and most importantly leave HERE pointing just after the new codeword. This is where
+ the interpreter will append codewords.
+
+ (5) Set STATE to 1. This goes into compile mode so the interpreter starts appending codewords to
+ our partially-formed header.
+
+ After : has run, our input is here:
+
+ : DOUBLE DUP + ;
+ ^
+ |
+ Next byte returned by KEY will be the 'D' character of DUP
+
+ so the interpreter (now it's in compile mode, so I guess it's really the compiler) reads "DUP",
+ looks it up in the dictionary, gets its codeword pointer, and appends it:
+
+ +-- HERE updated to point here.
+ |
+ V
+ +---------+---+---+---+---+---+---+---+---+------------+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP |
+ +---------+---+---+---+---+---+---+---+---+------------+------------+
+ len pad codeword
+
+ Next we read +, get the codeword pointer, and append it:
+
+ +-- HERE updated to point here.
+ |
+ V
+ +---------+---+---+---+---+---+---+---+---+------------+------------+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + |
+ +---------+---+---+---+---+---+---+---+---+------------+------------+------------+
+ len pad codeword
+
+ The issue is what happens next. Obviously what we _don't_ want to happen is that we
+ read ";" and compile it and go on compiling everything afterwards.
+
+ At this point, FORTH uses a trick. Remember the length byte in the dictionary definition
+ isn't just a plain length byte, but can also contain flags. One flag is called the
+ IMMEDIATE flag (F_IMMED in this code). If a word in the dictionary is flagged as
+ IMMEDIATE then the interpreter runs it immediately _even if it's in compile mode_.
+
+ This is how the word ; (SEMICOLON) works -- as a word flagged in the dictionary as IMMEDIATE.
+
+ And all it does is append the codeword for EXIT on to the current definition and switch
+ back to immediate mode (set STATE back to 0). Shortly we'll see the actual definition
+ of ; and we'll see that it's really a very simple definition, declared IMMEDIATE.
+
+ After the interpreter reads ; and executes it 'immediately', we get this:
+
+ +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT |
+ +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
+ len pad codeword ^
+ |
+ HERE
+ STATE is set to 0.
+
+ And that's it, job done, our new definition is compiled, and we're back in immediate mode
+ just reading and executing words, perhaps including a call to test our new word DOUBLE.
+
+ The only last wrinkle in this is that while our word was being compiled, it was in a
+ half-finished state. We certainly wouldn't want DOUBLE to be called somehow during
+ this time. There are several ways to stop this from happening, but in FORTH what we
+ do is flag the word with the HIDDEN flag (F_HIDDEN in this code) just while it is
+ being compiled. This prevents FIND from finding it, and thus in theory stops any
+ chance of it being called.
+
+ The above explains how compiling, : (COLON) and ; (SEMICOLON) works and in a moment I'm
+ going to define them. The : (COLON) function can be made a little bit more general by writing
+ it in two parts. The first part, called CREATE, makes just the header:
+
+ +-- Afterwards, HERE points here.
+ |
+ V
+ +---------+---+---+---+---+---+---+---+---+
+ | LINK | 6 | D | O | U | B | L | E | 0 |
+ +---------+---+---+---+---+---+---+---+---+
+ len pad
+
+ and the second part, the actual definition of : (COLON), calls CREATE and appends the
+ DOCOL codeword, so leaving:
+
+ +-- Afterwards, HERE points here.
+ |
+ V
+ +---------+---+---+---+---+---+---+---+---+------------+
+ | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL |
+ +---------+---+---+---+---+---+---+---+---+------------+
+ len pad codeword
+
+ CREATE is a standard FORTH word and the advantage of this split is that we can reuse it to
+ create other types of words (not just ones which contain code, but words which contain variables,
+ constants and other data).
+*/
+
+ defcode "CREATE",6,,CREATE
+
+ // Get the name length and address.
+ pop %ecx // %ecx = length
+ pop %ebx // %ebx = address of name