StrongForth's implementation of the ANS Forth Programming-Tools word set is provided as source code in blocks 80 to 91. A small number of these words is already included in the core and in the library.
Name | Word Set | Location | Comment |
---|---|---|---|
.S | TOOLS | Library | |
? | TOOLS | Block 81 | |
DUMP | TOOLS | Blocks 82 to 85 | 6 overloaded versions. Uses .HEX and .BYTE. |
SEE | TOOLS | Blocks 86 to 88 | Uses ?COLON, HAS-PARAM?, SEE-LIT, SEE-DLIT, SEE-SLIT and SEE-ANY. |
WORDS | TOOLS | Blocks 80 to 81 | Extended semantics. Uses . for items of data type DEFINITION. |
;CODE | TOOLS EXT | Block 91 | Uses (;CODE). |
AHEAD | TOOLS EXT | Library | |
ASSEMBLER | TOOLS EXT | Block 90 | Dummy word. |
BYE | TOOLS EXT | Core | |
CODE | TOOLS EXT | Core | |
CS-PICK | TOOLS EXT | None | This word is not available in strongForth. |
CS-ROLL | TOOLS EXT | None | This word is not available in strongForth. |
EDITOR | TOOLS EXT | Block 90 | Dummy word. |
FORGET | TOOLS EXT | None | This word is not available in strongForth. |
STATE | TOOLS EXT | Core | |
[ELSE] | TOOLS EXT | Block 89 | |
[IF] | TOOLS EXT | Block 90 | |
[THEN] | TOOLS EXT | Block 90 |
The complete Programming-Tools word set becomes available after compiling it into the dictionary with
80 91 THRU
StrongForth's version of WORDS has an extended semantics with respect to the ANS Forth specification. If the parse area is not empty after WORDS, only words with the specified name are displayed. This is quite useful for finding all overloaded versions of a word:
WORDS . . ( DEFINITION -- ) . ( DATA-TYPE -- ) . ( FLAG -- ) . ( CHARACTER -- ) . ( SIGNED -- ) . ( SINGLE -- ) . ( SIGNED-DOUBLE -- ) . ( DOUBLE -- ) OK
This example reveals another word, that is included in strongForth's Programming-Tools word set. . for items of data type DEFINITION is actually used by WORDS itself to display a definition including it's stack diagram.
? is actually a very simple word. In many ANS Forth systems, it is simply implemented like this:
: ? ( a-addr -- ) \ ANS Forth @ . ;
But this doesn't work in strongForth:
: ? ( ADDRESS -- ) @ . ; @ ? undefined word ADDRESS
All versions of @ that are provided by strongForth expect the address of a specific data type on the stack. Our first approach micht look like this:
: ? ( DATA -> SINGLE -- ) @ . ; OK BASE ? 10 OK
This works fine, but it has a couple of serious drawbacks. First, we need a separate version of ? for each kind of address (DATA, CONST, CODE, PORT and FAR-ADDRESS). If we add the character addresses, we already get 10 different versions of ?. Second, all items will be displayed as unsigned single-precision numbers, even items of data type SIGNED, FLAG, CHARACTER, and DOUBLE. ? wouldn't care about the different overloaded versions of . that display all data nicely according to their data type. That is, unless we decide again to overload ? by defining separate versions for all overloaded versions of .. But with 8 different versions of . and 10 different kinds of addresses, we'd have to define 80 (!) overloaded versions of ?. No way.
But there's a simple solution. Only one version of ?, that covers all those 80 combinations, plus all future kinds of addresses and all future versions of .. Here it is:
: ? ( -- ) POSTPONE @ POSTPONE . ; IMMEDIATE
The only drawback is that this version of ? compiles two tokens instead of one. But as a compensation, it executes a little bit faster at runtime.
strongForth provides 6 overloaded versions of DUMP in order to cover all combinations of the data size (single-cell, double-cell and character size) with the DATA and CONST memory areas:
DUMP ( CCONST UNSIGNED -- ) DUMP ( CDATA UNSIGNED -- ) DUMP ( CONST -> DOUBLE UNSIGNED -- ) DUMP ( DATA -> DOUBLE UNSIGNED -- ) DUMP ( CONST UNSIGNED -- ) DUMP ( DATA UNSIGNED -- )
Because the definitions of all these overloaded versions look very similar, it's easy to define the missing versions for addresses of data types CODE, PORT and FAR-ADDRESS, and the respective character addresses,
The versions of DUMP for character addresses display 16 2-digit hexadecimal numbers per line. The double-cell versions display 4 8-digit hexadecimal numbers per line. All other addresses are assumed to refer to single-cell data, which are displayed as 8 4-digit hexadecimal numbers per line. Here are some examples:
85 BLOCK 64 DUMP 05EC: 5C 20 50 52 4F 47 52 41 4D 4D 49 4E 47 2D 54 4F 05FC: 4F 4C 53 3A 20 44 55 4D 50 20 20 20 20 20 20 20 060C: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 061C: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 OK ' DUMP >CODE 20 DUMP 2282: 14BC 0088 0080 00FC 023E 0074 0236 0000 2292: 018A 021C 0036 0074 0212 0010 00FC 0236 22A2: 0000 0182 0074 0090 OK DTP@ 5 DUMP 0140: 061E0000 061E0000 062A0000 06160000 0150: 063A0000 OK
.BYTE and .HEX are used within DUMP for displaying one number as 2, 4 and 8 hexadecimal digits:
.BYTE ( SINGLE -- ) .HEX ( SINGLE -- ) .HEX ( DOUBLE -- )
Colon definitions can be decompiled and displayed with SEE. Other definitions, like code definitions, constants, variables and values, may easily be included by extending the semantics of SEE. SEE traverses the virtual code of a colon definition, displaying the names of the words that are assiciated with the compiled execution tokens. It further recognizes tokens that have a parameter, like (R@) or BRANCH. The parameters are displayed as signed numbers, because they are either branch offsets or return stack offset:
: TEST1 ( SIGNED -- 1ST ) DUP 0< IF 2* 1- THEN ; OK SEE TEST1 : TEST1 ( SIGNED -- 1ST ) DUP 0< 0BRANCH 6 2* 1- ; OK
The tokens of LIT, DLIT and SLIT are handled in a special way. Instead of displaying the names of these tokens, SEE directly displays the assumed source code:
: TEST2 100699. 533 UM/MOD . DROP " EURO" TYPE ; OK SEE TEST2 : TEST2 ( -- ) 100699 533 UM/MOD . DROP " EURO" TYPE ; OK
Of course, this implementation of SEE leaves many opportunities for improvements. Inclusion of non colon definitions, recognising conditionals and loops, indenting according to nested control structures, and other things are possible. On the other hand, the availability of the original source code makes these efforts mostly obsolete.
Three words specified by ANS Forth are not implemented in strongForth. CS-PICK and CS-ROLL had to be left out for the same reason as PICK and ROLL: strongForth's data type system does not allow defining words with ambiguous stack diagrams at compile time. They are obsolete anyway, because strongForth does not need a separate control-flow stack. Items of data type CONTROL-FLOW, which are processed by conditionals and loop structures, are simply kept on the data stack.
The third word from the Programming-Tools word set that is not available in strongForth is FORGET. ANS Forth declares this word as obsolete, because it does not work reliably. It is actually specified for backward compatibility only. Its semantics is now covered by MARKER.
The implementations of [IF], [ELSE] and [THEN] are identical to those suggested in section A.15 of the ANS Forth specification. Some syntactical differences are caused by words that are not available in strongForth, like WORD, 2DUP, 2DROP and S".
EDITOR and ASSEMBLER are implemented as dummy words, because strongForth does not yet support the Search-Order word set.
The definition of ;CODE is quite similar to the definition of DOES>. Both create defining words, and both compile a separate runtime portion ((;CODE) and (DOES)). An example of how to use ;CODE is included in the documentation of the strongForth assembler.
Dr. Stephan Becher - December 13th, 2005