I have been using metacompilation to target compile Forth for Computer Cowboy's MuP21 and F21 chips. I have presented papers for FIG on these simple and straitforward traditional metacompilers that use search order, and a couple of vocabularies to control the metacompilation. (see `A Simple Meta Compiler' jfox 6/94)
The current P21Forth was compiled in DOS with X21D. The OK ver F.1.0 was assembled in the OK directory and copied to boot memory with the batch file X.BAT. See Appendix C. The P21 directory contains the X21D metacompiler, and source, the P21Forth source, and some batch files. MS.BAT creates the S21 simulator version of P21Forth. MC.BAT creates the version for the original development system with the PCMCIA card. MPCB.BAT creates the version for the new PCB ROM. These batch files start the X21D cross compiler in the appropriate mode. From there the use should type FLOAD FORTH.FOX and SAVE to compile the source and save the output to a file of P21 type. MC.BAT and MPCB.BAT will also prompt again for the name of the file to be copied to the PCMCIA card drive.
P21Forth contains the full ANS core, core extension, exception, double, double extension, search-order, search- order extension, facility, and tools word sets and more. With these tools the metacompiler I have been using to compile P21Forth from DOS would port easily, but instead I use a very simple technique to force the normal P21Forth compiler to produce a new P21Forth system from source.
To do this only a few words need to be changed. Certain immediate words like IF compile a reference to a runtime counterpart. In Forth IF compiles the primitive if to perform the conditional branch and leaves an address for ELSE or THEN to resolve later.
After the if primitive is compiled in a target metacompile the address of this if can be placed in the IF in Forth. This will cause IF to compile the correct address for the target and make it unusable for normal compilation. There are a few other words in the Forth compiler that need to be modified to that they can compile a reference to a primitive word in the target rather than compiling the address of the primitive word in Forth.
The definition of IF starts with : IF [ ` if ] LITERAL COMPILE, ... This means that the first cell in the compiled word IF will be DO: , and the second cell is lit and the third cell is the address of the if primitive. Thus ` IF 2 CELLS + would give the address of the cell containing the if primitive in the word IF.
The word IF appears in other words in the Forth source code 57 times before the word IF is defined in the Forth source. But as soon as the the primitive if is compiled in a new system the word IF in the system doing the compiling can be patched to make it into a metacompiling IF. This is done by ` if ` IF 2 CELLS + !. This will get the address of if in the target system since it is the most recent definintion of if and then patch that address into the word IF in the system doing the compilation. Thus the word IF has been changed into a metacompiling IF. It will correctly compile references to the target if in the target code until a new IF is definined in the target.
This can be factored into a single definition and used on each of the immediate words in the Forth compiler as the source code is compiled.
: PATCH ( -- ) ` ` 2 CELLS + ! ; \ use PATCH if IFPATCH needs to be used on certain words in the Forth compiler to transform these words into metacompiling words that compile references to target primitives.
When the new run time words are compiled in the target memory space these addresses are patched into the compiling words of Forth so that words like a target IF can be used before IF is compiled in the target. It is a way of passing control from one running version of Forth to a new running version with the minimal amount of bridge building. A few commands added to the Forth source transform the normal compiler into a metacompiler on the fly. Then the compiling system is cut loose and the new running Forth is booted.
\ MINIMAL FORTH METACOMPILER copyright Jeff Fox 10/7/94 \ PATCH ( -
- ) \ get the address of name1 in target \ PATCH the literal # cell in the host word name2 \ place PATCH after the defintion of the TARGET name1 : PATCH ( - - ) ' ' 2+ ! ; \ 2 CELLS + for dtc (do: lit 'name) PATCH EXIT ; \ ; used 138 times \ before it is defined in target PATCH do: :NONAME \ : used 137 times PATCH lit LITERAL \ LITERAL used 25 times PATCH if IF \ IF used 57 times PATCH if UNTIL \ UNTIL used 10 times PATCH else AGAIN \ AGAIN used 1 time PATCH abort" ABORT" \ ABORT" used 3 times PATCH d" ." \ ." used 3 times Jeff Fox 10/13/94
Return to Table of Contents