Hallo,
die Überschrift sagt ja eigentlich schon alles.
Kann man innerhalb eines Basicprogramms (V2) löschen?
z.Bsp. Variablendelkarationen, Data-Zeilen, ...
und wenn 'ja', wie geht das?
Du bist in Begriff, Forum64 zu verlassen, um auf die folgende Adresse weitergeleitet zu werden:
Bitte beachte, dass wir für den Inhalt der Zielseite nicht verantwortlich sind und unsere Datenschutzbestimmungen dort keine Anwendung finden.
letzter Beitrag von BIF am
Hallo,
die Überschrift sagt ja eigentlich schon alles.
Kann man innerhalb eines Basicprogramms (V2) löschen?
z.Bsp. Variablendelkarationen, Data-Zeilen, ...
und wenn 'ja', wie geht das?
Genauso wie man BASIC Zeilen editiert.
Also zum komplett löschen einfach direkt die Zeilennummer eingeben, und RETURN drücken, weg ist die Zeile. Willst Du nur einen Teil der Zeile löschen, den Teil den man löschen will, mit DEL oder der Leertaste entfernen und dann RETURN drücken.
Oder hab ich die Frage jetzt komplett falsch verstanden?
Er möchte ja nicht im Direktmodus, sondern während der Programmausführung löschen. Selbstmodifizierender Code quasi.
Die einzige Möglichkeit, die mir als Laie einfällt wäre etwas aufwendig..
Ein gelegentlich verwendeter Trick für diverse Selbstmodifikation in BASIC ist, Direktmodusbefehle auf den Bildschirm zu schreiben, Cursor positionieren, ein paar "RETURN"-Zeichen in den Tastaturpuffer fummeln, so dass die Befehle (inklusive Rücksprung ins eigene Programm) automatisch ausgeführt werden.
Ist natürlich hässlicher Murks, weil es erstens sichtbar ist (kann man mit Farben tricksen) und zweitens ein wenig fragil...
Also bei DATA-Zeilen nehme ich an, dass gewisse DATA-Werte/-Zeilen inaktiv werden sollen, weil nicht mehr gebraucht? Da ist es vermutlich einfacher das DATA-Token im BASIC-Text durch z. B. ein REM-Token zu ersetzen und die DATA-Zeilen sind für das nächste RESTORE:READ ... nicht mehr vorhanden.
Wenn man die DATA-Zeilen am Anfang eines Programms positioniert kann man diese dann recht leicht identifizieren. Sonst muss man mit entsprechenden SYS-Aufrufen die Zeilenadresse ausfindig machen und da das erste Byte ansteuern und dort das erste Byte (was das DATA-Token sein solllte) ersetzen.
Sonst könnte man auch noch Zeilen durch Umsetzen der Link-Adresse (auf die folgende Zeile) so manipulieren, dass diese auf die übernächste Zeile zeigt und somit die neue Zeile "übergeht".
So richtig löschen, im Sinne von die Zeilen oder Zeiilenteile aus dem BASIC-Code zu entfernen, wäre schon recht aufwändig, würd ich meinen, aber wohl nur unter gewissen Umständen wirklich angebracht ...
Ein gelegentlich verwendeter Trick für diverse Selbstmodifikation in BASIC ist, Direktmodusbefehle auf den Bildschirm zu schreiben, Cursor positionieren, ein paar "RETURN"-Zeichen in den Tastaturpuffer fummeln, so dass die Befehle (inklusive Rücksprung ins eigene Programm) automatisch ausgeführt werden.
Ist natürlich hässlicher Murks, weil es erstens sichtbar ist (kann man mit Farben tricksen) und zweitens ein wenig fragil...
Okay...
Ziel wäre, hinterher mehr Speicher zur Verfügung zu haben als die Löschzeilen in Anspruch nehmen.
Ziel wäre, hinterher mehr Speicher zur Verfügung zu haben als die Löschzeilen in Anspruch nehmen.
Wenn DATA-Zeilen am Ende positioniert werden, kann man das BASIC-Text-Ende anpassen und mit CLR den Interpreter das verkürzte Programm zur Verfügung stellen. Das geht wirklich nur bei DATA-Zeilen mit Daten, die etwa in Speicher ge-POKE-t werden, da Variablen damit zerstört werden.
Welche Daten sollen das sein?
Ziel wäre, hinterher mehr Speicher zur Verfügung zu haben als die Löschzeilen in Anspruch nehmen.
Ein Lösungsvorschlag (aber halt nicht das, wonach du gefragt hast):
Die DATAs in eine Datei schreiben und statt DATAs im Programm zu lesen, die Daten von dort zu holen.
Dann benötigst du nur den Speicher für die Variablen selber, aber der Programmcode bleibt klein.
JeeK Ja, dass könnte es schon sein.
Mir ist bei einem VC20-Programm aufgefallen, dass ich vor dem Start noch rel. viel Speicher zur Verfügung habe.
Nachdem ein eigener Zeichensatz geladen und vorallem alle Variablen deklariert sind, wird es schon eng.
Alles rund um den Zeichensatz kann nach dem Laden ja eigentlich weg.
Die Idee war:
- den Zeichensatz zu laden
- die DATA-Zeilen und die Laderoutine zu "löschen"
- um mehr freien Speicher für die Variablen zu haben
Wenn ich dich richtig verstehe meinst du sowas wie:
LB & HB für die POKE-Zeilen durch Rumprobieren rausfinden?
[EDIT] Goodwell Ja, das ist natürlich eine Möglichkeit aber ich wollte es mit einem One-FILEr probieren.
Den Onefiler kann man auch aus mehreren Teildateien per Exomizer oder einem anderen Packer erzeugen:
https://www.c64-wiki.de/wiki/E…_mit_BASIC-Start_versehen
(geht auch mit BASIC+Zeichensatz o.ä. als Input-Dateien)
Ja, das wäre PRG-Zeilen löschen bei der Installation.
Wenn z.B. die DATA-Zeilen am Ende stehen geht das gar nicht so schwer.
Man berechnet die Zeilenadresse, ab der gelöscht werden kann, setzt zwei Nullbytes, eines reicht glaub ich auch, und setzt dann die PRG-END-Adresse und macht ein CLR.
Schönen Gruß.
Alles anzeigenJa, das wäre PRG-Zeilen löschen bei der Installation.
Wenn z.B. die DATA-Zeilen am Ende stehen geht das gar nicht so schwer.
Man berechnet die Zeilenadresse, ab der gelöscht werden kann, setzt zwei Nullbytes, eines reicht glaub ich auch, und setzt dann die PRG-END-Adresse und macht ein CLR.
Schönen Gruß.
Gute Idee!
Oh, und was natürlich auch geht, wenn man einen Onefiler will aber irgendwie keinen Exomizer o.ä. mag: Alles in VICE laden, VICE-Monitor öffnen, bank ram, save "onefiler.prg" 0 0801 cfff (ggf. mit angepasster Endadresse statt cfff und "8" statt "0", wenn man ins Diskettenimage und nicht ins Host-Dateisystem schreiben will). Das schreibt dann einfach ein Speicherabbild so wie's ist in ein ladbares Programm und funktioniert auch mit Daten unterm BASIC-ROM. Geht auch analog mit diversen Monitoren direkt auf dem C64.
Ansonsten (wenn man alles in BASIC halten will) gibt's auch speicherplatzsparende Möglichkeiten, Daten in DATA-Zeilen unterzubringen, da gab's hier auch letztens einen Thread zu. Alles besser und robuster als "selbstmodifizierender" BASIC-Code...
Mit folgendem Gerüst, schneidet man die Zeilen nach Zeile 999 ab.
Bei Zeile 10 beginnt das eigentliche Hauptprogramm.
Bei Zeile 1000 die Initialisierungsroutine, die einmalig - in diesem Fall die DATA-Zeilen verarbeitend - "initialisiert".
Wenn man das Programm ein weiteres Mal aufruft, ist dann alles nach 999 weg. Die Daten sollten dann bereits irgendwo im Speicher liegen (Maschinencode, Spritedaten etc.). In Variablen einlesen bringt hier nichts, da zum Korrigieren aller entsprechenden Zeiger per CLR alle Variablen und Array gelöscht werden.
In Zele 999 wird der CHRGET-Zeiger ausgelesen, der dann in 990 in Variable A zum Zeilenanfang umgerechnet wird. Zum Zeitpunkt des PEEK() befindet sich der CHRGET-Zeiger nach der geschlossenen Klammer. Da zwischen den beiden PEEKs eine Page-Grenze liegen könnte, erfolgt die Korrektur mit dem L>246 Ausdruck (der -1 wird, was das High-Byte korrigiert, weil es dann schon um eine Page höher liegt).
Für das Erstellen eines Onefilers gibt es mehrere Möglichkeiten, klingt hier im Thread ja auch schon an.
Für die Entwicklungsphase reicht ein
oder besser:
(um nur ein mal nachzuladen, bei weiteren Startversuchen dann nicht mehr).
Um aus Programm und Zeichensatz dann einem Onefiler zu erstellen, nutzt man einen Packer. Oder man lädt den Zeichensatz an den Anfang des BASIC-Programms und manipuliert die entsprechenden Zeiger in der Zeropage beim letzten Speichervorgang. Oder... usw. usf. Ist alles erheblich eleganter und weniger fehleranfälliger als ein selbstmodifizierendes BASIC-Programm.
Mit folgendem Gerüst, schneidet man die Zeilen nach Zeile 999 ab.
Bei Zeile 10 beginnt das eigentliche Hauptprogramm.
Bei Zeile 1000 die Initialisierungsroutine, die einmalig - in diesem Fall die DATA-Zeilen verarbeitend - "initialisiert".
Wenn man das Programm ein weiteres Mal aufruft, ist dann alles nach 999 weg. Die Daten sollten dann bereits irgendwo im Speicher liegen (Maschinencode, Spritedaten etc.). In Variablen einlesen bringt hier nichts, da zum Korrigieren aller entsprechenden Zeiger per CLR alle Variablen und Array gelöscht werden.
Alles anzeigenCode
- 1 gosub 999: clr
- 10 print "hauptprogramm"
- 99 end
- 990 a=l+((l>246)+h)*256-12: rem zeilenstart
- 991 b=peek(a)+256*peek(a+1): rem folgezeile
- 992 if peek(b+1) then gosub 1000: rem einmalig initialisieren
- 993 pokeb,0: pokeb+1,0: rem programm abschneiden
- 994 return
- 999 l=peek(122):h=peek(123): goto 990
- 1000 for i=1 to 2: reada$: printa$: next: return
- 1100 data "erste datazeile"
- 1110 data "noch eine datazeile"
In Zele 999 wird der CHRGET-Zeiger ausgelesen, der dann in 990 in Variable A zum Zeilenanfang umgerechnet wird. Zum Zeitpunkt des PEEK() befindet sich der CHRGET-Zeiger nach der geschlossenen Klammer. Da zwischen den beiden PEEKs eine Page-Grenze liegen könnte, erfolgt die Korrektur mit dem L>246 Ausdruck (der -1 wird, was das High-Byte korrigiert, weil es dann schon um eine Page höher liegt).
Das muss ich mir in Ruhe anschauen.
Vielen Dank✌🏼
Wie liegt der Basic-Programmcode eigentlich im Speicher?
In der Reihenfolge der Zeilennummern, oder in der Reihenfolge, in der ich die Zeilen eingebe?
Wenn ich also die Programmzeilen 10 20 30 und 40 eingebe und anschließend die Zeile 5, liegt die Zeile 5 dann hinten im Speicher, oder wird der gesamte Programmcode dann neu sortiert und der Inhalt der Zeile 5 wandert nach ganz vorne und der Rest verschiebt sich im Speicher nach hinten?
Stelle mir das bei größeren Programmen recht rechenintensiv vor.
In der Reihenfolge der Zeilennummern, oder in der Reihenfolge, in der ich die Zeilen eingebe?
Ersteres.
Stelle mir das bei größeren Programmen recht rechenintensiv vor.
Ja
https://www.c64-wiki.de/wiki/Speicherbelegung_(BASIC)
https://www.c64-wiki.de/wiki/BASIC#Technische_Realisierung
Edit: Naja "Rechenintensiv". Es muss ja nur etwas RAM verschoben werden (das kann auch der C64 sehr schnell) und die Verkettungspointer aktualisiert werden. Zweiteres WÄRE auch schnell, wenn der Code clever statt platzeffizient geschrieben worden wäre.
Auf jeden Fall ist die Entscheidung, bei der Eingabe zu sortieren, wesentlich besser, als alles andere (LIST, GOTO, Ausführung generell) zu verlangsamen, weil die Interpreter letztendlich immer den ganzen Speicher nach der "richtigen" Zeile durchsuchen müsste...