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