Speichernutzung und Bedienung eines Textprogramms stehen in dieser Folge im Mittelpunkt
Heute wollen wir tiefer in die Programmierung von "Magatext” einsteigen, unsere rein in Basic erstellte Textverarbeitung. Einrichtung des Textspeichers Bereits beim letzten Mal war im Listing die Dimensionierung des Feldes text mit den beiden Variablen maxspalte und maxzeile zu finden. Heute wollen wir uns mit den Möglichkeiten zum Festhalten eines Textes im Speicher der CPCs beschäftigen. Hierbei beschränken wir uns auf die Varianten, die in Locomotive-Basic vorgesehen sind, und betrachten deren Vor- und Nachteile. Nur nach diesem gründlichen Überblick läßt sich eine Entscheidung für die in unserem Fall geeignete Form treffen. 1. Möglichkeit: Text als String Zunächst kommt natürlich jeder Programmierer hier auf den Gedanken, einfach den gesamten Text in einen einzigen, beliebig langen String zu schreiben. Darunter versteht man eine zusammenhängende Kette von Buchstaben und anderen Zeichen, also Satzzeichen, Ziffern, Leerzeichen usw. Der Vorteil liegt dabei in der leichten Änderbarkeit, denn man muß ja lediglich an passender Stelle die Zeichen löschen, einsetzen oder überschreiben. Zudem könnte man versuchen, den normalen Basic-Editor zu verwenden, mit dem man auch die Programm-Listings eingibt. Bevor Sie jedoch Experimente damit veranstalten, sollten Sie einmal folgendes kleine Testprogramm eintippen und laufen lassen: 10 a$ = ”” 20 FOR i = 1 TO 400 30 a$ = a$+”#” 40 PRINT i 50 PRINT a$ 60 NEXT i 70 ENDEs arbeitet folgendermaßen. In Zeile 10 wird unser String a$ geleert und anschließend in einer FOR-NEXT-Schleife immer ein Sternchen an die bisherige Zeichenkette angehängt. Dann folgt die Ausgabe der aktuellen Durchlaufnummer und eines ebenso langen Strings. Schon kommt das böse Erwachen: Beim Wert 255 bricht der Computer mit der Fehlermeldung "String too long in 30” ab. Dies rührt daher, daß auf den CPCs ein String maximal 256 Zeichen umfassen darf. Der Abbruch bereits bei 255 resultiert daraus, daß jeweils die allererste Position in einer Zeichenkette für eine interne Längenmarkierung reserviert ist, die der Computer automatisch anbringt.Die Beschränkung auf 255 Zeichen macht diese Methode für unser Vorhaben unbrauchbar. Wer muß schon Schriftstükke mit einer Höchstlänge von 255 Zeichen verarbeiten? Schließlich wären das in Mode 2 nicht einmal vier Zeilen. 2. Möglichkeit: Jede Zeile als String Der nächste Gedanke ist sicherlich, einfach jede Zeile als String zu vereinbaren. Wenn man dann noch diese Zeilen durchnumeriert, kann man sie sehr einfach als Array definieren. Darunter versteht man eine Liste gleicher Elemente, die sich über den Dateinamen und einen sogenannten Index ansprechen lassen. Nach DIM zeile$(59) hätten wir also 60 String-Variablen zeile$, die durch einen nachgestellten Wert in Klammern einzeln aufgerufen werden können, zeile$(3) z.B. spricht die vierte Zeile an. Dies resultiert daraus, daß Computer grundsätzlich bei 0 zu zählen beginnen. Man kann dies allerdings umgehen, indem man einfach einen zusätzlichen Platz in der Liste definiert und die Zeile mit dem Index 0 unbenutzt läßt. Das bedeutet zwar eine gewisse Speicherplatzverschwendung, erleichtert aber dem Programmierer die Übersicht erheblich. Bei dieser Art der Speicherung ist die zeilenweise Bearbeitung gut möglich. Auch Zeichen können einfach geändert werden. Zu beachten ist allerdings die Begrenzung der .Kette auf 80 Zeichen. Deshalb kann es passieren, daß beim Einfügen die nach hinten verschobenen Teile unter Umständen hinausfallen und unwiederbringlich verschwinden. Hinzu kommt noch eine Erscheinung, die schon manche Computerbesitzer glauben ließ, ihr Gerät sei defekt. Nach einigen Änderungen geschieht plötzlich nichts mehr auf dem Bildschirm. Keine Eingaben sind möglich; nichts geht mehr. Es ist aber keineswegs so, daß der Rechner nicht arbeitet. Vielmehr findet nun die sogenannte Garbage Collection statt, zu deutsch die Müllbeseitigung. Im Speicher gibt es nämlich reichlich String-Müll. Bei jeder Änderung an einer Zeichenkette wird diese komplett neu angelegt, und die alte Version verbleibt sozusagen als Abfall im Speicher. Sie können sich leicht vorstellen, wie schnell die CPCs auf diese Weise an den Rand ihrer Kapazität gelangen. Deshalb wird dann eine Garbage Collection durchgeführt, die durchaus mehrere Minuten dauern kann. Aus diesem Grund kommt auch unser zweites Verfahren nicht in Frage, denn solche Wartezeiten stören doch sehr. 3. Möglichkeit: Jedes Wort als String Hier wird jedes einzelne Wort als String abgelegt. Dadurch sind Einfügungen und Löschungen leicht möglich. Allerdings treten wieder Probleme mit der Garba-ge Collection auf. Zudem muß man dann einen Programmteil vorsehen, der erkennt, wann ein Wort beendet ist. Das kann bei einem Leerzeichen, der ENTER-Taste oder einem Satzzeichen der Fall sein. 4. Möglichkeit: Jeder Buchstabe als String Diese Variante erscheint auf den ersten Blick unheimlich aufwendig: Jeder einzelne Buchstabe wird als String gespeichert. Hier läßt sich die Möglichkeit des mehrdimensionalen Arrays nutzen. DIM text$ (70, 60) stellt Ihnen beispielsweise ein Feld mit 60 Zeilen â 70 Spalten zur Verfügung, in denen sich dann jeder Buchstabe einzeln ansprechen läßt. Wir vernachlässigen hier wieder die Tatsache, daß der CPC mit 0 zu zählen beginnt, die erste Zeile und die erste Spalte bleiben leer. Jetzt kann man mit text$(4,3) = ”a” den Buchstaben a in die vierte Spalte der dritten Zeile schreiben. Das ist recht komfortabel und läßt Änderungen leicht zu. Jedoch sind immer noch sehr viele String-Operationen erforderlich. 5. Möglichkeit: Arrav mit Integer-Werten Im Handbuch zum CPC 464 finden Sie auf den Seiten 2 bis 13 des Anhangs III eine ASCII-Tabelle. Dort wird jedem Zeichen 'und Buchstaben ein Wert zwischen 0und 255 zugewiesen. Das ist der Bereich der Integer-Zah-len, mit denen der CPC schnell und effektiv rechnen kann. Wenn wir also unser zweidimensionales Feld ändern, indem wir nicht den Buchstaben, sondern nur seinen Wert in dieser Tabelle dort ablegen, so ersparen wir uns jegliche Garbage Collection. Bei der Darstellung mit Spalte und Zeile als Indizes wurde zuerst die Spalte und dann die Zeile gewählt, da diese Reihenfolge beim LOCATE- Befehl gefordert wird, den wir für die Ausgabe an der entsprechenden Bildschirmposition benötigen. Eine schnelle Ausgabe an der richtigen Stelle ist ohne große Umrechnungen möglich. Wir können auf jedes einzelne Zeichen gezielt und direkt zugreifen, es einfügen, löschen oder überschreiben. Außerdem läßt sich ein Cursor imitieren, indem wir das jeweils vorhandene Zeichen in inverser Darstellung, also weiße Schrift auf schwarzem Hintergrund, deutlich sichtbar hervorheben. Einziger Mangel ist, daß beim Einfügen die Übernahme der hinten aus der Zeile herausfallenden Zeichen nicht mit ausreichendem Tempo gelöst werden kann. Die Ausgabe erfolgt mit dem Kommando PRINT CHR$(Wert), wobei für Wert die jeweilige ASCII-Zahl eingefügt wird. 6. Möglichkeit: Integer-Feld für den ganzen Text Nun könnte man wieder zur ersten Version gehen und sagen: Wir nehmen einfach ein eindimensionales Feld mit 4200 Elementen, dann haben wir den ganzen Text in einem Durchlauf. Sicherlich ist so das Problem der beim Einfügen herausfallenden Zeichen bei den Zeilen gelöst, aber beim gesamten Text bleibt es bestehen. Zudem sind bei dieser Anordnung vor jeder Ausgabe eines Zeichens am Bildschirm umfangreiche Umrechenoperationen nötig, um exakt die richtige Zeile und Spalte zu ermitteln. Das kostet Zeit. Hinzu kommt, daß bei diesem Verfahren oft Wörter vom Programm getrennt werden. Die Entwicklung eines Program mteils, der richtig trennt, ist jedoch ein Unterfangen, das selbst bei Computern mit schnelleren Prozessoren und viel größerem Speicher erhebliche Probleme bereitet. Entscheidung Wie das Listing zeigt, habe ich mich für die fünfte Möglichkeit entschieden, denn sie bietet viele Vorzüge, aber nur einen einzigen Nachteil. Bedienung des Programms Hier fällt die Auswahl leichter, denn es gibt bei den CPC-Computern im Grunde nur zwei Varianten zur Bedienung eines Programms. 1. Möglichkeit: Befchlssteuerung Die Funktionen des Programms werden durch Befehle ausgelöst, die man über die Tastatur eingeben muß. Meist sind gleichzeitig mehrere Tasten zu betätigen. So muß man z.B. CTRL zusammen mit der Taste D drücken und anschließend noch L eingeben, um eine Datei zu laden. Der große Nachteil dieser Bedienungsvariante liegt darin, daß man entweder solche Kombinationen auswendig lernen oder aber dauernd im Handbuch blättern muß. Erschwerend kommt hinzu, daß die meisten Textverarbeitungen, die nach diesem System gesteuert werden, jeweils andere Kombinationen für dieselbe Funktion verwenden. 2. Möglichkeit: Menüsteuerung Hier werden die Funktionen des gesamten Programms oder des selektierten Teils auf dem Bildschirm aufgelistet, außerdem Kennbuchstaben oder -zahlen. Zur Anwahl muß man diese einfach drücken. Die Ausgabe des Menüs benötigt zwar etwas Zeit, aber man hat stets alles vor Augen. Das ist gerade in der Einarbeitungsphase ein großer Vorteil. Schon nach kurzer Zeit kennt man sich in der Bedienung des Programms bestens aus. Entscheidung Da mein Programm vor allem für Einsteiger gedacht ist, habe ich die Menüsteuerung gewählt. Umsetzung In den Zeilen 110 bis 300 finden Sie die Umsetzung in ein Basic-Programm. Dort stehen auch die vorgesehenen Funktionen, die wir der Einfachheit halber in Teil 1 in ein siebenteiliges String-Feld eingelesen haben. Ab Zeile 300 erfolgt die Abfrage der Tastatur nach Betätigung einer Taste. Dabei werden nur die Ziffern von 1 bis 7 ausgewertet; alle anderen Eingaben ignoriert das Programm. Durch diesen einfachen Trick vermeidet man von vornherein jegliche Fehlfunktion. Der Teil von Zeile 3130 bis Zeile 3520 umfaßt einige Unterprogramme. Die ersten beiden löschen alle Windows und bauen den Grundbildschirm auf, der aus drei Trennlinien besteht. Dann erscheint die aktuell angewählte Funktion in inverser Schrift in Fenster 2. Darüber zeigt Window 1 die Statuszeile an. Ab Zeile 3440 werden die jeweiligen Statuswerte zu Datei, Zeile und Spalte ausgegeben. Dabei sind zwei Punkte zu beachten. Erstens muß die Reihenfolge der Ausgaben so erfolgen, wie dies im Listing angegeben ist. Wenn sich nämlich später beim Schreiben nur die Spalte ändert, werden wir mit GOSUB 3500 gleich in die vorletzte Zeile des Unterprogramms gehen. Datei und Zeile bleiben ja unverändert. Bei Abwandlung der Zeile springen wir mit GOSUB 3480 weiter oben ein. Nur wenn sich auch der Dateiname ändert, benötigen wir das gesamte Unterprogramm. Dieser Trick erspart unnötige Wartezeiten. Zweitens finden Sie hier eine neue Variable namens textzeile. Unser Gesamttext soll bekanntlich 60 Zeilen umfassen, in das Bildschirmfenster passen jedoch nur jeweils 20. Um hier Verwechslungen mit schlimmen Folgen und aufwendige Umrechnungen zu vermeiden, verwende ich für die Position im Text die Variable textzeile, während zeile für die Bildschirmdarstellung zuständig ist. In diesem Teil haben wir viele Überlegungen zu geeigneter Speichernutzung und Bedienung angestellt, die sich bestimmt auch auf andere Vorhaben übertragen lassen. Das Hauptmenü ist fertig; eine Reihe notwendiger Unterprogramme steht zur Verfügung. In der nächsten Folge werden wir uns dem Kernstück zuwenden, der Texteingabe mit vielen Schikanen. Zum Schluß noch ein Tip. Falls Ihr Computer beim Test nach dem Abtippen einen nicht zu lokalisierenden Fehler meldet, dann lassen Sie sich doch die verwendeten Variablen mit PRINT-Befehlen ausgeben, und vergleichen Sie diese mit den vorgesehenen Werten. Berthold Freier , Computer Partner
|