6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 11:43 am

All times are UTC




Post new topic Reply to topic  [ 63 posts ]  Go to page 1, 2, 3, 4, 5  Next
Author Message
PostPosted: Sun Sep 18, 2022 10:39 pm 
Offline

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

Forth has the IF ELSE THEN and BEGIN WHILE REPEAT control flow structures as well as DO LOOP's. There are even some Forths with additional control flow words such as AHEAD and ELIF . I was wondering about other methods of control flow.
PETTIL, by chitselb, has a CASE# ELSE THEN structure. It also has ?:.
I was looking at one of my CREATE DOES> words and it reminded me of a CASE statement.
The CREATE DOES> word XTTABLE bears a resemblance to a CASE statement in sofar as there are tests and actions.
Code:
: XTTABLE  ( -- )
   CREATE
   DOES>  ( N -- )
      BEGIN
         2DUP @ EXECUTE 0=
      WHILE
         2+ 2+
      REPEAT
      2+ @ EXECUTE  ;
: DEFAULT  ( N -- T )
   DROP TRUE ;

XTTABLE creates a word without a parameter field. The parameter field is filled in after the child of XTTABLE is defined. The parameter field consists of tests and actions. A test word is passed the same parameter the XTTABLE word received and is expected to consume that parameter and return a flag. An XTTABLE word will keep going down the list of word pairs until a test returns a TRUE flag. When that happens, the corresponding action word is executed with the same parameter on the stack. After this action word executes, the XTTABLE word exits. Since the XTTABLE word will continue down the list of word pairs until a test returns a TRUE flag, the last test must be the default case. DEFAULT just drops the parameter and returns a TRUE flag. The words used by an XTTABLE word are compiled in this order:
Code:
TEST0  ACTION0  TEST1  ACTION1 ... TESTN  ACTIONN

Here is an example.
Code:
XTTABLE <SEE>  ( CFA -- ??? )
   ] ?CODE      >DIS
     ?HL        >:DIS
     ?DEFER     DDIS
     DEFAULT    CREATEDIS [

Rather than using ' SOMEWORD , , I reverse the normal order of [ and ] to compile the words used by the XTTABLE word <SEE> .
The word <SEE> is used like this:
Code:
: (SEE)  ( CFA -- )
   DUP CR .NAME
   SETWIDTH <SEE> ;
: SEE  ( -- )  ' (SEE) ;

So, what other unique control methods are out there, or even the traditional ones used in unique and interesting ways?


Top
 Profile  
Reply with quote  
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  
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 17 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: