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:
1
#include "../../std_lib_facilities.h"
2
3
// Klassen----------------------------------------------------------------------
4
5
class Token {
6
public:
7
    char kind;        // what kind of token
8
    double value;     // for numbers: a value
9
    Token(char ch)    // make a Token from a char
10
        :kind(ch), value(0) { }
11
    Token(char ch, double val)     // make a Token from a char and a double
12
        :kind(ch), value(val) { }
13
};
14
15
class Token_stream {
16
public:
17
    Token_stream();   // make a Token_stream that reads from cin
18
    Token get();      // get a Token (get() is defined elsewhere)
19
    void putback(Token t);    // put a Token back
20
private:
21
    bool full;        // is there a Token in the buffer?
22
    Token buffer;     // here is where we keep a Token put back using putback()
23
};
24
25
26
27
// Memberfunktionen-------------------------------------------------------------
28
29
// The constructor just sets full to indicate that the buffer is empty:
30
Token_stream::Token_stream()
31
    :full(false), buffer(0)    // no Token in buffer
32
{
33
}
34
35
// The putback() member function puts its argument back into the Token_stream's buffer:
36
void Token_stream::putback(Token t)
37
{
38
    if (full) error("putback() into a full buffer");
39
    buffer = t;       // copy t to buffer
40
    full = true;      // buffer is now full
41
}
42
43
Token Token_stream::get()
44
{
45
    if (full) {         // do we already have a Token ready?
46
                        // remove token from buffer
47
        full=false;
48
        return buffer;
49
    }
50
51
    char ch;
52
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
53
54
    switch (ch) {
55
    case '=':    // for "print"
56
    case 'x':    // for "quit"
57
    case '(': case ')': case '+': case '-': case '*': case '/':
58
        return Token(ch);        // let each character represent itself
59
    case '.':
60
    case '0': case '1': case '2': case '3': case '4':
61
    case '5': case '6': case '7': case '9':
62
    {
63
        cin.putback(ch);         // put digit back into the input stream
64
        double val;
65
        cin >> val;              // read a floating-point number
66
        return Token('8',val);   // let '8' represent "a number"
67
    }
68
    default:
69
        error("Bad token");
70
    }
71
}
72
73
74
75
// Objekterstellung und Vorwärtsdeklaration-------------------------------------
76
77
Token_stream ts;        // provides get() and putback()
78
79
double expression();    // declaration so that primary() can call expression() d.h. Vorwärtdeklaration
80
81
82
83
// Definitionen für primary(), term(), expression()-----------------------------
84
85
// deal with numbers and parentheses
86
double primary()
87
{
88
    Token t = ts.get();
89
    switch (t.kind) {
90
    case '(': case '{':    // handle '(' expression ')'
91
    {
92
        double d = expression();
93
        t = ts.get();
94
        if (t.kind != ')' || t.kind != '}') error("')' expected");
95
        return d;
96
    }
97
    case '8':           // we use '8' to represent a number
98
        return t.value;  // return the number's value
99
    default:
100
        error("primary expected");
101
    }
102
}
103
104
// deal with *, /, and %
105
double term()
106
{
107
    double left = primary();
108
    Token t = ts.get();        // get the next token from token stream
109
110
    while(true) {
111
        switch(t.kind) {
112
        case '*':
113
            left *= primary();
114
            t = ts.get();
115
            break;
116
        case '/':
117
        {
118
            double d = primary();
119
            if (d == 0) error("divide by zero");
120
            left /= d;
121
            t = ts.get();
122
            break;
123
        }
124
        default:
125
            ts.putback(t);     // put t back into the token stream
126
            return left;
127
        }
128
    }
129
}
130
131
// deal with + and -
132
double expression()
133
{
134
    double left = term();      // read and evaluate a Term
135
    Token t = ts.get();        // get the next token from token stream
136
137
    while(true) {
138
        switch(t.kind) {
139
        case '+':
140
            left += term();    // evaluate Term and add
141
            t = ts.get();
142
            break;
143
        case '-':
144
            left -= term();    // evaluate Term and subtract
145
            t = ts.get();
146
            break;
147
        default:
148
            ts.putback(t);     // put t back into the token stream
149
            return left;       // finally: no more + or -: return the answer
150
        }
151
    }
152
}
153
154
155
156
// main-Funktion---------------------------------------------------------------
157
158
int main()
159
try
160
{
161
    cout << "Willkommen zu unserem einfachen Taschenrechnerprogramm\n"
162
         << "Bitte geben Sie einen Ausdruck mit reelen Zahlen ein.\n\n"
163
         << "Erlaubte Operatoren sind + - * /\n"
164
         << "'==' startet berechnung, 'x' beendet das Programm\n\n";
165
    double val = 0;
166
    while (cin) {
167
        Token t = ts.get();
168
        if(t.kind == 'x') break;    // break verlässt die momentane Schleife
169
        switch(t.kind) {
170
        case '=':               // '==' for "print now"
171
            t = ts.get();
172
            if(t.kind == '=')
173
                cout << "=" << val << '\n';
174
            break;
175
        default:
176
            ts.putback(t);
177
            val = expression();
178
            break;
179
        }
180
    }
181
  keep_window_open();
182
}
183
catch (exception& e) {
184
    cerr << "error: " << e.what() << '\n';
185
  keep_window_open();
186
    return 1;
187
}
188
catch (...) {
189
    cerr << "Oops: unknown exception!\n";
190
  keep_window_open();
191
    return 2;
192
}

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]
  • [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.