Tokenizer

Aus C64-Wiki
Zur Navigation springenZur Suche springen

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]

Referenzen[Bearbeiten | Quelltext bearbeiten]