home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1991 / 05 / review / acalc.cpp next >
Text File  |  1991-02-21  |  7KB  |  175 lines

  1. /*--------------------------------------------------------*/
  2. /*                   ACALC.CPP                            */
  3. /*            Algebraischer Taschenrechner                */
  4. /*     (C) 1991 R. Fischer & TOOLBOX                      */
  5. /* Compiler/Bibliothek: Turbo C++ 1.0 / PSW C++ FlexList  */
  6. /*--------------------------------------------------------*/
  7. const int MaxErrLev=127;    // Achtung: Keine Fehlerprüfung!
  8.  
  9. #include <iostream.h>       // Für Ausgabe des Resultats
  10. #include <stdlib.h>         // Wegen strtod
  11. #include <math.h>           // Wegen pow
  12. #include "flexlist.hpp"     // Für die beiden Stacks
  13.  
  14. enum bool {false=0,true=1};
  15. enum symbol {Plus='+', Minus='-', Mal='*',
  16.     Dividiert='/', Potenz='^',
  17.     KlammerAuf='(', KlammerZu=')'};
  18. struct op {
  19. private:
  20.     symbol OpSymb; // Das Operatorsymbol
  21. public:
  22.     op(char c) : OpSymb(symbol(c)) {};
  23.     signed char prio(void);
  24.     double eval(double links, double rechts);
  25.     int arity()
  26.       { return OpSymb==KlammerAuf ? 0 : 2; }
  27. };
  28. signed char op::prio(void)
  29. {
  30.     switch (OpSymb) {
  31.     case KlammerZu:           return  1;
  32.     case Plus: case Minus:    return 10;
  33.     case Dividiert:           return 20;
  34.     case Mal:                 return 30;
  35.     case Potenz:              return 40;
  36.     case KlammerAuf:          return 99;
  37.     default:
  38.        cout << "Interner Fehler prio <op>: "
  39.             << OpSymb << " unzulässig.";
  40.        return 0;
  41.     }
  42. }
  43. double op::eval(double links, double rechts)
  44. {
  45.    switch(OpSymb) {
  46.    case Plus:     return links+rechts;
  47.    case Minus:    return links-rechts;
  48.    case Mal:      return links*rechts;
  49.    case Dividiert:return links/rechts;
  50.    case Potenz:
  51.              return pow(links,rechts);
  52.    default:
  53.       cout << "Interner Fehler eval <op>: "
  54.            << OpSymb << " unzulässig.";
  55.       return 0;
  56.    }
  57. }
  58.  
  59. struct iScan {
  60. private:
  61.     char **stringliste; // Tabelle mit Pointern
  62.     unsigned maxlines;  // Anzahl der Zeilen in stringliste
  63.     unsigned lineno;    // Akt. Zeilen (0..maxlines-1)
  64.     char *rover;        // Pointer aufs nächste Zeichen
  65.     void cskip(void);   // Trennzeichen überlesen
  66. public:
  67.     iScan(unsigned n, char** tab)
  68.         : maxlines(n), stringliste(tab)
  69.         { lineno=0; rover=*stringliste;};
  70.     bool ende(void)
  71.         { return bool(lineno==maxlines);}
  72.     char folgezeichen(void){return *rover;};
  73.     char Lies1(void);
  74.     double LiesZahl(void);
  75. };
  76. void iScan::cskip(void)
  77. {   if(*rover==char(0))                // Zeilenende?
  78.     {   lineno++;                      // nächste Zeile
  79.         if(!ende())                    // noch Daten da?
  80.         {   rover=stringliste[lineno]; // 1.Zeich. in Zeile
  81.             cskip();                   // könnte Blank sein!
  82.         }
  83.     }
  84.     else if(*rover==' ')               // Trennzeichen?
  85.     {   rover++; cskip(); }            // überspringen!
  86. }
  87. char iScan::Lies1(void)
  88. {    char z=folgezeichen(); // nächstes Zeichen lesen...
  89.      rover++; cskip();      // Trennzeichen überlesen
  90.      return z; // rover zeigt wieder auf gültiges Zeichen!
  91. }
  92. double iScan::LiesZahl(void)
  93. {    double zahl=strtod(rover,&rover); // Zahl berechnen
  94.      cskip();
  95.      return zahl; // rover zeigt wieder auf gült. Zeichen!
  96. }
  97.  
  98. bool reduzieren(
  99.   FlexList &DatenStack,
  100.   FlexList &OpStack)
  101. {   op Operat(char(0));        // Vorbelegen mit Dummy-Wert
  102.     double links,rechts;       // linker, rechter Operand
  103.     OpStack.pop(&Operat);      // Operator lesen
  104.     if(Operat.arity()==2)      // braucht 2 Argumente?
  105.     { DatenStack.pop(&rechts); // rechten Operand holen
  106.       DatenStack.pop(&links);  // linken Operand holen
  107.       DatenStack.push(         // Das Ergebnis wieder in
  108.         new double(            // den Datenstack schreiben
  109.           Operat.eval(links,rechts)));
  110.       return true;
  111.     } else return false;       // Muß KlammerAuf sein!
  112.  }
  113.  
  114. double ausrechnen(
  115.   FlexList &DatenStack,
  116.   FlexList &OpStack)
  117. {   while(OpStack.frontD() &&
  118.        reduzieren(DatenStack,OpStack));
  119.     return DatenStack.frontD() ?
  120.         *(double*)DatenStack.frontD() :0;
  121. }
  122.  
  123. int main(int argc, char *argv[])
  124. {
  125.     bool DatumErwartet=true;         // Zahl oder Operator?
  126.     double ergebnis;                 // Endergebnis
  127.     FlexList D_Stack(sizeof(double));// Datenstack
  128.     FlexList O_Stack(sizeof(op));    // Operatorstack
  129.     iScan Scanner(argc-1,argv+1);    // Eingabescanner
  130.     while(!Scanner.ende())                 // Noch Daten da?
  131.     {   if(DatumErwartet)                  // Folgt Zahl?
  132.         {        // Es muß Zahl oder öffnende Klammer folgen
  133.             if (Scanner.folgezeichen()     // Folgt Klammer?
  134.              == KlammerAuf)
  135.                   O_Stack.push(            // Klammer folgt!
  136.                     new op(
  137.                       Scanner.Lies1()));   // Klammer merken
  138.             else                           // Zahl folgt!
  139.             {  double zahl=Scanner.LiesZahl();
  140.                D_Stack.push(&zahl);        // Zahl merken
  141.                DatumErwartet = false;
  142.             }
  143.         }
  144.         else    // Es muß Operator oder Klammer-zu folgen
  145.         {   if (Scanner.folgezeichen()     // Folgt Klammer?
  146.              == KlammerZu)
  147.             {  Scanner.Lies1();            // Klammer folgt!
  148.                ausrechnen(D_Stack,O_Stack);// Zwischenergeb-
  149.             }                              // nis merken
  150.             else                           // Operator...
  151.             {  op *NeuerOp =               // ...lesen
  152.                 new op(Scanner.Lies1());
  153.                // Der neue Operator wird in jedem Fall im
  154.                // Op-Stack gemerkt. Ist es ein im Vergleich
  155.                // zum Vorgänger niederpriorer Operator, so
  156.                // kann man bereits ein Zwischenergebnis
  157.                // ausrechnen.
  158.                while (
  159.                 O_Stack.frontD() // OpStack nicht leer?
  160.                 && NeuerOp->prio() <=        // Priorität
  161.                      ((op*)O_Stack.frontD()) // niedriger?
  162.                        ->prio()
  163.                )  reduzieren(D_Stack,O_Stack);
  164.                O_Stack.push(NeuerOp);     // Operator merken
  165.                DatumErwartet = true;
  166.             }
  167.         }
  168.     }
  169.     cout << (ergebnis=ausrechnen(D_Stack,O_Stack));
  170.     return ergebnis>0 && ergebnis<=(MaxErrLev+0.5)
  171.            ? int(ergebnis+0.5) /* runden! */ : 0;
  172. }
  173. /*--------------------------------------------------------*/
  174. /*              Ende von ACALC.CPP                        */
  175.