Zeile 10 meldet SYNTAX ERROR, Zeile 20 nicht. Eigentlich müßten beide Zeilen völlig identische Wirkung haben,
da die beiden Operanden um AND vertauschbar sein müssen.
Des Rätsels Lösung: Der Interpreter findet nach dem S den Befehl TAN (Tangens), aber dahinter keine Klammer.
Und schon kennt er sich nicht mehr aus und bringt die Fehlermeldung. In Zeile 20 hat er keine Möglichkeit zu
Fehlinterpretationen In Zeile 30 findet er nach S den Befehl TO (FOR..TO..NEXT). Ein Space nach ST in 10 und
30 behebt den Fehler.
Sollte man sich also mit einem hartnäckigen SYNTAX ERROR herumschlagen, kann eine derartige Mißdeutung die
Ursache sein!
5.3 BASIC-Zeilenformat und Platzbedarf
Jede BASIC-Zeile beginnt mit einer Zeilennummer und kann, durch Doppelpunkt getrennt, mehrere Befehle aufnehmen.
Jedes BASIC-Befehlswort wird durch einen 1-Byte-Code komprimiert im Speicher gehalten. Jede andere Information
innerhalb der Zeile braucht soviele Bytes, wie sie Zeichen umfaßt.
Jede BASIC-Zeile benötigt 5 Bytes für ihre Verwaltung. Im einzelnen sind das 2 Bytes für die Zeilennummer, 2
Bytes für einen Vorwärtszeiger auf die nächste BASIC-Zeile und der Code 0 als Abschluß der Zeile.
Durch die Beschränkung der Bildschirmeingabe kann eine BASIC-Zeile maximal ca. 80 Zeichen lang sein. Allerdings
könnte der Interpreter BASIC-Zeilen bis zu einer internen (Interpretercode) Länge von 250 Bytes verarbeiten.
Es ist möglich, durch Verwendung der Befehlsabkürzungen mehr Information in die Zeile zu bringen, als die 80
Zeichen-Zeile normalerweise gestattet, aber dies sollte man nur in Ausnahmefällen nutzen, da LIST die betreffende
Zeile ja nicht mit den Abkürzungen druckt, sondern durch Verwendung der vollen Befehlsworte die Zeile über mehr
als 80 Zeilen auslistet. Zum Editieren müssen dann von Hand wieder alle Abkürzungen eingegeben werden, um die
Zeile geändert wieder in der vollen Länge abspeichern zu können.
5.4 Speichereinteilung
Der freiprogrammierbare BASIC-Arbeitsbereich des Rechners (34 K) gliedert sich in folgende Teile:
Die Zero Page ist ein 256 Bytes langer Bereich, auf den der Prozessor extrem schnell zugreifen kann.
Alle besonders häufig benötigten Daten legt das Betriebssystem und der Interpreter dort ab.
Der Stack (Stapel) wird im nächsten Abschnitt mit seinen Konsequenzen für BASIC beschrieben.
Die folgenden 512 Bytes (Page 2,3) enthalten unter anderem die beiden Kassettenpuffer mit zweimal 191
Bytes Länge, den BASICEingabepuffer mit 80 Zeichen Länge, sowie den Tastaturpuffer mit 10 Zeichen Länge.
Ab dem Byte 1024 steht der Text des BASIC-Programms im komprimierten Interpreter-Code.
Sobald ein Programm (mit RUN) gestartet wird, wird automatisch der Anfang der Variablentabelle auf das
Ende des BASIC Programms gesetzt. Das ist der Grund, warum andererseits nach einer Änderung im Programm
die Variablen 'weg' sind.
Das Ende der Variablentabelle ist gleichzeitig der Anfang der Felder-Tabelle. Dies hat zur Folge, dass
der gesamte Feldbereich nach hinten verschoben werden muß, wenn eine neue einfache Variable eingeführt wird.
Wichtig zu wissen ist, dass zwar jederzeit neue einfache und indizierte Variable eingeführt werden können,
dass aber nicht einzelne Variable oder Felder gelöscht werden können!
Die Stringinhalte 'wachsen' von der oberen Speichergrenze (32K) her nach ,unten'.
Der Speicher wird also optimal den jeweiligen Gegebenheiten angepaßt. Trotzdem kann er natürlich irgendwann
zu klein sein. Dies wird dann durch OUT OF MEMORY ERROR gemeldet. Bei folgenden Gelegenheiten kann diese
Meldung auftreten:
Tritt sie bei der Programmeingabe auf, so ist das Programm alleine schon zu groß, könnte also nie laufen,
da zu diesem Zeitpunkt noch keine Variable im Speicher steht. In diesem Fall kann nur 'Overlay' (LOAD) helfen.
Tritt sie nach dem Start des Programms auf, ist die häufigste Ursache eine Dimensionierung von Feldern
(DIM), da hiermit auf einmal sehr viel Speicherplatz belegt werden kann. Man kann leicht nachprüfen, ob
dies der Fall ist: Erstens muß in der gemeldeten Zeile ein DIM stehen und zweitens muß der Platzbedarf
des Feldes (s. indizierte Variable) größer sein, als der noch freie Speicherplatz (FRE).
Scheidet DIM aus, kann es ein String sein, da Strings immerhin auch auf einmal 255 Bytes belegen können.
In diesem Fall muß in der gemeldeten Zeile eine Stringzuweisung stehen.
Ist auch das nicht der Fall, könnte theoretisch eine neu eingeführte einfache Variable den Speicher
gerade um 7 Bytes zu klein gefunden haben.
Wahrscheinlicher ist aber, dass der Stack 'übergelaufen' ist:
5.5 Stack (Stapel)
Der Stack ist ähnlich wie die Zero Page ein bevorzugter Speicherbereich des Prozessors. Der Stack
eignet sich sehr gut zur Aufnahme von hierarchischen Strukturen, wie sie die Daten für Unterprogramme
(GOSUB/RETURN), Schleifen (FOR NEXT) und Klammerebenen in Ausdrücken darstellen.
Deshalb legt der Interpreter die nötigen Verwaltungsinformationen für Unterprogramme, Schleifen und
Ausdrücke im Stack ab. Dies hat den Vorteil, dass der Rücksprung aus Unterprogrammen (RETURN), der
Rücksprung in Schleifen, sowie die Überprüfung des Endwertes und die Berechnung von Ausdrücken in
sehr kurzer Zeit durchgeführt werden kann. Andererseits ist der Stack ein endlicher Speicherbereich,
der relativ schnell 'überläuft'.
Wie schon erwähnt, kann auch dies der Grund für OUT OF MEMORY ERROR sein. Die folgenden Werte sollen
Ihnen einen Anhaltspunkt geben, wieviel Ebenen jeweils möglich sind.
GOSUB 26
FOR NEXT 10
Klammerebenen 10
Diese Werte sind exklusiv, d.h. wenn Sie z.B. 26 GOSUB Ebenen haben, kann keine Schleife und kein
Ausdruck mehr existieren, ohne dass OUT OF MEMORY gemeldet wird.
Sollten Sie OUT OF MEMORY erhalten, helfen Ihnen vielleicht folgende Überlegungen weiter:
Eine Ausdrucksebene benötigt im Stack genausoviel Platz, wie eine FOR NEXT Schleife (18 Bytes), eine
GOSUB Ebene dagegen nur 5 Bytes. Sie können also durch Verzicht auf eine Ausdrucksebene eine Schleife
gewinnen oder 3 GOSUB Ebenen gegen eine Schleife eintauschen.
401 FOR A = 0 TO 1
402 FOR B = 0 TO 1
.
.
.
409 FOR 1 = 0 TO 1
410 FOR J = 0 TO 1
420 PRINT A;B;C;D;E;F;G;H;l;J
430 NEXT J,1,H,G,F,E,D,C,B,A
Die Beispiele in 2009 300 ..., und 400 ... zeigen die jeweilsmaximal mögliche
Schachtelungstiefe, nämlich log 26 und 10. Es sei nochmal betonte dass die drei
Beispiele nicht kombiniert werden können, weil jedes für sich den Stack vollkommen
in Anspruch nimmt.
Wenn Sie jeweils eine Ebene mehr anfügen, wird OUT OF MEMORY IN ... gemeldet.
Lösungsvorschläge
Am leichtesten kann die Schachtelungstiefe von Ausdrücken vermindert werden, da man sie nur in
Teilausdrücke zu zerlegen braucht, deren Ergebnisse schrittweise zusammengefaßt werden (s. numerische Ausdrücke).
GOSUB-Ebenen kann man simulieren, indem das Unterprogramm statt mit GOSUB mit GOTO angesprungen wird.
Anstatt des RETURN muß dann am Ende des Unterprogramms ein ON .. GOTO Verteiler dafür sorgen, dass das
Unterprogramm wieder zum aufrufenden Programm zurückspringt. [Das aufrufende Programm muß dem Unterprogramm
dann lediglich in einer zusätzlichen Variable mitteilen, wer es gerufen hat (s. ON GOTO).
FOR NEXT Schleifen sind sehr leicht durch IF THEN usw. zu ersetzen.
Natürlich sollte man zu solchen 'Krücken' erst greifen, wenn es wirklich nötig ist, weil sie die
Programmstruktur verschlechtern und langsamer sind.
Das BASIC Programm im Arbeitsspeicher wird Zeichen für Zeichen vom Interpreter abgetastet und
ausgeführt. Dabei muß der Interpreter im ersten Schritt jeden Befehl erst einmal analysieren.
Erst nachdem dies geschehen ist, kann der Befehl ausgeführt werden.
Der Interpreter ist selbst ein Programm, allerdings in Maschinensprache geschrieben. Dieses
Programm ist in ROMs (nichtlöschbare Speicherbausteine) eingespeichert und deshalb sofort beim
Einschalten verfügbar.
Der Vorteil der Interpretersprache liegt darin, dass man relativ einfach im 'Dialog' mit dem Rechner
Programme erstellen kann. Allerdings wird dies durch den Nachteil erkauft, dass Interpreterprogramme
relativ langsam ablaufen.
5.1 Geschwindigkeit
Bei manchen Programmteilen wäre es wünschenswert, dass sie schneller laufen. Es ist nicht sinnvoll,
exakte Laufzeiten von einzelnen Statements anzugeben, da sie oft von vielen Parametern abhängen.
Trotzdem ist es oft hilfreich, wenigstens die Größenordnung von Befehlsausführungszeiten zu kennen: Zwischen
1 ms und 100 ms
können einfache BASIC Statements zur Ausführung brauchen. Sehr umfangreiche Ausdrücke können auch
länger als 100 ms dauern.
Es können also sicher nicht mehr als 1000 BASIC Befehle pro Sekunde ablaufen. Als grobe Näherung
ist der Wert 100 Befehle pro Sekunde ganz nützlich.
Soweit es sinnvoll ist, werden bei einzelnen Befehlen qualitative Hinweise zur Ausführungszeit gegeben.
Hier sollen einige generelle Hinweise gegeben werden, die sich nicht auf spezielle Befehle beziehen:
Mehrere Befehle pro Zeile
Commodore-BASIC bietet im Gegensatz zu vielen anderen BASIC-Dialekten die Möglichkeit, mehrere
Anweisungen durch Doppelpunkt getrennt in eine Zeile zu schreiben. Diese Möglichkeit sollte aus
zwei Gründen ausgenützt werden: Erstens dauert der Übergang zu einer neuen Zeile länger, als der
Übergang zu einem neuen Statement und zweitens steigt die Zeit für Sprünge mit der Anzahl der Zeilen.
Außerdem braucht eine neue Zeile 5 Bytes an Verwaltung, während der Trenn-Doppelpunkt zwischen zwei
Befehlen nur 1 Byte benötigt. Pro weiterem Statement in einer Zeile spart man also vier Bytes ein.
Keine überflüssigen SPACEs
Wenn Zeit und Platz knapp sind, sollte nicht die Lesbarkeit des Listings durch Spaces erhöht
werden, weil jedes Space 1 Byte benötigt und vom Interpreter qelesen werden muß.
Kurze Variablennamen
In zeitkritischen Schleifen sollten möglichst nur einbuchstabige Variablen verwendet werden. Das
bedeutet, dass auch keine Integervariablen verwendet werden sollten, da das '%' auch gelesen werden
muß. Außerdem muß erst das Integerformat in Gleitkomma umgewandelt werden, was zusätzlich Zeit kostet.
5.2 Spaces im BASIC Text
Prinzipiell brauchen im BASIC Text keine Spaces als Trennzeichen stehen. Es gibt allerdings einige
Ausnahmefälle, wo durch Spaces eindeutige Verhältnisse geschaffen werden müssen:
Beispiel:
10 IFSTAND64THEN ... (IF ST AND 64 THEN)
20 1F64ANDSTTHEN ... (IF 64 AND ST THEN)
30 IFSTOR64THEN .... (IF ST OR 64 THEN)