?
Oki doki. Ich habe das in Code gefasst, wie das mit der Tabelle gemeint ist, ein Ansatz für nen Parser/Tokenizer, guckst du:
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
// Private Bezeichner der Indizes für die Vorher/Jetzt Aktionstabelle.
static enum action { eos, lbrack, rbrack, value, name, comma, ignore };
// Rückgabewert im Fehlerfall.
#define err -1
// Diese Macros lassen sich vermeiden, siehe weiter unten bei der Funktion look().
#define iseos(x) x == 0
#define islbr(x) x == '('
#define isrbr(x) x == ')'
#define isval(x) x >= '0' && x <= '9' || x == '.' // Beginn einer Zahl.
#define isname(x) x >= 'a' && x <= 'z' || x >= 'A' && x <= 'Z' || x == '_' // Beginn eines Namens.
#define namechar(x) isname(x) || x >= '0' && x <= '9' // Buchstabe eines Namens.
#define iscomma(x) x == ','
#define isignore(x) x == ' '
static char* s = NULL; // Private Zeigerkopie der Eingabe.
static int prev = eos, now = eos; // Vorher/Jetzt, private Indizes der Aktionstabelle.
// Allgemeiner Standardfehler. Detailierte Fehlermeldungen/Behandlungen lassen sich
// durch die Änderung der Aktionstabelle einrichten.
int Err()
{
puts("Error!");
return err;
}
// Spezielle Fehlermeldung.
// Zeigt, wie sich die Fehler in der Aktionstabelle benennen lassen können.
int E1() // Zwei Kommas in Folge Fehler.
{
puts("E1: double comma trouble!");
return err;
}
int Comma()
{
puts ("Comma read.");
s++;
return comma;
}
// Geeignet für die Prüfung von z.B. Funktionsnamen.
int Name()
{
printf ("Name: ");
while ( namechar(*s) )
putchar(*s++);
puts ("");
return name;
}
// Geeignet für Wertprüfung z.B. mit strtod.
int Value()
{
printf ("Value: ");
while ( isval(*s) )
putchar(*s++);
puts ("");
return value;
}
int Ignore()
{
puts("Ignoring whites...");
while ( *s == ' ' ) s++; // Kandidat für while (isspace(*s))
return prev;
}
// Geeignet für Klammer-Syntax-Prüfung.
int LBrack()
{
puts("Left bracket read.");
s++;
return lbrack;
}
// Geeignet für Klammer-Syntax-Prüfung.
int RBrack()
{
puts("Right bracket read.");
s++;
return rbrack;
}
// Geeignet zum Abfangen von Funktionen, die nicht void sein dürfen.
int Void()
{
s++;
puts("Found empty brackets.");
return now; // Wird hier ignoriert.
}
int Eos() // End of string ;;)
{
puts ("End of string - good bye!");
return eos;
}
// Die Vorher/Jetzt Aktionstabelle besteht aus Zeigern auf Funktionen.
// Die Indizes Vorher/Jetzt wählen die entsprechende Funktion aus.
// Du kannst direkt ablesen, was unter welcher Bedingung passiert.
int (*Action[][7])()= {
//-- prev --------------------------- now -------------------------
// 0 1 2 3 4 5 6
// Eos LBrack RBrack Value Name Comma Ignore
/*0 Eos*/ Eos, LBrack, Err, Value, Name, Err, Ignore,
/*1 LBr*/ Err, LBrack, Void, Value, Name, Err, Ignore,
/*2 RBr*/ Eos, Err, RBrack, Err, Err, Comma, Ignore,
/*3 Value*/ Eos, Err, RBrack, Err, Err, Comma, Ignore,
/*4 Name*/ Eos, LBrack, RBrack, Err, Err, Comma, Ignore,
/*5 Comma*/ Err, LBrack, Err, Value, Name, E1, Ignore
};
// Diese Funktion zusammen mit den Macros kann ganz entfallen.
int look()
{
if ( iseos(*s) ) return eos;
if ( islbr(*s) ) return lbrack;
if ( isrbr(*s) ) return rbrack;
if ( isval(*s) ) return value;
if ( isname(*s)) return name;
// if ( namechar(x) ) wird hier nicht gebraucht.
if ( iscomma(*s) ) return comma;
if ( isignore(*s) ) return ignore;
puts("Unbekanntes Zeichen!");
exit(1);
}
// Obige Funktion look(), zusammen mit den Macros lässt sich vermeiden, wenn man
// alle chars von 0 - 255 als Index benutzt und in den zugehörigen action-index mit Hilfe
// eines Arrays übersetzt(Codierung beachten!). Hier im Beispiel gekürzt und mit weiteren Zeichen
// für Operatoren, Vorzeichen, etc. beispielhaft dargestellt:
// (Der Wert null ist hier als Fehler gedacht.)
/*
const int tai[]= // Token action index :)
{
{eos},{null},{null},{null},{null},{null},{null},{ignore},{ignore},{ignore}, // 0-9
{ignore},{ignore},{ignore},{ignore},{null},{null},{null},{null},{null},{null}, // 10-19
// ... gekürzt ...
{lbrack},{rbrack},{op},{sigPlus},{comma},{sigMinus},{value},{op},{value}, {value},// 40-49
{value},{value},{value},{value},{value}, {value},{value}, {value}, {op},{null}, // 50-59
{null},{null},{null},{null},{null},{name},{name},{name},{name},{name},// 60-69
{name},{name},{name},{name},{name},{name},{name},{name},{name},{name},// 70-79
{name},{name},{name},{name},{name},{name},{name},{name},{name},{name},// 80-89
{name},{null},{null},{null},{op}, {name},{null},{name},{name},{name},// 90-99
{name},{name},{name},{name},{name},{name},{name},{name},{name},{name},// 100-109
{name},{name},{name},{name},{name},{name},{name},{name},{name},{name},// 110-119
{name},{name},{name},{null},{null},{null},{null},{null},{null},{null},// 120-129
{null},{null},{null},{null},{null},{null},{null},{null},{null},{null},// 130-139
// ... gekürzt ...
{null},{null},{null},{null},{null},{null},{null},{null},{null},{null},// 240-249
{null},{null},{null},{null},{null},{null} // 250-255
};
Man kann also die Aktionstabelle erweitern/ändern und weitere Funktionen und Regeln hizufügen,
um den Parser weiter auszubauen. Die Macros oben für die Klassifizierung der
Zeichen/Zeichenerkennung, können komplett entfallen,
sowie die Funktion look() und die Variable 'static int now'.
In der parse Funktion ersetzt man dann die Variable 'now' durch den 'Token action index' tai:
prev = Action[prev][tai[(unsigned)*s]]();
*/
int parse ( char* input ) {
s = input, now = prev = eos;
Ignore(); // Eventuell vorkommende, führende Leerzeichen ignorieren.
do {
now = look();
prev = Action[prev][now]();
}while ( prev > 0 );
if ( prev == -1 ) return 1; // Fehler
return 0; // Ok.
}
void print_line() {
char buf[81] = {0};
memset ( buf, '-', 80 );
printf (buf);
}
int main() {
char* test = "Funktionsname ( abc, def, 1.12 )"; // Simulierte Eingabe.
if ( 0 == parse ( test ) )
printf ("First stage passed for %s\n", test );
else
printf ("First stage failed for %s\n", test );
print_line();
test = " demo_double_comma_trouble_error ( 08.15,, )"; // Einsatz der E1 Funktion zeigen.
if ( 0 == parse ( test ))
printf ("First stage passed for %s\n", test );
else
printf ("First stage failed for %s\n", test );
return 0;
}
Gruß,
B.B.