# 11 Extending the compiler: Defining words and Compiling words

In comparison with conventional languages, Forth's compiler is completely backwards. Traditional compilers are huge programs designed to translate any foreseeable, legal combination of available operators into machine language. In Forth, however, most of the work of compilation is done by a single definition, only a few lines long. Special structures like conditionals and loops are not compiled by the compiler but by the words being compiled (IF, DO, etc.)

Lest you scoff at Forth's simple ways, notice that Forth is unique among languages in the ease with which you can extend the compiler. Defining new, specialized compilers is as easy as defining any other word, as you will soon see.

When you've got an extensible compiler, you've got a very powerful language!

## Just a question of time

Before we get fully into this chapter, let's review one particular concept that can be a problem to beginning Forth programmers. It's a question of time.

We have used the term "run time" when referring to things that occur when a word is executed and "compile time" when referring to things that happen when a word is compiled. So far so good. But things get a little confusing when a single word has both a run-time and a compile-time behavior.

In general there are two classes of words which behave in both ways. For purposes of this discussion, we'll call these two classes "defining words" and "compiling words."

A defining word is a a word which, when executed, compiles a new definition. A defining word specifies the compile-time and run-time behavior of each member of the "family" of words that it defines. Using the defining word CONSTANT as an example, when we say

    	      80 CONSTANT MARGIN

we are executing the compile-time behavior of CONSTANT; that is, CONSTANT is compiling a new constant-type dictionary entry called `MARGIN` and storing the value 80 into its parameter field. But when we say

    	      MARGIN

we are executing the run-time behavior of CONSTANT; that is, CONSTANT is pushing the value 80 onto the stack. We'll pursue defining words further in the next few sections.

The other type of word which possesses dual behavior is the "compiling word." A compiling word is a word that we use inside a colon definition and that actually does something during compilation of that definition.

One example is the word .", which at compile time compiles a text string into the dictionary entry with the count in front, and at run time types it. Other examples are control-structure words like IF and LOOP, which also have compile-time behaviors distinct from their run-time behaviors. We'll explore compiling words after we've discussed defining words.

## How to Define a Defining Word

Here are the standard Forth defining words we've covered so far:

    	   :
    	   VARIABLE
    	   2VARIABLE
    	   CONSTANT
    	   2CONSTANT
    	   CREATE

What do they all have in common? Each of them is used to define a set of words with similar compile-time and run-time characteristics.

And how are all these defining words defined? First we'll answer this question metaphorically.

Let's say you're in the ceramic salt-shaker business. If you plan to make enough salt shakers, you'll find it's easiest to make a mold first. A mold will guarantee that all your shakers will be of the same design, while allowing you to make each shaker a different color. In making the mold, you must consider two things:

1. How the mold will work. (E.g., how will you get the clay into and out of the mold without breaking the mold or letting the seams show?)
2. How the shaker will work. (E.g., how many holes should there be? How much salt should it hold? Etc.)

To bring this analogy back to Forth, the definition of a defining word must specify two things: the compile-time behavior and the run-time behavior for that type of word.

Hold that thought a moment while we look at the most basic of the defining words in the above list: CREATE. At compile time, CREATE takes a name from the input stream and creates a dictionary heading for it.

7 | E | X | A | M | P | L | E
link
execution token
(body)

At run time, CREATE pushes the body address of EXAMPLE onto the stack.

What happens if we use CREATE inside a definition? Consider this example, which is the definition for VARIABLE:

    	   : VARIABLE  CREATE  0 , ;

When we execute VARIABLE as in

    	   VARIABLE ORANGES

We are indirectly using CREATE to create a dictionary head with the name `ORANGES` and an xt that points to CREATE's run-time code. Then we are allotting a cell for the variable itself (with "0 ,").

Since the run-time behavior of a variable is identical to that of a word defined by CREATE, VARIABLE does not need to have run-time code of its own, it can use CREATE's run-time code.

How do we specify a different run-time behavior in a defining word? By using the word DOES>, as shown here:

    	   : DEFINING-WORD  CREATE  (compile-time operations)
    	                    DOES>   (run-time operations) ;

To illustrate, the following could be a valid definition for CONSTANT (although in fact CONSTANT is usually defined in machine code):

    	   : CONSTANT  CREATE  ,  DOES> @ ;

To see how this definition works, imagine we're using it to define a constant named `TROMBONES`, like this:

    	   76 CONSTANT TROMBONES

compile-time portion |
`CREATE` | Create a new dictionary entry (e.g., `TROMBONES`)
`,` | Compiles the value (e.g., 76) for the constant from the stack into the constant's parameter field.
run-time portion |
`DOES>` | Marks the end of the compile-time behavior and the beginning of the run-time behavior. At run time, DOES> will leave the body address of the word being defined on the stack.
`@` | Fetches the contents of the constant, using the body address that will be on the stack at run time.

The words that precede DOES> specify what the mold will do; the words that follow DOES> specify what the product of the mold will do.

`DOES>` | run time: ( -- addr ) | Used in creating a defining word; marks the end of its compile-time portion and the beginning of its run-time portion. The run-time operations are stated in higher-level Forth. At run time, the body address of the defined word will be on the stack.

## Defining Words You Can define Yourself

Here are some examples of defining words that you can create yourself.

Recall that in our discussion of "String Input Commands" in Chap. 10, we gave an example that employed character-string arrays called `NAME`, `EYES`, and `ME`. Every time we used one of these names, we followed it with a character count. In the input definition, we wrote

          ... PAD NAME 14 MOVE

and in the output definition we wrote

          ... NAME 14 -TRAILING TYPE ...

and so on.

Let's eliminate the count by creating a defining word called `CHARACTERS`, whose product definitions will leave the address and count on the stack when executed.

We'll use it like this: if we say

    	20 CHARACTERS ME

we will create an array called `ME`, with twenty characters available for the character string.

When we execute `ME`, we'll get the address of the array and the count on the stack. Now we can write

    	PAD ME MOVE

instead of

    	PAD ME 20 MOVE

or

    	ME -TRAILING TYPE

instead of

    	ME 20 -TRAILING TYPE

Here's how we might define `CHARACTERS`:

`: CHARACTERS` |
compile-time portion |
`CREATE` | Create a new dictionary entry (e.g., ME)
`DUP , ALLOT` | Compiles the count (e.g., twenty) into the first cell of the array for future reference. Then allots an additional twenty bytes beyond the count for the string.
run-time portion |
`DOES>` | Marks the beginning of run-time code, leaving the body address of the product-word on the stack at run-time.
`DUP` | Copies the body address.
`CELL+` | Advances the address to point past the count, to the start of the character string.
`SWAP @` | Swaps the string address with the count address and fetches the count. The stack now holds ( addr count -- ).
`;` |

We have just extended our compiler! Our new word `CHARACTERS` is a defining word that creates a data structure and procedure that we find useful. `CHARACTERS` not only simplifies our input and output definitions, it also allows us to change the length of any string, should the need arise, in one place only (i.e., where we define it).

Our next example could be useful in an application where a large number of byte (not CHAR!) arrays are needed. Let's create a defining word called `STRING` as follows:

    	: STRING   CREATE ALLOT  DOES> + ;

to be used in the form

    	30 STRING VALVE

to create an array thirty bytes in length. To access any byte in this array, we merely say:

    	6 VALVE C@

which would give us the current setting of hydraulic valve 6 at an oil-pumping station. At run time, `VALVE` will add the argument 6 to the body address left by DOES>, producing the correct byte address.

If our application requires a large number of arrays to be initialized to zero, we might include the initialization in an alternate defining word called `0STRING`:

    	: ERASED  HERE OVER  ERASE ALLOT ;

    	: 0STRING  CREATE ERASED DOES> + ;

First we define `ERASED` to ERASE the given number of bytes, starting at HERE, before ALLOTing the given number of bytes.

Then we simply substitute `ERASED` for ALLOT in our new version.

By changing the definition of a defining word, you can change the characteristics of all the member words of that family. This ability makes program development much easier. For instance, you can incorporate certain kinds of error checking while you are developing the program, then eliminate them after you are sure that the program runs correctly.

Here is a version of `STRING` which, at run time, guarantees that the index into the array is valid:

    	: STRING  CREATE  DUP , ALLOT
    	          DOES>   2DUP @ U< 0= ABORT" Range error "  + CELL+ ;

which breaks down as follows:

`DUP , ALLOT` | Compiles the count and allots the given number of bytes.
`DOES> 2DUP @` | At run time, given the argument on the stack, produces ( arg pfa arg count -- ).
`U< 0=` | Tests that the argument is not less than the maximum, i.e., the stored count. Since U< is an unsigned compare, negative arguments will appear as very high numbers and thus will also fail the test.
`ABORT" Range error "` | Check if the comparison test fails.
`+ CELL+` | Otherwise adds the argument to the body address, plus an additional cell to skip the count.

Here's another way that the use of defining words can help during development. Let's say you suddenly decide that all of the arrays you've defined with `STRING` are too large to be kept in computer memory and should be kept on disk instead. All you have to do is redefine the run-time portion of `STRING`. This new `STRING` will compute which record on the disk a given byte would be contained in, read the record into a buffer using INCLUDED, and return the address of the desired byte within the buffer. A string defined in this way could span many consecutive records (using the same technique as in Prob. 5, Chap. 10).

You can use defining words to create all kinds of data structures. Sometimes, for instance, it's useful to create multi-dimensional arrays. Here's an example of a defining word which creates two-dimensional byte arrays of given size:

| c0 | c1 | c2 | c3
--- | --- | --- | --- | ---
r0 |  |  |  |
r1 |  |  |  |
r2 |  | ? |  |
r3 |  |  |  |

    	: ARRAY	( #rows #cols -- )
    		CREATE	DUP , * ALLOT
    		DOES>	( member: row col -- addr )
    			ROT OVER @ * + +  CELL+ ;

To create an array four bytes by four bytes, we would say

    	4 4 ARRAY BOARD

To access, say, the byte in row 2, column 1, we could say

    	2 1 BOARD C@

Here's how our `ARRAY` works in general terms. Since the computer only allows us to have one-dimensional arrays, we must simulate the second dimension. While our imaginary array looks like this

| c0 | c1 | c2 | c3
--- | --- | --- | --- | ---
r0 | 0 | 1 | 2 | 3
r1 | 4 | 5 | 6 | 7
r2 | 8 | 9 | 10 | 11
r3 | 12 | 13 | 14 | 15

our real array looks like this

row# | 0 | 1 | 2 | 3
offs | 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15

If you want the address of the byte in row 2, column 1, it can be computed by multiplying your row number (2) by the number of columns in each row (4) and then adding your column number (1), which indicates that you want the ninth byte in the real array. This calculation is what members of `ARRAY` must do at run time. You'll notice that, to perform this calculation, each member word needs to know how many columns are in each row of its particular array. For this reason, `ARRAY` must store this value into the beginning of the array at compile time.

For the curious, here are the stack effects of the run-time portion of array:

Operation | Contents of stack
--- | ---
`...` | row col pfa
`ROT` | col pfa row
`OVER @` | col pfa row #cols
`*` | col pfa row-index
`+ +` | address
`CELL+` | corrected address

It is necessary to add a cell to the computed address because the first cell of the array contains the number of columns.

Our final example is the most visually exciting, if not the most useful.

    	\ Shapes, using a defining word.

    	DECIMAL

    	: star  [CHAR] * EMIT ;

    	: .row  CR 8 0 DO
    			   DUP 128 AND IF  star
    				     ELSE  SPACE
    				     THEN
    			   1 LSHIFT
    		     LOOP  DROP ;

    	: SHAPE CREATE  8 0 DO  C,  LOOP
    		DOES>	DUP 7 + DO  I C@ .row  -1 +LOOP  CR ;

    	HEX	18 18 3C 5A 99 24 24 24  SHAPE man
    		81 42 24 18 18 24 24 81  SHAPE equis
    		AA AA FE FE 38 38 38 FE  SHAPE castle
    	DECIMAL

`.ROW` prints a pattern of stars and spaces that correspond to the 8-bit number on the stack. For instance:

    	2 BASE ! ok
    	00111001 .ROW
    	  ***  * ok
    	DECIMAL ok

The defining word `SHAPE` takes eight arguments from the stack and defines a shape which, when executed, prints an 8-by-8 grid that corresponds to the eight arguments. For example:

    	MAN
    	   **
    	   **
    	  ****
    	 * ** *
    	*  **  *
    	  *  *
    	  *  *
    	  *  *
    	ok

In summary, defining words can be extremely powerful tools. When you create a new defining word, you extend your compiler. Traditional languages like Fortran or BASIC do not provide this flexibility because these traditional compilers and interpreters are inflexible packages that say, "Use my instruction set or forget it!"

The real power of defining words is that they can simplify your problem. Using them well, you can shorten your programming time, reduce the size of your program, and improve readability. Forth's flexibility in this regard is so radical in comparison with traditional languages that many people don't even believe it. Well, now you've seen it.

The next section introduces still another way to extend the ability of Forth's compiler.

## How to Control the Colon Compiler

Compiling words are words used inside colon definitions to do something at compile time. The most obvious examples of compiling words are control-structure words such as IF, THEN, DO, LOOP, etc. Because Forth programmers don't often change the way these particular words work, we're not going to study them any further. Instead we'll examine the group of words that control the colon compiler and thus can be used to create any type of compiling word.

Recall that the colon compiler ordinarily looks up each word of a source definition and compiles each word's address into the dictionary entry--that's all. But the colon compiler does not compile the address of a compiling word--it executes it.

How does the colon compiler know the difference? By checking the definition's "precedence bit." If the bit is "off," the address of the word is compiled. If the bit is "on," the word is executed immediately; such words are called "immediate" words.

The word IMMEDIATE makes a word "immediate." It is used in the form:

    	: name	definition ; IMMEDIATE

that is, it is executed right after the compilation of the definition.

To give an immediate example, let's define

    	: SAY-HELLO  ." Hello" ; IMMEDIATE

We can execute `SAY-HELLO` interactively, just as we could if it were not immediate.

    	SAY-HELLO Hello ok

But if we put `SAY-HELLO` inside another definition, it will execute at compile time:

    	: GREET	SAY-HELLO ." I speak Forth " ; Hello ok

rather than at execution time:

    	GREET I speak Forth ok

Before we go on, let's clarify our terminology. Forth folks adhere to a convention regarding the terms "run time" and "compile time." In this example, the terms are defined relative to `GREET`. Thus we would say that `SAY-HELLO` has a "compile-time behavior" but no "run-time behavior." Clearly, `SAY-HELLO` does have a run-time behavior of its own, but relative to `GREET` it does not.

To keep our levels straight, let's call `GREET` in this example the "compilee"; that is, the definition whose compilation we're referring to. `SAY-HELLO` has no run-time behavior in relation to its compilee.

Here's an example of an immediate word that you're familiar with: the definition of the compiling word BEGIN. It's simpler than you might have thought:

    	: BEGIN	HERE ; IMMEDIATE

BEGIN simply saves the address of HERE at compile time on the stack. Why? Because sooner or later an UNTIL or REPEAT is going to come along, and either has to know what address in the dictionary to return to in the event that it must repeat. This is the address that BEGIN left on the stack.

BEGIN's compile-time behavior is leaving HERE on the stack. But BEGIN compiles nothing into the compilee; there is no run-time behavior for BEGIN.

Unlike BEGIN, most compiling words do have a run-time behavior. To have a run-time behavior, a word has to compile into the compilee the address of the run-time behavior, which must already have been defined as a word.

A good example is DO. Like BEGIN, DO must provide, at compile time, a HERE for LOOP or +LOOP to return to. But unlike BEGIN, DO also has a run-time behavior: it must push the limit and index onto the return stack.

The run-time behavior of DO is defined by a lower-level word, sometimes called (DO) or 2>R. The definition of DO is this:

...
2>R
...
compilee definition

    	: DO  POSTPONE 2>R  HERE ; IMMEDIATE

The word POSTPONE finds the address of the next word in the definition (in this case 2>R) and compiles its address into the compilee definition, so that at run-time 2>R will be executed.

> Another example is the definition of ;. At compile time, semicolon must do the following things:

> 1. compile the address of EXIT into the dictionary entry being compiled,
> 2. expose the new word to the colon compiler, and
> 3. leave compilation mode.

> Here's the definition of semicolon:

>     	: ;  POSTPONE EXIT  REVEAL POSTPONE [ ; IMMEDIATE

> The first phrase compiles EXIT, providing the run-time behavior. The second phrase, which is the compile-time behavior, first exposes the word being compiled and then gets out of the compiler.

> What is the reason for REVEAL? When words are in the process of being compiled, they are not yet findable by the colon compiler. This is done to make it possible to redefine existing words in terms of the old definition plus additional code, for example:

>     	: CR  CR SPACE ;

> If during the compilation of the new CR its name were findable, the name of the original CR would be blocked, and we would have had to do, e.g.:

>     	: _cr_  CR ;
>     	: CR  _cr_ SPACE ;

The word POSTPONE can also be used to compile an immediate word as though it were not immediate. Given our previous example, in which `SAY-HELLO` is an immediate definition, we might define

    	: GREET  POSTPONE SAY-HELLO ." I speak Forth " ; ok

to force `SAY-HELLO` to be compiled rather than executed at compile time. Thus:

    	GREET Hello I speak Forth ok

Be sure to note the "intelligence" built into POSTPONE. POSTPONE parses the next word in the input stream, decides if it is immediate or not, and proceeds accordingly. If the word was not immediate, POSTPONE compiles the address of the word into a compilee definition; think of it as deferred compilation. If the word is immediate, POSTPONE compiles the address of this word into the definition currently being defined; this is ordinary compilation, but of an immediate word which otherwise would have been executed.

To review, here are the two words which are useful in creating new compiling words:

`IMMEDIATE ( -- )` | Marks the most recently defined word as one which, when encountered during compilation, will be executed rather than being compiled.
`POSTPONE xxx ( -- )` | Used in the definition of a compiling word. When the compiling word, in turn, is used in a source definition, the execution token of xxx will be compiled into the dictionary entry so that when the new definition is executed, xxx will be executed. Used in a colon definition, causes the immediate word xxx to be compiled as though it were not immediate; xxx will be executed when the definition is executed.

## More Compiler-controlling Words

There are two other compiler control words you should know. The words [ and ] can be used inside a colon definition to stop compilation and start it again, respectively. Whatever words appear between them will be executed "immediately", i.e., at compile time.

Consider this example:

    	: SAY-HELLO  ." Hello " ;
    	: GREET  [ SAY-HELLO ] ." I speak Forth " ; Hello ok
    	GREET I speak Forth ok

In this example, `SAY-HELLO` is not an immediate word, yet when we compile `GREET`, `SAY-HELLO` executes "immediately."

For a better example we first need to introduce the word LITERAL.

As you may recall, a number that appears in a colon definition is called a "literal." An example is the "4" in the definition

    	: FOUR-MORE  4 + ;

9 | F | O | U | R | - | M | O | R | E
link
execution token
(LITERAL)
4
+
EXIT

The use of a literal in a colon definition requires two cells. The first contains the execution token of a routine which, when executed, will push the contents of the second cell (the number itself) onto the stack.

The name of this routine may vary; let's call it the "run-time code for a literal," or simply (LITERAL). When the colon compiler encounters a number, it first compiles the run-time code for a literal, then compiles the number itself.

The word you will use most often to compile a literal is LITERAL (no parentheses). LITERAL compiles both the run-time code and the value itself. To illustrate:

    	: FOUR-MORE  [ 4 ] LITERAL + ;

Here the word LITERAL will compile as a literal the "4" that we put on the stack between the square brackets. We get a dictionary entry that is identical to the one shown above.

For a more useful application of LITERAL, recall that in Chap. 8 we created an array called `LIMITS` that consisted of five cells, each of which contained the temperature limit for a different burner. To simplify access to this array, we created a word called `LIMIT`. The two definitions looked like this:

    	VARIABLE LIMITS 4 CELLS ALLOT
    	: LIMIT ( index -- addr ) CELLS LIMITS + ;

Now let's assume we will only access the array through the word `LIMIT`. We can eliminate the head of the array (some bytes and one cell) by using this construction instead:

    	HERE  5 CELLS ALLOT  BASE !
    	: LIMIT ( index -- addr ) CELLS [ BASE @ ] LITERAL + ;
    	DECIMAL

In the first line we put the address of the beginning of the array (HERE) in the system variable BASE (any other scratch variable will work). In the second line, we compile this address as a literal into the definition of `LIMIT`.

Old version
head for LIMITS
5 CELLS
head for LIMIT
CELLS
LIMITS
+
EXIT

New version
5 CELLS
head for LIMIT
CELLS
(LITERAL)
addr
+
EXIT

Now we know all there is to know about LITERAL, we can also give a better example of [ and ]. Imagine a colon definition in which we need to type the byte from row 2, column 3, of the array `BOARD` we defined in the previous section. To get the address of this byte, we could use the phrase

    	BOARD  2 8 ( #cols) * 3 +  CELL+  +

but it's time consuming to execute

    	2 8 * 3 +

every time we use this definition. Alternatively, we could write

    	BOARD  19 CELL+ +

but it's unclear to human readers exactly what 19 means, and it is irritating that, for portability, we still have to write CELL+ although 1 CELLS is just a constant.

...
(LITERAL)
23
...

The best solution is to write

    	BOARD [ 2 8 ( #cols) * 3 +  CELL+ ] LITERAL +

Here the arithmetic is performed only once, at compile time, and the result is compiled as a literal.

Here's a silly example which may give you some ideas for more practical applications. This definition let's you peek into the innards of the word itself:

    	: DUMP-THIS  [ HERE ] LITERAL  32 DUMP ." DUMP-THIS" ;

When you execute `DUMP-THIS`, you will dump the memory into which `DUMP-THIS` was defined. You should see how your Forth compiles the literal value of "here," the literal "32," the execution token of DUMP, and then how it inlines the string "DUMP-THIS." (At compile-time, HERE points to the address of the next free code byte. LITERAL compiles this number into the definition as a literal, so that it will serve as the argument for DUMP at run-time.)

By the way, here's the definition of LITERAL:

    	: LITERAL  POSTPONE (LITERAL) , ; IMMEDIATE

First it compiles the address of the run-time code, then it compiles the value itself (using comma).

To summarize, here are the additional compiler control words we introduced in this section:

`LITERAL` | compile-time ( -- ) run-time ( -- n ) | Used only inside a colon definition. At compile time, compiles a value from the stack into the definition as a literal. At run time, the value will be pushed on the stack.
`[` | ( -- ) | Leaves compilation mode.
`]` | ( -- ) | Enters compilation mode.

## Curtain calls

This section gives us a chance to say "Goodbye" to the text interpreter and the colon compiler and perhaps to see them in a new light.

Here is a definition of INTERPRET that will work in most Forth systems:

    	: INTERPRET ( -- )
    		BEGIN
    		   BL WORD FIND IF  EXECUTE ?STACK ABORT" Stack empty"
    			      ELSE  NUMBER
    			      THEN
    		AGAIN ;

We've covered each of the words contained in this definition; we can describe INTERPRET in English by simply "translating" its definition, like this:

> Begin a loop. Within the loop, try to look up the next word from the input stream. If it's not defined, try to convert it to a number. If it is defined, execute it, then check to see whether the stack is empty. (If it is, exit the loop and print "STACK EMPTY.") Then repeat the infinite loop.

As you can see, the Forth text interpreter is a simple yet powerful structure. Now let's compare its structure with that of the colon compiler:

    	: ]  ( -- )
    		BEGIN
    		  BL WORD FIND DUP IF -1 = IF  EXECUTE ?STACK ABORT" Stack empty"
    					 ELSE  ,
    					 THEN
    				 ELSE DROP (NUMBER) POSTPONE LITERAL
    				 THEN
    		AGAIN ;

The first thing you probably noticed is that the name of the colon compiler is not :, but ]. The definition of : invokes ] after creating the dictionary head and performing a few other odd jobs.

The next thing you may have noticed is that the compiler is somewhat similar to the interpreter. Let's translate the definition into English:

> Begin a loop. Within the loop, try to look up the next word from the input stream. If it's not defined, try to convert it to a number and, if it's a number, compile it as a literal.

> If it is defined, FIND has tested the word's precedence bit. If the word is immediate, then execute it and check to see whether the stack is empty. If it is not immediate, FIND returned an execution token that can be compiled. Then repeat the infinite loop.

Compare this to INTERPRET and you'll see that ] could be called an interpreter with the ability to decide whether to execute or compile any given word. It is the simplicity of this design that let's you add new compiling words so easily.

In summary, we've shown two ways to extend the Forth compiler:

1. Add new, specialized compilers, by creating new defining words.
2. Extend the existing colon compiler by creating new compiling words.

While traditional compilers try to be universal tools, the Forth compiler is a collection of separate, simple tools ... with room for more.

Which approach seems more useful:

Here is a summary of the words we've covered in this chapter:

`DOES>` | run time: ( -- addr ) | Used in creating a defining word; marks the end of its compile-time portion and the beginning of its run-time portion. The run-time operations are stated in higher-level Forth. At run time, the body address of the defined word will be on the stack.
`IMMEDIATE` | ( -- ) | Marks the most recently defined word as one which, when encountered during compilation, will be executed rather than being compiled.
`POSTPONE xxx` | ( -- ) | Used in the definition of a compiling word. When the compiling word, in turn, is used in a source definition, the execution token of xxx will be compiled into the dictionary entry so that when the new definition is executed, xxx will be executed. Used in a colon definition, causes the immediate word xxx to be compiled as though it were not immediate; xxx will be executed when the definition is executed.
`LITERAL` | compile-time ( -- ) run-time ( -- n ) | Used only inside a colon definition. At compile time, compiles a value from the stack into the definition as a literal. At run time, the value will be pushed on the stack.
`[` | ( -- ) | Leaves compilation mode.
`]` | ( -- ) | Enters compilation mode.

## Review of Terms

Compile-time behavior | when referring to defining words: the sequence of instructions which will be carried out when the defining word is executed--these instructions perform the compilation of the member words; when referring to compiling words: the behavior of a compiling word, contained within a colon definition, during compilation of the definition.
Compilee | a definition being compiled. In relation to a compiling word, the compilee is the definition whose compilation the compiling word affects.
Compiling word | a word used inside a colon definition to take some action during the compilation process.
Defining word | a word which, when executed, compiles a new dictionary entry. A defining word specifies the compile-time and run-time behavior of each member of the "family" of words that it defines.
Precedence bit | In Forth dictionary entries, a bit which indicates whether a word should be executed rather than be compiled when it is encountered during compilation.
Run-time behavior | when referring to defining words: the sequence of instructions which will be carried out when any member is executed; when referring to compiling words: a routine which will be executed when the compilee is executed. Not all compiling words have run-time behavior.

## Problems -- Chapter 11

1. Define a defining word named `LOADED-BY` that will define words which include a file when they are executed. Example:

       	S" mail.forth" LOADED-BY CORRESPONDENCE

   would define the word `CORRESPONDENCE`. When `CORRESPONDENCE` is executed, the file `mail.forth` is included (Hint: SLITERAL is NOT useful here). [answer]

2. Define a defining word `BASED`. which will create number output words for specific bases. For example,

       	16 BASED. H.

   would define H. to be a word which prints the top of the stack in hex but does not permanently change BASE.

       	DECIMAL
       	17 DUP H. . 11 17 ok

   [answer]

3. Define a defining word called `PLURAL` which will take the address of a word such as CR or `STAR` and create its plural form, such as `CRS` or `STARS`. You'll provide `PLURAL` with the execution token of the singular word by using tick. For instance, the phrase

       	' CR PLURAL CRS

   will define `CRS` in the same way as though you had defined it

       	: CRS ( times -- )  0 ?DO  CR  LOOP ;

   [answer]

4. The French words for DO and LOOP are TOURNE and RETOURNE. Using the words DO and LOOP, define `TOURNE` and `RETOURNE` as French "aliases." Now test them by writing yourself a french loop. [answer]

5. Write a word called `LOOPS` which will cause the remainder of the input stream, up to the carriage return, to be executed the number of times specified by the value on the stack. For example,

       	7 LOOPS CHAR * EMIT SPACE * * * * * * * ok

   [answer]