|
Tutorial zum Hinzufügen neuer Befehle in Yab System: BeOS, Haiku, Zeta 1. Einleitung Yab basiert auf dem Yabasic Interpreter (http://www.yabasic.de). Auf der Yabasic Webseite finden Sie zusätzliche Quellen, wie man den Interpreter erweitert (Titel: "Guide into the Guts of Yabasic"). Dennoch soll dieses Dokument eine ausreichende Einleitung sein. Sie benötigen für das Hinzufügen neuer Befehle in yab grundlegendes Wissen über yab, C, C++ und der BeAPI. Wissen über Flex und Bison sind nicht zwingend notwendig. 2. Entwerfen eines Befehls Ein typischer yab Befehl ist normalerweise entweder eine Prozedur (also eine Funktion die void zurückgibt), eine Funktion, die eine Zahl zurück gibt (double oder int) oder eine Funktion, die eine Zeichenkette (char*) zurückgibt. Ein Befehl besteht aus
2.1 Die Befehlswörter Die benötigten Wörter für einen Befehl (tokens/Terminale) werden in der Datei yabasic.flex definiert. Kontrollieren Sie bitte vorher, ob es nicht schon ein Befehlswort gibt, was genau Ihren Befehl beschreibt. Somit werden unnötige doppelte Befehle vermieden. Ein Befehlswort besteht aus dem Wort selbst (in Großbuchstaben) und aus dem Zeichen, das es zurückgeben soll. Das Zeichen ist häufig einfach das Wort selbst mit einem t davor.
Beispiel:
BUTTON return tBUTTON; Anmerkung: Es gibt bei den Befehlswörtern Ausnahmen, z.B. tGet stellt das Befehlswort GET$ dar, während tGETNUM GET darstellt.
Neue Befehle (Tokens) müssen in der Datei yabasic.bison beschrieben werden. Dazu fügen Sie den Befehlsnamen am Anfang der Datei in der Befehlliste hinzu.
Die folgenden drei Abschnitte sind interessant:
Eine Befehlsregel wird am Anfang mit einem senkrechten Strich | (pipe) geschrieben, gefolgt von einem Zeichen und dem Befehlswort. Hinter dem Wort werden die Argumente geschrieben. Hinter dem letzten Argument folgt noch ein, in zwei geschweifte Klammern gefasster C Funktionsname z.B. {add_command(cBUTTON,NULL);} . Dieser Bezeichner wird mit einem Semikolon beendet. Beispiel: | tBUTTON coordinates to coordinates ',' string_expression ',' string_expression ',' string_expression {add_command(cBUTTON,NULL);}
Das eine Argument ist eine expression, das ist immer eine Zahl von Typ double.
oder
Sie können durch Kommata getrennt werden ",". Klammern ("(" und ")") sind auch möglich, aber ich habe sie so gut wie nie benutzt.
Außerdem muss in der Datei yabasic.h der Name der C-Funktion, die in der Datei graphic.c hinzugefügt wird,
beschrieben werden. Prozeduren erhalten immer einen struct command *, YabInterface * als Argument. Der struct
command enthält Informationen über die yab Argumente, Zeilennummer usw.
Vor dem Hinzufügen der Funktion in graphic.c, müssen Sie die Funktion auch in der Datei main.c hinzufügen. Fügen Sie die Funktion der switch Abfrage hinzu, die entsprechend ihrem Bezeichner die Funktion benennt. z.B.:
case cBUTTON Das folgende Beispiel zeigt eine typische Void Funktion in der Datei graphic.c:
void createbutton(struct command *cmd, YabInterface* yab) In unserem Beispiel zuerst werden die 7 yab Argumente vom Befehl struct zurückgeholt. Anmerkung: Die Argumente werden auf einem Stack gelagert, also müssen Sie sie im umgekehrten Reihenfolge zurückholen! Hier wird z.B. y1 vor x1 zurückgeholt. Auch Zeichenketten und Zahlen haben unterschiedliche pop calls. Zahlen können entweder von Typ double oder int sein, aber für Koordinaten sollte man immer double benutzten. Die aktuelle Zeilennummer wird der YabInterface Klasse hinzugefügt, indem man yi_SetCurrentLineNumber aufruft. Diese Zeile ist für alle void Funktionen gleich.
Schließlich werden die Argumente an die YabInterface Klasse weitergeleitet, indem man yi_CreateButton aufruft.
Anmerkung: die Funktionen werden durch die Anzahl ihrer Argumente sortiert! Wie schon zuvor, muss der Name der C-Funktion in die Datei graphic.c hinzugefügt und auch in yabasic.h beschrieben werden. Anders als bei den Prozeduren, bekommt die Funktion ihre Argument sofort, z.B.: int listboxgetnum(const char*, YabInterface *yab, int line, const char* libname); listboxgetnum gibt ein int bei einer Zeichenkette als Argument zurück. Die weiteren Argumente YabInterface *yab, int line, const char* libname müssen hinzugefügt werden, um die Informationen der YabInterface Klasse zur Verfügung zu stellen. Anders als bei den Prozeduren sind die Argumente und der Funktionsaufruf in der Datei function.c gespeichert. Diese Argumente werden vom Stack zurückgeholt und an die Funktion in graphic.c weitergegeben. Beispiel:
case fLISTBOXGETNUM: Das Zeichenkettenargument wird durch den a1->pointer zurückgegeben. Numerische Argumente werden durch z.B. a3->value adressiert (nicht in diesem Beispiel). Die Argumente werden von a1 bis a6 nummeriert. Mehr Argumente werden z.Z. nicht unterstützt. Das Resultat wird als Zahl gespeichert. Das Resultat für Zeichenketten wird im stString (pointer and result = stSTRING; ) gespeichert. Damit Sie eine Vorstellung bekommen, wie andere Befehle aussehen, schauen Sie sich die Datei an. Schließlich muss die Wrapper-Funktion in graphic.c. eingefügt werden. Der folgende Code zeigt Ihnen wie es aussehen könnte:
int listboxgetnum(const char* id, YabInterface *yab, int line, const char* libname) Die Zeilennummer wird an die YabInterface Klasse weitergeleitet, indem man die Werte an die Funktion yi_SetCurrentLineNumber übergibt. Diese Zeile ist für alle Funktionen gleich. Die zurückgegebene Zahl wird dann einfach durch yi_ListboxgetNum weitergeleitet. Anmerkung:Zeichenketten müssen mit my_strdup kopiert werden, z.B. return my_strdup ((char*) yi_CheckMessages (yab)); Bedenken Sie, dass die Zeichenketten noch im Speicher bestehen bleiben, wenn sie kopiert werden!
3. Die C++-Klasse YabInterface
Die Wrapper-Funktion nimmt den Pointer zum YabInterface-Objekt und ruft die Hauptmethode auf:
void yi_CreateButton(double x1, double y1, double x2, double y2, const char* id, const char* title, const char* view, YabInterface* yab)
Anmerkung: Das _L () Makro, das für alle Texte verwendet wird, übersetzt die Texte automatisch über das ZETA Local Kit. Es wird erst dann benutzt, wenn Sie den Befehl LOCALIZE verwenden. Bitte benutzen Sie dieses Makro so oft wie möglich, damit Sie eine einfache Lokalisierung der Programme ermöglichen. Die Methode selbst ist ein Teil der YabInterface-Klasse, die von der BApplication-Klasse abgeleitet wird. Da der Interpreter in einem eigenen Thread läuft, sind alle BApplication-Methoden direkt von Ihrer Methode ansprechbar.
void YabInterface::CreateButton(BRect frame, const char* id, const char* title, const char* view)
3.2 Zugriff auf yab-Datenstrukturen
YabView *myView = cast_as((BView*)viewList->GetView(view), YabView); Neue Widgets sollten automatisches Layout ermöglichen. Schauen Sie sich bitte die Befehle Button und Listbox an, damit Sie verstehen, was für unterschiedliche Arten von Layouting in yab verwendet werden. Wenn Sie ein bestimmtes Widget auf einem Ihnen unbekannten View finden möchten, müssen Sie die Views durchsuchen. Solch eine Schleife sieht folgendermaßen aus (unter der Bedingung, dass MyWidget von BView abgeleitet wurde):
YabView *myView = NULL; Anmerkung: return wird nachdem etwas mit dem Widget gemacht worden ist und nachdem man wieder das Fenster geunlockt hat, aufgerufen. Dieses erlaubt eine einfache Fehlerüberprüfung am Ende der Schleife.
3.3. Kurze Anmerkungen
4.0 Zusammenfassung Zum Schluß noch eine kleine Checkliste, damit Sie sehen können, ob Sie alle Punkte abgearbeitet haben.
Bereitgestellt durch BeSly, der BeOS & Zeta Wissensbasis. |