Skip to main content

A tomato a day keeps 
the doctor away.
My mother-in-law : Collected Works.

                         STRENGTH IN FORTH
                             part five     
 
                     MAKING A TRUE DECISION (2)

It's rather easy for me now to complete this part about loops  and 
conditional  structures.  That's because I can restrict myself  to 
two words:  {BRANCH} and {0BRANCH}. These two elements are used to 
implement   structures   as   {IF..ELSE..THEN},    {BEGIN..UNTIL}, 
{BEGIN..WHILE..REPEAT} and {BEGIN..AGAIN}.  The word {BRANCH} is a 
unconditional  branch.  It  always  occurs,  if  that  point  (see 
beneath) is reached.  {0BRANCH} is only activated if the condition 
is FALSE. You can find {BRANCH) and {0BRANCH} in the dictionary. 
One  feature  all loops - the definite {DO..LOOP} as well  as  the 
conditional  {IF..THEN}-structure and the indefinite loops -  have 
in common: they should only be used from within a definition !!!

It's  for sure,  that control-structures as indefinite  loops  and 
conditional branches can produce tidier applications than definite 
loops and jumps out of loops.

CERTAIN CONDITIONS 

The   first  (conditional) structure  to  be  explored   will   be 
IF..(THEN)..ELSE. Here is its scheme:

          0BRANCH
 |¯¯¯¯¯¯¯¯       ¯¯¯¯¯¯¯|
{IF}           {ELSE}  é          {THEN}
                 |________BRANCH______     

In  BASIC this control-structure is used as  IF..THEN..ELSE.  This 
could be read as: IF condition=TRUE THEN do-this ELSE  do-that. In 
FORTH it's quite different read as: condition IFTRUE do-this IFNOT 
do-that THEN_GO_ON with-the-following. So if  'condition'  is TRUE
do-this will be executed,  followed by with-the-following.  If the 
condition is FALSE,  do-that will be executed,  followed by  with-
the-following.  In both cases with-the-following is  executed.  In 
FORTH first the condition is tested i.e.  FORTH examines the value 
TOS on being zero or non-zero,  FALSE or TRUE respectively.  First 
we'll have a closer look at a plain IF..THEN-structure. a) If TRUE 
the  words between {IF} and {THEN} are  executed.  Then  execution 
goes on with the words after {THEN}. b) If FALSE the words between 
{IF}  and  {THEN} are omitted and a direct branch is made  to  the 
words beyond {THEN}.
When {ELSE} is used with {IF}..{THEN},  the words between {IF} and 
{ELSE}  are executed on a TRUE-test and when execution arrives  at 
{ELSE} the unconditional branch is made to {THEN}. When {IF} finds 
zero  TOS  a branch is made beyond {ELSE} and  the  words  between 
{ELSE}  and  {THEN}  are executed,  followed by  the  words  after 
{THEN}. 
As you might have guessed  it's allowed to nest  IF..(ELSE)..THEN_
structures. The nesting is submitted to the same rules as apply to 
a DO..LOOP.  When the nesting grows very complicated,  you  should 
see,  wether your definition could be splitted in smaller ones, or 
you  should  write down your definition on a piece of  paper  like 
this:  IF(1)....ELSE(1)..IF(2)..ELSE(2)...THEN(2)...THEN(1). But I 
prefer  the  smaller-ones-technique.  Like this  barking  example. 
First we define a variable. VARIABLE ?DOG OK  : IFSO 1 = IF ." Run 
for your life, if you have one !! " THEN  ; OK : IFNOT 0= IF ." Go
inside and say 'Hello' " THEN ;  OK  :  INIT ?DOG ! ; OK  : SAFE 0 
?DOG !  ;  OK.  Now we can construct the final word.  : DOG?  INIT 
?DOG @ DUP IFSO IFNOT SAFE ;  OK.  Execute the DOG?-word with  one 
parameter (1 or 0).  1 DOG?  Run for your live, if you have one !! 
OK
.  We could have defined DOG?  as: : DOG?  DUP 1 = IF ." Run for 
your live,  if you have one !! " ELSE ." Go inside and say 'Hello' 
"  THEN DROP ;  .  While discussing the  relational  operators,  I 
mentioned    the   fact,    that   conditional    branches    like 
IF..(ELSE)..THEN  in  most cases,  make their tests with  help  of 
these operators.  Consider my mother-in-law. She has dedicated her 
life  to grow tomatoes.  (And grapes,  to make some wine for  me). 
Enchanting,  isn't it ?  She really grows the tastiest tomatoes  I 
ever  ate.  And all sizes.  Imagine she had a machine to sort  the 
tomatoes  according to their sizes.  I could have  automated  this 
process  with FORTH and some electronics.  She hasn't got  such  a 
machine,  so  I'm  alas restricted to make a text-version  of  it. 
Let's sort all tomatoes into 5 groups:  EL,  L,  M, S, ES. That is 
from extra large to extra small, according to their weight. 

: TOOSMALL  DUP 25  < IF ." Rejected   " THEN ; OK
: ?ES       DUP 50  < IF ." Extra small" THEN ; OK
: ?S        DUP 125 < IF ." Small      " THEN ; OK
: ?M        DUP 200 < IF ." Medium     " THEN ; OK
: ?L        DUP 250 < IF ." Large      " THEN ; OK
: ?EL       DUP 250 > IF ." Extra large" THEN ; OK
It  might seem very simple now to forge these small ones  together 
into one final definition : SIZE  TOOSMALL ?ES ?S ?M ?L ?EL DROP ; 
OK,  to  determine the size of a tomato.  Try some numbers  !!  It 
doesn't work very well,  does it ? We will have to look around for 
some better way.  The smaller-ones-technique failed in the case of 
the tomatoes.  The nesting method has to bring the solution  here. 
But that one will have to wait for the touch of YOUR magic 'green' 
fingers in the exercises. 

ALL BEGINNING HAS AN END

Here is another one.

                         |¯¯¯¯¯¯0BRANCH¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯  
{BEGIN}               {WHILE}                {REPEAT}
  ü                                             |
   |__________________BRANCH_____________________|

Now,  if you examine the scheme above well,  you will  undoubtedly 
notice,  that it is a variation of IF..ELSE..THEN. The {IF} is, as 
it  were,  part way into the loop.  The 0BRANCH now starting  from 
{WHILE},  if  the condition between {BEGIN} and {WHILE} is  FALSE. 
And  it swings us out of the indefinite loop far beyond  (REPEAT}. 
If  the  condition preceding {WHILE} is TRUE,  the  words  between 
{WHILE}  and  {REPEAT} are  executed.  When  execution  encounters 
{REPEAT}  an  unconditional BRANCH is made backwards  to  {BEGIN}, 
where  it all starts again.  An example to honour  the  fleet,  my 
MAJESTY's or your MAJESTY's...it doesn't matter. VARIABLE SHOT OK.
:  HIT   BEGIN  1 SHOT +!  SHOT @ DUP 10 <  WHILE .  ." hit is  no 
hit.  We  rule  the  waves  !!" REPEAT . ."  hit  is a  real  hit. 

Blubblubblub....." ; OK. As you can see in this example of courage 
and  arrogance,   the  TRUE-FALSE-test  has  to  precede   {WHILE} 
immediately,  although other words may be injected between {BEGIN} 
and {WHILE}. The {+!}-word resembles {!}. In fact, it  also stores 
values at addresses.  Unlike {!} however,  it doesn't replace  the 
old value with a total new one,  but increases the old value  with 
the  given number.  123 SHOT {!} will store the value 123  at  the 
address  SHOT (the parameter field address,  remember  ?).  Having 
done  that job,  456 SHOT {+!} will add the value 456 to  the  old 
value 123 at the address SHOT.  The variable SHOT will now contain 
the value 123 + 456 = 579. Now execute HIT.

RIDICULOUS

Two indefinite loops remain to be explored:  the {BEGIN}..{UNTIL}- 
and the {BEGIN}..{AGAIN}-loop.  They are - at branch-level -  each 
other's counterpart. See for yourself.

      é¯¯¯¯¯¯¯¯¯0BRANCH¯¯¯¯¯¯¯¯¯¯¯¯|
    {BEGIN}                      {UNTIL}

      é¯¯¯¯¯¯¯¯¯¯BRANCH¯¯¯¯¯¯¯¯¯¯¯¯|
    {BEGIN}                      {AGAIN} 

As  you  could  have figured out  for  yourself,  the  testing  on 
TRUE/FALSE  takes place at {UNTIL}. At {AGAIN} no test is  made as
the branch (backwards) is unconditionally carried out.  The  words 
between {BEGIN} and {UNTIL} are executed as long as the test  made 
by {UNTIL} is FALSE. This test has to precede {UNTIL} immediately.
If the test gives TRUE, the words after {UNTIL} are executed. It's 
easy to see,  that the {BEGIN}..{AGAIN}-loop is for ever  lasting. 
That may seem ridiculous,  but it is not. The main routine in each 
computer is such an endless loop.  In the FORTH-system it is  used 
for  the keyboard interpreter,  which interprets all input to  the 
computer. While FORTH is in action all operations are at a more or 
less deep level of nesting from within that keyboard  interpreter. 
Ultimately  control must return to him,  displaying OK.  So it  is 
very  usefull  for turnkey applications,  where the  user  is  not 

expected to know or wish to alter the method of operation. Here is 
an example of a {BEGIN}..{UNTIL}-loop. A slightly usefull one.
: G-C-D   BEGIN ( n1 n2 -- gcd )
               SWAP OVER MOD ?DUP 0=
          UNTIL
;

: .GCD    ( n1 n2 -- gcd )
     G-C-D CR ." The GCD is " . 
;
Entering 12 20 .GCD will display The GCD is 4 OK. GCD is of course 
the  greatest  common divisor.  In this  two  definitions  another 
feature  of  FORTH-programming is beautifully  made  visible.  The 
display-routine  and the actual calculation-routine are placed  in 
separate words.  Why ? Well, if in a larger application the GCD is 
to  be displayed as well as merely calculated  without  displaying 
the  result,  we can use the G-C-D-word in both  cases.  It  saves 
rewriting  the calculationroutine.  There are some conventions  in 
naming words too. A dot as first character indicates that the word 
will print something, as .GCD does. If a routine has to store some  
value it is often named !PIPO (Pipo is a dummyword).  When a  word 
has to give TRUE or FALSE on some action of the user ?  is used as 
an indication of the word's nature: ?KEY, was a key pressed or not 
pressed  ?  It's another help to make a program more  readable  to 
another  human  (and to yourself).  The efforts layed in  a  well-
structured lay-out, a well-chosen name and well-proportioned words 
pay  ten  times  back as you will enjoy clear  structures  as  the 
result of clear thinking........... Well, it was easy after all !!

A WARMING-UP

Now we have some room to take the returnstack out of the  freezer. 
After a warming-up,  it appears as a ordinary stack....however  it 
is not,  as you should be well aware of.  The returnstack is  used 
for system control.  One,  just one uncontrolled movement on  this 
stack is disastrous.  Your system will go away.  Nevertheless  the 
returnstack can be accessed by the user of FORTH. We've done it in 
the {DO..LOOP},  using {I} and {J}. Both transfer numbers from the 
returnstack to the computationstack.  A further three words earn a 
living   transferring numbers to and fro. Here they are: {R@} {>R} 
{R>}  (say:  are-fetch,  to-are,  are-from).  {>R}  and  {R>}  are 
inseparable   twins.   {>R}   transfers  the  top  item   of   the 
computationstack  to  the returnstack,  {R>} the top item  of  the 
returnstack to the compu-stack.  In both cases the items are moved 
from their respective stacks.  ( {I} and {J} just COPY items,  not 
MOVE  them  ).   As  {>R}  and {R>} modify  the  contents  of  the 
returnstack, they should never be used directly from the keyboard. 
Always  use  them within a definition.  And  within  a  definition 
always  (normally) as a pair.  Maintaining this simple rules  will 
ensure  that  the state of the returnstack  is  unchanged  between 
entry  and exit,  when the word containing {>R} and {R>} is  later 
executed.  Are  those  two words that important  then  ?  No,  not 
really. Their main use is as a temporary store for the top item on 
the compu-stack,  when the items below are needed for some reason. 
Let's step in reality.  Suppose the stack shows like this:18 23 34 
55  and you would have to multiply 18 and 23 and then  divide  the 
result through 34.  That needs some shuffling on the stack !! With 
the help of the twins it's easily done. But within a definition !! 
:  TWINS   18 23 34 55 >R */ R> .S  ;  On executing TWINS it  goes 
like:
STACK                 WORDS              COMMENTS              
18 23 34 55           >R      55 is transferred to the ret-stack
18 23 34              */      18 * 23 / 34 (star-slash-action)=12
12                    R>      restore 55 on the compu-stack
12 55                 .S      print the stackcontents

Now the stack is showing 11 18 23 55 34 66.  The numbers 18 23  34 
will play the same rôle.  The extension is that you have to add 11 
and 55 and to subtract 66 from the result. It's done by TWINS2. : 
TWINS2   11 18 23 55 34 66 >R SWAP >R */ R> ROT + R> -  .S  ;  OK
Figure out for yourself how TWINS2 is doing the job,  just like  I 
did with TWIN. As you can see, every {>R} has its {R>} and as long 
as that is the matter within the same definition, it's allright. I 
almost forgot {R@}. This word copies the top of the returnstack to 
the computationstack.  It does not alter the returnstack.  Imagine 
that  you  have  to add a constant changing number to  5 different 
numbers.  Here is the word that will perform the required  action. 
:  +5DIF   >R R@ 10 + . R@ 11 + . R@ 12 + . R@ 13 + . R@ 14 + . >R 
DROP ; OK.  10 +5DIF will give 20 21 22 23 24 .

A VARIABLE SUBJECT

Scattered all around through this course are remarks on {CONSTANT} 
and  {VARIABLE}.  Let's scratch these together and add some  fresh 
ones.  Now {CONSTANT} and {VARIABLE} are both defining words. They 
can create a new entry in the dictionary.  It's quite obvious from 
their names,  what kind of entry that will be. The word {CONSTANT} 
is  used to name and number a value that won't change at  run-time 
of  an  application.  It is used as 10  {CONSTANT}  VAT.  (VAT  is 
British BTW,  MwSt).  In BASIC you would have written VAT=10.  The 
word VAT on execution places the value 10 TOS. Let's assume VAT is 
just  a tax of 10 percent.  The calculation of a price  incl.  VAT 
would go like this.  :  PRICE  DUP  VAT 100 */ + .  ; Here is what 
happens,  when you type  150 PRICE 165 OK. So 150 was excl.,165 is 
incl. VAT. 

         STACK               WORDS                COMMENTS
         150                 DUP            Duplicating 150
      150 150                VAT            The value 10 goes TOS
     150 150 10              100            100 goes TOS
     150  150  10  100       */             150 * 10 / 100 = 15
     150 15                  +              150 + 15 = 165
         165                 .              Prints the result 

We  could  have nòt defined a constant and simply  have  used  the 
value of 10.  Of course we could have - and it is better  practice 
in  small  applications  of  one or two words  -  ,  but  when  an 
application  involves  a huge amount of  calculations  you  better 
define a constant.  For two reasons.  First of all the  government 
doesn't  yet know of that 10-percent-VAT,  but what if she knew  ? 
Yes, she would increase it and you would have a nice job, changing 
10 to 20 everywhere 10 appears in your program.  Now if you  would 
have defined a constant VAT,  you only would have had to change 10 
{CONSTANT}  VAT  in  20  {CONSTANT}  VAT  and  everywhere  in  the 
application  VAT would have produced 20.  Secondly,  VAT has  more 
sense than 10 (or 20). Remember: the value of a constant is set at 
its  creation.  Why should you alter the value of a CONSTANT  ?  I 
don't know.  It can be done yet. Like this: 20 {'} {VAT} {!}. OK . 
Typing {VAT} {.} gives 20 OK . The word {'} (say: tick) places the 
parameter field address of {VAT} TOS. Beneath that pfa of {VAT} is 
the number 20.  {!} takes the second item on the  stack,  assuming 
it's a number and stores it at the TOS-item,  assuming  that's  an 
address.  Sometimes  it  happens,  that the value  of  a  constant 
depends on the value of (an)other one(s).  It's a good practice to 
then  calculate the dependant constant.  An example  will  clarify 
this:
2000 {CONSTANT} SCREEN 
80 {CONSTANT} COLUMNS
SCREEN COLUMNS / {CONSTANT}  LINES. 
The constant SCREEN is worth 2000.  The constant COLUMNS is  worth 
80.  The constant LINES is consequently 2000 / 80 = 25. Any change 
made in SCREEN and/or COLUMN will affect LINES' value.
A {VARIABLE} is declared like this: {VARIABLE} CHANGE. You see, no 
initialising  a value for {CHANGE}.  In some  FORTH-dialects,  you 
have  to  initialise  a variable at  its  creation:  0  {VARIABLE} 
ANOTHER.  I  mention it here,  because some books on  FORTH  write 
about it. It's easy to write a word that initialises a variable to 
zero. : VAR   CREATE 0 , ; OK .  You use it like this: {VAR} ME OK
{ME} has got the value 0.  Initializing a variable with any  value 
is made possible by this definition:  :  VARIANT  CREATE  ,  ; OK
The use is 23456789 {VARIANT} ONOMATOPEE OK.  {ONOMATOPEE}'s value 
is 23456789. {ANOTHER}'s {VARIABLE} is constructed like {VARIANT}.
'Our'  {VARIABLE} can be defined in high-level FORTH  comme-ça;  : 
VARIABLE    CREATE 4 ALLOT ;  and just for fun the  definition  of 
{CONSTANT} in high-level FORTH:  :  CONST  CREATE ,  DOES> @ ;. It 
really works !! You use it like {CONSTANT}.
I introduced the words {CREATE} and {DOES>} and the tiny word {,}.
The  latter  compiles  a  number  in  the  first  available   free 
dictionary-space.   {CREATE} and {DOES>} are very powerfull words. 
I  told you,  that FORTH lets you extend his dictionary.  You  can 
write words and add these to the dictionary.  But FORTH gives  you 
still more power.  I also told you,  that {CONSTANT} is a defining 
word;  it compiles a dictionary entry,  just like {:...........;}. 

As  you  can  see,  the defining word  {CONSTANT}  was built  with 
{CREATE....DOES>}.  So you can also define words, which can define 
new  types of words,  as I did with three types of {VARIABLE}  !!! 
More on that subject (much)later.
The word {ALLOT} allots memory-space,  as many bytes as the number 
preceding it indicates. 
Now,  how to put some value in a variable ?    Use {!}. The format 
is 123 {CHANGE} {!}.  You can change that value by storing a total 
new value, 234 {CHANGE} {!}, or by increasing/decreasing its value 
with  {+!}.  Increasing goes like this:  66 {CHANGE}  {+!},  which 
brings 300 for {CHANGE} (234 + 66 = 300).  Decreasing follows this 
method:  -66 {CHANGE} {+!} and {CHANGE} is back to 234  again.  To 
get  the variable's value onto the computationstack {@}  is  used: 
{CHANGE}  {@} .  234 OK.  Don't use {.},  if you didn't intend  to 
display its value.  For displaying a variable's value is done in a 
easier way with {?}: {CHANGE} {?} 234 OK. Of course {?} is defined 
in this way: : ?    @ . ; Simple ? Yes, very !!
Now we discussed three subjects.  The remaining part about  loops, 
the returnstack and constants and variables.  Next time we'll have 
a closer look at input and output in FORTH.
                                        Till then !!

SUMMARY

The  conditional loopstructure in FORTH is  the  {IF...THEN}-loop. 
The syntax is somewhat different from BASIC's IF..THEN.  In  FORTH 
it's  layed out like this:  'condition' IF 'words'  THEN.  If  the 
condition is TRUE,  the words between IF and THEN are carried out, 
if FALSE these words are skipped and control is handed over to the 
words,  if any,  following THEN. This conditional structure can be 
extended  with  {ELSE},  placed between {IF} and  {THEN}.  If  the 
condition is FALSE,  the words after {ELSE} are executed, followed 
by the words after {THEN}. 
There are three indefinite loops. {BEGIN..WHILE..REPEAT}, {BEGIN.. 
UNTIL}  and {BEGIN..AGAIN}.  The respective syntacti  are:  {BEGIN 
(words) 'condition' WHILE words REPEAT},  {BEGIN words 'condition' 
UNTIL},  {BEGIN  words  AGAIN}.  The 'conditions'  are  tested  by 
{WHILE}  and  {UNTIL}.  As long as 'condition' is TRUE  the  words 
between {WHILE} and {REPEAT} are executed.  As long as 'condition' 
is FALSE the words between {BEGIN} and {UNTIL} will be performed.
All  loops  and conditional structures should only  be  used  from 
within  a definition.  All loops,  definite  and  indefinite,  and 
conditional  branches may be nested mutually,  provided that  each 
component is fully enclosed by another.
The  returnstack can be used by the user for temporary storage  of 
Parameters  and  numbers.  It  can  only be  done  from  within  a 
definition  by  use  of  the words  {>R}  and  {R>}  in  numerical 
conjunction: 2 times {>R} requires 2 times {R>} etc. The word {R@} 
copies  the  item on top of the returnstack onto the  top  of  the 
compu-stack.
{CONSTANT} and {VARIABLE} are defining words.  These can create  a 
dictionary-entry.  They are used to declare programm-constants and 
-variables.  The  initial  value  of a constant is  given  at  its 
creation and is usually maintained throughout the application. The 
value of a variable is stored at a later point in the  application 
by  means of {!}.  This value can be changed by {!}  and  {+!}. On
execution of a constant its value is placed TOS.  On execution  of 
a  variable its address is placed TOS,  its value can  be  fetched 
from the address with {@}.

REMEMBER

Branch     - In an application a branch occurs, when control no 
             longer follows the common course , but leaves it to
             fulfill a task elsewhere in memory. The application
             may come to an end there or it may return to its 
             common course and go on. A branch may be backwards or
             forwards. A branch may occur, if certain conditions 
             are fulfilled or it may be forced. These are called
             conditional and unconditional branches respectively.

|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|   WORD       |     STACKACTION       |       DESCRIPTION       |
|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|      IF      |    (f --- )           |Used in colondefinitions |
|              |                       |in the forms: IF (true)..|
|              |                       |..THEN and IF (true).....|
|              |                       |ELSE (false)....THEN.    |
|     THEN     |                       |See IF. Marks the desti- |
|              |                       |nation of forward bran-  |
|              |                       |ches from IF or ELSE.    |
|______________|_______________________|_________________________|
|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|   WORD       |     STACKACTION       |       DESCRIPTION       |
|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|     ELSE     |                       |See IF and THEN.         |
|     >R       |    (n ---)            |Moves a number from the  |
|              |                       |compu-stack to the return|
|              |                       |stack. Must be balanced  |
|              |                       |with R>.                 |
|     R>       |    (--- n)            |Moves the top number from|
|              |                       |ret-stack to the compu-  |
|              |                       |stack. See >R.           |
|     R@       |    (--- n)            |Copies the top of the ret|
|              |                       |stack to the compu-stack.|
|     +!       |    (n addr ---)       |Adds n to the value at   |
|              |                       |address addr.            |
|______________|_______________________|_________________________|

|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|   WORD       |     STACKACTION       |       DESCRIPTION       |
|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|  BEGIN       |                       |Used in a colondefinition|
|              |                       |in the forms: BEGIN......|
|              |                       |AGAIN , BEGIN...UNTIL and|
|              |                       |BEGIN..WHILE..REPEAT.    |
|              |                       |BEGIN marks the start of |
|              |                       |a repeatedly executed se-|
|              |                       |quence  and  acts  as  a |
|              |                       |returnpoint from AGAIN,  |
|              |                       |UNTIL and REPEAT.        |
|  AGAIN       |                       |Forces a branch back to  |
|              |                       |BEGIN, creating an end-  |
|              |                       |less loop. See BEGIN.    |
|  UNTIL       |   (f ---)             |If f is FALSE execution  |
|              |                       |branches back to BEGIN,if|
|              |                       |TRUE execution goes on   |
|              |                       |with the next word after |
|              |                       |UNTIL. See BEGIN.        |
|______________|_______________________|_________________________|

|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|   WORD       |     STACKACTION       |       DESCRIPTION       |
|¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
|  WHILE       |   (f ---)             |On f=TRUE execution con- |
|              |                       |tinues on REPEAT, which  |
|              |                       |causes a branch back to  |
|              |                       |BEGIN. On f=FALSE execu- |
|              |                       |tion skips to the word   |
|              |                       |next to REPEAT. See BEGIN|
|  REPEAT      |                       |In execution REPEAT for- |
|              |                       |ces an unconditional     |
|              |                       |branch back to BEGIN. See|
|              |                       |BEGIN.                   |
|  ALLOT       |     (n ---)           |Reserves n bytes of dicti|
|              |                       |onaryspace, increasing   |
|              |                       |the dictionarypointer    |
|              |                       |with n. See later DP.    |
|     ?        |      (addr  --- )     |Prints  the  value  at   |
|              |                       |address addr.            |
|     '        |      (--- addr)       |Gives pfa of the ticked  |
|              |   Used as: ' word     |word if in executionmode |
 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
EXTRAS  

As one of the pecularities of FORTH, I mentioned the extensibility 
of this marvellous language.  You can extend the executable  words 
in  the  dictionary,  you can extend furthermore the  compiler  by 
creating new defining words,  which can write new executable words 
in the dictionary.  The third way of extending FORTH is  producing 
alternative ways of generating new defining words. This process is 
often  referred to as Meta-FORTH.  It enables the writing  of  new 
FORTH-like languages !! I own a Meta-FORTH, but it's damaged !!
Meta-FORTH  is  far beyond the scope of  this  course  and......my 
knowledge, honestly.

EXERCISES

1.   Look upon the smaller definitions, which make out the {SIZE}-
word,  as separate definitions. One of them is superfluous, if you 
make some minor changes in another one.  Which one is  superfluous 
and which one is to be changed and how ?
2.   Why can't you simply substitute the changed definition in the 
'old' {SIZE}-word to form a new {SIZE-2}-word ?

3.    Define a new {SIZE-3}-word,  using nested  {IF..ELSE..THEN}- 
structures.  The {SIZE-3}-word should work better than the {SIZE}-
word.
4.    Consider the following.  VARIABLE EL OK ; 0 EL ! OK ; : ?EL 
DUP 250 > DUP IF EL +!  ." Extra large" THEN EL @ .  ; Execute the 
new ?EL-word:  300 ?EL.  See what happens. Now rewrite the {SIZE}-
word,  that  not only the tomato-sizes are printed out,  but  also 
their respective quantities.  Take care of a good-looking  display 
with each size on a new line.
5.     The next exercise,  thanks my mother-in-law,  is to write a 
word, which results in a display like:
Extra large   8 tom.    2 kg
Large        20 tom.    5 kg etc.
Now,  as the sizes are within certain limits of weight, e.g. large 
is within 200 and 250 gr, you should calculate the number of kg's, 
using the lower limit.  The overweight as a result of tomatoes not 
all  being  as  heavy  as exactly 200 gr is not  to  be  taken  in 
account.  My mother-in-law is a very generous woman !!  And  don't 
give up too soon !!!

6.      If  you  succeeded in defining the word asked for  in  the 
previous exercise,  you did a great job !! To function properly on 
a machine which has to carry out the tomato-sorting  continuously, 
this word has to be extended from a software point of view.  Which 
extension is meant here ?

SOLUTIONS TO PART 4

1.  The (CLS)-word is NOT a defined word i.e. you must find out on 
your system, how to clear the screen.
: LINE   (CLS) SWAP 0 DO CR LOOP SPACES ;
2.  : ASC1   (CLS) DO I EMIT LOOP ;
3.  : ASC2   (CLS) DUP ROT 20 MIN + SWAP DO I EMIT LOOP ;
4.  : POWERLIFT   SWAP DO I . I +LOOP ;
5.  : BACK   DO I . -1 +LOOP ;
6.  We define the powerraising routine first.
    : ^  1- ?DUP IF OVER -ROT 0 DO OVER * LOOP SWAP DROP THEN ;
If your system lacks {-ROT},  use {ROT} {ROT}.  Next we define the 
word {THICK}. : THICK   2 25 ^ 55 + 100 /  CR ." The paper is " .
." mm thick now !!"  ;.  Notice how the rounding is performed  (55 
+).  Dividing by 100 is the same as multiplying with 0,01.  If you 

want to observe the folding step by step you should define {THICK} 
as : THICK  2 SWAP ^ 55 + 100 / CR ." The paper is " . ." mm thick 
now !!" ;.  Then enter 18 THICK for instance.  The word {^} can be 
used separatedly as: 8 11 {^}, this will calculate 8^11. 
7. The solution to make 1 I gave as an example. : TWO 5 5 /  5 5 / 
+ .  ;     : THREE  5 5 5 + + 5 / . ;    : SIX   55 5 / 5 - . ;  : 
SEVEN   5 5 + 5 / 5 + .  ;   : NINE  5 5 + 5 5 / - . ;  : TEN  5 5 
5 + + 5 - .  ;.  It's possible to make 4 and 5 as well. But that's 
for some other time !!
8. One can't dig half a hole. It may be small, but a whole !!
9.  :  TABLE   11 1 DO CR DUP DUP I .  ." X " .  ." = " I * . LOOP 
DROP ;. In the next part I'll teach you how to perfect the output.
10.  :  SAME  9  MIN 10 0 DO DUP I = IF ." Equal " I .  LEAVE THEN 
LOOP ;

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.