You are on the archived version of the www.TheForthSource.com website. These materials are presented for informational purposes only. We express our gratitude to 1PLs Co [urgent loans in the USA] for paying for hosting.

FORTH GUIDE


CHAPTER X


STRUCTURES


MVP-FORTH includes three structure types: 1/ the conditional IF ... ELSE ... THEN ; 2/ a fixed range, repetitive loop, DO ... LOOP , with several variations and 3/ a repetitive structure, BEGIN ... UNTIL , also with a number of variations. These structures provide all of the conventional programming structures. You have already used two of these structures.

The conditional structure you have already seen in some of the examples. Its use is relatively straight forward once you appreciate its unique requirement. The last data given to the system before the beginning of the IF function must be a truth flag. That flag is consumed by the function. A value of zero indicates a false flag and any non-zero value is interpreted as a true flag.

A selection of comparison functions are available in MVP-FORTH. These include = , , , 0 , 0, and 0= as well as some which are double precision operators. Their functions are clear enough. In all cases, any data being compared is consumed. To be sure of the function of a particular operator it is easy to interactively test the function.

        2 3  >  .
        2 3  <  .

It is often easier to verify the function rather than try to remember it or to look it up. The system is there ready to help you through interactive programming.

The function of the IF command is to set a system flag and on a zero value to branch. The primitive available for your use if you insist is 0BRANCH. The word IF must be compiled in a definition. The structure cannot be used outside of a definition. Thus you must write a colon definition to test or use the conditional IF ... ELSE ... THEN structure.

The function performed is to jump either to the high level FORTH code which follows the optional ELSE or to that following the THEN, if the flag is zero. Remember a zero flag is false. If the flag is non-zero, the high level FORTH code following the IF is executed up until the optional ELSE or through the THEN. If the ELSE construct is used, the system compiles an unconditional branch instruction with the primitive BRANCH to the code which follows the THEN. The primitive, BRANCH, is also available to you should you need it.

You have seen examples of the IF ... ELSE ... THEN structure in an earlier section. Perhaps you can contrive some to exercise it now.

        : TEST
           IF ." The value is not zero."
           ELSE ." The value is zero. "
           THEN ;

You have an example of writing style to set off the structure. Begin each part of the structure on a new line. This way you will be able to spot missing matched pairs. If you do not match these structures, the definition will not compile and you will get the message: DEFINITION NOT FINISHED.

You can give the system a truth value and execute the function TEST. According to the value given, zero or non-zero, you will be given the appropriate message.

You might shorten this example, but it might be cryptic and make it harder to read. You be the judge.

        : TEST1
           ." The value is "
           IF ." not "
           THEN ." zero. " ;

As you can see, there are many possible ways of programming a desired function. Each may well produce the desired result. There is no single correct way. The ultimate test is whether the function works correctly in all circumstances. In checking any new function it is good to examine particularly the boundary conditions. Perhaps you do not have a boundary condition as in this case.

And speaking of cases, a number of CASE functions have been written. It is interesting to find that the code actually compiled is usually the same as that compiled by a series of nested IF ... ELSE constructs.

        : TEST2
           DUP IF ... 
              ELSE IF ...
                 ELSE IF ...
                 THEN
              THEN
           THEN
        ;

You can build up any sort of system you wish. Perhaps you can find one of the many CASE definitions and test it. Do a DUMP, or if you have a decompile function available use that to see what the actual compiled FORTH code looks like.

In using special functions such as CASE, you are adding complexity to your vocabulary. You will probably find that it is easier to master the functions available in the kernel and completely understand the use of each than it is to learn and understand a larger number of utilities.

The choice of how you desire to work is left up to you. There is nothing in FORTH to force you to do many things in the manner already described. In MVP-FORTH, you are also given the source code and can make any personal changes you wish. A CASE function is included in the latest ALL ABOUT FORTH.

You saw the first part of the DO ... LOOP discussion earlier. It is repeated here for convenience.

First, the DO function requires two input values or parameters. They constitute a range. The first value is one more than the last iteration to be performed and the second is the first iteration to be performed. The current value of the index for the structure can be found with the MVP-FORTH word, I .

The function of LOOP is to terminate the iteration. If the value at I is equal to or greater than the terminating value the loop is terminated.

        : TEST3
           10 0
           DO I .
           LOOP ;

This example will display the digits 0 through 9 and stop. The style is open. You are wasting a lot of space. But it tends to increase the clarity of the code you have written. You might wish to adopt some other style. In the example, the style is to begin a DO structure at the beginning of a line. Therefore, the values, i.e., the parameters, for the structure must be at the end of the preceding line.

For very short structures such as this one which include only two high level FORTH functions, you might prefer to place them together on a single line. There is nothing in FORTH which forces you to adopt any given style. That is left to you. If you adopt a readable style, you will be able to understand your program later. Few comments are needed. If you run everything together, you are responsible for your later difficulties in understanding and debugging your program. You also should remember that others may need to read your code.

LOOP increments the index by one on each iteration. There are two other variations of the terminating loop function. +LOOP increments the index by the value given the system immediately preceding the name.

        : TEST4
           10 0
           DO I . 2
           +LOOP ;

For the sake of beginning the terminating line with +LOOP the incrementing value will always be on the end of the preceding line. Again this is a matter of style.

The increment is a simple signed arithmetic addition. Thus in signed integer arithmetic the limit is going to be 7FFF hexadecimal. The value 8000 hexadecimal is the lowest, not the highest, value and may cause trouble.

Occasionally, it is convenient to use addresses for the parameters of the LOOP function. You must then be careful to not cross the boundary for signed integer arithmetic. An alternate loop function, /LOOP, ( 'up-loop' ) does simple unsigned arithmetic. This can then be used to cross the boundary condition imposed by +LOOP.

DO ... LOOP structures can be nested indefinitely to the size of memory available. In nested structures, the value returned by I is always the value for the current loop. The index for the preceding loop structure is returned with the function J . You might want to look up one other function which will return the index under special circumstances: I' .

Nested DO ... LOOP structures must always be paired. Again using a convenient style will facilitate the pairing of all of the structures.

There are some occasions in which you may wish to leave the DO ... LOOP structure before the indexed iterations are completed. This can be done with the function LEAVE. Suppose you are executing a function and you realize that the wrong thing is happening. You would like to be able to terminate the structure.

        : COPIES
           DO I . I I 100 + COPY
              ?TERMINAL IF LEAVE THEN
           LOOP FLUSH ;

This is the sort of utility you might write to copy a group of FORTH screens up 100 screens. The offset value of 100 in this case could be made equal to the offset from one disk drive to the next. The function would then copy the selected screens from one disk to the other.

One feature illustrated in this example is the use of I . 'dot' within the definition. The word I returns the value of the current iteration of the DO ... LOOP which you can then print. It is always nice to know how you are progressing in such functions.

The second is the use of ?TERMINAL to inspect the key board. If a key has been struck, the flag will change from zero to non-zero and you will force the loop to terminate at that point. The function ?TERMINAL has a potential problem among implementations of MVP-FORTH. The problem depends on whether the system has a type-ahead input buffer. Check the documentation for your system. In the example given here, there is no problem in any of the implementations of MVP-FORTH. This is just a word of caution.

The last structure is the BEGIN ... UNTIL structure. This general structure also has a number of variations.

        : TEST5 0
           BEGIN 1+ DUP . DUP 9 =
           UNTIL DROP ;

The 0 provides the initial value for this example. That value is incremented and then displayed on each repetition. The value is then compared to 9 and a flag is set. If the flag is false the sequence will be repeated. When the flag is true the repetition is terminated. The example is contrived and would probably be better written as a DO ... LOOP structure. However, the program does exactly the same thing. This is another example of the multiple ways which can be used to write a program. There is no one correct way.

One limitation with a DO ... LOOP structure is that the sequence must run at least once. There are occasions where you would like to only conditionally do the loop at all. The DO ... LOOP could be executed within an IF ... THEN structure. Alternatively, you could use a BEGIN ... WHILE ... REPEAT variation of this structure.

        : TEST6 0
           BEGIN DUP 10
              WHILE DUP . 1+
           REPEAT DROP ;

This is still another way to execute exactly the same function you saw earlier. The proper flag is set before the WHILE function and as long as the flag is true, non-zero, the sequence will repeat. When the flag is zero, the rest of the sequence is skipped and the structure execution terminated.

The function REPEAT compiles a related MVP-FORTH word AGAIN. It is the run time function of AGAIN which causes the unconditional repetition of the structure. If you have no means of leaving the structure you will be in an infinite loop. That is exactly what the run time FORTH program is doing.

Look up the definition of QUIT. You will see that it is an infinite loop. That will give you something more to think about.

We have covered the three basic structures available in MVP-FORTH: the conditional IF ... ELSE ... THEN and two repetitive structures, DO ... LOOP and BEGIN ... UNTIL. They provide much of the power of FORTH. If your system runs at all, you can be sure that these structures are functioning properly.

The function of the DO ... LOOP in MVP-FORTH has been made to conform with the requirements of the FORTH-79 Standard. This was done early on. But the code is unnecessarily complicated. In the MVP-FORTH PADS (Professional Applications Development System) implementation, the adherence to the Standard has been sacrificed for the sake of improved performance. It is highly unlikely that a user will notice the difference. For the sake of stability of the MVP-FORTH program, the implementation has not been changed.

The future holds the possibility of requiring yet another change in the implementation of the DO ... LOOP structure. In implementing a FORTH processor there are advantages to using a count down register rather than the limits and an iteration pointer. If such a hardware implementation becomes common, the function of loop will be changed. Hopefully, a new name will be found for the new function rather than changing the function of a previously used FORTH word.

Next Previous Contents