barrym95838 wrote:
Jim, I knew you'd be the guy here to figure out how eForth's AFT works. Now all I have to do is figure out how you figured it out, then figure out a proper use for it ...
I definitely needed the examples for that. It looks like all duplicate spaces were deleted from the original control flow diagrams.
Here are two words using WHILE to branch from between AFT and AFT's matching THEN to between that THEN and NEXT .
Code:
v-------------------------------------------<<
FOR A0 ... AFT A1 ... WHILE A2 ... THEN A3... THEN A4... NEXT A5...
>>------------------------^
>>--------------------------^
Here is the first word.
Code:
: N4 ( -- )
9
FOR
." X"
AFT
." Y"
5 R@ <
WHILE
THEN
R@ .
THEN
NEXT ;
And the test run.
Code:
N4 X9 Y8 Y7 Y6 YYYYYY OK
Here is the other.
Code:
: N6 ( -- ) 9
FOR
CR ." A0"
AFT
CR ." A1"
5 R@ <
WHILE
." A2"
THEN
." A3"
ELSE
." A4"
THEN
." A5 " R@ .
NEXT ;
And the test run.
Code:
N6
A0 A3 A5 9
A1 A2 A3 A5 8
A1 A2 A3 A5 7
A1 A2 A3 A5 6
A1 A4 A5 5
A1 A4 A5 4
A1 A4 A5 3
A1 A4 A5 2
A1 A4 A5 1
A1 A4 A5 0 OK
The word N7 has a FOR NEXT loop within another FOR NEXT loop.
Code:
: N7 ( -- ) 9
FOR
CR ." A0"
AFT
CR ." A1"
5 R@ <
WHILE
." A2 " 3 FOR ." X" AFT ." Y" THEN R@ . NEXT
THEN
." A3"
ELSE
." A4"
THEN
." A5 " R@ .
NEXT ;
And it works well.
Code:
N7
A0 A3 A5 9
A1 A2 X3 Y2 Y1 Y0 A3 A5 8
A1 A2 X3 Y2 Y1 Y0 A3 A5 7
A1 A2 X3 Y2 Y1 Y0 A3 A5 6
A1 A4 A5 5
A1 A4 A5 4
A1 A4 A5 3
A1 A4 A5 2
A1 A4 A5 1
A1 A4 A5 0 OK
Multiple occurrences of AFT in a FOR NEXT loop will not work. The first AFT drops the backward branch data from FOR and replaces it with its own and a forward branch. A second AFT would drop the forward branch data from the first AFT , leaving its backward branch data. The matching THEN will not resolve the backward branch and abort.
This will not compile on my system.
Code:
: N9 ( -- )
CR 3
FOR ." A0 "
AFT ." A1 "
AFT ." A2 "
THEN ." A3 "
THEN ." A4 "
R@ .
NEXT ;
So let's get tricky. The first AFT still has backward branch data on the control flow stack, so that is what must be resolved.
Code:
: N10
CR 3
FOR ." A0 "
AFT ." A1 "
AFT ." A2 "
THEN ." A3 "
TRUE
UNTIL ." A4 "
R@ .
NEXT ;
This is what gets compiled.
Code:
SEE N10
N10
31299 6707 CR
31301 2266 3
31303 4656 >R
31305 7809 (.") A0
31311 3042 BRANCH 0
16
OK
The forward branch from the first AFT does not get resolved resulting in a branch to address zero.
I typed
Code:
EAD :DIS
to see the rest of N10 .
Code:
EAD :DIS
31315 7809 (.") A1
31321 3042 BRANCH 31331
31325 7809 (.") A2
31331 7809 (.") A3
31337 3388 TRUE
31339 2781 ?BRANCH 31325
31343 7809 (.") A4
31349 4740 R@
31351 7568 .
31353 31202 (NEXT)
31355 31315
31357 2970 EXIT
44
OK
It is possible to tighten the compiler security so this doesn't happen. The control flow data consists of an address and a number.
One for >MARK and >RESOLVE .
Two for <MARK and <RESOLVE .
Code:
// FOR NEXT LOOP -- EXTRA SECURITY
: FOR ( -- )
( N -- )
COMPILE >R
<MARK 2+ 2+ ; IMMEDIATE
: NEXT ( -- )
COMPILE (NEXT)
2- 2- <RESOLVE ; IMMEDIATE
: AFT ( -- )
6 ?PAIRS DROP
COMPILE BRANCH >MARK
<MARK 2+ 2+
[COMPILE] CS-SWAP ; IMMEDIATE
Sixteen extra bytes to make sure:
FOR is only resolved with AFT or NEXT .
AFT is only resolved with THEN and NEXT in that order.
By the way, the version of Gforth on my desktop has FOR and NEXT but not AFT . I suspect it is because this version of Gforth does not have CS-DROP , just CS-PICK and CS-ROLL in accordance with the ANSI standard.
Since this version of Gforth uses the data stack for the control flow stack, I was able to add AFT to it.
Code:
\ AFT for gforth
: AFT ( -- )
2DROP DROP
POSTPONE BRANCH >MARK
POSTPONE BEGIN DROP DO-DEST
POSTPONE BUT ; IMMEDIATE
Code:
: BUT
1 CS-ROLL ; IMMEDIATE
Anyone who notices that DO-DEST and thinks this version of Gforth's FOR NEXT loops are compatible with its DO LOOP's would be correct. Gforth's DO LOOP's only have two parameters pushed to the return stack, the limit and index. Gforth's FOR pushes a zero as a limit and the number on the stack as the index. Here is an example of a mixed FOR and DO loop in Gforth. Gforth's I is an alias for R@ .
Code:
\ this is weird
: test 50 for cr i . -10 +loop ; ok
test
50
40
30
20
10
0 ok