Why is my verse so barren of new pride,
So far from variation or quick change ?
Why with the time do I not glance aside
To new-found methods and to compounds strange ?
W. Shakespeare (sonnet LXXVI)
STRENGTH IN FORTH
part three
IS FORTH A LIE-DETECTOR ?
( By C. Janssen )
Yes ! And I will reveal to you, who is the liar. FORTH himself
maybe ? Wait and see !! First follow me to Merlin's cave. We are
going to have some magic. In FORTH Merlin's Cave is known as The
Stack. A hand points to the entrance of The Stack: {SP@}. Let's
see if The Stack is empty. Use {.S} △ Empty OK.......or not empty
of course if some grues were still visiting The Stack. If The
Stack wasn't empty, {.S} will not have altered it anyhow, contrary
to {.} . The latter is stack-destructive, {.S} leaves the
stackitems as it found them. Clear the stack with {SP!} △ OK.
(If you had any trouble with {.S} or more likely with {SP!}, take
a look at EXTRAS).
Check the clearing with our stackscanner {.S}. Now put some
numbers on the stack: 1 2 3 4 5 6 7 8 △ OK. Use {.S} △ 1 2 3 4 5 6
7 8 OK. Repeat {.S} △. You got the same output, I hope. Enter {.}
{.} {.} {.} {.} {.} {.} {.} △ 8 7 6 5 4 3 2 1 OK. This output
should now have surprised you. Take a good look at both outputs.
{.S} always prints out the top stack item to the right and the
bottom to the left. Using {.} repeatingly as we did will output
the top stack item left and the bottom right. Enter {.S} again.
FORTH tells you the stack is empty: {.S} scans the items, {.} also
removes them.
THE BIG LIE
Enter {SP@} {.} △ 326368 OK.(The number may differ with your
FORTH). As told before {SP@} points to the actual entrance of the
stack i.e. the top. The stack was empty, so 326328 is the address
of the bottom. Enter {SP0} {DUP} {.} △ 326684 OK . This is an
address too. I duped it, because I need to fetch something from
that address. Fetching items from addresses is accomplished by {@}
which word curious enough is called 'fetch'. Which item is hiding
at address 326684 ? Enter {@} {.} △ 326368 OK. The same number as
we managed to get from {SP@} when the stack was empty. At address
{SP0} is stored the address of {SP@} when the stack is empty, i.e.
the bottom-address. Enter a number: 123 △ OK. Let's go through
all that stuff again: {SP@} {.} and {SP0} {DUP} {.} {@} {.}. The
respective output was: 326364 326684 326368. Not good enough for
the Guiness Book of Records ? The output of {SP@} is 4 LESS this
time as it was the first time, yet we put a number ON the stack.
Have you ever seen a stack growing lower after you put something
on it ?
Is FORTH confused ? (FORTH confused..? Never !). Let's enter more
numbers to give him another chance: 456 789 △ OK. Next {SP@} {.} △
326356 OK. He did it again !! The stack grew downwards, not
upwards. And how is {SP0} doing ? Try it. {SP0} {@} {.} △ 326368
OK. At least that one is stable. What mystery crossed our paths-
of-life by now ? The traditional spells won't help us here, we'd
better read in FORTH's dictionary and find a modern computer-
spell. Here are some: {.S} {DEPTH} {OVER} {DROP} {SWAP} {DUP}
{ROT} {ROLL} {PICK}. Perhaps we can unravel the mystery now.
{DEPTH} seems an interesting one. What's going downwards, is
somehow related to depth. Enter {DEPTH} △ 3 OK. That's most
helpful, isn't it ? Now wait, we put three numbers on the stack,
and maybe {DEPTH} knew. Type 234 △ OK. Now {DEPTH} △ 4 OK. One
more time: watch, {DUP} {DEPTH} △ 5 OK. (Why five ?). See it with
{.S}. We'll doublecheck the action of {DEPTH} with {DROP}. The
word {DROP} removes the top stack item and never tells where it
went. In one go {DROP} {DEPTH} △ 4 OK. Hit !! {DEPTH} knew !! So
it must have its stackconnections ? Right you are. The word
outputs the number of items on the stack. And FORTH calls it
'depth', not 'height'. Thus, I must have given you a wrong
impression of the stack, writing things as top of stack, putting
numbers on etc. Am I that liar then ? FORTH may suggest that to
you, but I am not ! I gave you the conventional idea of a
stack, as a stack in real life should be: a pile whereupon we can
put things and where we can take things from. But inside a
computer real (human) life doesn't come in account. Inside a
computer a region of memory is set apart. The word {SP0} gives you
the address, where you can fetch the address of the stack's start.
The word {SP@} supplies the address where FORTH can find the TOS.
Depending on what stackactions take place, the address supplied
varies, increasing and decreasing incessantly.
To put it more computerlike: {SP@} gives you the address of the
most accessible stackitem. So if you {DROP} an item, there isn't
really made any move: the Stack Pointer got a new address, that's
all. If you then put an item on, you simply overwrites the item
you thought you removed. Enter {.S} 123 456 789 234 OK. We now
{SP@} . We got the address of the TOS. Let's find out what really
is on that address: {@} {.} 234 OK. Marvellous, isn't it ? And
what about clearing the stack with {SP!} ? Well, you then replace
the {SP@}-value with the address stored at {SP0}. Try to
understand the following: : CLST SP0 @ SP@ ! ; . Understanding
that will be easier when you know that {!} is the opposite of {@}.
{!} is called 'store', simply because it stores values at the
desired address. 1234 {SP@} {!} will store the number 1234 at the
current address of {SP@}. Think of all the possibilities you have
with those seven simple words; {.S} {SP0} {SP@} {SP!} {@} {!}
{DEPTH}. You have complete control of the stack. With the help of
some other words like {+} and {-} you can (dis)organize the stack
to your free will.
STACKMANIPULATION
But you better use the stackmanipulators which are ready for use
provided by the system itself. You already know some: {DUP},
{SWAP}, {DROP}. And others are: {OVER} {ROT} {PICK} {ROLL}
{?DUP}. Some more may be in your FORTH. Such as {-ROT} {TUCK}
{NIP} etc. At the end is a table with stacknotations and
descriptions of a number of stackoperators.
Why do we need such a lot of stackoperators ? Well, to change the
order of the items on the stack. Did you try to solve the sixth
exercise of part 2 without the use of a stackoperator ? Tcheeee..!
Take this for instance: 3X^2 - 5X + 4, a quadratic expression.
Now you have to calculate this formula for various values of X.
Of course you can adapt the calculation to each separate value
of X. If, for example our little X has the value 2, the result
could be found as follows: 2 2 * 3 * 2 5 * -4 + . This can be
improved upon by using stackoperators in such a way that the
X-value needs to be typed only once:
STACK CONTENTS
2 2 ( This is the chosen X-value )
DUP DUP 3 2 2 2 3 ( 3 is on top )
* * 2 12 ( 3*2 (6); 6 TOS ; 6*2 (12) )
SWAP 5 12 2 5 ( First swap 2 12,then 5 TOS )
* 12 10 ( 5*2 (10), 10 now TOS )
- 4 2 4 ( 12-10 (2), then 4 TOS )
+ 6 ( 2+4 (6), 6 TOS )
. Empty ( Print TOS on display )
If X's value is 7, only that first 2 on top has to change, the
rest remains the same. The result now being 11. ( As I'm very
smart, I wouldn't bother at all. The result for each value of X
can be obtained by adding that last 4 to the value of X. Try it
!). The advantage of this is that everything, except the value of
X can be made into a colondefinition.
: QUAD DUP DUP 3 * * ( n -- )
SWAP 5 * - 4 + . ;
It works like this: 4 QUAD △ 8 OK 9 QUAD △ 13 OK.
Here is a list of useful stackmanipulations, which require two
words:
STACK BEFORE STACK AFTER WORDS USED
1 2 1 1 2 OVER SWAP
1 2 2 1 2 SWAP OVER
1 2 2 1 1 SWAP DUP
1 2 1 2 1 1 OVER DUP
1 2 3 2 1 3 ROT SWAP
1 2 3 3 2 1 SWAP ROT
Try them out at the keyboard. And use {.S}, as {.} will respond on
1 2 {OVER} {SWAP} with 2 1 1. Do you remember why ?
32-BIT STACKS
I made a promise to spend a few words on 32-bit stacks. As you
might have noticed, I let FORTH output numbers which won't fit on
a 16-bit stack: 326684, 326364. Remember that the highest number
that fit into 16 bits is 65536. All FORTHs for Atari ST I know of
are nearly Standard-83. So nearly....because of their 32-bit stack
and aberrant method of mass-storage. There may be two main reasons
why you choose for a 32-bit stack. The 68000 MP is internally
organised to work on 32-bit size and secondly the addressbus is 24
bits width. This implies that working with a 32-bit stack is far
more easier handling addresses to reach into the full potential of
memory-space. On the 'outside' - you, the user - numberhandling
has grown less complicated. You have no longer to worry about
single and double length numbers. All numbers ranging from -
2147483648 to +2147483647 inclusive (unsigned 0 - 4294967295 )
will comfortably fit on the 32-bit stack, without further
requirments. It is even possible, that a double length number set
is included in your FORTH, double now being 64 bits.
On the other hand the 68000 MP allows operations on bytes, words
and longwords, 8, 16 and 32 bit resp. The implication can be that
a wide variety of all kinds of operators is defined in a FORTH.
Your manual should supply a so called GLOSSARY, a description of
all the words your FORTH can work with. There you will find the
extend and exact stacknotation of your system.
One more remark I'll bring up here. It might have crossed your
mind, that numberhandling in FORTH has certain rather tight
limits. Don't get disappointed, that you can't handle enormous
numbers in FORTH. Remember the following. Astronomy deals with
big numbers, don't you think ? Well, FORTH was designed for
astronomical purposes ! We humans intend to scale down big
numbers. We don't say: that star is at a distance of
30480000000000000 km, or 3,259 lightyear, but at 1 (lovely one)
parsec. That's more convenient to the limits of our imagination.
It saves time too !!
A FAIRY_TALE
Well, once upon a time there were double-length numbers. You could
easily recognize them at their size of 32 bits. The stack had to
be warned if you wanted to put a d.l.-number on. The number had
to be marked: 1203457., e.g. a dot had to terminate the number. So
12. was a d.l. number, as was 1234., 23143567. and 0. Some FORTHs
allow more d.l.-markers (e.g. , ; : ) and the place in the number
is free.
There was (is) only one d.l. arithmetic operator: {D+}. To add two
numbers, there were several possibilities: 1) add 2 s.l. numbers
2) add 2 d.l. numbers 3) add 1 s.l number to 1 d.l. number.
Ad 1. put 2 s.l. numbers on the stack and use {+}: 4 5 {+}.
Ad 2. put 2 d.l. numbers on the stack and use {D+}: 78960. 341234.
{D+}.
Ad 3. put 1 s.l. number on the stack and 1 d.l. number ? Wrong !!
That won't work. If even only one number of a series you
wanted to add is of d.l.-format, all numbers have to be in
that format. So, 234 124536. {+} or 234 123546. {D+} will
give a false result. This will work: 234. 123546. {D+}.
To check the result {.} won't work on d.l. format either. The d.l.
equivalent of {.} is {D.}. Using a 32-bit stack, all these kludgey
things are over and out. (Except with multiplication and division.
Examine the exact stacknotation for information about the kind of
numbers an operator expects on the stack).
To subtract two d.l.-numbers you had to write a word of your own.
Here it is: : D- DNEGATE D+ ; . (Remember one of the excersises of
part two ?). {DNEGATE} is of course the d.l. counterpart of
{NEGATE}, as {DABS} is of {ABS}. To manipulate d.l.-numbers on the
stack there are special words: {2DUP}, {2DROP}, {2OVER}, {2SWAP},
{2ROT}. They accomplish the same task as {DUP}, {DROP} etc. do, on
d.l.-numbers. They can also work on a combination of two s.l.-
numbers.
SERIOUS AGAIN
These five are of interest for 32-bit stacks too. Let's be
practical. Enter 123 345 567 789 {2SWAP} .S △ 567 789 123 345 OK.
Pay serious attention to how the swapping is performed. At least 4
items have to be on the stack for {2SWAP} and {2OVER}. {2DROP} is
less demanding: at least two, as is {2DUP}. {2ROT} expects at
least six items. Play dropping and swapping and duping and rotting
(hmmm) to get used to those operators. Be aware, that the exact
action of these {2....} depends on the kind of stackitems they
operate upon.
We are going to enter the twilightzone of mixed operators.
These operators are all related to multiplication and/or division.
For example {UM*} is a mixed operator. The stacknotation is ( uw1
uw2 -- lproduct ). The two operands may not exceed the unsigned
16-bit range, while the result of the multiplication is a 32-bit
number. In working with mixed operators, consult your manual for
the exact use. Most Mixed operators are declared mixed by use of
the character 'M' in the composition of the name of the word, as
{UM*} for instance.
WHAT ABOUT FORTH's RELATIONS
One group of operators I must review: the relational and logic
ones. Relational operator....the word sounds as if it cost a
fortune. But if I name one and only one you will recognize one
when you see 'm. Here it is: {=}. And here are more: {<} {>} {<>}
{0=} {0<} {0>}. These operators always test if a relation exists
between at least two items on top of the stack. They are
frequently used in conjunction with conditional loops as {IF..ELSE
..THEN}. I won't give any example of this use. I would have to
explain to you, how to use conditional loops. I'll better wait
till then. Some of these operators test the relation of the TOS to
zero: {0=), {0<} etc. Let's have some fun: clear the stack, and
put a number on, 8 △ OK. Now enter {0=} △ OK. You asked FORTH if 8
equals 0. Look up FORTH's answer with {.S}. You will find a 0 on
the stack. The result of the testing was false (0). If you now
{0=} again, followed by {.S}, you will find a -1, denoting the
testing ( 0 = 0 ? ) was true. Well, I told you in part two: -1
denotes TRUE in computerlogic. Be careful, FORTH considers all
numbers to be true (-2, 3, 12345, -124578 ), except the number 0,
which is always false. Enter {SP!} 8 6 {<} △ OK. How do you read
such an expression ? You probably know this from BASIC: IF 8 < 6
THEN GOTO 120 or IF ATARI > COMMODORE THEN LIVE = GOOD. In the
first example 8 is compared to 6 to test if 8 is smaller than 6,
which is not (false=0). The second example is to show that live is
still worth living. So, in 8 6 {<} you do NOT compare 8 and 6 to
test if 6 is smaller than 8. Think of 8 6 {<} as 8 {<} 6. This aid
counts also for other relational, logical and arithmetical
operators. Two relational operators do not leave a true or false
result on the stack: {MIN} and {MAX}. The first compares the two
numbers on top of stack and leaves the smaller, the other one acts
similarly, but leaves the higher number. Both words are most
frequently used to set the low and high limits in such events
as DO-LOOP- and conditional-loopconstructions. I'll give one
example in advance. : LOOPY 10 MIN 0 DO CR ." I'm going loopy !!"
LOOP ." Phhhheeeeeeew...!!!" ; We made a new word LOOPY. It
executes as follows. 5 LOOPY △
I'm going loopy !!
I'm going loopy !!
I'm going loopy !!
I'm going loopy !!
I'm going loopy !! Phhhheeeeeeew...!!! OK
Again, but with a higher number. 100 LOOPY △ . Our psychological
most interesting sentence is now printed out...no, not a hundred
times, but only 10. All due to the fantastic job {MIN} did,
keeping my enthusiasm within certain limits. Notice, how the text
was typed between {."} and {"}.
NOR TO BE NAND NOT TO BE
You do know logical operators, don't you ? Such tiny words as
{NOT}, {OR}, {AND}, {XOR}. All this logic isn't as frightning as
most people think. The temptation to show you that logic is a
very exciting world, tickles my brains. Two more logic operators
are {EQV} and {IMP}. But they are not frequently used. You never
will encounter {NOR} or {NAND}, in a computerlanguage. But in
electronics nand is very popular. It is (theoratically) possible
to exclusively wire a computer with NAND-gates. I should remember,
that some issue later on is dedicated to logic.
Now let's go in binary. We did it once before: 2 BASE ! △ OK.
FORTH accepts only 2 figures in binary: 1 and 0 !! Try it: 8 △ 8?.
The questionmark shows that FORTH has completely forgotten about
the other figures. So 1 and 0 !! All logic needs 2 parameters,
at least, except {NOT}, which needs only one. This even applies
for "hardware logic" !!
Enter 1111 1100 {AND} {.S} △ 1100 OK. What happened ? Let's put it
right up. 1111 0000 1111
1100 {AND} and more 1100 {AND} 1111 {AND}
1100 0000 1111
You know 1 and 0 as binary figures. But also as TRUE(1) and
FALSE(0). At the very moment you use a mathematical operator in
binary base, FORTH treats 1 and 0 as figures, which constituate
numbers, which count quantities. At the very moment you use a
logical function, FORTH considers 1 and 0 as TRUE and FALSE, not
forming numbers, as EACH 1 and EACH 0 is taken apart, not counting
quantities, but signalling qualities ( TRUE and FALSE ).
Also, a bit can only be 1 or 0. And..yes an electric wire can be
set on (1) or off (0) current. So here it all comes together:
electronics, logic and binary base. Two simple(!!!) elements as
TRUE and FALSE, 1 and 0, ON and OFF rule the whole business of
computers. So, if you are getting angry or bored reading this
words, true, blame your computer for on(c)e and turn it off; it's
all voltage !!
Back to the examples. The first one: 1111 1100. The four ones
signalling (flagging) four times TRUE, the two ones-two nulls
flagging two times TRUE, two times FALSE. Now {AND} takes the
rightmost of 1111 and the rightmost of 1100, 1 and 0. With this
TRUE-FALSE parameters the {AND}-function gives FALSE (0) as a
result. The leftmosts of 1111 and 1100, both 1 (=TRUE), have a
TRUE after {AND}ing them, like this: 1111
1100 {AND}
1100 .
The second example shows, that {AND}ing FALSE and FALSE gives
FALSE as a result. From here off we can derive so called
Truthtables. You can find them in the manual of ST-BASIC and in
most computerbooks. Just remember, that 1111 1100 {+} is something
quit different from 1111 1100 {AND}. Try it out !!
Also try out the functions of {OR} and {XOR},as done for {AND}.
And don't forget to experiment in other numberbases. And try to
see some logic in the magic.
Logical operators are frequently used in conjunction with
conditional loops, as relational operators are. In that context,
notice that {0=} has resemblance to {NOT}. But they are used in
a different way. E.g. .....{DEPTH} {0=} IF.....has a significant
meaning, as {DEPTH} outputs a number. But .....{SP@} {SP0} {>}
{NOT} IF.....easily reads as 'if the value of {SP@} is NOT higher
than the value of {SP0)',as the use of {0=} in this case does not.
A special word on {NOT}. {NOT} outputs in 32-bit, so 1111 {NOT},
will give 11111111111111111111111111110000 and 1111111 {NOT}. will
give 11111111111111111111111110000000. See, the {NOT}ting is done
bit by bit at the rightmost side. All logical operators work bit
by bit. The most exotic and less understood operator is {XOR}.
Sometimes also called {EOR} in BASIC. One application of {XOR} is
to determine the sign of the product of two numbers. A negative
number has its leftmost bit set to one. The {XOR} of two numbers
of the same sign (i.e. whose leftmost bits are both 0 or both 1)
will be a number with a zero leftmost bit, indicating a positive
number. With two numbers of the opposite sign, the {XOR} will
result in a 1 leftmost bit, showing the result to be negative. The
value of the result has in this context no meaning.
The last logical operator is {TOGGLE}. It is somewhat like {XOR}
in this, that it exclusive-ors the low order byte of the top stack
number with the byte, whose address is second on the stack; the
result is placed at this address. It is used in byte-masking
operations, as to change particular bits. Here is a definition of
{TOGGLE} in FORTH-assembler, merely for the sake of demonstration.
Watch the EOR mnemonic ! Here it is: CODE TOGGLE SP )+ D0 MOVE SP
)+ A0 AMOVE BYTE D0 A0 EOR C;
This part three tends to grow to heaven, but I'd like to stay on
earth for some while.
Next time we're going to discuss loops. We now have mastered
enough of the stack's mysteries to successfully jump from
stackiness to loopiness. Whatever that may be.................
Till we meet in heaven.
SUMMARY
To get the full of arithmetic in FORTH-style, FORTH supplies
several words to manipulate the order of items on the stack. They
also serve to rearrange the order of parameters in the way a word
expects them to be. These words are called stackoperators.
To test stackvalues on quantitative conditions there are many
operators, called relative operators.
To test if a condition is TRUE or FALSE we can use the logical
operators.
Both relative and logical operators are often used in combination
with conditional loops as IF..ELSE..THEN, BEGIN..UNTIL,
BEGIN..WHILE..REPEAT and CASE-structures.
I shuddered to think of the discussion on 16- and 32- bit stacks.
The use of 32-bit stacks allows an easier way of numberhandling,as
I learned, for most common arithmetic.
It isn't possible to list all arithmetic and other operators,
which appear in the many ST-FORTHs, commercial as well as public
domain.
Please now load the next part of this course, which is called
"Forth Course IIIb"!
Disclaimer
The text of the articles is identical to the originals like they appeared
in old ST NEWS issues. Please take into consideration that the author(s)
was (were) a lot younger and less responsible back then. So bad jokes,
bad English, youthful arrogance, insults, bravura, over-crediting and
tastelessness should be taken with at least a grain of salt. Any contact
and/or payment information, as well as deadlines/release dates of any
kind should be regarded as outdated. Due to the fact that these pages are
not actually contained in an Atari executable here, references to scroll
texts, featured demo screens and hidden articles may also be irrelevant.