1 \ Listing in "Towards a Discipline of ANS Forth Programming"
\r
2 \ Originally published in Forth Dimensions XVIII, No.4, pp5-14
\r
3 \ Adapted to hForth v0.9.9 by Wonyong Koh
\r
4 \ An ANS compliance problem in v0.9.7 is fixed now.
\r
5 \ 'dest+' should not be necessary.
\r
7 \ Dijkstra Guarded Command Control Structures
\r
11 \ Environmental dependencies:
\r
13 \ Requires AGAIN from the CORE EXT word set
\r
14 \ Requires AHEAD from the TOOLS EXT word set
\r
15 \ Requires CS-PICK from the TOOLS EXT word set
\r
16 \ Requires CS-ROLL from the TOOLS EXT word set
\r
17 \ Requires PICK from the CORE EXT word set
\r
18 \ Requires ROLL from the CORE EXT word set
\r
19 \ Requires THROW from the EXCEPTION word set
\r
20 \ Requires hForth word COMPILE-ONLY or equivalent
\r
21 \ Requires .( from CORE EXT word set (test sequence only)
\r
23 \ hForth has the capability to flag a word COMPILE-ONLY. On
\r
24 \ other systems, COMPILE-ONLY can be ignored by defining it as
\r
27 BL WORD COMPILE-ONLY FIND NIP 0= [IF]
\r
31 : {IF \ start a conditional
\r
34 0 \ put counter on stack
\r
35 ; COMPILE-ONLY IMMEDIATE
\r
37 : IF> \ right-arrow for {IF ... FI}
\r
38 ( count -- count+1 )
\r
41 1+ >R \ increment and save count
\r
42 POSTPONE IF \ create orig1
\r
44 ; COMPILE-ONLY IMMEDIATE
\r
46 : |IF| \ bar for {IF ... FI}
\r
48 ( C: orig ... orig1 -- orig ... orig2 )
\r
51 POSTPONE AHEAD \ new orig
\r
52 1 CS-ROLL \ old orig to top of CFStack
\r
53 POSTPONE THEN \ resolve old orig
\r
55 ; COMPILE-ONLY IMMEDIATE
\r
57 : BAD{IF...FI} \ abort if there is no TRUE condition
\r
60 CR ." {IF ... FI}: no TRUE condition" CR \ error message
\r
61 -22 THROW \ 'control structure mismatch'
\r
64 : FI} \ end of conditional
\r
66 ( C: orig1 ... orign -- )
\r
69 POSTPONE AHEAD \ new orig
\r
70 1 CS-ROLL \ old orig
\r
71 POSTPONE THEN \ resolve old orig
\r
73 \ if we got here, none of the guards were TRUE
\r
75 POSTPONE BAD{IF...FI} \ compile the abort
\r
78 0 ?DO \ resolve all remaining origs
\r
81 ; COMPILE-ONLY IMMEDIATE
\r
83 : {DO \ start a loop
\r
86 POSTPONE BEGIN \ create dest
\r
87 ; COMPILE-ONLY IMMEDIATE
\r
89 : DO> \ right arrow for {DO ... OD}
\r
90 ( C: dest -- orig1 dest )
\r
92 POSTPONE IF \ create orig
\r
93 1 CS-ROLL \ bring dest back to top of CFStack
\r
94 ; COMPILE-ONLY IMMEDIATE
\r
96 : |DO| \ bar for {DO ... OD}
\r
97 ( C: orig1 dest -- dest )
\r
99 0 CS-PICK \ copy the dest
\r
100 POSTPONE AGAIN \ resolve the copy
\r
101 1 CS-ROLL \ old orig
\r
102 POSTPONE THEN \ resolve old orig
\r
103 ; COMPILE-ONLY IMMEDIATE
\r
105 : OD} \ end of loop
\r
106 ( C: orig dest -- )
\r
107 POSTPONE AGAIN \ resolve dest
\r
108 POSTPONE THEN \ resolve orig
\r
109 ; COMPILE-ONLY IMMEDIATE
\r
112 \ Simple test words
\r
114 : TEST1 \ print the relationship between 'x' and 'y'
\r
118 2DUP = IF> CR ." = "
\r
120 2DUP > IF> CR ." > "
\r
122 2DUP < IF> CR ." < "
\r
127 \ execute TEST1 for all three combinations
\r
138 : TEST2 \ deliberately erroneous test case --
\r
139 \ 'equal' case left out!
\r
143 2DUP < IF> CR ." < "
\r
145 2DUP > IF> CR ." > "
\r
150 CR .( Since TEST2 aborts if 'x' and 'y' are equal, we will )
\r
151 CR .( test TEST2 later; first we will compile and test USEFUL )
\r
154 VARIABLE x 5 6553 * x !
\r
155 VARIABLE y 6551 5 * y !
\r
157 : USEFUL \ sets both 'x' and 'y' to GCD(x, y)
\r
161 x @ y @ > DO> y @ NEGATE x +!
\r
163 y @ x @ > DO> x @ NEGATE y +!
\r
167 CR .( Before: x, y = ) x @ . y @ . CR
\r
168 CR .( USEFUL ) USEFUL
\r
169 CR .( After: x, y = ) x @ . y @ . CR
\r
171 CR .( Now we'll test TEST2 )
\r