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

Forth Programmer’s Handbook

branch at the end of the true clause (this will later be resolved by THEN). At run time, execute the unconditional branch to skip over the false clause.

IF

( x — )

Core

 

At compile time, place a forward reference origin on the control stack, marking

 

the beginning of a conditional branch. At run time, if x is zero take the for-

 

ward branch to the destination that will have been supplied (e.g., by ELSE or

 

THEN); otherwise, continue execution beyond the IF.

 

THEN

( — )

Core

At compile time, provide the location beyond THEN as the destination address for the forward branch origin found on the control stack. This origin will normally have been placed there either by ELSE (if there was a false clause) or by IF (if there was no false clause). At run time, simply continue execution.

References Logic operations, Section 2.2.2

Control-flow stack, Section 4.4.2

Text interpreter directives, Section 4.1.6

2.5.4 CASE Statement

A high-level CASE statement structure is available for situations in which an input condition needs to be checked against more than one or two possible values. The usual syntax is:

CASE

<x1> OF < x1 action> ENDOF

<x2> OF < x2 action> ENDOF

<default action> ENDCASE

The structure begins with the word CASE. When it executes, a case selector x must be on the stack. A series of OF ENDOF clauses follow, each OF being preceded by a test value on the stack (x1, x2, etc.). The case selector is compared against the test values in order. If it matches one, the corresponding code between that OF and ENDOF is executed, and execution branches beyond the ENDCASE. If the case selector does not match any of the test values, it remains on the stack after the last ENDOF, and some default action may be

Forth Fundamentals 67

Forth Programmer’s Handbook

taken. Any action should preserve the stack depth (use DUP if necessary), because ENDCASE performs a DROP (presumably on the case selector) and then continues execution beyond ENDCASE.

This structure is flexible, and is more readable than nested IF statements if there are more than two or so comparisons. CASE statements may be nested; there may be any number of OF ENDOF pairs; and there may be any amount of logic inside an OF ENDOF clause, including computation of the next test value.

Implementation details of a CASE statement are system dependent—especially with regard to the method of handling the multiple branches—but in all cases, the logic conforms to the above description.

Glossary

CASE

( — )

Core Ext

 

At compile time, mark the start of a CASE OF ENDOF ENDCASE struc-

 

ture. At run time, continue execution.

 

ENDCASE

( x — )

Core Ext

 

At compile time, resolve all branches in the case structure, such that the loca-

 

tion beyond ENDCASE becomes the destination for all branches originated by

 

occurrences of ENDOF. At run time, discard the top stack value x (presumably

 

the case selector) and continue execution.

 

ENDOF

( — )

Core Ext

 

At compile time, provide the location following ENDOF as the destination address

 

for the forward conditional branch originated by the corresponding OF. Place a

 

new forward reference origin on the control stack, marking the beginning of an

 

unconditional branch (this will later be resolved either by the next ENDOF or by

 

ENDCASE). Perform other system-dependent functions which may involve reso-

 

lution of other clause origins. At run time, execute the unconditional branch.

OF

( x1 x2 — | x1 )

Core Ext

At compile time, place a forward reference origin on the control stack, marking the beginning of a conditional branch. At run time, if test value x2 is not equal to case selector x1, discard x2 and take the forward conditional branch to the destination that will have been supplied by ENDOF; otherwise, discard both values and continue execution beyond the OF.

68 Forth Fundamentals

Forth Programmer’s Handbook

References Logic operations, Section 2.2.2

Control-flow stack, Section 4.4.2

2.5.5 Un-nesting Definitions

When a high-level definition calls another, it is said to nest the calls, because the return will normally be to the next location in the calling definition. The called definition un-nests when it is finished executing, to effect this return.

EXIT is a function that causes un-nesting to occur. EXIT may be used to leave a definition at any point. In indirect-threaded implementations, EXIT is compiled by ; at the end of every : definition, but may also be called directly. EXIT leaves the current definition, and resumes execution of the next word in the definition which called the word containing EXIT. Because many implementations use the return stack to control nesting, it must be clear of any temporarily stored data before an EXIT can be performed; for example, loop parameters must be discarded by UNLOOP if EXIT is executed within a DO LOOP.

A trivial example of EXIT is:

: TEST ( n) 1 . IF EXIT THEN 2 . ;

0 TEST 1 2

1 TEST 1

Frequently, words containing EXIT will have different stack results, depending on whether the word EXITs or not. The standard stack notation for such a situation is:

( input-arguments -- EXIT-case | normal-case)

EXIT is the only Forth word which permits unstructured programs (modules with multiple exit points). Because unstructured techniques tend to impair code’s readability and maintainability, they should be used sparingly—only when the overall effect is to simplify the code. It is considered bad form to use EXIT more than once in a word; if you believe you need to do so, try factoring that word into several words.

Forth Fundamentals 69

Forth Programmer’s Handbook

Glossary

 

 

 

 

 

 

EXIT

 

 

( — ); ( R: nest-sys — )

Core

 

 

 

Return control immediately to the calling definition specified by nest-sys.

 

 

 

Before executing EXIT, a program must remove any items explicitly stored on

 

 

 

the return stack. If EXIT is called within a DO LOOP, UNLOOP must be exe-

 

 

 

cuted first to discard the loop-control parameters.

 

 

 

 

Interpreter pointer, Section 1.1.7

 

References

 

 

 

 

 

LOAD, Section 3.4.3.1

 

 

 

 

 

Text interpreter, Section 1.1.5

 

 

 

 

UNLOOP, Section 2.5.2

 

 

 

 

 

2.5.6 Vectored Execution

 

 

 

 

Although normal Forth usage (as well as good programming practice) empha-

 

 

 

sizes the structured programming modes of sequential, iterative, and conditional

 

 

 

execution, it is sometimes desirable to direct Forth to execute a specific func-

 

 

 

tion in response to some external stimulus. This technique may be used, for

 

 

 

example, by a report that searches a database, selecting records according to a

 

 

 

criterion which may need to vary; by a bank of push-buttons, each of which is

 

 

 

attached to a particular Forth word; or by a routine that computes the address

 

 

 

of a function to be executed.

 

 

 

 

The word EXECUTE expects an execution token on the stack—a value, usually an

 

 

 

address, that points to the execution behavior of a definition. EXECUTE removes

 

 

 

the token from the stack and uses it to cause the given definition to execute.

 

 

 

 

For example:

 

 

 

 

 

VARIABLE NUMERAL

 

 

 

 

 

: T1

1 . ;

 

 

 

 

 

: T2

2 . ;

 

 

 

 

 

: ONE

['] T1

NUMERAL ! ;

 

 

 

 

: TWO

['] T2

NUMERAL ! ;

 

 

 

 

: N

NUMERAL @ EXECUTE ;

 

70 Forth Fundamentals

Forth Programmer’s Handbook

If the user types:

ONE N

the system will display 1. Typing:

TWO N

will produce 2.

The stack effect of all members of a set of words to be EXECUTEd in a particular context must be the same. That is, they must all require and leave the same number of items on the stack.

The word DEFER provides a convenient means of managing a single execution vector. The syntax is:

DEFER <name>

This creates a dictionary entry for name and makes it an execution variable. name is similar to a variable, but specifically contains the execution token of another word; the other word is executed when name is executed. The execution token of the other word to be executed is stored into the data area of name by the word IS. If name is executed before it has been initialized by IS, an error will occur.

DEFER lets you change the execution of previously defined commands by creating a slot which can be loaded with different behaviors at different times. The preceding example would be defined this way using DEFER:

DEFER NUMERAL

 

 

 

: T1

1

. ;

 

 

 

: T2

2

. ;

 

 

 

: ONE

 

[']

T1

IS

NUMERAL

;

: TWO

 

[']

T2

IS

NUMERAL

;

Then, typing:

ONE NUMERAL

displays 1, and

Forth Fundamentals 71

Forth Programmer’s Handbook

TWO NUMERAL

displays 2.

Most uses of EXECUTE are for implementing a variable function, as described in the previous sections. The ability to generate and manage a table of execution addresses is also extremely useful for such purposes as managing a func- tion-button pad, a function menu on a graphics tablet, etc. The following example will outline a simple button-response application which may serve as a model for similar situations.

Let us assume that the word BUTTON has been defined to wait until a button is pressed and then to return the button number (0–15) of the button (the actual definition of BUTTON would depend on the computer and interface). Now consider the following:

VARIABLE

BUTTONS

15 CELLS

ALLOT

: IGNORE

;

 

 

' IGNORE

BUTTONS !

BUTTONS

DUP CELL+

14 CELLS CMOVE

The above lines create a table with one cell for each button, and initialize all positions to contain the address of an empty definition (which effectively “ignores” an undefined button). The move and replication of the IGNORE address must be done with a CMOVE instead of a MOVE, because only CMOVE is guaranteed to move one cell or less at a time, achieving the replication of the address.

Now we will define special versions of : (colon) and ; (semicolon) that will not only create an ordinary definition but also store its execution token into a specified cell of BUTTONS. To do this, we use the word :NONAME, which returns the execution token of the current definition on the stack. Because :NONAME does not create a dictionary entry, we need to make an entry explicitly with CREATE, and we need to store the execution token into this word’s parameter field (done by the second ! in the definition of ;B below).

: :B ( n) CREATE

HERE 0 , :NONAME DOES> @ EXECUTE ;

: ;B

POSTPONE ;

ROT OVER SWAP CELLS BUTTONS + !

 

SWAP ! ; IMMEDIATE

Now we can create definitions which are attached to certain buttons by using

72 Forth Fundamentals

Forth Programmer’s Handbook

:B with the button number as a parameter, and concluding the definition with ;B. Each such definition will have a name, to allow it to be tested independently of the button pad. For example,

0 :B ESCAPE 1 ABORT" ?" ;B

defines Button 0 to be an “escape” button. All that remains is to define a routine to monitor the button pad and to handle responses:

: MONITOR BEGIN BUTTON BUTTONS + @ EXECUTE AGAIN ;

Typing MONITOR will place the terminal task in an infinite loop that responds to buttons. Button 0 will cause an abort and return control to the terminal.

In practice, MONITOR may very likely be executed by a background task (on systems that support multitasking). In this case, you may need techniques other than ABORT" (which requires a terminal) for halting.

Glossary

DEFER <name> ( — ) common usage

Define name to be an execution variable. When name is executed, the execution token stored in name’s data area will be retrieved and the behavior associated with that token will be performed. An error will occur if name is executed before it has been initialized by IS.

EXECUTE

 

( i*x xt — j*x )

Core

 

 

Remove execution token xt from the stack and perform the execution behavior

 

 

it identifies. Other stack effects are due to the word that is EXECUTEd.

IS <name>

( xt — )

common usage

 

 

Store xt in the data area of the execution variable name.

 

 

 

['], Section 4.3.6

 

 

References

 

 

 

 

:NONAME definitions, Section 4.2.4

 

 

 

ABORT", Section 2.6

 

 

 

 

Custom defining words and DOES>, Section 4.2.6.2

 

 

 

IMMEDIATE and POSTPONE, Section 4.4.1

 

 

 

TO used with VALUEs, Section 4.2.3

 

Forth Fundamentals 73

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