mikrocontroller.net

Forum: PC-Programmierung Hilfestellung bei Aufgabe in C++


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Alex (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich arbeite Momentan mit dem Buch "Programming Principles and 
Practise using C++". Es geht um das bekannte Taschenrechnerprogramm von 
Stroustrup.

Auf Basis folgender Grammatik wird ein Programm entwickelt:

Ausdruck:
   Term
   Ausdruck + Term
   Ausdruck - Term
Term:
   Faktor
   Term * Faktor
   Term / Faktor
Faktor:
   Zahl
   "(" Ausdruck ")"
Zahl:
   Gleitkommaliteral

Und hier die Übungsaufgabe, es soll das Programm so umgeschrieben 
werden, dass auch geschweifte Klammern verwendet werden können, sodass 
z.B. {(4+5)*6}/(3+4) ein gültiger Ausdruck ist. Ich habe überhaupt 
keinen Ansatz wo ich anfangen soll. Wäre über Hilfe echt erfreut.



Und hier ist der koplette Programmcode:

#include "../../std_lib_facilities.h"

// Klassen----------------------------------------------------------------------

class Token {
public:
    char kind;        // what kind of token
    double value;     // for numbers: a value
    Token(char ch)    // make a Token from a char
        :kind(ch), value(0) { }
    Token(char ch, double val)     // make a Token from a char and a double
        :kind(ch), value(val) { }
};

class Token_stream {
public:
    Token_stream();   // make a Token_stream that reads from cin
    Token get();      // get a Token (get() is defined elsewhere)
    void putback(Token t);    // put a Token back
private:
    bool full;        // is there a Token in the buffer?
    Token buffer;     // here is where we keep a Token put back using putback()
};



// Memberfunktionen-------------------------------------------------------------

// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
    :full(false), buffer(0)    // no Token in buffer
{
}

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;       // copy t to buffer
    full = true;      // buffer is now full
}

Token Token_stream::get()
{
    if (full) {         // do we already have a Token ready?
                        // remove token from buffer
        full=false;
        return buffer;
    }

    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

    switch (ch) {
    case '=':    // for "print"
    case 'x':    // for "quit"
    case '(': case ')': case '+': case '-': case '*': case '/':
        return Token(ch);        // let each character represent itself
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '9':
    {
        cin.putback(ch);         // put digit back into the input stream
        double val;
        cin >> val;              // read a floating-point number
        return Token('8',val);   // let '8' represent "a number"
    }
    default:
        error("Bad token");
    }
}



// Objekterstellung und Vorwärtsdeklaration-------------------------------------

Token_stream ts;        // provides get() and putback()

double expression();    // declaration so that primary() can call expression() d.h. Vorwärtdeklaration



// Definitionen für primary(), term(), expression()-----------------------------

// deal with numbers and parentheses
double primary()
{
    Token t = ts.get();
    switch (t.kind) {
    case '(': case '{':    // handle '(' expression ')'
    {
        double d = expression();
        t = ts.get();
        if (t.kind != ')' || t.kind != '}') error("')' expected");
        return d;
    }
    case '8':           // we use '8' to represent a number
        return t.value;  // return the number's value
    default:
        error("primary expected");
    }
}

// deal with *, /, and %
double term()
{
    double left = primary();
    Token t = ts.get();        // get the next token from token stream

    while(true) {
        switch(t.kind) {
        case '*':
            left *= primary();
            t = ts.get();
            break;
        case '/':
        {
            double d = primary();
            if (d == 0) error("divide by zero");
            left /= d;
            t = ts.get();
            break;
        }
        default:
            ts.putback(t);     // put t back into the token stream
            return left;
        }
    }
}

// deal with + and -
double expression()
{
    double left = term();      // read and evaluate a Term
    Token t = ts.get();        // get the next token from token stream

    while(true) {
        switch(t.kind) {
        case '+':
            left += term();    // evaluate Term and add
            t = ts.get();
            break;
        case '-':
            left -= term();    // evaluate Term and subtract
            t = ts.get();
            break;
        default:
            ts.putback(t);     // put t back into the token stream
            return left;       // finally: no more + or -: return the answer
        }
    }
}



// main-Funktion---------------------------------------------------------------

int main()
try
{
    cout << "Willkommen zu unserem einfachen Taschenrechnerprogramm\n"
         << "Bitte geben Sie einen Ausdruck mit reelen Zahlen ein.\n\n"
         << "Erlaubte Operatoren sind + - * /\n"
         << "'==' startet berechnung, 'x' beendet das Programm\n\n";
    double val = 0;
    while (cin) {
        Token t = ts.get();
        if(t.kind == 'x') break;    // break verlässt die momentane Schleife
        switch(t.kind) {
        case '=':               // '==' for "print now"
            t = ts.get();
            if(t.kind == '=')
                cout << "=" << val << '\n';
            break;
        default:
            ts.putback(t);
            val = expression();
            break;
        }
    }
  keep_window_open();
}
catch (exception& e) {
    cerr << "error: " << e.what() << '\n';
  keep_window_open();
    return 1;
}
catch (...) {
    cerr << "Oops: unknown exception!\n";
  keep_window_open();
    return 2;
}


von MaWin (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Na ja, die Lösung ist falsch, sie akzeptiert auch

(6+8}*3

Die Grammatik sollte man schon erweitert haben

Faktor:
Zahl
"(" Ausdruck ")"
"{" Ausdruck "}"

von Alex (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo MaWin, bei der primary-Funktion habe ich vergessen die geschweifte 
Klammer aus dem Code zu nehmen (habe das etwas ausprobiert), ein Fehler 
Meinerseits.

Mit deiner Lösung hat es jetzt funktioniert, habe es auch logisch 
nachvollziehen können. Bin schon etwas deprimiert, dass ich auf so eine 
einfache Lösung selber nicht gekommen bin. Wie lange programmierst du 
schon?

von guest (Gast)


Bewertung
0 lesenswert
nicht lesenswert
MaWin schrieb:
> Na ja, die Lösung ist falsch, sie akzeptiert auch
>
> (6+8}*3

Obiger Code akzeptiert dieser Ausdruck aber nicht: "error: Bad token". 
Und das nicht wegen der '}'.
Dafür akzeptiert der sowas "1+2=4==" und gibt als Ergebnis 3 aus.

Mal davon abgesehen, daß sich der Code wegen fehlender geschweifter 
Klammern eigentlich gar nicht erst übersetzen läßt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.