Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
170 views123 pages

Kail Paul A C An Introduction To Forth

Uploaded by

yoman777
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
170 views123 pages

Kail Paul A C An Introduction To Forth

Uploaded by

yoman777
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 123

An introduction to

FORTH
Paul A C Kail
An introduction to
FORTH
Paul A C Kail
TABLE OF CONTENTS

INTRODUCTION.1
CHAPTER ONE: A QUICK LOOK.2
The Stack.4

CHAPTER TWO: DEFINING NEW WORDS.8


Printing messages.9
Writing new words.9
Forget.10
Clear.10

CHAPTER THREE: VARIABLES.11


Constants.14
Arrays.14
Two-dimensional arrays.16
Moving data around.18

CHAPTER FOUR: IFS AND ANDS.20


BEGIN ...AGAIN.20
BEGIN ...UNTIL.20
testing words.24
more loops.26
DO ... LOOP.26
loops with different sized steps.27
nesting loops.28
leave.30
IF... ELSE ...THEN.30
ORsand ANDs.32
Boolian Operations.35

CHAPTER FIVE: BIGGER NUMBERS.36


Floating point arithmetic.36
Number bases.36
Other representations of numbers.39
Handling Bigger numbers.42
Double-length integers.43
Mixed-length numbers.44
Converting single-length numbers to double-length.45
Scientific notation.46

CHAPTER SIX: MORE ABOUT THE STACK.47


Double-length stack operators.48
The Return Stack.49
Exit words.51

IV
CHAPTER SEVEN: SOUND AND LIGHT.52
Sound.52
Graphics.53
Moving graphics.54
Plot graphics.56
Spectrum PLOT.57

CHAPTER EIGHT: TAPES AND DISKS.59


Editing.59
Disk-based FORTH systems.59
The Spectrum Editor.61
The Jupiter Ace.62

CHAPTER NINE: INPUT AND OUTPUT.64


Inputting text.64
Reading the keyboard.66
Formatting.67

CHAPTER TEN: VOCABULARIES.70

CHAPTER ELEVEN: OTHER WAYS OF DEFINING WORDS.73


A word definition.73
New ways of defining words.74
Strings.75
Last thoughts.76

APPENDIX ONE: PROGRAMS.77


(1) Laserbase.78
(2) Laserbase (for 19K).82
(3) Squash.87
(4| Code.91
(5) Music.94
(6) Quick-sum.95
(7) Snap.99

APPENDIX TWO: SUMMARY OF WORD DEFINITIONS.102

APPENDIX THREE: ASCII CODES.1 \2

INDEX.113

V
INTRODUCTION

FORTH is a very unusual and exciting language. It is fast, compact, and very versatile. A
good FORTH program can run at up to three-quarters of the speed of the equivalent
machine code version; yet at the same time, for many applications it is as easy to use as
BASIC. FORTH is also a language of the future. It is available for most home micros, and
is being used increasingly to control home robots. Unlike any other computer language,
the range of words that it contains can be easily extended (indeed, this is the basis on
which programs are written): it can therefore be adapted to suit a wide variety of
applications. In some ways it is quite primitive: it uses a "stack" rather than variables
(although variables can be defined as well), it uses Reverse Polish Notation and it lacks
many of the functions such as sine and square root which are built into other languages.
However, these functions can easily be defined and added. The advantages of FORTH
more than make up for these defects.
FORTH was designed by the astronomer Charles Moore during the 1960's and 1970's.
He called it FORTH because he saw it as a fourth-generation language, but because the
computer that he designed it for, the IBM 1130, could not accept more than five
characters in a name, he shortened this to FORTH. Since then, it has been extended,
and has been used to control Radio Telescopes, intensive care units in a hospital, the
baggage handling system at an airport, and, more recently, domestic robots.
Since its original conception, two standard versions have been developed, called
FORTH-79 and fig-FORTH. Any version of FORTH that is advertised as being FORTH-79
must include all of the words in a "core” dictionary known as the FORTH-79 standard.
FORTH-79 also includes two extension vocabularies, the Double Number Word Set (for
dealing with large numbers) and the Assembler Word Set (for accessing machine code
subroutines within a FORTH program).
The other standard that has developed is fig-FORTH, produced by the FORTH Interest
Group. It includes most of the core vocabulary, and both the extension vocabularies of
FORTH-79; but not all the words are used in the same way as in FORTH-79. The FORTH
Interest Group was founded to promote interest and ideas about the language, and it
publishes a bi-monthly magazine called FORTH Dimensions. (The address of the F.I.G.
is P.O. Box 1105, San Carlos CA94070, U.S.A.)
The programs in this book are written for either the Spectrum, (using the Artie version of
FORTH) or for the Jupiter Ace computer: however, the text is not based on any
particular version of the language; moreover, because of the nature of FORTH, it is very
easy to define those words which are not present in a particular version.
Throughout this book, several examples are given to illustrate each important point.
The emphasis is on gaining a fundamental understanding of what is happening, rather
than on concentrating on the details of a particular dialect. FORTH is a language unlike
any other, in that you can use it to make it grow to suit your needs.

Happy programming.
CHAPTER ONE A QUICK LOOK
Before attempting to program anything in FORTH, it would be useful to have an
overview of the language. As you know, a BASIC program consists of a series of
commands, each with a number, and each consisting of words. These words represent
the basic building blocks of BASIC, and although it is possible to buy cassettes which
extend the vocabulary, you cannot do so yourself unless you know machine code. When
you type RUN, the computer performs these commands in order. For example, suppose
you had written a short program which we might call ADD UP' which simply adds up two
numbers and prints the results:

10 REM ADD UP
20 PRINT "WHAT IS THE FIRST NUMBER?"
30 INPUT A
40CLS
50 PRINT "WHAT IS THE SECOND NUMBER?"
60 INPUT B
70CLS
80 LETC=A+B
90 PRINT "THE ANSWER IS C
As in most BASIC programs, we are dealing with several different numbers, each of
which has been made into a variable. When we RUN this, the computer will stop to ask
the values of each of these variables and then give the answer (called 'C’l. Here is the
same thing in FORTH:

:ADDUP
WHAT IS THE FIRST NUMBER?"
QUERY LINE
WHAT IS THE SECOND NUMBER?"
QUERY LINE
+
."THE ANSWER IS "

Notice that there are no variables in this, nor any program numbers. In fact, there isn't
even a program, strictly(speaking, but rather the definition of a new word. If you have
typed this in properly (it will work on the Jupiter Ace), each time that you type ADDUP
and enter it, you will get the same routine.
I said that this is a word definition, rather than a program, because this is one of the
essential differences between FORTH and BASIC. In FORTH, the number of words
available is not fixed: type VLIST and enter this, to see the words that you already have
in your FORTH vocabulary. By putting a colon at the beginning of a word definition and
a semicolon at the end, we can create a new word - I have just defined a word called
"ADDUP" in the example above. Each time we define a word, we are adding it to the
FORTH vocabulary (we will lose these definitions when the computer is switched off, of
course, unless they are recorded on tape or disc). The new words can themselves be
used to define other words. Since the early words would be the parts of a complicated
program, the definition of later words can be as involved as a whole program in BASIC.
For example, suppose that I had written a game called “SPACE ATTACK" (a variation of
a famous game with a similar name). The final step of putting the game together would
be to define a word - we might actually call it "SPACEATTACK" - which included all the
elements of the game. When we have done this, if we type the word SPACEATTACK, we
will get our game.

2
A major problem in BASIC is that, whereas short programs such as the one above are
very easy to write and understand, it is harder to write very long programs without
getting in a muddle. The best way to write a long program is by tackling it in several
subunits, testing these separately, and then putting them together. However, the
computer cannot automatically distinguish between one part of the program and
another. Suppose I decided to write another program called “MULTIPLY", which was
exactly the same as ADDUP, except that it multiplied the two numbers together rather
than adding them. To attempt to separate it from ADDUP, we might put it in lines 1010
to 1090. However, unless we made special provision for the computer to sidestep the
later steps when we just wanted ADDUP, or to jump straight to line 1010 when we just
wanted MULTIPLY, we would always get the two together. Whereas we could organize
the two subroutines in different blocks of program numbers, and make them into
separate subroutines, we could never separate them completely in our minds. If we had
a longer program, such as one to play noughts and crosses, we might allocate the
subroutines into blocks like this:

0-999 GOSUBs to access rest of program


1000-1999 Choose next player
2000-2999 Select X's next move
3000-3999 Testing if 0's move is valid
etc.

Each of these blocks would be a sub-routine with a separate function, which would be
put together in block 0-999. Notice that when we are doing something like this in BASIC,
we have to put the subroutines that are used most often at lower program numbers,
because the computer has to look through all the program lines to find the correct
subroutine. (This is like putting the things we use most at the top of the pile of rubbish
in a drawer.)
In FORTH, the problem of separating the different parts of a program does not arise, as
they are kept separate by being inside word definitions. These are not executed unless
they are typed into the computer and entered: there is no word RUN in FORTH.
Because new words can be defined so quickly, it is easy to adapt the basic language to
suit a particular need. For example, if I were a statistician, I could define words such as
MEAN, MODE or CHI-SQUARED, which I could use whenever 1 had some data to
analyze. Moreover, because the basic subunits of a program can be changed, it is very
easy to make very subtle - or very radical - changes to all the more complicated words
that use these subunits in their definitions. For example, I might have used MEAN in a
particular word definition; but then later decide that the mode would be a more
appropriate way of calculating the 'average’ of my data. (The mean of a set of data is the
sum of the data, divided by the number of data; the mode is the commonest element -
for example, the mean of 2, 2 and 3 is (2+2+31/3 = 2'A, but the mode is 2.1 could use a
general word AVERAGE in all the word definitions that included this calculation, and
then redefine AVERAGE to be the mode, mean or median of the data. It is as if I could
build a house from brick, and then, when it was finished, look at it and say 'let’s change
the brick to stone, and the tiles to thatch'. I would then redefine the words for 'building
material' and 'roof and the house would change, without falling down.
It is no accident that the building blocks of FORTH are called "words". In a spoken
language, the word is the smallest unit that contains any sense by itself. The word is the
building block of language. Some words, such as "red" or “sky" convey simple concepts
- these words cannot be defined using simpler words, and the best way to explain them
is to point to something to which they refer. Some of the words built into the FORTH
vocabulary are like this: they are the key to a subroutine in machine code, and are
called "primitive words". The other words in the vocabulary, and all of the words which
you will later define yourself, are made up of other FORTH words. Similarly in English,
just one word, such as “existentialism" may convey a very complex idea. These words
are equivalent to a large group of other words, which they replace, and their main

3
function is to save having to repeat that large group of words. (Some words, such as
"lack" may have different meanings to different people, and as we shall see later, there
is an analogy to this in FORTH as well.) The names of the chapters of this book and even
the title, might be better thought of as “words" that stand for the contents of each
chapter and of all the chapters together, respectively.

THE STACK
We have not yet seen how data is put into the computer in FORTH, except to say that
this does not usually involve variables. Instead, FORTH uses something called the
“stack". All the words defined in the dictionary take their operands (the numbers that
they work on) off the stack, and also leave their results there.
The stack is simply a number of memory addresses, which are used for storing numbers,
usually temporarily, in the order in which they are put on it. Because each number
moves down the pile when a new one is put on top, it is not necessary to allocate names
to them, as would be the case if they were stored as variables. Instead, a system
variable called the “stack pointer" automatically gives the address of the top of the
stack, and the addresses of the other numbers on the stack do not change as other
numbers are added.
Numbers fed into the machine are automatically put onto the stack. Type 3 and press
enter: this has put 3 on the stack. Now type 4 (I am going to stop reminding you to enter
things from now on). This puts 4 on the stack, and moves 3 down to the second position.
Now type 7 (The fullstop is the FORTH word for 'Print'). First we get 4. Type again and
we get the 3. If you type ‘.'a third time, you will get an error message, because you tried
to take something off an empty stack.
You can think of the stack as a pile of boxes with a strong spring underneath. When a
number is put on it, the “weight" of the numbers pushes the spring down; but when the
top number is removed, the spring forces the next number to the top:

In the rest of this book, I shall use boxes like this to represent the stack. Many books on
FORTH write the stack from left to right or from right to left. However, it is much easier
to visualize it if you see the top number actually at the top of the diagram. 1 shall not
include a spring in the other diagrams, so you will have to imagine that.
Notice that the word doesn’t just print a copy of the top of the stack, it actually
removes it. This is rather different from the BASIC word PRINT. (You would be rather
surprised if a computer working in BASIC forgot the value of A when you wrote PRINT A
The stack is very volatile, and of course the positions of the numbers on it are very
important: consequently, we shall use many diagrams like this to illustrate what is
happening to it inside word definitions.
The word only acted on the top number of the stack. The word +, for example, takes
off the top two numbers and replaces them by their sum:

L_U

4
Similarly, * multiplies the top two numbers together:

5
*

The word AVERAGES which we mentioned above, in its original form, takes a large
amount of data off the stack and leaves the arithmetic mean of these numbers, if we
wanted it to work out the means of several sets of data, we could put a 0 between each
set, as a signal that it is to be taken separately:

marks of first pupil

this signifies end of first batch


of data

first part of second batch

and so on. Suppose, for example, that the data were the marks of the pupils in a school.
The word AVERAGES could take the marks for each pupil (the numbers in between the
zeros], and calculate the average of these. It could then use these averages to calculate
the average mark of each class, and so on. At each stage, the data from the previous
stage would be used to calculate the next stage, by using the same word again and
again. One problem with the stack, demonstrated by this example, is that it is
sometimes necessary to store numbers temporarily, but still use the stack for
something else. It is possible to use variables in FORTH, but as well as that, there is a
completely separate stack, called the Return Stack. This works in completely the same
way as the stack we have just met, and can be used as a temporary store:

RETURN STACK

5
and so on. We will look at the Return Stack in more detail later.
Another trouble with having a stack is that you may want to perform an operation on
numbers that are not top of the stack at that moment. There are therefore a large
number of words built into FORTH which you can use to play around with the order of
numbers on the stack. For example, SWAP swaps around the top two numbers:

LJLl I 6 I
SWAP
-►
1.6 I LJJ
while DUP duplicates the top number:

lJLi

so that, for example, you can print something without losing it:

DUP

prints 4

Notice that because it uses the stack for arithmetic operations, FORTH uses Reverse
Polish notation. For example, instead of writing

1 + 1=2
we would say

1 1 +
This can be difficult to get used to. Longer operations can seem very convoluted. For
example,

4 + 3 + 2* (6+ 2* 3)
might be written

432623* + * + +

A
Here is what happens to the stack:

3 12 24
2 + 3
6 —> 3 4
2 4
3
4

27 31

> 4

if you have a Jupiter Ace, you will find a very useful word called DEM which is on the
cassette that you get with the machine. It displays the stack as a pack of cards, and
allows you to see the effect of various manipulations, it is worth writing a version of this
word yourself if you have a different computer.

What, then, are the advantages of having a stack? The first advantage is speed. Because
the computer can quickly find the top of the stack using the stack pointer, and because
all functions take their numbers from the top of the stack, it is very easy for the
computer to carry out an operation. If the numbers were stored as variables, however,
the computer would first have to look in the address where the value of that variable
was stored.
A second advantage of the stack is that it saves memory. In BASIC, all the numbers that
are going to be used have to be assigned names, even if they are only going to be used
once; but in FORTH, numbers are automatically "thrown away” if they are no longer
needed.
A third advantage is that it offers a very effective de-bugging tool. Provided we know
what is happening to the stack at every stage, we can determine what any word will do.
Because the stack is in practice rarely more than half-a-dozen numbers long, this is a
fairly straightforward thing to do.
We have looked at the two most significant features of FORTH, the way it is used to
create new words, and the way it handles data on the stack. We have done this
abstractly, without seeing very much code. The next chapter will introduce some new
FORTH words and show how to use these to define new ones.

7
CHAPTER TWO DEFINING NEW WORDS
We have already met four words in the FORTH vocabulary. In this chapter, we shall see
some more, and begin to put them together to define new words.
We have seen the words * and +. Similarly, there are words - and /:

prints 2

uu empty stack

Notice thattakes the second from top number from the stack and subtracts the top
number from it. This seems more logical if you look at the way the numbers are put into
the machine:

64-
will leave 2 on the stack.
One of the snags of FORTH which i didn't mention in the last chapter is that you can't
use a decimal point (or rather, you can’t use floating point arithmetic). Some versions of
FORTH, such as the one in the Jupiter Ace, do have provision for this, using a special set
of arithmetic functions, (F+, F-, F*, F/, etc.) If your version does not have floating point
arithmetic, you can define words that allow you to use it, or else find ways of getting
round the problem by just using integers. In fact, it is quite possible to do most things
without using decimals.
Because there is no decimal point, FORTH will ignore the part of the number after the
point when it is giving you the answer to a division. Thus the word / gives you the result
rounded down to the nearest whole number: 10 3 / gives 3, for example.
if you do need to know the decimal part of the answer, you can work it out using the
next word. This gives you the result of the division, as before, and also gives you the
remainder:
l_3_|
/MOD
I 10 I LU
(Remember that /MOD is one word, so you must type it in without a gap. if you are using
a Spectrum, you will be used to using single-key entry, but in FORTH you must type out
the whole word, even with words such as LOAD which are the same as BASIC.)
As well as not having a decimal point, FORTH cannot handle very big numbers without
using a special set of arithmetic functions. We will look at why this is in more detail later,
but for the moment just remember that the numbers must not be higher than 32767, not
lower than -32768. To demonstrate this, put 32767 on the stack, and add 1 to it: print
the result, and you will get -32768. Unlike BASIC, which gives you an error message if it
gets to numbers outside its range, FORTH does not tell you anything, and what is worse,
it will often give you a number which is wrong but which looks at first glance as though it
might be right. For example, try 2344 455 * . This gives 17944, whereas the correct
answer is 1,066,520.
In the last chapter, we used the words DUP and SWAP to manipulate the stack. DROP is
another manipulator: it simply drops the top number off the stack:

DROP
I ,1.1
A slightly more sophisticated word is PICK, which “picks up" the nth value of the stack
and leaves a copy of it at the top of the stack, n is given by the top of the stack (so you
usually type this in when you are typing in PICK. This number is lost in the operation,
and is not included in the counting:

copy of this

4r 4th element on stack

Printing messages
So far, we have only been able to print out the number at the top of the stack: but what
if we want to print words instead? The FORTH word for 'print the following quotation’ is
V”. Notice that this is one word, so you need to leave a space between it and the things
that you want to print. There is another quote mark at the end, but no gap here. For
example, if you wanted to print "Hello!", you would type:
H
HELLO!

gap here but not here

Spectrum FORTH can also be used with a printer if you have one. If you type

1 PRINT!
Then everything in quote marks will go to the printer. When you are fed up with wasting
the special printing paper, typing

0PRINT !
will turn the printer off. As in BASIC, the word COPY will make the printer leave a copy of
the screen.

Writing new words


Now that we have met a reasonable number of FORTH words, we can start putting some
of these words together. For example, DUP * will duplicate the top of the stack, then
multiply the two numbers together (i.e., it will square the original number):

L_6_| .DUP^ L_6_| t 36 I

If we wanted to square a lot of numbers, we might want to save time by defining a new
word which this in one go. To define a word, we type Y to tell the computer that we are
going to start a new definition, we then type the new word that we want to define (you
can think up an appropriate name for this); then we type what the new word has got to
do - the definition - and finally we put a semicolon, to tell the computer that we have
finished the definition. For example, we might want to define a word SQUARE which did
the job of DUP and *:

9
starts definition ends definition

S. another gap here


gap here 4

Here is another example. 2* will double the number at the top of the stack, e.g.,

So we could make up a word "DOUBLE":

: DOUBLE
2*
/

Suppose we wanted a word which squared the number on the top of the stack and then
doubled the result, i.e.,

f(x)-^2x2
we would just put SQUARE and DOUBLE together:

:SQDOUB
SQUARE DOUBLE
I

1 have used a rather unpronounceable name, but you could think up a better one. You
will want to remember what your words do, so a name that means something is often
useful: according to the FORTH-79 Standard, any name can be 31 characters long. It may
contain numbers or symbols, but not a blank or a return (CR). In practice it is more
convenient if the name is not too long.
In the last chapter we introduced the word VLIST. When you ENTER this, you will get a
list of the current vocabulary. When you have defined these new words, type VLIST
again, and you will see SQUARE, DOUBLE and SQDOUB at the start of the vocabulary
list.
In BASIC, the word LIST will display the whole of your program. In FORTH, however, it is
not quite so straightforward. In a later chapter, we will see how disc-based FORTH
systems work, but for the moment, we will stick to the lupiter Ace. Jupiter Ace FORTH
has a word LIST with which you can list each word separately, while another word, EDIT,
lets you change anything in a particular word, while REDEFINE gets rid of the old
definition in the dictionary. If you are using another version of FORTH, for the moment
you should just re-write any words that you have typed in wrongly, and RE-DEFINE
them.

Forget
If you have a lot of rubbish in the machine, you might want to clear it all out. The word
FORGET X gets rid of all the words defined after you defined X and also gets rid of X
itself. For example, FORGET DOUBLE would make the computer forget DOUBLE and
SQDOUB but not SQUARE Itype VLIST again to see this for yourself). In Spectrum
FORTH, there is a word TASK. This does not actually do anything, but appears in the
dictionary below all the words which you define, so if you FORGET TASK you will clear
out all the words you have defined since you switched the machine on.
Clear
If you have finished practising the things in this chapter and want to clear the screen
ready for the next one, type CLS. This will also move the cursor back to the top
left-hand corner. If you are using the Spectrum, and have decided that you want to go
back to using BASIC, there is a word BYE which does just that. To go back to FORTH for
chapter three, you will have to re-load the cassette. (Incidentally, there is no need to
load the editor at this stage.)
CHAPTER THREE VARIABLES
Although most operations in FORTH are done more conveniently just using the stack, it
is sometimes useful to have numbers stored as variables. For example, some numbers
may be used several times, and it might be inconvenient to keep on rearranging the
stack when they are not needed, in some of the programs at the end of this book 1 have
used variables wherever possible, as it is usually easier to understand a program that
uses variables than one that relies entirely on the stack.
As in BASIC, each variable in FORTH has a name to identify it. However, unlike in BASIC,
the name itself does not give the value of the variable itself, but only where it is stored.
For example, if I have a variable A, which is equal to 6, say, at the moment, in BASIC I
could say

PRINTA
and I would get the answer 6. In FORTH, if I said

A.
I would get a long number which would seem to have nothing to do with the value of A.
The number that we get when we type in the name of a variable in FORTH is the
address of that number. It is rather as if we were storing numbers by putting different
numbers of people in different houses. The Smith’s house might have 10 people in it,
the Jones's might have 15, and so on:

NUMBER 6534
NUMBER 6533
NUMBER 6532
NUMBER 6531

(Notice that this is an American street,


with very big street numbers!)

If we wanted to know how many people were at Smith's, we could look in the phone
book, and this would give us the address of the Smith's. We could then go round to that
address and look to see how many people were there.
In your computer, information is also stored in addresses. Each address can store one
byte of information: a byte is a number in binary between 0 and 11111111. 11111111
means the same as 255 in base 10, so there are 256 possible different numbers
(including 0) that can be stored in one address. It would not be much good if a
computer could not handle numbers larger than 255, so in practice numbers are made
up using more than one byte. In chapter two we saw that it is not possible in FORTH to
use numbers that are higher than 32767 or lower than -32768. This is because even
using two bytes restricts the size of numbers that can be handled.
In practice, although you should understand how your numbers are stored, you do not
need to actually work out what to put in the two addresses. There are two words which
work all this out, and put your variables into and out of the correct addresses.
The first word is pronounced store'. For example, if we wanted to store the number 6
in address 33916, we could write

6 33916 !

11
This particular address might not be available on your computer). The word 'store'
takes two numbers off the stack, and stores the top one in the address given by the
second from top-.

|33916||

lU

(Notice the representation of the address, which we will be using throughout this book.)
We can forget the fact that the number actually takes up two bytes and just remember
where the first is stored.
The other word we use with the variables is pronounced "fetch", which does the
reverse of this, if 1 say

33916@
the computer will go to address 33916 and fetch' a copy of the number that is stored
there and leave it on the stack:

|33916| @ | 6 |

So we now have a (rather clumsy) way of storing numbers.


In our example, however, we did not need to remember the address of each house.
Instead, we just had to remember the name and look up the address in the phone
book. In the same way, it is not necessary to remember the address where a number is
stored in FORTH. If we want the computer to find a spare address, and give it a name,
we say, for example,

VARIABLE SMITH
This is called ''declaring” a variable, and is not something that you have to do in BASIC,
although you do do so in some other computer languages. Some versions of FORTH,
such as the one in the Jupiter Ace, also require you to give the variable an initial value.
If this is necessary, it is usually a good idea to use 0 as the initial value:

0 VARIABLE SMITH

If we now type the word SMITH, the computer will leave the address of SMITH on the
stack. So to recover the value of the variable Smith, we type SMITH, followed by @:

12
^ address of value of
SMITH
Smith Smith .

address of Smith

Spectrum FORTH has two very useful words which make it easier to use variables, and if
your version does not have them, they are very easy to define:

'?' fetches a variable and prints out its value. The other useful word is +!, which takes an
address (A) and a number (X) off the stack. It finds the number in address A, adds X to
it, and puts the sum in A:

lAj +! ^ empty stack

if your version does not have +!, here is a definition:

: +!
DUP @
ROT + (ROT takes the third number off the stack and
moves it up to the top, thus ROTating the top
three numbers)
SWAP

13
Constants
Sometimes, however, we do not need to continuously change the value of a variable (or
in other words, we want a constant, instead). There are two ways of creating a constant in
FORTH. The most straightforward way is simply to define a word as being equal to that
constant. For example, if we write

: A3 ;
then whenever we subsequently type A the computer will treat that as if it were 3.
Unlike when we use a variable, we do not need to fetch the value from an address
ourselves. To change the value of A, however, we would have to REDEFINE it, and this is
something that we can't do inside a word definition.
The other way of storing a number is with the word CONSTANT. This has the same effect
as making a constant with a word definition, but is quicker for the computer to
understand, and uses up less memory. For example

2 CONSTANTX
has the same effect as

:X2;
We can change the value by repeating this procedure for the new value, and then
redefining X.

Arrays
However, it is often the case that we want to store more than one number in a variable.
A super-variable like this is called an array. For example, we might want to write a
payroll program for a small firm. In its simplest form, this might be a list in the computer
of each employee, together with salary, e.g.

employee no.1 £12,000


employee no.2 £8,500
employee no.3 £18,200
employee no.4 £25,410
employee no.5 £26,410
An array needs two things. Firstly, we must have a name for it, and a way of finding
where the information is stored. Secondly, we must have a way of reserving a certain
number of spaces in memory to store the data. In BASIC, there is a word DIM which
automatically sets up an array of the required number of elements. FORTH does not
have such a word, but arrays may easily be constructed, using one of two methods.
The first method uses an extension of VARIABLE. When we use this word, the computer
allocates an address in memory to the name of that variable, it also stores some
information which shows that it is a variable, and then it allocates two bytes of space to
store the value itself. An array is the same, except that it needs more memory. There are
two words in FORTH which allocate memory in this way. The word ALLOT takes a
number off the stack, and reserves that number of bytes in memory after the two bytes
already reserved by VARIABLE. Because we need two bytes for each extra number to
be stored, an array for 5 numbers will need 10 bytes. We already have the two bytes
allocated by VARIABLE, so we need 8 more. For example, if we wanted to make an array
called PAYROLL for storing the salaries, we would write

0 VARIABLE PAYROLL 8 ALLOT

If we want to put numbers in these spaces, we simply have to find'the right address.
Remember, when we type PAYROLL, we get the address at which the array starts:

14
Each pair of addresses can store one number, so the five numbers are arranged like
this:

This puts the address of PAYROLL (the start of the array) on the stack, adds 4 to it to
move up to the position reserved for the third element in the array, and then stores
18200 (the salary of the third employee) in that space.
Similarly, if we want to recover the value stored at position 3, we would write

PAYROLL 4 + @

15
In our example, we had a word SALARY that took a number off the stack and
automatically worked out the right address to look in to get the value of that element of
the array. We could define SALARY like this:

:SALARY
1-2*
PAYROLL +
@.

Similarly, we could have a word CHANGESALARY to change a number in the array:

: CHANGESALARY
1-2*
PAYROLL +!

This takes two numbers off the stack: the employee's number and the new salary:

The other way of reserving space in memory is with the word CREATE. This word will be
discussed in more detail later, but basically it sets up a space in memory for the name
of a word (in the same way as V does) but it does not give the word a function. If we
CREATE a word, we can therefore use this as a marker for our array. We can either use
ALLOT as before, e.g.,

CREATE PAYROLL 20 ALLOT


(notice that this time we have to ALLOT all the spaces as CREATE does not make any by
itself). Alternately, we can use the word 7 (comma). This takes a number off the stack,
and allocates two bytes for it in memory after the markers for PAYROLL. Using CREATE,
we could then write our array and fill in the values at the same time:

CREATE PAYROLL 12000,8000,18200,25410,26410 ,


(remember to leave a space both before and after each comma, and don’t forget the
comma at the end.) We can then access the array in the same way as before, using
SALARY and CHANGESALARY.
Two dimensional arrays
In BASIC, it is also possible to create an array with more than one dimension. For
example, in our PAYROLL example, a more complicated program would store more
information about each employee than just his salary. We might want to know
a) His salary
b) His National Insurance number
c) Whether his salary is to be paid in cash, or directly into his bank account
d) The number of his bank account

16
In BASIC, we would dimension an array with five elements, each with four sub-elements,
e.g. DIM PAYROLL2 (5,4). We can also create two-dimensional arrays in FORTH, but we
have to think first.
A two dimensional array appears to be a matrix, because that is how we would
represent the information:

SECOND DIMENSION OF ARRAY


1 2 3 4

1 U 1,2 1,3 1,4


2 2,1 2,2 2,3 2,4
3 3,1 3,2 3,3 3,4
4 4,1 4,2 4,3 4,4

However, of course, the information is actually stored in the computer linearly:

1,1 1,2 1,3 1,4 2,1 2,2 2,3 2,4 3,1 3,2 3,3 3,4 etc.
The first stage in creating such an array will be to set aside enough memory. Again,

0 VARIABLE PAYROLL2
will set aside two bytes after the markers for PAYROLL2. We need to store 5X4
numbers, so we need 5x4x2 bytes. We already have 2, so we need 38 more:

38 ALLOT
in fact, it might be useful to have a word which will take the dimensions of the array off
the stack and ALLOT enough spaces in memory:

: ALLOTARRAY * 2 * 2 - ALLOT ;
Next we need a way of putting information into the array in the right places. PAYROLL2
will put the address of the first element of the array (1,1) on the stack. PAYROLL2 + 2
will give the address of (1,21 and so on up to (1,4). For the second row, everything is
shifted up by eight bytes. Similarly, for the third row, everything is shifted up by sixteen
bytes, etc. In general, the address of row R and column C will be

(address of start of arry) + 2( 4(R - 1 ) + ( C - 1 ))


Here is a word which takes three numbers off the stack, and stores the number third
from bottom on the stack in the array position given by the numbers first and second on
the stack:

L_C_|
L_R_I ARRAY
->
stores X

C,R
Here is the definition of ARRAY:

:ARRAY
I- (takes 1 from column number)
SWAP ( puts row number on top)
1- (takes 1 off that as well)
4* ( multiplies the (row number - 1)

17
by 4, because each row has 4 numbers)
4- ( adds the row displacement to the
column displacement)
2* ( multiplies this by 2 because we need
two bytes per number)
PAYROLL2 ( puts the starting address of the
array on the stack)
+ ( adds the starting address to the
displacement)
! ( stores this number-which is now
second on the stack - in the correct
; address-which is now top of the
stack - )

Notice the comments in brackets. You are allowed to put these in a FORTH word
definition, and like REM statements in BASIC, they are remembered by the computer
but otherwise ignored. As with the inverted colons in quote statements, the first word,
'(' must be separated from the next word by a gap, but the ')' at the end is a delimiter,
and there is no need for a gap between the end of the comment and this.
Now, of course, we need another word to get numbers out of the array:

RECALL
1 - This takes the column number
SWAP and row number off the stack
1 - and calculates the correct
4* address in the same way that
+ ARRAY did.
2*
PAYROLL2
+
@ This fetches the contents of
that address and prints the result.

Moving data around


What happens, though, if we want to move information around from one variable to
another (or just from one address to another)? There is a word, not available on the
Jupiter Ace, which does just that. This is CMOVE. It takes three numbers off the stack:
the old address, the new address and the number of bytes to be moved:

| No. of bytes |

jNewaddressj CMOVE

{Old address |
new address

old address
Spectrum FORTH has three other words which perform a similar function:
(1) FILL 'fills' the memory from address A onwards, with N bytes each of value X:

(2) ERASE fills N bytes from address A onwards with 0's (i.e., it ERASE’s this part of
memory - ERASE is exactly the same as 0 FILL.

For example, if we wanted to clear out the array PAYROLL, which we made earlier, we
could say:

PAYROLL 10 ERASE
(3) Lastly, BLANKS will fill N bytes starting at address A with 32's. This is the ASCII code
for a blank, hence the name:

Clearly, BLANKS is the same as 32 FILL. Its main use is in string handling, which we shall
look at later.

19
CHAPTER FOUR IFS AND ANDS
So far in this book, the word definitions that we have looked at have done no more than
save time - they have provided a short-hand for series of other words. However, it is
often the case that we want to use logic in a program. In BASIC, we can say

IF A=1 THEN GOTO 10


for example, or in some versions,

IF A=1 THEN GOTO 10 ELSE GOTO 100


We can also make the computer perform a certain path several times, using lines such
as:

FOR N = 1 TO 16 STEP 2

NEXT N
A computer language which did not have this facility would be very limited indeed, and
therefore FORTH is very rich in such procedures.

BEGIN...AGAIN
The simplest loop possible in FORTH (but one that is not available in some versions,
such as the one in the Jupiter Ace) is BEGIN...(action)...AGAIN. This simply repeats a
function without stopping, until the BREAK key is pressed, or the machine is switched
off:
:FOREVER
BEGIN
I AM A COMPUTER"
CR
UNTIL
/

This might not seem very useful; but consider for example a ball game. There will be a
word which PLOTs or PRINTS the ball, another which determines how the ball is to
bounce off obstacles, if the ball has a goal, then another word might test whether or not
the ball has entered the goal. All of these functions are to be carried out for the whole
length of the game, so the loop must go round many thousands of times without
stopping:
: BALLGAME
BEGIN
BALLPLOT BALLMOVE BALLCHECK
BALLGOAL SCORE
AGAIN

BEGIN...UNTIL
From what we have seen so far, we would not be able to make the word AVERAGE which
we met in chapter one. This took a variable number of marks off the stack and
calculated their arithmetic mean. We used 0 as a signal that the marks for one group had
all been received, so that the computer would calculate the mean of that lot without
muddling them in with the next. (A number like this which is either 0 or 1 and which
conveys the fact that something is true or is not true is called a flag. For example, in the
two-dimensional array in the last chapter, we could have used the code 1= "has bank
account”, 0= “does not have bank account" as a flag. Several of the words in this chapter
use numbers as flags, and although strictly speaking a "true” flag must be 1, in practice,
they will accept any non-zero number on top of the stack as a "true" flag.)
The logic in AVERAGE would be something like this:

BEGIN...UNTIL forms a continuous loop which carries on until a condition is true (i.e.,
until the number at the top of the stack is non-zero.)

It is sometimes the case (as in the word AVERAGE that we are going to define) that we
want the loop to continue if the condition is true, rather than if it is false. The next loop
that we will look at is arranged in this way; however, another way to change the logic is
to use the word 0=. This tests to see if the flag is 0. If it is, the condition is true, and it
leaves a 1. If it is not, the condition is false and it leaves a 0. It therefore has the effect of
reversing the truth value of the top of the stack, and is exactly the same as the word
NOT which is found in some versions of FORTH.
Going back to AVERAGE, our next problem is to find a way of knowing how many
numbers are present in each group. The numbers are put on the stack in groups of
varying size, separated by a 0

data of first group

signal to separate groups of data


data of second group
We could put a counter on the stack, and move this to the return stack each time
another number comes along. However a much more sensible solution would be to use
a variable to store the number of data: this would start at 1 and go up by one each time
the computer went round the loop:

1 VARIABLE N
:AVERAGE
BEGIN (starts loop)
+ (adds the top two numbers - i.e., the
new data value and the sum so far-
or the first two data values)
N@ ( puts value of N on the stack)
1+ (adds 1 to this**)
21
N ! (restores new value of N)
OVER ( put next data on top*)
0= (tests to see if it is zero)
UNTIL ( goes back to BEGIN to get anoth
if it is not)
N@ ( puts N on the stack again)
/ ( divides the sum by N)
(prints result)
1 N ! ( adjusts value of N for next loop)

* The word OVER takes a copy of the second number on the stack and leaves it on top
of the stack. For example,

* * The word 1 + has the same meaning as the separate words + and 1, but is marginally
quicker to type and works faster. The words 1 — , 2+ and 2— also defined in most
versions of FORTH.
Let's see what happens to the stack in AVERAGE. Suppose that we have data 1,2 and 3
(rather low marks!) We key them in in that order, preceded by 0:

UNTIL
1
(Notice that this word will only give the answer rounded down to the next integer.
However, if fairly large numbers are used, this will not affect the accuracy very much.)

23
Testing words
So far, we only have one testing tool to put before UNTIL: whether or not the top of the
stack is zero. Ultimately, any logic words we use will have to end up as 'true' or 'not
true'; however, there are many more sophisticated ways of getting this flag than simply
leaving it on the stack in the first place. For example, suppose that we wanted a word
which prints out the numbers from 1 to 100. We could start with 1 and add 1 to it each
loop, and print the result:

1 .BEGIN
1 +
DUP

but how do we stop the count at 100? The word '=’ takes two numbers off the stack, and
leaves 1 if they are equal, and 0 otherwise. For example,

43 = . gives us0
whereas

44 = . gives us 1
So in the loop we could say

DUP
100= (is this number 100?)
(We have to duplicate it before testing it, as the testing word removes it from the stack.)
Here at last is the word to print the numbers from 1 to 100:

HUNDRED
0 ( puts initial value of counter on the
stack)
BEGIN (begins the loop)
1 + ( adds one to the counter)
DUP (copies this, so it is not lost by
(prints counter)
DUP ( copies counter again, so it is not lost
by testing word)
100 = (is the counter equal to 100?)
BEGIN (if so, then stop, if not, then go back
to BEGIN)

In this word, we knew what the finishing point would be before we started. However, it
is often the case that we don't know this: perhaps we just want the loop to stop if the
counter exceeds a certain value. The word '>’ ("greater than") does just that. It takes
two numbers off the stack and replaces them by 1 (“true") if the second number from
top is greater than the top, and a 0 (“false") if not, e.g.,

43 >. will print 1


but

34>. will print0


Suppose that we wanted to print the series 1, 2, 4, 8, etc., but to stop as soon as the
values exceeded 10,000. We could say:

24
SERIES
1 puts initial value on stack)
DUP duplicates this, so that it is not lost
by printing)
prints it)
BEGIN starts loop)
2* doubles last value of counter)
DUP duplicates it, ready for printing)
10000 puts limit on stack)
> is counter greater than 10,000?)
UNTIL if so, finish loop; otherwise go back
to BEGIN)

The trouble with this word is that, as you will see if you type it in and enter it, UNTIL
does not test the counter until it is too late - so SERIES prints the numbers up to the
first one above 10,000. This problem does not arise with the next loop we will look at;
but before then, let's try to get round the problem using the BEGIN...UNTIL loop. In fact,
all we have to do is to shift the to before the 2 *:

: SERIES2
1
BEGIN
DUP.2*
DUP 10000 >
UNTIL

As well as >, there is the opposite word < ("less than"), which also takes two numbers
off the stack, but this time leaves 1 if the second number from top is less than the top
one, and leaves 0 otherwise, e.g.
46 <. prints 1
64 <. prints 0
It may seem at first glance as though > and < simply have opposite effects. However,
each of these leaves out the condition where the top and second numbers are equal: so
the opposite of “less than” is actually “greater than or equal to" (2s), and the opposite of
"greater than” is “less than or equal to" (). These two conditions are not themselves
usually defined in FORTH, but they are quite useful, and are easy to define:
:>= :<=
< 0=
Here are some examples of how they work:

22 >= prints 1
32 >= . prints 1
but 24 <= . prints 1
As well as the combinations 0= made up of 0 and =, there are combinations 0> and 0<
which have the same effect as the two words typed in separately, and test if a number is
negative or greater than zero, respectively.
We looked earlier at the loop BEGIN...AGAIN, which produced a continuous loop. This is
very useful for many games, and, if it is not available on your computer (for example, if
you have a Jupiter Ace) it can be exactly mimicked by BEGIN...0 UNTIL. As the top of the
stack is always 0 when UNTIL does its testing, it will always repeat the loop. It is not
really worth defining AGAIN unless you are likely to use it a lot.

25
More loops
The two problems which we met using the BEGIN...UNTIL loop were, firstly, that we
often needed to reverse the logic, using 0=, so that the computer looped back when we
wanted it to, rather than going out of the loop. The other snag was that the testing word,
UNTIL, occurred after the loop itself. This problem was demonstrated by the first
version of the SERIES program. Although we were able to get round it that time, this
might not always be so easy.
The next loop we will look at has three parts:

BEGIN <—i
REPEAT
WHILE

T
There is no need to put any words apart from the testing words before the WHILE:
these will go between WHILE and REPEAT, and will only be carried out if the flag is
'true'. Here is a simple word definition which uses this loop: it just prints the numbers
backwards from 10 to 1 - we’ll have a go at making it more interesting later:

:COUNTDOWN
11 ( puts initial value + 1 on the stack)
BEGIN (starts loop)
DUP ( duplicates counter, so it is not
lost by WHILE)
WHILE (tests if counter is 0 or not. If
it is non-zero, i.e., flag is true,
it allows loop to continue to
REPEAT - notice that WHILE is written
directly underneath BEGIN, rather
than indented: this shows that it
is part of the loop structure)
1 - (reduces value of counter by 1)
DUP ( duplicates counter, so it is not
lost by'.')
REPEAT (return to just after BEGIN)

DO...LOOP
The last example illustrates a problem that we come across very often in computing:
instead of making a loop repeat itself UNTIL or WHILE some condition is true or not
true, we simply want it to repeat a fixed number of times and then finish. In BASIC we
can do this using a FOR . NEXT loop:

10 FOR N = 1 TO 10
20 PRINT N
30 NEXT N
We have to give the counter a name (N, in this case), and we have to give it upper and
lower limits. The computer will make the counter equal to the lower limit (1 in this
case), then increase it for the next loop, and so on until it reaches the upper limit. In
general, the FOR...NEXT loop could be written:

26
FOR N=A TO BE

NEXT N
Where A and B are the initial and final values respectively. In FORTH, we can do the
same thing, using the DO...LOOP routine. Unlike in BASIC, we do not need to think up a
name for the counter, as the computer always store this in the same place (on the
Return Stack, in fact, which we briefly met in Chapter 1). So for the example above, we
would have:
11 1 DO

LOOP
or in general,
B + 1 A DO

LOOP
If we want to know the value of the counter, the word I will take a copy of it from the top
of the Return Stack and leave this on the Normal Stack (the Normal Stack - the one that
we are used to, is called the Data Stack). If we wanted to print the numbers from 1 to 10,
we would write:
:COUNTUP
11 1 DO
I .
LOOP

Loops with different sizes steps


Sometimes, however, we want the counter to go down instead of up, or to move in steps
of more than I. In BASIC, we could say:
10 FOR N = 0 TO 20 STEP 2
20 PRINT N
30 NEXT N
The word STEP does not exist in FORTH. Instead, we use +LOOP in place of LOOP and
put the size of the step just before this, so that +LOOP can take it off the top of the
stack:
: STEPSERIES
21 (final value of counter)
0 ( original value of counter)
DO ( start of loop)
1 ( puts counter on stack)
( prints value of counter)
2 ( puts step size on stack)
+ LOOP (takes step size off stack,
increases counter by this
amount, and loops back unless
the counter exceeds the final value)

27
Here, then, in general, are the equivalent loops in BASIC and FORTH:

BASIC: FOR N=ATOB (STEP C)....NEXT N


FORTH: B+1ADO.LOOP (or C + LOOP)
Unlike in BASIC, you can change the step size within the loop, e g.,

:STEPUP
1000
DO ( +LOOP uses the counter
IDUP. as the next step size)
+ LOOP
/

Some versions of FORTH work differently when +LOOP is used with a negative
increment. Instead of stopping at the loop before the one in which the counter reaches
the limit (as is the case for positive increments), they carry on into the next loop. (This is
the way that BASIC works, of course.) For example, if one wanted to print out the
numbers from 5 to 1, the loop would be written,

: PRINTOUT
1 5
DO
1.-1
+ LOOP

The lupiter Ace FORTH and the Artie version of FORTH for the Spectrum do not have
this problem, and work the same way with negative increments as with positive
increments. The same word for the Spectrum would have read:

: PRINTOUT
05
DO
1.-1
+ LOOP

Nesting loops
In BASIC, we can have as many FOR...NEXT loops inside one another as we like, and the
same is true of FORTH. For example,

: LOOPYLOOP
11 (final value 4-1 of outer loop)
1 (initial value of outer loop)
r-►DO ( start of outer loop)
' , 3 (final value 4-1 of inner loop)
outer loop ^ (initial value of inner loop)
—► DO ( start of inner loop)
loop | ( puts counter of inner loop on stack)
( prints the counter out)
—►LOOP (ends inner loop)
CR ( carriage return - makes printing
start on a new line)
-►LOOP (ends outer loop)

28
If you are using two loops, the word I will give the value of the counter of the innermost
loop. Another word J will give the value of the next outer loop. (J is not available in Artie
FORTH). Some versions of the language even have a word K which puts the value of the
counter of the next outermost loop on the stack. However, in practice, it is rare to need
more than two loops running at the same time. Here is a new version of LOOPYLOOP
which uses J.

: LOOPYLOOP2
11 1
DO ."J= " ( prints message)
J. (prints counter of outer loop)
3 SPACES (leaves three spaces in the printing)
30
DO ."l="
I.
LOOP
CR
LOOP

Here, T will take the same values as before, and ) will give the values I to 10. The word
SPACES is new. As the name suggests, it takes a number off the stack and leaves that
number of spaces in the printing.
Notice the way in which the DO...LOOPS are indented: some versions of FORTH do not
do this, but it is always worth writing the word definitions out in this way. Each level of
looping must be both started and finished completely if it is nested inside another
loop. This notation makes it harder to miss out the end part of a loop, or to attempt to
interleave two loops. For example, if we want to put a DO...LOOP inside a
BEGIN...UNTIL loop we can do so like this:

BEGIN
100
DO

LOOP
UNTIL

but not like this:

100
DO

BEGIN

LOOP

UNTIL

29
Leave
It is sometimes the case that we want the program to leave a loop at a certain point. The
word LEAVE will set the counter to the limit, and so cause the program to leave the loop
the next time round. (Notice that we still get another round of the loop, because the
value of the counter is not tested until the end of the loop.)

IF...THEN...ELSE
So far, we have only been able to make decisions to either repeat or not repeat a
certain section of program. However, we may want to make a program branch
completely so that one sequence is performed if a condition is true, and another takes
place if it is false. In BASIC, this takes the form:

IF....THEN....ELSE
FORTH has an equivalent:

IF....ELSE....THEN
Although these two constructions both work in the same way, it is important to realize
that the word THEN has very different meanings in the two languages. The usage in
BASIC is more like the English "If you are hungry THEN (in that case) have something to
eat ELSE shut-up". In FORTH, the question is written before the IF, and the word THEN
just means 'then, after that': "Are you hungry? IF (so) have something to eat, ELSE
shut-up THEN (whether you had something to eat or not) go back to work". IF takes the
top number off the stack (the flag) and performs the sequence from IF to ELSE if it is
true (=/0) but takes the path from ELSE to THEN if it is false.
For instance, in the example in chapter one we had a word CHECK which printed a
message if the top number on the stack was greater than 100:

:CHECK
DUP (duplicates the top number, so it is
not lost by CHECK)
100 (leaves 1 ('true') on the stack if
> the number being tested is greater
than 100, but 0 ('false') otherwise)
IF ( prints message if flag is 1)
." TOO HIGH"
THEN ( but not otherwise)

Here is what happens to the stack during CHECK. First, here is a number that is less
than 100:

± false; 50 is not
greater than 10
50
(IF takes away the flag, and because it is 0 the program goes straight to
the end, leaving the 50 intact)

30
And this is what happens if the number being tested is greater than 100:

^ y 11 J the two marks


1150, £b>8teSted

l_50j

(true, 150 is
greater than
| 150 |
100)

(IF takes the flag off the stack: since it is 1 (true) the computer goes to the path between
IF and THEN)

.''TOO HIGH" 100

prints message, and leaves number


on stack intact.

CHECK was not much use in practice, since it didn't allow us to change a number when
we found that it was wrong. We will look later at ways of interfering with the stack in the
middle of a program.
Here is a word which uses ELSE as well: it simply tests if a number is greater than, equal
to, or less than 10, and prints this fact. First of all, we define the messages:

: ME ."THIS IS TEN!";
: MH ." THIS IS HIGHER THAN TEN" ;
: ML ." THIS IS LOWER THAN TEN" ;
and then the word itself:

TEN?
DUP DUP 10=
IF +

OUTER BRANCH
INNER
BRANCH

31
Here is a generalized comparison between the IF statements in BASIC and in FORTH:

BASIC

FORTH

THEN

ORs and ANDs


So far, we have looked at several conditions which affect flags (>, < and =), and several
words which act on these conditions (BEGIN, WHILE and IF). Together, these words can
perform most kinds of logic that you will need. However, it is sometimes the case that
we want something to happen if one thing is true AND another is true, or false; or
alternatively, if one condition, OR another is true or false. This may sound complicated,
so let's first look at the equivalents in English:
IF you do that again OR say another thing, I shall send you to bed.
IF the car is red AND it is a Mercedes, it may be the one that was stolen.
There is a slight difference. The English word OR does not necessarily include the case
where both conditions ke met. For example, we might say,
We want to know IF this was an accident OR it was deliberate.
FORTH has three words which manipulate flags in this way:
AND takes two flags off the stack and leaves a 1 if both of them are true:

AND (true)
Li_J

but
l_!_i
AND (false)

32
I 0 I I 0 I (false)
'- AND -

and

l! AND (false)

and

1 AND (false)
0

On the other hand, OR takes two flags off the stack and leaves 1 if one of them at least is
true:

LU
(true)

The English word ‘or’ corresponds in meaning better to the third word that we are going
to look at, XOR ("exclusive or"). This takes two flags off the stack and leaves 1 if one is
true or the other is true, but not if they are both true:

33
(false)

(true)
L_U

i 0 i i_Lj
XOR (false)
i 0 i ->
Now let's have a go at using some of these words. Suppose we wanted a word
FAIRLYHIGH to go with CHECK and HIGH. This would check if a mark lay between 75%
and 90%. We could use AND for this:
First we must initialize a variable FH;

0 VARIABLE FH
: FAIRLYHIGH
DUP ( copies the mark, so that it is not
destroyed by the testing words 75)
DUP ( copies it again, so that it is not
destroyed by the testing words 75)
75
> (leaves 1 if number is greaterthan 75)
SWAP (transfers mark to top of stack)
90
< (leaves 1 if number is less than 90)
AND (leaves 1 if both of these previous
conditions are true)
IF (IF both of these previous conditions are
true, the value of FH is increased by 1)
FH @
1+
FH !
THEN

As well as AND, OR and XOR, there is another word in this set which we have actually
met already. This is NOT, or 0= as it is sometimes called: it simply reverses the truth
value of the top of the stack. Together this group of four words form part of a branch of
Mathematics known as Boolian Algebra. In the next section, we will look a little bit
closer at what these words can do.

34
Boolian operations
Up to now, we have regarded any non-negative flag as meaning true', as that is the case
as far as IF and so on are concerned. However, AND, OR and XOR can interpret the flag
in more ways than that. Try the following:

23 45 AND . 5
76 98 OR .110
31 9 XOR . 22
What do you make of that? To understand better what is happening, we have to make
the computer display the numbers in binary:

23 in binary is 010111
45 in binary is 101101
AND
5 in binary is 000101
Now do you see? AND is working on each digit in each of the two numbers:

010111
101101
AND
000101
only those columns with a 1 in both numbers leave a I in the result.
What use is this? Well, for instance, in an earlier example, we looked at a
two-dimensional array, in which a flag was used to indicate whether or not an employee
had his salary paid directly into his bank account. Many other kinds of information can
be expressed in this form. For example, we might record
(1) Has he been ill or not in the past six months?
(2) Has he been innoculated against polio?
(3) Has he worked for a rival firm for the past 10 years? etc.
Each of these facts could be represented by the digits of a binary number. Each
employee would have such a number, which could be stored along with out information
in his file:

(1) (2) (3) (4) (5) (6) (7) (8)


employee no. 1 110 0 0 1 1 0 = 198
employee no. 2 0 0 111 0 1 0 = 58
employee no. 3 0 0 110 0 1 0 = 50
employee no. 4 10 0 11 0 1 1 = 155
employee no. 5 0 0^1 0 1 1 1 1 = 47
remember, this is the one
which means that the employee
has been inocculated against polio
Suppose, for example, that there is a polio outbreak and we want to know which
employees are safe. We could AND each man's code number with 01000000 (64 in base
10). If the result were 0 in a particular case, we would know that that person should be
advised to go to the doctor.

35
CHAPTER FIVE BIGGER NUMBERS
So far the limits of arithmetic in FORTH have been rather severe. We have not been
able to use a floating decimal point, and we haven't had a number greater than 32,767
or less than -32,768.

Floating point arithmetic


Many versions of FORTH do not allow decimal arithmetic; however, the Jupiter Ace
version does have a separate set of functions, F., F+, F—, and F/ which can deal with
decimals. It is not possible to mix integer numbers with floating point numbers, so even
whole numbers must be written with a decimal point after them when using these
functions. The word 1NT converts from floating point to integers, by dropping the
decimals:

4.23 INT^ 4

-4.23 INT -4

3. F+ 5.5
——»

Floating point functions are not available in many versions of FORTH, although they can
be defined.

Number bases
When people first started counting, they used their fingers; and because we have ten
fingers altogether (including thumbs) we began counting in units of ten. The number
system we used today evolved on this basis and is called the decimal system: each
digit is worth ten times as much as before, when it is moved one place to the left.
Counting on computers, however, has evolved in a different way. Computers have to
record numbers as voltages, and a system which had to interpret ten different voltages
would be very complex, as well as being liable to error. For example, if a voltage which
was supposed to represent 5 happened to be a little too high, say it was 5.4 volts
instead of 5.0 volts, and at the same time the measuring device which had to interpret it
was slightly over-sensitive then it might be the case that it read the 5.4 as a 6. For these
and other reasons, computers interpret all numbers in base 2, or binary. In this form,
any number can be expressed as a series of I's and 0's. We have met this fact already,
when we were discussing the way that FORTH could not handle numbers above a
certain limit. In binary, each digit is worth 2 x more, each time it is moved one place to
the left:

BINARY DECIMAL EQUIVALENT


1 1
10 2
100 4
1000 8 etc.

We are not limited to bases 2 and 10, but can express numbers in any base (although
particular computers will have limits to the highest base that they can handle). For
example, in base 6, each number in a particular column is worth six times as much as it
would be in the next column to the left:

36
everything in this column everything in the
is worth 6 x 6 = 36 — * first column
is worth 1

■f ^everything in this
everything in this v column is worth
column is worth
6 x 6 x 6 = 216

compare this with a number in base 10:

everything in this everything in the first


column is worth column is worth 1
10 x 10 = 100

*
everything in this
everything in this column is column is worth 10
worth 10 x 10 x 10 = 100

But what happens if we want to express numbers in a base greater than 10? Our system
of number symbols does not have any symbols which by themselves mean 10, 11, and
so on, as in base 10 we use two or more symbols to represent these. The usual
convention in fact is to use the letters of the alphabet, i.e.,

A= 10 (decimal)
B = 11 (decimal)
C= 12 (decimal)

So, for example, the number 30 in base 10 would be IE in base 16. (This is (6 x 1) + (E
(=14) x 1).
Because the computer has to convert all numbers into binary anyway, before doing any
calculations with them, it can easily accept and output numbers in another base apart
from base 10. The base number is stored in the system variable BASE. (A system
variable is one that is used by the computer, rather than by you - although you can
change it - and it is also initialized by the computer). When the machine is switched on,
BASE is set to 10, so unless you tell it otherwise, it will assume that any numbers you
type in are in decimal. Since only one byte of information is needed to hold the value of
the base, it is changed using the word C! rather than !. C! is simply the one-byte version
of!. There is another word, C@ which fetches one byte rather than two. To convert the
computer to work in another base, simply change the value of this variable:

2 BASECI

37
(Just to confuse you, Spectrum FORTH uses two bytes instead of one to store BASE, so
you don't need to use C!).
Now we are in base 2, let's go through an addition in this base. This is important,
because this operation is the basic block of computer arithmetic. If you are still not sure
about other number bases, then this will also help to clarify things: if you feel that I am
being too patronizing, then just skip this section.
Suppose we want to add 10111 and 101. As with base ten, this is easier to visualize in
columns. In the first column, 1 + 1 = 10 (not ten, but two in binary):

10 111 carry 1
1 0 1
0
Similarly, for the next column, 1 + 1 = 10, so again we leave 0 and carry 1:

10 111 carry 1
1 0 1
0 0
And so on up to the last column. Computers perform multiplication in the same way. if
we were to multiply our two numbers together, we would effectively be shifting the
digits of 10111 one place to the left at each stage, and adding these into the total:

10 111
10 1
10 111 1X10111
000000 0 X 10111
1011100 100 X 10111
1110 0 11
The only processes that are required here are addition, the ability to shift the digits of a
binary number, and the ability to test if the next digit in the other number is 1 or 0.
These commands are all understood by the microprocessor, and are part of the
Machine Code definition of the FORTH word
To return to Base 10, we need to change the value of BASE back to 10. However,
because we are still in base 2, we have to work out what the number 10 is in base 2.
Here again are the column values in base 2:

8's 4's 2's 1's

Clearly, 10 could be made up with a 1 in the 8's column and a 1 in the 2's column, and 0's
in all the others:

etc. 8's 4's 2's 1's


1 0 1 0
in other words, ten is 1010 in base 2, so to convert back to base ten, we type:

1010 BASE C!
In general, then, to convert into another number base, we type

X BASE C!
where X is the base number that we want to move to, in the base that vie are in at the moment.
In fact, because it can be a bit of a nuisance to have to work all of this out, there are a
number of words to help. In practice, although we can work in any base, you are unlikely
to want to use any base apart from bases 2 (binary), 8 (octal) 10 (decimal) or 16

38
(hexadecimal). Consequently, there are several words which convert the base into one
of these bases automatically. For example, the word DECIMAL converts the computer
into base ten. Spectrum FORTH also has the word HEX, which converts the machine
into hexadecimal. Some versions also have a word OCTAL. If your version does not have
these words, you can very easily define them:

: BINARY :OCTAL : HEX


DECIMAL DECIMAL DECIMAL
2 BASE C! 8 BASE C! 16 BASE C!

The word DECIMAL is slightly harder to define from scratch. Although BASE C@ will
always give the value of the base you are in, it will express it in that base. For example,
if you are in base ten, it will give you the number 10 (ten); however, if you are in base
two it will also give you 10 as that is two in base two. Here is a definition of DECIMAL
which gets round this problem.'First of all, it converts the machine to base 1, since 1 is
interpreted the same in all bases (apart from in base I itself, which you are hardly likely
to use apart from in this word). In base 1, the only digit which the computer will allow is
0. However, the word +1 is defined in Machine Code, so the computer does understand
that. We can therefore move from that into base two: now we know which base we are in.
We might have saved time by saying 2 BASE C!, but that would not have worked if we
had been in base two to begin with. You might think that we could go straight from there
to base ten by saying 1010 BASE Cl, like we did before. However, the problem is that
the computer will interpret 1010 as a number in the base it was in to begin with, rather
than in base 2. We therefore have to use the word IMMEDIATE, which tells it to carry
this instruction now, rather than when we type the word in later. Finally, we can use this
first word to work back to decimal, if this all sounds too confusing, don't worry. Here is
what you type:

: BINARY
1 BASEC! BASE C@
1+ BASE C!

IMMEDIATE

: DECIMAL BINARY
1010 BASEC!
r

You could of course use BINARY now instead of DECIMAL in the other definitions.
You can also use these words to convert from one base to another: for example, here is
a word to convert from decimal to base 16 (the word assumes that you are in decimal to
begin with, and converts the machine back into decimal for the next time you want to
convert something:

:CONVERT
HEX.
DECIMAL

Other representations of numbers


A major limitation of FORTH so far has been that we cannot handle numbers greater
than 32767, or less than -32768. Another problem, which I mentioned earlier, is that if
we have a calculation that includes a step with larger numbers than this, the computer

39
may give an answer which is false, but which looks as though it could be right, in BASIC,
of course, this could not happen, and you would get a message such as ‘integer out of
range'.
In order to understand the possible solutions to these limitations, we must see how
numbers are coded inside the computer. We have looked at some of this before, but as
it is important, we will go over the principles again briefly.
As we explained in the previous section, the computer itself performs all its calculations
in base two. It stores numbers in addresses, each of which can hold one byte of
information: one byte consists of eight bits, each of which is an electronic switch which
can be either on or off. If the switch for a particular bit is on, this represents a digit 1,
while if it is off, there is a 0. One byte can therefore store any binary number up to
11111111, which is 255 in base 10: if you include 0 (00000000), there are 256 possible
different combinations of binary digits. As we are normally allowed to use two bytes of
information to store each number, there are

256 256
possible combinations and possible combinations
of binary digits in “"V of binary digits in
the first byte -wvy the second byte
<21
i.e. 256 x 256 = 65536 possible different numbers. This is rather as though we had room
for 65536 people in each pair of houses in our analogy in chapter three (perhaps they
could be semi-detached houses). One way we could allocate all the possible pieces of
information would simply be on the basis that each binary number formed by the two
bytes represented its decimal equivalent, i.e.

2nd byte 1st byte


00000000 00000000 = 0
0 0 0 0 0 0 0 0 00000001 = 1

00000000 11111111 =255


00000001 00000000 = 256
... and so on
This method would work perfectly - and, you can in fact use the bytes in this way, as we
shall see later. However, if we use this method, there is no way to represent a negative
sign. For most purposes, being able to use negative numbers is more useful than being
able to use the full range of numbers, in normal usage, therefore, the computer uses the
first of these bits to represent the sign of the number. One might imagine at first that a
negative number would be exactly the same as the corresponding positive number,
except that the first digit was a 1 instead of a 0, or vice versa. However, this method
would be difficult for the machine to interpret. For instance, suppose we take an
example of a binary number,

01101100 00001010
This is 27,658 in base 10. Now imagine that -27,658 were represented like this:

11101100 00001010
for negative
sign
In base 10, 27,658 H—27,658 = 0, and we wotild expect this to be the same in any other
representation that we used. However, using this method, the sum is clearly not zero!

0 110 110 0 0 0 0 0 1 0 1 0
1110 11 fl fl 0 0 0 0 10 10 +
^(1) 0 10 110 0 0 0 0 0 1 0 1 0 0
the digit carried,
which is lost
The method actually used to represent negative numbers does use the first digit to
indicate the negative sign, but it also changes the representation of the rest of the
number, to put it in a form such that A x -A does equal f. This method is called the
two's complement system, and works like this. Suppose that we want a representation
for — I. As we have said, this must be such that, when added to 1, the result is zero (we
can ignore any digits carried over into the next byte - since in practice they are lost
from the system). This works as — 1 as

11111111 11111111
because then,
11111111 1111111
00000000 0 0 0 0 0 0 0 ±-
1
( ) 00 0 00000 00000000
Similarly, -2 is

11111111 1111111
and —3 is

11111111 1111110 1
and so on up to the limit, which is -32,768:

1 0 0 0 0 0 0 0 00000000
if we add this to 32,767, we get back to -1 again:

1 0 0 0 0 0 0 0 00000000
0 1111111 11111111 +
11111111 11111111
The number system that we have then is circular: when we reach the limit of the
positive numbers

32767 = 01111111 11111111


and add 1, we get to the limit of the negative numbers,

-32,768 = 10000000 00000000


so the values of the representations of the two bytes are like this:

-1 32,767 0 +1

41
Test this for yourself by typing 32767 1+ .: you will get the answer -32768. In general,
to work out the representation of a negative number using the two's complement
system,
a) Change all the 0's to l’s and all the l's to 0’s.
b) add 1.
For example,

01101001 00001000
(a) 10 0 10 110 11110 111
(b) 1 0 0 1 0 1 1 0 1 1 1 1 1 0 0 0

(Add the first and third numbers together yourself, to show that this works properly.)

Handling bigger numbers


The simplest way that we could extend the size of the numbers handled is if we stop
using the two's complement system, and make do without negative numbers. If you are
doing a calculation which will not go below 0, but which might go above 32767, you can
use what are called 'unsigned numbers'. Because these use all of the two bytes to
represent your number, the possible range of numbers is from 0 to 65536. in the
unsigned system, the binary numbers stored in the computer are converted directly
into other decimal equivalents (or their equivalents in whatever other base you are
using).
As the computer can perform its calculations equally well, without caring whether it is
dealing with negative numbers expressed as two's complements or as positive
numbers between 32767 and 65536, the normal arithmetic functions can still be used in
the unsigned system. However, in order to see the numbers as unsigned, we must use
the word 'U.' in place ofTo see this in action, change BASE to 2, and type in

1100110100001010
and DUP this. Because the sign digit (the left-most one) is a 1, this will give a negative
number with convert back to decimal and print out the first of the two copies on the
stack:

-13046
Now use 'U.':

U. 52490
There is another word, U<, which is available on the Jupiter Ace but not on the
Spectrum. It works the same way as <, except that it assumes that the numbers on the
stack are unsigned. U= is not defined, as that would obviously be the same as =. U>
can be defined from U<:

: U>
OVER OVER
U< >R =
R> OR 0=
f

(Remember that >R and R> store a number - in this case, the first flag - on the top of
the return stack, so that they are out of the way while we do the next part of the
program.)

42
Double-length integers
Although unsigned numbers may be useful in some situations, if we want to extend the
range of arithmetic still further, we will need to use more than two bytes at a time. If we
used four bytes at once, there would be 32 bits of information (the word 'bit' means one
binary digit). With this number, the possible range would be 232= 4,294,967,295: this
should be enough for most purposes (Spectrum BASIC actually uses five bytes per
number). There is a special set of arithmetic functions in FORTH which can deal with
four bytes at a time; and the numbers that they deal with are known as double-length
integers.
Because the computer uses base 2 rather than base 10, it is not obvious how we should
combine two single-length integers to make a double-length one. For instance, if we
wanted to represent a number greater than 65536, would we put 65536 in one pair of
bytes and the rest in the other? Or would we split the new number equally between the
two pairs of bytes? One way to look at the problem is to think of the number held in
each pair of bytes as being a digit in base 65536. To store a larger number, we divide it
by 65536, put the quotient in one pair and the remainder in the other. Although the
quotient is the more significant of the two (because it represents a larger number by
itself) it is placed above the other in the stack - i.e., it is put onto the stack afterwards.
Another way to look at this problem is to use base 16. Because 16 is 24, each group of
four digits in a binary number corresponds exactly to one digit in the hexadecimal
equivalent.
For example, the 32-bit binary number

0101110010001101011100001101001
We can split this up into groups of four bits, each of which corresponds directly with a
digit in the hexadecimal equivalent:

0101 1100 1000 1101 0111 0000 1101 0010


5C8D70D2
t_r t_t i_i t_t
1st byte 2nd byte 3rd byte 4th byte

The hexadecimal number 5C8D70D2 is of course a double-length number. When it is


put onto the stack it is put on back-to-front, i.e., the more significant pair of bytes is
typed in last. The hex number is split up to fit into the two bytes, with any spaces to the
left filled in by zeros. For example, the number would be keyed in as

7 0 D 2 5 C 8 D
Similarly, 3EFD8 would go in like this:

3 E F D8

E F D 8 0 0 0 3

spare spaces to left filled


in with 0's
There are several words in FORTH which are used to manipulate double-length
numbers. D+ and D. work just like + and ., except that they work on four bytes at a time
instead of two. As an example, let’s add together 534,025,858 and 10,879,229: in
hexadecimal, these are 1FD49682 and A600FD, respectively. In this form, we can easily
divide them up and add them:

43
1 F D 4 9 6 8 2 + A 6 0 0 F D

9682 1 F D 4 00 FD00A6
D. D+ should give 207A977F. First of all, here is what is happening to the stack:

10 0 A 6|
2nd number
10 0 F D| _ |2 0 7 A| answer
1-1 D+ v - D. 207A977F
|1 F D 4| 19 7 7 F|
1st number
>9 6 8 2|
D+ takes the double-length integer which occupies the third and fourth positions on
the stack and adds it to the double-length integer that occupies the first and second
positions on the stack. This leaves a double-length number occupying the first and
second positions of the stack. D. takes the contents of these two positions, interprets
the two numbers together as a double-length number, and prints this number out. If we
want to look at the contents of these two places on the stack separately, we can do so
with U.
In addition, some versions of FORTF1 have the word D-. Most versions also have
another word DC, which again, is like the single-length number versions.

Mixed-length numbers
There is no word D* to multiply two double-length numbers, because if such numbers
were multiplied together, the result would be too large, even for four bytes. However, it
is possible to multiply two (unsigned! single-length numbers to get an answer that is an
(unsigned) double-length number. There are two words to do this.
U* works entirely with unsigned numbers. For example,

3 D 1 0 3 F 5 3 U* D. gives F 1 A B C 3 0
here is what is happening to the stack:

13 F 5 31 |0 F 1 A|
i-1 U* 1-1 D.
I3 D 1 Ql tB C 3 0| prints F 1 A B C 3 0
M* works in exactly the same way, except that it works on unsigned numbers. (M* is not
found on the lupiter Ace). With numbers below 32767, the two operators will give the
same result:

3 D 1 0 3 F 5 3 U* D. F1ABC30
3 D 1 0 3 F 5 3 M* D. F1ABC30
but, of course, with numbers between 32767 and 65536, M* will interpret them as being
two's complement numbers, but U* will not:

F D 1 0 3 F 5 3 U* D. 3E98FC30
but
F D 1 0 3 D 5 3 M* D. -BA03F0
Another set of mixed operators work similarly for division. U/ works on unsigned
numbers, and M/works on signed numbers. Unlike their counterpart /, these words do
leave a remainder. Here is how U/ works:

44
single-length, single-length,
unsigned divisor unsigned quotient

I A/B |

double-length, single-length,
unsigned dividend unsigned remainder

In other words, (A-AI/B = (the answer to the division! + (the remainder).


The words M/ and U/ actually have more in common with the word /MOD than with /. In
fact, some versions of FORTH use the name U/MOD instead of U/. In other versions,
U/MOD may exist as well, but be slightly different in meaning. Spectrum FORTH, for
example, has a word M/MOD, which is the same as Ml, except that the numbers are
unsigned and the quotient (the answer to the division) is double-length.

Converting single-length numbers to double-length


Because D+, D< and so on deal with four bytes at a time, no matter how large the
numbers stored there actually are, if smaller numbers are used, the other bytes must
be filled in. For example, D+ can be used to add 2 and 2 together, provided that the
more significant byte of each pair is filled with 0:
i 0 i

In the case of negative numbers, we must fill the more significant byte with - I instead:

-2x2: I _2j

lAj * L_i_|

Li_l
There is a word in some versions of FORTH called S—>D, which automatically turns
single-length numbers into double-length numbers. It is not available on the Jupiter
Ace, so here is a definition:

: S->D
DUP
0<
IF —1
ELSE 0
THEN

45
There are two other words which are mixed-length operators, but which might not
appear to be, as they do not actually display the double-length stage. The first is */,
which takes three numbers off the stack and leaves one, as follows:

B */. (B*C)/A

LLJ
For example,
_5_

2 */
Li_I
10

*/MOD is the same, except that, like /MOD, it also leaves the remainder on the stack:

L_U _8_
Li_J */MOD
4
22

These words calculate the intermediate product as a double-length number: therefore,


the effect will be the same as if you had used the two operators separately, unless the
numbers involved are fairly large.

Scientific notation
Most people are used to expressing very large numbers in the form A x I0B. This is
commonly used in Physics and Chemistry, and is available on many pocket calculators.
It is also available in FORTH, simply by putting the letter E in the number:

e.g. 3.5E3 = 3.5 xIO3 = 3,500


This feature is available on the lupiter Ace, using floating point numbers and operators
only, but it is not a standard feature of FORTH.

46
CHAPTER SIX MORE ABOUT THE STACK
In the last few chapters, we have come across several words which manipulate the stack.
In this chapter, we will put these together, develop manipulators for double-length
numbers, and have a closer look at the return stack.
In chapter one, we met DUP, DROP and PICK:

I 3 I DUP)

DROP
->

L_U
| 2 | 3 PICK

L±J

ROLL is similar to PICK, except that it does not leave the nth number in place:

L-Lj 4 ROLL
LJLj
l2j Li_l
lAj 4th number down
lJLj
OVER is the same as 2 PICK:

1—1—1 l_Lj
L_2_J -*
OVER i—l—i
i_Lj LLj
and ROT is the same as 3 ROLL: L2_l

l_l_l i_Li
l_Lj ROT
->■ l—L-i
!_U i—Lj
Other operators available include NEGATE, which changes the sign of the top of the
stack, e.g.,

47
NEGATE
Li_l
Spectrum FORTH uses the word MINUS for this.
ABS is slightly different. It takes the negative sign from the top of the stack if there is
one, but does nothing otherwise - in other words, it gives the 'absolute' value of that
number:

MIN and MAX take the top two numbers off the stack and replace them by the smaller
(MINimum) or larger (MAXimuml of the two, respectively:

MIN
L_3_J

MAX^ I 6 |

?DUP is the same as DUP, except that it has no effect if the top of the stack is zero. (This
word is called -DUP in Spectrum FORTH.)

Double-length stack operators


Because the usual stack manipulators such as OVER and DUP are designed to work only
on single-length numbers, we will need a new set of operators for double-length
integers. These are provided by some dialects of FORTH, but if they are not directly
available, they are easy to define. For example, the double-length version of DROP is

: 2DR0P
DROP DROP

Similarly,

: 2DUP
OVER OVER

LA2j A1

A2
1 A1 |
OVER OVER A1
1 A2j *
A2
1 B1 1
B1

lB2 ■ B2

ROT has the double-length version

48
: 2R0T
6 ROLL
6 ROLL
/

1 A1 1 [ C_Ll IC1 1

1 A1 1 LC2j
1 A2|

1 A21 » A1 1
1 B1 1
6 ROLL 6 ROLL
1 B2 | » l£Li >
1 A2»

LB2j 1 B1 |
1 C1 1

1 C2 , l£U 1 B2 |

initially, this now this isthe


is the 6th element 6th element
on the stack

2SWAP is the same as 2R0T, except that it shifts up the second double number on the
stack, instead of the third:

: 2SWAP
4 ROLL 4 ROLL

1 A1 1 1 62 1 l£Li
1 A2I l A1 1 i B21
4 ROLL 4 ROLLv
-> \_Mj
1 B1 1 -* |_^Ll
LB2j
1 61 1 1 A2 1

The Return Stack


We have met the Return Stack in two different contexts, so far:
(1) It has been used to store numbers temporarily while the data stack (the main stack)
is being used for something else. The words >R and R> take a number from the data
stack to the Return Stack and vice versa:

A x

l±J Y

L_cj L^J
DATA STACK RETURN STACK

49
and, later,

lAj L2U
1_JLJ lJLj
L_cj lZj
DATA STACK RETURN STACK

It is important that the number of >R's is exactly equal to the number of R>'s within
any one word, and also within any DO...LOOP: if not, the system will crash.
(2| The second use that we have seen for the Return Stack is during a DO...LOOP, when
it is used to store the limit of the loop and the value of the counter. The counter is kept
at the top of the Return Stack, and the limit of the stack is kept below it. The word LOOP
compares these two values, and adds 1 to the counter at each cycle, if there are two or
more loops nested within each other, the counters and limits are stacked up one above
the other:

I limit of innermost loop |

| counter of innermost loop;

counter of next outer loop |

I limit of next outer loop |

RETURN STACK

Now you can see what 1 and | do: 1 puts a copy of the top of the Return Stack onto the
top of the data stack:

X
X
LOOP RETURN STACK

and | puts a copy of the third number of the Return Stack on the top of the data stack:

LOOP X
LOOP X
RETURN STACK

50
and so gives the value of the counter of the next outer loop. Some versions of FORTH
even have a word K that puts the counter of the second outer loop on the stack, by
copying the fifth number on the Return Stack. A word which is commoner is T. This puts
the limit of the innermost loop on the stack, by copying the second number of the
Return Stack. If this is not clear, then type this word in:

: LIMIT
81
DO
."THE COUNTER IS NOW"
I CR
BUT THE LIMIT IS ALWAYS"
I'. CR CR

However, the Return Stack does not exist just for our convenience. When FORTH is
carrying out a sequence of words, it needs to know how to move from one word to
another. Each word has an address, called the Return Address, that tells the computer
where to go when that word is completed, and these are stored on the Return Stack.
This is why the system will crash if a number is put onto the Return Stack but not
removed within the same word definition.

Exit words
When you switch the machine off, all the numbers on the stack are lost. However,
sometimes, you will want to clear numbers out without losing the words that you have
defined. In other situations, you may want to leave a word and go on to the next one.
This section looks at various ways of doing these things. The words can be slightly
confusing, because they all mean similar things in English, but very different things in
FORTH:
(1) ABORT empties the input buffer and clears both the data and the return stack. It
also leaves an error message and returns control to the keyboard.
(2) EXIT makes the computer leave the word that it is in. It cannot be put inside a
DO...LOOP, as then the Return Stack will have the loop parameters on top, rather than
the Return Address of the next word. FORTH puts EXIT at the end of each word
definition when it compiles it.
(3) LEAVE, which we have met already, makes a DO...LOOP or a DO...+ LOOP finish the
next time round.
(4) QUIT empties the input buffer, clears the Return Stack and returns control to the
keyboard.
(5) COLD performs a cold start by clearing the dictionary and the stack.

51
CHAPTER SEVEN SOUND AND LIGHT
The FORTH-79 standard does not include words for sound and graphics facilities,
because these are usually different for different computers. However, the principles
behind these facilities are very similar in all machines.
The Jupiter Ace is limited to black-and-white graphics, but does have a sound facility.
The Spectrum also has colours, DRAW, CIRCLE, FLASH and so on, which work in the
same way as the corresponding words in BASIC. Similarly, Acornsoft FORTH has
facilities which exploit the graphics capabilities of the BBC computer.

Sound
The Ace word BEEP takes the length of the note in milli-seconds from the top of the
stack, and the pitch number in units of 8/u.s from the second:

| length of note in ms j
1-1 BEEP
pitch number in units of ->~
I_§f*2_I
In practice, a value of around 300 for both of these gives a reasonable note. Higher
values of the top number give a longer sound, and higher values of the second give a
deeper pitch. Because a single beep is not very exciting, it is often worth putting it in a
loop:

:BEEPS
0 5
DO
10 1
DO
I J 5 * +
30* 150 BEEP
LOOP
-1
+ LOOP

Here is a similar version of BEEPS for the Spectrum. Because there is no word ) in
Spectrum FORTH, we have to make J a variable and get its value from the outer loop:

3 VARIABLE J
: BEEPS2
03
DO I J !
8 1
DO
1 I J @ * BEEP (this works like the BEEP
LOOP in Spectrum BASIC)
-1
+ LOOP

Unfortunately, as Spectrum FORTH does not allow decimal numbers, it is not possible
to make a sound last less than one second. Consequently, the loops in this version have
been shortened, to make the tune less tedious.

52
Graphics
The Ace has two systems of graphics. High resolution graphics are produced by
redefining one of the graphic characters, each of which is an 8 x 8 array of dots. Each
character can be positioned within 32 columns and 23 lines using the word AT. Low
resolution graphics are a quarter of the size of a graphic character, and are positioned
using PLOT.
As well as the high-resolution graphics which you can design yourself, the Ace has a set
of sixteen pre-defined characters in addition to the normal ASCII set of letters, numbers
and symbols. The word EMIT prints the character whose ASCII code is top of the stack:
for example, 98 EMIT will give b. Another word related to this is SPACE, which is the
same as 32 EMIT - it 'emit's a space (ASCII code 32). We have met its friend, SPACES,
which takes a number off the stack and leaves that number of spaces.
In addition to the ASCII symbols associated with each key, there is a graphic character,
which can be seen after pressing G' to get into graphics mode. When the machine is
switched on, these graphics characters are the same as the pre-defined graphic
characters printed on the top row of the machine, and this sequence is repeated
several times throughout the keyboard. To define your own character, you have to
change the information stored in the memory addresses corresponding to that
character. Suppose, for example, that you wanted to change the graphic character of
letter A to look like a man. As we said above, each character consists of an array of 8 x 8
dots. Each dot is represented by one bit in the computer's memory. Each line has eight
dots, and is therefore represented by one byte (8 bits) of information:
1 2 3 4 5 6 7 8
1
2
3
4
5
6
7
8
For example, the top line is represented by the binary number

0 0 1 1 1 0 0 0
The l’s represent the white of the man, and the 0's represent the background. The
whole man is represented by 8 bytes, corresponding to the eight rows:

first byte 0 0 1 1 1 0 0 0 = 56
second byte 0 0 1 1 1 0 0 0 = 56
etc/ 0 0 0 1 0 0 0 0 = 16
0 1 1 1 1 1 0 0 = 124
0 0 0 1 0 0 0 0 = 16 DECIMAL
0 0 1 1 1 0 0 0 = 56 EQUIVALENTS
0 0 1 0 1 0 0 0 = 40
0 1 1 0 1 1 0 0 = 108
The machine would accept these numbers in decimal, i.e., 56, 56, 16, 128, 16,56,40, 112.
However, it is probably easier to put them in in binary, since that is the form that you
will work them out. It would be worth working out the decimal equivalents if you were
going to publish the program.

53
The graphics characters are stored in addresses 11264 to 12287. The first eight bytes of
this area of memory are for the graphic symbol of the character with ASCII code 1 and so
on. Here is a word which takes the ASCII code off the stack, together with the numbers
corresponding to the new character, and places them in the correct addresses:

: CHARACTER
8 * 11272 + DUP
8-
DO
1C!
LOOP

The procedure for defining a graphic character is thus:


(11 Type in the definition of CHARACTER.
(2) Draw the character that you want to produce on an 8 x 8 grid.
(3) Mark 1 for each square on the grid which corresponds to the character, and 0 for
each square which corresponds to the background.
(41 Type 2 BASE C! to convert the machine to accepting binary numbers.
(5| Type in the binary numbers of the grid, starting at the top left hand corner and
continuing row by row until the end.
(61 Type the word ASCII, followed by the letter corresponding to the graphic character
that you want to define (in practice, this can be any letter).
(7) Enter CHARACTER.
(8) (When you have finished defining characters! type DECIMAL to return the machine
to base ten arithmetic.
To display your new character, press 'G' followed by the letter that you chose in (6).
Spectrum FORTH is just like this, except that there is a word DEF already in the
dictionary, which has the same function as CHARACTER.
As we mentioned above, any character can be printed anywhere on the screen using the
word AT. This can be used for normal printing, as well as for the characters that you
define yourself. AT requires two numbers on the stack:

| column |
AT
| line |
line

22@ column 31

There are 23 lines and 32 columns, and hence 736 possible positions to choose from.

Moving graphics
Moving graphics form the bases of most computer games. The principle behind them is
the same as that used in the film industry: if we see a series of images, each of which is
slightly different from the next, our brain is able to "fill in the gaps" and give us the
sensation of motion. This is true, provided that the images are not too different, or
changed too slowly.
in order to make an image more, we therefore need to print it, remove it, and then print
it again in the new position. Provided the motion is in a straight line, we can use a loop
for this. Let’s make our man fly across the screen:

54
: FLY
CLS 30 0
DO
10 I AT ."A" ( graphic mode)
500 0
DO (this is to produce a delay,
LOOP to slow him down to a reasonable
speed)
10 I AT " ( unprint him, to clear
the space)
LOOP

Better still, let's make him walk across the screen. We can produce two new graphic
characters, which show him with his legs out and his arms up, and then with his legs in
and his arms down. Here they are:

1 0 0 0 1 1 0 0 0
2 0 0 0 1 1 0 0 0
3 0 0 0 1 1 0 0 0
4 0 0 0 1 0 1 0 0
5 0 0 0 1 1 0 0 0
6 00010000
7 0 0 1 0 1 0 0 0
8 1 1 0 0 0 1 1 0
1 0 0 0 1 1 0 0 0
2 0 0 0 1 1 0 0 0
3 0 0 0 1 1 0 0 0
4 0 0 0 1 1 0 0 0
5 0 0 0 1 0 1 0 0
6 00010000
7 00010000
8 0 0 0 1 1 0 0 0
Use CHARACTER to redefine graphic characters A and B with these shapes. The word
MAN prints graphic character A, then pauses, then unprints A, then prints graphic
character B. The loop moves the printing position across the screen:

:PAUSE
500 0 (this is to slowdown the other
DO loops)
LOOP
/

: RUN
CLS 30 0
DO
10 I AT ."A" ( graphics mode)
PAUSE
10 I AT B" ( graphics mode)
PAUSE
10 I AT " (to clear the figure)
LOOP

55
Plot graphics
The other system of graphics on the Ace uses a different set of co-ordinates. The word
PLOT takes three numbers off the stack: the second and third from top specify the y
and x co-ordinates respectively. The top number gives the plotting mode, which may
be black (0) white (1), no effect (2) or the opposite of what it was before (3). If you want
to see this in action, type in

:SEEPLOT
4 0
DO
10 10 I DUP 10
10 AT PLOTTING MODE "
.PLOT 10000 0
DO
LOOP
LOOP

Mode 2 may appear to be useless. However, it is sometimes useful, for example when a
program produces a sequence of events and requires a pause. For example:

: FLASH
20 20
100 I
DO I 3 MODE
PLOT
500 1
DO
LOOP
LOOP

The word MOD has the same effect as /MOD, except that it only puts the remainder on
the stack.
The word PLOT prints a square a quarter the size of the ASCII characters. This may go
anywhere within a grid of 63 x co-ordinates and 45 y co-ordinates:

[plotting mode |
*
|y co-ordinate! 45

[x co-ordinatel
y

0
x
in addition to these words, the Ace has INVIS, which stops the machine printing up
messages after each statement, and VIS, which reverses this change. INVIS is useful if
you are drawing graphics on the screen, as otherwise the messages would spoil the
effect.
Because the Spectrum has a colour display, the words used to control the colour,
brightness and flashing of the screen are included in the vocabulary. The words CIRCLE
and DRAW are also available. All of these commands are exactly the same as the BASIC
equivalents, except, of course, that they take their operands off the stack. So instead of
writing

BORDER 6
to make the border of the screen yellow, you would type

6 BORDER.
It is also necessary to state specifically if you want the colours to remain after you have
cleared the display with CLS. To do this, use the word PERM (for permanent) after the
command, e.g.,

6 BORDER PERM

Spectrum PLOT
Spectrum FORTH also has a PLOT command, although this one works like the BASIC
word PLOT rather than the Jupiter Ace word, it takes two numbers off the stack and
prints a dot (i.e., one pixel) at position X,Y:

|Y co-ordinatei
PLOT 175 Y co-ordinate
[X co-ordinatei

0L
255
0 X co-ordinate

for example, DIAGLINES will print a diagonal line across the screen:

: DIAGLINE
200 0
DO I I PLOT
LOOP

Since it is rather tedious to PLOT a large number of points, here is a word which moves
a line on the screen, using the keys grouped around G as cursors (there are eight
directions of motion) as follows:

T( ) Y( ) H( ) N( )
B( ) V( ) F( ) R( )
Because Spectrum FORTH is rather slow anyway, there are no controls to prevent you
plotting outside the screen, so be careful near the edge!

100 VARIABLE X
100 VARIABLE Y

57
Here are the words which control input through the various keys:

Cl 70 = IF -1 0 DRAW THEN ;
C2 86 = IF 0 -1 DRAW THEN;
C3 66 = IF 1 -1 DRAW THEN ;
C4 78 = IF 1 -1 DRAW THEN ;
C5 72 = IF 1 0 DRAW THEN ;
C6 84 = IF 0 1 DRAW THEN ;
C7 84 = IF -1 1 DRAW THEN ;
C8 82 = IF -1 1 DRAW THEN;
And here is the word that puts these together in a continuous loop:

:CONTROL
X @ Y @ PLOT ( this prints the initial pixel)
BEGIN
KEY 8 0 ( KEY is like INKEY$ IN BASIC: it
DO leaves the ASCII code of the last
DUP key pressed on the stack)
LOOP ( duplicates this enough times
for all the eight testing words)
Cl C2 C3 C4( the testing words)
C5 C6 C7 C8
AGAIN ( creates continuous loop)

Remember that, as KEY puts the ASCII code of the key pressed on the stack, this will
depend on whether it is a capital or a small-case letter. (This is also true of the games at
the back of this book.) This program assumes you are using capitals.

58
CHAPTER EIGHT TAPES AND DISCS
The Jupiter Ace is unusual in that you can SAVE data directly onto cassette, and LIST
and EDIT any new words that you have added to the dictionary. Disc-based systems are
more complex, and require you to format the text into screens before storing it.

Editing on the lupiter Ace


On the Ace, the word LIST will bring up the definition of any word that you have written
yourself or loaded in on tape, and EDIT will do the same but also give a cursor so that
the definition may be changed. After using EDIT, you must always REDEFINE the word,
even if you haven't actually changed it, or else there will be two definitions wasting
space in the dictionary. This facility is one of the best features of the lupiter Ace, and in
this respect it is very much easier to use than other FORTH systems.

Disc-based FORTH systems


Other FORTH systems are disc-based, and use the concept of screening. Spectrum
FORTH is also in this form, despite the fact that it actually uses a cassette recorder.
Disc-based systems require an Editor as well as the FORTH compiler, and this should
be included in the package.
Although the basic unit of information for the purpose of programming is the word, it
would be very inconvenient if each word had to be transferred to the disc separately.
One page (on earlier microcomputers) consisted of 16 lines of 64 characters, i.e., 1024
characters, or equivalently, 1K bytes of information. This unit is known as a screen or a
block, and is the smallest amount of information that can be transferred. Disc-based
FORTH systems have a buffer in memory, which can hold 2 or 3 blocks of information at
a time:
99
RAM
R( IFFFR ->—
—V- —— OF COMPUTER

IK IK IK
DISC
Each block on the disc is numbered sequentially, starting at 0, with the first few blocks
reserved for the error messages. A 5'A inch single-sided floppy disc would hold about
110 screens, and a microdrive cartridge would hold at least 85.
Let's go through the procedure of putting material into a screen, and transferring this to
the disc. Because each system uses slightly different terminology, this account will be
as general as possible, to illustrate the principles involved. Later in this chapter we will
look in more detail at the editing facilities of the Spectrum version of FORTH.
The first step in an editing session is to call up the Editor vocabulary, using the word
EDITOR (we will have more to say about vocabularies in a later chapter).
Next, we must clear out the memory buffers. Some disc-based FORTH systems have
several buffers, but Spectrum FORTH only provides one. The word EMPTY-BUFFERS
does not actually empty the memory buffers, but marks each buffer with a code that
means that it is not wanted, and can be overwritten by something else. To select a
screen (this can be any number from one, up to the limit of memory available), type

x CLEAR
To begin with, x may as well be 1. When we now type 1 LIST we will see the screen
number (I) and line numbers. To add material to a particular line, we print that line
number, followed by the word P, and the new text. For example, if you wanted to store
the plotting program above into screen 1, you would say

59
0P 100 VARIABLE X 100 VARIABLE Y
1 P : Cl 70 = IF -1 0 DRAWTHEN;
etc.
As we have already seen, any comments that you want to leave in a program can be put
in brackets (with a space between the first bracket and the start of the comment itself).
These comments are like REM statements in BASIC. Although they are stored on the
screen together with the rest of the program, they are not compiled by the computer.
When you are storing information on screens it is usual to use the first line of each
screen to store the comments - such as the names of the words being defined. There is
a word INDEX, which takes two numbers off the stack and displays the first lines of the
screen numbers within this range, e.g„

10 20 INDEX
will give you the first lines of screens 10 to 20. if these each contain an intelligent
comment, they will provide a useful index of the contents of the disc.
When a screen has been written or edited, it must be transferred back to the disc. There
are two stages to this: firstly you must tell the computer that this screen number now
contains material that you want to save, e.g.,

1 UPDATE
for the first screen. The second stage is to use the word SAVE-BUFFERS (or FLUSH, as it
is called in fig-FORTH). This stores all the blocks that have been updated onto the disc.
Finally, the word LOAD will take a screen number, and enter the words in that screen
into the FORTH dictionary.
When text has been put into a screen, it can easily be accessed and modified. Just as
the word LIST n in BASIC prints out the nth line, so n LIST in FORTH will print out screen
n ready for editing. When a screen has been displayed, an elaborate set of editor
commands can be used to move the cursor around the screen and to change any part of
a line. Here are some of the more important editor commands:
1) TOP moves the cursor to the top left-hand corner of the screen.
2) M takes a number x off the stack. If x is positive, the cursor moves x characters to the
right; if x is negative, it moves x places to the left.
3) E takes line number x off the stack and replaces that line by blanks.
4) S moves everything down by one line, it takes the line number x off the stack and
moves the contents of that line down to the next line, leaving line x blank. The letter 'S'
stands for "spread”.
Several commands use the PAD, which we will meet again in a later chapter. Briefly, this
is an area of memory which can store numbers or text, and is used like a piece of rough
paper for manipulating data.
5) x R takes the data out of the pad and puts it in line x, destroying anything that was in
x to begin with.
6) x D has the opposite effect: it removes the contents of line x from the screen and
puts them in the pad.
7) x T does the same, but also TYPEs out the text in line x. We met TYPE earlier in the
chapter.
8) x 1 is similar to S. Like S, it moves the lines below x down by one (and in both cases,
line 15 is lost), x 1 puts the contents of the pad in line x, however, rather than leaving it
blank.
9) F string (where string is a particular word) is used if you want to search through a
screen to find a particular word. If it does find this word, it prints the line number where
it is found, and also moves the cursor to the end of the string, if it does not find it, it
leaves an error message and moves the cursor to the top left-hand corner of the screen.

60
Another word B used in conjunction with this moves the cursor back to the beginning of
the string so that the string can be edited. The main use for F would be if you wanted to
change a particular word wherever it occured in the screen. After you have typed in F
and the text to search for, the word N will repeat this, so that the cursor moves to the
next place where that string is found.
10) A more aggressive command is X. This doesn't just find the text written after it, it
also destroys it.
111 As well as having hunter-killer commands, the editor has a word which will destroy
a whole line, until it gets to a particular word. TILL text (where text is a particular word or
group of words) will destroy all the characters in the current line (i.e., the line where the
cursor is) up to the text.
12) Having destroyed a particular text, you will want to replace it by something better.
The word C takes the text typed in after it and prints that at the current position of the
cursor.
13) DELETE takes a number x off the stack and deletes x characters to the left of the
cursor.
As well as moving material to and from the pad, or destroying it in situ, the editor will
move material from some other address and also give you the address where a
particular line is stored:
14) MOVE (rather like CMOVE, which we have seen already), takes an address and a
line number off the stack (line number on top) and moves a line of text from the
memory, starting at that address to the line number that you have given.
15) x LINE give the address of line number x.
16) Because the splitting up of data into screens is rather artificial, it is often the case
that a program, or even a single word-definition, may spread across more than one
screen. It is possible to have several screens compiled together, e g.,

9 LOAD 10 LOAD 11 LOAD


etc.

but it is neater to record the fact that two screens are to be taken together on the
screens themselves. The word which does this is ~> which is put at the end of one
screen to link it with the next one. Screens linked in this way are compiled together, so
if you had linked screens 9, 10 and 11, then

9 LOAD

would have had the same effect as the line above.


17) Another word, ;S’, has the opposite effect: it stops compilation of a series of
screens. If it is placed after a word definition, it will have the same effect as if the rest of
that screen were in brackets, as a comment.

The Spectrum editor


If you are using Spectrum FORTH, you will not have needed to load the Editor up to
now. The first part of the tape contains the compiler and is loaded in the normal way,
i.e.,

LOAD ""CODE

61
The Editor comes after that, and occupies three screens. Because there is not much gap
between them, it is important to operate the computer keyboard and the cassette keys
fairly quickly. When the compiler is loaded, the cursor will appear on the screen,
together with the copyright notice and some other writing. When it is loaded, you must
stop the tape immediately. Type

1 TYPE

and enter, then wait for a few seconds. When the message 'READY CASSETTE' comes
up, press enter’ again, and start the tape. You will have to do this three times, for each
of the three screens. As soon as the code for the first screen has gone through - i.e.,
when the noise and the yellow and blue stripes have finished - stop the tape, then wait
again for 'READY CASSETTE' to appear. When it does, press 'enter', start the tape to
load the second screen; stop the tape when it has loaded, wait for 'READY CASSETTE',
press enter', and start the cassette for the third screen. When the third screen is
loaded, you should press enter' again, to check that the system is in operation (this
should simply leave an 'OK'). To access the editor vocabulary, type EDITOR then I (say)
- this is the screen number - followed by CLEAR. This defines the first screen. Add or
edit text using the editing command described above, and FLUSH the screen to
cassette when you have finished. In fact, even if you aren't intending to save the words
you have defined, it is worth using the editor because then you can LIST and EDIT what
you have done (although because Spectrum FORTH gives you only one buffer, you
cannot store more than one screen at a time, without using a cassette recorder.

The Jupiter Ace


Versions of FORTH designed to be used with cassette recorders can have much simpler
facilities for information storage. The Jupiter Ace, for example, will SAVE (some program
name), VERIFY (the same name) and later LOAD (the same name). The word SAVE will
automatically transfer all the words not actually built into the ROM of the computer
onto the tape. The name is useful if you are likely to put other sets of words on the
same tape.
The Ace also has three words BSAVE, BVERIFY AND BLOAD: These work in exactly the
same way as the equivalents SAVE, VERIFY and LOAD, except that they deal directly
with bytes of information from the computer’s memory. BSAVE will save Y bytes starting
from address X, where Y and X are the first and second numbers on the stack:

Similarly, BVERIFY checks that the bytes SAVEd have been saved properly. BLOAD
interprets the numbers on the stack slightly differently. If you leave two 0s on the stack,
it will put the bytes from the tape back to the same position in memory where they
came from.
62
But if instead you put two non-zero numbers on the stack, BLOAD will put the bytes
into the memory addresses from A to A+B, where A and B are the second and top
numbers on the stack, respectively:

if there are more bytes of information on the tape than you allowed for between A and
A+B, then an error message will show, and you will have to decide whether or not you
can spare more spaces in memory.
One major snag with cassette-based systems is that they often do not work. This may be
because the cassette is dirty or is poor quality, or because the machine is not properly
adjusted. Good quality stereo recorders in particular continually cause trouble:
paradoxically, cheap mono players are quite reliable. If you must use a stereo recorder,
it is best to just use one channel. Some tape recorders even claim to be
"computer-compatible", or to have a "computer-mode".
It is also a good idea if you are having problems to use a proper data cassette, rather
than a normal music cassette. Apart from the fact that you will lose programs in the
middle of a C90 tape, data cassettes actually work better. This is because the speed of
the recording and playback of a long tape vary slightly - they slow down as the cassette
gets nearer the end. This change in speed will not always be the same, (especially if you
use batteries), so you may find that you cannot LOAD a program that you SAVEd some
time ago. Because data cassettes are much shorter, you do not get this problem.

63
CHAPTER NINE INPUT AND OUTPUT
This chapter looks at various ways of putting information into the computer, apart from
through the stack, and ways of getting information out of the computer, in the form that
you want it.

Inputting text
There are a number of words which can be used to put information into the input buffer
of the computer in the middle of a program. The input buffer is that part of a computer’s
memory which holds instructions before they are carried out. Words and numbers in the
input buffer are displayed at the bottom of the screen, and may be changed by moving
the cursor back and forth. The word RETYPE stops the computer in the middle of a
program and allows you to change the words that are left in the input buffer: when you
press 'ENTER' the program continues using these new words. QUERY is the same as
RETYPE, except that it clears out the contents of the input buffer, so you can only add
new words. QUERY or RETYPE must be followed by one of four words which tell the
computer what to do with the new words that you have typed in.
LINE tells the computer to use the words in the normal way (this word will not be
confused with the Editor command LINE, because these are in different vocabularies,
and so can be interpreted separately - see later).
NUMBER makes the computer look for a number in the input stack. It leaves this
number on the stack second from the top, and puts the number 4102 on the top of the
stack; and if there is no number at all in the input buffer, it leaves a 0 on the stack.*
FIND makes the computer look for FORTH words in the input buffer (including ones
that you have defined yourself). When it FINDs one, it leaves its compilation address on
the stack.
WORD takes a series of letters out of the input buffer, up to a pre-determined symbol
called the delimiter. For example, WORD 35 would take in letters up to the symbol #
(ASCII code 35): WORD 35 would take 'some letters' from the following, but ignore the
rest:

some letters # in the input buffer

•this is only true for the Jupiter Ace: see below.

It puts these letters in a part of memory called the pad. The pad goes from address
9985 to 10239. (NB All the addresses given in this section are specific to the Jupiter Ace;
and as we will see later, some of the words are defined differently in other computers.)
WORD puts the number of letters in the message in the first address of the pad, 9985,
followed by the ASCII codes of the letters of the message. The pad can be used as a
work-space for changing the message - for example, one might want to change all the
small-case letters to capitals, or vice versa. The ASCII codes will stay in place until
WORD is used again, or the computer is switched off. If you want to look at the letters
stored in the pad, you can use the word TYPE. This takes two numbers off the stack: the
top is the length of the message and the second to top is the address of the first byte.
For example,

H3J TYPE will printout


'-^ "some letters"
199861

The word WORD is also found in other versions of FORTH, except that it means
something slightly different. These versions have a word TEXT which means the same

64
as the Jupiter Ace word WORD. The word WORD found on other computers has a similar
function to TEXT, except that it does not use the pad. Instead, it puts the length of the
string and the string itself in some other area of memory, it then puts the address of this
information on the stack.
Another word not found on the Ace is EXPECT. This takes two numbers off the stack.
The first of these is the address where you would like the input message to be stored,
and the second is the maximum number of characters that you want to store. For
example,

will take the first 10


EXPECT characters out of the
input buffer and store
them in addresses 2000
to 2009

stor ‘ '

The Ace word NUMBER also exists in FORTH-79, but with a different meaning. To
understand this, we will have to go over what happens normally when the computer is
given a number.
When you put a number on the stack, the computer automatically converts it into binary
so that it can do calculations with it. When it is given a number, it assumes that it is in
the base set by the variable BASE. (This will be base 10 unless you have altered it.l
Thus a number represented as a, string of digits - for example, 324 - will not
automatically be understood by the computer. NUMBER is a way of taking a set of digits
which are stored as a string, with one digit in one address, the next one in the next
address, and so on, and turning them into a binary number that the computer can use in
calculations.
The FORTH-79 word NUMBER takes a string from a given address and converts it into a
number which it puts on the stack in binary. NUMBER expects the address that it is
directed to tc contain the length of the string, it ignores this, however, and takes its
characters from the address afterwards. Thus suppose that the characters 3 2 and 4 are
stored at addresses 2001,2002 and 2003. Address 2000 would then contain the length of
the character string (3 in this case).

puts binary version of


this on stack

65
NUMBER takes these three characters and converts them into binary, assuming that
they are originally in the base set by BASE. Although NUMBER converts the characters
into binary, they will not be displayed as such. Although all calculations are done by the
computer in binary, they are displayed in the current base number. It is not necessary
to tell NUMBER how many numbers to expect. It will carry on taking characters until it
reaches a character which is not a number. It will also read a -ve sign before the
character string, and use this to make the number on the stack "negative" (i.e., two's
complement). You may be wondering why NUMBER should expect the string to be
stored together with its length (especially since it does not need to know the length in
order to do the calculation). The answer is that most of the words which will put a string
into memory (such as TEXT and WORD) will put it in this form
NUMBER is fine, provided that the number that it produces is less than 32,768. Another
word, CONVERT, (or BINARY, as it is called in some versions) does a similar operation
for double-length integers. CONVERT also requires a double-length number on the
stack as well as the address of the length of the string. It adds the binary number that it
creates onto the double number and returns the address of the first character that was
not a number (i.e., the address after the address of the last character of the string).

Reading the keyboard


All of these ways of putting information into the computer are very slow. However, some
of the programs at the end of this book require very rapid responses: they use the word
INKEY. This word takes the ASCII code of the key being pressed at that moment onto
the stack. The main problem with using INKEY is that the computer processes the word
much more quickly than you could respond. If IN KEY is used alone, it usually puts 13 on
the stack, which is the ASCII code of the RETURN key - because you still have your
finger on this key when INKEY is processed by the computer. It must therefore be used
in a loop which waits until you have lifted your finger from the RETURN key. This word
prints out the ASCII code of the key that you press after pressing RETURN:

66
: INPUT (without the 'print' at the end,
this would be the same as the
word INPUT in BASIC)
BEGIN (this loop carries on until you
IN KEY stop pressing RETURN)
13=
WHILE
REPEAT
BEGIN (this loop waits until you have
INKEY 0= stopped moving your finger off
WHILE RETURN, onto another key)
REPEAT
IN KEY (this one is the one that we want)

Some versions of FORTH such as Spectrum FORTH have a word KEY which does all of
this in one go. It waits until you press a key before putting the code of that key on the
stack, (and does not always give you the code of the Return key!)
As an example of KEY and INKEY, here is a word which prints 0 if you press n (for ‘no’),
and I if you press y (for yes’):

: INPUT2
INPUT DUP110 =
IF
0 -

THEN
121 =
IF 1 .
THEN

Notice that in this word, as in the back of the book, it is important to distinguish
between capital letters and small-case letters, as the ASCII codes for these are different
(and, of course, KEY and INKEY can take account of the CAPS SHIFT key).

Formatting
The reverse of the process of taking information into the computer is, in one sense, the
way we can control the way that information comes out. The way that information is
arranged on the screen is known as formatting.
Suppose, for instance, that we wanted to print out the salaries of our employees from
the word PAYROLL above. In that example, the salaries were all complete numbers of
pounds; but in practice they would probably include pence as well, if you have a Jupiter
Ace, this will not be too much of a problem, as that version of FORTH has provision for
floating-point arithmetic. However, other versions will not readily allow you to print out
an amount of pounds and pence with the decimal point printed in the correct place.
Alternatively, you might want to print out a time or a date or a telephone number, such
as

14/10/84 01-623-4281
FORTH provides six words to enable you to do this. These words take a number off the
stack, and print it out with whatever signs or symbols you need in the middle. Before
looking at the actual process of formatting, we will briefly go over the vocabulary:

67
(1) <# starts the process (but does not actually do anything by itself).
(2) Similarly, #> finishes off the process of formatting.
(3) In between these, # puts one number into the output string (this is the string that is
printed out). If there is no number to output, it leaves a f
(4) #S puts all the numbers available into the output string.
(5) SIGN adds a negative sign if required - that is, if the top number of the stack is
negative.
(6) HOLD takes numbers off the stack and prints its ASCII code. For example, 46 HOLD
will print a decimal point.
Suppose, for example, that we wanted to print out the prices of some goods. Here is a
word that will take the amount in pence and print it out as pounds and pence.

: FORMAT
S~> (converts single-length integers
to double-length)
<# ( starts the process of formatting)
## (prints the pence)
58 HOLD ( prints the colon)
#S ( prints all the pounds digits)
96 ( prints out the £ sign)
HOLD #> (finishes the process)
TYPE (prints this lot out)
3 SPACES ( prints three spaces before the
O.K.)

Notice that the formatting takes place from right to left. The formatting words leave two
numbers on the stack: the number of characters in the string and the address of the first
character below that:

No. of characters
in string ;
TYPE prints out string
address of first
character in
string

TYPE takes these two values and prints out the string.
The numbers which <# and so on work with are likely to be fairly big. (Even the salaries
of the employees in our array are in the millions when they are expressed in pence), so
the words work with double integers. They also only work with positive numbers.
If we are using numbers which are not positive, we must temporarily make them
positive, using DABS, the double-number version of ABS. However, if our numbers are
negative, we will want them to be printed out as negative numbers. The word SIGN
takes the top number of the stack (the third from top in some versions) and outputs a
—ve sign if the number is negative. If we want to use SIGN, we must therefore make a
copy of the top of the stack before we use ABS.
If the numbers to be formatted are not double-length, we have another problem, as we
then have to convert them into that form. As explained in the chapter on double-length
numbers, the way to do that is to add 0 to form what will become the more significant
byte. Here is an example of what to do with a number that is both negative and
single-length:

I ~6 I (single-length, negative number)

DUP |_±J

|_-6J

ABS | 6 | (makes the top


number positive)

0_ I 0 | ( make the top number


* a double integer)

| ~6 | (this copy will be


used by SIGN)

The material in this chapter is much harder than most of the rest of this book, and the
account is made even harder by the fact that many of the words are not standard.
INKEY, QUERY and WORD are very important, and should be mastered; but much of
the rest of this chapter can safely be left until later.

69
CHAPTER TEN VOCABULARIES
In the first chapter, the analogy was made between FORTH and a spoken language such
as English: both are made up of words, and these words may represent very basic
ideas, which cannot be expressed more simply using other words; or alternatively, they
may exist simply to save time, when one wants to refer to a very complex concept.
Another similarity between FORTH and spoken language is that both can use different
sets of vocabulary. For example, in spoken language, the word "Jack" means very
different things to a sailor, a carpenter, or a card-player, in FORTH it is also possible to
use different context vocabularies. This might be useful if you were working on two or
three different programs at the same time. You could keep the words from the different
programs in separate vocabularies, and then they could be listed out and edited
separately.
The present vocabulary, i.e. the one which is operating when your machine is switched
on, is called FORTH. Suppose you wanted to start a new vocabulary called NEWWORDS.
Type

VOCABULARY NEWWORDS
(this has to be followed by the word IMMEDIATE in Spectrum FORTH). This will define a
vocabulary word (NEWWORDS) which is in the FORTH vocabulary, but which also
provides a link from that vocabulary. It also sets up the new vocabulary. Because
FORTH is its parent vocabulary, all the words in the FORTH vocabulary are
automatically in the NEWWORDS vocabulary. To show that NEWWORDS is actually in
the FORTH vocabulary, type VLIST. This will show NEWWORDS as the most
recently-defined new word in the vocabulary list.
So far we have defined the new vocabulary, but we are still working in the FORTH
vocabulary. There are two transitions between being in the FORTH vocabulary and
being in the NEWWORDS vocabulary. The first transition is to change the context
vocabulary. This determines the vocabulary which the computer uses to search for
words. To make NEWWORDS the context vocabulary, simply type NEWWORDS:

FORTH ■ NEWWORDS context


NEWWORDS
VOCABULARY VOCABULARY vocabulary
„ FORTH —4_I

searching
\f \f
for words

COMPUTER

The second transition into a new vocabulary is to change the current vocabulary. This is
the vocabulary which the computer uses to store new word definitions. While the
current vocabulary is still FORTH, the computer may search through the NEWWORDS
vocabulary, but it will still put new definitions into the old FORTH vocabulary To
change the current vocabulary to NEWWORDS, type

NEWWORDS DEFINITIONS
Now any new words defined will go into the NEWWORDS vocabulary:

70
| FORTH | ^ newwords definitions NEWWORDS current
VOCABULARY „ forth definitions VOCABULARY vocabulary
i___> —\-1 -i—-1

adding new words


to vocabulary

COMPUTER

Although the vocabularies can be made up separately, because FORTH is the parent
vocabulary, all word searches will end up looking through the FORTH vocabulary if a
particular word is not found in NEWWORDS. Thus, all new words defined in the FORTH
vocabulary are effectively also in the NEWWORDS vocabulary. If we create a third
vocabulary, THIRDLOT, again, words defined in FORTH are also available in THIRDLOT.
Words defined in THIRDLOT cannot be accessed when the context vocabulary is
FORTH, nor when it is NEWWORDS. We might also define a fourth vocabulary, SUBSET,
which has NEWWORDS as a parent li e., we make NEWWORDS the current vocabulary
and then define SUBSET using VOCABULARY). The word SUBSET is in the NEWWORDS
vocabulary, but not in the FORTH vocabulary, so SUBSET can only be accessed via
NEWWORDS. SUBSET can use all the words in NEWWORDS, and also all the words in
FORTH, but NEWWORDS can only use its own words and the words in FORTH. This can
be illustrated like this:

the arrow indicates information flow and the order in which the vocabularies are
established. Another analogy would be as a family tree. Imagine a peculiar sort of
genetics in which a mother could pass on all her genes to her offspring (which are
always girls) and the father of each generation can add genetic information to this.
FORTH is the mother, and the other vocabularies are her offspring; and you are the
fathers, adding different sets of genetic information to each generation.
Thus we can now have two or more independent groups of words. Because the
vocabularies are separate, we can define the same word differently in two or more
different vocabularies. For example, we might have two sets of words, each of which had
a similar function to its partner with the same name, but which was subtly different in
some way. We could use each of the pair in the same way, and because they had the
same name we would know what they did; but then by changing the vocabulary we
could produce that same subtle effect on both of them.
For example, suppose we had a set of words which made a picture of a man move
across the screen, and another set which made a frog move across the screen. It might
be the case that, as far as the rest of the program was concerned, it did not matter

71
whether it was a man or a frog - we might have some other words which fired missiles at
any creature moving across the screen. We could use words such as CREATUREMOVE,
CREATURECHANGE-COLOUR and so on, without caring what the creature was. But then
another part of the program might have a word KISS which changed the context
vocabulary and made the frog turn into a man.
We could probably have done all this just as easily without using different vocabularies,
although they would certainly have made it easier to think about what was going on.
However, we might also have completely different programs in the machine. If they are
in separate vocabularies then they can be listed and edited completely separately.

72
CHAPTER ELEVEN OTHER WAYS OF DEFINING WORDS
So far, we have been able to define words using either VARIABLE or CONSTANT. In
this chapter, we are going to do three things. Firstly, we shall look at what goes on in the
computer’s memory when a new word is defined, and how this word is used. Secondly,
we shall discuss other ways of defining new words. Finally, we shall use these ideas to
develop words to handle strings.

A word definition
When you define a new word, certain information has to be stored by the computer to
record the name of that word, what it is going to do, and so on. Broadly, this information
can be divided into the header and the parameter field. The header contains the name
of the word, a piece of information linking that word to the next one, and another piece
of information called the 'code field’, which tells the computer what kind of definition
this is (e.g„ whether it is a new word definition, a constant, or whatever). The parameter
field consists of the compilation address of the words in the definition, or the elements
of the array or whatever else is appropriate: in other words, the information which the
word contains.

NAME OF WORD

THE ADDRESS OF THE LAST WORD


DEFINED IN THAT VOCABULARY
HEADER
-1
GENERAL INFORMATION ABOUT
TYPE OF DEFINITION (CODEl
FIELD)

-1
CODE FIELD ADDRESS OF
j FI RST V\/ ORD

PARAMETER
FIELD

CODE FIELD ADDRESS OF


SECOND WORD |

It is instructive to look at the numbers stored for a word definition, to see all these bits
and pieces in action. There is a word., which takes any word defined in the current
vocabulary, and gives you the address of its parameter field. (A similar word, FIND, on
the Jupiter Ace, is the same, except that the result it gives is two higher than with “ ’ ",
because it gives the code field address instead. This is really more logical, as it is the
code field address which the computer uses in its parameter field.) Each word
definition will give you the compilation address of the words that it is made up of and
this is true of these other words as well. It is therefore quite easy to follow through the
definitions to the machine code subroutines of the primitives.

73
To see the parameter field, we can use another word, HERE. This gives the address of
the first free byte in the dictionary, i.e., the address after the end of the parameter field
address of the last word defined. The actual addresses of the memory locations will be
different in different computers; but if you find the start and end of the parameter field
and fetch each of the pair of bytes using @, you can compare these with the
compilation addresses of the words making up the definition. The bytes used to store
the header are used singly, so you should read them with C@ rather than with @. The
first byte stores the length of the name of the word (+128); the next bytes store the
ASCII codes of the name, except for the last letter, which has 128 added onto this (so
that the computer knows that this is the last byte of the group). The four bytes after that
are taken up by the link field address and the code field address.
One of the points that we made in the introduction is that FORTH is very fast. Some
versions of FORTH available for home computers are actually slower than BASIC;
however, a good FORTH system should work very quickly indeed. The reason for this is
that most of the work of a program is done when a word is compiled, rather than when it
is actually used. When you use a FORTH word, the computer has to search through its
dictionary to find the header of that word. However, since the final stage of writing a
FORTH application is usually to put all the parts together into one final word definition,
that definition will be the first one that it comes to. It will contain the compilation
addresses of all the words used, and those words will, in turn, contain the compilation
addresses of the words used to define them and so on. Thus at each stage, the
computer can go straight to the correct machine code subroutines. In BASIC, by
contrast, when the computer finds a word it has to search through its memory to find the
machine-code subroutines for that word, and so on for the next word. This is true no
matter how many times a particular word is used in a program, nor how often that
program is run.
A crude analogy between the two languages would be between a supermarket and a
country grocer’s. When a customer come to the check-out at a supermarket, all his
goods are together in the right place, so the cashier simply has to add up the prices. In a
small grocer’s, on the other hand, the shopkeeper has to go off looking for every item on
the list. In this example, of course, the total amount of work done is the same; but as far
as the owners are concerned, there is a very big difference in the speed of the sale.

New ways of defining words


In this section we will look very briefly at other ways of defining words, apart from with
CONSTANT and VARIABLE. This area is one of the most interesting and powerful in
FORTH, but it is not really for the beginner.
We have already met the word CREATE; and now we can look at it in more detail. We
have already used it to set up an array: it set up a header, but no parameter field, so we
were able to use it to provide a name and space in memory for the array, and then put
the elements of the array in the parameter field.
CREATE can also be used in some versions of FORTH to define words which can be
used to define other words - that is, it can be used to create defining words, lupiter Ace
FORTH uses slightly different terminology for this, which because it is different can be
slightly less confusing; so we shall stick to this version for the moment.
In the section on arrays, we had to use CREATE to set up a header and reserve enough
spaces, each time that we wanted to start an array. It would have saved a lot of energy if
we could have had a word which did all of this automatically. What we need, then, in
general, is a word that tells the computer how a word is to be defined, and then tells it
what this word will do, once it is defined. The two parts of this procedure are separated
by the word DOES> in the word definition; and because we are defining a new defining
word rather than just a regular word, we use another word called DEFINER instead of
the colon at the beginning. For example, if we wanted a word DIM like the
corresponding word in BASIC, we could say:

74
DEFINER (tells the computer that this is
to be a defining word, rather than
just a regular word)
DIM (this is the name of the defining
word that we are creating)
(this tells the computer to reserve
two bytes for each number to be
ALLOT stored in the array, when DIM is used)
DOES>
(this marks the division between
SWAP the two parts of the definition)
2*
(this is the part that tells the
computer how the word DIM will work.
It will take the array position off
the stack, and also the address of
the start of the array; and will
then move along memory by two bytes
; for each element.)
( we still need the semicolon, even though we don't
have a colon at the beginning)
The part after DOES> works in exactly the same way as the word used earlier to make
arrays. We can now use DIM to define arrays of any given size, e.g.,

5 DIM PAYROLL
will set up any array called PAYROLL with five elements. We can store and retrieve
values from PAYROLL in the same way as if we had set it up directly, e.g.,

12000 2 PAYROLL !
will put the value 12000 info position 2 of the array. To get this value back, we would say

2 PAYROLL @ .
There is another pair of words, used by lupiter Ace FORTH,

COMPILER. ...RUNS>
Which is used to define new compiling words. The FORTH-79 version uses the colon,
and CREATE.

CREATE.,.DOES>
is used in place of either of these pairs of words.

Strings
We have already met ways of printing strings (with '’) and have seen how the pad and
the words WORD and QUERY may be used to manipulate strings put into the computer.
Now that we have met DEFINER, we can create strings more easily, lust as we had a
defining word DIM which defined an array, so we can have a word STRING, which
defines strings:

DEFINER
36 this is the delimiter for WORD: it is the
ASCII code of $. WORD takes a string out
of the input buffer and reads it up to this

75
symbol - so when we are putting the
string in, we use this to mark the end)
WORD ( WORD takes the string in up to $ and puts
it in the pad. It puts the address of the
start of the pad on the stack, and puts the
length of the string at that address.)
DUP ( duplicates the address of the start of the
pad)
1+ (this is now the address of the start of the
string)
SWAP (these are swapped round, so that the
address of the start of the pad is on the
stack again.)
C@ ( puts the length of the string on the stack)
C, ( reserves one byte in memory, after the
header of the string)
OVER ( adds the length of the string to the
address of the start of the string, so as to
give the address of the end of the string)
SWAP ( puts the address of the end of the string
below the address of the top of the string,
ready for DO)
DO
I C@ C, (takes each element of the string from the
array, and puts it in one byte at a time to
the spaces in memory after the header).
LOOP (this is the definition of the word itself. It
DOES takes the string in the form given by
DUP WORD and converts it into the form
1+ required by TYPE. This is the same as the
SWAP corresponding part of the first part of the
C@ word.)

Using STRING is as straightforward as defining a string in BASIC. For example, in BASIC


we might say

let MESSAGE$ = " HAVE A NICE DAY "


and similarly, in FORTH we can now say,

STRING MESSAGE HAVE A NICE DAY $


if we want to see our string, we can say

MESSAGE TYPE

Last thoughts
in this book, we have not had the chance to look deeply into the more esoteric aspects
of FORTH. Moreover, because the book has been written to cover several different
versions of the language, we have not been able to explore interesting features which
are found in only one particular variety. But the greatest beauty of FORTH is that you
can make your own version grow to suit your particular needs. You have grasped the
basics of FORTH: now it is up to you to find out what you can do with it.

76
APPENDIX ONE
This section contains a number of short programs written for the Jupiter Ace, either for
the basic 3K version, or, in the case of one or two, for a machine with a 16K RAMpak.
Although these programs are, by necessity, machine-specific, they are very clearly
explained, so there will be no problem at all in modifying them to suit your individual
needs. (The simplest way to do this would be to define all those words used on the
Jupiter Ace which are not available or which are defined slightly differently in your
version.)
FORTH is a very compact language: however, on the basic 3K version of the Jupiter Ace,
there is-only about IK of memory available to the user, and this is not enough for any
but the simplest programs, even in FORTH. |n order to use this amount of memory as
effectively as possible, I have written the programs for the 3K machine as single words.
Apart from being quicker to key in, this means that memory is not wasted in word
headers and so on.

77
(1)LASERBASE
The basis of a large number of arcade games is gun-missile-target, and this game
consists of little more than that: it is therefore an excellent introduction to arcade
games. Many people, having learnt the structure of a high-level language such as
FORTH, are still unable to actually move things around the screen. This game is written
for the 3K machine, in only one word, but later in the book is a 19K version, using
several words, in which the game is developed in more detail.
The game consists of a laserbase, or missile silo, and a target which moves across the
top of the screen. This continues indefinitely, until the fire' button is pressed,
whereupon a missile shoots up from the silo. If the target is hit, the game stops with the
message 'HIT!' and waits until any key is pressed: this causes the game to continue as
before. To save the complexities of high-resolution graphics, the target is an X' and the
missile is the symbol'l'.
Here is the complete listing.

: BASE INVIS CLS 21 12

62 0
DO
I 01 PLOT
LOOP
BEGIN
300
DO
100 20 BEEP 1 I
ATX"
inkey 102 =
IF
020
DO
11 =
J 14 = AND
IF
I J AT
."HIT!"
1000 1000 BEEP 10000
DO
LOOP
BEGIN
INKEY
UNTIL
I J AT

LEAVE
THEN
114 AT
u |u

200
DO
LOOP
I MAT

78
/i n

-1
+LOOP
THEN
1000
DO
LOOP
1 I AT." "
LOOP
0
UNTIL

The first part of the program simply clears the screen and draws the silo:

INVISCLS
22 12 AT

The two words iNVIS and CLS are essential somewhere in a game program, if the scene
is not to be spoilt by "OK’s" and lines of text.
The next part prints the ground:
62 0
DO
I 0 1 PLOT
LOOP
This first part of the word is printed only once: the rest of the word is a continuous loop.
This starts with BEGIN and continues to 0 UNTIL at the end. We don’t want the game to
end unless we BREAK into it, and UNTIL returns the machine back to BEGIN unless the
top of the stack is non-zero.

300
DO
10020 BEEP 1 I
ATX"

This is the part that creates the target. Because FORTH is so fast, it is often necessary to
slow things down, and the easiest way to do this is with a DO LOOP, in this game, the
target appears on the screen all the time that the rest of the word is running, but even
so needs to be slowed down by the line 100 0 DO LOOP at the end. By varying the
length of the delay, the speed of the target can be controlled.
The method by which an image is made to move across the screen of a computer is
exactly the same as the way a cartoon is animated. The first print command prints the
character at a succession of positions across the screen, and after the delay, a second
print statement prints a space at the same positions. This 'unprints' the target. The
target therefore appears in one space, remains there for about 20 ms, then disappears.
About 5 ms later, it appears at the next space, and then disappears again: it therefore
seems to move across the screen. The lines to unprint are at the end of the word, after
the delay. This means that the target is on the screen for as long as possible, and
invisible for as short a time as possible. If the reverse were the case, it would appear to
flash on and off across the screen: and in any case, if the speed is increased beyond a
delay of about 20 LOOPS, the illusion of smooth motion begins to break down. Here are
all the parts from the program concerned with moving the target:

79
3 00
DO
100 20 BEEP 1 I
AT." X"
1000
DO
LOOP
1 I AT." "
LOOP
These words will move an 'X' once across the top of the screen, making a sound that is
supposed to sound like a flying-saucer.
The next part of the word registers the fact that the 'fire’ key has been pressed, and
initiates the fire sequence:

INKEY 102 =
IF
The word INKEY puts the ASCII code of the button being pressed at that time onto the
stack. Because a word is normally processed very quickly by the computer, there is not
enough time between pressing the enter' key (ASCII 13) and pressing the next key for
the code of the latter to get on the stack. Thus INKEY is only useful in a continuous loop
(as in this case) or if the program is made to wait until a button (other than ASCII 13) is
pressed.
When the 'fire' key (letter 'f'l is pressed, two things happen: the missile begins to move
upwards, and the program begins to check for a hit. 1 happen to have written the second
part first; but since the program works in a continuous loop, the actual order does not
matter.
The HIT!' message comes up if the missile and target are both printed in the same
space. The sequence begins with the start of another loop:

020
DO
The next bit checks if the missile (which we have not yet printed, but which will be at a
position determined by the loop we have just started) is in the same position as the
target:

I 1 =
J 14 = AND
IF
If they are, it prints the 'HIT!' message and makes a noise:

I J AT
." HIT!"
1000 1000 BEEP 10000
DO
LOOP
The missile moves from 20, 14 to 0, 14, while the target moves from 1,0 to 1,30. The word
| gives the value of the counter of the loop which controls the target, while the I is the
counter of the missile loop. Thus the line

I 1 =

compares the lines of the missile and the target, and the line

J 14 =
80
compares their columns. AND combines these such that the top of the stack is 1 only if
both conditions are true, i.e. 'if the missile and target are in both the same column and
in the same line. 1000 1000
BEEP is a long deep noise to mark the hit, and 1000 0 DO
LOOP is a delay. The next section waits for a key to be pressed before re-starting the
game: it is important that the 'HIT!' message is displayed long enough to be read
before this happens; and there must be enough time for the player to lift his finger from
the ‘fire’ key, otherwise that would activate the re-start mechanism, and the message
would never be displayed at all.
The section to re-start the game uses INKEY again, in another loop:

BEGIN
INKEY
UNTIL
Lastly, the HIT! message is removed:

I 14 AT
n n

LEAVE
THEN
LEAVE leaves the DO LOOP, and so gets us back to where we were before the missile
was fired.
The next part of the program produces the missile, in the same way that the target was
produced:

I 14 AT
// | n

200
DO
LOOP
I MAT
n rr

After that,

LOOP
THEN
completes the IF sequence started by pressing the 'fire' button.
The last part of the program unprints the target:

1000
DO
LOOP
1 I AT." "
finally LOOP completes the loop producing the target, and

0 UNTIL

completes the continuous loop which keeps the whole program running indefinitely.

81
(2) LASERBASE (FOR 19K)
This version of the game uses the extra memory of the 19K machine to improve on the
graphics of LASERBASE and to add a scoring system. I have suggested other
modifications that would improve the game still further.
This version uses separate words for the different parts as follows:
(1) HI This is the same as the word 'GR' in the manual: it makes spaces in the right part
of memory for the digits of the high resolution graphics. To simplify things, 1 have not
used binary notation for the graphics: it is much quicker to use the decimal equivalent,
since the numbers are much shorter, and since this does not require conversion into
binary mode. 1 worked out which numbers to use from the binary, however.

: HI 8* 11263 + DUP
8+
DO
1C! -1
+ LOOP

This stores the numbers on the stack (added in the next word) one byte at a time into
the appropriate memory spaces. The high resolution graphics are stored between
address 11264 and 12287, with eight bytes per character. They are arranged in order of
their ASCII codes, so this word has to work out from the ASCII code where to place the
information. You can use the codes of any characters, so for simplicity we have used
ASCII 1 to 4. Thus the bytes for the character with code 1 will lie between 112271 and
11286, and so on.
(2) The next word draws an improved version of the laser base, using the word HI to
define graphic symbols.; and it also prints the words ‘'targets” and “missiles" as
headings for the score table.
First the screen is cleared:

:LBASE
IN VIS CLS
then the headings are drawn:

15 0 AT
."TARGETS"
15 2^ AT
." MISSILES"
The next part defines two triangular pieces which are used to make the sides of the
laserbase:

01 3715
31 63 127 1 HI
This defines graphic symbol 'a' as A\ while

0128 192 224


240 248 252 254
2 HI
graphic symbol 'b' (ASCII 2) as k. These are used in the print statement:

21 12 AT

82
Finally, the ground is drawn as before:

62 0
DO
I 01 PLOT
LOOP
/

(3) Two variables are needed: M for the number of missiles left and T for the number of
targets left. These must be given an initial value:

10 VARIABLE M
10 VARIABLE T
(4) The word TARGET defines the graphic symbols for the target (a flying saucer) and
the missile:

:TARGET
0060 126 0
126 6003 HI
24 24 60 6060
60 60 126 4 HI
r

(5) The word MCHECK regulates and displays the number of missiles left. The first part
reduces the number of missiles (M) left by one, each time a missile is fired, and prints
M:

0 VARIABLE M
: MCHECK
M @ DUP DUP1-
M!1625 AT

The next part initiates the '1 HAVE WON!' sequence if no missiles are left. There is also a
BEEP, and a DO LOOP which makes the message flash on and off five times:

0= IF
CLS 5 0 DO
10 10 AT."I HAVE WON!
7001000 BEEP 5000
DO
LOOP
10 10 AT."
500 0
DO
LOOP
LOOP
EXIT
THEN

EXIT causes the computer to leave the word and move to the next one.
(6) The analogous word TCHECK regulates and displays the number of targets left. The
player wins the game if he destroys all the targets before all his missiles are left:

83
:TCHECK
T @ DUP DUP1 —
T! 16 4 AT
.0=
IF
50
DO
1010AT." YOU HAVE WON!"
700 1000 BEEP
500 0
DO
LOOP
10 10 AT."
500 0
DO
LOOP
LOOP
EXIT
THEN

The structure of this word is very similar to the previous one: reduce number of targets
by one; print number; test if number is zero; if so, print message; make noise; make
message flash on and off five times; leave word.
(7) The next word is the most complicated, and it includes the complete fire sequence,
plus the words developed above.

: FIRE
M10 ! T10 !
This initializes the values of M and T. This is not necessary at the beginning, but does
save having to type the values in after each round.
Like the last version, this word runs in a continuous loop using BEGIN at the beginning
and 0 UNTIL at the end, and has the loop which controls the target outside that which
controls the missiles. This part starts off the continuous loop and prints the target:

BEGIN
300
DO
100 20 BEEP 1 I
AT."S"
As before, INKEY now takes the ASCII code of the button being pressed and puts it on
the stack, if it is the 'fire' button, the fire sequence is initiated as before, and MCHECK
reduces the number of available missiles by one, displays the number left and checks
how many are left:

INKEY 102 =
IF MCHECK
The rest of the word is the same as in the previous version, except that TCHECK is
inserted after each target is hit, to reduce the number of targets by one, etc., and the
number of missiles is brought back to 10 at this point. There is also a mechanism for
speeding up the missiles as the number of missiles left goes down. This is the HIT!
sequence again:

84
020
DO
11 =
J 14 = AND
IF
IJ AT
HIT!"
TCHECK
10 M !
1000 1000 BEEP 10000
DO
LOOP
BEGIN
INKEY
UNTIL
IJ AT
// n

LEAVE
THEN

Next, the missile is printed. The length of the delay loop, and hence the speed of the
missiles, is determined by the number of missiles left:

I MAT
"JL"
M@4*10 + 0
DO
LOOP
I MAT
// n

Because of the way the lines are mapped on the screen, the loop to control the
movement of the missile goes from 20 to 0. We therefore need to put -1 on the top of
the stack and use +LOOP instead of LOOP. This adds the top of the stack to the loop
counter, rather than just automatically adding I as LOOP does.

-1
+ LOOP
THEN
As before, there is a delay to slow the program down to a workable level:

1000
DO
LOOP
Finally, the target is unprinted, the loop for the target is finished, and the continuous
loop around that is completed:

II AT." "
LOOP
0
UNTIL

85
The game, then, is as follows: as before, a target (looking this time more like a
flying-saucer) moves overhead, while the laserbase waits on the ground. When the ‘fire’
button is pressed, a missile (looking like a missile) shoots up at it. Initially there are ten
missiles and ten targets. Each time a missile is fired, the number left is displayed, and
the missiles speed up slightly. If all the missiles are used up, the computer wins.
However, each time a target is hit, the supply of missiles is replenished. Each time a
target is lot, the number of targets left is also recorded, and if they are all destroyed
before all the missiles, have gone, the player has won. As before, a missile is fired by
pressing button ‘f, and the game is restarted after firing by pressing any button. The
game can be played by keying in the words above as follows:

HI
10 VARIABLE M
10 VARIABLE T
TARGET
MCHECK
TCHECK
LBASE
FIRE
A number of modifications would improve the game still further. The main problem at
the moment is that the target moves very predictably, and so is fairly easy to hit. The
speed could be randomized, as could the height and direction from which it comes. In
addition, one might want to add some unpredictable hazard, such as a meteor or
another spaceship.

86
(3) SQUASH

This game, which was written for the 19K machine, consists of a court with a goal at one
end. The ball moves around the court, bouncing off the walls, and off the bat. The latter
can be moved up and down using the cursor keys (without using SHIFT), and the aim is
to prevent the ball from going into the goal. The ball makes a high-pitched sound when
it bounces off something, and a longer, lower note when it ends up in the goal. To get it
out of the goal, press any key. The words used are as follows:
WALLS - this builds the walls and the goal.

CLSINVIS
As usual, this clears the screen and removes the messages. The next part draws the top
and bottom of the screen, using a loop:

32 0
DO
01 AT."B"
221 AT."B"
LOOP
The next section uses another loop to print the end of the court:

23 0
DO
I 0 AT
LOOP
The end with the goal is printed in two lots: the part of the wall below the goal, and then
the part of the wall above the goal:

2315
DO
131 AT
LOOP
80
DO
131 AT
LOOP

The next set of words control the bat. This moves up or down, depending on which
cursor key is pressed. The first word, BAT, actually draws the bat; but first, it is
necessary to initiate a variable:

0 VARIABLE X
X gives the line number of the top of the bat. This is used to draw the bat, using a loop:

: BAT
5X@ + X
@
DO
I 25 AT
LOOP

The next word, CLEARBAT, removes the bat after it has been printed:

87
: CLEARBAT
22 1
DO
I 25 AT "
LOOP

The word MOVEBAT responds to the cursor keys. The ASCII code of 7 (the key with the
downward arrow as second function) is 55. INKEY puts this number on the stack if this
key is pressed, and IF it is, increases the value of X by 1. Similarly, if key 6 is pressed, X
is decreased by 1. Because this word will be used in a loop, it will test repeatedly for
the key which is being pressed. This means that if either key is pressed during the
game, the bat will move slowly in the appropriate direction.

: MOVEBAT
INKEY 55 =
IF
X@1+ X !
THEN
INKEY 54 =
IF
X@1-X
!
then

If the bat were to go too high or too low, the game would stop, and an ERROR would
show. Consequently, this word, CHECKBAT, stops it moving beyond the court:

:CHECKBAT
X @ 0=
IF
1 X!
THEN
X@ 18 =
IF
17 X !
THEN

Notice that 0= is a single word, defined in the FORTH dictionary, but 18 = are two
words.

The next set of words control the ball. First, we must initialize four variables:

4 VARIABLE BX
4 VARIABLE BY
1 VARIABLE BIX
1 VARIABLE B1Y
The first two of these are plot-variables, and control where the ball will be plotted:

: BALL
BX @ BY @ 1
PLOT

88
The second two variables are control variables, and control the movement of the ball:

: MOVEBALL
BX @ BIX @ +
BX ! BY @ B1Y
@ + BY !

Each time the program passes through this word, the position of the ball is shifted by
one unit in both directions.
The value of the control variables determines the direction that the ball will travel: for
example, if BIX is 1, the ball will move from left to right. Clearly, if the value of the
control variable is multiplied by -1, the ball will change direction. The next word,
CHECKBALLWALLS, ensures that the ball bounces off the walls when it hits them (and
it also makes a noise). When the ball hits the side walls, the value of BIX is multiplied
by — 1: so if it is moving left it starts moving right and vice versa:

: CHECKBALLWALLS
BX @ DUP 60 >
SWAP 3 < OR
IF
BIX @ —1 * BIX
! 100 100 BEEP
THEN
Similarly, if it hits the top or bottom of the court, the direction of motion in the
y-direction is reversed:

BY @ DUP 42 >
SWAP 3 < OR
IF
B1Y@ -1 * B1Y
! 100 100 BEEP
THEN

The next work causes a long, deep sound when the ball hits the goal, and makes the
game wait until a button is pressed before continuing:

: CHECKBALLGOAL BX @ 60 > BY
@ DUP 15 > SWAP
30 < AND AND
IF
1000 1000 BEEP
BEGIN
IN KEY
UNTIL
10 BX !
THEN

The next word makes the ball bounce off the bat. The problem with this is that the bat
moves using the co-ordinates of the AT system. These have to be converted to the
co-ordinates of the plot system, in which the units are smaller and which go down the
screen rather than up it. The first part checks whether the ball is at the same horizontal
position as the bat:

89
: CHECKBALLBAT
BX @ 51 =
Next, we convert the position of the top part of the bat into PLOT co-ordinates:

BY @ DUP 22 X @
- 2 * DUP1 +
ROT >
The next part converts the bottom of the bat into PLOT co-ordinates:

ROT ROT 10
-AND AND
IF
100 100 BEEP B1X@
-1 * BIX!
THEN

The final word, SQUASH, puts all these words together in a continuous loop:

:SQUASH
WALLS
BEGIN
BALL
CHECKBAT
BAT
MOVE BAT
100 DO LOOP
CLEARBAT
BX @ BY @ 0
PLOT
CHECKBALLWALLS
CHECKBALLGOALS
CHECKBALLBAT
MOVEBALL
0 UNTIL

90
(4) CODE
Here is a very short program called CODE, which converts messages into a series of
numbers on the basis A= I, B=2, etc. It is a useful illustration of the word WORD, which
takes words from the input buffer and stores them in an area of memory known as the
pad. The program accepts either capital or lower-case letters (unlike the other
programs), and can cope with 254 characters. Here it is altogether:

: CODE
QUERY 35 WORD DUP C@
2 + + 9986
DO
I C@ DUP DUP DUP
DUP DUP 64 > SWAP
91 < AND
IF
64- .
THEN
96 > SWAP 123 <
AND
IF
96- .
THEN
32 =
IF
32 EMIT
THEN
LOOP

To encode something, type in and ENTER this word, then ENTER your secret message.
The word QUERY stops the program to allow you to enter something into the input
buffer (i.e., to type things in at the bottom). 35 WORD takes in text from the input buffer
up to the symbol # (ASCII code 35).

: CODE
QUERY 35 WORD
WORD copies the words from the input buffer to an area of memory called the Pad. it
leaves the message (in the form of the ASCII codes of the letters) in addresses 9986
onwards, and the number of characters stored in address 9985. It leaves the number
9985 on the stack. Thus suppose the message were 'Meeting tonight' the pad would
contain

15 (no. of characters) at address 9985


77 (Capital 'A') at address 9986
101 (small 'e') at address 9987
and so on.

The starting address and the number of bytes filled are used in a DO...LOOP: C@
leaves the length of the message, and this is added to the starting address (plus one) to
give the end of the loop. The loop starts at 9986:

DUP C@
2 + + 9986
DO

91
For each address (given by I), the number is fished out of the pad with C@ and
duplicated five times in preparation for the manipulation to come. (Notice that we are
using C@ rather than @ to 'fetch’ the contents of an address. This is because we are
only dealing with one address at a time. @ takes two bytes at a time, and is used when
we are re-calling variables).

I C@ DUP DUP DUP


DUPDUP
Next, we want to know if the letter is a capital:

64 > SWAP
91 < AND
If it is, we subtract 64 to give us our code:

IF
64- .
THEN
Secondly, we want to test if it is small-case:

96 > SWAP 123 <


AND
IF
96- .
THEN
Finally, we want to test whether or not it is 32 (the ASCII code for a space). If it is, we
want a blank space:

32 =
IF
32 EMIT
THEN
LOOP

EMIT prints the symbol whose code is the top number on the stack.
The main objection to this code is that it is fairly obvious, and therefore easy to crack.
Flowever, once the message has been converted into numbers, it can be manipulated
mathematically.
Here is a second word, DECODE, which will turn your messages back into English:

:DECODE '
INVISCLS
BEGIN
QUERY LINE DUP 35 =
IF
EXIT
ELSE
64+ EMIT
THEN
0
UNTIL

92
This will continue indefinitely, unless you ENTER 35 (the ASCII code for #). Because
CODE produced a space rather than a code number to correspond with a space in the
message, DECODE cannot decode a space. If you want a space in the decoded
message, ENTER -32. Note that in DECODE you must press ENTER after each code
number, rather than at the end of the message as is the case with CODE.

93
(5) MUSIC
This short program, which fits easily on the unexpanded machine, turns the Ace into an
electronic organ. Here first of all is the listing:

: MUSIC
BEGIN
BEGIN
INKEY
UNTIL
INKEY 100 + DUP 10
10 AT. 100 BEEP
10000
DO
LOOP
0 CLS
UNTIL

There are two BEGIN...UNTIL loops, one inside the other. The inner makes the
computer wait until you have pressed a key: until then IN KEY leaves 0 on the stack, and
UNTIL returns to BEGIN. The outer loop simply makes sure that the program continues
indefinitely.
When a key is pressed, INKEY puts its ASCII code on the stack. We add 100 to this, in
order to make a better range of notes. DUP duplicates this, so we don't lose it when we
print it. It is then printed at position 10 10, right in the middle of the screen:

INKEY 100 + DUP 10


10 AT. 100 BEEP
Next, there is a delay, so that one note is not confused with the next one:

10000
DO
LOOP
Finally, 0 CLS UNTIL clears the screen and leaves 0 on the stack so that the loop
continues.
There are a number of modifications which would make the program more interesting:
(1) Increasing the range of notes by a factor of two, say;
(2) Producing a musical scale on the screen, rather than just the pitch number;
(3) Producing a vibrating note, rather than a static one
(4) Using other keys to change the length of the note.

94
(6) QUICK-SUM
This program, which is suitable for the unexpanded machine, flashes sums very briefly
on the screen, and asks you for the answer. You score one point for each sum you get
right, and the machine gets a point if you get the answer wrong. There are nine words
and variables, which should be keyed in in the order in which they are given. The word
QSUM will start the game.
(11 At first, the variable S must be set at 0:

0 VARIABLES

(2) The randomizing word may look familiar:

: RND
S@ 7511*75
0D+ OVER OVER U<
- - 1-DUPS
! U* SWAP DROP

This word (which is based on the words used in the manual I works by shifting around
the two parts of double-length integers.
(3| This word produces a pause using an empty loop:

:PAUSE
12000
DO
LOOP

(4) The next word is another ‘convenience word’ which simply saves us having to type
out the same sequence several times over, it is used for the print statements:

: PNT
1010
AT

(5) In order to record the score on the screen, we will need two variables, which first
need to be initialised. MS gives the value of the computer's score ‘MY SCORE’, which is
the number of sums that you get wrong:

0 VARIABLE MS

(6| Similarly, YS gives the value of 'YOUR SCORE’, which is the number of sums that you
get right:

0 VARIABLE YS

(71 The word SCORE prints the score chart at the bottom of the screen:

:SCORE
14 8 AT
."ME SCORE YOU"
27 6 DO 161 AT."B" LOOP
18 8 AT MS @
■" 18 23 AT YS @
23 16 DO I 16 AT

95
LOOP

The first part of SCORE prints out the heading of the score table. There should be four
spaces between the words. The next part prints a line underneath the title:

27 6 DO 16 I AT.LOOP
The next part prints the score of the computer:

18 8 AT MS @
and of the player:

18 23 ATYS@
The last part balances the chart by putting a vertical line between the two sides:

23 16 DO I 16 AT
LOOP

(8) If we used CLS to clear the screen after each part of the sum, the score chart would
be lost as well. So here is a word which just clears the part of the screen with the sums:

: CLEAR 23 10 DO
71 AT." " LOOP

(9) Finally, here is the word which puts everything together and contains the rest of the
program. First of all, here is the complete listing:

: QSUM
INVIS CLS 0 11 AT
."QUICK-SUM"
32 0
DO
21 AT."B"
LOOP
BEGIN
SCORE CLEAR 21 RND DUP
PNT. PAUSE 100 100
BEEP CLEAR PNT." +"
PAUSE 200 100 BEEP 21
RND DUPPNT.PAUSE
100100 BEEP CLEAR PNT
." = ? "
200 100 BEEP PAUSE +
QUERY LINE =
IF
YS @ 1 + YS !
."YES!"
ELSE
MS@ 1+ YS !
. " NO!"
THEN 1000 1000
BEEP SCORE PAUSE

96
0 UNTIL

The first part of the word, as usual, clears the screen and stops the ‘OK' being printed:

: QSUM
INVISCLS
The next part prints the caption:
0 11 AT
QUICK-SUM"
And a line underneath:
32 0
DO
2 I AT
LOOP

Now the continuous loop is started; the score table is printed; and the sums from last
time are cleared off the screen (they are obviously not there the first time around):

BEGIN
SCORE CLEAR
The next part chooses a random number between 0 and 20, prints it out in the middle of
the screen for a short time, and sounds a note at the same time:
21 RNDDUP
PNT.PAUSE 100100
BEEP CLEAR
The next part prints the "+" sign in the same space:
PNT." +"
PAUSE 200 100 BEEP
And finally, the second number to be added:
21
RNDDUP PNT. PAUSE
100 100 BEEP CLEAR
Then, the computer asks for the answer to the sum, and adds them together itself:
PNT
." = ? "
200100 BEEP PAUSE +
The next word, QUERY, allows the player to enter the answer in the input buffer: when
this happens, the cursor will appear at the bottom. You can put in your answer and
correct it if necessary using the usual keys. The word LINE interprets the input buffer
(i.e„ what you have just typed) as normal FORTH words. (This might be what you would
expect it to do anyway; but compare LINE with words such as WORD and EXECUTE.)
The two words QUERY LINE together are equivalent to the BASIC word INPUT. So

QUERY LINE =
IF
asks you for your answer and compares it with the top of the stack. If the answer is right

97
the value of YS is increased by one and the word "YES" is flashed on the screen:

YS @ 1 + YS !
"Yes!"

If not, the value of MS is increased instead, and the word "NO!" is flashed up instead:

ELSE
MS @1+ MS !
NO!"

In each case, there is a longer note:

THEN 1000 1000 BEEP

Finally, the new score is put up, there is a PAUSE and the continuous loop is
completed:

SCORE PAUSE 0
UNTIL

An interesting modification to this game, which would require the 16K RAMpak, would
be to randomize the type of sum, ie or *. Each function would be given a code
number, which would be selected in the same way as the operands were chosen here.
Another change would be to use INKEY instead of QUERY LINE to imput the answer: it
would then be possible to incorporate a time limit for answering the question. One
might also make the scoring dependent on the length of time given or on the possible
range of numbers. If it were slowed down several times, it might be useful for children
learning to do arithmetic.

98
(7) SNAP
This program, which requires the 19K machine, uses several of the words developed in
‘QUICK-SUM’. Instead of having to add up two numbers, however, the aim is to play
'snap' with them. Two random numbers will be flashed very briefly on the screen. If they
are the same, you must press the ‘S' button as quickly as possible (without CAPS
LOCK). If you press the button at the right time, you get a point, but if you miss it, or if
you press when the two numbers are not the same, the computer gets a point instead. If
you find the game too easy, either reduce the length of the pause by decreasing the
number of loops in the word PAUSE, or decrease the number of PAUSES which give you
time to think when pressing the button.
The words are as follows, and should be keyed in in the order given:
(1) 0 VARIABLE MS (to set the value of 'MY SCORE' at 0 and initialise that variable);
(2) 0 VARIABLE YS (for 'YOUR SCORE').
(3) 0 VARIABLE S (for the word RND).
(4) RND This is just the same as in 'QUICK-SUM'.
(5) PAUSE (as in 'QUICK-SUM').
(6) CLEAR - this serves the same function as the word in 'QUICK-SUM', but has a
slightly different range of values:

: CLEAR
32 0
DO
81 AT "
LOOP

(7) SCORE (as in QUICK-SUM).


(8) SNAP. This is the heart of the program. First of all, here is the complete listing:

: SNAP
INVIS CLS 011 AT
SNAP"
32 0
DO
2 I AT
LOOP
BEGIN
SCORE CLEAR 10 RND DUP
8 8 AT. 100
100 BEEP PAUSE 10 RND
DUP823 AT.
= PAUSE 100 100 BEEP
CLEAR 8 10 AT."SAME?"
PAUSE PAUSE PAUSE 200 100
BEEP CLEAR
IF
INKEY 115 =
IF
8 10 AT."YES!"
200 100 BEEP YS@
1+YS !
ELSE
MS@ 1+ MS !
THEN

99
ELSE
INKEY 115 =
IF
MS@ 1+ MS !
THEN
THEN
SCORE PAUSE PAUSE 0
UNTIL

The first part of the word clears the screen, prints the title and underlines it:

: SNAP
IN VIS CLS 0 11 AT
SNAP"
32 0
DO
21 AT."B"
LOOP

Then the continuous loop is started, the score is printed and the centre of the screen is
cleared.

BEGIN
SCORE CLEAR

Following that, the first random number is chosen, duplicated for checking later and
printed on the screen. After this, there is a short note and a pause:

10RND DUP
8 8 AT.100
100 BEEP PAUSE

This is repeated for the other number:

10RND
DUP8 23 AT.
= PAUSE 100 100 BEEP
CLEAR

The = equates the two numbers on the stack - i.e., the two random numbers which
have just been displayed. The computer then asks if these two numbers are the same:

8 10 AT."SAME?"

There is a longish pause to allow you time to think:

PAUSE PAUSE PAUSE 200 100


BEEP CLEAR

Now comes the tricky point. There are four contingencies which have to be catered for:
the player may press the button and the two numbers are the same (YS + I); he may
press the button but the two numbers are not the same (MS +1); he may not press it,
even though they are the same (MS +1) or he may not press it when they are different
(no change in score). In addition, if the player does score a point, there is a sound, and
the word 'YES!' flashes on the screen. To begin with, we test if the two numbers are the
same and the button is pressed:

= (a few lines above)

100
IF
INKEY 115 =
IF
8 10 AT." YES"
200 100 BEEP YS@
1+YS !

i.e., ‘YOUR SCORE' goes up by one. If you miss the button,

ELSE
MS @ 1+ MS I
THEN

If the numbers are not equal:

ELSE
INKEY 115 =
IF
MS@ 1+ MS !
THEN
THEN

The score is printed again; there is another pause, and the continuous loop is finished:

SCORE PAUSE PAUSE 0


UNTIL

101
APPENDIX TWO

This section contains a summary of all the FORTH words introduced in this book, for
reference.
KEY: n = single length integer
u = unsigned integer
f = floating-point number (this must have a decimal point in it somewhere)
‘file’, 'word-name' etc., refer generally to a word or file name.
In this section, an abbreviated representation of the stack is used, in which the
element on the right is at the top of the stack.
! p.l 1 (n, addr. —» -)
Pronounced 'store': this stores the second number on the stack in the address given by
the top number.
# pp.64, 68 (udl —> ud2|
Used in formatting. Produces the next digit from the integer udl and stores it in the pad.
# > p.68 (ud —> addr., n)
This ends the process of formatting and gives the address and length of the string
formed.
#S p.68 (ud —> 0,0|
Produces all the digits from ud until ud is equal to 0. #S carries out the process
performed by # for all the remaining digits of the double-length unsigned number ud.
' p.73 (nnnn —> addr.)
This gives the parameter field address of a dictionary word. It is not found on the lupiter
Ace, but there is a very similar word, FIND.
( pp.18, 60
Starts a comment. Notice that, as this is a word, it must be followed by a gap.
) pp.18, 60
Finishes a comment. This is not a word, but a delimiter, so it does not have to be
separated from the comment by another gap.
# pp.5, 6, 9 (nl n2 —> n I *n2)
Multiplies the top two (single-length) numbers on the stack, leaving the product on top
of the stack.
*/ pp.46 (nl n2 n3 —> (n 1 *n2)/n3)
Works out the product of the top two numbers on the stack (to double-length accuracy)
and divides this by the number third on the stack.
+ pp. 4, 6 (nl n2 —> nI +n2)
Ads the top two single-length numbers on the stack and leaves the sum on the top of
the stack.
+ ! p.13 (nl addr.—> -)
(Not found on the lupiter Ace). Adds the number second on the stack into the memory
address first on the stack (in other words, it adds this new number to the original
number stored at this address, and stores the sum there instead).
+ LOOP pp.27, 83 In —» -)
Takes the step size n of the loop off the stack and adds this to the counter. If the
counter is less than the limit, (if n is positive), or greater than the limit (in the cases
where n is negative), it loops back to DO.
, p.16 (n —» —)
Encloses a single-length integer n in the dictionary.
— p.8 (nl n2 —» nl-n2)
Takes the top number of the stack away from the second number and leaves the result
on top of the stack.

102
— DUP p.48 (runn) if n =ff
(n—»n) if n=0
— DUP is the same as ?DUP. It copies the top number on the stack, provided that this
number is non-zero. (It is called ?DUP on the lupiter Ace.)
—> p.61 (—) Editor vocabulary
(Not found on the lupiter Ace). This links two screens together so that one is
interpreted with the next. It is put at the end of the first of each pair of screens to be
linked in this way.
. pp.7, 13 (n —» —)
Prints the single-length signed integer n to the screen, followed by a space.
.” p.9 (nnnn —> -)
Prints the string up to the delimiter' “ ’. As with (, this is a word, so it must be followed
by a gap.
/ p.8 Ini n2 —* nl/n2)
Divides the second number on the stack by the first number, and leaves this result on
the stack.
/MOD p.8 (n 1 n2 —* remainder, quotient of nl/n2)
Does the same as /, but also leaves the remainder on the stack below the quotient. The
remainder is given the same sign as the dividend.
0< P-25 (n flag)
Same as 0 and < separately: leaves a true flag (1) if the single-length integer n is
negative.
0= p.25 (n —> flag)
Leaves the true flag (i.e., 1) if n is zero, and a false flag if it is non-zero. In other words, it
has the effect of reversing the truth value of the top of the stack. This is the same as
NOT, defined in some versions of FORTH.
0> p.25 (n —» flag)
Leaves flag I if n is greater than 0, and leaves 0 otherwise.
1+ p.22 (n n + 1)
Same as 1 and + separately, but works faster and saves one keystroke when it is being
typed in.
1- p.22 (n —> n—1)
Same as I and - separately, but faster.
2+ p.22 (n —* n + 2)
Same as 2 and + separately, but faster.
2- p.22 In —> n —2)
Same as 2 and - separately, but faster.
2DROP p.48 (d I —> —)
Double-integer version of DROP.
2DUP p.48 (d 1 —> d I dl)
Double-integer version of DUP.
2ROT p.49 (d3 d2 d I —> d2 d 1 d3)
Double-integer version of ROT.
2SWAP p.49 ( d2 dI -»dl d2)
Double-length version of SWAP.
(None of these double-length stack manipulators is available on the lupiter Ace, but
suitable definitions are given in the text.)
: p.26
Starts a colon definition.
; p.26
Ends a definition started by colon, DEFINER or COMPILER.

103
;S p.6l
Ends compilation of a screen.
< p.25 (nl n2 —» flag)
Gives a 'true' flag if nl n2, but a false one otherwise.
<# p.68 (-)
Starts formatting procedure.
= p.24 (nl n2 —> flag)
Gives a 'true’ flag if n 1 = n2
> p.24 (nl n2 flag)
Gives a ‘true’ flag if nl n2, and a false one otherwise.
>= p.25 (nl n2 —» flag)
Gives a ‘true’ flag if nl n2 and nl=n2, but a false one otherwise. (Not defined on the
Jupiter Ace.)
>R p.49 (n —» —)
Takes the top number on the stack and puts it at the top of the Return Stack.
? p. 13 (addr. —» —)
Fetches and prints the contents of the address given. (Not defined on the Jupiter Ace.)
?DUP p.48 (n —> n n) if n f); (n —» n) otherwise
Same as -DUP: duplicates the top of the stack, provided that it is non-zero. If it is zero,
it has no effect.
@ p. 12 (addr. —» n)
Pronounced 'fetch': gives the value of the number stored at the address at the top of
the stack.
ABORT p.51
Clears both the stacks, destroys any incomplete word definitions and returns control to
the keyboard.
ABS p.48 (nl -> n2)
Gives the absolute value of n, ie the value without the sign.
AGAIN p.20
Ends a BEGIN...AGAIN loop which carries on forever. AGAIN is not found on the lupiter
Ace, but has the same action as 0 UNTIL.
ALLOT p.14 (n —» -)
Encloses n bytes in the dictionary.
AND pp.32, 33 (nl n2 -> nl AND n2)
Performs a Boolian AND operation on the top two numbers of the stack.
ASCII p.53
Gives the ASCII code of the first letter of the next word in the input buffer.
AT p.53 (line column —» —)
(For the Jupiter Ace). Takes the line and column numbers of the next printing position
off the stack.
B p.60 (Editor vocabulary)
Used in conjunction with F in the Editor. B moves the cursor back to the beginning of a
string so that it can be edited.
BASE p.37
A system variable containing the number base that the machine will use to interpret
and print out numbers. On the lupiter Ace this is a one-byte number, so it is changed
with Cl; but in the Artie version for the Spectrum it occupies two bytes, and so is
changed with !
BEEP p.51 (n2 n 1 —» -)
This varies, depending on the sound facilities of the computer. On the Jupiter Ace, the
top number on the stack is the time in milliseconds and the second number is the

104
period of the note in units of 8 ju.s. On the Spectrum, BEEP works just like BEEP in
Spectrum BASIC, except of course that it takes the numbers off the stack.
BINARY p.65 (udl, addr.l —> ud2, addr.2)
This is the same as CONVERT; and is used to turn a string into any unsigned
double-length number. It adds the binary number that it creates from the string onto
udl, and leaves this on the stack as the unsigned double-length number ud2. The string
is found at addr. I, and addr.2 gives the end of the string,
BLANKS p.19 (addr., n —» —)
Fills n bytes with blanks, starting at the address given by the second number on the
stack.
BLOAD ‘file' p.62 (addr., n —» -)
Loads a maximum of n bytes of the file ‘file1 starting from the address given second on
the stack.
BSAVE 'file' p.62 (addr., n —» —)
Saves a maximum of n bytes to the file 'file' starting at the address given.
BVERIFY 'file' p.62 (addr., n -» -)
Compares a maximum of n bytes from file 'file' against the bytes stored in memory from
the address given.
(The last three words are only used on the lupiter Ace.)
BYE p. 11
(Used in Spectrum FORTH). Returns the machine to BASIC.
C 'text' p.61 (Editor vocabulary).
It takes the text typed in after it and puts it at the current cursor position.
C! p.61 (n, addr. —» —)
Stores the lower (less significant) byte of the single-length integer n at the address
given.
C@ p.39 (addr. —> byte)
Puts the contents of the byte stored at the address given onto the stack.
CIRCLE pp.5l, 56 (nl n2 n3 -» -)
Used in Spectrum FORTH. Draws a circle of radius nl at plot co-ordinates n2,n3.
CLEAR pp.59, 62 (n —» —) (Editor vocabulary)
Clears screen n and selects it for editing.
CLSp.li
CLS clears the television screen.
CMOVE p.)8 (addr.l addr.2 —» n —)
Moves n bytes from the section of memory starting at address I up to address 2. The
procedure starts at address 1.
COLD p.51
Performs a cold start, clearing the stacks and all those words that you have defined.
COMPILER p.75
Starts the definition of a new computing word.
CONSTANT 'name' p. 14 (n —> —)
Creates a constant with value n and name 'name'.
CONVERT pp.39, 66
Same as BINARY.
CR p.10 (-)
Makes the next line of printing start on a new line (CR stands for ‘Carriage Return’.)
CREATE 'name' pp.16, 74
Creates a new word without a parameter field.
D p.60 (n —» —) (Editor vocabulary)
Removes the contents of line n from the screen and puts them in the pad.

105
D+ p.44 (dl d2 —> dl + d2)
Adds the two double-length numbers at the top of the stack.
D— p.44 (dl d2 —* d 1 —d2)
Subtracts the top double-length integer from the second double-length integer.
D. p.44 (dl -* -)
Prints out the double-length integer at the top of the stack.
D< p.44 (dl d2 —» flag)
Gives a true flag if d 1 <d2.
DABS p.68 (dl -» d2)
Gives the absolute value of the double-length integer dl.
DECIMAL p.37 ( —)
Returns the base number to ten.
DEF p.54 (blb2...b8 nl -» -)
Used in Spectrum FORTH to create a user definable graphic character.
DEF1NER p.75
Used in Jupiter Ace FORTH together with DOES> to create new defining words.
DEFINITIONS p.70 (-)
Makes the context vocabulary become the current vocabulary as well.
DELETE p.60 (n —» —) (Editor vocabulary)
Takes a number n off the stack and deletes n characters to the left of the cursor.
DO p.26 (nl n2 —* -)
Stars a DO...LOOP, taking the initial value and the final value + I, n, off the stack.
DOES> p.75
Used with DEFINER (see above).
DRAW pp.51, 56 (nl n2^ -)
Used in Spectrum FORTH in the same way as the equivalent words in Spectrum BASIC:
draws a line from the current PLOT position to a point nl pixels to the left (or to the
right if n 1 is negative), and n2 pixels up (or down in n2 is negative).
DROP p.8 (n —> -)
Takes the top (single-length) number off the stack.
DUPp.9 (nl -» nl nl)
Makes a copy of the top of the stack and leaves this on the stack above the original
version.
E p.46 (Forth Vocabulary)
Used on the lupiter Ace to produce a number in scientific notation. The number must
be floating-point.
E p.60 (n —» —) (Editor vocabulary)
Takes a line number n off the stack and replaces that line by blanks.
EDIT p.59 'wordname'
Puts a copy of the word with this name on the screen, together with a cursor for editing.
This word is found on the Jupiter Ace, but not on versions of FORTH which use screens
to store data.
EDITOR p.59, 61
Calls up the Editor vocabulary so that data may be entered on a screen and edited.

ELSE p.30
Part of the IF...ELSE...THEN sequence.
EMIT p.53 (n —> —)
Prints the character with ASCII code n onto the screen.
EMPTY-BUFFERS (Editor vocabulary)
Marks each input buffer with a code that means that the contents of that buffer are not
wanted and can be overwritten with new data.
ERASE p.19 (addr.,n —» -)
Fills N bytes from this address onwards with 0's.
EXIT p.51,83
Leaves that word definition immediately. Cannot be used within a DO...LOOP.
EXPECT p.64, 65 (n, addr. -» -)
(Not found on the Jupiter Ace). Stores the first n characters in the input buffer in
addresses starting at the address given on the stack.
F 'string' p.60 (Editor vocabulary)
Searches through a screen of text for a string, and if it finds it, moves the cursor to the
end of it. If it does not find it, it gives an error message and moves the cursor to the top
left-hand corner of the screen.
F* p.36 (fl f2 —> fl*f2)
Multiplies the top two floating-point numbers and leaves this result on the stack.
F+ p.36 (fl f2 —> fl -Ff2)
Adds the top two floating-point numbers and leaves this result on the stack.
F- p.36 (fl f2 —* fl-f2)
Subtracts the top floating-point number on the stack from the floating-point number
second on the stack, and leaves the result on the top of the stack.
F. p.36 (f—> —)
Prints the floating-point number at the top of the stack.
F/ p.36 (fl f2—»fl/f2)
Divides the floating-point number second from top on the stack and leaves this result
on the stack.
FILL p.19 (addr., nl n2 —> —)
Puts n 1 bytes each of value n2 into memory starting at address a.
FIND p.64, 73 (-* addr.)
Puts the compilation address of the first word in the input buffer on the stack provided
that that word is in the context vocabulary. If it is not, it leaves 0. (This is similar to the
word ' found in other versions of FORTH.)
FLASH p.51 (flag —> -)
(Spectrum only). If this flag is 0, characters are printed normally, but if it is 1 they are
made to flash.
FLUSH p.60 (Editor vocabulary)
This is the fig-FORTH version of SAVE-BUFFERS. It stores all of the memory blocks
which have been labelled with UPDATE onto the disk.
FORGET 'wordname' p.10
Removes all the word definitions added to the dictionary since 'word-name' was
defined, including 'word-name' itself.
HERE p.74 (-» addr.)
Leaves the address of the first free byte in the dictionary.
HEX p.39 (-)
Converts the number base to base sixteen (hexadecimal). Not found on the Jupiter Ace.
HOLD 'character' p.68 (character—> -)
Used in formatting output to insert 'character' in the pad so that it may be printed out
when the pad is TYPEd.
1 pp.27, 50 (FORTH vocabulary)
Gives a copy of the top of the Return Stack. Inside a DO...LOOP, this is the counter of
that loop.
1 p60 In —» -) (Editor vocabulary)
Puts the contents of the pad in line n and moves the lines below n down t>y one. The

107
fifteenth line is lost from the screen.
I’ p.51 (-> n)
Gives a copy of.the second number down on the Return Stack. With a DO...LOOP, this is
the limit of the loop.
IF p.20 (flag —> -)
Used in IF...THEN and IF...ELSE...THEN. IF the flag is true, the words between IF and
THEN or between IF and ELSE are carried out. If it is not true, the words between ELSE
and THEN are carried out.
IMMEDIATE p.70
The last word defined in the current vocabulary is made into an immediate word, i.e.
one that works with another word definition, before that word is ENTERed.
INDEX p.60 (nl n2—> -) (Editor vocabulary)
Displays the first lines of the screen numbers between nl and n2.
IN KEY p.66 (-> n)
Puts the ASCII code of the key being pressed on the stack.
INVIS p.56
Stops the computer printing up the input buffer and the O K. at the top of the screen.
I pp.29, 50 (—> n)
Puts a copy of the third number of the Return Stack on the top of the Data Stack. Within
a DO...LOOP, this will be the counter of the second innermost loop.
K pp.29, 51 H> n/
Puts the counter of the third innermost loop on the stack.
KEY p.58 (-» n)
Waits for the next key to be pressed after ENTER and puts the ASCII code of this on the
stack.
LEAVE pp.30, 51
Used inside a DO...LOOP. Makes the loop counter become equal to the limit, and so
makes the loop end at the next cycle.
LINE p.60 (n —> —) (Editor vocabulary)
pives the address of the line number n.
LINE p.64 (FORTH vocabulary)
Used after QUERY or RETYPE. Makes the computer interpret text put into the input
buffer as normal FORTH words.
LIST 'name' pp.59, 62
Lists the definition pf the word 'name' on the screen. Versions of FORTH using screens
use a similar word in the Editor vocabulary, which takes a number n off the stack and
lists that screen (p.60).
LOAD 'file' p.60
Loads 'file' from tape. A similar word in the Editor vocabulary of versions using screens
takes a number off the stack and compiles the words in that screen, (p.61)
LOOP p.27
Completes a DO...LOOP, (see above).
M p.60 (n —> —) (Editor vocabulary)
Moves n characters to the right, or to the left if n is negative.
M* p.44 (nl n2--> d)
Multiplies two single-length signed numbers and leaves this result on the stack as a
double-length signed number.
Ml p.44 (d nl —» n2 n3)
Divides the double-length number d by the single-length number nl, and leaves the
signed remainder n2 and the quotient n3 on the stack. n2 has the same sign as d.

108
MAX p.48 (nl n2-> nl) if nI>n2
(nl n2 —> n2) if n2>nl
Leaves the greater of nl and n2 on the stack and removes the other one.
MIN p.48 (nl n2 —> nl) if nl<n2
(nl n2-> n2) if n2<nl
Leaves the lesser of nl and n2 on the stack and removes the other.
MINUS p.48 (nl—>n2)
Changes the sign of the top of the stack.
MOD p.56 (nl n2 —» n3)
Leaves the remainder of nl/n2 and gives it the same sign as nl.
MOVE p.61 (addr., n -» ) (Editor vocabulary)
Moves a line of text from memory, starting at the address given, to line n of the current
screen.
NEGATE p.48 (nl —» -nl)
Changes the sign of the top of the stack.
NOT p.34 (nl —» n2)
Reverses the truth value of the top of the stack; same as 0=
NUMBER p.64
(Jupiter Ace version). Looks for the first number that it can find in the input buffer. If it
finds one, it leaves it on the stack and puts the number 4102 on top. if it does not find a
number in the input buffer, it leaves 0 on the stack. (FORTH-79) (addr —> -) Takes a
string from address + 1 and converts it into a number which it puts on the stack, p.109
OCTAL p.38
Converts the number base to eight (octal).
OR p.32 (nl n2 —> n3)
Takes two numbers off the stack and performs the Boolian operation OR, leaving the
result on the stack.
OVER pp.22, 47 (n 1 n2 -» n 1 n2 n 1)
Puts a copy of the second number of the stack onto the top of the stack.
P p.60 (n —> —) (Editor vocabulary)
Adds text to line n of the current screen.
PAD pp.60, 64 ( n)
Puts the address of the pad on the stack.
PICK p.9 (nl -> n2)
Gives a copy of the nlth element of the stack (n I itself is not included in the count).
PLOT p.55 (n 1 n2 n3-> -)
(Jupiter Ace version) plots a pixel (nl n2) with plotting mode n3, where

n3 = 0 means plot black


n3 = 1 means plot white
n3 = 2 means do nothing
n3 = 3 means change from what it was before

PLOT p.56 (nl n2 —> —) (Spectrum version)


Moves the PLOT position to (nl, n2) and prints a dot there. (Unlike on the Jupiter Ace,
this is a single pixel.)
PRlNTp.il (flag —> -)
If the flag is 1, output is sent to the printer as well as the screen; if it is 0, output is only
displayed on the screen.
QUERY p.64
Used to enter text from input buffer with a word definition, it clears the Return Stack
and returns control to the keyboard.

109
QUIT p.51
Clears the Return Stack, empties the input buffer and returns control to the keyboard.
R p.60 (n —> —) (Editor vocabulary)
Replaces the contents of line n with the contents of the pad.
R> p.42 (-> n)
Takes the top number on the Return Stack and puts it onto the data stack.
REDEFINE ‘word-name’ pp.14, 59
Used on the Jupiter Ace after EDIT to clear out old version of ‘word-name’.
REPEAT p.26
Used with BEGIN and WHILE. Causes a loop back to BEGIN.
RETYPE p.64
Same as QUERY, except that it does not clear out the input buffer first.
ROLL p.47 (n -> -)
Moves the nth value down the stack to the top of the stack, n itself is not included in the
count.
ROT p.48 (nl n2 n3 —» n2 n3 n 1)
Rotates the top three numbers on the stack.
RUNS> p.75
Used on the Jupiter Ace together with COMPILER (see above.)
Sp.60(n—» -) (Editor vocabulary)
Moves the contents of line n down by one, leaving the new line n blank. All the other
lines move down by one, and the fifteenth line is lost.
S —>D p.45
(Not defined on the Jupiter Ace). Converts a two-byte number into a four-byte number.
SAVE 'file’ pp.59, 62
Saves ’file’ onto tape.
SAVE-BUFFERS p.60 (Editor vocabulary)
Stores all the blocks that have been updated with UPDATE onto the disk.
SIGN p.68 (n —> —)
Used in formatting. HOLDs a minus sign if n is negative.
SPACE p.53 (-)
Leaves a space in the printing.
SPACES p.53 (n)
Leaves n spaces in the printing.
T p.60 (n —» —) (Editor vocabulary)
Removes the contents of line n from the current screen, and puts them in the pad and
also TYPEs out the text.
THEN p.30
Part of IF...THEN and IF.. ELSE...THEN (see above.)
TILL ‘string’ p.60 (Editor vocabulary)
Removes all the characters in the current line up to ‘string’.
TOP p.60 (Editor vocabulary)
Moves the cursor to the top left-hand corner of the screen.
TYPE pp.62, 64, 68 (addr. n ^ -)
EMITS n characters starting from the given address.
U* p.44 (uni un2 —» d)
Gives the unsigned double-length product of two unsigned single-length integers.
U. p.42 (un —» -)
Prints the unsigned single-length number un.
U< p.42 (uni un2 —> flag)

110
Leaves a 1 if unl<un2 and a 0 otherwise.
UPDATE p.60 (n ->) (Editor vocabulary)
Labels a block in the input buffer to show the computer that it has been changed and
that you want to save it.
UNTIL p.20 (flag —» -)
Used in a BEGIN...UNTIL loop. Returns to BEGIN if flag is 0.
VARIABLE 'word-name' p.l 1 (n —»)
Creates a variable with this name and initializes its value as n.
VERIFY word-name’ p.62 (-)
Checks the file with this name stored on tape against the corresponding words in
memory.
VIS pp.56, 79
Reverses the effect of INVIS (see above).
VLIST p.2
Gives the contents of the current dictionary.
VOCABULARY 'word-name' p.70
Starts a new vocabulary with this name.
WHILE p.26 (flag —» -)
Used in the BEGIN...WHILE...REPEAT loop. If the flag is 0, it goes to the word after
REPEAT.
WORD 'string' p.64 (delimiter—> addr.)
(Jupiter Ace version). Takes a series of letters out of the input buffer, up to a
pre-determined symbol called the delimiter, and puts these in the pad, preceded by
the length of the string (excluding the delimiter). It puts the address of the pad on the
stack.
(Other versions) This is similar, except that the text goes into some other area of
memory instead of the pad. Again, it leaves the address of this on the stack.
X'text' p.61 (Editor vocabulary)
Finds and destroys the text.
XORp.34 (nl n2 —* n3)
Takes two single-length numbers nl and n2 off the stack and leaves nl XOR n2 in their
place. XOR performs a bitwise Boolian exclusive-or operation.

Ill
APPENDIX THREE ASCII CODES
Here is a list of those ASCII codes which are virtually standard in all computers (the
other codes are used for control functions, graphics, etc.)
58 : 92 |
59 ; 93 /
60 < 94 |
Carriage 61 = 95 -
Return 62 > 96 £
63 ? 97 a
64 @ 98 b
32 Space 65 A 99 c
33 ! 66 B 100 d
34 " 67 C 101 e
35 # 68 D 102 f
36 $ 69 E 103 g
37 % 70 F 104 h
38 & 71 G 105 i
39 ' 72 H 106 j
40 ( 73 I 107 k
41 ) 74 J 108 1
42 * 75 K 109 m
43 + 76 L 110 n
44 , 77 M 111 0
45 - 78 N 112 p
46 . 79 0 113 q
47 / 80 P 114 r
48 0 81 Q 115 s
49 1 82 R 116 t
50 2 83 S 117 u
51 3 84 T 118 v
52 4 85 U 119 w
53 5 86 V 120 x
54 6 87 W 121 y
55 7 88 X 122 z
56 8 89 Y 123 {
57 9 90 Z 124 |
91 1 125 }

112
INDEX
All FORTH word definitions are also summarized in Appendix Two. Words given in
capitals are either FORTH words or words defined in the text.
11 |
64,68 #
68 #>
68 #S
73 ■
18,60 (
18,60 )
5,6,9 *
46 */
46 ‘/MOD
4,6 +
13 +!
27,85 + LOOP
16 r
8 -
48 -DUP
61 -->
4,8
9 tn
8 1
8 /MOD
25 h
25 t><
25 i»
22 i+
22 i-
22 2+
22 2-
48 2DROP
48 2DUP
49 2ROT
49 2SWAP
26
26
61 ;S
25 <
68 <#
24 =
25 <=
24 >
25 >=
49 >R
13 ?
48 ?DUP
12 @

51 ABORT
48 ABS
11 addresses
20 AGAIN
14 ALLOT
17 ALLOTARRAY
32,33 AND

114
112 appendix three
102 appendix two
1 Artie version
53 ASCII
53 AT
5 AVERAGES

60 B
37 BASE
37 base 2
37 base 6
37 base 10
36 bases
51 BEEP
20 BEGIN...AGAIN
20,21 BEGIN...UNTIL
42 bigger numbers
37,65 BINARY
19 BLANKS
62 BLOAD
59 BLOCK
35 Boolian algebra
56 BORDER
62 BSAVE
11 BYE
11 byte

61 C
37 C!
39 C@
63 C90 tape
59 cassette recorder
16 CHANGESALARY
54 CHARACTER
1 Charles Moore
30 CHECK
88 CHECKBAT
89 BECKBALLWALLS
51,56 CIRCLE
59,62 CLEAR
87 CLEARBAT
11 CLS
18 CMOVE
91 CODE
73 code field
51 COLD
54 column
73 compilation address
59,61 compiler
75 COMPILER..RUNS
63 computer-compatible
63 computer-mode
58 control
70 context vocabulary
14 CONSTANT
14 constants
39 CONVERT

115
10 CR
16,74 CREATE
72 CREATUREMOVE
70 current vocabulary

60 D
44 D+
44 D-
44 D,
44 D<
68 DABS
63 data cassettes
63 data, recording
63 data, storing
37 DECIMAL
36 decimal arithmetic
92 DECODE
54 DEF
75 DEF1NER
70 DEFINITIONS
60 DELETE
64 delimiter
7 DEM
57 DIAGLINES
14 DIM
59 DISKS
26 DO...LOOP
75 DOES>
9 DOUBLE
51,56 DRAW
8 DROP
9 DUP

46,60 E
59,62 EDIT
30 ELSE
53 EMIT
59 EMPTY-BUFFERS
19 ERASE
51,83 EXIT
64,65 EXPECT

60 F
36 F*
36 F+
36 F—
36 F.
36 FI
34 FA1RLYH1GH
12 FETCH
19 FILL
73 field, parameter
64 FIND
80 FIRE
30,24 flag
51 FLASH

116
36 floating-point numbers
59 floppy disk
60 FLUSH
55 FLY
83 flying saucer
26 FOR
10 FORGET
67 formal
67 formatting
1 FORTH-79
1 FORTH Dimensions
1 FORTH Interest Group

71 genetics
53 graphics
54 graphics, moving
54 grid

74 HERE
39 HEX
82 HI
80 HIT
68 HOLD

27,50 1
57 r
20 IF
30 IF...ELSE...THEN
30 If...Then...Else
39,70 IMMEDIATE
60 index
66 IN KEY
64,67 INPUT
60 INPUT2
64 input buffer
1 Introduction
56 IN VIS

29,50 I

29,51 K
58 KEY
66 keyboard

78 LASERBASE
30,51 LEAVE
60,64 LINE
59,62 LIST
60 Editor
60 LOAD
28 LOOPYLOOP

60 M
44 M*
44 Ml
44 M/MOD

117
55 MAN
48 MAX
9 messages, printing
48 MIN
48 MINUS
59 Microdrive
56 MOD
57 mode, plotting
94 MUSIC
60 MOVE
89 MOVEBALL
88 MOVEBAT

48 NEGATE
28 nesting
70 NEWWORDS
26 NEXT
34 NOT
51 Note, length
64,65 NUMBER
36 number bases

38 OCTAL
32 OR
22,47 OVER

60 P
60,64 PAD
73 parameter field
55,95 pause
17 PAYROLL2
14 PAYROLL
57 PERM
9 PICK
51 pitch number
53,55,56 PLOT
57 plotting mode
95 PNT
11 PRINT
9 printing message
28 Printout

64 QUERY
94 QUICK-SUM
51 QUIT
95 QSUM

60 R
42 R>
59 RAM
18 recall
18 Rem
63 recording
63 recording data
14,59 REDEFINE
26 REPEAT
5,49 Return stack

118
6 Reverse Polish
47 ROLL
48 ROT
55 Run
75 RUNS>

60 S
45 S->D
59,62 SAVE
60 SAVE-BUFFERS
16 SALARY
46 Scientific Notat.
59,60 Screen
56 SEEPLOT
68 Sign
79 Silo
99 SNAP
51 Sound
53 SPACE
53 SPACES
10 SQUARE
87 SQUASH
10 SQDOUB
4,47 STACK
5,49 stack,return
5,27 step
63 stereo recording
12 store
63 storing data
11 street
75 strings
71 SUBSET

60 T
59 tapes
83 TARGET
10 TASK
83 TCHECK
64 TEXT
30 THEN
60 TILL
60 TOP
60 transfer to disk
41 two's complement
16 two-dimensional
62,64,68 TYPE

44 U*
42 U.
42 U<
42 U>
60 UPDATE
42 unsigned numbers
20 UNTIL

11 VARIABLE
11 variables

119
62 VERIFY
56,79 VIS
2 VLIST
70 vocabulary
70 context

87 WALLS
26 WHILE
64,91
91 WORD

61 X
34 XOR

120

You might also like