In compile mode, Forth parses a line word by word, so in compile mode this would work this way with a given word:
Search the word in the dictionary (for example print) if found, is it immediate ? yes: execute it, no: compile a call to it. if not found, is it a number ? yes: compile a literal with that value, no: give an error. The statement ?if? is an immediate word, so it will be executed while compiling. The execution semantics compiles a conditional jump to an unresolved address. This address will resolved as soon as then or else occurs. That means that ?then? is also immediate, takes the address to the last unresolved address (from the data stack, pushed while executed the if statement) and stores the current code-address there (or an offset for relative jumps).
Since print is not an immediate word a call to print would be compiled.
With this method one could make a simple interactive machine code generating a Forth compiler for any target in some days. Some other days to implement some optimizing rules like peep hole and literal folding and code inlining.
Much fun in implementing your own compiler :-)
=== EDIT ===
I have made a small course which explains the implementation of a FORTH virtual machine in C: Implementing a FORTH virtual machine