Compilerbauhome Compilerbau & Formale Sprachen: Rekursiver Abstieg Prof. Dr. Uwe Schmidt FH Wedel

Rekursiver Abstieg

weiter

weiter

Top-Down Parser

Rekursiver Abstieg
weiter
Idee
.1
Zu jedem Nichtterminal-Symbol wird eine Prozedur für die Analyse von Zeichenreichen entwickelt, die aus dem NT-Symbol abgeleitet werden können.
weiter
.2
In jeder Prozedur wird durch Testen des nächsten Eingabe-Symbols eine Regel (eine rechte Seite einer Produktion) für das NT-Symbol ausgewählt.
weiter
Rahmen
class Parser {
    // die Terminalsymbole
    // als int kodiert
 
    static final int
        IFSY  = 1,
        ID    = 2,
        ...
        EOFSY = n;
 
    int sy;
 
    // der Scanner
    int nextSymbol () {
        return ...;
    }
 
    void inSymbol() {
        sy = nextSymbol();
    }
 
    void checkSymbol(int sy) {
        if ( this.sy == sy ) {
            inSymbol();
        } else {
            error(...);
        }
    }
    void error(...) {
        // ...
    }
 
    void parse() {
        inSymbol();
        S1();
    }
 
    void S1() {
        S();
        checkSymbol(EOFSY);
    }
 
    // ... Methoden fuer die NT-Symbole
 
    }
weiter
Beispiel
Grammatik für den Anweisungsteil einer einfachen Pascal-ähnlichen Sprache.
Die Terminalsymbole und Nichtterminalsymbole können aus den Regeln extrahiert werden.
Stmt sei das Startsymbol.
 
Stmt    ::= if Expr then Stmt else Stmt fi
Stmt    ::= while Expr do Stmt done
Stmt    ::= begin SL end
Stmt    ::= id := Expr
 
SL      ::= Stmt SL1
SL1     ::=
SL1     ::= ; SL
 
Expr    ::= id
Expr    ::= num
weiter
Parser
Die aus den Regeln erzeugten Routinen für den recursive descent parser
 
void Stmt() {
  switch (sy) {
  case IFSY :
        checkSymbol(IFSY);
        Expr();
        checkSymbol(THENSY);
        Stmt();
        checkSymbol(ELSESY);
        Stmt();
        checkSymbol(FISY);
        break;
 
  case WHILESY :
        checkSymbol(WHILESY);
        Expr();
        checkSymbol(DOSY);
        Stmt();
        checkSymbol(DONESY);
        break;
 
  case BEGINSY :
        checkSymbol(BEGINSY);
        SL();
        checkSymbol(ENDSY);
        break;
 
  case ID :
        checkSymbol(ID);
        checkSymbol(ASSIGNSY);
        Expr();
        break;
 
  default :
        error("if, while, begin or id expected");
  }
}
 
void SL() {             // nur eine Regel für SL
        Stmt();         // keine Auswahl möglich
        SL1();
}
 
void SL1() {
  switch (sy) {
  case SEMICOLON :
        checkSymbol(SEMICOLON);
        SL();
        break;
 
  default : // epsilon Produktion
        break;
  }
}
weiter
Strategie
  1. über das nächste Eingabezeichen die passende Regel auswählen
  2. Terminalsymbole mit checkSymbol oder inSymbol überlesen
  3. für die NT-Symbole die zugehörige Prozedur aufrufen
weiter
merke
Fehlererkennung und Fehlerbehandlung noch ungenau und nur rudimentär realisiert
weiter
merke
Nur eine Regel für ein NT-Symbol: keine Auswahl-Problematik.
weiter
merke
Problem: Die Auswahl der Regeln nur durch Testen des einen nächsten Zeichens.
weiter
merke
Problem: Mit welchen Symbolen kann eine rechte Seite beginnen?
weiter
merke
Problem: Wie behandelt man Epsilon-Produktionen?
weiter
2. Beispiel
Grammatik für arithmetische Ausdrücke mit Klammerschachtelung.
 
Expr    ::= Expr + Term
Expr    ::= Expr - Term
Expr    ::= Term
 
Term    ::= Term * Factor
Term    ::= Term / Factor
Term    ::= Factor
 
Factor  ::= id
Factor  ::= num
Factor  ::= ( Expr )
weiter
Formalisierung
FIRST- und FOLLOW-Mengen für die Berechnung der Regelauswahl und zum Testen, ob der rekursive Abstieg überhaupt möglich ist.
weiter

Letzte Änderung: 14.02.2012
© Prof. Dr. Uwe Schmidt
Prof. Dr. Uwe Schmidt FH Wedel