Meta Programming
gbforth is a Forth cross-compiler. It runs on your computer (the host system) while it will generate a program that will be executed on a Game Boy (the target system).
This imposes some restrictions compared to other Forth environments.
The most fundamental limitation is that you cannot interpret code that is intended to be executed on the target. For instance, the following code will not work:
: square dup * ;
\ We can't run SQUARE on the host!
: f [ 10 square ]L ;
However, you are still able to get the execution token (XT) of a word by using
'
as follows:
: square dup * ;
\ Push the target address of SQUARE to the stack
' square
We can characterize code based on 2 criteria:
- When the code is executed (compile-time or run-time)
- Where it acts on (host system or target system)
Since it does not make sense for a computation in the target system to act on the host system, we are left with 3 meaningful combinations:
- Colon definitions execute at run-time, act on the target system
- Top-level code executes at compile-time, acts on the target system
- Host definitions execute at compile-time, act on the host system
Colon definitions
when: run-time, where: target system
This is the most common kind of code that you will write. It executes on the target and allows you to read/write variables, display to screen and all you would like to do with your device.
: foo
%11100100 $FF47 ! ;
The words in the definition of foo
would execute at run-time, storing a
value to an address on the target.
gbforth does not provide a run-time Forth system, so for example, you can’t
create new words (CREATE
), and you can’t read words from the input stream
(PARSE
). You can, however, switch to interpreter mode (using [
and ]
) and
do those things at compile-time.
Top-level code and interpretation
when: compile-time, where: target system
In this mode, you can run words like CREATE
, CONSTANT
, VARIABLE
and other
defining and parsing Forth words.
CREATE bar 2 cells allot
In this code, CREATE
is executed during the compilation of the program.
Likewise, 2 cells allot
will allocate 2 cells on the target system memory.
Meta colon definitions
As described above, the word :
switches to colon definition / compilation mode
for code that is meant to be executed on the target system.
However, that introduces a challenge. Sometimes we want to build new
abstractions on top of interpreting words. To do that, we can use the word :m
,
which allows us to create a word that can be executed on the host, but will
still act on target structures.
For example, we can define this enumerations facility like:
:m begin-enum 0 ;
:m enum 1+ dup constant ;
:m end-enum drop ;
This code, unlike ordinary colon definitions, can be executed in interpreter mode, so we can use it like:
begin-enum
enum DARKER
enum DARK
enum LIGHT
enum LIGHTER
end-enum
This mode is intended to be as intuitive as possible, but it still imposes some
important limitations. For example, you cannot allocate memory in the host
system, as the words allot
, here
and so on act on the target data
structures.
To use even more advanced scenarios, you will want to switch to host definitions.
Host definitions
when: compile-time, where: host system
Sometimes you’ll want to write code that is executed on the host system, and operates on data in the host as well.
That is useful in advanced scenarios where, for example, you would like to allocate some memory for some compile-time computations, but that data does not need to be available at run-time at all.
Summary
Context | Execution | Data |
---|---|---|
Colon definition : |
Run-time (target) | Target (ROM / RAM) |
Top-level | Compile-time (host) | Target (ROM) |
[host] |
Compile-time (host) | Host |