Previous: Literals, Up: Compiling words
Literal and friends compile data values into the current
definition. You can also write words that compile other words into the
current definition. E.g.,
: compile-+ ( -- ) \ compiled code: ( n1 n2 -- n ) POSTPONE + ; : foo ( n1 n2 -- n ) [ compile-+ ] ; 1 2 foo .
This is equivalent to
: foo + ; (
see foo to check this).
What happens in this example?
Postpone compiles the compilation
compile-+; later the text interpreter
compile-+ and thus the compilation semantics of +, which
compile (the execution semantics of)
postpone"name" – core “postpone”
Compiles the compilation semantics of name.
[compile]compilation "name" – ; run-time ? – ? core-ext “bracket-compile”
Compiling words like
compile-+ are usually immediate (or similar)
so you do not have to switch to interpret state to execute them;
mopifying the last example accordingly produces:
: [compile-+] ( compilation: --; interpretation: -- ) \ compiled code: ( n1 n2 -- n ) POSTPONE + ; immediate : foo ( n1 n2 -- n ) [compile-+] ; 1 2 foo .
Immediate compiling words are similar to macros in other languages (in particular, Lisp). The important differences to macros in, e.g., C are:
postponeetc. deal with the language at a higher level than strings; name binding happens at macro definition time, so you can avoid the pitfalls of name collisions that can happen in C macros. Of course, Forth is a liberal language and also allows to shoot yourself in the foot with text-interpreted macros like
: [compile-+] s" +" evaluate ; immediate
Apart from binding the name at macro use time, using
also makes your definition
state-smart (see state-smartness).
You may want the macro to compile a number into a word. The word to do
literal, but you have to
postpone it, so its
compilation semantics take effect when the macro is executed, not when
it is compiled:
: [compile-5] ( -- ) \ compiled code: ( -- n ) 5 POSTPONE literal ; immediate : foo [compile-5] ; foo .
You may want to pass parameters to a macro, that the macro should
compile into the current definition. If the parameter is a number, then
you can use
postpone literal (similar for other values).
If you want to pass a word that is to be compiled, the usual way is to
pass an execution token and
: twice1 ( xt -- ) \ compiled code: ... -- ... dup compile, compile, ; : 2+ ( n1 -- n2 ) [ ' 1+ twice1 ] ;
compile,xt – core-ext “compile-comma”
Compile the word represented by the execution token xt into the current definition.
An alternative available in Gforth, that allows you to pass compile-only words as parameters is to use the compilation token (see Compilation token). The same example in this technique:
: twice ( ... ct -- ... ) \ compiled code: ... -- ... 2dup 2>r execute 2r> execute ; : 2+ ( n1 -- n2 ) [ comp' 1+ twice ] ;
In the example above
2r> ensure that
works even if the executed compilation semantics has an effect on the
You can also define complete definitions with these words; this provides
an alternative to using
does> (see User-defined Defining Words). E.g., instead of
: curry+ ( n1 "name" -- ) CREATE , DOES> ( n2 -- n1+n2 ) @ + ;
you could define
: curry+ ( n1 "name" -- ) \ name execution: ( n2 -- n1+n2 ) >r : r> POSTPONE literal POSTPONE + POSTPONE ; ; -3 curry+ 3- see 3-
>r : r> is necessary, because
: puts a
colon-sys on the data stack that makes everything below it unaccessible.
This way of writing defining words is sometimes more, sometimes less
convenient than using
does> (see Advanced does> usage example). One advantage of this method is that it can be optimized
better, because the compiler knows that the value compiled with
literal is fixed, whereas the data associated with a
created word can be changed.
 A recent RFI answer requires that compiling words should only be executed in compile state, so this example is not guaranteed to work on all standard systems, but on any decent system it will work.