Tokenizer
Ein Tokenizer ist eine Programmroutine, die Quelltext in ein für einen Interpreter ausführbaren Code konvertiert, wobei Befehle, Funktionen oder Operanden in Token umgewandelt werden. Der Programmcode ist damit kürzer als der Quellcode und seine Ausführung ist schneller.
Tokenizer des C64[Bearbeiten | Quelltext bearbeiten]
Für den C64 gibt es verschiedene Arten von Tokenizern.
- Interne Tokenizer, die im C64 eingegebenen PETSCII-Code in Interpretercode wandeln.
- Externe Tokenizer, wie die im Cross-Development eingesetzten, die den im Host-System eingegebenen ASCII-Code in C64-Programmcode wandeln.
Der Tokenizer im Betriebssystem des C64[Bearbeiten | Quelltext bearbeiten]
Der BASIC-Interpreter des C64 ruft den Tokenizer an der Adresse $A579 zum Abschluss der Routine "Eingabe einer Zeile" auf, wenn der Quelltext im Eingabepuffer gespeichert ist und die Eingabe mit RETURN abgeschlossen wurde.
Von $A579 springt er zum Inhalt des Vektors $0304/$0305 ($A579 JMP ($0304)
), der als Standardwert $A57C enthält.
Mit dem "Umbiegen" dieses Vektors auf eine eigene Routine kann man eine BASIC-Erweiterung oder eine andere Programmiersprache implementieren. Dies geschieht in der Regel gemeinsam mit anderen Routinen:
Vektor | Funktion | Standardadresse |
---|---|---|
$0302-$0303 | Eingabe einer Zeile | $A483 |
$0304-$0305 | Umwandlung in Interpretercode (Tokenizer) | $A57C |
$0306-$0307 | Umwandlung in Klartext | $A71A |
$0308-$0309 | Befehl ausführen | $A7E4 |
Der Tokenizer vergleicht den Text aus dem Eingabepuffer mit seiner Befehlstabelle ab $A09E. Entspricht ein Textabschnitt einem Befehl, so wird er ersetzt durch ein Token, einem Byte aus dem Bereich $80 bis $CB (128 bis 203). Kennzeichen eines solchen Tokens ist also das gesetzte Bit7. Die weiteren möglichen Werte $CC bis $FE (204 bis 254) sind frei und werden von anderen BASIC-Dialekten oder BASIC-Erweiterungen benutzt. Der Wert $FF (255) ist für das Zeichen π (Pi) reserviert und daher nicht als Token einsetzbar. Das letzte Zeichen eines Befehls in der Befehlstabelle ist durch ein gesetztes Bit7 gekennzeichnet. Diese Methode macht auch die Abkürzung von Befehlen möglich.
- Nach einem Anführungszeichen (Code $22 = 34) findet keine Umwandlung in Token mehr statt bis nach dem nächsten $22 bzw. bis zum Zeilenende.
- Das Fragezeichen (Code $3f = 63) wird direkt in das Token $99 für PRINT umgewandelt.
- Zeichen aus dem Bereich $30 bis $3b - also Ziffern, Doppelpunkt und Semikolon - werden nicht mit der Befehlstabelle verglichen und unverändert wieder in den Eingabepuffer geschrieben.
- Zeichen ab $80 (>= 128) werden - bis auf $ff für π - nicht berücksichtigt, es sei denn, sie befinden sich im Quote-Modus hinter einem Anführungszeichen. Ausnahme: im Einfügemodus hinter REM.
Beginn der Befehlstabelle:
:a09e 45 4e c4 46 4f d2 4e 45 58 d4 44 41 54 c1 49 4e enDfoRnexTdatAin :a0ae 50 55 54 a3 49 4e 50 55 d4 44 49 cd 52 45 41 c4 put¯inpuTdiMreaD :a0be 4c 45 d4 47 4f 54 cf 52 55 ce 49 c6 52 45 53 54 leTgotOruNiFrest :a0ce 4f 52 c5 47 4f 53 55 c2 52 45 54 55 52 ce 52 45 orEgosuBreturNre :a0de cd 53 54 4f d0 4f ce 57 41 49 d4 4c 4f 41 c4 53 MstoPoNwaiTloaDs :a0ee 41 56 c5 56 45 52 49 46 d9 44 45 c6 50 4f 4b c5 avEverifYdeFpokE :a0fe 50 52 49 4e 54 a3 50 52 49 4e d4 43 4f 4e d4 4c print¯prinTconTl ...
Beispiel[Bearbeiten | Quelltext bearbeiten]
10 PRINT 2*3
Eingabepuffer nach Eingabe, vor Tokenizer:
:0200 31 30 20 50 52 49 4e 54 20 32 2a 33 00 00 00 00 1 0 P R I N T 2 * 3
nach Tokenizer:
:0200 99 20 32 ac 33 00 4e 00 20 32 2a 33 00 00 00 00
Zeilennummer und BASIC-Verkettungsbytes in $01FC bis $01FF sind hier schon verarbeitet.
- 99 = PRINT-Token
- ac = Token für Operator "*"
- 00 = Ende der Zeile
Danach folgen Bytes, die von vorherigen Aktionen im Speicher verblieben sind.
Erzeugte BASIC-Programmzeile:
:0801 0b 08 0a 00 99 20 32 ac 33 00 00 00
.
0b 08: Verkettung auf Folgezeile 0a 00: Zeilennummer 10 99 : Token für PRINT 20 : " " 32 : "2" ac : Token für "*" 33 : "3" 3x00 : Programmende
Abkürzung von Befehlen[Bearbeiten | Quelltext bearbeiten]
Weil das letzte Zeichen eines Eintrags der Befehlstabelle durch das gesetzte Bit7 gekennzeichnet ist, kann man Schlüsselwörter, die mindestens drei Zeichen lang sind, bei der Eingabe im BASIC-Editor abkürzen, indem man mit einem "geshifteten" Zeichen den Befehlstext vorzeitig beendet. Die gültigen Abkürzungen sind im Artikel Token aufgeführt. Der Interpreter arbeitet die Befehlstabelle der Reihe nach durch. Findet er einen Befehl, für den die Abkürzung passt, ist diese für alle folgenden Befehle nicht mehr nutzbar. Einige Beispiele:
Befehl | Abkürzung |
---|---|
save | sA |
clr | cL |
close | clO |
load | lO |
print# | pR |
input# | iN |
Da CLR vor CLOSE kommt, kann CLOSE nur mit clO und nicht mit cL abgekürzt werden.
Da PRINT# vor PRINT und INPUT# vor INPUT kommen, können PRINT und INPUT nicht auf diese Weise abgekürzt werden.
Für das häufig verwendete PRINT gibt es deshalb das spezielle Kürzel "?".
Der Abkürzungs-Bug: "Kürzt" man einen Befehl ab, indem das letzte Zeichen geshiftet eingegeben wird, reagiert der Interpreter bei der LIST-Ausführung mit Fehlern. Bei den meisten Befehlen wird das letzte Zeichen dann einfach nicht ausgegeben. Bei gotO und gosuB kommt es zu verblüffenden Ergebnissen.
Eingabe: | Ausgabe: |
---|---|
10 foR i=0 tO 1: print i: nexT |
10 fo i=0 t 2: print i: nex
|
10 gotO 20 |
10 mid$t 20
|
10 gosuB 100 |
10 mid$su 100
|
Das Verhalten wird detailliert im Blog-Artikel "A Curious Bug in the Commodore BASIC Tokenizer Routine"[1] beschrieben.
BASIC Erweiterungen[Bearbeiten | Quelltext bearbeiten]
BASIC-Erweiterungen benutzen nicht nur die freien Token, sondern auch zusammengesetzte Token mit einer Kennung (meistens nur ein Byte) und der Token-Nummer (zwischen 1 und 127) als letztem Byte. Simons' Basic zum Beispiel hat $64 als Kennung, Simons' Basic Extension zusätzlich noch $65.
Erweiterungen besitzen ihren eigenen Tokenizer, der vor dem System-Tokenizer aufgerufen wird. Das kann zu Abweichungen bei den Abkürzungen führen. Während etwa das originale Simons' Basic als Befehlsende-Kennung das Zeichen "@" benutzt und keine Abkürzungen für seine Befehle bietet, funktioniert der Tokenizer von TSB nach demselben Prinzip wie dem des Betriebssystems. Da die TSB-Befehle aber zuerst verarbeitet werden, nehmen sie den BASIC V2-Befehlen gelegentlich die Abkürzung weg. So stellt z. B. "cH" nicht mehr CHR$ dar, sondern CHAR. CHR$ kann nur noch mit "chR" abgekürzt werden. Auch "lO" gilt nicht mehr als Abkürzung für LOAD (hier muss man nun "loA" eingeben), sondern für LOOP.
Besonderheiten nach REM[Bearbeiten | Quelltext bearbeiten]
Die Zeichen größer oder gleich $80 (128) besitzen einen PETSCII-Code, der mit dem Wert für ein Token übereinstimmt. Bei der Eingabe werden sie normalerweise nur im Quote-Modus berücksichtigt, in einer Zeile hinter REM aber in Token umgewandelt. Gegebenenfalls kann man eine Umwandlung erzeugen, indem man den Einfügemodus benutzt.
Beispiele:
Großbuchstaben im Klein-/Groß-Modus:
10 rem - Beispiel - LIST 10 rem - peekeispiel -
Hier ist "B" mit dem PETSCII-Code $C2 = 194 als Token für PEEK interpretiert worden.
Mit Einfügemodus:
10 REM{insert}{shift space}TEST LIST 10 REMCLOSETEST
Hier ist {shift space} mit dem Code $A0 = 160 als Token für CLOSE interpretiert worden.
Weblinks[Bearbeiten | Quelltext bearbeiten]
- 64'er Der gläserne VC 20 Teil 3 auf archive.org von Christoph Sauer
- Commodore BASIC tokenized file
Referenzen[Bearbeiten | Quelltext bearbeiten]
Dieser Artikel wurde Artikel des Monats. |