Reflection in a BASIC program

Basic and Machine Language

Moderator: Moderators

carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Perhaps you can have your DATA statements with graphic definitions at the end of your program. First you POKE them into memory as usual, then you change the pointer to end of Basic and start of variables so you'll effectively overwrite the former DATA statements with dynamic variables. It should probably be doable within one BASIC program and would free up some valuable memory.
Anders Carlsson

Image Image Image Image Image
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

eslapion wrote:[...]a self modifying BASIC programs is something I would instinctively expect to be incredibly difficult.

That's because BASIC is stored in memory in the form of tokens. In order to change these tokens, you have to know exactly at what address they are stored. This can instantly change if you change only one thing in one line of code [...]
Emphasis by me.

You can get by the necessary information, for example the start address of a BASIC line, with a little help. This serves to make the whole thing a little more robust against program changes in other lines.

The appended program utilises a small ML routine to locate a BASIC statement in memory, when its line number is given. The ML routine is POKEd in line 10, and put into the USR vector.

Lines 50, and 52 are modified with the sub-routine in line 90. LI$ is printed with 'CONT:' beforehand, and ':REM' afterwards. BASIC exits to direct mode, and issues a HOME, and RETURN from the keyboard buffer.

The complete line gets tokenized, CONT then continues execution in program mode.

In the following loop, the input buffer (without the 'CONT:') is copied into program memory, overwriting the old instructions. All variables are preserved!

The REM takes care, that the running program ignores all junk at the end of the line, if the newly inserted line is shorter. No test is made for an over-length line.

Another useful application for the ML routine is RESTORE <line>, which can now be done thus: 'AD=USR(LI)-1:POKE66,INT(AD/256):POKE65,AD-256*PEEK(66)'.

Code: Select all

10 FORT=0TO12:READA:POKE673+T,A:NEXT:POKE1,161:POKE2,2
11 DATA  32,247,215:REM JSR $D7F7 ; convert FAC#1 to integer in LINNUM
12 DATA  32, 19,198:REM JSR $C613 ; search for line number
13 DATA 164, 95    :REM LDY $5F
14 DATA 165, 96    :REM LDA $60
15 DATA  76,145,211:REM JMP $D391 ; convert integer in (A/Y) to float in FAC#1
16 :
20 LI=50:LI$="PRINT"+CHR$(34)+"FIRST I'LL COUNT FROM 1 TO 10."+CHR$(34):GOSUB90
21 LI=52:LI$="FORT=1TO10":GOSUB90
22 PRINT"{CLR}";:GOSUB50 
23 :
30 LI=50:LI$="PRINT"+CHR$(34)+"NOW BACKWARDS TO 1 AGAIN."+CHR$(34):GOSUB90
31 LI=52:LI$="FORT=10TO1STEP-1":GOSUB90
32 PRINT"{CLR}";:GOSUB50
33 :
40 END
41 :
50 PRINT"THIS MESSAGE WON'T BE PRINTED!":REM
51 GETA$:IFA$=""THEN51
52 FORT=10TO1STEP-1:REM
53 PRINTT
54 NEXT
55 GETA$:IFA$=""THEN55
56 RETURN
60 :
90 REM ** tokenize LI$, and copy to line LI
91 PRINT"{CLR}CONT:"LI$":REM":POKE631,19:POKE632,13:POKE198,2:END
92 PT=USR(LI)+4:PS=514
93 IFPEEK(PS)<>0THENPOKEPT,PEEK(PS):PS=PS+1:PT=PT+1:GOTO93
94 RETURN
98 :
99 REM ** EXAMPLE OF DYNAMIC CODE IN CBM BASIC, WRITTEN 2008 BY M. KIRCHER
Post Reply