6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Jun 06, 2024 8:44 pm

All times are UTC




Post new topic Reply to topic  [ 38 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject: Re: Self Modifying Code
PostPosted: Tue Nov 06, 2018 11:14 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
GARTHWILSON wrote:
How 'bout a separate SMC stack? It wouldn't need much space.

Not a separate SMC stack, a general purpose auxiliary stack, the aux stack.
There could be words to move single values from the data stack to the aux stack and back.
analogous to >R and R> they could be called >A and A>.
There could also be words to move two cells between the data and aux stacks 2>A and 2A>.
Words to move control flow data from the control flow stack ( which on most implementations is probably just the data stack ) to the aux stack could be CS>A and A>CS.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Wed Jan 16, 2019 9:51 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
I don't think SMC is as useful with high level code. The only example I could think of involves a deferred word's 'vector', for lack of a better word, setting the deferred word to another vector.
Case in point: Fleet Forth's (ABORT") , the word compiled by ABORT" , executes the word WHERE . WHERE shows the location of the error ( or tries to ). If loading a block causes an error, WHERE will try to load that block to show the error, causing yet another error ( recursively!)
One solution was to try something like the following:
Code:
DEFER (WHERE)
: SHOW.WHERE
   ['] NOOP IS (WHERE)
   // SHOW THE LOCATION OF THE ERROR
   //
   //
;
: WHERE
   (WHERE)
   ['] SHOW.WHERE IS (WHERE) ;

(WHERE) is set to a no-op by SHOW.WHERE . If an error occurs when SHOW.WHERE is running, WHERE gets executed, but does nothing more than reset (WHERE) back to SHOW.WHERE so it's ready for the next error.
It was actually easier to take care of this with a flag variable like so:
Code:
VARIABLE WHERE?  TRUE WHERE? !
: WHERE
   WHERE? @
   IF
      WHERE? OFF
      // SHOW THE LOCATION OF THE ERROR
      //
      //
   THEN
   WHERE? ON ;

So I'm not sure how useful self modifying high level Forth is. Does anyone have another example of high level Forth self modifying code?

Cheers,
Jim


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Fri Mar 29, 2019 9:02 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
What about manipulating the return stack to control program flow?
I was just reading Dynamically Structured Codes by M. L. Gassanenko. Does this count as self modifying code?


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Sat Mar 30, 2019 3:20 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3363
Location: Ontario, Canada
JimBoyd wrote:
What about manipulating the return stack to control program flow?
I can supply an example, and (unsurprisingly) it's rather odd. In FIG Forth, there's one particular word which contains the remarkable sequence R> DROP :shock: The purpose is to unwind the Return Stack and thus exit a BEGIN AGAIN loop that's in progress one level higher.

As we know, the stuff between BEGIN and AGAIN would ordinarily keep happening forever. But in this case, somewhere between BEGIN and AGAIN a condition is tested, and eventually the mystery word is allowed to execute, causing top-of-R to be dropped. Because it's a colon definition, the mystery word concludes with SEMIS which of course invokes the un-nest sequence. And instead of un-nesting to the mystery word's caller (ie, the word with the BEGIN AGAIN loop), we un-nest to that word's caller.

You might wonder whether the BEGIN AGAIN shouldn't just be replaced with a BEGIN WHILE REPEAT but this particular situation doesn't seem amenable to properly structured conditionals, and the R> DROP is used as a GOTO of sorts! A similar need may arise in other situations; I don't suppose the FIG example is unique.

That concludes the summary. To be explicit I'll need to identify the situation, and that entails explaining some cleverness in a different department. The word containing R> DROP has a name one character long, and that character is an ascii Null -- $00. Since Null is unprintable, the FIG Glossary lists the word as X, and interested parties can find it under that pseudonym.

As part of Forth's startup, QUIT calls INTERPRET and INTERPRET is the word with the BEGIN AGAIN loop I mentioned. The loop uses -FIND to get fragments of input text one by one and either compile or execute them. When no more text is available, a fetch from the buffer yields only a null, which is the end-of-buffer marker. -FIND dutifully does a search attempting to find a word in the dictionary named null, and the search is successful! Unprintable/X/Null is executed, and it's a case of, "Scotty, beam me up!" :P INTERPRET ceases to be real, and suddenly we're back in QUIT.

-- Jeff

( QUIT is in Screen 54 of the FIG Forth source. INTERPRET is in Screen 52, and X is in Screen 45.)

_________________
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  
 Post subject: Re: Self Modifying Code
PostPosted: Sun Mar 31, 2019 8:00 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
Fleet Forth does something similar. When WORD parses the text stream , whether a block, the text input buffer, or a string, it places a counted string at here and appends a blank. when the text stream is exhausted, word paces a count of zero and no characters, it still appends a blank. The blank name is found and it is immediate. In Fleet Forth, the blank name has a code field that points to EXIT , but no body, making it an alias for EXIT . Why waste memory on a colon definition when an alias for EXIT will work?
What about the technique used by M. L. Gassanenko? What do you think of it?


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Fri Apr 05, 2019 9:27 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
I don't want to get hung up on assembler control flow workarounds, but since SCAN and SKIP were already mentioned, here is what I think is the best solution since I added an Auxiliary stack to Fleet Forth.
Code:
SCR# 38
// SCAN
HEX
CODE SCAN  ( AD1 N1 C -- AD2 N2 )
   0= # LDA,   // LOAD D0 ( BNE )
   HERE 1+ >A
   BAD STA,
   3 # LDA,  SETUP JSR,
   AHEAD,
   BEGIN,
      N 4 + INC,
      0= IF,  N 5 + INC,  THEN,
      N 2+ LDA,
      0= IF,  N 3 + DEC,  THEN,
      N 2+ DEC,
   CS-SWAP THEN,
      N 2+ LDA,  N 3 + ORA,

SCR# 39
// SCAN SKIP
   0= NOT WHILE,
      N 4 + )Y LDA,  N EOR,  .A ASL,
   HERE A> !
   0= UNTIL,
   THEN,
   DEX,  DEX,
   N 4 + LDA,  0 ,X STA,
   N 5 + LDA,  1 ,X STA,
   N 2+ LDA,  PHA,
   N 3 + LDA,
   PUSH JMP,  END-CODE
CODE SKIP  ( A1 L1 C -- A2 L2 )
   0= NOT # LDA,   // LOAD F0 (BEQ)
   ' SCAN @ 2+ JMP,  END-CODE

Given the way my INTERPRET is defined ( with EXECUTE called by INTERPRET rather some word called by INTERPRET ) if I squeeze the code enough to fit both >A and A> on the same source screen I wouldn't even need to use the Auxiliary stack. It just wouldn't be portable.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Sun Jun 23, 2019 7:08 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
Dr Jefyll wrote:
JimBoyd wrote:
What about manipulating the return stack to control program flow?
I can supply an example, and (unsurprisingly) it's rather odd. In FIG Forth, there's one particular word which contains the remarkable sequence R> DROP :shock: The purpose is to unwind the Return Stack and thus exit a BEGIN AGAIN loop that's in progress one level higher.

Is it as odd as this example from M. L. Gassanenko's paper Dynamically Structured Codes ?
Code:
    : ENTER >R ; \ ( tcf-addr -- ) call the threaded code fragment at tcf-addr
    : SUCC COMPILE R@ COMPILE ENTER ; IMMEDIATE
    : FAIL COMPILE R> COMPILE DROP COMPILE EXIT ; IMMEDIATE
    : 1-10 ( --> i --- i --> ) \ generate numbers from 1 to 10
        0 BEGIN       1+ DUP 11 <
           WHILE      SUCC \ call the continuation, of type ( i -- i )
           REPEAT
           DROP
           FAIL ; \ exit the code fragment that contains the continuation
    : //2 ( i --> i --- i --> i ) \ filter even numbers
           DUP 2 MOD 0=
           IF     SUCC \ call the continuation, of type ( i -- i );
                       \ (in the case of //2 we could just exit)
           THEN
           FAIL ; \ exit the code fragment that contains the continuation
    : .even1-10 ( -- ) 1-10 //2 DUP . ;

.even1-10 yields:
Code:
    .even1-10 2 4 6 8 10    ok


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Apr 14, 2020 7:32 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
Fleet Forth has a word, WHERE , to show where an error occurred. If the value of BLK is zero, WHERE displays the string pointed to by TIB with the length stored in #TIB . If BLK is non zero, WHERE prints the block and line numbers and displays the text on that line. Since I/O is involved (if the block is not in memory) there is a possibility of WHERE causing another error which would lead to WHERE being called which would cause another error and so on.
The solution I went with looks like this:
Code:
NH VARIABLE WHERE?  TRUE WHERE? !
: WHERE  ( -- )
   WHERE? @ IF
      WHERE? OFF
      // The main body of WHERE
            .
            .
            .
   THEN
   WHERE? ON ;

NH is a metacompiler directive that makes the following word headless.
If any error occurs while WHERE executes, WHERE does nothing but set the variable WHERE? to true.
Here's a solution involving self modifying code:
Code:
HEX
: WHERE  ( -- )
   // SWITCH WHERE OFF
   ['] EXIT (IS) RECURSE
   // The main body of WHERE
         .
         .
         .

(IS) is the primitive compiled by IS and RECURSE compiles the CFA of the latest word so the phrase
Code:
   ['] EXIT (IS) RECURSE

makes EXIT the first word in the body of WHERE , effectively switching it off. All error handling in Fleet Forth eventually goes through ABORT . A slight modification to ABORT switches WHERE back on. The original ABORT :
Code:
: ABORT  ( -- )
   ERR SP! AP!
   QUIT ; -2 ALLOT

and the new version :
Code:
: ABORT  ( -- )
   ERR SP! AP!  ['] LIT (IS) WHERE
   QUIT ; -2 ALLOT

WHERE becomes eight bytes smaller while ABORT becomes eight bytes bigger. No net loss or gain there. The headless variable WHERE? is no longer needed for a total savings of four bytes.
By the way, the word ERR is a deferred word to allow extending the error handling. It is normally set to the word NOOP , a no-op.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Wed Apr 15, 2020 2:26 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
I recall QUAN structures in MMSForth, a syntactically cleaner albeit nonstandard replacement for VARIABLE. The way it worked in your code was:
Code:
quan foo
42 is foo
foo .
at foo .
: compiledfoo   ( -- )
   37 is foo   foo .    at foo . ;

Under the hood, FOO has three different code field addresses, and the words IS and AT are immediate words to select either the 'assignment CFA' or 'address-of CFA'. If neither IS nor AT prefixes FOO, then the 'value-of CFA' is used.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Mon Jun 15, 2020 7:54 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
chitselb wrote:
I recall QUAN structures in MMSForth, a syntactically cleaner albeit nonstandard replacement for VARIABLE. The way it worked in your code was:
Code:
quan foo
42 is foo
foo .
at foo .
: compiledfoo   ( -- )
   37 is foo   foo .    at foo . ;

Under the hood, FOO has three different code field addresses, and the words IS and AT are immediate words to select either the 'assignment CFA' or 'address-of CFA'. If neither IS nor AT prefixes FOO, then the 'value-of CFA' is used.

I was thinking that maybe instead of IS , use TO.
TO and AT would be used with QUAN's or any QUAN like word ( double QUAN's, floating point QUAN's , etc. ) and IS could still be used to set DEFERred words.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Jun 16, 2020 8:48 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
I was thinking that QUANs could be a replacement for variable if the default action is to return a QUAN's data's address ( like a variable ). TO could select the set value CFA and AT could select the fetch value CFA.
Code:
QUAN FOO
AT FOO U.  \ get the data AT FOO
137 TO FOO \ send the data TO FOO
FOO U.     \ where is the data ( just like VARIABLE )

Here is some prototype code I wrote last night.
Code:
SCR# 1076
// QUAN -- CODE FOR CODE FIELDS
HEX
SUBR DO.VAR
   CLC,
   6 # LDA,  W ADC,  PHA,
   TYA,   W 1+ ADC,
   PUSH JMP,  END-CODE
SUBR TO.Q
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' ! @ JMP,  END-CODE
SUBR AT.Q
   ' BL @ JMP,  END-CODE

SCR# 1077
// TO AT
HEX
// SET A QUAN
: TO ( N -- )  // PARSE TEXT STREAM
   2 ' DUP @ DO.VAR <>
   ABORT" NOT A QUAN"
   +  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE
// GET A QUAN'S VALUE
: AT  ( -- N )  // PARSE TEXT STREAM
   4 BRANCH [ ' TO >BODY 2+ , ] ;
   -2 ALLOT IMMEDIATE

SCR# 1078
// QUAN
HEX
: CFA-ALIGN
   >IN @ BL WORD  // AVOID INDIRECT
   SWAP >IN !     // JUMP BUG IN
   COUNT + 1 AND  // NMOS 6510
   ALLOT ;        // PROCESSOR
: QUAN
   CFA-ALIGN CREATE -2 ALLOT
   DO.VAR ,  TO.Q ,  AT.Q ,
   0 , ;
;S
CREATE MAKES SURE THE FIRST CFA
DOES NOT STRADDLE A PAGE BOUNDARY.
CFA-ALIGN HANDLES THE OTHER TWO.

SCR# 1079
// 2QUAN
HEX
SUBR TO.2Q
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2! @ JMP,  END-CODE
SUBR AT.2Q
   CLC,  DEX,  DEX,
   2 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2@ @ JMP,  END-CODE
: 2QUAN
   CFA-ALIGN  CREATE -2 ALLOT
   DO.VAR , TO.2Q ,  AT.2Q ,
   0 , 0 , ;

With this behavior, QUAN could be renamed VARIABLE and 2QUAN could be renamed 2VARIABLE. As long as TO and AT were not used, these versions of VARIABLE and 2VARIABLE would behave just like the original versions.
I was thinking about removing the ABORT" in TO and have it ( and AT ) execute or compile the word's only CFA if the word is not a 'QUAN' .
[Edit: fixed incorrect stack comment. TO does not return an address, it parses the text stream for the next word.]


Last edited by JimBoyd on Mon Jan 18, 2021 10:35 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Wed Jun 17, 2020 8:54 pm 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
There are some things I neglected to mention in my previous post.
The defining word SUBR creates a variable with no space alloted, but it switches on the assembler. A word created with SUBR returns its address.
The word CFA-ALIGN is only needed for Forth's running on NMOS 6502's or 6510's.
That funny looking word ;S ends loading of a block ( it's an alias for EXIT ).
And since this is for a Commodore 64, just read \ ( backslash ) for each // ( double forward slash ).
Here is the code for new style variables ( VARs ) cleaned up a little:
Code:

SCR# 1076
// VAR -- CODE FOR CODE FIELDS
HEX
: DO.VAR  // PRIMARY CODE FIELD
   ;CODE
   CLC,
   6 # LDA,  W ADC,  PHA,
   TYA,   W 1+ ADC,
   PUSH JMP,  END-CODE
SUBR TO.VAR
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' ! @ JMP,  END-CODE
SUBR AT.VAR
   ' BL @ JMP,  END-CODE

SCR# 1077
// TO AT
HEX
// SET A VAR
: TO ( N -- )
   ' DUP @ [ ' DO.VAR 4 + ] LITERAL
   <> ABORT" NO TO BEHAVIOR"
   2+  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE
// GET A VAR'S VALUE
: AT  ( -- N )
   ' DUP @ [ ' DO.VAR 4 + ] LITERAL
   <> ABORT" NO AT BEHAVIOR"
   2+ 2+  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE

SCR# 1078
// VAR
HEX
: CFA-ALIGN
   >IN @ BL WORD  // AVOID INDIRECT
   SWAP >IN !     // JUMP BUG IN
   COUNT + 1 AND  // NMOS 6510
   ALLOT ;        // PROCESSOR
: VAR
   CFA-ALIGN CREATE
   TO.VAR ,  AT.VAR ,
   0 ,  DO.VAR ;
;S
CREATE MAKES SURE THE FIRST CFA
DOES NOT STRADDLE A PAGE BOUNDARY.
CFA-ALIGN HANDLES THE OTHER TWO.

SCR# 1079
// 2VAR
HEX
SUBR TO.2VAR
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2! @ JMP,  END-CODE
SUBR AT.2VAR
   CLC,  DEX,  DEX,
   2 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2@ @ JMP,  END-CODE
: 2VAR
   CFA-ALIGN  CREATE
   TO.2VAR ,  AT.2VAR ,
   0 , 0 ,  DO.VAR ;

Since ANS Forth uses TO to set the data of a VALUE, if one wanted to ad ANS Forth style VALUEs to Forth:
Code:
: VALUE
   CONSTANT ;CODE
   ' BL @ JMP,
END-CODE
: TO   
   ' DUP VALUE-CFA <> // TEST IF NOT A VALUE
   IF   [COMPILE] TO EXIT  THEN
   // PERFORM VALUE RELATED BEHAVIOR
; IMMEDIATE

[Edit: I made some mistakes when changing the code. Sorry, I was away from my desktop. I've corrected the errors. Hopefully. I'm fighting with a weak data connection.]


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Jan 19, 2021 12:06 am 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
JimBoyd wrote:
I was thinking that QUANs could be a replacement for variable if the default action is to return a QUAN's data's address ( like a variable ). TO could select the set value CFA and AT could select the fetch value CFA.


At one time I thought that this behavior ( the default action being that of a VARIABLE rather than that of a VALUE would be the only easy way to tell if a word being parsed by TO or AT was a multi code field word. I no longer feel this is necessary.
I just realized that a clever implementation would allow TO and AT to fetch the address of the first code field, to get to the parent word, and backup to find if there is a word unique to multi code field defining words ( even if that word is a no-op ). This word's address could be the flag used to tell if a word is a multi code field word.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Mar 02, 2021 1:05 am 
Online

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

I'm not sure if this would qualify as self modifying code. The following word modifies itself without modifying the running code.
Fleet Forth has a word CHAR that is used by the following:
Code:
.(  (  ,"  "
.( ABC)  displays the string ABC
( ABC)  comment -- discards the string
," ABC"  compiles the string ABC
" ABC"   If interpreting, stores ABC as a counted string at PAD
         If compiling, compiles helper word (") and ABC as a counted string

CHAR takes the ASCII code for a character to use as a delimiter and parses the text stream until that delimiter is found. It returns the address and count of the string that was parsed. CHAR aborts with the following message if the delimiter was not found:
'X' MISSING
Where 'X' is the delimiter used. For example:
Code:
.( THIS IS A TEST
^^
) MISSING

This is the most streamlined version I had:
Code:
: CHAR  ( C -- ADR CNT )
   DUP>R HERE C!
   'STREAM 2DUP R>
   SCAN DUP 0=
   IF
      WHERE
      CR HERE C@ EMIT ."  MISSING"
      ABORT
   THEN
   ADJUST ;

This version is 13 bytes smaller
Code:
: CHAR  ( C -- ADR CNT )
   DUP>R LIT [ HERE >A 0 , ] C!
   'STREAM 2DUP R>
   SCAN DUP 0=
   [ HERE 3 + A> ! ]
   ABORT"   MISSING"
   ADJUST ;

CHAR modifies the inline text used by (ABORT") , which is compiled by ABORT" , by storing the ASCII code for the delimiter at the address of the first character of the string.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Sat Oct 29, 2022 12:38 am 
Online

Joined: Fri May 05, 2017 9:27 pm
Posts: 865
JimBoyd wrote:
What about manipulating the return stack to control program flow?
I was just reading Dynamically Structured Codes by M. L. Gassanenko. Does this count as self modifying code?


Since the actual code does not get modified, I have concluded that this is not self modifying code.


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

All times are UTC


Who is online

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