2009-05-16 1 views
29

Ich mache die Übungen in Stroustrups neuem Buch "Programming Principles and Practice Using C++" und fragte mich, ob jemand auf SO sie getan hat und bereit ist, das Wissen zu teilen? Speziell zu dem Rechner, der in Kap. 6 und 7 entwickelt wurde. ZB die Fragen zum Hinzufügen des! Operator und sqrt(), pow() usw. Ich habe das getan, aber ich weiß nicht, ob die Lösung, die ich habe, der "gute" Weg ist, Dinge zu tun, und es gibt keine veröffentlichten Lösungen auf Bjarnes Website. Ich würde gerne wissen, ob ich auf dem richtigen Weg bin. Vielleicht können wir ein Wiki für die Übungen machen?Hinzufügen der! Bediener und sqrt(), pow() usw. zu einem Rechner Beispielanwendung

Grundsätzlich habe ich einen Token-Parser. Es liest ein Char zu einer Zeit von CIN. Es soll Ausdrücke wie 5 * 3 + 1 symbolisieren und es funktioniert gut dafür. Eine der Übungen besteht darin, eine Funktion sqrt() hinzuzufügen. Also habe ich den Tokening-Code modifiziert, um "sqrt (") zu erkennen und dann ein Token-Objekt zurückzugeben, das sqrt repräsentiert. In diesem Fall benutze ich das char 's. Würden andere das tun? Was, wenn ich sin() implementieren muss? die Case-Anweisung würde chaotisch.

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

switch (ch) { 
    case ';': // for "print" 
    case 'q': // for "quit" 
    case '(': 
    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 '8': 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" 
     } 
    case 's': 
     { 
      char q, r, t, br; 
      cin >> q >> r >> t >> br; 
      if (q == 'q' && r == 'r' && t == 't' && br == '(') { 
       cin.putback('('); // put back the bracket 
       return Token('s'); // let 's' represent sqrt 
      } 

     } 

    default: 
     error("Bad token"); 
} 
+0

Geben Sie einfach Ihren Code hier, und viele Leute werden glücklich sein, Ihnen zu sagen, was verbessert werden kann. Diese Seite enthält alle benötigten Wikis. :) – jalf

+0

Ok ich werde es kurz aufkleben! – PowerApp101

+0

Ich habe die Übung nicht gesehen, aber was seltsam erscheint, ist, dass Sie versuchen, aus jeder Ziffer und jedem Dezimalpunkt, auf den Sie stoßen, eine Verdopplung zu machen. – jbasko

Antwort

210
  • es gibt nur wenige Lösungen veröffentlichten am Stroustrup - Programming und mehr Willen komm her g über die Zeit.

  • Versuchen Sie, Übungen nur mit den Sprachfunktionen und den Bibliotheksfunktionen durchzuführen, die bisher im Buch vorgestellt wurden - echte Anfänger können nichts anderes tun. Kehren Sie später zurück, um zu sehen, wie eine Lösung verbessert werden kann.

+2

Ja, ich habe mit der Karte betrogen ... sie erscheint erst in späteren Kapiteln. Ich genieße das Buch übrigens sehr. Ich denke, der Taschenrechner könnte tatsächlich in der realen Welt nützlich sein, was man nicht über die Beispiele sagen kann, die in den meisten einführenden Büchern vorgestellt werden. – PowerApp101

0

ich würde die ‚sqrt‘ Erkennung in einer anderen Methode zur Funktionserkennung bewegen. im Wesentlichen würde ich die ‚s‘ Erkennung entfernen und etwas in dem Standardfall hinzufügen, das lesen würde String bis zu einem ‚(‘.

Wenn keine ‚(‘ erkannt wird, dann Fehler.

Wenn Sie erfolgreich eine Zeichenfolge lesen, passiert, dass zu einem Funktionsnamen pa rser, das Zeichenkettenvergleiche verwendet, um ein Token zu generieren, das einen Aufruf an sqrt oder sin oder eine Funktion darstellt, die Ihnen gefällt. Die Methode, die nach den Funktionsnamen sucht, kann auch einen Fehler enthalten, wenn sie eine Zeichenfolge liest, die sie nicht erkennt.

+0

Ok, ich werde versuchen, dies zu implementieren Das würde die Funktionssachen schön trennen. – PowerApp101

10

Ich dachte, eine Karte von Strings Zeiger funktionieren könnte eine prägnante Art und Weise sein, usw. darstellen Dinge wie sqrt, sin, cos, die eine einzige Doppel nehmen und zurück ein doppeltes:

map<std::string, double (*)(double)> funcs; 
funcs["sqrt"] = &sqrt; 
funcs["sin"] = &sin; 
funcs["cos"] = &cos; 

Dann, wenn der Parser erkennt eine korrekte Zeichenkette (str) er die Funktion mit einem Argument nennen kann (ARG) wie folgt:

double result = funcs[str](arg); 

mit diesem Verfahren wird ein einziger Aufruf alle Fälle von Funktionen (dieses Typs) verarbeiten kann.

Eigentlich bin ich nicht sicher, ob das die richtige Syntax ist, kann jemand bestätigen?

Scheint dies eine brauchbare Methode?

+7

Es könnte, aber Bjarne Stroustrup beantwortet Ihre Fragen tion. Sich verbeugen. –

4

Es ist einfacher, mit abgeleiteten Klassen und virtuellen Funktionen zu arbeiten: jede spezialisierte Klasse ihren eigenen Eingang zu lesen ...

class base{public: 
virtual double calc()=0; 
}; 
class get_sqrt:public base{ 
int useless; 
public: 
virtual double calc(){cin>>number;return sqrt(number);} 
}get_sqrt; 

jetzt organisieren wir diese in einer Karte, werden wir nur ihre Zeiger verwenden:

map<string,base*> func; 
func["sqrt"]=&get_sqrt; 

gibt es auch eine spezialisierte Methode, die nur auf das nächste Zeichen schaut: peek();

char c=cin.peek(); 

Sie des Schalters erhalten durch Verwendung von 1 zu befreien, wenn und setzen! + - ...in Funktion; (Sollten sie auf left_param der Einfachheit halber arbeiten

if (c>='0'&&c<='9') cin>>right_param; //get a number, you don't have to put the character back as it hasn't been removed 
else{string s; cin>>s;right_param=func[s]->calc();} 

Also im Grunde eine Art von Funktionszeiger aber ohne chaotisch sintax und in Hexe können Sie Daten zwischen Berechnungen speichern

edit: ich dachte an das Leerzeichen Problem;. es kann hinzugefügt werden, bevor es zu berechnen beginnt, ich denke auch, es könnte ein Weg sein, verschiedene Separatoren zu setzen, wie Zahlen, aber ich weiß nicht, wie.

+0

Schön. Ich wusste, dass da irgendwo eine OOP-Lösung sein würde! Aber ... die cin >> s würden nicht funktionieren, weil der Ausdruck keine Leerzeichen enthalten könnte, d. H. 5 + sqrt (144)/2. Also immer noch einen Char auf einmal lesen, um Funktionsnamen wie sqrt zu überprüfen, denke ich. – PowerApp101

+0

Ich denke, es sollte peek sein, nicht Spitze! Ich frage mich, warum Stroustrup diese Methode nicht verwendet hat, sie erscheint logischer als get() und putback(). – PowerApp101

+7

Ich verzichtete auf peek(), um so früh und (noch wichtiger) eine neue Einrichtung zu vermeiden, weil "stream with putback()" eine sehr allgemeine Idee ist, die an vielen Orten verwendet werden kann - peek() involviert jemand anderes einige puffern für dich. Denken Sie auch an Whitespace und Fehlerbehandlung - was ist, wenn es keinen nächsten Charakter gibt, den man betrachten kann? Ich sehe peek() eher als "cleveren Trick" als als allgemeine Technik. –

Verwandte Themen