6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 6:13 pm

All times are UTC




Post new topic Reply to topic  [ 63 posts ]  Go to page 1, 2, 3, 4, 5  Next
Author Message
PostPosted: Mon Sep 19, 2022 3:29 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
JimBoyd wrote:
So, what other unique control methods are out there, or even the traditional ones used in unique and interesting ways?

Courtesy of "HAA" on usenet:
Code:
FOR NEXT came from cmForth as a replacement for DO LOOP. The latter
was deemed too expensive to implement on Forth chips. Implementations
vary e.g. cmForth's iterates n+1 times for reasons peculiar to Novix.

eForth creator Bill Muench provides this diagram & test to explain how
FOR NEXT works with AFT and WHILE. Use fixed-width font to view.

\ v--------<<
\ FOR ... NEXT a1 ...
\
\ v---------------------<< >>----------v
\ FOR ... WHILE a1 ... NEXT a2 ... ELSE a3 ... THEN ...
\ >>-------------------------^
\
\ v-----------------<<
\ FOR ... AFT a1 ... THEN ... NEXT a2 ...
\ >>----------^

( test FOR-NEXT ============================================= )

: N1 ( -- ) 9 FOR R@ . NEXT ;
: N2 ( -- ) 9 FOR 5 R@ < WHILE R@ . NEXT ." X" ELSE R> DROP ." Y" THEN ;
: N3 ( -- ) 9 FOR ." X" AFT ." Y" THEN R@ . NEXT ;

Results using Bill's eForth

ok N1 9 8 7 6 5 4 3 2 1 0
ok N2 9 8 7 6 Y
ok N3 X9 Y8 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 20, 2022 1:00 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
One of the words I added to my version of FIG Forth is NIF (short for "not if"). Predictably, it compiles a primitive which behaves like 0= IF. And NUNTIL was "not until."

These are pretty trivial, of course, but seemed worthwhile given my own relative priorities re the speed/memory tradeoff.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 20, 2022 9:14 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Dr Jefyll wrote:
One of the words I added to my version of FIG Forth is NIF (short for "not if").

Wow, looking at my own code, there are enough occurrences of 0= IF that I think that would pay for itself in memory, so there's no penalty for the faster execution. I think I would call it something else though unless "NIF" is already in common use, because it looks like a short form of "nifty" and definitely did not make me think "NOT IF." NOT in Forth XOR's the value with -1, rather than doing 0=.

I believe FOR...NEXT is in the newest standards, probably as a concession to reduce newcomers' resistance to Forth, but I do like DO...LOOP and friends. I have 32-bit equivalents too, at http://wilsonminesco.com/Forth/32DOLOOP.FTH .

Michael, can you give further explanation of what the flow is in FOR...WHILE a1...NEXT a2...ELSE a3...THEN...

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 20, 2022 10:13 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
I asked the question and received that from HAA as the kindest answer, but I'm not embarrassed to admit that I still don't fully understand the answer.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 21, 2022 9:40 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
barrym95838 wrote:
Courtesy of "HAA" on usenet:


Monday evening I think I figured this out and wrote FOR NEXT words. The diagrams were not much help. This better represents what my FOR NEXT words do.
Code:
\     v--------<<
\ FOR a0 ... NEXT a1 ...
\
\     v--------------------<<           >>------------v
\ FOR a0... WHILE a1 ... NEXT a2 ... ELSE a3 ... THEN a4 ...
\              >>-------------------------^
\
\                v--------------------<<
\ FOR a0 ... AFT a1 ... THEN a2 ... NEXT a3 ...
\             >>-------------^

This is how it works in my Forth.
First a brief refresher on the control flow words >MARK >RESOLVE <MARK <RESOLVE .
>MARK leaves an address to be resolved and reserves a cell in the dictionary while >RESOLVE resolves the forward reference.
<MARK leaves a destination address for a backward branch and <RESOLVE compiles that address in the dictionary. This is from my Forth. The (minimal) compiler security is just to make sure that a <MARK is resolved by a <RESOLVE and a >MARK is resolve by a >RESOLVE .
Code:
: ?PAIRS  ( N1 N2 -- )
   <>
   ABORT" STRUCTURE MISMATCH" ;

: >MARK  ( -- >SYS )
   HERE 1  0 , ;
: >RESOLVE  ( >SYS -- )
   1 ?PAIRS  HERE SWAP ! ;

: <MARK  ( -- <SYS )
   HERE 2 ;
: <RESOLVE  ( <SYS -- )
   2 ?PAIRS  , ;

Here are the FOR NEXT words. The only new primitive is (NEXT) .
Code:
' ?BRANCH @ 8 + CONSTANT 2.IP.+!
CODE (NEXT)  ( -- )
   PLA  TAY
   0= IF
      PLA
      0= IF
         2.IP.+! JMP
      THEN
      SEC  1 # SBC  PHA
   THEN
   DEY  TYA  PHA
   0 # LDY
   ' BRANCH @ JMP
   END-CODE

And the high level words.
Code:
: FOR  ( -- )
       ( N -- )
   COMPILE >R  <MARK ; IMMEDIATE
: NEXT  ( -- )
   COMPILE  (NEXT)
   <RESOLVE ; IMMEDIATE
: AFT  ( -- )
   [COMPILE] CS-DROP  COMPILE BRANCH
   >MARK  <MARK
   [COMPILE] CS-SWAP ; IMMEDIATE

The FOR and NEXT loop structure is similar to a BEGIN UNTIL loop.
AFT is the unusual one. It drops the control flow data from FOR , compiles BRANCH and adds control flow data for a forward branch and backward branch. AFT then swaps the control flow data because the forward branch gets resolved before the backward branch.

Here are the test words:
Code:
: N1  ( -- )
   9
   FOR
     R@ .
   NEXT ;
: N2  ( -- )
   9
   FOR
      5 R@ <
   WHILE
      R@ .
   NEXT
      ." X"
   ELSE
      R> DROP ." Y"
   THEN ;
: N3  ( -- )
   9
   FOR
      ." X"
   AFT
      ." Y"
   THEN
      R@ .
   NEXT ;

And what got compiled:
Code:
SEE N1
N1
 31296  3419 CLIT 9
 31299  4656 >R
 31301  4740 R@
 31303  7568 .
 31305 31202 (NEXT)
 31307 31301
 31309  2970 EXIT
15
 OK
SEE N2
N2
 31320  3419 CLIT 9
 31323  4656 >R
 31325  3419 CLIT 5
 31328  4740 R@
 31330  4448 <
 31332  2781 ?BRANCH 31352
 31336  4740 R@
 31338  7568 .
 31340 31202 (NEXT)
 31342 31325
 31344  7809 (.") X
 31348  3042 BRANCH 31360
 31352  4672 R>
 31354  3031 DROP
 31356  7809 (.") Y
 31360  2970 EXIT
42
 OK
SEE N3
N3
 31371  3419 CLIT 9
 31374  4656 >R
 31376  7809 (.") X
 31380  3042 BRANCH 31388
 31384  7809 (.") Y
 31388  4740 R@
 31390  7568 .
 31392 31202 (NEXT)
 31394 31384
 31396  2970 EXIT
27
 OK

The address after (NEXT) is the branch address. My SEE doesn't recognize (NEXT) as a branching word, but that is not a problem.
The results match those provided.
Code:
N1 9 8 7 6 5 4 3 2 1 0  OK
N2 9 8 7 6 Y OK
N3 X9 Y8 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0  OK

[Edit: Added some clarification about my SEE .]


Last edited by JimBoyd on Mon Sep 26, 2022 11:07 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 21, 2022 10:12 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
GARTHWILSON wrote:
Dr Jefyll wrote:
One of the words I added to my version of FIG Forth is NIF (short for "not if").

Wow, looking at my own code, there are enough occurrences of 0= IF that I think that would pay for itself in memory, so there's no penalty for the faster execution. I think I would call it something else though unless "NIF" is already in common use, because it looks like a short form of "nifty" and definitely did not make me think "NOT IF." NOT in Forth XOR's the value with -1, rather than doing 0=.

I think I saw it called -IF but it has been a while and I can't remember where.


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 22, 2022 1:16 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

I need to run some more tests on my FOR NEXT loops. I suspect the following will be true:
When nested, an inner FOR NEXT loop can be in any part of the outer loop as long as the control structures do not cross.
WHILE can even be used with a FOR ... AFT ... THEN ... NEXT loop. Because AFT places two sets of control flow data on the control flow stack (in my case, the data stack), WHILE cannot be used to branch past NEXT from between AFT and THEN . In other words, I don't think this will work:
Code:
FOR a0 ... AFT a1 ... WHILE a2 ... THEN a3 ... NEXT a4 ... THEN a5 ...

Multiple WHILEs can be used. Each must have a matching THEN after NEXT.

I think my Forth's compiler security of making sure each >MARK is matched with a >RESOLVE , each <MARK is matched with a <RESOLVE and a colon or CODE is matched with a semicolon or END-CODE will cause an ABORT if these conditions are not met.
Also, if any WHILE's are used to branch out of the FOR NEXT loop, the loop parameter will still be on the return stack as shown in test word N2 .
Code:
: N2  ( -- )
   9
   FOR
      5 R@ <
   WHILE
      R@ .
   NEXT
      ." X"
   ELSE
      R> DROP ." Y"
   THEN ;

I also think this might be possible, but I need to test it:
Code:
               v-------------------------------------------<<   
FOR A0 ... AFT A1 ... WHILE A2 ... THEN A3... THEN A4... NEXT A5...
                         >>------------------------^
            >>--------------------------^



Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 22, 2022 4:46 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
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 ... :lol:

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 25, 2022 7:05 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
JimBoyd wrote:
GARTHWILSON wrote:
Dr Jefyll wrote:
One of the words I added to my version of FIG Forth is NIF (short for "not if").

Wow, looking at my own code, there are enough occurrences of 0= IF that I think that would pay for itself in memory, so there's no penalty for the faster execution. I think I would call it something else though unless "NIF" is already in common use, because it looks like a short form of "nifty" and definitely did not make me think "NOT IF." NOT in Forth XOR's the value with -1, rather than doing 0=.

I think I saw it called -IF but it has been a while and I can't remember where.

IF0 or IF_0 would be pretty intuitive.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 26, 2022 2:35 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
GARTHWILSON wrote:
JimBoyd wrote:
GARTHWILSON wrote:
Dr Jefyll wrote:
One of the words I added to my version of FIG Forth is NIF (short for "not if").

Wow, looking at my own code, there are enough occurrences of 0= IF that I think that would pay for itself in memory, so there's no penalty for the faster execution. I think I would call it something else though unless "NIF" is already in common use, because it looks like a short form of "nifty" and definitely did not make me think "NOT IF." NOT in Forth XOR's the value with -1, rather than doing 0=.

I think I saw it called -IF but it has been a while and I can't remember where.

IF0 or IF_0 would be pretty intuitive.

How about "ZIF" or "ZEQIF"?


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 26, 2022 3:32 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
GARTHWILSON wrote:
JimBoyd wrote:
... I think I saw it called -IF but it has been a while and I can't remember where.

IF0 or IF_0 would be pretty intuitive.


-IF is the one that I saw previously, but I have to say that IF0 is the best combination of intuitive and fast to type for me.

I think -IF is most intuitive if you have a dictionary with a leading "-" for a number of words that invert the test for the underlying word. Otherwise I'd have a risk of reading it as taking the following action if the top of the stack is negative.

I would say that "I have FOR NEXT in xForth", but I haven't had an opportunity to work on it over the past year, and until I have a working CREATE / DOES> word pair, I don't think it's fair to say that I actually "have" xForth -- rather I have code that hopes to grow up into xForth on of these days.


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 26, 2022 11:01 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

What about 0IF ?
Also 0WHILE and 0UNTIL ?
Code:
   ...
      BEGIN
         2DUP @ EXECUTE
      0WHILE
         2+ 2+
      REPEAT
   ...

Code:
   ...
      BEGIN
         2DUP @ EXECUTE
      WHILE0
         2+ 2+
      REPEAT
   ...

Which do you think reads better?
I also have:
Code:
?EXIT   \ pop top of stack. exit if true.
0EXIT   \ pop top of stack. exit if false.



Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 26, 2022 11:49 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
JimBoyd wrote:
What about 0IF ?
Also 0WHILE and 0UNTIL ?
To me, the leading zero seems good. Terse yet clear. Of course I liked the leading N too (example: NIF ), and I knew well enough that it didn't mean NOT (or "nifty"!) :P

But the leading 0 seems fine for 0IF and likewise for 0WHILE.
As for this...
Code:
?EXIT   \ pop top of stack. exit if true.
0EXIT   \ pop top of stack. exit if false.
... my own preference would be...
Code:
?EXIT   \ pop top of stack. exit if true.
?0EXIT  \ pop top of stack. exit if false.
... because they both conditionally execute based on TOS (which gets popped), and that's a scenario I associate with the question mark. And the 0 gets added if you wanna reverse the sense.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 27, 2022 12:26 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Dr Jefyll wrote:
... my own preference would be...
Code:
?EXIT   \ pop top of stack. exit if true.
?0EXIT  \ pop top of stack. exit if false.
... because they both conditionally execute based on TOS (which gets popped), and that's a scenario I associate with the question mark. And the 0 gets added if you wanna reverse the sense.

-- Jeff


I like it. Good thing I haven't released Fleet Forth version 2.0 yet.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 27, 2022 12:59 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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 ... :lol:


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



Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 63 posts ]  Go to page 1, 2, 3, 4, 5  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: