Parser / Recursive Descent Übersetzer



  • N`Abend,

    bin auf der Suche nach einem einfachen Parser/Recursive Descent Übersetzer, also als C++ Code.

    Habe schon das Netz durchsucht und zwar auch 1-2 Beispiele gefunden, die waren aber sehr umfangreich, also bin ich bei Euch gelandet 🙂
    Suche also eher etwas einfaches als Anschauungsobjekt, damit ich da mal durchsteige 😃

    Nehme sonst auch gerne Pseudocode 🙂

    Danke!!



  • boost::spirit ist eine möglichkeit - http://boost.org/libs/spirit/index.html



  • r0nny schrieb:

    boost::spirit ist eine möglichkeit - http://boost.org/libs/spirit/index.html

    Der sieht auch ganz schön mächtig aus 😮
    Würde ja gern mal selbst einen kleinen erstellen, für einfache mathematische Aufgaben oder so. Deshalb wäre ein einfacher, fertiger sehr hilfreich 🙂 Könnte man die Funktionsweise genau erkennen.



  • Tip: Schau Dir mal ANTLR an, insbesondere die von ANTLR erstellten Codes, das sind wunderschöne Recursive Descent Parser. Schön ist auch die Einführung des Autors in die manuelle Konstruktion von Recursive Descent Parsern:

    http://www.antlr.org/book/byhand.pdf

    (Ist zwar alles Java, ist aber recht einfach nach C++ übertragbar.)



  • Moin,

    so, habe mich nun mal rangemacht und probiert einen Parser zu schreiben, der einen Term - erlaubt sind Ziffern, + , -, *, ( und ) - in infix einliest und in postfix wieder ausgibt.

    Soweit bin ich bisher gekommen...hoffe das ist soweit richtig, habe mich bemüht den Code zu erklären, hoffe jemand steigt durch 🙂
    Für Verbesserungen bin ich jederzeit offen 😋

    Problem ist nun die Funktion stack.
    Operanden werden ja sofort in den Postfix-String geschrieben. (Funktion push)
    Diese Regeln soll der stack anwenden:
    http://www.cz.j.th.schule.de/html_inc/schule/lehrer/privat/mirko_koenig/postfix/postfix.htm#in2post

    Jemand eine Idee ? Wäre dufte 🙂 Danke!

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include<iostream.h>
    #include<string.h>
    
    char	lookahead;		// nächstes Zeichen in expression
    int     pos = 0;		// aktuelle Positon des Zeichens
    char    expression[20]; // der zu parsende Ausdruck
    int		fehler = 0;		// Fehler-Index
    int		klammer = 0;	// Klammer-Fehler wenn am Ende !=0
    int		stellepost = 0;	// Stelle im Postfix-String
    int		stellestack = 0;// Stelle im Operanden Stack
    
    char aktuell;
    char postfix[20];	// Postfix-String
    char operanden[10];	// Operanden-Stack
    
    void push(char reindamit); // Schreibe Zahlen in Postfixstring
    void stack(char aufnstack);// Stack für Operanden und Klammern
    
    // Grammatik-Anfang
    void expr();		// epxr -> term exprrest
    void exprrest();	// exprrest -> + term exprrest | - term exprrest | NIX
    void term();		// term -> factor termrest
    void termrest();	// termrest -> * factor termrest | NIX
    void factor();		// factor -> + factor | - factor | (expr) | number
    void number();		// number -> 0.....9
    // Grammatik-Ende
    
    void consume(char); // aktuelles Zeichen abarbeiten, pos++
    void error(int);	// werfe Fehler aus
    
    // Fehler-Anfang
    void error(int fehler)
    {
    	switch(fehler)
    	{
    	case 1: cout << "Fehler bei number()\n "; break;
    	case 2: cout << "Fehler bei consume()\n"; break;
    	case 3: cout << "Klammerfehler\n "; break;
    	}
    
    }
    // Fehler-Ende
    
    // Expr-Anfang
    void expr()
    {
    	term();
    	exprrest();
    }
    // Expr-Ende
    
    // Epxrrest-Anfang
    void exprrest()
    {
    	switch( lookahead ) 
    	{
    		case '+' : case '-':
    		stack(lookahead);
    		consume( lookahead );
    		term();
    		exprrest();
    		break;
    	}
    
    	switch( lookahead ) 
    	{
    		case ')' : klammer--;
    		stack(lookahead);
    		consume( lookahead );
    		break;
    	}
    
    }
    // Epxrrest-Ende
    
    // Term-Anfang
    void term()
    {
    	factor();
    	termrest();
    }
    // Term-Ende
    
    // Termrest-Anfang
    void termrest()
    {
    	switch( lookahead ) 
    	{
    		case '*' :
    		stack(lookahead);
    		consume( lookahead );
    		factor();
    		termrest();
    		break;
    
    		default:
            return;
    	}
    }
    // Termrest-Ende
    
    // Factor-Anfang
    void factor()
    {
    	switch( lookahead ) 
    	{
    		case '+' : case '-':
    		stack(lookahead);
    		consume( lookahead );
    		factor();
    		break;
    	}
    
    	switch( lookahead ) 
    	{
    		case '(' : klammer++;
    		stack(lookahead);
    		consume(lookahead);
    		expr();
    		break;
    	}
    
            number();	
    }
    // Factor-Ende
    
    // Number-Anfang
    void number()
    {
    	switch( lookahead ) 
    		{
    			case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    			push(lookahead);
    			consume(lookahead);
    			break;
    
    			default:
    			error(1);
    			break;
    			}
    }
    // Number-Ende
    
    // consume-Anfang
    void consume(char t) 
    	{
    		if(lookahead == t) 
    			{
    				//aktuell = lookahead;
    				//stack(aktuell);
    				pos++;
    				lookahead = expression[pos];            
    			}
    		else
    			error(2);
    	}
    // consume-Ende
    
    // Push-Anfang
    void push(char reindamit)
    {
    
    	postfix[stellepost]= reindamit;
    	stellepost++;
    }
    // Push-Ende
    
    //Stack-Anfang
    void stack(char aufnstack)
    {
    
    }
    //Stack-Ende
    
    // Main-Anfang
    void main()
    {
    	cout << "Bitte geben Sie einen Ausdruck in Infix-Notation ein:\n\n\t";
    	gets( expression );
    
    	lookahead = *expression;
    	expr();
    
    	// Klammer-Fehler
    	if(klammer !=0)
    		{
    		error(3);
    		}
    	// Klammer-Fehler-Ende
    
    	cout << pos;
    	int i = 0;
    	cout << "Ausgabe:  ";
    	while(i <= pos)
    		{
    	  cout << postfix[i];
    	  i++;
    		}
    }
    // Main-Ende
    


  • xMänneken schrieb:

    Jemand eine Idee ? Wäre dufte 🙂 Danke!

    Wo ist denn da Dein Problem? Die Regeln sind doch recht gut beschrieben. Das kann man mit nem Switch erschlagen.

    void stack(char aufnstack)
    {
        switch (aufnstack) {
           case '(': push('('); break;
           case ')':
               for (; ;) {
                   char zeichen = pop();
                   if (zeichen == '(') break;
                   ausgabe(zeichen);
               }
               break;
           case '+', '-', '*', '/':
               // Als Übung Dir überlassen. ;-)
        }
    }
    

Anmelden zum Antworten