String zerlegen.



  • Hallo! Ich möchte gerne ein Ausdruck, der in einer zeichenkette gespeicher ist, ausrechnen lassen. Also z.B. folgende Zeichenkette: "2+2^3".
    Ich habe schon eine Funktion geschrieben die so aussieht:

    long double Ausrechnen(string Ausdruck);

    Sie rechnet den Ausdruck aus und gibt das ergebnis als long double zurück.
    nun ist diese Funktion so kompliziert geworden, dass ich sie nicht weiter entwickeln möchte. Deshalb möchte ich sie neuschreiben. Könntet ihr mir ein paar Tips geben wie ich sie am einfachsten schreibe? Oder vielleicht gibt es irgendwo schon eine fertige?

    PS: Das wird ein Programm zur darstellung Mathematischer Funktionen mit OpenGL



  • Zerleg den Ausdruck in einen Baum.

    Ein Node ist ein Ausdruck, Childs sind die Elemente die wieder Ausdrücke sein können.

    So das 2+3/4 wird zu:

    +
    2 /
     3 4
    

    Jeder Node hat dann eine "ausrechnen" Funktion, die erst die Childs ausrechnet und dann die eigene Operation durchführt. Musst nur im String den Operator raussuchen, der am geringsten bindet und entsprechend auflösen und den Baum erstellen.



  • ja, damit werde ich mich mal beschäftigen. Danke!



  • neoexpert schrieb:

    ja, damit werde ich mich mal beschäftigen. Danke!

    Ich beschäftig mich auch gerade mit diesen Thema.
    Ich entwickle einen Matheparser um wärend der Laufzeit für meine Anwendung mathemtische Ausdrücke auszuwerten. Der Parser muss für meine Ansprüche Variablen verwalten und mit konfigurierbaren Symbolen arbeiten können.

    list<string> wordlist=new Words("5^2-3");
    Lexikon lex;
    list<lexToken*> tokenl = lex.Scan();
    aExpression* expr = par.parse(tokenl);
    cout << expr->eval();
    

    Da ist als erstes eine Klasse für die Grundlegende Zerlegung in Wörtern aus Zahlen, Buchstaben und Operatorzeichen.

    Das Lexikon versucht jetzt die Zeichen zu übersetzten, dabei verwende ich mehrere std::map um separt erkante Variabeln abzulegen bzw nach Operatoren oder Funktionsbezeichner zusuchen.
    Da die Wörter von Links nach rechts ausgewertet werden, können unäre Operatoren (Mit rechten und linken Argument) und binären Operatoren nur bedingt überlagert werden. Das Ergbeniss ist einer Liste aus Token oder einige Exceptions wenn die Eingabe eine illegale Kombinationen aus Werten, unäre und Binären Operatoren darstellt.

    Der anschliessende Parser sucht nach den Symbol mit der schwächste Bind, diesmal von rechts vor links.
    Bei Jeder Rekursion wird ein Expression Obejkt durch eine Methode des Token erstellt die durch rekursiven aufruf der Parser Methode ermittelten Ausdrücke als rechter und/oder linkes Argument gespeichert.

    Das Ergebniss ist ein Baum aus Ausdrücken. Der durch die virtuelle eval() Function an jedem Knoten ihr Egebniss berechnet.

    class aExpression 
    {
        public:
        ...
        virtual double eval ()=0;
        ...
    }
    class aBinaryExpr : aExpression 
    {
        public:
        ...
        virtual double eval ()=0;
        private:
           aExpression* rExpr; 
           aExpression* lExpr; 
        ...
    }
    lass AddExpr : public aBinaryExpr
    {
        public:
        ...
           virtual double eval () { return lExpr->eval() + rExpr->eval(); };
        ...
    }
    

    Das ergibst einen Haufen Klassen, selbst wenn wir für die Token im Lexikon template Klassen verwenden. Der Expressionbaum benötigt während der Auswertung nach dem Parsen keine Fallunterscheidung (switch) mehr.
    Bei der Auswertung muss nur noch bei wenigen Operationen auf Domainfehler (z.B. Teilen durch Null) geachtet werden.


Log in to reply