Click Here To Go To The Your Computer Archive



Written By John Cottrell


Cover Art
Click Here To Enlarge Loading Screen

Loading Screen
Click Here To Enlarge Opening Screen

Opening Screen
Click Here To Enlarge Screenshot

Game Screenshot

Forth Compiler

J C Cottrell explains the principles of Forth and describes a program for the BBC to imitate it

Before you begin to use Forth, it helps to have some understanding of how it differs from Basic. Forth is a compiled language - the computer:

  1. takes your input,
  2. translates it into machine code, and
  3. stores the machine code

Hence, by the time you have entered the program, a complete machine language program is resident in memory.

Basic is an interpreted language - the lines you type in are stored as they are typed, then when the program is executed, it is translated a line at a time to machine code, but the resultant code is not stored. This means that each line of program is translated as it is met and so considerably slows down execution. The important fact here is simply that Forth runs faster than Basic.

A fundamental point of any language is the method it uses to handle arithmetic. Forth uses a system known as Reverse Polish Notation or RPN. This method will be immediately familiar to anyone who has used a Hewlett Packard calculator. At any time a number is encountered in a line input by the user, it is placed in a position in memory known as the stack.

Any number being placed on the stack goes on the top, above all the other items; also when numbers are taken from the stack, these numbers come from the top. Therefore, the last number on the stack will be the first one off, and for this reason the stack is known as a last-in-first-out structure - LIFO structure.

A number is placed on the stack simply by typing this number and pressing RETURN. Typing 3 followed by RETURN would leave the number 3 on the stack. Now typing 4 and pressing RETURN will place 4 on top of the 3 already there. Incidentally, typing:

3 4

followed by RETURN would produce the same effect. Note the importance of a space between the 3 and the 4. This is an important convention in Forth - all words and separate numbers must be separated by at least one space, unlike Basic where spaces can often be omitted.

To print the top number on the stack in Forth a full stop is used. So typing:

3 .

followed by RETURN - remember the space between the 3 and the full stop - will place the 3 on top of the stack, and the full stop will print it, so:

3 OK

will appear on the screen. OK is the normal Forth response when no error has occurred.

Most Forth words remove any numbers from the stack that they use so that in the above example there would be nothing on the stack; the 3 having been removed from the stack by the full stop.

Now onto arithmetic. This is handled in Forth by the four words + * - /, which perform the same functions as in Basic. Each one of these words expects two numbers on the stack, and the operation is applied to these two numbers. As is normal, the two numbers are removed from the stack. The result of the operation is stored on the stack.

For instance:

3 4 +

followed by RETURN would place the 3 on the stack, and the 4 on top of it, the + would remove the 4 and the 3 and add them together and then leave the answer 7 on top of the stack. Note that nothing would appear on the screen apart from the usual OK message. To print the answer, a . must be used to print the top number on the stack. The dot of course could have been included in the first line, to give 3 4 + . followed by RETURN, which would have printed:

7 OK

immediately.

Multiplication acts in a similar fashion, so:

3 4 * .

followed by RETURN would print:

12 OK

But what about division and subtraction, where the order of the two numbers is clearly important? The second number on the stack is either divided by, or subtracted from, the top number on the stack. So:

4 3 - .

would produce

1 OK

and:

1 2 3 / .

would produce a

4 OK

In Forth, arithmetic is integer only, and numbers are rounded down to the nearest whole number after division. In the sort of application for which Forth is chosen, however, this is not as much of a problem as it might appear. There is also a group of words whose purpose is to directly manipulate the contents of the stack. These words are:

DUP. This makes a copy of the top number on the stack, and puts it on top of the original. Thus to calculate the square of a number: 3 DUP * .

9 OK is the response.

SWAP. This literally swaps over the top two numbers on the stack. For instance, if the top two numbers are 4 and 2 - in this and other examples, I place the top number on the left - after the SWAP, these numbers would be 2 and 4.

OVER. This will take a copy of the second item on the stack and put it on top of the top item e.g., before OVER: 3,4 after OVER: 4,3,4.

ROT. This goes further by rotating the top three items on the stack. The first item is removed, and pushed on top of the two to become the new top of stack e.g., before ROT: 1,2,3 after ROT: 3,1,2.

DROP. This simply removes the top item and forgets about it.

As well as the full stop to print a number, there is the word:

."

to print text. Spaces are very critical in Forth and this word is no exception - it must be followed by a single space. So to print "HELLO", the sequence:

."HELLO"

will do the job. The last quote is not a Forth word, just a delimiter, so it needs no preceding space.

Forth has the words If and Then to handle conditionals. The usage of these words differ from Basic. The word If expects to find a flag on top of the stack. If this flag is true, then the computer will continue execution of the code following the If. A false result will send the computer on a search for the next Then. As soon as this is found, execution continues with the next word after Then.

The flags expected on the stack are produced by a series of words. These words are:

> takes the top two numbers on the stack. If the top number is greater than the second number, a true flag is placed on the stack, otherwise a false flag is placed there.

< is the logical inverse of >.

= compares the top two numbers. If they are equal, a true flag is left on the stack, otherwise a false flag is left there.

= 0 takes the top number on the stack and compares it to zero. If it is zero, a true flag is left on the stack, otherwise a false flag is left there.

> gives a true flag if the top number on the stack is non-zero, otherwise gives a false flag.

As an example, type in two numbers, then the following sequence:

IF ."SAME" THEN

This will print "SAME" if the two numbers were equal. The = compares the top two numbers and leaves a flag on the stack. The IF tests the flag. If it is false, a branch is made to the word following THEN. Since this is the last word, however, control returns to the user. If the flag is true, execution continues with the printing of the word "SAME".

Loop Types

Forth has three types of loop. These are:

  1. the BEGIN...UNTIL loop,
  2. the BEGIN...WHILE...REPEAT loop, and
  3. the DO...LOOP loop.

Begin...Until

The BEGIN...UNTIL loop is used in a line such as:

BEGIN 1 0 . *' UNTIL

The word BEGIN initialises the loop and has no other function. The UNTIL will expect a flag on top of the stack, in this case placed there by the = 0. The flag here will always be false, since one will never be equal to nought. The UNTIL tests the top flag. If it is false, execution branches to the corresponding BEGIN. If the flag is true, execution continues with the next word.

Begin...While...Repeat

BEGIN...WHILE...REPEAT are enclosed in a program line in a similar fashion to BEGIN...UNTIL. The BEGIN is again just a pointer. When the word WHILE is encountered, the top flag on the stack is tested. If it is false, execuion continues with the first word after REPEAT. If it is true, execution continues with the next word after WHILE. The REPEAT will cause execution to continue with the next word after the corresponding BEGIN.

Do...Loop

The DO...LOOP loop is Forth's equivalent of Basic's FOR...NEXT loop. The DO expects two numbers on the stack. The first is the loop index, the second is the initial value of the loop index. The Loop will increment the loop index. If it exceeds the finish value, execution will proceed with the next word after Loop, otherwise the computer will branch to the word following the corresponding DO. There is a variation on this - the word +LOOP may be used instead of LOOP; Instead of incrementing the loop index, +LOOP adds the top number on the stack to the loop index, but otherwise functions as LOOP.

Miscellaneous Words

There are various miscellaneous words present in this implementation of Forth. These are:

EMIT, which takes the top number on the stack and prints the character with this ASCII code;

VDU, which acts as the VDU statement in Basic. It takes as many numbers as necessary off the stack, from the top downwards;

!, which is equivalent to Poke in most Basics. It stores the top number on the stack at the address pointed to by the second number on the stack;

@, which will fetch the contents of the address pointed to by the top number on the stack, and place this value on the stack;

+!, which adds the top number on the stack to the address pointed to by the second number on the stack;

?KEY, which expects a number on the stack. The word will wait for the length of time represented by this number in hundredths of a second, continually testing to see if a key is being pressed. When a key is pressed, its ASCII code is left on the stack. If no key is pressed before the time expires, 0 is left on the stack;

CMOVE, which expects three numbers on the stack. These will be referred to as n1, n2, n3 with n1 coming from the top of the stack. The routine moves n3 bytes starting at the address n1 to the block of memory starting at address n2.

MOVE, which acts as CMOVE except that it moves 16-bit words;

CR, which prints a carriage-return, linefeed sequence on the screen;

SPACE, which prints a single space on the screen;

SPACES, which takes the top number of the stack, and prints the number of spaces on the screen.

Variable Handling

Variable handling is achieved in Forth in the following way: A variable is set up using the word Variable. For example:

VARIABLE JIMMY

creates JIMMY as a variable, and assigns it an address to store its contents. Executing the word JIMMY puts this address on the stack. Thus variables are read using @, written to using !, and added to using +!. So to set JIMMY to 23, the sequence

23 JIMMY

will do the job. Similarly, to print the contents of JIMMY, use JIMMY @, and to add 12 to JIMMY use:

12 JIMMY +!

String Handling

String handling is rather complex. The separate bytes of a text string are stored in memory, preceded by a length counter, indicating length of string. To set up a string, the word VARIABLE is used, followed by the name of the string, followed by the maximum length of string, followed by the word ALLOT. So to set up a string FRED with a maximum length of 10 characters, use the sequence:

VARIABLE FRED 10 ALLOT

The contents of the string must either be moved from somewhere else in memory using MOVE, or else stored byte-by-byte using !.

TYPE And COUNT

There is, however, an easier way to print out the string than removing it byte-by-byte using @ and then printing each byte using EMIT. Instead, the word TYPE may be used. To set up the parameters for TYPE, the word COUNT is used.

COUNT expects the address of the start of the string on the stack. It is assumed that this is the address of the length byte and that the string itself starts at this address plus one.

When COUNT has been used in this manner, TYPE will print a string on the screen. Finally, to remove any trailing spaces on the end of the string, the word - Trailing is used. It expects the address of the first character of the string on top of the stack, and the length count of the string just below this.

When it has altered the length count to exclude trailing spaces, the string address is left on top of the stack, followed by the new length count.

Any Word Sequence

The above section has dealt simply with the actions of words. Any sequences of words may be used, and any results will be displayed as soon as you press RETURN, This is not programming. A program in Forth consists of a list of defined words. An analogy may be helpful at this stage.

A program consists of a number of actions, referred to as words. These words are combined in further definitions until the whole program consists of a single word. The program is run by typing in this word.

To write a program, the specification of the task must be decided upon. This single action is broken down into groups of smaller actions, and each action in these groups itself broken down, until the stage is reached when the list may be easily converted to Forth code.

As an example, take brushing your teeth in the morning. The whole action could be regarded as one word, Teeth. In pseudo-Forth the code would look something like this:

: TEETH BRUSH PASTE CLEAN;

In Forth, a colon indicates a word definition and a semi-colon an end of word definition. Each word could be defined as follows:

: BRUSH
OPEN-CUPBOARD GET BRUSH
CLOSE-CUPBOARD;

: PASTE
GET-PASTE SQUEEZE TUBE
DROP-PASTE;

: CLEAN
SCRUB RINSE;

and each word in these definitions could be defined themselves, until the only words in the definitions are those provided in the Forth system. The only other thing you need to know to write programs is the format of a word name. It must be no more than 20 characters long and may include any character except a space - upper and lower case letters, numbers and symbols are all equally acceptable.

Saving And Loading

For storing your Forth programs, the two words Load and Save are provided. These act as in Basic except that files are numbered rather than named. Numbers should be in the range 1-15. So to Save the current user-defined vocabulary with a file number of 6.

6 SAVE

will achieve the desired result. And to load this back again, use:

6 LOAD

The Forth Compiler

This brief summary should have got you to the point where it is possibly for you to write programs in Forth, so I will move on to the machine-specific of my BBC compiler.

As a start, enter the first, short program, and Save it on tape. Next, enter the second program. Save this on a separate tape. Now insert the tape you used to Save the first program and position it after this program. Type Run. Now type:

*SAVE FORTH1 4700 578D 4700

Press play and record on your tape recorder, and press RETURN. Stop the tape when the computer has finished recording.

Now enter the final program. Save this after the text of the second program on your second tape. These copies are not functional; their purpose is to help you to correct any mistakes. Run the program as before, then insert your original tape, and Save the code using

*SAVE FORTH2 5790 606E 5790

You can now use the program from this tape. Use:

CHAIN

to load the first part,

LOAD "" E0D

for the second part, and

*LOAD "" 1E99

for the last part. When the last part has loaded:

CALL &E0D

will start the program.