Using kForth


2.7 Making Decisions

Forth words are usually very short for two reasons:

  1. A single word is usually written to perform a single, and simple, computation.

  2. Forth words most often use the stack to obtain input data for their computations, and leave their results on the stack.
Consider the following example:


: F>C ( n1 -- n2 | convert degrees Fahrenheit to degrees Celsius) 32 - 5 * 9 / ;


New words may make use of previously defined words, thereby making the higher level words (those words that make use of the simpler Forth words defined earlier).

2.8 The Return Stack

Because Forth words often use values on the stack for input data, it may become difficult to keep the items ordered exactly as needed during the calculation, especially when there are several input values required. While Forth provides several stack manipulation words such as DUP SWAP ROT, etc., sometimes the most convenient operation is to temporarily remove an item from the top of the stack, then place it back on the stack when needed. Of course we may use variables for this purpose, but Forth provides a simpler way to accomplish this by providing another stack, called the return stack. An item on the stack can be temporarily moved onto the return stack by using the word >R. The item may be moved back from the return stack to the ordinary data stack with the word R>.

The following example also illustrates the use of the return stack.


: this_date ( -- day month year )
     time&date >r >r >r 2drop drop r> r> r> ;


The word this_date returns today's date on the stack with the year on top. It does this by calling kForth's built-in word, TIME&DATE, which has the following stack diagram:

time&date ( -- secs mins hours day month year )


We want our word this_date to only return the day, month, and year, so we must remove secs, mins, and hours left on the stack by TIME&DATE. However, day, month, and year are on top and the three numbers we want to drop (secs, mins, and hours) are buried underneath. Using >R three times, we remove the year, month, and day from the stack, in that order. These numbers are moved onto the return stack. Now we use 2DROP and DROP to remove hours, mins, and secs from the stack. Finally, we use the word R> three times to move day, month, and year from the return stack back to the data stack.

A word of caution to the novice Forth user: the return stack must be used with the following restrictions because Forth itself places items on the return stack at the beginning of executing a word and also when executing DO loops:




Example 2: Calculating Age

In this example, we will make use of what we have learned up to now to compute the age of a person given their birth date. Following good Forth practice, we will first define a few simple words which we anticipate will be helpful for writing the actual age calculator:


: this_year ( -- year )
     this_date >r 2drop r> ;

: this_month ( -- month )
     this_date drop nip ;

: this_day ( -- day )
     this_date 2drop ;

The words this_year, this_month, and this_day all use this_date, defined previously, and remove any extra items from the stack. A couple more words will be helpful in our calculation:
: date< ( day1 month1 day2 month2 -- flag )
      rot swap
      2dup                  \ is month1 less than month2?
      < if
        2drop 2drop         \ remove items on stack --- no further test needed
	true                \ leave true flag on the stack
      else
        = if                \ is month1 equal to month2?
          <                 \ flag represents day1 less than day2
        else
	  2drop             \ remove items on stack --- month1 is greater than
          false             \   month2 so return false flag
        then
      then ;

Notice that we used two nested IF ... ELSE ... THEN structures in our definition of DATE<. The first IF examines the flag returned by <, which tests whether or not month1 is less than month2. If month1 is not less than month2, we must then check to see if month1 is equal to month2. The word = tests this condition and returns the appropriate flag, which is examined by the second IF.

: after_today ( day month -- flag | test whether day and month are in future)
     this_day this_month 2swap date< ;

We are ready now to calculate a person's age, given their birth date.

: age ( day month year -- age | calculate age given birth date )
     this_year swap -       \ number of years between birth year and this year
     -rot                   \ move top item to bottom of stack
     after_today if	    \ is birthday later than today?
       1-                   \ yes, subtract one from number of years
     then ;

We may test our definition of AGE by typing

day month year age .


where day, month, and year are the numbers for your birth day, month, and year. kForth will respond by printing your current age.




©1998--2001 Creative Consulting for Research and Education