Rekursive Abstiegsanalyse

1. Der Zweck des Experiments:

Kompilieren und debuggen Sie das rekursive Abstiegsanalyseprogramm gemäß einer bestimmten Grammatik, um eine beliebige Eingabesymbolzeichenfolge zu analysieren. Der Zweck dieses Experiments ist es, das Verständnis der rekursiven Abstiegsanalyse zu vertiefen.

2. Erinnerung vor dem Experiment

1. Die Funktion der Methode der rekursiven Abstiegsanalyse

Die Funktion des lexikalischen Analysators besteht darin, die rekursiven Aufrufe zwischen Funktionen zu verwenden, um die Top-Down-Konstruktion des Syntaxbaums zu simulieren.

2. Die Prämisse der Methode der rekursiven Abstiegsanalyse

Änderung der Grammatik: Mehrdeutigkeit beseitigen, linke Rekursion beseitigen, linken Faktor extrahieren, feststellen, ob es sich um LL (1) -Grammatik handelt,

3. Die experimentellen Entwurfsideen und Algorithmen der Methode der rekursiven Abstiegsanalyse

Konstruieren Sie einen rekursiven Prozess für jedes nicht-terminale Symbol U von G, das U heißen kann.

Die rechte Seite der Produktion von U zeigt die Codestruktur dieses Prozesses:

(1) Wenn es sich um ein Terminalsymbol handelt, vergleichen Sie es mit dem zukunftsgerichteten Symbol.

Wenn es eine Übereinstimmung gibt, bewegen Sie ein Symbol vorwärts, andernfalls tritt ein Fehler auf.

(2) Wenn es sich um ein Nicht-Terminal-Symbol handelt, rufen Sie die Prozedur auf, die diesem Nicht-Terminal-Symbol entspricht. Wenn sich im rechten Teil von A mehrere Produktionen befinden, kann dies durch Auswahlstruktur realisiert werden.

Speziell:

(1) Für jedes nicht-terminale Symbol U → X1 | X2 | ... | Xn ist das Verarbeitungsverfahren wie folgt:

U ()

{

Read (ch); // Aktuelles Symbol

Wenn ch in First (X1) das Unterprogramm von X1 aufruft;

sonst, wenn ch in First (X2) die Unterroutine von X2 aufruft;

sonst Fehler ()

}}

(2) Die Verarbeitungsarchitektur für jeden rechten Teil X1 → Y1 Y 2 ... Y n ist wie folgt:

Rufen Sie das Unterprogramm von Y1 auf;

Rufen Sie das Unterprogramm von Y 2 auf;

Rufen Sie das Unterprogramm von Y n auf

(3) Wenn das rechte Teil leer ist, wird es nicht verarbeitet.

(4) Für jedes Symbol Yi im rechten Teil

① Wenn Yi ein Terminalsymbol ist:

if (Yi = = aktuelles Symbol)

{

Read (ch); //

Rückkehr;

}}

sonst Fehler ()

② Wenn Yi ein nicht-terminales Symbol ist, rufen Sie direkt die entsprechende Unterprozedur Yi () auf.

3. Experimenteller Prozess und Anleitung:

(1) Vorbereitung:

1. Lesen Sie die entsprechenden Kapitel des Lehrbuchs.

2. Betrachten Sie den Entwurfsplan.

3. Entwerfen Sie die Modulstruktur, testen Sie die Daten und bereiten Sie das Programm zunächst vor.

(2) Verfahrensanforderungen:

Beispiel für Programmeingabe / -ausgabe:

Verwenden Sie für die folgende Grammatik die Methode der rekursiven Abstiegsanalyse, um eine beliebige Eingabesymbolzeichenfolge zu analysieren:

(1) E → TG

(2) G → + TG | -TG

(3) G → ε

(4) T → FS

(5) S → * FS | / FS

(6) S → ε

(7) F → (E)

(8) F → i

Das Ausgabeformat lautet wie folgt:

(1) Rekursives Abstiegsanalyseprogramm, erstellt von: Name, Schülernummer, Klasse

(2) Geben Sie die Symbolzeichenfolge ein, die mit # endet (einschließlich + - / () i #): Geben Sie die Symbolzeichenfolge an dieser Position ein, zum Beispiel: i + i i #

(3) Ausgabeergebnis: i + i * i # ist eine zulässige Symbolzeichenfolge

Anmerkungen: Für die Eingabesymbolzeichenfolge wie i + i * # muss die Ausgabe eine "unzulässige Symbolzeichenfolge" sein.

Hinweis: 1. Operatoren (+ - * /), Trennzeichen (Klammern), Zeichen i und Abschlusszeichen # sind in Ausdrücken zulässig.

2. Wenn Sie auf einen falschen Ausdruck stoßen, sollten Sie eine Fehlermeldung ausgeben (je detaillierter die Informationen, desto besser).

3. Für Schüler, die lernen können, können Sie den Ableitungsprozess detailliert ausgeben, dh die in jedem Schritt verwendeten Produktionen detailliert auflisten.

(3) Programmideen (nur als Referenz):

0. Definitionsteil: Definieren Sie Konstanten, Variablen und Datenstrukturen.

1. Initialisierung: Geben Sie die Eingabesymbolzeichenfolge aus der Datei in den Zeichenpuffer ein.

2. Verwenden Sie die Methode der rekursiven Abstiegsanalyse, um zu analysieren, eine Funktion für jedes nicht-terminale Symbol zu schreiben und die Funktion des Grammatik-Startsymbols in der Hauptfunktion aufzurufen.

(4) Üben Sie den Zweck und die Ideen des Experiments:

Das Programm wird immer komplizierter und erfordert die Verwendung von Programmiersprachenkenntnissen und viele Programmierkenntnisse. Die Methode der rekursiven Abstiegsanalyse ist eine praktischere Analysemethode. Diese Übung kann die Fähigkeit zur Softwareentwicklung erheblich verbessern. Beherrschen Sie durch Übung die Methode, sich zwischen Funktionen gegenseitig aufzurufen.

(2) Um ein gutes Programm zu entwerfen, beachten Sie Folgendes:

1. Moduldesign: Teilen Sie das Programm in eine Reihe von sinnvollen Modulen (Funktionen) auf, und jedes Modul macht das Gleiche.

2. Schreiben (zeichnen) Sie den Entwurfsplan: Modulbeziehungsdiagramme, Flussdiagramme, globale Variablen, Funktionsschnittstellen usw.

3. Achten Sie beim Programmieren auf den Programmierstil: die Verwendung von Leerzeilen, die Verwendung von Kommentaren, die Verwendung von Einrückungen usw.

 

Viertens der experimentelle Prozess

Experimentcode

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEN 255
bool flag=true;
char src[LEN];
int i;
void E();
void T();
void G();
void F();
void S();

int main(){
    printf("编制人:周江峰,20161209719,计科1601\n");
    printf("请输入字符串(以#结束):");
    
    scanf("%s",&src);

    i=0;
    E();
    if(src[i]=='#'&&flag==true){
        printf("语句合法");
    }else
    {printf("不合法");} 
    return 0;
}

void E(){
    printf("E=>TG");
    T();
    G();
    
}

void T(){
    printf("T=>FS");
    F();
    S();
}
void G(){
    if(src[i]=='+'){
        i++;
        printf("G->+TG");
        T();
        G();
    }else if(src[i]=='-'){
        printf("G->-TG");
        i++;
        T();
        G();
    }
    
}

void F(){
    if(src[i]=='('){
        i++;
        E();
        if(src[i]==')')
        {   i++;
            printf("F->(E)");}
        else flag=false;
        }
    else if(src[i]=='i')
    {   printf("F->i");
        i++;}
    
    
    else flag=false;
}

void S(){
    
    if(src[i]=='*'){
        i++;
        F();
        S();
    }else if(src[i]=='/'){
        i++;
        F();
        S();
    }

}


Hinweis: Das Dateisuffix lautet .cpp

5. Versuchsergebnisse

 

 

Ich denke du magst

Origin blog.csdn.net/qq_41371349/article/details/104951610
Empfohlen
Rangfolge