genau - Umwandlung einer Automatenbeschreibung in eine C-Funktion ggf. mit Zustandsreduktion Optionen: ========= genau genau Wird keine Datei angegeben, wird die Standardeingabe verarbeitet. Format der Eingabedatei ======================= Die Eingabedatei gliedert sich in mehrere Abschnitte für Optionen (options), Zustands-Definitionen (states), Eingabe-Definitionen (inputs), Ausgabe-Definitionen (outputs) und Übergangs-Regeln (rules). Options-Abschnitt ----------------- Der Options-Abschnitt wird durch eine Zeile eingeleitet, in der nur [options] enthalten ist. Die einzelnen Optionen haben jeweils das Format = wobei sich die Namen und Werte ggf. aus mehreren Teilstrings zusammensetzen können. Folgende Einträge sind möglich: c file gibt an, in welche Datei die C-Funktion geschrieben werden soll. h file gibt an, in welche Header-Datei die Konstanten-Definitionen für Ein- u. Ausgänge und Zusände geschrieben werden soll. prototypes gibt an, ob Protoypen für den C-Compiler erzeugt werden sollen (yes, on, 1, true) oder die Prototypen mit dklibs-Konstanten geschrieben werden sollen (dk) oder K&R-Deklarationen erzeugt werden sollen (no, off, 0, false). transition function legt den Namen für die Zustands-Übergangs-Funktion fest. reset function legt den Namen für die Reset-Funktion fest. reduced file legt den Namen für die Datei fest, in der eine reduzierte Automatenbeschreibung abgelegt wird. reduce legt fest, daß eine Zustandsreduktion erfolgen soll. include protect legt einen Namen für die Konstante fest, die in der Header-Datei genutzt wird, um mehrfacher Inclusion vorzubeugen. c define legt einen Namen für die Präprozessor-Konstante fest, die für die intern/extern-Unterscheidung genutzt wird. test file generiert ein C-Programm, daß alle Kombinationen von Zuständen und Eingaben testet. doxygen comments legt fest, ob Kommentare für doxygen mit in die Ausgabe geschrieben werden. suqeezed legt fest, ob "schmale" Ausgabe (weniger Leerzeichen und Leerzeilen) oder normale Ausgabe erzeugt wird. Der States-Abschnitt -------------------- Der Abschnitt wird durch [states] eingeleitet. Jede Zeile enthaält den Namen für einen möglichen Zustand, optional gefolgt von einer int-Kennnummer. Der Inputs-Abschnitt -------------------- Der Abschnitt wird durch [inputs] eingeleitet. Jede Zeile enthält den Namen für eine mögliche Eingabe, optional gefolgt von einer int-Kennnummer. Der Outputs-Abschnitt --------------------- Der Abschnitt wird durch [outputs] eingeleitet. Jede Zeile entählt den Namen für eine mögliche Ausgabe, optional gefolgt von einer int-Kennnummer. Der Rules-Abschnitt ------------------- Der Abschnitt wird durch [rules] eingeleitet. Jede Zeile enthält eine Übergangsregel, bestehend aus - aktuellem Zustand - Eingabe, die verarbeitet werden soll - Folgezustand, in den der Automat bei der Bearbeitung übergeht - Ausgabe. Jede dieser Komponenten wird über ihren in den vorherigen Abschnitten festgelegten Namen angesprochen. Für den aktuellen Zustand und die Eingabe kann das Wildcard-Symbol "*" verwendet werden, dieses sorgt darür, daß die Regel für alle Zustände/Eingaben Anwendung findet. Die Verwendung von Wildcard-Regeln kann dazu führen, daß für bestimmte Zustand-Eingabe-Kombinationen mehrere Regeln vorhanden sind. In diesem Fall werden die Prioritäten wie folgt gesetzt: - Ist eine genau zutreffende Regel (ohne Wildcard-Symbole) vorhanden, wird diese Regel genutzt. - Andernfalls wird nach Regeln mit einem Wildcard-Symbol gesucht, sind hiervon mehrere vorhanden, wird die _erste_ (in der Datei am weitesten oben stehende) Regel verwendet. - Wurde keine zutreffende Regel ohne Wildcard-Symbol bzw. mit einem Wildcard-Symbol gefunden, wird nach einer allgemeinen Regel (Zustand und Eingabe jeweils durch Wildcard-Symbol ausgedrückt) gesucht. - Wurde gar keine passende Regel gefunden, kommt die implizite Regel zum Tragen. Diese besagt, daß der Automat in seinem derzeitigen Zustand verbleibt und diejenige Ausgabe tätigt, die im Outputs-Abschnitt als erste definiert wurde. Beispiel-Datei ============== Beschrieben wird ein Automat, der für einen String ermittelt, ob er einem Identifier entspricht, wie er in der Programmiersprache C verwendet wird. D.h. der String setzt sich aus Buchstaben, Zahlen und Unterstrichen zusammen, darf aber nur mit Buchstaben oder Unterstrich beginnen. Die Automatenfunktion wird aus einer Check-Funktion heraus aufgerufen: #include "testid.h" int check_string(char *str) { int state_machine; int input; int output; char *ptr; reset_decide(&state_machine); ptr = str; while(*ptr) { input = I_ANY; if(((*ptr) >= 'a') && ((*ptr) <= 'z')) input = I_CHARACTER; if(((*ptr) >= 'A') && ((*ptr) <= 'Z')) input = I_CHARACTER; if(((*ptr) >= '1') && ((*ptr) <= '9')) input = I_DIGIT; if((*ptr) == '0') input = I_DIGIT; if((*ptr) == '_') input = I_UNDERSCORE; (void)decide(&state_machine,input); ptr++; } output = decide(&state_machine,I_FINISHED); return output; } Die zugehörige Automatendatei sieht dann folgendermaßen aus: [options] c file = testid.c # C-Datei h file = testid.h # Header-Datei reduced file = testid2.au transition function = decide reset function = reset_decide [states] S_START # Der Start-Zustand, der beim Reset eingestellt wird S_OK # Wir befinden uns innerhalb eine Identifieres S_ERROR # Der String ist kein Identifier [inputs] I_ANY # Ein beliebiges Zeichen I_UNDERSCORE # Der Unterstrich I_CHARACTER # Ein Buchstabe I_DIGIT # Eine Zahl I_FINISHED # Kennzeichen, dass der String komplett verarbeitet ist [outputs] O_OK # bisheriger String ist ein Identifier O_ERROR # bisheriger String ist kein Identifier [rules] * * S_ERROR O_ERROR * I_FINISHED S_START O_ERROR S_START I_UNDERSCORE S_OK O_OK S_START I_CHARACTER S_OK O_OK S_OK I_UNDERSCORE S_OK O_OK S_OK I_CHARACTER S_OK O_OK S_OK I_DIGIT S_OK O_OK S_OK I_FINISHED S_START O_OK