C++ Mathematischer Ausdruck in Laufzeit klammern lassen



  • Hallo,
    ich komme hier einfach nicht weiter. Ich soll in mein Programm einen Mathematischen Ausdruck eingeben (mit + - und 😉 zum Beispiel:
    2*4-6*a und daraus soll werden ((2*4)-(6*a))
    Dies soll aber nicht mit einem Baum gelöst werden. Ich danke dann über einen Stack, aber nur wie... Hat jemand mal einen Denkanstoß für mich?

    Gruß





  • Wir sind gerade beim Thema Stacks, also ich denke mal ich soll das darüber lösen und nicht über Parsing.

    Die Aufgabe lautet direkt:
    Einen ungeklammerten mathematischen Ausdruck unter Beachtung der Vorrangregeln in einen
    vollständigen dyadischen Ausdruck umwandelt und das Ergebnis auf dem Bildschirm ausgibt!

    Und daraus dann einen Ausdrucksbaum entwerfen.

    Ich hab versucht es über 2 Stacks zu lösen. Einer für die Operanten einen für die Operatoren - denkt ihr es wäre auch so lösbar?



  • der Recursive Descent Parser, der im ersten Link erwähnt wird, arbeitet mit dem Programmstack.
    Und der Shunting-Yard-Algorithmus erzeugt aus dem algebraischen Ausdruck mit Hilfe eines Stacks die UPN, die wieder mit Hilfe eines Stacks aufgelöst werden kann (war der dritte Link von oben)



  • Denkanstoß schrieb:

    http://www.c-plusplus.net/forum/p1642138

    Vielleicht ist es für Minnifutzi nicht hilfreich, aber mit Hilfe des Expression-Parsers auf den oben verlinkt ist, kann man die gestellte Aufgabe tatsächlich lösen. Man muss sich bloß einen passenden Type T definieren und die vier Grundrechenarten passend implementieren.

    Das ganze sieht so aus:

    #include "expression.h" // -> <http://www.c-plusplus.net/forum/p1642138#1642138>
    #include <iostream>
    #include <string>
    #include <sstream>
    
    template< typename T >
    std::string to_string( const T& x )
    {
        std::ostringstream buf;
        buf << x;
        return buf.str();
    }
    
    template< typename T >
    struct Foo
    {
        explicit Foo( const T& x = T() )
            : value_( to_string( x ) )
        {}
        Foo& operator=( const T& x )
        {
            value_ = to_string( x );
            return *this;
        }
        Foo& operator+=( const Foo& b )
        {
            value_ += '+' + b.value_;
            return *this;
        }
        Foo& operator-=( const Foo& b )
        {
            value_ += '-' + b.value_;
            return *this;
        }
        Foo& operator*=( const Foo& b )
        {
            value_ = '(' + value_ + '*' + b.value_ + ')';
            return *this;
        }
        Foo& operator/=( const Foo& b )
        {
            value_ = '(' + value_ + '/' + b.value_ + ')';
            return *this;
        }
        Foo operator-() const
        {
            return Foo( '-' + value_ );
        }
        friend std::istream& operator>>( std::istream& in, Foo& foo )
        {
            T x;
            if( in >> x )
                foo = Foo( x );
            return in;
        }
        friend std::ostream& operator<<( std::ostream& out, Foo& foo )
        {
            return out << foo.value_;
        }
    private:
        Foo( const std::string& s ) : value_( s ) {}
        std::string value_;
    };
    
    int main()
    {
        using namespace std;
        cin >> noskipws;
        for( Foo< int > x; cout << "> ", cin >> ws >> expression( x ); )
            cout << "    Ergebnis: " << x << endl;
        return 0;
    }
    
    > 2*4-6*8
        Ergebnis: (2*4)-(6*8)
    > 13+4*5*6+987*2
        Ergebnis: 13+((4*5)*6)+(987*2)
    >
    

    Ich find's immer wieder erstaunlich, was mit diesen Template-Konstruktionen alles so geht, obwohl das beim Entwurf gar nicht vorgesehen war. (siehe auch hier)

    Gruß
    Werner

    PS.: im Expression-Parser müssen dazu drei Zeilen ausgetauscht werden. Von Zeile 104 bis 106 muss es heißen:

    const bool minus = !ctest( in, '+' ) && ctest( in, '-' );
        in >> Term< T >( m_value );
        if( minus ) m_value = -m_value;
    

Anmelden zum Antworten