en:pfw:condicompi
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| en:pfw:condicompi [2023-09-04 18:11] – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | en:pfw:condicompi [2023-09-04 18:11] (current) – ↷ Seite von pfw:condicompi nach en:pfw:condicompi verschoben uho | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | {{pfw: | ||
| + | ====== Conditional Compilation ====== | ||
| + | |||
| + | Conditional compilation lets you selectively process program text depending on certain conditions. We look at different flavours. | ||
| + | |||
| + | ==== The ICE concept ==== | ||
| + | |||
| + | One of Forth strengths is its ICE (interpret, compile, execute) concept: You can | ||
| + | |||
| + | * **interpret** expressions while the program text is processed, | ||
| + | * **compile** function definitions (words) to capture actions for reuse, and | ||
| + | * **execute** these words with different parameters | ||
| + | |||
| + | within the same program text. | ||
| + | |||
| + | In Forth you can switch between I, C, E arbitrarily.\\ | ||
| + | While interpreting you can make a definition via '' | ||
| + | While compiling you can enclose program text to be interpreted (and executed) in '' | ||
| + | //Immediate words// are always executed regardless of whether forth is in compiler mode or not. | ||
| + | ==== [IF] [ELSE] [THEN] ==== | ||
| + | |||
| + | Standard Forth proposes to have the immediate words '' | ||
| + | |||
| + | <code forth> | ||
| + | «words to be processed» | ||
| + | «some sequence of words that puts a value on the stack» | ||
| + | [IF] | ||
| + | | ||
| + | [ELSE] | ||
| + | | ||
| + | [THEN] | ||
| + | «more words to be processed» | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | '' | ||
| + | |||
| + | One drawback of '' | ||
| + | |||
| + | Inside a definition: | ||
| + | |||
| + | <code forth> | ||
| + | : «someword» ( ... -- ... ) | ||
| + | [ «some sequence of words that puts a value on the stack» ] | ||
| + | [IF] | ||
| + | ... | ||
| + | [THEN] | ||
| + | ... | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | ==== Variant based conditional compilation ==== | ||
| + | |||
| + | In this programming pearl Albert Nijhof shows how to do conditional compilation, | ||
| + | |||
| + | The idea here is to have a convenient conditional compilation syntax that can distinguish given variants. A //variant// is a specific (named) configuration that the program should be adapted to, such as a specific kind of arithmetic it should use or the presence of certain features.\\ | ||
| + | Each variant is denoted by a single symbol most often a single letter. The conditions have the form of disjunctions ('' | ||
| + | |||
| + | Instead of | ||
| + | |||
| + | <code forth> | ||
| + | «some sequence of words that puts a non zero value on the stack | ||
| + | if variant A or variant C or variant F is selected» | ||
| + | [IF] | ||
| + | «words to be processed if that value is not zero» | ||
| + | [THEN] | ||
| + | </ | ||
| + | |||
| + | we would like to write | ||
| + | |||
| + | <code forth> | ||
| + | [IF ACF] | ||
| + | «words to be processed if variant is A or C or F» | ||
| + | [THEN] | ||
| + | </ | ||
| + | |||
| + | So what we need is to define a new immediate word **'' | ||
| + | |||
| + | Here is Albert' | ||
| + | |||
| + | <code forth> | ||
| + | 1 \ Conditional compilation -- an 03mar2022 | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | 10 until then nip | ||
| + | 11 postpone [IF] ; immediate | ||
| + | 12 \ ----- end ----- | ||
| + | 13 | ||
| + | </ | ||
| + | |||
| + | The currently selected variant to be processed is supposed to be stored in the Forth value '' | ||
| + | |||
| + | Line 7 parses the input stream up to the next space, i.e. just including the trailing '' | ||
| + | |||
| + | Lines 8-10 then look in loop wether or not the string contains the (symbol denoting the) current variant by inspecting the string one character after the other: '' | ||
| + | |||
| + | Line 9 then checks that character against the variant symbol. If it is found then the loop also stops. | ||
| + | |||
| + | Note, that the loop is quite uncommon. It is a '' | ||
| + | |||
| + | - exit when there are no more characters to be processed (the length became 0) and the variant symbol has not been encountered. | ||
| + | - exit when the current variant symbol is encountered (the length then is not equal to zero) before the end of the string. | ||
| + | |||
| + | The '' | ||
| + | |||
| + | So the length is appropriate as the condition value that can be passed to '' | ||
| + | |||
| + | As '' | ||
| + | |||
| + | That's it the ICE principle in action: A nice custom syntax that allows for a concise notation. | ||
| + | |||
| + | |||
| + | ---- | ||
| + | |||
| + | Albert' | ||
| + | |||
| + | <code forth> | ||
| + | (* | ||
| + | [IF A] -code- [THEN] | ||
| + | [IF AB] | ||
| + | [IF ACDE] -code- [THEN] | ||
| + | | ||
| + | You want to write a generic code | ||
| + | that differs only slightly in some variants. | ||
| + | Conditional compilation can be a solution. | ||
| + | Name each variant with a letter. | ||
| + | [IF reads the next " | ||
| + | *) | ||
| + | | ||
| + | \ ----- Test | ||
| + | char A to variant | ||
| + | [IF AC] 1 [ELSE] 0 [THEN] . | ||
| + | [IF CA] 1 [ELSE] 0 [THEN] . | ||
| + | [IF B] 1 [ELSE] 0 [THEN] . | ||
| + | [IF BCEFD] 1 [ELSE] 0 [THEN] . | ||
| + | [IF 13%A] 1 [ELSE] 0 [THEN] . | ||
| + | [IF ] 1 [ELSE] 0 [THEN] . | ||
| + | : test1 [IF BCEFD] 1 [ELSE] 0 [THEN] . ; | ||
| + | char C to variant | ||
| + | : test2 [IF BCEFD] 1 [ELSE] 0 [THEN] . ; | ||
| + | test1 | ||
| + | test2 | ||
| + | | ||
| + | (* | ||
| + | ----- Test results | ||
| + | char A to variant | ||
| + | [IF AC] 1 [ELSE] 0 [THEN] . 1 OK | ||
| + | [IF CA] 1 [ELSE] 0 [THEN] . 1 OK | ||
| + | [IF B] 1 [ELSE] 0 [THEN] . 0 OK | ||
| + | [IF BCEFD] 1 [ELSE] 0 [THEN] . 0 OK | ||
| + | [IF 13%A] 1 [ELSE] 0 [THEN] . 1 OK | ||
| + | [IF ] 1 [ELSE] 0 [THEN] . 0 OK | ||
| + | : test1 [IF BCEFD] 1 [ELSE] 0 [THEN] . ; OK | ||
| + | char C to variant | ||
| + | : test2 [IF BCEFD] 1 [ELSE] 0 [THEN] . ; OK | ||
| + | test1 0 OK | ||
| + | test2 1 OK | ||
| + | ( Have a look at SEE TEST1 and SEE TEST2 ) | ||
| + | | ||
| + | ----- noForth code (VALUE and BL-WORD) | ||
| + | value VARIANT | ||
| + | : [IF ( ccc] -- ) \ ccc is case-sensitive | ||
| + | bl-word dup c@ 1 max | ||
| + | begin 1 /string dup | ||
| + | while over c@ variant = | ||
| + | until then nip | ||
| + | postpone [IF] ; immediate | ||
| + | *) | ||
| + | \ <><> | ||
| + | </ | ||
| + | |||
| + | |||
| + | ---- | ||
| + | |||
| + | uh 2022-03-28 | ||
| + | |||
| + | ===== Contributions ===== | ||
| + | |||
| + | < | ||
| + | |||