home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------*/
- /* ACALC.CPP */
- /* Algebraischer Taschenrechner */
- /* (C) 1991 R. Fischer & TOOLBOX */
- /* Compiler/Bibliothek: Turbo C++ 1.0 / PSW C++ FlexList */
- /*--------------------------------------------------------*/
- const int MaxErrLev=127; // Achtung: Keine Fehlerprüfung!
-
- #include <iostream.h> // Für Ausgabe des Resultats
- #include <stdlib.h> // Wegen strtod
- #include <math.h> // Wegen pow
- #include "flexlist.hpp" // Für die beiden Stacks
-
- enum bool {false=0,true=1};
- enum symbol {Plus='+', Minus='-', Mal='*',
- Dividiert='/', Potenz='^',
- KlammerAuf='(', KlammerZu=')'};
- struct op {
- private:
- symbol OpSymb; // Das Operatorsymbol
- public:
- op(char c) : OpSymb(symbol(c)) {};
- signed char prio(void);
- double eval(double links, double rechts);
- int arity()
- { return OpSymb==KlammerAuf ? 0 : 2; }
- };
- signed char op::prio(void)
- {
- switch (OpSymb) {
- case KlammerZu: return 1;
- case Plus: case Minus: return 10;
- case Dividiert: return 20;
- case Mal: return 30;
- case Potenz: return 40;
- case KlammerAuf: return 99;
- default:
- cout << "Interner Fehler prio <op>: "
- << OpSymb << " unzulässig.";
- return 0;
- }
- }
- double op::eval(double links, double rechts)
- {
- switch(OpSymb) {
- case Plus: return links+rechts;
- case Minus: return links-rechts;
- case Mal: return links*rechts;
- case Dividiert:return links/rechts;
- case Potenz:
- return pow(links,rechts);
- default:
- cout << "Interner Fehler eval <op>: "
- << OpSymb << " unzulässig.";
- return 0;
- }
- }
-
- struct iScan {
- private:
- char **stringliste; // Tabelle mit Pointern
- unsigned maxlines; // Anzahl der Zeilen in stringliste
- unsigned lineno; // Akt. Zeilen (0..maxlines-1)
- char *rover; // Pointer aufs nächste Zeichen
- void cskip(void); // Trennzeichen überlesen
- public:
- iScan(unsigned n, char** tab)
- : maxlines(n), stringliste(tab)
- { lineno=0; rover=*stringliste;};
- bool ende(void)
- { return bool(lineno==maxlines);}
- char folgezeichen(void){return *rover;};
- char Lies1(void);
- double LiesZahl(void);
- };
- void iScan::cskip(void)
- { if(*rover==char(0)) // Zeilenende?
- { lineno++; // nächste Zeile
- if(!ende()) // noch Daten da?
- { rover=stringliste[lineno]; // 1.Zeich. in Zeile
- cskip(); // könnte Blank sein!
- }
- }
- else if(*rover==' ') // Trennzeichen?
- { rover++; cskip(); } // überspringen!
- }
- char iScan::Lies1(void)
- { char z=folgezeichen(); // nächstes Zeichen lesen...
- rover++; cskip(); // Trennzeichen überlesen
- return z; // rover zeigt wieder auf gültiges Zeichen!
- }
- double iScan::LiesZahl(void)
- { double zahl=strtod(rover,&rover); // Zahl berechnen
- cskip();
- return zahl; // rover zeigt wieder auf gült. Zeichen!
- }
-
- bool reduzieren(
- FlexList &DatenStack,
- FlexList &OpStack)
- { op Operat(char(0)); // Vorbelegen mit Dummy-Wert
- double links,rechts; // linker, rechter Operand
- OpStack.pop(&Operat); // Operator lesen
- if(Operat.arity()==2) // braucht 2 Argumente?
- { DatenStack.pop(&rechts); // rechten Operand holen
- DatenStack.pop(&links); // linken Operand holen
- DatenStack.push( // Das Ergebnis wieder in
- new double( // den Datenstack schreiben
- Operat.eval(links,rechts)));
- return true;
- } else return false; // Muß KlammerAuf sein!
- }
-
- double ausrechnen(
- FlexList &DatenStack,
- FlexList &OpStack)
- { while(OpStack.frontD() &&
- reduzieren(DatenStack,OpStack));
- return DatenStack.frontD() ?
- *(double*)DatenStack.frontD() :0;
- }
-
- int main(int argc, char *argv[])
- {
- bool DatumErwartet=true; // Zahl oder Operator?
- double ergebnis; // Endergebnis
- FlexList D_Stack(sizeof(double));// Datenstack
- FlexList O_Stack(sizeof(op)); // Operatorstack
- iScan Scanner(argc-1,argv+1); // Eingabescanner
- while(!Scanner.ende()) // Noch Daten da?
- { if(DatumErwartet) // Folgt Zahl?
- { // Es muß Zahl oder öffnende Klammer folgen
- if (Scanner.folgezeichen() // Folgt Klammer?
- == KlammerAuf)
- O_Stack.push( // Klammer folgt!
- new op(
- Scanner.Lies1())); // Klammer merken
- else // Zahl folgt!
- { double zahl=Scanner.LiesZahl();
- D_Stack.push(&zahl); // Zahl merken
- DatumErwartet = false;
- }
- }
- else // Es muß Operator oder Klammer-zu folgen
- { if (Scanner.folgezeichen() // Folgt Klammer?
- == KlammerZu)
- { Scanner.Lies1(); // Klammer folgt!
- ausrechnen(D_Stack,O_Stack);// Zwischenergeb-
- } // nis merken
- else // Operator...
- { op *NeuerOp = // ...lesen
- new op(Scanner.Lies1());
- // Der neue Operator wird in jedem Fall im
- // Op-Stack gemerkt. Ist es ein im Vergleich
- // zum Vorgänger niederpriorer Operator, so
- // kann man bereits ein Zwischenergebnis
- // ausrechnen.
- while (
- O_Stack.frontD() // OpStack nicht leer?
- && NeuerOp->prio() <= // Priorität
- ((op*)O_Stack.frontD()) // niedriger?
- ->prio()
- ) reduzieren(D_Stack,O_Stack);
- O_Stack.push(NeuerOp); // Operator merken
- DatumErwartet = true;
- }
- }
- }
- cout << (ergebnis=ausrechnen(D_Stack,O_Stack));
- return ergebnis>0 && ergebnis<=(MaxErrLev+0.5)
- ? int(ergebnis+0.5) /* runden! */ : 0;
- }
- /*--------------------------------------------------------*/
- /* Ende von ACALC.CPP */