In which I learn how to regain control.
In Forth
http://beza1e1.tuxen.de/articles/forth.htmlif
,while
, and similar control flow constructs are not builtin but implemented. Implement them in your Forth.
Let’s start with IF ... ELSE ... THEN
. This construct doesn’t have a run time primitive word (or words). Instead it compiles as follows:
cond IF
conditional-words THEN
trailing-words
becomes
cond 0 = BRANCH?
conditional-words trailing-words
In the above <trailing-words>
is the relative offset of *trailing-words*. The 0 =
logically inverts the original condition.
cond IF
conditional-words ELSE
else-words THEN
trailing-words
becomes
cond 0 = BRANCH?
conditional-words BRANCH
else-words trailing-words
The problem is that we can’t put in the offset for the branch at the point where we encounter the IF
because we don’t know how far along the ELSE
or THEN
will be. Instead we’ll put in a placeholder to be filled in with the offset later. When we get to the THEN
or the ELSE
we need to know where the placeholder was so we can go back and put it in. For an ELSE
we then have to repeat the process for the THEN
.
It as to be possible to nest control structures, so the natural way to implement this is through a stack called the control-flow stack. You can fold the control flow stack into the data stack as gforth does, but I am going to keep it separate for now on the grounds that my data stack only holds integers and we will need two types of value: dest for backward jumps (e.g. a loop) and orig for forward jumps (THEN
and ELSE
).
The code for IF
… ELSE
… THEN
is tagged blog-1070-1
It has not escaped my notice that I now have a failing unit test. Because I tightened up the conditions for executing in interpreting mode and executing in compile mode, comments no longer work in interpreting mode. I was going to continue this blog by discussing loops, but that is going to have to go by the wayside while I refactor compilation and interpreting semantics.