Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Conklin E.K.Forth programmer's handbook.2000.pdf
Скачиваний:
321
Добавлен:
23.08.2013
Размер:
2.04 Mб
Скачать

Forth Programmer’s Handbook

In order to perform certain of these operations, it is necessary to refer to the unconverted portion of a number being printed. This unconverted portion is equivalent to the original number divided by the current radix, for each numeric digit already generated. For example, if the initial number is 123 and the radix is 10, the intermediate number is 12 (following the conversion of the first digit) and 1 (following conversion of the second digit).

The value of this number may be tested, and logical decisions may be made based upon its value. To illustrate, consider the following block of source code. The word D.ENG prints a double-precision integer in U.S. engineering format (i.e., a comma after every three decimal places):

0 ( Number Formats)

DECIMAL

VARIABLE #PLACES

1

: ','

44

HOLD

;

 

 

 

 

2

: (D.ENG) ( d)

SWAP OVER DABS

<# BEGIN

3

# 1

#PLACES

+!

2DUP D0=

NOT WHILE

4

#PLACES

3 MOD NOT IF

','

THEN

REPEAT

5

ROT SIGN

#> ;

 

 

 

 

 

6

: D.ENG

( d)

(D.ENG)

TYPE

SPACE ;

7

8

9

10

11

12

13

14

15

Using techniques similar to those above, you can do any kind of numeric output editing in Forth.

References Block-based disk access, Section 3.4

2.5 PROGRAM STRUCTURES

This section describes a set of Forth words used to establish program loops and to alter the normal, sequential execution of words. Similar words for use in CODE definitions are defined in the ASSEMBLER word list.

Forth Fundamentals 59

Forth Programmer’s Handbook

Logic control words must be used within a definition. They will not operate properly when typed from a keyboard, because the text interpreter (which is sequentially processing the input stream) has no way to tell where a forward branch is to terminate. Loops must be opened and closed within the same definition. Loops may be nested to any depth.

Some words in this section are called compiler directives. When the compiler sees most words, it compiles references to the words’ run-time behavior. But when the compiler sees a compiler directive, it executes it immediately, rather than compiling it. Forth is extensible, so you may define your own compiler directives. Specific techniques appear in the section referenced below.

References Compiler directives, Section 4.4

2.5.1 Indefinite Loops

The simplest looping method available in Forth is the BEGIN AGAIN loop. This loop endlessly repeats the code that is between the BEGIN and AGAIN. BEGIN AGAIN loops are used for control activities which are not expected to stop. These commonly are used to define the power-up behavior of an embedded system, or a loop that will only terminate if an error condition causes a THROW. Examples of such applications include process-control loops and com- puter-sequenced machinery. BEGIN AGAIN is also used in QUIT, the high- est-level word of an interactive Forth system. Loops with no exit can only be used at the highest level in a program.

An example of the outermost loop in a program to control an industrial process might be:

: REACTION CONTROLS CLEAR

BEGIN DATA ERROR CORRECT AGAIN ;

This process-control loop clears the controls, then enters an infinite loop which continuously collects data, calculates an error quantity, and applies a correction function. Usually, such a program is run asynchronously by a background task, and the operator stops it with a word built from task-control words.

BEGIN does not actually compile anything, it simply pushes the address of the

60 Forth Fundamentals

Forth Programmer’s Handbook

next available dictionary location on the stack at compile time. Thus, it marks a location for use by a subsequent compiler directive’s operation.

BEGIN and UNTIL allow the user to set up a loop which may be executed repetitively, in a manner similar to BEGIN AGAIN loops except that a test is performed before the loop repeats.

The form of a BEGIN UNTIL construct is:

BEGIN <words to execute repeatedly> <test value> UNTIL

When execution reaches the word UNTIL, the test value on top of the stack is examined and removed from the stack. If this value is false (zero), execution returns to the word that follows BEGIN; if the value is true (non-zero), execution continues with the word that follows UNTIL.

BEGIN loops can be nested. entirely within any outer loop. trol structure. For example,

However, a loop of any type must be nested There is no way to branch directly out of a con-

BEGIN <words>

BEGIN <words>

UNTIL <words>

UNTIL <words>

BEGIN UNTIL may only be used within a definition; it may not be executed interpretively from a terminal.

The ASSEMBLER word list also contains words named BEGIN and UNTIL; these words function similarly to their equivalents, but with differences related to the context in which they occur.

Pre-testing indefinite loops are similar to BEGIN UNTIL loops, except the test to leave the loop is performed before the end of the loop code. The syntax of the Forth pre-testing loop is:

BEGIN <executed every iteration> <test> WHILE <not executed on the last iteration> REPEAT

There may be no code before WHILE except the test, in which case the loop code may not execute at all. WHILE removes the top number from the stack and tests it, then leaves the loop if the value is false (zero), skipping the words

Forth Fundamentals 61

Forth Programmer’s Handbook

between WHILE and REPEAT. If the value on the stack is true (non-zero), WHILE continues to the next word in the loop. When the program execution reaches REPEAT, it branches unconditionally back to the words immediately after BEGIN and repeats the loop.

For an example, consider a word that counts fruit in a mechanical sorter:

: GOOD ( -- n )

0 BEGIN

FETCH FRUIT ?GOOD

WHILE 1+ REPEAT ;

As long as the machine sees good fruit in the test cell, the loop continues and the machine considers the next fruit. When the test fails, the fruit remains in the test cell, to be evaluated by some process other than the word ?GOOD.

In situations when both are equally convenient, the BEGIN UNTIL loop is faster and requires fewer bytes, and thus is preferable to the BEGIN WHILE REPEAT loop.

Glossary

AGAIN

( — )

Core Ext

 

At compile time, compile an unconditional backward branch to the location on

 

the control-flow stack (usually left there by BEGIN; see Section 4.4.2). At run

 

time, execute the branch.

 

BEGIN

( — )

Core

 

At compile time, save the next available dictionary location on the control-

 

flow stack. This action marks the destination of a backward branch for use by

 

other compiler directives. At run time, simply continue execution.

 

REPEAT

( — )

Core

At compile time, resolve two branches, usually set up by BEGIN and WHILE. In the most common usage, BEGIN leaves a destination on the control-flow stack and WHILE places an origin under BEGIN’s destination. Then REPEAT compiles an unconditional backward branch to the destination location following BEGIN and provides the location following REPEAT as the destination address for the forward conditional branch originated by WHILE.

At run time, execute the unconditional backward branch to the location fol-

62 Forth Fundamentals

Соседние файлы в предмете Электротехника