Ich kann ja mal versuchen, ob ich die Funktionsweise ein wenig beschrieben bekomme.
Das System besteht im Grunde aus 3 großen Programmteilen: Den Parser, den Executer und den Parametrisierer (Wie ich ihn nenne
).
Im Direktmodus befindet man sich erst einmal in einer rel. einfachen Input-Routine. Wird die eingegebene Zeile abgeschickt wird diese dem Parser übergeben.
Dieser fängt nun an die Zeile zu zerhacken. Hierzu wird nach Trennzeichen gesucht (Leerzeichen, Doppelpunkt, Komma, Semikolon, Klammer usw.). So wird dann ein Zeilen-Segment abgetrennt. Nun wird in mehreren Tabellen gesucht, ob es dieses Segment dort gibt, also ob es ein Befehl, eine Funktion, ein Operator oder eine Verknüpfung ist. Wenn ja, wird das Token erstellt und in die ausführbare Zeile kopiert. Wird das Segment in keiner Tabelle gefunden, wird versucht dieses als Zahl zu konvertieren. Geht dies, liefert die Konvertierroutine die Zahl mit einer Typkennzeichnung (Dez, Hex, Bin) zurück. Diese wird dann in die Zeile kopiert. Schlägt auch dies fehl, geht der Parser von aus, es ist ein Element was erst zur Laufzeit festgelegt (Variable oder Portzuweisung z.B.) wird und speichert es einfach so ab. Sonderzeichen werden einfach so kopiert.
Ist die Zeile komplett übersetzt, geht es weiter zum Executer. Dieser schaut erst einmal nach, ob eine ihm eine Programmzeile angeboten wird. Wenn ja, wird der Speicher durchwühlt, ob diese Zeile schon vorhanden ist. Wenn ja, schmeisst der Executer die raus und verrückt den oberen Teil des aktuellen Programms soweit, dass die neue Zeile reinpasst. Dann wird die Zeile reinkopiert.
Ist die Zeile noch nicht vorhanden, wird geprüft, ob die Zeilennummer größer als alle anderen Zeilen ist. Wenn ja, wird einfach die Zeile hinten 'drangeklatscht'. Muss diese in ein Prigramm eingefügt werden, wird wieder eine Lücke geschaffen und die Zeile eingefügt.
Ein Sonderfall ist es, wenn nur eine Zeilennummer eingegeben wurde. Dann wird die Zeile, die man eingegeben hat, gelöscht, wenn sie gefunden hat. Wenn sie nicht da ist, auch egal
.
Finder der Executer keine Zeilennummer, weiß er, dass er diese Zeile ausführen soll. Hier wird dann geschaut, ob ein Befehls-Token vorhanden ist. Wenn ja, wird der Tokencode in der Sprungtabelle gesucht und angesprungen.
Der Befehl nun benötigt unter Umständen Parameter. Hier wird ein Kontrollbyte generiert in dem steht, welche Datentypen der aufrufende Befehl erwartet. Nun wird der Paramtrisierer aufgerufen. Dieser schaut dann ob in der Programmzeile nun eine Zahl, String oder eine Funktion folgt. Folgt eine Zahl wird anschließend geprüft, ob eine Verknüpfung folgt. Wenn ja, wird sich das aktuelle gemerkt und wieder zum Anfang der Routine gesprungen ob zu schauen ob wieder eine Zahl, Funktion oder ein Operand folgt. Diese wird dan ausgelesen oder ausgeführt. Anschließend wird das alte Ergebnis mit der jetzt gewonnen Zahl genommen und geschaut, wie die beiden miteinander verknüpft werden sollen, was dann entsprechend auch getan wird. Folgt nun keine weitere Verknüpfung etc. wird der Ergebnistyp mit dem geforderten Typ abgeglichen. Passt es, wird der Wert zurück gegeben. Wenn nicht: 'Type missmatch'
Wurde nun eine Zeile so komplett abgearbeitet, schaut der Executer, ob er sich im Direktmodus befindet. Wenn ja, gehts zurück zur Eingaberoutine, welche das allseits bekannte und beliebte 'Ready' ausgiebt und auf die nächste Eingabe wartet.
Befindet er sich im Programmodus, werden die Daten der neuen Zeile geholt, die aktuelle Zeilennummer für evtl. spätere Verwendung gespeichert (z.B. Fehlermeldung) und übersprungen. Dann wird die Zeile wie oben ausgeführt.
Findet sich keine neue Programmzeile, wird wieder auf Direktmodus umgeschaltet und ... Siehe weiter oben
Hoffe, das es ein wenig Licht reinbringt. Aber, wie so oft, der Teufel steckt im Detail. Wenn ich nur an die Entwicklung des Every-Befehls denke ... Ständig gab es Abstürze oder komplettes Choas, weil er sich dauernd 'verschluckt' hat.