Strolling Forth
by Stephen Maguire and Evan Rosen
In the previous three articles, we have discussed what FORTH is and have given some examples of FORTH code. But the novice still has many questions stemming from FORTH's esoteric way of doing things. For example, why doesn't FORTH run under a Disk Operating System? This installment will answer this and many other questions still remaining about FORTH.
In fact, if the programmer understands why FORTH seems quirky, a better appreciation of the language is gained.
What is "Fig" FORTH?
All of the popular FORTHs for the Atari are implementations of the public domain software provided by the FORTH Interest Group (fig). About six years ago, this group implemented a usable FORTH system on many different computers. This was made available to anyone for reproduction costs and put no restrictions on its use. The effort to increase the popularity of FORTH resulted in literally hundreds of implementations of fig-FORTH. This dialect by far has become the most popular.
And just for the record, a great deal of credit should be given to Bill Ragsdale for making his 6502 figFORTH available to the public. Without his implementation, none of the FORTHs for the Atari would exist. He too was a main driving force in making fig-FORTH available for as many processors as possible.
Ironically, fig-FORTH (which conforms to the 77-standard) has become so widely accepted all attempts to bring it up to the 79-standard have failed. Incidentally, the 83-standard has just been accepted and a new public domain FORTH soon will be available that conforms to this standard.
To DOS or Not to DOS
This is probably the question most frequently asked by new FORTH programmers. I here are several reasons for not using a DOS. The best answer is the vast majority of programs do not need the capabilities provided by DOS and would waste 10K-plus by having it in memory. And for those programs which do need to save and retrieve data from disk, very few require the file manager DOS affords. Many can simply perform basic read/writes to the disk.
A second reason for going DOSless is transportability of data. For example, FORTH source code can be written on a TRS-80 which unlike the Atari uses a standard disk format. And an IBM PC running FORTH can read the disk as though it was developed on that machine.
However, disks written using TRS-80 DOS cannot be read by the IBM DOS because the file structure is vastly different. Thus, because of software incompatibility in the DOS, file transfers between the two systems are practically impossible. This problem does not exist in FORTH.
Finally, it is very easy to implement FORTH on any new processor. Minimal disk routines need to be written to have FORTH up and going, whereas a good DOS could take more than a year to write.
Then Why Use Screens?
FORTH source code is not stored in files, but on screens. By using the minimal disk routines available in FORTH, source code is entered directly onto disk sectors. A screen is generally 512 or 1024 bytes (four or eight sectors) in length. A special editor is used to write source code to these screens. To compile a FORTH program, it is LOADed. LOAD takes a screen number on the stack and source code on that screen is compiled.
Because source code is stored directly on disk and not in files, a great deal of available disk space is wasted. For example, if only the first two lines of a screen contain code, the remainder of the screen is wasted disk spaces. Usage shows that nearly half the disk is effectively wasted. It is for this reason FORTH programmers traditionally pack as much code on a screen as possible. Basically, program readability is given up for increased disk storage. Hence, FORTH has become known as a write-only language.
With the cost of disks much lower today than ever before, it is far better to code for readability than to minimize disk usage. This means indenting DO loops -- IF. . . ENDIF constructs and the like.
Using Reverse Polish Notation
Without going into detail, Reverse Polish Notation is a method of expressing arithmetic formulas without the need for parentheses. Hewlett Packard has used this form of notation in its calculators for more than a decade. FORTH does not use RPN for any particular reason except it fits nicely into the whole FORTH picture.
The FORTH language is composed entirely of subroutines which all behave in the same manner. These subroutines -- words -- take a number of arguments, operate on them and return a number of arguments.
To simplify, FORTH sets aside a special stack called the parameter stack which holds arguments until needed. FORTH words will remove arguments from this stack and possibly replace with others. The arithmetic words -- *, /, etc. -- do exactly this. Each removes two arguments and puts one back.
Thus, to write the expression (3 + 5)/2 in FORTH, we have:
3 5 + 2/
This is evaluated as follows: The numbers 3 and 5 are pushed onto the parameter stack and the word + is called, which removes them. The sum is computed and the results, 8, is pushed onto the stack. Next, 2 is pushed and / is called which then divides 8 by 2 and pushes 4. Notice no parentheses were needed to ensure the addition was done before the division. If we had wanted to express 3 + (5/2), we would have written: ,
3 5 2/+
Because FORTH uses the stack in this manner, it is called a stack-oriented language -- which has a great deal to offer.
Because words can leave more than one argument, FORTH can perform many computations more efficiently (and therefore faster) than its non-stack counterparts such as BASIC. For example, when a division is performed internally both the quotient and the remainder come out naturally. But BASIC allows only one value to be returned from an operation. If both the quotient and the remainder are wanted in BASIC, the division routine must be called twice -- once more than needed. FORTH does not suffer from this. The FORTH word /MOD takes two numbers and leaves two -- the quotient and the remainder.
Neither BASIC nor FORTH support complex numbers, but they can be added to both languages. Since complex numbers have both a real and an imaginary part, they must be represented by two numbers. This presents problems in BASIC. How would 3 + 5i and 4 + 2i be multiplied? BASIC allows only one value to be returned from a function and we need to return two. In FORTH, simply write a word C* -- which takes four numbers off the stack and leaves two. C* would have the stack notation
(rl il r2 i2 -- - r3 i3).
To do the multiplication above, we need only write:
3 5 4 2 C*
Doing this, the result is left on the stack. Of course, a complete set of complex operators could be written and used just as easily.
Since BASIC does not allow more than one argument to be returned from a function, many simple programs become quite complicated. Any program which needs to read a joystick becomes cluttered because a single stick value must be broken into its horizontal and vertical components. A BASIC program which has to perform a simple function like returning the current (x,y) cursor position also becomes cluttered. Stack-oriented languages do not suffer the same problems.
Extensible Defined
FORTH is one of few languages which are extensible. This means the FORTH compiler can be extended and made more useful. Everything in FORTH can be changed to suit individual preferences. This cannot be done in BASIC.
If a Microsoft BASIC program must be translated to Atari BASIC, there will most probably be statements Atari BASIC does not have such as the WHILE . . . WEND construct. If a WHILE . . . WEND is in the original program, it must be recoded into recognizable keywords. This may take a great deal of time.
In FORTH, however, if a WHILE . . . WEND is needed it can be added to the compiler and the program itself does not need to be recoded. Hence, the compiler is extended. For example, there is no FOR . . . NEXT structure in FORTH. The DO . . . LOOP structure is very similar to a FOR . . . NEXT loop, but it is not as nice as it could be. Take the following program:
10 REM: TEST
20 FOR I =1 TO 10
30 PRINT I
40 NEXT I
50 END
In traditional FORTH, this is written as:
: TEST ( --- )
11 1 (last + 1 1st)
DO I . CR ( . means PRINT)
LOOP; (CR means c/r)
If we were to extend the compiler, we could have:
: TEST ( --- )
1 10
FOR
I PRINT
NEXT;
Screen 10 actually contains the source code for the FOR . . . NEXT structure. This extensibility makes FORTH so powerful Charles Moore, creator of FORTH, was able to write a BASIC compiler in only eight screens of code!
Dear Dr. Quatro,
I've looked at the definition of FILL in my FORTH and it is defined using the word CMOVE. I'm confused, what's up?
Yottsu Daiskii,
Yokohama, Japan
Do you ever wonder where the programmers get the name "hacker"? Well, I'll tell you. They get this name because they sit around all day thinking up the "hacks" -- the programming tricks. In FILL, CMOVE is a hack. If you put a character in the first byte, move it to the second byte, then move the second byte to the third byte, you are filling memory.