Quit: Forth's Outer Interpreter


Forth's quit is its outer interpreter, the part that accepts and interprets input. (The inner interpreter is next which is compiled by semicolon; it one word to the next during execution.) The name quit is descriptive, because the word makes Forth "quit" what it is doing and start over, but it is misleading because it does not indicate its central importance. A better name would be restart.

The ANSI standard says that quit should "Empty the return stack, enter interpretation state, accept new input from the current input device, and begin text interpretation. Do not display a message." Note that the parameter stack is not emptied.

The standard continues: "When the input stream has been exhausted, all processing has been completed, and no ambiguous condition exits, the implementation-defined system prompt is displayed. The interpreter then waits for further input."

In most systems, quit is an ordinary colon definition. It is easy to write your own quit loop by copying the original with suitable modifications. Although all quit loops resemble each other, most of the details are implementation-dependent and you cannot copy from one Forth to another. The commands marked "housekeeping" are rather advanced; don't try to understand them now, just copy them. The following applies to F83.

: quit Define as an ordinary colon definition.

sp0 @ 'tib ! Housekeeping. Set tib just above the stack.

blk off Set blk to 0, thus forcing Forth to get input from the terminal.

[compile] [
[
turns off compilation mode if it happens to be on. It is an immediate word, so it must be preceded by [compile] to prevent it from executing during compilation.

begin Start a begin ... again (endless) loop.

rp0 @ rp! More housekeeping. Reset the return stack.

status A deferred word that can be made to do anything you want. Its default action is cr.

query Get keyboard input. query is a standard Forth word that will get 80 characters into tib (terminal input buffer).

run Analyze the input and execute it a word at a time. (F83 uses run instead of the more standard interpret, as F83's version of the latter does not permit multi-line compilation).

state @ not
if ." ok" then
Emit Forth's standard "ok" prompt unless we are compiling.

again ; Complete the loop and end the definition.

It is not possible to exit from a begin ... again loop in a "normal" way. It is an endless loop, from which the program can escape only by 1) executing bye which exits from Forth, 2) executing quit explicitly, which starts the loop over again, or 3) executing abort or one of its "cousins" which executes quit implicitly.

As noted, status is a deferred word. The default is cr. The name implies that it can be used to show the status of the system, for example to display certain variables, etc. But it can do more than that; it can perform any action desired, but if you are going to get fancy, it is probably better to write your own interpreter loop, as will be explained below.

Writing your own interpreter loop

It is easy to write your own loop. Just be sure to copy all the housekeeping details. For example, suppose you want to make the prompt a deferred word so that you can change it on the fly into something besides "ok," and you don't want to recompile. Just write the following:

defer prompt
: (prompt) state @ not if ." ok" then ;
' (prompt) is prompt
: new_interpret sp0 ! 'tib ! blk off [compile] [
  begin rp0 @ rp! status query run prompt again ;

Now, executing new_interpret has the desired effect, which will continue until you exit from the program, or execute quit either explicitly or via an error routine.

Summing intergers

Suppose that you want to accept lines containing 3 integers, add them and display the result. This is easily done by:

: add3 (n1 n2 n3 -- ) + + . cr ;

Now, simply type 3 4 5 add3, and the computer will respond with the sum , 12. If you keep it up, you will get tired of typing add3 . Also, the "ok" prompt will be annoying. You will wish you could make <cr> alone perform the desired action. One way is to write a new interpreter loop:

: sum_them sp0 @ 'tib ! blk off [compile] [
  begin rp0 @ rp! status query run add3 again ;

Now, executing sum_them will start the desired action. Simply type 3 4 5 <cr>, and the computer will respond with the sum. Executing quit will restore normal action; also, an error, such as having only 2 items on the stack instead of 3, will do the same.


Code is Forth 83 (not ANSI) compliant. First Presented at North Bay Forth Interest Group, September 9, 1989.

Expanded into an article in Forth Dimensions XII, 4, Nov-Dec, 1990, entitled "The Three-Number Problem"

Home

Updated: June 18, 1996

\ Copy of F83 source code
defer prompt
: (prompt) state @ not if ." ok" then ;
' (prompt) is prompt

: new_interpret sp0 ! 'tib ! blk off [compile] [
  begin rp0 @ rp! status query run prompt again ;

: add3 (n1 n2 n3 -- ) + + . cr ;

: sum_them sp0 @ 'tib ! blk off [compile] [
  begin rp0 @ rp! status query run add3 again ;