Testing CREATE DOES>

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
Post Reply
JimBoyd
Posts: 931
Joined: 05 May 2017

Testing CREATE DOES>

Post by JimBoyd »

I noticed on the Forth standard website when testing DOES>, there were no tests of nested CREATE DOES>. Something similar might be useful in an object oriented package for Forth. Here is a test I came up with for nested CREATE DOES>.

Code: Select all

SCR# 3 
// TEST CREATE DOES>
HEX
: LEVEL0  ( N -- )
   CREATE , DOES>  ( N2 -- )
   CREATE @ , , DOES>  ( N3 -- )
   CREATE 2@ , , , DOES>  ( N4 -- )
   CREATE DUP 2+ 2@ ROT @ , , , ,
   DOES>  ( -- )
      DUP 4 + 2@ ROT 2@ 4 0
      DO  U.  LOOP ;
2 LEVEL0 LEVEL1
3 LEVEL1 LEVEL2
5 LEVEL2 LEVEL3
7 LEVEL3 LEVEL4
LEVEL4
And here is the result

Code: Select all

3 LOAD 2 3 5 7  OK
And an examination of the parameter fields.

Code: Select all

' LEVEL1 >BODY 10 DUMP 
5A11   2  0  6 5A 86 4C 45 56  45 4C B2 BD 59  2  0  3   ...Z.LEVEL..Y...
 OK
' LEVEL2 >BODY 10 DUMP 
5A1E   2  0  3  0 13 5A 86 4C  45 56 45 4C B3 CC 59  2   .....Z.LEVEL..Y.
 OK
' LEVEL3 >BODY 10 DUMP 
5A2D   2  0  3  0  5  0 22 5A  86 4C 45 56 45 4C B4 E5   ......"Z.LEVEL..
 OK
' LEVEL4 >BODY 10 DUMP 
5A3E   2  0  3  0  5  0  7  0   4 44 55 4D 50 20 20 20   .........DUMP   
 OK
I'd like to hear about difficulties implementing CREATE DOES> , what situation caused it to fail, so those of us writing our own Forths can more thoroughly test our implementations of CREATE DOES>.

Cheers,
Jim
scotws
Posts: 576
Joined: 07 Jan 2013
Location: Just outside Berlin, Germany
Contact:

Re: Testing CREATE DOES>

Post by scotws »

I'm glad somebody is trying to get this test, the whole concept makes my brain explode. I know that https://forth-standard.org/ allows comments and discussions, have you considered posting it there for feedback?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Testing CREATE DOES>

Post by GARTHWILSON »

I had to go through that when I did my '816 Forth, but it has been many years so I'll have to review it when I get time. The way I originally did it turned out to have a problem, so I had to put some more brain power into it. I believe the 2nd time was a charm, but I don't remember much about it. There's also ;code, and does (a runtime routine).
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?
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

GARTHWILSON wrote:
There's also ;code, and does (a runtime routine).
I like it. My runtime routine for DOES> and ;CODE is named (;CODE) but I like DOES , it's a smaller name, and I may just rename mine.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Testing CREATE DOES>

Post by GARTHWILSON »

JimBoyd wrote:
GARTHWILSON wrote:
There's also ;code, and does (a runtime routine).
I like it. My runtime routine for DOES> and ;CODE is named (;CODE) but I like DOES , it's a smaller name, and I may just rename mine.
The 6502 Forth I got started on used lower-case for the internals, and I have stuck with that. So for example, DO compiles do, LOOP compiles loop, IF compiles 0branch, etc.. It's shorter than (do), (loop), etc.. which I think fig-Forth does, and if you want to put it in a comment marked out by parentheses, you can, without ending the comment prematurely.
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?
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

scotws wrote:
I'm glad somebody is trying to get this test, the whole concept makes my brain explode.
It really makes you appreciate what Charles Moore accomplished.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

GARTHWILSON wrote:
The 6502 Forth I got started on used lower-case for the internals, and I have stuck with that. So for example, DO compiles do, LOOP compiles loop, IF compiles 0branch, etc.. It's shorter than (do), (loop), etc.. which I think fig-Forth does, and if you want to put it in a comment marked out by parentheses, you can, without ending the comment prematurely.
Sadly, the Commodore 64 uses PETSCII and it doesn't have a caps lock key, it has a shift lock key.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

Regrettably, I cannot relate any difficulties I had because the first time I wrote a Forth for the C64, the only Forth I've written, was in the mid 1990's and I have no records ( notes or source code ) from that time.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

The following should also work under Forth-83 and ANSForth. Edited so the computer's responses are in curly braces.

Code: Select all

: DOES1   DOES>  @ . ;  { OK }
: DOES2   DOES>  @ 2* . ;  { OK }
CREATE PI  314 ,  { OK }
DOES1 PI { 314  OK }
PI  { 314  OK }
DOES2 PI { 628  OK }
PI { 628  OK }
DOES1 PI { 314  OK }
PI { 314  OK }
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »


The following example is for an ITC Forth. It's not so much a test to determine if CREATE DOES> is properly implemented, more like a test of what's possible. This example is a number generator which may also work with other Forth threading techniques.

Code: Select all

: GEN  ( -- )
   CREATE
      NOOP
   DOES>
      DUP 2@ SWAP ROT +! ;

Now to alter GEN to change it into a number generator. Each time it is called it will return a number.

Code: Select all

GEN

Set GEN to return an initial value of zero and increment by one each time it is executed.

Code: Select all

' GEN >BODY OFF
1 ' GEN >BODY 2+ !

Now set the new initial value to 1000 and the increment to 5.

Code: Select all

1000 ' GEN >BODY !
5 ' GEN >BODY 2+ !

In this example NOOP is just a place holder. DOES> compiles DOES , which will change the code field of the latest word in the current vocabulary. Since GEN is used to change its own code field, these two words are only executed once and can be safely overwritten after GEN modifies itself.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »


Should CREATE ;CODE be nestable if after ;CODE there is a shift to high level Forth?
Here is a test of nesting CREATE ;CODE and placing a CREATE DOES> in the mix. The JSR to the subroutine DO.VAR places the PFA on the data stack.

Code: Select all

SCR# 1 
// DO.VAR
SUBR DO.VAR  ( -- ADR )
   CLC
   W    LDA  2 # ADC
   W 1+ LDY  CS IF  INY  THEN
   DEX  DEX
   0 ,X STA  1 ,X STY
   RTS
   END-CODE

SCR# 2 
// TEST CREATE ;CODE
DECIMAL
: LEVEL0  ( N -- )
   CREATE , ;CODE  ( N2 -- )
   DO.VAR JSR  >FORTH
   CREATE @ , , ;CODE  ( N3 -- )
   DO.VAR JSR  >FORTH
   CREATE 2@ , , , ;CODE  ( N4 -- )
   DO.VAR JSR  >FORTH
   CREATE DUP 2+ 2@ ROT @ , , , ,
   DOES>  ( -- )
      DUP 4 + 2@ ROT 2@ 4 0
      DO  U.  LOOP ;

SCR# 3 
// THE TEST RUN
2 LEVEL0 LEVEL1
3 LEVEL1 LEVEL2
5 LEVEL2 LEVEL3
7 LEVEL3 LEVEL4
LEVEL4

And the result.

Code: Select all

1 RAM 3 RAM THRU 4001 4002 4003 2 3 5 7  OK

The contents of the parameter fields of LEVEL1 , LEVEL2 , LEVEL3 and LEVEL4 .

Code: Select all

' LEVEL1 >BODY 2 DUMP 
7A0C   2  0  3 40  1 7A 86 4C  45 56 45 4C B2 B0 79  2   B@C@A..LEVEL...B
 OK
' LEVEL2 >BODY 4 DUMP 
7A1B   2  0  3  0  3 40 10 7A  86 4C 45 56 45 4C B3 C2   B@C@C@P..LEVEL..
 OK
' LEVEL3 >BODY 6 DUMP 
7A2C   2  0  3  0  5  0  3 40  21 7A 86 4C 45 56 45 4C   B@C@E@C@!..LEVEL
 OK
' LEVEL4 >BODY 8 DUMP 
7A3F   2  0  3  0  5  0  7  0   4 44 55 4D 50 20 20 20   B@C@E@G@DDUMP   
 OK

These are the same results as with my test of nested CREATE DOES> .
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »

I made an error in the following and I'm surprised nobody noticed. At least, nobody commented on it.
JimBoyd wrote:

The following example is for an ITC Forth. It's not so much a test to determine if CREATE DOES> is properly implemented, more like a test of what's possible. This example is a number generator which may also work with other Forth threading techniques.

Code: Select all

: GEN  ( -- )
   CREATE
      NOOP
   DOES>
      DUP 2@ SWAP ROT +! ;

Now to alter GEN to change it into a number generator. Each time it is called it will return a number.

Code: Select all

GEN

Set GEN to return an initial value of zero and increment by one each time it is executed.

Code: Select all

' GEN >BODY OFF
1 ' GEN >BODY 2+ !

Now set the new initial value to 1000 and the increment to 5.

Code: Select all

1000 ' GEN >BODY !
5 ' GEN >BODY 2+ !

In this example NOOP is just a place holder. DOES> compiles DOES , which will change the code field of the latest word in the current vocabulary. Since GEN is used to change its own code field, these two words are only executed once and can be safely overwritten after GEN modifies itself.
When GEN is run without a name, CREATE will abort with an error message.

Code: Select all

GEN 
GEN
   
NAME?!

CREATE should not be in the definition of GEN if it is to modify itself. The presence of NOOP and DOES (compiled by DOES> ) reserves room for two cells.

Code: Select all

: GEN
    NOOP
    DOES>
       DUP 2@ SWAP ROT +! ;
GEN
1000 ' GEN >BODY !
5 ' GEN >BODY 2+ !

A short test.

Code: Select all

: TEST 
   5 0 
   DO 
       GEN . 
   LOOP ; 

And the results.

Code: Select all

TEST 1000 1005 1010 1015 1020  OK
TEST 1025 1030 1035 1040 1045  OK
TEST 1050 1055 1060 1065 1070  OK

BruceRMcF
Posts: 388
Joined: 21 Aug 2019

Re: Testing CREATE DOES>

Post by BruceRMcF »

JimBoyd wrote:
GARTHWILSON wrote:
The 6502 Forth I got started on used lower-case for the internals, and I have stuck with that. So for example, DO compiles do, LOOP compiles loop, IF compiles 0branch, etc.. It's shorter than (do), (loop), etc.. which I think fig-Forth does, and if you want to put it in a comment marked out by parentheses, you can, without ending the comment prematurely.
Sadly, the Commodore 64 uses PETSCII and it doesn't have a caps lock key, it has a shift lock key.
For my (still unfinished) xForth for the X16, which supports both ASCII and PETSCII, I use upper case ASCII for the Forth words, which is still upper case in PETSCII graphics and is lower case in PETSCII upper/lower case. In that context, lower case for the internals would drive me around the bend, since it would be EXTERNALNAME internalname in ASCII mode and externalname INTERNALNAME in PETSCII upper/lower case and EXTERNALNAME <petsciigraphicstring> in PETSCII graphics mode.

At one time I must have come across a Forth that uses DO<name> for internals, since that I what I mostly have ... DOLOOP DOLIT etc. ... but one of the conventions I might use to save a scattered byte here or there is to use the leading underscore for the internals ... _LOOP _LIT etc.

In PETSCII, that underscore character is a right pointing arrow, which kind of works.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Testing CREATE DOES>

Post by JimBoyd »


The internals for the DO LOOPs and a few others now have the same name as the compiling words in my Forth.
The internal for DO is DO and the internal for LOOP is LOOP to name just two. This is because an internal does not normally need found once its compiling word is defined.
Post Reply