1 The FORTH challenge
What is Forth? - Forth is a pretty old programming language! As we all know, programming languages just get better directly proportional to wine. That’s why I recently started to learn Forth. However, the so-far learning experience had no taste of my favorite wine in it, it rather made me whine and cry. That’s to some extent due to Forth’s basic strangeness as it’s a stack-based, concatenative language but the lack of detailed explanations in my learning resources have played quite a role, too. Just recently I have discovered Starting Forth which is a nice online Forth introduction. It helped me a lot to understand Forth’s fundamental words of POSTPONE, IMMEDIATE and LITERAL which are used in Forth’s “grey” area of compilation vs. interpretation semantics. Starting Forth should be your choice if you want to study Forth. Anyway, flashed with my new Forth knowledge I decided to collect my findings on those exciting words for my fellow to-be-born Forth comrades so that they may find their way to Forth illumination earlier than I did; this is my legacy for you!
You can use IMMEDIATE to change the compilation semantics of the last defined word to be equal to the interpretation semantics. In the below example that means that
[FOO] already is executed upon
: [FOO] ( -- ) 5 . ; immediate [FOO] : bar ( -- ) [FOO] ; bar see bar
1.2 : ; [ and ]
: switches into compile state and ; switches back to interpret state. They contain the factors ] (switch to compile state) and [ (switch to interpret state), that do nothing but switch the state.
: xxx ( -- ) [ 5 . ] ; xxx see xxx
It is worth mentioning that ; expects the data stack to be empty, usually. Otherwise an “unstructured” exception gets thrown.
POSTPONE has different effects. Either it gets called on an immediate word or on a word which isn’t immediate.
1.3.1 POSTPONE and immediate words
That’s the easy case. Called on an immediate word POSTPONE just undos the “immediate nature” of that word.
: SAY-HELLO ." Hello" ; IMMEDIATE : GREET1 SAY-HELLO ." I speak Forth " ; \ upon compilation "Hello" is printed : GREET2 POSTPONE SAY-HELLO ." I speak Forth " ; \ nothing is printed upon compilation. On execution both strings are printed.
1.3.2 POSTPONE and not so immediate words
POSTPONE finds the address of the next word in the definition (in the below case it is
x) and compiles its address into the compilee (
: x + ; : y postpone x ; immediate see y \ : y 140635553271192 compile, ; immediate ok : z ( n1 n2 -- n3 ) y ; 8 3 z .
In the definition of
y POSTPONE is called on
x which is a non- immediate-word. As a result, the address of
+ and the word “compile,” are compiled into y. I made
y immediate so that during the definition of
z y gets executed immediately so that “140635553271192 compile,” is run, which compiles the addition function into
LITERAL is an immediate word. During the compilation of a word
x its effect consists of consuming a number from the stack; when
x is run LITERAL then pushes that number onto the stack.
#FUN-FACT: The runtime part of literal (its word is (LITERAL)) is often used without really knowing. In the following example
bla just pushes 5 onto the stack - what gets compiled into bla behind the scenes is the “run-time code for LITERAL" (the mentioned (LITERAL)) and just then the number itself.
: bla 5 ;
Have a look at the definition of LITERAL. It compiles the address of the run-time pushing code with POSTPONE and then compiles a number with “,”. Consequently, a resulting compilee’s compiled code just pushes that number onto the stack.
: LITERAL POSTPONE (LITERAL) , ; IMMEDIATE \ Gforth does not know (LITERAL)
1.5 Case Study - IMMEDIATE, POSTPONE and LITERAL in the wild
: x 5 ; immediate : y x ; \ unstructured! \ Using POSTPONE : y postpone x ; \ Using LITERAL : y x literal ;
: y x ; we get an exception since the word ; finds 5 on the data stack, the stack should be empty, though. There are two ways how to solve our problem.
Using POSTPONE: With POSTPONE we can easily undo the immediate effect of
x. As a result,
x gets compiled into
y like a “normal” word.
Using LITERAL: Knowing that
x pushes a number onto the stack we take that number and compile it into
y. You wanna do that? Then LITERAL is your man!