Hi
Ich habe das mal durch den Kate auto-aligner gelassen, um es ein bisschen einzurücken.
C++:
//============================================================================
// Name : Lab2.cpp
// Author : Denis
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include<stack>
#include<sstream>
using namespace std;
bool operatoren(const string& input);
bool checkdoublenumber(const string& input);
void opausfueren(const string& input, stack<double>& RechnerStack);
// Main
int main() {
cout << "Der UPN Taschenrechner" << endl; // prints !!!Hello World!!!
stack<double> RechnerStack;
string input;
while(true)
{
cout << ">>";
cin >> input;
double Zahl;
if(istringstream(input) >> Zahl)
{
RechnerStack.push(Zahl);
}
else if (checkdoublenumber(input))
{
}
else if (operatoren(input))
{
opausfueren(input, RechnerStack);
}
else if (input == "q" || "x")
{
return 0;
}
else
{
cout << "Invalid input" << endl;
}
}
}
// Funktionen
bool operatoren(const string& input)
{
string operatoren[] = {"-", "+", "*", "/"}; // string array mit verfügbaren Operatoren
for(int i=0; i<4;i++)
{
if(input == operatoren[i]) // wenn
{
return true;
}
}
return false;
}
void opausfueren(const string& input, stack<double>& RechnerStack)
{
double zahl1, zahl2, ergebnis;
zahl2 = RechnerStack.top();
RechnerStack.pop();
zahl1 = RechnerStack.top();
RechnerStack.pop();
if (input == "-")
{
ergebnis = zahl1 - zahl2;
}
else if (input == "+")
{
ergebnis = zahl1 + zahl2;
}
else if (input == "*")
{
ergebnis = zahl1 * zahl2;
}
else
{
ergebnis = zahl1 / zahl2;
}
cout << ergebnis << endl;
RechnerStack.push(ergebnis);
}
////////////////////////////////////////////////////////////////////////////
bool checkdoublenumber(const string& input){
enum states{
Vorzeichen,
Vorkomma,
Nachkomma,
Exponent
};
states state = Vorzeichen;
for(unsigned int i = 0; i < input.size(); i++)
{
char c = input[i];
{
}
switch(state){
case Vorzeichen:
if(c == '-') {
state = Vorkomma;
}
else if(c == '.'){
state = Nachkomma;
}
else if(!isdigit(c)){
return false;
}
break;
case Vorkomma: if(!isdigit(c)){
state = Vorkomma;
}
else if (c == '.'){
state = Nachkomma;
}
break;
case Nachkomma: if(!isdigit(c)){
state = Nachkomma;
}
else if ((c == 'e') || (c == 'E')){
state = Exponent;
}
break;
//case Exponent:
if(c == '-'){
// state = Vorzeichen;
// }
// else if(c != Vorzeichen){
// return false;
// }
// else if (!isdigit(c)){
// state = Nachkomma;
}
break;
default: cout << "Keine gültige eingabe" << endl;
break;
}
}
}
Das Programm rechnet auch wie es soll nur erkennt das Programm nicht das (4-e) ein Fehler ist.
Nun, du prüfst nicht alle Fälle.
Der State "Vorzeichen" müsste so korrekt sein (auch wenn man das ein bisschen optimieren könnte).
Der State Vorkomma: Falls es keine Ziffer ist, bleibt der State ja nicht ein Vorkomma? Dann sollte es eigentlich als falsch bezeichnet werden.
("-abc" wäre nach dieser Prüfung eine korrekte Doublezahl).
Den Fall "c == '.'" würde ich daher zuerst bearbeiten, also
C++:
case Vorkomma:
if(c == '.') state = Nachkomma;
else if(!isdigit(c)) return false;
break;
(Kommt hier drauf an, ob "4e10" eine Doublezahl sein soll. Falls ja, dann musst du zusätzlich auf 'e' prüfen).
Der State Nachkomma ist analog zu behandeln (hier ist 'e' / 'E' erwartet für den Statewechsel, sonst, falls nicht isdigit() abbrechen, sonst einfach weitermachen in diesem State).
Den Case Exponent behandelst du in diesem Code ja nicht einmal?
Anyway, in den State "Vorzeichen" zu wechseln ist hier sicher falsch.
Wenn schon, dann müsstest du einen neuen State "ExpVorzeichen" erschaffen, der dann einzig den Exponenten behandelt.
Dein aktueller Code akzeptiert übrigens nur dann eine Eingabe nicht, wenn das erste Zeichen weder '-' noch '.' noch eine Ziffer ist.
Ansonsten wird alles akzeptiert (bzw. der Rückgabewert ist undefiniert).
Du solltest am Ende der Funktion ein "return true" hinzufügen, damit klar ist, dass, falls ein String durch alle States ohne Fehler durchkommt, dieser eine gültige Double-Zahl ist.
Ich habe mir überlegt das so zu machen das ich die Eingabe mit dem Case Vorzeichen und einem Integer vergleiche:
while(Vorzeichen = True and c == b)
do...return false;
Also erstens müsste das
C++:
while(state == Vorzeichen && c == b)
{
return false,
}
lauten und zweitens verstehe ich nicht, was du damit erreichen willst.
Ich weiss echt nicht, wie ich dir die States noch besser erläutern kann...
Ein einfaches Beispiel vielleicht:
Sagen wir, du baust einen Kühlschrank. Wenn die Türe aufgeht, soll das Licht gradiell angehen, geht die Türe zu, soll das Licht sofort abschalten.
Code:
State: Zu ====Türe auf====> State: Öffnen ==Hell_Genug==> State: Offen ==== Türe zu ====> State: Schliessen ===== Türe geschlossen ===> State: Zu
| |
| |
heller() =>|
Hier ist der Erste und der Letzte State natürlich derselbe, aber es ist schwierig, das in ASCII so hinzuzeichnen.
Hier hat einzig der State "Öffnen" eine Sonderfunktion: Es wird der Helligkeitswert stetig erhöht, bis dieser hoch genug ist, dann wird in den State "Offen" gewechselt.
Im State "Zu" ist das Licht aus. Im State Offen ist es komplett an. Im State "Öffnen" nimmt es zu.
Im State "Schliessen" bleibt es an, wir bräuchten diesen State für dieses Modell also gar nicht.
Wichtig ist hier aber: Der State "Öffnen" wird niemals bleiben. Nach einer gewissen Zeit wechselt dieser State automatisch zu "Offen". Die anderen States können theoretisch bleiben ("Schliessen" ist ein Spezialfall, da er eigentlich nichts macht).
In deinem Beispiel sind die State-Transitions (hier mit ==== <Name> ==> bezeichnet) die Gründe, warum ein Stateswitch stattfindet. Für dein Beispiel ist es z.B. "State: Vorzeichen === '.' ===> State: Nachkomma".
Deine State Machine muss immer an ein Ende kommen; kam sie ohne Fehler dahin, dann ist die Eingabe korrekt.
Das heisst für dich: Jedes Zeichen, das erwartet wurde (entweder als Signal für einen Statewechsel oder ein Signal für ein beibehalten des State), ist ok. Alle anderen Zeichen sorgen dafür, dass die FSM sofort abbricht und einen Fehler meldet.
Dein aktueller Code tut das nur für den ersten Case ("Vorzeichen"), der Rest hat keine einzige Abbruchbedingung...
Vielleicht half das ja etwas...
Gruss
cwriter