REM-Killer
Überflüssige REM-Anweisungen in Basic-Programmen lassen sich leicht entfernen. Dieses Programm rechnet aber zusätzlich alle Sprünge auf gelöschte REM-Zeilen um. Und das in wenigen Sekunden.
REM-Statements sind, vor allem für längere Basic-Programme, unumgänglich, um im relativ unübersichtlichen »Basic-Dschungel« den Überblick zu behalten. Spätestens dann, wenn an einem umfangreichen Programm nach einiger Zeit Änderungen erforderlich sind, wird auch der erfahrene Programmierer dankbar sein, wenn er seine Unterprogramme und undurchsichtigen PEEKs, POKEs und SYS-Befehle mit Hilfe von REMs noch durchschauen kann. Kurz gesagt, auch in sauber strukturierten Programmen gehört eine klare Dokumentation einfach dazu.
Das Problem mit den REMs
Leider haben REM-Statements die unangenehme Eigenschaft, Programme wesentlich zu verlängern und auch zu verlangsamen. Im Gegensatz zu einem Befehl (zum Beispiel POKE), werden REMarks nicht in einem Byte abgespeichert, sondern nehmen durch buchstabenweise Abspeicherung in ASCII-Codes eine Menge Platz weg. Am besten wäre daher, Basic-Programme mit ausführlicher REM-Dokumentation zu entwickeln und auch so zu speichern. Aus diesen »Quellprogrammen« können dann die REMs entfernt werden, um kürzere und schnellere »Lauf«-Versionen zu erhalten. Sollten später einmal Änderungen erforderlich werden, nimmt man diese am »Quellprogramm« vor und generiert daraus wiederum das »Laufprogramm«.
Da es sehr umständlich ist, die REMs in Handarbeit zu entfernen, braucht man ein Programm, das einem diese Arbeit abnimmt. Wozu hat man schließlich einen Computer. Das Programm sollte sehr schnell und unkompliziert zu bedienen sein; es sollte ferner Sprünge auf Zeilen, die mit einem REM beginnen (und daher vollständig gelöscht werden) korrigieren. Genau das macht diese Maschinenroutine.
Der REM-Korrektor
Wenn der REM-Korrektor mittels MSE als Maschinenprogramm auf Kassette oder Diskette gespeichert ist, kann dieses jederzeit mit LOAD"REM-KORREKTOR",8,1 (,1,1) geladen werden. Auch dann, wenn sich bereits ein Basic-Programm im Speicher befindet. Der gefürchtete OUT OF MEMORY ERROR, der durch das Nachladen von Maschinenprogrammen und dem damit verbundenen »Verbiegen« der Basic-Zeiger auftritt, wird beim Starten des REM-Korrektors mit SYS 52000 aufgehoben. Der REM-Korrektor liegt ab Adresse 52000 im Speicher, damit die Datasetten-Anwender nicht auf TURBO TAPE verzichten müssen.
Befindet sich der REM-Korrektor einmal im Computer, kann er selbstverständlich immer wieder mit SYS 52000 aufgerufen werden. Danach werden alle REMs aus dem Basic-Programm entfernt. Steht die REM-Anweisung am Zeilenanfang, wird die ganze Zeile gelöscht. Steht sie am Zeilenende, wird nur alles nach dem REM gelöscht. Sprünge auf gelöschte REM-Zeilen werden korrigiert, auch wenn die neuen Sprungadressen aus mehr ASCII-Codes bestehen wie die ursprünglichen. GOTO 99 erfordert 3 Bytes in Basic. Wird die Zeile gelöscht, und die nächste gültige Zeile ist 12300, werden für den geänderten Befehl GOTO 12300 6 Bytes erforderlich. Ferner setzt das Programm alle Basic-Zeiger in der Zeropage auf den aktuellen Wert.
Bearbeitet werden alle Sprünge wie
- GOTO
- GOSUB
- IF…THEN (Zeilennummer)
- IF…THEN GOTO (Zeilennummmer)
- IF…THEN GOSUB (Zeilennummer)
- IF…GOTO (Zeilennummer)
- IF…GOSUB (Zeilennummer)
- ON X GOTO (Zeilennummer), (Zeilennummer),…
- ON X GOSUB (Zeilennummer), (Zeilennummer),…
Einer Zeilennummer vorangehende Leerzeichen sind ebenfalls erlaubt. Bei ON X GOTO oder ON X GOSUB muß jede Zeilennummer, bis auf die letzte durch ein Komma abgetrennt sein.
ON X GOTO 200, 300, 400, 500, 600 ist erlaubt. Nicht jedoch
ON X GOTO 200, 300, 400 , 500, 600.
Während des Programmablaufs erscheinen zur Kontrolle der Korrekturen die Nummern der in die Sprungbefehle neu eingesetzten Zeilen auf dem Bildschirm.
Anschließend kann mit dem Basic-Programm ganz normal weitergearbeitet werden.
Tips zur Benutzung
- Der REM-Korrektor ist in der Lage, durch NEW versehentlich gelöschte Basic-Programme zu regenerieren (RENEW-Funktion), wenn man vor dem Starten durch SYS 52000 den Befehl POKE 2050,1 eingibt (allerdings sind dann sämtliche REMs »raus«).
- Zeile 0 darf keine REM-Zeile sein (0REM…). Enthält Zeile 0 einen REM-Befehl, werden keine Sprungkorrekturen ausgeführt.
Der REM-Korrektor benötigt für ein 20 KByte langes Basic-Programm etwa 1,5 Sekunden, wenn keine Sprungkorrekturen notwendig sind. Aber auch wenn zahlreiche Korrekturen durchgeführt werden müssen, bleibt die Ablaufzeit im Bereich von einigen Sekunden.Ist kein Basic-Programm im Speicher, stoppt der REM-Korrektorsofortwieder. Sind nur REM-Zeilen vorhanden, führt er einen RESET durch. Der REM-Korrektor bleibt jedoch funktionsfähig.
Das Programm arbeitet aus Geschwindigkeitsgründen mit Hilfsspeicherbereichen in denen Hilfszeiger abgelegt sind. Da diese den RAM-Speicher unter dem ROM benutzen, wird kein Basic-Speicherplatz verbraucht.
- Die Arbeitsweise des REM-Korrektors
Das Maschinenprogramm ist in drei Hauptteile gegliedert. Im ersten Teil wird das Basic-Programm durchsucht und für jede gültige Zeile, oder den gültigen Teil einer Zeile, die Anfangsadresse (2 Bytes) und die Zahl der Bytes (1 Byte) unter dem ROM ab Adresse $A000 abgelegt.
Die Nummern der gelöschten Zeilen (2 Bytes) sowie die Nummer der jeweils nächsten gültigen Zeile (die nicht mit einem REM beginnt), werden ab Adresse $FFFF, ebenfalls unter dem ROM, in absteigender Folge abgelegt.
Anhand der Zeiger ab $A000 werden die Zeilenteile der Basic-Bereiche neu zusammengesetzt und nach untern komprimiert. Das heißt, daß mit den gültigen Zeilen oder Zeilenteilen das ursprüngliche Basic-Programm überschrieben wird. Da das neue Basic-Programm kürzer oder höchstens gleich lang ist wie das alte, kann diese Operation Zeile für Zeile im selben Speicherbereich (Basic-Bereich ab 2048) stattfinden. Damit sind die REMs entfernt!
Die Teile 1 und 2 sind sehr schnell, da der Basic-Speicherbereich jeweils nur einmal durchlaufen werden muß.
Im dritten Teil wird das Basic-Programm nach Sprungcodes durchsucht. Dabei werden Bytes, die zufällig eine Sprungadresse darstellen, sich aber innerhalb von Anführungszeichen befinden (Strings), natürlich ignoriert.
Die gefundene Adresse, also die Folge von ASCII-Codes, wird in eine 2-Byte-Hexadezimalzahl umgewandelt und der Bereich von $FFFF abwärts durchsucht, ob diese Zeilennummer mit der Nummer einer gelöschten Zeile übereinstimmt. Trifft dies zu, wird die ebenfalls abgespeicherte Hexadezimalzahl (Zeilennummer) der nächsten gültigen Zeile geholt und in ASCII-Codes umgerechnet. Ist die neue Zeilennummer, in einer Folge von ASCII-Codes ausgedrückt, länger als die alte, wird das Basic-Programm um diesen Unterschied nach hinten verschoben und die Basic-Zeiger restauriert. Dann wird die Zeilennummer eingefügt und festgestellt, ob noch eine Zeilennummer folgt (ON…GOTO). Wenn nicht, wird nach weiteren Sprungcodes gesucht.
PROGRAMM : REMKORREKTOR CB20 CF12 ----------------------------------- CB20 : AD 02 08 D0 01 60 78 A9 33 CB28 : 35 85 01 A9 00 85 F7 A9 F5 CB30 : 08 85 F8 A9 00 85 F9 A9 D5 CB38 : A0 85 FA A9 FF 85 39 A9 F3 CB40 : FF 85 3A A9 00 8D FF FF 32 CB48 : 8D FE FF 8D FD FF 8D 01 1E CB50 : A0 A0 00 B1 F7 F0 06 20 D6 CB58 : 66 CC 4C 53 CB C8 B1 F7 5C CB60 : D0 05 C8 B1 F7 F0 51 A5 B3 CB68 : F7 85 9E A5 F8 85 9F 20 F9 CB70 : 66 CC 20 66 CC 20 66 CC 12 CB78 : 20 66 CC 20 66 CC A0 00 52 CB80 : B1 F7 F0 10 C9 8F F0 04 50 CB88 : C8 4C 80 CB C0 00 D0 03 65 CB90 : 4C 74 CC 88 98 AA A0 00 BC CB98 : A5 9E 91 F9 20 6D CC A5 1C CBA0 : 9F 91 F9 20 6D CC 8A 91 15 CBA8 : F9 20 6D CC 18 65 F7 85 3E CBB0 : F7 90 02 E6 F8 4C 53 CB 24 CBB8 : A5 F9 8D 3C 03 A5 FA 8D A9 CBC0 : 3D 03 AD 01 A0 D0 07 A9 0A CBC8 : 37 85 01 4C E2 FC A9 00 48 CBD0 : 85 F7 A9 08 85 F8 A9 00 83 CBD8 : 85 F9 A9 A0 85 FA A0 00 8B CBE0 : B1 F9 85 9E 20 6D CC B1 C7 CBE8 : F9 85 9F 20 6D CC B1 F9 88 CBF0 : AA E8 E8 E8 E8 E8 20 6D 97 CBF8 : CC 86 02 B1 9E 91 F7 C8 A6 CC00 : C4 02 D0 F7 A0 00 20 66 50 CC08 : CC A5 F7 85 9E A5 F8 85 5B CC10 : 9F 8A 18 65 9E 85 9E 90 59 CC18 : 02 E6 9F A5 9E 91 F7 A5 CB CC20 : 9F 20 66 CC 91 F7 CA CA 9C CC28 : 8A 18 65 F7 85 F7 90 02 75 CC30 : E6 F8 A5 F9 CD 3C 03 D0 A7 CC38 : A7 A5 FA CD 3D 03 D0 A0 9B CC40 : A0 00 A9 00 91 F7 20 66 71 CC48 : CC 91 F7 20 66 CC 91 F7 E2 CC50 : 20 66 CC A5 F7 85 2D 85 F6 CC58 : 2F 85 31 A5 F8 85 2E 85 CA CC60 : 30 85 32 4C 14 CD E6 F7 A4 CC68 : D0 02 E6 F8 60 E6 F9 D0 D9 CC70 : 02 E6 FA 60 A5 F7 85 3B 57 CC78 : A5 F8 85 3C 20 F2 CC B1 B2 CC80 : 3B 91 39 20 F2 CC 20 FD E8 CC88 : CC B1 3B 91 39 20 FD CC 54 CC90 : 20 06 CD 20 06 CD B1 3B 37 CC98 : D0 F9 20 06 CD 20 06 CD BF CCA0 : B1 3B D0 09 20 0D CD 20 26 CCA8 : 0D CD 4C CE CC A0 03 B1 CA CCB0 : 3B A0 00 C9 8F F0 32 20 FE CCB8 : 06 CD 20 06 CD B1 3B 91 E8 CCC0 : 39 20 F2 CC 20 FD CC B1 E8 CCC8 : 3B 91 39 20 FD CC A9 00 0B CCD0 : 91 39 20 FD CC A9 00 91 03 CCD8 : 39 20 FD CC A9 00 91 39 8E CCE0 : 20 0D CD 20 0D CD 4C 53 15 CCE8 : CB 20 06 CD 20 06 CD 4C 01 CCF0 : 93 CC C6 3B A9 FF C5 3B 2A CCF8 : D0 02 C6 3C 60 A5 39 D0 BC CD00 : 02 C6 3A C6 39 60 E6 3B 75 CD08 : D0 02 E6 3C 60 E6 39 D0 DE CD10 : 02 E6 3A 60 A9 00 85 F7 C1 CD18 : 8D 3C 03 A9 08 85 F8 8D 65 CD20 : 3D 03 A0 00 84 3D 84 49 DE CD28 : A0 00 B1 F7 AA D0 24 A5 41 CD30 : F7 8D 3C 03 A5 F8 8D 3D 30 CD38 : 03 20 66 CC 20 66 CC B1 4A CD40 : F7 F0 35 84 3D 84 49 20 EB CD48 : 66 CC 20 66 CC 20 66 CC EA CD50 : 4C 28 CD E0 22 D0 06 A9 54 CD58 : 01 45 3D 85 3D A5 3D D0 93 CD60 : EC E0 89 F0 19 E0 8D F0 ED CD68 : 15 E0 A7 F0 11 A5 49 F0 3A CD70 : DC E0 2C D0 D8 4C 7E CD 67 CD78 : A9 37 85 01 58 60 20 66 14 CD80 : CC B1 F7 C9 20 D0 03 4C 89 CD88 : 7E CD C9 30 90 BF C9 3A 08 CD90 : B0 BB 20 3A CE 84 3E B1 DB CD98 : F7 C9 2C D0 05 85 49 4C D3 CDA0 : A6 CD A9 00 85 49 A0 00 BC CDA8 : A9 FF 85 39 A9 FF 85 3A FE CDB0 : B1 39 D0 17 20 FD CC B1 9D CDB8 : 39 D0 0D 20 FD CC B1 39 20 CDC0 : D0 03 4C 28 CD 20 0D CD D8 CDC8 : 20 0D CD B1 39 C5 48 D0 9D CDD0 : 0C 20 FD CC B1 39 C5 47 90 CDD8 : D0 06 4C EC CD 20 FD CC CB CDE0 : 20 FD CC 20 FD CC 20 FD F9 CDE8 : CC 4C B0 CD 20 FD CC 20 25 CDF0 : FD CC B1 39 AA 20 0D CD 62 CDF8 : B1 39 A0 37 84 01 20 CD C1 CE00 : BD A9 2C 20 CA F1 78 A0 00 CE08 : 35 84 01 A0 00 B9 00 01 A4 CE10 : F0 04 C8 4C 0D CE 98 38 D8 CE18 : E5 3E 85 4A E6 4A A0 00 0A CE20 : C6 4A F0 06 20 87 CE 4C 1A CE28 : 1E CE A0 00 B9 00 01 F0 57 CE30 : 06 91 F7 C8 4C 2C CE 4C 10 CE38 : 28 CD A0 00 84 47 84 48 94 CE40 : B1 F7 38 E9 30 18 65 47 20 CE48 : 85 47 A9 00 65 48 85 48 1A CE50 : C8 B1 F7 38 E9 30 C9 0A 51 CE58 : 90 01 60 20 61 CE 4C 40 C3 CE60 : CE A5 47 85 39 A5 48 85 70 CE68 : 3A 06 47 26 48 06 47 26 5A CE70 : 48 06 47 26 48 06 39 26 38 CE78 : 3A 18 A5 39 65 47 85 47 84 CE80 : A5 3A 65 48 85 48 60 A5 0C CE88 : F7 85 3B A5 F8 85 3C A0 B3 CE90 : 00 B1 2D C8 91 2D A5 2D 41 CE98 : C5 3B D0 09 A5 2E C5 3C AB CEA0 : D0 03 4C AB CE 20 09 CF 2C CEA8 : 4C 8F CE AD 3C 03 85 3B 8E CEB0 : AD 3D 03 85 3C A0 00 B1 9A CEB8 : 3B F0 06 20 06 CD 4C B7 60 CEC0 : CE A0 02 B1 3B D0 03 4C 74 CEC8 : EF CE A0 01 B1 3B AA E8 D8 CED0 : 8A 91 3B D0 08 C8 B1 3B 10 CED8 : AA E8 8A 91 3B 20 06 CD 34 CEE0 : 20 06 CD 20 06 CD 20 06 D6 CEE8 : CD 20 06 CD 4C B5 CE 20 EF CEF0 : 06 CD 20 06 CD 20 06 CD 37 CEF8 : A5 3B 85 2D 85 2F 85 31 8C CF00 : A5 3C 85 2E 85 30 85 32 3F CF08 : 60 A5 2D D0 02 C6 2E C6 3D CF10 : 2D 60 B6