[gforth] / gforth / kernel / cond.fs  

gforth: gforth/kernel/cond.fs


1 : anton 1.1 \ Structural Conditionals 12dec92py
2 :    
3 : anton 1.26 \ Copyright (C) 1995,1996,1997,2000,2003,2004,2007,2010,2011 Free Software Foundation, Inc.
4 : anton 1.1
5 :     \ This file is part of Gforth.
6 :    
7 :     \ Gforth is free software; you can redistribute it and/or
8 :     \ modify it under the terms of the GNU General Public License
9 : anton 1.22 \ as published by the Free Software Foundation, either version 3
10 : anton 1.1 \ of the License, or (at your option) any later version.
11 :    
12 :     \ This program is distributed in the hope that it will be useful,
13 :     \ but WITHOUT ANY WARRANTY; without even the implied warranty of
14 :     \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 :     \ GNU General Public License for more details.
16 :    
17 :     \ You should have received a copy of the GNU General Public License
18 : anton 1.22 \ along with this program. If not, see http://www.gnu.org/licenses/.
19 : anton 1.1
20 :     here 0 , \ just a dummy, the real value of locals-list is patched into it in glocals.fs
21 :     AConstant locals-list \ acts like a variable that contains
22 :     \ a linear list of locals names
23 :    
24 :    
25 :     variable dead-code \ true if normal code at "here" would be dead
26 :     variable backedge-locals
27 :     \ contains the locals list that BEGIN will assume to be live on
28 :     \ the back edge if the BEGIN is unreachable from above. Set by
29 :     \ ASSUME-LIVE, reset by UNREACHABLE.
30 :    
31 :     : UNREACHABLE ( -- ) \ gforth
32 :     \ declares the current point of execution as unreachable
33 :     dead-code on
34 :     0 backedge-locals ! ; immediate
35 :    
36 :     : ASSUME-LIVE ( orig -- orig ) \ gforth
37 :     \ used immediatly before a BEGIN that is not reachable from
38 :     \ above. causes the BEGIN to assume that the same locals are live
39 :     \ as at the orig point
40 :     dup orig?
41 :     2 pick backedge-locals ! ; immediate
42 :    
43 :     \ Control Flow Stack
44 :     \ orig, etc. have the following structure:
45 :     \ type ( defstart, live-orig, dead-orig, dest, do-dest, scopestart) ( TOS )
46 :     \ address (of the branch or the instruction to be branched to) (second)
47 :     \ locals-list (valid at address) (third)
48 :    
49 :     \ types
50 : jwilke 1.6 [IFUNDEF] defstart
51 :     0 constant defstart \ usally defined in comp.fs
52 :     [THEN]
53 : anton 1.1 1 constant live-orig
54 :     2 constant dead-orig
55 :     3 constant dest \ the loopback branch is always assumed live
56 :     4 constant do-dest
57 :     5 constant scopestart
58 :    
59 :     : def? ( n -- )
60 :     defstart <> abort" unstructured " ;
61 :    
62 :     : orig? ( n -- )
63 :     dup live-orig <> swap dead-orig <> and abort" expected orig " ;
64 :    
65 :     : dest? ( n -- )
66 :     dest <> abort" expected dest " ;
67 :    
68 :     : do-dest? ( n -- )
69 :     do-dest <> abort" expected do-dest " ;
70 :    
71 :     : scope? ( n -- )
72 :     scopestart <> abort" expected scope " ;
73 :    
74 :     : non-orig? ( n -- )
75 :     dest scopestart 1+ within 0= abort" expected dest, do-dest or scope" ;
76 :    
77 :     : cs-item? ( n -- )
78 :     live-orig scopestart 1+ within 0= abort" expected control flow stack item" ;
79 :    
80 :     3 constant cs-item-size
81 :    
82 : crook 1.7 : CS-PICK ( ... u -- ... destu ) \ tools-ext c-s-pick
83 : anton 1.1 1+ cs-item-size * 1- >r
84 :     r@ pick r@ pick r@ pick
85 :     rdrop
86 :     dup non-orig? ;
87 :    
88 : crook 1.7 : CS-ROLL ( destu/origu .. dest0/orig0 u -- .. dest0/orig0 destu/origu ) \ tools-ext c-s-roll
89 : anton 1.1 1+ cs-item-size * 1- >r
90 :     r@ roll r@ roll r@ roll
91 :     rdrop
92 :     dup cs-item? ;
93 :    
94 : anton 1.25 : CS-DROP ( dest -- ) \ gforth
95 :     dest? 2drop ;
96 :    
97 : anton 1.1 : cs-push-part ( -- list addr )
98 : pazsan 1.3 locals-list @ here ;
99 : anton 1.1
100 :     : cs-push-orig ( -- orig )
101 :     cs-push-part dead-code @
102 :     if
103 :     dead-orig
104 :     else
105 :     live-orig
106 :     then ;
107 :    
108 :     \ Structural Conditionals 12dec92py
109 :    
110 : anton 1.18 defer other-control-flow ( -- )
111 :     \ hook for control-flow stuff that's not handled by begin-like etc.
112 :    
113 : anton 1.1 : ?struc ( flag -- ) abort" unstructured " ;
114 :     : sys? ( sys -- ) dup 0= ?struc ;
115 :     : >mark ( -- orig )
116 : anton 1.18 cs-push-orig 0 , other-control-flow ;
117 : anton 1.11 : >resolve ( addr -- )
118 : anton 1.13 here swap !
119 : anton 1.12 basic-block-end ;
120 : anton 1.13 : <resolve ( addr -- ) , ;
121 : anton 1.1
122 :     : BUT
123 :     1 cs-roll ; immediate restrict
124 :     : YET
125 :     0 cs-pick ; immediate restrict
126 :    
127 :     \ Structural Conditionals 12dec92py
128 :    
129 :     : AHEAD ( compilation -- orig ; run-time -- ) \ tools-ext
130 : pazsan 1.14 POSTPONE branch >mark POSTPONE unreachable ; immediate restrict
131 : anton 1.1
132 :     : IF ( compilation -- orig ; run-time f -- ) \ core
133 : pazsan 1.14 POSTPONE ?branch >mark ; immediate restrict
134 : anton 1.1
135 :     : ?DUP-IF ( compilation -- orig ; run-time n -- n| ) \ gforth question-dupe-if
136 : crook 1.5 \G This is the preferred alternative to the idiom "@code{?DUP IF}", since it can be
137 : anton 1.1 \G better handled by tools like stack checkers. Besides, it's faster.
138 : pazsan 1.14 POSTPONE ?dup-?branch >mark ; immediate restrict
139 : anton 1.1
140 :     : ?DUP-0=-IF ( compilation -- orig ; run-time n -- n| ) \ gforth question-dupe-zero-equals-if
141 : pazsan 1.14 POSTPONE ?dup-0=-?branch >mark ; immediate restrict
142 : anton 1.1
143 :     Defer then-like ( orig -- )
144 :     : cs>addr ( orig/dest -- ) drop >resolve drop ;
145 :     ' cs>addr IS then-like
146 :    
147 :     : THEN ( compilation orig -- ; run-time -- ) \ core
148 :     dup orig? then-like ; immediate restrict
149 :    
150 :     ' THEN alias ENDIF ( compilation orig -- ; run-time -- ) \ gforth
151 :     immediate restrict
152 :     \ Same as "THEN". This is what you use if your program will be seen by
153 :     \ people who have not been brought up with Forth (or who have been
154 :     \ brought up with fig-Forth).
155 :    
156 : anton 1.20 : ELSE ( compilation orig1 -- orig2 ; run-time -- ) \ core
157 : anton 1.1 POSTPONE ahead
158 :     1 cs-roll
159 :     POSTPONE then ; immediate restrict
160 :    
161 :     Defer begin-like ( -- )
162 :     ' noop IS begin-like
163 :    
164 :     : BEGIN ( compilation -- dest ; run-time -- ) \ core
165 : anton 1.11 begin-like cs-push-part dest
166 : anton 1.12 basic-block-end ; immediate restrict
167 : anton 1.1
168 :     Defer again-like ( dest -- addr )
169 :     ' nip IS again-like
170 :    
171 :     : AGAIN ( compilation dest -- ; run-time -- ) \ core-ext
172 : pazsan 1.14 dest? again-like POSTPONE branch <resolve ; immediate restrict
173 : anton 1.1
174 : anton 1.8 Defer until-like ( list addr xt1 xt2 -- )
175 :     :noname ( list addr xt1 xt2 -- )
176 :     drop compile, <resolve drop ;
177 :     IS until-like
178 : anton 1.1
179 :     : UNTIL ( compilation dest -- ; run-time f -- ) \ core
180 : pazsan 1.14 dest? ['] ?branch ['] ?branch-lp+!# until-like ; immediate restrict
181 : anton 1.1
182 :     : WHILE ( compilation dest -- orig dest ; run-time f -- ) \ core
183 :     POSTPONE if
184 :     1 cs-roll ; immediate restrict
185 :    
186 :     : REPEAT ( compilation orig dest -- ; run-time -- ) \ core
187 :     POSTPONE again
188 :     POSTPONE then ; immediate restrict
189 :    
190 :     \ counted loops
191 :    
192 :     \ leave poses a little problem here
193 :     \ we have to store more than just the address of the branch, so the
194 :     \ traditional linked list approach is no longer viable.
195 :     \ This is solved by storing the information about the leavings in a
196 :     \ special stack.
197 :    
198 :     \ !! remove the fixed size limit. 'Tis not hard.
199 :     20 constant leave-stack-size
200 :     create leave-stack 60 cells allot
201 :     Avariable leave-sp leave-stack 3 cells + leave-sp !
202 :    
203 :     : clear-leave-stack ( -- )
204 :     leave-stack leave-sp ! ;
205 :    
206 :     \ : leave-empty? ( -- f )
207 :     \ leave-sp @ leave-stack = ;
208 :    
209 :     : >leave ( orig -- )
210 :     \ push on leave-stack
211 :     leave-sp @
212 :     dup [ leave-stack 60 cells + ] Aliteral
213 :     >= abort" leave-stack full"
214 :     tuck ! cell+
215 :     tuck ! cell+
216 :     tuck ! cell+
217 :     leave-sp ! ;
218 :    
219 :     : leave> ( -- orig )
220 :     \ pop from leave-stack
221 :     leave-sp @
222 :     dup leave-stack <= IF
223 :     drop 0 0 0 EXIT THEN
224 :     cell - dup @ swap
225 :     cell - dup @ swap
226 :     cell - dup @ swap
227 :     leave-sp ! ;
228 :    
229 :     : DONE ( compilation orig -- ; run-time -- ) \ gforth
230 : pazsan 1.23 \g resolves all LEAVEs up to the compilaton orig (from a BEGIN)
231 : anton 1.1 drop >r drop
232 :     begin
233 :     leave>
234 :     over r@ u>=
235 :     while
236 :     POSTPONE then
237 :     repeat
238 :     >leave rdrop ; immediate restrict
239 :    
240 :     : LEAVE ( compilation -- ; run-time loop-sys -- ) \ core
241 :     POSTPONE ahead
242 :     >leave ; immediate restrict
243 :    
244 :     : ?LEAVE ( compilation -- ; run-time f | f loop-sys -- ) \ gforth question-leave
245 :     POSTPONE 0= POSTPONE if
246 :     >leave ; immediate restrict
247 :    
248 :     : DO ( compilation -- do-sys ; run-time w1 w2 -- loop-sys ) \ core
249 :     POSTPONE (do)
250 :     POSTPONE begin drop do-dest
251 :     ( 0 0 0 >leave ) ; immediate restrict
252 :    
253 :     : ?do-like ( -- do-sys )
254 :     ( 0 0 0 >leave )
255 :     >mark >leave
256 :     POSTPONE begin drop do-dest ;
257 :    
258 :     : ?DO ( compilation -- do-sys ; run-time w1 w2 -- | loop-sys ) \ core-ext question-do
259 : pazsan 1.14 POSTPONE (?do) ?do-like ; immediate restrict
260 : anton 1.1
261 :     : +DO ( compilation -- do-sys ; run-time n1 n2 -- | loop-sys ) \ gforth plus-do
262 : pazsan 1.14 POSTPONE (+do) ?do-like ; immediate restrict
263 : anton 1.1
264 :     : U+DO ( compilation -- do-sys ; run-time u1 u2 -- | loop-sys ) \ gforth u-plus-do
265 : pazsan 1.14 POSTPONE (u+do) ?do-like ; immediate restrict
266 : anton 1.1
267 :     : -DO ( compilation -- do-sys ; run-time n1 n2 -- | loop-sys ) \ gforth minus-do
268 : pazsan 1.14 POSTPONE (-do) ?do-like ; immediate restrict
269 : anton 1.1
270 :     : U-DO ( compilation -- do-sys ; run-time u1 u2 -- | loop-sys ) \ gforth u-minus-do
271 : pazsan 1.14 POSTPONE (u-do) ?do-like ; immediate restrict
272 : anton 1.1
273 :     : FOR ( compilation -- do-sys ; run-time u -- loop-sys ) \ gforth
274 :     POSTPONE (for)
275 :     POSTPONE begin drop do-dest
276 :     ( 0 0 0 >leave ) ; immediate restrict
277 :    
278 :     \ LOOP etc. are just like UNTIL
279 :    
280 :     : loop-like ( do-sys xt1 xt2 -- )
281 :     >r >r 0 cs-pick swap cell - swap 1 cs-roll r> r> rot do-dest?
282 :     until-like POSTPONE done POSTPONE unloop ;
283 :    
284 :     : LOOP ( compilation do-sys -- ; run-time loop-sys1 -- | loop-sys2 ) \ core
285 : pazsan 1.14 ['] (loop) ['] (loop)-lp+!# loop-like ; immediate restrict
286 : anton 1.1
287 :     : +LOOP ( compilation do-sys -- ; run-time loop-sys1 n -- | loop-sys2 ) \ core plus-loop
288 : pazsan 1.14 ['] (+loop) ['] (+loop)-lp+!# loop-like ; immediate restrict
289 : anton 1.1
290 :     \ !! should the compiler warn about +DO..-LOOP?
291 :     : -LOOP ( compilation do-sys -- ; run-time loop-sys1 u -- | loop-sys2 ) \ gforth minus-loop
292 : pazsan 1.14 ['] (-loop) ['] (-loop)-lp+!# loop-like ; immediate restrict
293 : anton 1.1
294 :     \ A symmetric version of "+LOOP". I.e., "-high -low ?DO -inc S+LOOP"
295 :     \ will iterate as often as "high low ?DO inc S+LOOP". For positive
296 :     \ increments it behaves like "+LOOP". Use S+LOOP instead of +LOOP for
297 :     \ negative increments.
298 :     : S+LOOP ( compilation do-sys -- ; run-time loop-sys1 n -- | loop-sys2 ) \ gforth s-plus-loop
299 : pazsan 1.14 ['] (s+loop) ['] (s+loop)-lp+!# loop-like ; immediate restrict
300 : anton 1.1
301 :     : NEXT ( compilation do-sys -- ; run-time loop-sys1 -- | loop-sys2 ) \ gforth
302 : pazsan 1.14 ['] (next) ['] (next)-lp+!# loop-like ; immediate restrict
303 : anton 1.1
304 :     \ Structural Conditionals 12dec92py
305 :    
306 :     Defer exit-like ( -- )
307 :     ' noop IS exit-like
308 :    
309 :     : EXIT ( compilation -- ; run-time nest-sys -- ) \ core
310 : anton 1.12 \G Return to the calling definition; usually used as a way of
311 :     \G forcing an early return from a definition. Before
312 :     \G @code{EXIT}ing you must clean up the return stack and
313 :     \G @code{UNLOOP} any outstanding @code{?DO}...@code{LOOP}s.
314 : anton 1.1 exit-like
315 :     POSTPONE ;s
316 : anton 1.12 basic-block-end
317 : anton 1.1 POSTPONE unreachable ; immediate restrict
318 :    
319 :     : ?EXIT ( -- ) ( compilation -- ; run-time nest-sys f -- | nest-sys ) \ gforth
320 :     POSTPONE if POSTPONE exit POSTPONE then ; immediate restrict
321 :    

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help