Time for another boring programming entry, this time about a rather odd and cool trick Forth can do.
Forth, as you all doubtlessly know, isn't really like other languages. The "compiler" is part of the interpreter, and is almost more like a macro assembler than what we all think of as compilers.
A good example is the way control structures are compiled in Forth. Here's an example
: hello forth love if honk then ;
The colon turns on the compiler, creates a new word called "hello" and begins compiling calls to the words that follow. Some "magic" words are marked as being "IMMEDIATE", which means the compiler runs them instead of compiling them. The semicolon is one such word, and what it does is compile a RETURN statement and turn off the compiler. So the above Forth code winds up compiling to something like this:
[call forth] [call love] [pop eax | je %%][call honk]%%[return]
"IF" and "THEN" are also IMMEDIATE words. When IF runs, it codes a jump instruction and leaves a pointer to the "TO" address on the stack. "THEN" comes along and stores the current compile location in whatever address is on the stack. "ELSE" codes a jump, resolves the IF and leaves another address on the stack. In fact, you could write as many ELSE statements as you wanted, each one "leapfrogging" code, though I don't know any good uses for such a construct.
Now we get to the really crazy part. WHILE and other looping words work the same way, and can be mixed in with the IF/ELSE/THEN words in interesting ways. Here's a good example:
BEGIN
get-next-record
WHILE
is-this-the-right-record?
UNTIL
process-record
ELSE ( 'while' jumps to here if it fails )
report-out-of-records
THEN
Or in english (remember Forth reads "backwards")
While we can still get records,
loop until we get the right record and then process it
If we couldn't get another record, do something
No "break" or "continue" needed! Of course, it makes your brain hurt a little trying to understand the code, but all of Forth is that way, so it's ok. :-)
Of course you can write this code in other ways with lots of IF's and boolean variables, but once you wrap your brain around the flow of the above construct, it's very elegant. The only problem is I'm not sure how to indent it for best readability. :-)
forth