<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>
; ______ _ _____ _ _ ; | ____| | / ____| | | | | ; | |__ | | _____ __ | | ___ _ __ | |_ _ __ ___ | | ; | __| | |/ _ \ \ /\ / / | | / _ \| '_ \| __| '__/ _ \| | ; | | | | (_) \ V V / | |____| (_) | | | | |_| | | (_) | | ; |_| |_|\___/ \_/\_/ \_____|\___/|_| |_|\__|_| \___/|_| ; Flow control words ; MARK & AHEAD: Utilities for flow control words ; : MARK ( -- addr) HERE 0 , ; mark data docol data ghere,lit0,comma data exit ; : AHEAD ( -- addr ) POSTPONE BRANCH MARK ; IMMEDIATE ahead data docol data compile,branch,mark data exit ; FOR ( loop_count -- ) ; Implements FOR...NEXT looping as in COUNT FOR .. .. NEXT ; I is available for retrieving the index. ; : FOR ( start--) COMPILE LIT 0 , COMPILE SWAP [COMPILE] DO ; IMMEDIATE forh data gtezh,immed+3 text 'FOR ' for data docol data compile,lit0 data compile,swap,do1 data exit ; NEXT ; : NEXT ( --) COMPILE LIT -1 , [COMPILE] +LOOP ; IMMEDIATE nexth data forh,immed+4 text 'NEXT' fnext1 data docol data litm1,clc,ploop1 data exit ; : IF ( -- addr ) POSTPONE ?BRANCH MARK ; IMMEDIATE ; IF flag -- C,I,79 ; -- sys (compiling) ; Used in the form: ; flag IF ... ELSE ... THEN ; or flag IF ... THEN ; If flag is true, the words following IF are executed and the words following ; ELSE until just after THEN are skipped. The ELSE part is optional. ; If flag is false, the words from IF through ELSE , or from IF through THEN ; (when no ELSE is used), are skipped. ; sys is balanced with its corresponding ELSE or THEN . ; See: "9.9 Control Structures" ifh data nexth,immed+2 text 'IF' if data docol data lit,ifcnt,refup data compile,zbrnch,mark data exit ;] ; : THEN HERE SWAP ! ; IMMEDIATE ; THEN -- C,I,79 ; sys -- (compiling) ; Used in the form: ; flag IF ... ELSE ... THEN ; or flag IF ... THEN ; THEN is the point where execution continues after ELSE , or IF when no ELSE ; is present. ; sys is balanced with its corresponding IF or ELSE . See: IF ELSE thenh data ifh,immed+4 text 'THEN' then data docol data lit,ifcnt,refdn data ghere,swap,store data exit ; : ELSE POSTPONE AHEAD SWAP POSTPONE THEN ; IMMEDIATE ; ELSE -- C,I,79 ; sys1 -- sys2 (compiling) ; Used in the form: ; flag IF ... ELSE ... THEN ; ELSE executes after the true part following IF . ELSE forces execution to ; continue at just after THEN . sys1 is balanced with its corresponding IF . ; sys2 is balanced with its corresponding THEN . See: IF THEN elseh data thenh,immed+4 text 'ELSE' else data docol data ahead,swap,ghere,swap,store data exit ; BRANCH ( -- ) ; unconditional branch: e.g: BRANCH 4 will branch forwards four words. ; Negative offsets supported. brnchh data elseh,6 text 'BRANCH' branch data $+2 ; at entry, R3 is pointing at the branch address... mov *pc,pc ; get the in-line address and move to the b *next ; instruction pointer ; 0BRANCH ( flag -- ) ; Branch if data on the stack is 0. e.g: 0BRANCH 4 will branch forwards 4 ; bytes if the value on the data stack is 0 zbrchh data brnchh,7 text '0BRANCH ' zbrnch data _zbrnch ; code is in high-speed ram. ; see 1-15-Initialise.a99 ; CASE..OF..ENDCASE ( -- ) ; Part of CASE..OF..ENDCASE ; CASE caseh data zbrchh,immed+4 text 'CASE' case data docol data lit,cascnt,refup ; reference count data lit0 data exit ; OF ofh data caseh,immed+2 text 'OF' of data docol data lit,ofcnt,refup data compile,over,compile,eq,if,compile,drop data exit ; ENDOF endofh data ofh,immed+5 text 'ENDOF ' endof data docol data lit,ofcnt,refdn,else data exit ; ENDCASE endcah data endofh,immed+7 text 'ENDCASE ' endcas data docol data lit,cascnt,refdn ; reference count data compile,drop,qdup,zbrnch,$+8,then,branch,$-10 data exit ; : BEGIN HERE ; IMMEDIATE \ synonym purely for readability ; BEGIN -- C,I,79 ; -- sys (compiling) ; Used in the form: ; BEGIN ... flag UNTIL ; or BEGIN ... flag WHILE ... REPEAT ; BEGIN marks the start of a word sequence for repetitive execution. ; A BEGIN-UNTIL loop will be repeated until flag is true. ; A BEGIN-WHILE-REPEAT will be repeated until flag is false. ; The words after UNTIL or REPEAT will be executed when either loop is finished. ; sys is balanced with its corresponding UNTIL or WHILE . ; See: "9.9 Control Structures" beginh data endcah,immed+5 text 'BEGIN ' begin data docol data lit,begcnt,refup data ghere data exit ; : UNTIL POSTPONE ?BRANCH , ; IMMEDIATE ; UNTIL ( address -- ) untilh data beginh,immed+5 text 'UNTIL ' until data docol data lit,begcnt,refdn data compile,zbrnch,comma data exit ; : AGAIN POSTPONE BRANCH , ; IMMEDIATE ; AGAIN ( address -- ) againh data untilh,immed+5 text 'AGAIN ' again data docol data lit,begcnt,refdn data compile,branch,comma data exit ; : WHILE POSTPONE IF SWAP ; IMMEDIATE ; WHILE flag -- C,I,79 ; sys1 -- sys2 (compiling) ; Used in the form: ; BEGIN ... flag WHILE ... REPEAT ; Selects conditional execution based on flag. When flag is true, execution ; continues to just after the WHILE through to the REPEAT which then continues ; execution back to just after the BEGIN. ; When flag is false, execution continues to just after the REPEAT, exiting the ; control structure. ; sys1 is balanced with its corresponding BEGIN. ; sys2 is balanced with its corresponding REPEAT. See: BEGIN whileh data againh,immed+5 text 'WHILE ' while data docol data if,swap data exit ; : REPEAT POSTPONE AGAIN POSTPONE THEN ; IMMEDIATE ; REPEAT -- C,I,79 ; sys -- (compiling) ; Used in the form: ; BEGIN ... flag WHILE ... REPEAT ; At execution time, REPEAT continues execution to just after the corresponding ; BEGIN. ; sys is balanced with its corresponding WHILE. See: BEGIN repeth data whileh,immed+6 text 'REPEAT' repeat data docol data again,then data exit ; DO w1 w2 -- C,I,83 ; -- sys (compiling) ; Used in the form: ; DO ... LOOP ; or DO ... +LOOP ; Begins a loop which terminates based on control parameters. ; The loop index begins at w2, and terminates based on the limit w1. ; See LOOP and +LOOP for details on how the loop is terminated. ; The loop is always executed at least once. ; For example: w DUP DO ... LOOP executes 65,536 times. ; sys is balanced with its corresponding LOOP or +LOOP . ; See: "9.9 Control Structures" ; note: DO is immediate and compiles a reference to (DO) ; ; Loop frame format: ; 0 = current loop index <----- RSTACK points to this value ; +2 = loop limit ; +4 = loop exit address ; To drop a loop frame, add 6 to RSTACK ; ; In words, for A B DO ... LOOP ; (DO) puts three things on to the return stack ; 1. the address of the word after LOOP - where execution continues when ; the loop executes ; 2. A + >8000 (A with its sign bit 'permuted') ; 3. B minus the value computed at step 2 <-- top of return stack ; ; LOOP and +LOOP add 1 or whatever to the value at 3. ; If the overflow flag is set, drop two elements from the return stack, ; pop the final value from R (the address at 1. above) ; into I and execute next. ; ; I becomes: ; 4. Move the value at 2. above to the data stack ; 5. Add the value at 3. above to the data stack ; do1h data repeth,immed+2 text 'DO' do1 data docol data lit,docnt,refup ; increase reference counters data compile,do,ghere,lit0,comma ; compile (do) here 0 , data exit doh data do1h,4 text '(DO)' do data $+2 mov *stack+,r0 ; pop initial index mov *stack+,r1 ; pop loop termination value ai r1,>8000 ; flip sign bit s r1,r0 ; calculate initial index dect rstack ; new return stack entry mov *pc+,*rstack ; loop exit address to return stack dect rstack ; new return stack entry mov r1,*rstack ; loop limit to return stack dect rstack ; new return stack entry mov r0,*rstack ; loop index to return stack b *next ; LOOP -- C,I,83 ; sys -- (compiling) ; Increments the DO-LOOP index by one. If the new index was incremented across ; the boundary between limit-1 and limit the loop is terminated and loop control ; parameters are discarded. When the loop is not terminated, execution ; continues to just after the corresponding DO. ; sys is balanced with its corresponding DO . See: DO ; note: LOOP is immediate and compiles a reference to (LOOP) loop1h data doh,immed+4 text 'LOOP' loop1 data docol data lit,docnt,refdn ; reduce DO/LOOP reference counters data dup,compile,loop loop2 data ghere,plus2,swap,store,plus2,comma data exit looph data loop1h,6 text '(LOOP)' loop data $+2 inc *rstack ; increment loop count loopchk jno lagain ; if no overflow then loop again loopx ai rstack,6 ; otherwise pop loop frame inct pc ; move past (LOOP)'s in-line parameter b *next lagain mov *pc,pc ; reload loop address b *next ; +LOOP n -- C,I,83 "plus-loop" ; sys -- (compiling) ; n is added to the loop index. If the new index was incremented across the ; boundary between limit-1 and limit then the loop is terminated and loop ; control parameters are discarded. When the loop is not terminated, execution ; continues to just after the corresponding DO. ; sys is balanced with its corresponding DO. See: DO ; note: +LOOP is immediate and compiles a reference to (+LOOP) plooh1 data looph,immed+5 text '+LOOP ' ploop1 data docol data lit,docnt,refdn data dup,compile,ploop,branch,loop2 ; compile (+LOOP) then as (LOOP) plooph data plooh1,7 text '(+LOOP) ' ploop data $+2 a *stack+,*rstack ; pop increment and add to index on return stack jmp loopchk ; LEAVE -- C,I,83 ; -- (compiling) ; Transfers execution to just beyond the next LOOP or +LOOP . ; The loop is terminated and loop control parameters are discarded. ; May only be used in the form: ; DO ... LEAVE ... LOOP ; or DO ... LEAVE ... +LOOP ; LEAVE may appear within other control structures which are nested within the ; do-loop structure. More than one LEAVE may appear within a do-loop. ; See: "9.3 Return Stack" ; Note: LEAVE *must* appear within an IF ... THEN block for correct operation. leaveh data plooph,5 text 'LEAVE ' leave data $+2 mov @4(rstack),pc ; load pc with exit address ai rstack,6 ; pop loop frame from return stack b *next ; I -- w C,79 ; w is a copy of the loop index. May only be used in the ; form: ; DO ... I ... LOOP ; or DO ... I ... +LOOP ; or FOR .. I ... NEXT getih data leaveh,1 text 'I ' geti data $+2 dect stack ; new data stack entry mov @2(rstack),*stack ; place index on data stack a *rstack,*stack ; adjust b *next ; J -- w C,79 ; w is a copy of the index of the next outer loop. ; May only be used within a nested DO-LOOP or DO-+LOOP in the form, for example: ; DO ... DO ... J ... LOOP ... +LOOP ; Also active in nested FOR...NEXT loops. getjh data getih,1 text 'J ' getj data $+2 dect stack ; new data stack entry mov @8(rstack),*stack ; place outer loop index on data stack a @6(rstack),*stack ; adjust b *next ; utility routines for reference counting refup data $+2 mov *stack+,r0 ; pop address of reference counter inc *r0 ; increase reference counter b *next refdn data $+2 mov *stack+,r0 ; pop address of reference of counter dec *r0 ; decrease reference counter b *next