Software that runs in several system environments often contains some source code that is environmentally dependent. Conditional compilation - the selective inclusion or exclusion of portions of the source code at compile time - is one technique that is often used to assist in the maintenance of such source code.
Conditional compilation is sometimes done with smart comments - definitions that either skip or do not skip the remainder of the line based on some test. For example:
If 16-Bit? contains TRUE, lines preceded by 16BIT\ will be skipped. Otherwise, they will not be skipped.
ram_variable 16-BIT? : 16BIT\ ( -- ) 16-BIT? @ IF POSTPONE \ THEN ; IMMEDIATE
This technique works on a line by line basis, and is good for short, isolated variant code sequences.
More complicated conditional compilation problems suggest a nestable method that can encompass more than one source line at a time. The words included in the ANS Forth optional Programming tools extensions word set are useful for this purpose.
Compilation: Perform the execution semantics given below.
Execution: ( "< spaces >name" ... -- )
Skipping leading spaces, parse and discard space-delimited words from the parse area, including nested occurrences of [IF] ... [THEN] and [IF] ... [ELSE] ... [THEN], until the word [THEN] has been parsed and discarded. If the parse area becomes exhausted, it is refilled as with REFILL. [ELSE] is an immediate word.
Typical use: ... flag [IF] ... [ELSE] ... [THEN] ...
: [ELSE] ( -- )
1 BEGIN \ level(--
BEGIN
BL (word) DUP
WHILE \ level adr len(--
2DUP S" [IF]" COMPARE 0=
IF \ level adr len(--
2DROP 1+ \ level'(--
ELSE \ level adr len(--
2DUP S" [ELSE]"
COMPARE 0= IF \ level adr len(--
2DROP 1- DUP IF
1+
THEN \ level'
ELSE \ level adr len(--
S" [THEN]" COMPARE 0= IF \ level(--
1- \ level'(--
THEN
THEN
THEN ?DUP 0= IF
EXIT
THEN \ level'(--
REPEAT 2DROP \ level(--
REFILL 0= UNTIL \ level(--
DROP
; IMMEDIATE
Compilation: Perform the execution semantics given below.
Execution: ( flag | flag "< spaces >name" ... -- )
If flag is true, do nothing. Otherwise, skipping leading spaces, parse and discard space-delimited words from the parse area, including nested occurrences of [IF] ... [THEN] and [IF] ... [ELSE] ... [THEN], until either the word [ELSE] or the word [THEN] has been parsed and discarded. If the parse area becomes exhausted, it is refilled as with REFILL. [IF] is an immediate word.
An ambiguous condition exists if [IF] is POSTPONEd, or if the end of the input buffer is reached and cannot be refilled before the terminating [ELSE] or [THEN] is parsed.
Typical use: ... flag [IF] ... [ELSE] ... [THEN] ...
: [IF] ( flag -- )
0= IF [COMPILE] [ELSE] THEN
; IMMEDIATE
Compilation: Perform the execution semantics given below.
Execution: ( -- )
Does nothing. [THEN] is an immediate word.
Typical use: ... flag [IF] ... [ELSE] ... [THEN] ...
: [THEN]
; IMMEDIATE