6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Sep 21, 2024 5:08 pm

All times are UTC




Post new topic Reply to topic  [ 354 posts ]  Go to page Previous  1 ... 12, 13, 14, 15, 16, 17, 18 ... 24  Next
Author Message
PostPosted: Thu Dec 16, 2021 5:35 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8510
Location: Southern California
My :NONAME is defined as:
Code:
: :NONAME       ( -- addr )                                     \   ANS_CORE_EXT
   ?EXEC
   ALIGN  HERE
   DEPTH  CSP !
   ['] nest ,
   ]            ;

but I never thought of making it work with RECURSE. Anyway, all it compiles is the CFA of nest.

_________________
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: Fri Dec 17, 2021 10:11 pm 
Offline

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

Here is the version of :NONAME I'm considering adding to Fleet Forth's system loader.
Code:
: ALIGN  ( ADR1 -- ADR2 )
   HERE 1+ SPLIT DROP 0= ABS ALLOT ;
// DUMMY TARGET TO UNSMUDGE
HERE >A  0 C,
: :NONAME  ( -- ADR )
   ALIGN  HERE  DUP (IS) LAST
   CURRENT @ CONTEXT !
   [ A> ] LITERAL TRUE
   [ ' : @ ] LITERAL , ]       ;

This version of align doesn't align to an even address. It will allot one byte if the address is of the form $xxFF. The C64 uses the 6510 processor which has the infamous indirect jump bug.
Fleet Forth doesn't save the stack depth for colon or code words. The address to unsmudge and the value of true are pushed on the stack for compiler security. The one byte allotted prior to the definition of :NONAME provides a safe address for semicolon to unsmudge. Here are Fleet Forth's : and ; .
Code:
: :  ( -- ADR TRUE )
   ] CREATE  LATEST
   TRUE OVER TSB
   CURRENT @  CONTEXT !
   ;CODE
   IP 1+ LDA  PHA
   IP    LDA  PHA
   CLC
   2 # LDA  W    ADC  IP    STA
       TYA  W 1+ ADC  IP 1+ STA
   NEXT JMP  END-CODE

: ?PAIRS  ( N1 N2 -- )
   <>
   ABORT" STRUCTURE MISMATCH" ;
: ;  ( ADR TRUE -- )
   COMPILE EXIT
   [COMPILE] [
   TRUE ?PAIRS  TSB ; IMMEDIATE

TSB takes an address and toggles the smudge bit at that address.
Code:
// TOGGLE SMUDGE BIT
: TSB  ( ADR -- )
   SBIT TOGGLE ;

As for the ability to support recursion in a headerless word, Fleet Forth has the word VOCS to display the vocabulary tree. VOCS uses the recursive word .VOCS . .VOCS could be made headerless.
Code:
// .VOCS WITHOUT A NAME
:NONAME  ( PFA CNT -- )
   ?STACK
   DUP>R CR SPACES
   DUP BODY> >NAME ID.  VOC-LINK @
   BEGIN
      2DUP 2- @ =
      IF
         DUP 2- 2- R@ 2+ RECURSE
      THEN
      @ ?DUP 0=
   UNTIL
   R> 2DROP ;

and used like this.
Code:
>A
: VOCS
   [ ' FORTH >BODY ] LITERAL 0
   [ A> , ]  CR ;

Or if there is no aux stack.
Code:
: VOCS
   [ ' FORTH >BODY ] LITERAL 0
   [ ROT , ] CR ;

Here is a definition for CNONAME , a word which is used to create headerless code words.
Code:
: CNONAME  ( -- ADR ) // CODE DEF
   :NONAME  [COMPILE] [
   ASSEMBLER [ ASSEMBLER ] MEM
   LAST 2+ LAST ! ; // OVERWRITE CFA

Although I doubt I would need CNONAME .
LAST is handy if there is an error while compiling. The following will not compile successfully. There is no matching THEN .
Code:
:NONAME  ( N -- )
   2 MOD
   IF
      CR ." ODD"
   ELSE
      CR ." EVEN"
   ;

When the system aborts, the stacks will be cleared.
Code:
0 FH LOAD
SCR# 8489 LINE# 7
   ;
   ^
STRUCTURE MISMATCH
.S EMPTY  OK

If the definition was compiled from the command line, there will not even be source to examine; however, there is a LAST resort to (SEE) what went wrong.
Code:
LAST (SEE)

 23025  2262 2
 23027  5716 MOD
 23029  2749 ?BRANCH 23045
 23033  7052 CR
 23035  6741 (.") ODD
 23041  3043 BRANCH 0
 23045  7052 CR
 23047  6741 (.") EVEN
 23054  2949 EXIT
31
 OK

That BRANCH 0 shows that the ELSE was never resolved by a matching THEN .


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 17, 2021 10:23 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 890
IamRob wrote:
In stead of using :NONAME, can one not just use HERE, then write some code, leave HERE on the stack so that when some future word definition needs it, the address to return to is already there. You wouldn't even need to create a colon definition or use :NONAME.


:NONAME is used to create a headerless colon definition and some of the words in Fleet Forth's system loader are candidates. These colon definitions are complex enough that I would not want to rewrite them as code words, code words which would be much larger.

Quote:
It would just be:

Code:
HERE 0 , CODE
.
.
.
ENDCODE


The 0 , would be needed since CODE does a -2 allot, which stores the CFA which points to the PFA (or body) of a regular word definition. The address for HERE gets left on the stack and is used, when needed, in the assembler calculation. Which I believe needs to be HERE+2 to skip past the CFA pointer.


Using CODE to create a headerless code word doesn't work because CODE parses the text stream for a name and creates a header. 64Forth's CODE behaves the same way.
Code:
: CODE    ?EXEC   CREATE   [COMPILE] ASSEMBLER   MEM   !CSP   ;S IMMEDIATE

This is Fleet Forth's CODE
Code:
: SUBR  ( -- ADR TRUE )
   CREATE  LATEST TRUE
   OVER TSB
   [ ASSEMBLER ] ASSEMBLER MEM ;
: CODE  ( -- ADR TRUE )
   SUBR  HERE DUP 2- ! ;

Neither version has -2 ALLOT .
The word SUBR is for creating subroutines. Here is an example from Fleet Forth's kernel.
Code:
SUBR (>FORTH)  ( -- )
   CLC
   PLA  1 # ADC  N STA
   PLA  0 # ADC  TAY
   IP 1+ LDA  PHA
   IP    LDA  PHA
   N LDA
   IP    STA
   IP 1+ STY
   NEXT JMP  END-CODE

And its use in the assembler.
Code:
ASSEMBLER DEFINITIONS
: >FORTH  ( -- )
   ?EXEC
   (>FORTH) JSR
   CURRENT @ CONTEXT !
   ] ; IMMEDIATE
FORTH DEFINITIONS

Although (>FORTH) , and all SUBR words, return the address of the code, the code in (>FORTH) does not alter the data stack.

I've also looked at the fig-FORTH Installation Manual and it appears that version of CODE also creates a header.
Here is a test screen.
Code:
SCR# 8001
0: // TEST -- THIS IS GOING TO FAIL!
1: HERE 0 , CODE  ( N -- N+10 )
2:    CLC
3:    0 ,X LDA  10 # ADC  0 ,X STA
4:    TYA  1 ,X ADC  1 ,X STA
5:    NEXT JMP
6: END-CODE
7:
8:
9:
A:
B:
C:
D:
E:
F:

And the result of trying to load it.
Code:
0 FH LOAD
( EXISTS

SCR# 32769 LINE# 1
HERE 0 , CODE  ( N -- N+10 )
                   ^^
WHAT?

So CODE tries to redefine open parenthesis and the system aborts when double dash can't be found in the specified search order. Not surprising since double dash isn't defined in Fleet Forth.
One way to create a headerless code word in Fleet Forth would be the following.
Code:
ASSEMBLER MEM ALIGN  // NAMELESS CODE DEF -- INCONVENIENT
   HERE DUP 2+ ,
   $D020 INC
   NEXT JMP
   FORTH

I should mention that ALIGN does not align to an even address. If the address is of the form $xxFF, ALIGN allots one byte to push the address past the page boundary. This is done to avoid the indirect jump bug found in NMOS 6502s and the C64's 6510 processor.
Here is a way to create headerless subroutines in Fleet Forth. There is no CFA, just an address to to be used by JSR.
Code:
HERE ASSEMBLER MEM
   $D020 INC
   RTS
FORTH

Used like so.
Code:
>A                   \ push address to aux stack
CODE TEST
   A> JSR  NEXT JMP  \ pull it and use with JSR
   END-CODE



Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 25, 2021 2:14 am 
Offline

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

I've been entertaining some ideas on changing the working of INTERPRET which breaks the way INTERPRET would exit the interpret loop.
I already mentioned that Fleet Forth's WORD parses the text stream and returns the address of a counted string padded with a trailing blank as per the Forth-83 Standard. The address it returns is HERE . If the text stream is exhausted as WORD is called, then a count of zero followed by a trailing blank will result.
The find primitive, when checking a header for a match, checks the count and each character, using exclusive or, until it finds a non-match. The high bit of the last comparison is masked off ( $7F and). If this results in a match, the word was found. If not, follow the link to the next header, unless the link field has a value of zero. This is the shortest and fastest way I could write the search with a traditional dictionary with headers next to their respective code fields. Because of this behavior, if there is a name in the dictionary with just a count of zero and a blank space (both having the high bit set), it will be found when WORD is called on an empty text stream and the returned address is passed to FIND .
This was the means used to exit the interpreter in Fleet Forth. The mystery word was an immediate alias for EXIT which had no parameter field, just a code field which pointed to the body of EXIT .
My latest changes to Fleet Forth did away with that. The mystery word is now gone and INTERPRET checks the size of the string returned by WORD . If the size is zero, INTERPRET exits.
Here is the new INTERPRET .
Code:
// INTERPRET
: INTERPRET  ( -- )
   BEGIN
      PAUSE  NAME C@ 0EXIT
      HERE FIND ?DUP
      IF
         STATE @ =
         IF
            ,
         ELSE
            EXECUTE ?STACK
         THEN
      ELSE
         NUMBER? ?HUH ?STACK
         DPL @ 0<
         IF
            DROP STATE @
            IF
               [COMPILE] LITERAL
            THEN
         ELSE
            STATE @
            IF
               SWAP
               [COMPILE] LITERAL
               [COMPILE] LITERAL
            THEN
         THEN
      THEN
   AGAIN ;   -2 ALLOT

This version of INTERPRET is six bytes larger; however, removing the mystery word saves six bytes. So far, everything works fine.
This is what I'm going to try next:
Code:
DEFER I/C
: INTERPRET
   BEGIN
      PAUSE NAME C@ 0EXIT
      HERE I/C
   AGAIN ; -2 ALLOT

which is just a streamlined version of this:
Code:
DEFER I/C
: INTERPRET
    BEGIN
      PAUSE NAME DUP C@
    WHILE
      I/C
    REPEAT
    DROP ;

with the default vector for I/C :
Code:
: (I/C)  ( ADR -- ? )
   FIND ?DUP
   IF
      STATE @ =
      IF  , EXIT  THEN
      EXECUTE ?STACK  EXIT
   THEN
   NUMBER? ?HUH ?STACK  DPL @ 0<
   IF
      DROP STATE @ 0EXIT
      [COMPILE] LITERAL  EXIT
   THEN
   STATE @ 0EXIT  SWAP
   [COMPILE] LITERAL
   [COMPILE] LITERAL ;

This latest modification will allow me to remove some of the 'tricky code' from the metacompiler. I wrestled with this for a while because the metacompiler is not a part of Fleet Forth for normal day to day use. It's more like an application written in Fleet Forth to build new versions of the kernel. The metacompiler is already large and reducing a little complexity in it at the expense of even a little bit larger Fleet Forth didn't seem worthwhile. I'm investigating this newest version of Fleet Forth's interpreter not just for the benefit of the metacompiler, but because it will open up other possibilities as well.
[Edit: Minor correction. It's the metacompiler's complexity which could be reduced, not necessarily its size.]


Last edited by JimBoyd on Sun Dec 26, 2021 7:33 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 25, 2021 2:26 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 890
JimBoyd wrote:

Here is the version of :NONAME I'm considering adding to Fleet Forth's system loader.
Code:
: ALIGN  ( ADR1 -- ADR2 )
   HERE 1+ SPLIT DROP 0= ABS ALLOT ;
// DUMMY TARGET TO UNSMUDGE
HERE >A  0 C,
: :NONAME  ( -- ADR )
   ALIGN  HERE  DUP (IS) LAST
   CURRENT @ CONTEXT !
   [ A> ] LITERAL TRUE
   [ ' : @ ] LITERAL , ]       ;



There is a slight error in the stack comment for :NONAME . The actual stack comment should be
( -- ADR ADR2 TRUE )
ADR2 and TRUE are consumed by semicolon . ADR2 is the address of an unused byte, a safe target semicolon can 'unsmudge'. After semicolon executes, ADR, the address of the nameless word's code field, is the only one of the three parameters left on the stack
For comparison, here is the stack effect for colon.
( -- LATEST TRUE )
[Edit: corrected an error. EXIT does not consume anything from the stack. It pulls an address off the return stack and places it in IP .
Code:
: ?PAIRS  ( N1 N2 -- )
   <>
   ABORT" STRUCTURE MISMATCH" ;
: ;  ( ADR TRUE -- )
   COMPILE EXIT
   [COMPILE] [
   TRUE ?PAIRS  TSB ; IMMEDIATE



Last edited by JimBoyd on Sun Jan 09, 2022 7:04 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 30, 2021 1:52 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 890
JimBoyd wrote:

This is what I'm going to try next:
Code:
DEFER I/C
: INTERPRET
   BEGIN
      PAUSE NAME C@ 0EXIT
      HERE I/C
   AGAIN ; -2 ALLOT

which is just a streamlined version of this:
Code:
DEFER I/C
: INTERPRET
    BEGIN
      PAUSE NAME DUP C@
    WHILE
      I/C
    REPEAT
    DROP ;

with the default vector for I/C :
Code:
: (I/C)  ( ADR -- ? )
   FIND ?DUP
   IF
      STATE @ =
      IF  , EXIT  THEN
      EXECUTE ?STACK  EXIT
   THEN
   NUMBER? ?HUH ?STACK  DPL @ 0<
   IF
      DROP STATE @ 0EXIT
      [COMPILE] LITERAL  EXIT
   THEN
   STATE @ 0EXIT  SWAP
   [COMPILE] LITERAL
   [COMPILE] LITERAL ;



I've made this change to Fleet Forth and it works great. Since FIND is in (I/C) rather than INTERPRET , (I/C) and any other vector used with the deferred word I/C takes the string address returned by BL WORD .
I mentioned multi line comments and the word COMMENT: in another post. The drawbacks to this version of COMMENT: are that it is case sensitive in a case insensitive Forth and it only works within the current text stream. This is more than sufficient if loading source from blocks; however, Fleet Forth also has the ability to include source from Commodore 64 sequential files (C64 version of text files).
Code:
" FILENAME" INCLUDE

The given file is included one line at a time. The original version of COMMENT: will not work with multi line comments in ordinary text files because the file is interpreted/compiled one line at a time, just like text typed in from the keyboard.
Fleet Forth's new INTERPRET allows an elegant solution.
Code:
// MULTI LINE COMMENTS
: MLC  ( ADR -- )
   9 " ;COMMENT" TEXT= 0EXIT
   ['] (I/C) IS I/C ;
: COMMENT:  ( -- )
   ['] MLC IS I/C ; IMMEDIATE

If the word COMMENT: is encountered, it sets I/C to MLC (Multi Line Comment). MLC checks if the string returned by BL WORD is ';COMMENT' . If it is, MLC sets I/C back to (I/C) .
This version of multi line comments will span multiple lines in a text file. It will even span multiple blocks loaded with THRU . I have also tested it by typing COMMENT: at the Forth's command line. Nothing else typed has any effect until I type ;COMMENT . It even displays the 'OK' prompt if in interpreting state.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 7:53 am 
Offline

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

I just noticed in the Ans Forth Standard, the word INCLUDE parses the text stream for a file name and the word INCLUDED takes the address and count of a string for the file name.
Fleet Forth's INCLUDE was written to take the address of a counted string.
I've redefined Fleet Forth's INCLUDE so it too parses the text stream.
I still have not made Fleet Forth's INCLUDE nestable and I'm not sure if I will.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 12:00 am 
Offline

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

Here are words for conditional compilation using Fleet Forth's redesigned interpreter. The code was inspired by the conditional compilation words in the Ans Forth Standard.
Code:
// CONDITIONAL COMPILATION
: <IF>  ( NL1 ADR -- NL2 )
        ( NL1 ADR -- )
   DUP  5 " [IF]"   TEXT= ABS UNDER+
   DUP  7 " [THEN]" TEXT= UNDER+
        7 " [ELSE]" TEXT= OVER 1 =
   AND +  ?DUP ?EXIT
   ['] (I/C) IS I/C ;
: [THEN] ; IMMEDIATE
: [ELSE]  ( -- )
   1  ['] <IF> IS I/C ; IMMEDIATE
: [IF]  ( FLAG -- )
   ?EXIT
   [COMPILE] [ELSE] ; IMMEDIATE

The string left on the stack for I/C is a counted string and so is a string compiled by " .
TEXT= is used to compare strings. It takes the address of one string, the length to compare, and the address of a second string. It is normally used in MATCH where a sub string is sought in a larger string.
For this application an exact match is sought so that, for example, the string '[THEN]AGAIN' isn't mistaken for the string '[THEN]'. This is why counted strings are used and the size of the comparison for each string is one byte larger than the string. The count byte is treated as part of the string for the comparison. TEXT= doesn't check for valid PETSCII characters. It just compares a certain number of bytes at two addresses for equality.
The conditional compilation words can span multiple blocks or, more importantly, multiple lines in a sequential file (C64 text file).


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 12:41 am 
Offline

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

I'd like to mention something for those new to Forth. With a Forth-83 Standard system, and maybe a few others, it should be possible to experiment with new interpreter ideas without the need to rebuild the system. Just define the new INTERPRET then load the source for QUIT . Here is a fairly generic QUIT .
Code:
: QUIT  ( -- )
   [COMPILE] [
   BEGIN
      RP! CR QUERY INTERPRET
      STATE @ 0=
      IF  ."  OK"  THEN
   AGAIN ;

Some of you may have noticed that QUIT doesn't set BLK to zero. I've made the assumption that QUERY sets BLK , as well as >IN , to zero like it does in Fleet Forth.
Just type QUIT and the new QUIT loop is running. If there is an ABORT the old quit loop will be running.
Don't forget to type ABORT before forgetting the new words.
Experimenting with a new interpreter can be risky, so caution is advised. This will make Fleet Forth unresponsive.
Code:
' DROP IS I/C

It will still display the 'OK' prompt. It just won't do anything. This is remedied with the run/stop restore key combination. As a precaution, I added I/C to the table of deferred words which will be reset when a warm start happens. A warm start can be caused by pressing the run/stop and restore keys at the same time. The restore key generates a non-maskable interrupt, so this key combination is also useful to get out of an endless loop.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 17, 2022 11:25 pm 
Offline

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

I have removed the following user variables from Fleet Forth:
SPLIM The full mark for the data stack.
APLIM The full mark for the auxiliary stack.

When I originally included these variables, the idea was that each task would be able to perform a stack check. This is fine for a system with multiple users; however, Fleet Forth only supports background tasks in addition to the main task. While working with my multitasker, I found that I do not need them. Since background tasks do not run a quit loop, no stack bounds checking is performed. Obviously, code run by a background task needs tested in the main task before it is set to run in the background.
For stack checking in the main task, ?STACK was rewritten so that SPLIM is no longer needed.
Code:
: ?STACK  ( -- )
   DEPTH 0<
   ABORT" STACK EMPTY!"
   >ASSEM
   SP.LIMIT # CPX
   NEXT.JMP CS BRAN
      >FORTH  TRUE
      ABORT" STACK FULL!" ;
   -2 ALLOT

SP.LIMIT is a metacompiler macro.
Code:
" $1E"  COUNT MACRO SP.LIMIT

A metacompiler macro is a word with a string which is evaluated when the macro is executed. The macros for the Fleet Forth kernel are all defined on screens 2 and 3 of the kernel source.
As for APLIM , the primitives which move data to and from the auxiliary stack perform stack bounds checking. This is necessary since the return stack resides just below the auxiliary stack and above the auxiliary stack are the tables the C64 Kernal uses to keep track of open files.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 17, 2022 11:37 pm 
Offline

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

As written, COMMENT: is not nestable; however, multiple occurrences of COMMENT: can all terminate with a single ;COMMENT as in the following screen.
Code:
0: // 4# .BIT .BITS <[ ]>
1: : 4#  ( -- )  4 0 DO  #  LOOP ;
2: : .BIT  ( N -- )
3:    RB  2 BASE !
4:    0 <# 4# BL HOLD 4# BL HOLD
5:         4# BL HOLD 4# #> TYPE ;
6: : .BITS   ( N1 ... NM M -- )
7:    0  ?DO  ?STACK CR .BIT  LOOP ;
8: : <[   SP@ >A ;
9: : ]>   SP@ A>  SWAP - DUP 0<
A:    ABORT" STACK?"  2/ ;
B: COMMENT: TEST1
C: RB  DECIMAL TRUE <[ 21 73 37 12 ]> .BITS  CR .S SP!
D: COMMENT: TEST2
E: 1 2 3 <[ CR .S DROP CR .S ]>
F: ;COMMENT

Neither test case will run when this screen is loaded; however, they can be run individually with the appropriate LINELOAD as shown in this log file.
Code:
 OK
$C 0 FH LINELOAD
0000 0000 0000 1100
0000 0000 0010 0101
0000 0000 0100 1001
0000 0000 0001 0101
65535  OK
$E 0 FH LINELOAD
    1     2     3
    1     2
SCR# 4166 LINE# 14
1 2 3 <[ CR .S DROP CR .S ]>
                          ^^
STACK?
CONSOLE



Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 01, 2022 1:48 am 
Offline

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

Here is the screen defining the constants used in Fleet Forth's assembler:
Code:
// SYSTEM CONSTANTS
HEX
  85 CONSTANT N   8D CONSTANT XSAVE
  8E CONSTANT UP  FB CONSTANT IP
  FE CONSTANT W
      A4F CONSTANT PUSH
      A56 CONSTANT NEXT
      A81 CONSTANT SETUP
' 2DROP @ CONSTANT POPTWO
  PUSH 2+ CONSTANT PUT
POPTWO 2+ CONSTANT POP
 ' 1 @ 2+ CONSTANT APUSH
 APUSH 2+ CONSTANT AYPUSH
AYPUSH 2+ CONSTANT AYPUT

The first five constants are set by design. The value of the others can change depending on how I modify the source for the kernel. Of the constants that are not set by the system design, three where not defined in terms of other constants. As a result, the last step of metacompiling was to insert the system loader disk and load this screen, then issue the metacompiler command ASSEM-CONSTANTS and edit the screen as necessary.
I was able to do something about that and I don't know why it didn't occur to me sooner.
NOOP is a no op defined in Fleet Forth. It is to give some of the deferred words, such as PAUSE , nothing to do. NOOP is a code word with no body. It's code field points directly to NEXT. PUSH is exactly seven bytes before NEXT. CLIT is a code word with a six byte body and the subroutine SETUP follows CLIT in memory.
Here is the modified screen.
Code:
// SYSTEM CONSTANTS
HEX
  85 CONSTANT N   8D CONSTANT XSAVE
  8E CONSTANT UP  FB CONSTANT IP
  FE CONSTANT W
  ' NOOP @ CONSTANT NEXT
  NEXT 7 - CONSTANT PUSH
' CLIT 8 + CONSTANT SETUP
 ' 2DROP @ CONSTANT POPTWO
   PUSH 2+ CONSTANT PUT
 POPTWO 2+ CONSTANT POP
  ' 1 @ 2+ CONSTANT APUSH
  APUSH 2+ CONSTANT AYPUSH
 AYPUSH 2+ CONSTANT AYPUT



Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 15, 2022 2:43 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 890
JimBoyd wrote:
In another thread,
GARTHWILSON wrote:
Jim, you have quite a few words above that are neither part of any standard I know of, nor defined above. One I'll ask about however is REDEFINE:. It appears to edit the old word to redirect execution to the new one, for secondaries that are already compiled using it, so those secondaries don't need to be recompiled.. Is that what's happening? I've had a way to do that but I like yours more.


I haven't written a word to implement this, but I implemented the idea in my metacompiler. I make use of >FORTH since it is already in Fleet Forth.


And here is a quick implementation of this idea. It does not redirect execution to another name, nor does it create a new name. It just redirects the execution of the old word to a new body. Fleet Forth's END-CODE and ; both need an address to unsmudge and TRUE on the stack. A dummy address is provided since no new name is created.
Code:
HERE 0 C, >A
: REDEFINE  ( -- ADR TRUE )
   HERE ' !
   ASSEMBLER [ ASSEMBLER ] MEM
   [ A> ] LITERAL TRUE ;

This will redirect execution to a new code word without a name or code field of its own. With >FORTH , the code word can become a high level word. Here is an example.
Code:
: TEST  ( -- )
   CR ." TEST FINISHED." ;
: RUN.TEST  ( -- )
   TEST ;
REDEFINE TEST
   >FORTH
   CR ." START TEST." ;

The old behavior can be appended to the new word with a BRANCH.
Code:
: TEST  ( -- )
   CR ." TEST FINISHED." ;
: RUN.TEST  ( -- )
   TEST ;
REDEFINE TEST
   >FORTH
   CR ." START TEST."
   BRANCH [ ' TEST >BODY , ] ;



Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 20, 2022 8:30 pm 
Offline

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

Notice that in the source for REDEFINE , the context VOCABULARY was set to ASSEMBLER , to include words from the ASSEMBLER vocabulary, and not set back to FORTH ; however, the definition for REDEFINE and the test words were on the same screen and colon sets the CONTEXT vocabulary equal to the CURRENT vocabulary, at least in Fleet Forth and Blazin' Forth.
I recently realized I don't even need to waste a byte of memory as an address for semicolon to 'unsmudge'. Once a code word like TOGGLE (or any of the memory access words) is executing, the W register is not needed until NEXT uses it. Here is a version of REDEFINE which uses the W register. The double slash ( // ) is for end of line comments just like backslash ( \ ).
Code:
: REDEFINE  ( -- ADR TRUE )
   // <NAME>
   HERE ' !
   ASSEMBLER [ ASSEMBLER ] MEM
   W  TRUE ;
FORTH

It is used just like the other version.
Here is a version which is not dependent on knowledge of the workings of colon and semicolon, so it is more portable. It does create a new name in the dictionary, but is still used the same.
Code:
: REDEFINE  ( -- ADR TRUE )
   // <NAME>
   >IN @ >R  CODE  R> >IN !
   HERE ' ! ;

Here is a version which takes a new name and the old name to redefine.
Code:
: REDEFINE  ( -- ADR TRUE )
   // <NEW NAME>  <OLD NAME>
   CODE  HERE ' ! ;
: TEST  ( -- )
   CR ." TEST FINISHED." ;
: RUN.TEST  ( -- )
   TEST ;

So it is used a little differently.
Code:
REDEFINE TEST2 TEST
   >FORTH
   CR ." START TEST."
   BRANCH [ ' TEST >BODY , ] ;

The BRANCH is optional if the original behavior of the word is not to be appended to the new behavior.
Code:
REDEFINE TEST2 TEST
   >FORTH
   CR ." START TEST." ;

With this version of REDEFINE , TEST has the behavior of TEST2 and both names are visible in the dictionary. They are aliases of each other.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 10, 2022 2:37 am 
Offline

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

I'm considering making a slight change to Fleet Forth's interpreter. The word (I/C) would change from this:
Code:
: (I/C)  ( ADR -- )
   FIND ?DUP
   IF
      STATE @ =
      IF  , EXIT  THEN
      EXECUTE ?STACK  EXIT
   THEN
   NUMBER? ?HUH ?STACK  DPL @ 0<
   IF
      DROP STATE @ 0EXIT
      [COMPILE] LITERAL  EXIT
   THEN
   STATE @ 0EXIT  SWAP
   [COMPILE] LITERAL
   [COMPILE] LITERAL ;

to this:
Code:
: (I/C)  ( ADR -- )
   FIND ?DUP
   IF
      STATE @ 0<> =
      IF  , EXIT  THEN
      EXECUTE ?STACK  EXIT
   THEN
   NUMBER? ?HUH ?STACK  DPL @ 0<
   IF
      DROP STATE @ 0EXIT
      [COMPILE] LITERAL  EXIT
   THEN
   STATE @ 0EXIT  SWAP
   [COMPILE] LITERAL
   [COMPILE] LITERAL ;

The inclusion of 0<> after STATE @ would allow INTERPRET to work even if STATE has a true value other than -1. Although it adds two bytes and slightly more time ( one extra pass through NEXT ) , it would be more robust. Normally only ] and [ set the value of STATE , so this might be needlessly redundant. Then again, Murphy's law.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 354 posts ]  Go to page Previous  1 ... 12, 13, 14, 15, 16, 17, 18 ... 24  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 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: