home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* UPN22.PAS *)
- (* Eingabe in Infix-Notation, Rechnung mit Postfix-Term *)
- (* (c) 1991 Wolfgang Müllner & TOOLBOX *)
- (* ------------------------------------------------------ *)
- PROGRAM Taschenrechner_in_UPN;
-
- USES Crt, RealStck, ChStack, ScrnStck, ScrnOut;
-
- CONST
- Ziffern = ['0'..'9'];
- MonOperator = ['s','S','k','K','W','w','q','Q',
- 'e','E','L','l'];
- (* Sinus, Kosinus, (Quadrat-) Wurzel, Quadrat, Exponent,
- Log zur Basis e *)
- BinOperator = ['+','-','*','/','^'];
-
- TYPE
- Meldung = ARRAY[1..10] OF ScrnOut.S80;
-
- VAR
- TermInfix, Term : STRING;
- Ergebnis, Dummy, links, rechts, deltaX : RealStck.ElTyp;
- I : INTEGER;
- Scrn1, Scrn2 : Bildschirm; (* aus UNIT ScrnStck *)
-
- (* Diese Variablen sollen verschiedene Bildschirme
- zwischenspeichern. *)
- M : Meldung;
-
-
- PROCEDURE SmR(y1, y2 : INTEGER;
- M : Meldung;
- Schatten : BOOLEAN);
- (* Schreibt einen Rahmen um die Strings aus dem Array M.
- Die Ausgabe erfolgt mittig, es müssen nur die y-Werte
- übergeben werden. *)
- VAR
- I, Anzahl, Breite : INTEGER;
-
- FUNCTION x(B : INTEGER; links : BOOLEAN) : INTEGER;
- BEGIN
- IF links THEN x := 39 - B
- ELSE x := 41 + B;
- END;
-
- BEGIN
- Anzahl := y2 - y1 - 1;
- Breite := 0;
- (* Bestimme den breitesten String *)
- FOR I := 1 TO Anzahl DO
- IF Breite < Length(M[I]) THEN
- Breite := Length(M[I]);
- Breite := Breite DIV 2;
- Rahmen(x(Breite, TRUE), y1,
- x(Breite, FALSE), y2, Schatten);
- FOR I := 1 TO Anzahl DO BEGIN
- Breite := Length(M[I]) DIV 2;
- WrtXY(40-Breite, y1+I, M[I]);
- END;
- END;
-
- PROCEDURE Vorspann;
- CONST
- S : ARRAY[1..13] OF S80 =
- (' Erweiterung 1 ',' Erkannt werden reelle',
- ' Koeffizienten und x ', ' als Variable. ',
- ' Erweiterung 2.1 ',' Terme können in Infix-',
- ' Schreibweise eingege- ',' ben werden. ',
- ' Erweiterung 2.2 ',' Die Ausgabe ist dem ',
- ' heutigen Standard an- ',' gepaßt. ',
- ' w e i t e r m i t RET . .');
- BEGIN
- ClrScr;
- Rahmen(1,1,80,25,FALSE);
- Hintergrund(2,2,79,24,'║');
- Scrn1 := Screen^;
- FillChar(M,SizeOf(M),' ');
- M[1] := ' UPN-Taschenrechner-Simulation ';
- M[2] := ' (UPN / Umgekehrt Polnische Notation) ';
- SmR(2,5,M,TRUE);
- FillChar(M,SizeOf(M),' ');
- M[1] := ' Beispiele ';
- M[2] := ' Infix-Notation (AOS) '
- +' Postfix-Notation (UPN) ';
- M[3] := ' (Schulalltag) '
- +' (ungewohnt, aber elegant)';
- M[4] := ' (3-2)^5 '
- +' 3,2-5^ ';
- M[5] := ' 5*s(2) ( s für sin ) '
- +' 5,2s* ';
- M[6] := ' x^2-2.8*x+7.3 '
- +' x2^2.8x*-7.3+ ';
- SmR(8,15,M,FALSE);
- Farbe(WeissVorRot); Rahmen( 2,17,25,22,FALSE);
- Rahmen(28,17,52,22,FALSE); Rahmen(55,17,79,22,FALSE);
- WrtXY(3,18,S[1]); Farbe(GelbVorBlau);
- WrtXY(3,19,S[2]); WrtXY( 3,20,S[3]);
- WrtXY(3,21,S[4]); Farbe(WeissVorRot);
- WrtXY(29,18,S[5]); Farbe(GelbVorBlau);
- WrtXY(29,19,S[6]); WrtXY(29,20,S[7]);
- WrtXY(29,21,S[8]); Farbe(WeissVorRot);
- WrtXY(56,18,S[9]); Farbe(GelbVorBlau);
- WrtXY(56,19,S[10]); WrtXY(56,20,S[11]);
- WrtXY(56,21,S[12]);
- Rahmen(80-Length(S[13])-5,23,78,25,FALSE);
- WrtXY(80-Length(S[13])-3,24,S[13]); GotoXY(1,1);
- ReadLn;
- Screen^ := Scrn1
- END;
-
- PROCEDURE EingabeString(VAR Term : STRING);
- VAR
- x, y : INTEGER;
- OK : BOOLEAN;
- BEGIN
- FillChar(M,SizeOf(M),' ');
- M[1] := ' Erlaubte Operationen ';
- Farbe(WeissVorRot); SmR(2,4,M,FALSE);
- Farbe(DunkelgrauVorHellgrau);
- FillChar(M,SizeOf(M),' ');
- M[1] := ' Binäre Operationen '
- +' Monäre Operationen ';
- M[2] := ' (zwei Operanden) '
- +' (ein Operand) ';
- M[3] := ' ----------------------'
- +'--------------------------------------- ';
- M[4] := ' + - '
- +' S(inus) K(osinus) W(urzel) ';
- M[5] := ' * / '
- +' Q(uadrat) E(xponent) L(oga-';
- M[6] := ' ^ '
- +' rithmus zur Basis e) ';
- SmR(5,12,M,TRUE);
- Farbe(BlauVorHellgrau);
- FillChar(M,SizeOf(M),' ');
- M[1] := ' Hinweis: Eine Prüfung '
- +'findet nur hinsichtlich der erlaubten ';
- M[2] := ' Zeichen, nich'
- +'t jedoch auf korrekte Syntax statt ! ';
- SmR(14,17,M,TRUE);
- FillChar(M,SizeOf(M),' ');
- Farbe(WeissVorRot);
- M[1] := ' Funktionsterm in (gewo'
- +'hnter) Infix-Schreibweise eingeben : ';
- SmR(19,23,M,FALSE);
- WrtXY(40-(Length(M[1]) DIV 2),21,' Eingabe : ');
- x :=21; y:=21;
- OK := FALSE;
- Scrn2 := Screen^;
- REPEAT
- Screen^ := Scrn2;
- GotoXY(x,y); ReadLn( Term );
- GotoXY(x,y+1); write('Alles ok ? j/n');
- OK := (UpCase(ReadKey)='J')
- UNTIL OK;
- Farbe(GelbVorBlau);
- Screen^ := Scrn1;
- END;
-
- PROCEDURE EingabeGrenzen(Term : S80;
- VAR links, rechts, deltaX : RealStck.ElTyp);
- CONST
- S : ARRAY[1..4] OF S80 =
- (' Eingabe Startwert : ',
- ' Endwert : ',
- ' Schrittweite : ',
- ' Alles ok ? j/n ');
- VAR x, y : INTEGER;
- OK : BOOLEAN;
- BEGIN
- (* Überschrift *)
- FillChar(M,SizeOf(M),' ');
- M[1] := 'f(x) = '+Term;
- M[2] := ' ';
- M[3] := ' Eingabe von Intervall'
- +'grenzen und Schrittweite ';
- Farbe(DunkelgrauVorHellgrau ); SmR(2,6,M,TRUE);
- Farbe(GelbVorBlau);
- Rahmen(5,10,32,15,FALSE);
- WrtXY(6,11,S[1]); x:=6+Length(S[1]); y := 11;
- WrtXY(6,12,S[2]);WrtXY(6,13,S[3]);
- Scrn2 := Screen^;
- REPEAT
- Screen^ := Scrn2;
- GotoXY(x,y); ReadLn(links);
- GotoXY(x,y+1); ReadLn(rechts);
- GotoXY(x,y+2); ReadLn(deltaX);
- WrtXY(6,14,S[4]); GotoXY(1,1);
- OK := (UpCase(ReadKey) = 'J') AND (deltaX <> 0);
- UNTIL OK;
- Screen^ := Scrn1;
- END;
-
- FUNCTION LeseReelleZahl(T : STRING;
- VAR I : INTEGER) : REAL;
- (* Liest eine reelle Zahl aus dem übergebenen String und
- gibt in I Anzahl der schon gelesenen Zeichen zurück. *)
- VAR
- KommaErkannt : BOOLEAN;
- Zahl, (* Speichert schon gelesenen Teil *)
- Position : REAL; (* Speichert Kehrwert der Wertigkeit *)
- L : INTEGER; (* der aktuellen Nachkommastelle *)
-
- FUNCTION Wert(CH : CHAR) : INTEGER;
- (* Konvertierung Zeichen - entsprechende Ziffer *)
- BEGIN
- Wert := (Ord(CH) - 48);
- END;
-
- BEGIN
- Zahl := 0; KommaErkannt := FALSE;
- Position := 1; L := Length(T);
- WHILE (I <= L) AND ((T[I] IN Ziffern) OR
- ((T[I] = '.') AND (NOT KommaErkannt))) DO BEGIN
- IF T[I] = '.' THEN
- KommaErkannt := TRUE
- ELSE IF NOT KommaErkannt THEN BEGIN
- (* Man ist noch vor dem Komma und die
- Stellenwertigkeit ist eine Zehnerpotenz *)
- (* Null anfügen *)
- Zahl := Zahl * 10;
- (* Einer dazu *)
- Zahl := Zahl + Wert(T[I]);
- END ELSE BEGIN
- (* Man ist nach dem Komma, die Stel-
- lenwertigkeit beträgt eine Potenz von 1/10 *)
- Position := Position * 10;
- Zahl := Zahl + Wert(T[I]) / Position;
- END;
- I := I + 1
- END;
- I := I - 1;
- (* Korrektur, da letzte Erhöhung zum Abbruch führte *)
- LeseReelleZahl := Zahl
- END;
-
- PROCEDURE AuswertungTerm( Term : STRING;
- x : RealStck.ElTyp;
- VAR Erg : RealStck.ElTyp);
- VAR
- Stack : RealStck.KELLER;
-
- PROCEDURE MonOp(Operation : CHAR;
- VAR Element : RealStck.ElTyp);
- (* Wendet die ausgewählte Operation auf Element an und
- gibt das Ergebnis in Element zurück. *)
- BEGIN
- CASE UpCase(Operation) OF
- 'S' : Element := Sin(Element);
- 'K' : Element := Cos(Element);
- 'W' : Element := Sqrt(Element);
- 'Q' : Element := Sqr(Element);
- 'E' : Element := Exp(Element);
- 'L' : Element := Ln(Element)
- END;
- END;
-
- PROCEDURE BinOp( El1 : RealStck.ElTyp;
- Operation : CHAR;
- El2 : RealStck.ElTyp;
- VAR Erg : RealStck.ElTyp);
- (* Wendet auf die übergebenen Operanden El1 und El2
- die ausgewählte Operation an (Reihenfolge festgelegt
- durch den Index!) und gibt in Erg das Ergebnis zu-
- rück. *)
-
- FUNCTION Potenz(Basis : RealStck.ElTyp;
- Exponent : INTEGER) : REAL;
- (* Liefert die Zahl Basis hoch Exponent *)
- VAR
- Erg : REAL;
- BEGIN
- Erg := 1.0;
- WHILE Exponent > 0 DO BEGIN
- Erg := Erg * Basis;
- Exponent := Pred(Exponent);
- END;
- Potenz := Erg
- END;
-
- BEGIN
- CASE Operation OF
- '+' : Erg := El1 + El2;
- '-' : Erg := El1 - El2;
- '*' : Erg := El1 * El2;
- '/' : Erg := El1 / El2;
- '^' : Erg := Potenz(El1, Trunc(El2));
- END;
- END;
-
- VAR
- L, SchonGelesen : INTEGER;
- Zeichen : CHAR;
- Zahl, Element1, Element2,
- Element, Ergebnis : RealStck.ElTyp;
-
- BEGIN
- RealStck.StackInit(Stack);
- SchonGelesen := 1;
- (* SchonGelesen "zeigt" auf die Position bis zu
- der der übergebene String schon gelesen wurde *)
- L := Length( Term );
- WHILE SchonGelesen <= L DO BEGIN
- Zeichen := Term[SchonGelesen];
- IF Zeichen IN Ziffern THEN
- RealStck.PUSH(Stack,
- LeseReelleZahl(Term, SchonGelesen))
- ELSE IF Zeichen IN MonOperator THEN BEGIN
- RealStck.POP(Stack, Element);
- MonOp(Zeichen, Element);
- RealStck.PUSH(Stack, Element);
- END ELSE IF Zeichen IN BinOperator THEN BEGIN
- RealStck.POP(Stack,Element2);
- RealStck.POP(Stack,Element1);
- BinOp(Element1, Zeichen, Element2,Ergebnis);
- RealStck.PUSH(Stack, Ergebnis);
- END ELSE IF (Zeichen='x') OR (Zeichen='X') THEN
- RealStck.PUSH(Stack, x)
- ELSE IF Zeichen=',' THEN
- SchonGelesen := Succ(SchonGelesen)
- (* Einfach überlesen ! *)
- ELSE
- WriteLn('Fehler ! Zeichen ', Zeichen, ' ?');
- (* Ende der Auswertung eines Zeichens. *)
- SchonGelesen := Succ(SchonGelesen);
- END;
- (* Jetzt ist im Stack das Ergebnis. Dieses wird in Erg
- zurückgegeben *)
- RealStck.POP(Stack, Erg);
- END;
-
- PROCEDURE Konvertiere( Infix : STRING;
- VAR Postfix : STRING);
- (* Es wird ein in Infix-Notation geschriebener String in
- einen Postfix-String konvergiert. *)
-
- FUNCTION Priority(Op : CHAR) : INTEGER;
- (* Diese Funktion gibt die Priorität einer Operation zu-
- rück. Da im Stapel auch "Klammer auf" abgelegt wird,
- bekommt dieses Zeichen auch eine Priorität zugewiesen,
- und zwar die niedrigste . Je höher der zurückgegebene
- Wert, desto vorrangiger wird die Operation ausgeführt.
- *)
- BEGIN
- CASE Op OF
- '(' : Priority := 1;
- '+','-' : Priority := 2; (* binäre *)
- '*','/' : Priority := 3; (* Opera- *)
- '^' : Priority := 4; (* toren *)
- 'S','K','W', (* monäre *)
- 'Q','E','L' : Priority := 5 (* Operatoren *)
- END;
- END; (* von priority *)
-
- VAR
- SchonGelesen, L, LaengePostfix : INTEGER;
- oben, Zeichen : ChStack.ElTyp;
- Stapel : ChStack.KELLER;
- ZuletztZahlGespeichert : BOOLEAN;
- Zahl : REAL;
- S, Sganz : STRING;
- Merker, Breite, Nachkomma, Ganzteil : INTEGER;
-
- BEGIN
- ChStack.StackInit(Stapel);
- Postfix := ''; L := Length(Infix); SchonGelesen := 1;
- ZuletztZahlGespeichert := FALSE;
- WHILE SchonGelesen <= L DO BEGIN
- Zeichen := Infix[ SchonGelesen ];
- IF (Zeichen IN MonOperator) OR (Zeichen = 'x') THEN
- Zeichen := UpCase(Zeichen);
- CASE Zeichen OF
- 'X' : Postfix := Postfix + 'X';
- '0'..'9' : BEGIN
- LaengePostfix := Length(Postfix);
- IF LaengePostfix > 0 THEN
- ZuletztZahlGespeichert :=
- (Postfix[LaengePostfix] IN Ziffern);
- IF ZuletztZahlGespeichert THEN
- Postfix := Postfix + ',';
- (* Somit Trennzeichen gesetzt. *)
- Merker := SchonGelesen;
- Zahl :=
- LeseReelleZahl(Infix, SchonGelesen);
- (* Es muß nun ermittelt werden, aus
- wievielen Stellen die Zahl besteht
- und wieviele Nachkommastellen vor-
- handen sind.
- Zuerst die Breite der Zahl. *)
- Breite := SchonGelesen-Merker+1;
- (* Anzahl der Nachkommastellen *)
- IF (Trunc(Zahl) - Zahl < 0) THEN BEGIN
- (* Zahl ist nicht ganz *)
- Str(Trunc(Zahl), Sganz);
- Nachkomma := Breite-Length(Sganz) -1;
- END ELSE Nachkomma := 0;
- (* Konvergiere Zahl in String*)
- Str(Zahl:Breite:Nachkomma, S);
- Postfix := Postfix + S;
- END;
- '(','S','K',
- 'W','Q','E',
- 'L' : ChStack.PUSH(Stapel, Zeichen);
- '+','-','*',
- '/','^' : BEGIN
- (* nur lesen *)
- ChStack.TOP(Stapel, oben);
- WHILE (NOT ChStack.IstLeer(Stapel)) AND
- (Priority(Zeichen) <= Priority(oben))
- DO BEGIN
- (* jetzt entfernen *)
- ChStack.POP(Stapel, oben);
- Postfix := Postfix + oben;
- ChStack.TOP(Stapel, oben)
- END;
- ChStack.PUSH(Stapel, Zeichen);
- END;
- ')' : BEGIN
- (* Alles vom Stapel bis "Klammer auf" *)
- ChStack.POP(Stapel, oben);
- WHILE oben <> '(' DO BEGIN
- Postfix := Postfix + oben;
- ChStack.POP(Stapel, oben);
- END
- END;
- END;
- SchonGelesen := Succ(SchonGelesen);
- END;
- WHILE NOT ChStack.IstLeer(Stapel) DO BEGIN
- (* Übertrage den Rest des Kellers *)
- ChStack.POP(Stapel, oben);
- Postfix := Postfix + oben;
- END
- END;
-
- FUNCTION machLesbarer(S : STRING) : STRING;
- (* Ersetzt die verabredeten Abkürzungen für die monären
- Oparationen durch die allgemein üblichen Namen. *)
- VAR
- i, Stelle : INTEGER;
- D(* ummy *) : STRING;
- BEGIN
- D := S;
- (* "Stelle" zeigt auf aktuelle Stelle im String D *)
- Stelle := 1;
- (* I zeigt auf aktuelle Stelle im String S *)
- FOR i := 1 TO Length(S) DO BEGIN
- IF S[i] IN MonOperator THEN BEGIN
- D[Stelle] := UpCase(S[i]);
- CASE D[Stelle] OF
- 'S' : BEGIN (* Sinus *)
- Insert('IN', D, Succ(Stelle));
- Stelle := Succ(Succ(Stelle));
- END;
- 'K' : BEGIN (* Kosinus *)
- Delete(D, Stelle, 1);
- Insert('COS', D, Stelle);
- Stelle := Succ(Succ(Stelle));
- END;
- 'W' : BEGIN (* Quadratwurzel *)
- Delete(D, Stelle, 1);
- Insert('SQRT', D, Stelle);
- Stelle := Succ(Succ(Succ(Stelle)));
- END;
- 'Q' : BEGIN (* Quadrat *)
- Delete(D, Stelle, 1);
- Insert('SQR', D, Stelle);
- Stelle := Succ(Succ(Stelle));
- END;
- 'L' : BEGIN (* Log. naturalis *)
- Insert('N', D, Succ(Stelle));
- Stelle := Succ(Stelle);
- END;
- 'E' : BEGIN (* e hoch x *)
- Insert('XP', D, Succ(Stelle));
- Stelle := Succ(Stelle);
- END
- END;
- END;
- Stelle := Succ(Stelle);
- END;
- machLesbarer := D;
- END;
-
- PROCEDURE vertausche(VAR x, y : REAL);
- VAR
- Dummy : REAL;
- BEGIN
- Dummy := x ; x := y ; y := Dummy
- END;
-
- PROCEDURE WerteTabelle(TermInfix, Term : S80;
- links, rechts, deltaX : RealStck.ElTyp);
- VAR
- Satz, Wort : S80;
- Ergebnis : RealStck.ElTyp;
- I : INTEGER;
- BEGIN
- Screen^ := Scrn1;
- FillChar(M,SizeOf(M),' ');
- M[1] := ' < < W e r t e t a b e l l e > > ';
- Farbe(BlauVorHellgrau); SmR(3, 5, M, TRUE);
- Farbe(WeissVorRot); Rahmen(10,8,70,23,FALSE);
- M[1] := ' x-Wert y = f(x) = ' +
- machLesbarer(TermInfix);
- Farbe(DunkelgrauVorHellgrau); SmR(9, 11, M, FALSE);
- Farbe(GelbVorBlau);
- Scrn2 := Screen^;
- I := 12;
- WHILE links <= rechts DO BEGIN
- IF (i = 23) THEN BEGIN
- Satz := 'w e i t e r m i t RET . .';
- Farbe(WeissVorRot);
- Rahmen(75 - Length(Satz), 23, 78, 25, FALSE);
- WrtXY(76 - Length(Satz), 24, Satz);
- Farbe(GelbVorBlau);
- ReadLn;
- Screen^ := Scrn2;
- i := 12;
- END;
- AuswertungTerm(Term, links, Ergebnis);
- (* Wandle x-Wert in String um, wg WrtXY *)
- Str(links:13:2, Wort);
- WrtXY(16, i, Wort);
- (* Wandle Ergebnis in String um, wg WrtXY *)
- Str(Ergebnis:13:2, Wort);
- WrtXY(38, i, Wort);
- links := links + deltaX;
- i := Succ(i);
- END;
- END;
-
- BEGIN
- Vorspann;
- EingabeString(TermInfix);
- Konvertiere(TermInfix, Term);
- EingabeGrenzen(machLesbarer(TermInfix), links,
- rechts, deltaX);
- IF links > rechts THEN vertausche(links, rechts);
- WerteTabelle(TermInfix, Term, links, rechts, deltaX);
- ReadLn;
- ClrScr
- END.
- (* ------------------------------------------------------ *)
- (* Ende von UPN22.PAS *)