home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 05 / tricks / upn.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1990-01-15  |  15.1 KB  |  430 lines

  1. (* ------------------------------------------------------ *)
  2. (*                      UPN.PAS                           *)
  3. (*    (c) 1989, 1990 C.Ohr, Albin Bigalke & TOOLBOX       *)
  4. (* ------------------------------------------------------ *)
  5. PROGRAM UPNCalc;
  6.  
  7. {$I-,V-}
  8.  
  9. {$M 2000, 0, 100}
  10.  
  11. USES Crt, Tsr, { TOOLBOX 4`89 BZW 5`88 } Dos;
  12.  
  13. CONST
  14.   ErsatzX   = 50;
  15.   ErsatzY   =  3;
  16.   HotKey    = $6600;
  17.   MaxReal   = 1.6E38;
  18.   MaxExp    = 88.029691931;
  19.  
  20. VAR
  21.   Regs      : Registers;
  22.  
  23. {$F+}                               { Far-Model wegen TSR  }
  24.  
  25. TYPE
  26.   pElement = ^Element;          { Zeiger auf Kellerelement }
  27.   Element  = RECORD             { Kellerelemt y1 -> y2 ... }
  28.                fig   : REAL;
  29.                next  : pElement;
  30.              END;
  31.   string14 = STRING[14];
  32.   ScrType  = ARRAY[0..3999] OF BYTE;          { Bildschirm }
  33.  
  34. CONST
  35.   ndef   = 'Not defined!'; { Meldung, wenn Keller leer ist }
  36.   Liste  = 1;
  37.   Float  = 2;
  38.   Input  = 3;
  39.   Overfl = 8;
  40.   MaxM   = 9;
  41.  
  42. VAR
  43.   ePtr     : pElement;    { Zeiger auf ersten Datenelement }
  44.   Screen   : ScrType ABSOLUTE $B800:$0000;
  45.                                    { Bildschirmspeicher :  }
  46.                                    { $B000 für Monochrom:  }
  47.                                    { $B000 für CGA      :  }
  48.  
  49.   Buffer  : ScrType;         { Buffer für Bildschirminhalt }
  50.   m       : ARRAY [0..MaxM] OF REAL;  { Konstantenspeicher }
  51.   OldX, OldY,
  52.   OldWMin, OldWMax   : WORD;
  53.   SoftKey            : WORD;
  54.   XPos, YPos         : BYTE;
  55.   ch                 : CHAR;
  56.   zahl               : string14;
  57.   x, h               : REAL;
  58.   temp               : REAL;
  59.   i, error           : INTEGER;
  60.   EFlag              : BOOLEAN; { Flag für Darstellungsart }
  61.  
  62.   PROCEDURE Init;               { Programm initialisieren  }
  63.   BEGIN
  64.     OldX    := WhereX;
  65.     OldY    := WhereY;      { alte Cursorposition retten   }
  66.     OldWMin := WindMin;
  67.     OldWMax := WindMax;     { alte Fenster retten          }
  68.     Zahl    := '';          { Eingabestring löschen        }
  69.     x       := 0.0;         { x-Register löschen           }
  70.     FOR i := 0 TO MaxM DO m[i] := 0.0;
  71.     EPtr    := NIL;      { Keller leer => Zeiger ins Blaue }
  72.     EFlag   := TRUE;     { Darstellung: Zehnerpotenzen     }
  73.     Move(Screen, Buffer,
  74.           SizeOf(Buffer))   { alten Bildschirm retten      }
  75.   END;
  76.  
  77.   PROCEDURE BWrite(s : STRING);
  78.                   { Schreibprozedur für den Taschenrechner }
  79.   BEGIN
  80.     FOR i := 1 to Length(s) DO BEGIN
  81.       IF S[i] = '#' THEN BEGIN  { Falls dem Zeichen        }
  82.                                 { ein '#' vorgestellt ist, }
  83.          Inc(i);                { das nächste Zeichen      }
  84.          TextColor(White);      { heller schreiben         }
  85.       END ELSE
  86.        TextColor(LightGray);    { ansonsten normal         }
  87.       Write(s[i]);
  88.     END;
  89.   END;
  90.  
  91.   PROCEDURE Swap(VAR x, y : REAL);
  92.   BEGIN
  93.     h := x;  x := y;  y := h;
  94.   END;
  95.  
  96.   PROCEDURE DrawCalc;
  97.   BEGIN
  98.     TextColor(Magenta);
  99.     TextBackGround(Black);
  100.     Window(XPos, YPos, XPos+19, YPos+11);
  101.     ClrScr;
  102.     Write  ('                    ');
  103.     Write  ('╒══════════════════╕');
  104.     Write  ('│x:                │');
  105.     Write  ('│y:                │');
  106.     Write  ('│z:                │');
  107.     Write  ('║══════════════════║');
  108.     BWrite ('║ L#n  E#n  L#og  R#pV ║');
  109.     BWrite ('║ #Pi  R#d  #Int  C#hS ║');
  110.     BWrite ('║ x'+Chr(16)+'#Z En#g #Y^X  #* #/ ║');
  111.     BWrite ('║ S#mx #Wm  #Rm   #+ #- ║');
  112.     BWrite ('║ #Sxy #Ex #. #'+Chr(17)+'#- #C #Ac ║');
  113.     BWrite ('║ C#ly #'+Chr(17)+'#- #Kill #Quit ║');
  114.     Window(XPos, YPos+11, XPos+19, YPos+12);
  115.                           { Fenster vergrößern. sonst wird }
  116.                           { beim letzten Zeichen gescrollt }
  117.     Write  ('╙══════════════════╜');
  118.     Window(XPos+3, YPos+1, XPos+18, YPos+3);
  119.     TextColor(LightMagenta);
  120.   END;
  121.  
  122.   PROCEDURE WriteStr(s : STRING; y : BYTE);
  123.   BEGIN
  124.     Gotoxy(1, Y); Write(' ', s);
  125.     ClrEoL;
  126.   END;
  127.  
  128.   PROCEDURE WriteR(x : REAL; y : BYTE);
  129.   BEGIN
  130.     Gotoxy(1, Y);
  131.     IF EFlag THEN Write(x:15)
  132.              ELSE Write(x:15:15);
  133.     ClrEoL;
  134.   END;
  135.  
  136.   PROCEDURE Push(x : REAL);
  137.   VAR
  138.     NPtr : pElement;
  139.   BEGIN
  140.     New(NPtr);            { Speicherplatz bereitstellen    }
  141.     NPtr^.fig  := x;      { x-Wert eintragen               }
  142.     NPtr^.next := EPtr;   { Next-Zeiger auf das alte Elem. }
  143.     EPtr       := NPtr;   { Zeiger auf das 1. Element      }
  144.   END;
  145.  
  146.   FUNCTION Pop : REAL;    { holt den Inhalt des obersten   }
  147.   VAR
  148.     OPtr : pElement;
  149.   BEGIN
  150.     Pop         := EPtr^.fig;  { Wert auslesen             }
  151.     OPtr        := EPtr;       { Zeiger retten             }
  152.     EPtr        := EPtr^.next; { erstes Element ausklinken }
  153.     Dispose(OPtr);             { ... und löschen           }
  154.   END;
  155.  
  156.   PROCEDURE Err(nr : BYTE);
  157.   BEGIN
  158.     CASE nr OF
  159.       Liste : WriteStr(#7 + 'List Error! ', 2);
  160.       Float : WriteStr(#7 + ndef, 1);
  161.                             { z.B. bei 1/0 oder Ln(-3) ... }
  162.       Input : WriteStr(#7 + 'Input Error! ', 3);
  163.       Overfl: WriteStr(#7 + 'Overflow !   ', 3)
  164.     END;
  165.     Delay(1000);
  166.   END;
  167.  
  168.   PROCEDURE TestX;              { String in Zahl umwandeln }
  169.   BEGIN
  170. {$V-}
  171.     Val(Zahl, x, error);
  172.     IF error <> 0 THEN
  173.       Err(Input)
  174.     ELSE
  175.       IF Abs(x) > MaxReal THEN Err(Input);
  176. {$V+}
  177.   END;
  178.  
  179.   FUNCTION InputNr(s : STRING) : BYTE;
  180.                          { Nummer des m-Speichers eingeben }
  181.   VAR
  182.     TempB : BYTE;
  183.   BEGIN
  184.     WriteStr(s, 3);      { String ausgeben,                }
  185.     REPEAT               { auf Eingabe einer Ziffer warten }
  186.       ch := ReadKey
  187.     UNTIL (ch >= '0') AND (ch <= '9');
  188.     Write(ch);
  189.     Delay(100);
  190.     Val(ch, TempB, error);
  191.     InputNr := TempB;    { ... und umwandeln.              }
  192.   END;
  193.  
  194.   FUNCTION Overflow(x, y : REAL; Operand : Char) : BOOLEAN;
  195.  
  196.     FUNCTION Sign(x : REAL ) : BOOLEAN;
  197.     BEGIN
  198.       IF x < 0.0 THEN Sign := FALSE
  199.                  ELSE Sign := TRUE;
  200.     END;
  201.  
  202.   BEGIN
  203.     CASE Operand OF
  204.       '+': BEGIN
  205.              IF Sign(x) = Sign(y) THEN
  206.                IF Abs(x) > MaxReal - Abs(y) THEN
  207.                  Overflow := TRUE
  208.                ELSE Overflow := FALSE
  209.              ELSE Overflow := FALSE;
  210.            END;
  211.       '-': BEGIN
  212.              IF Sign(x) <> Sign(y) THEN
  213.                IF Abs(x) > MaxReal - Abs(y) THEN
  214.                  Overflow := TRUE
  215.                ELSE Overflow := FALSE
  216.              ELSE Overflow := FALSE;
  217.            END;
  218.       '*': BEGIN
  219.              IF (Abs(x) >= 1.0) AND (Abs(y) >= 1.0) THEN
  220.                IF Abs(x) > MaxReal / Abs(y) THEN
  221.                  Overflow := TRUE
  222.                ELSE Overflow := FALSE
  223.              ELSE Overflow := FALSE;
  224.            END;
  225.       '/': BEGIN
  226.              IF Abs(y) < 1.0 THEN
  227.                IF Abs(x) > MaxReal / Abs(1.0 / Abs(y)) THEN
  228.                  Overflow := TRUE
  229.                ELSE Overflow := FALSE
  230.              ELSE Overflow := FALSE;
  231.            END;
  232.       'Y': BEGIN
  233.            IF NOT Overflow(y, Ln(Abs(x)), Char('*')) THEN
  234.              IF Abs(y * (Ln(Abs(x)))) <= MaxExp THEN
  235.                Overflow := FALSE
  236.              ELSE Overflow := TRUE
  237.            ELSE Overflow := TRUE;
  238.          END;
  239.     END;
  240.   END;
  241.  
  242.   FUNCTION PotenzXY(x, y : REAL) : REAL;
  243.   BEGIN
  244.     error := 0;
  245.     IF x > 0.0 THEN
  246.       IF Not Overflow(x, y, 'Y') THEN
  247.         PotenzXY := Exp(y * Ln(x))
  248.       ELSE error := 8
  249.      ELSE
  250.        IF x = 0.0 THEN
  251.          IF y > 0.0 THEN PotenzXY := 0.0
  252.                     ELSE error    := 1
  253.     ELSE                                       { Basis < 0 }
  254.       IF Not Overflow(x, y, 'Y') THEN
  255.         IF y = Trunc(y) THEN     { Exponent ist ganzzahlig }
  256.           IF Odd(Trunc(y)) THEN              { gerade oder }
  257.             PotenzXY := -Exp(y * Ln(-x))
  258.           ELSE                               { ungerade    }
  259.             PotenzXY :=  Exp(y * Ln(-x))
  260.         ELSE
  261.           IF (1/y = Round(1/y)) AND (Odd(Round(1/y))) THEN
  262.             PotenzXY := -Exp(y * Ln(-x))     { ungerade    }
  263.           ELSE error := 1     { sonst aber wirklich Fehler }
  264.                    { Exponent ist der Kehrwert einer unge- }
  265.                    { raden Zahl: eigentlich nicht de-      }
  266.                    { finiert, die meisten TR lassen        }
  267.                    { die Rechnung aber zu !                }
  268.       ELSE error     := 8;
  269.   END;
  270.  
  271.   PROCEDURE Execute;                          { Rechnungen }
  272.   BEGIN
  273.     REPEAT
  274.       REPEAT
  275.         ch      := Upcase(Readkey)
  276.       UNTIL ch <> '';
  277.       CASE ch OF
  278.        '0'..'9',
  279.        'E', '.',
  280.        '_'       : IF ch <> '_' THEN zahl := zahl + ch
  281.                                 ELSE zahl := zahl + '-';
  282.       { Zur Unterscheidung zum normalen Minusyeichen wird   }
  283.       { hier der Underline '_'zur Vorzeichenwahl verwendet  }
  284.  
  285.        'A'       : BEGIN
  286.                      WHILE EPtr <> NIL DO x := Pop;
  287.                      x    := 0.0;
  288.                      Zahl := '';
  289.                    END;                { Alles löschen     }
  290.        'C'       : x  := 0.0;          { x-Register löschen}
  291.        'D'       : x  := Round(x);                { Runden }
  292.        'G'       : EFlag  := NOT EFlag;{ Real-Darstellung  }
  293.        'H'       : x  := -x;           { Vorzeichenwechsel }
  294.        'I'       : x  := Int(x);       { Integerfunktion   }
  295.        'K'       : Zahl := '';     { Eingabestring löschen }
  296.        'L'       : IF EPtr <> NIL THEN h := Pop
  297.                                   ELSE Err(Liste);
  298.                                    { y1-Register löschen   }
  299.        'M'       : BEGIN           { x <---> m[0..9]       }
  300.                      SWAP(x, m[InputNr('Swap x with m')]);
  301.                      WriteStr('M swapped!',1);
  302.                      Delay(300);
  303.                    END;
  304.        'N'       : IF x > 0.0 THEN x := Ln(x)
  305.                               ELSE Err(Float);
  306.                                  { Natürlicher Logarithmus }
  307.        'O'       : IF x > 0.0   THEN x := Ln(x)/Ln(10)
  308.                                 ELSE Err(Float);
  309.                                  { Zehnerlogarithmus       }
  310.  
  311.        'P'       : Str(Pi:10:8, Zahl);                { Pi }
  312.        'R'       : BEGIN                 { x <---> m[0..9] }
  313.                      x := m[InputNr('Read from m')];
  314.                      WriteStr('M read!', 1);
  315.                      Delay(300);
  316.                    END;
  317.        'S'       : IF EPtr <> NIL THEN Swap(x, Eptr^.Fig)
  318.                                   ELSE Err(Liste);
  319.                                               { x <---> y  }
  320.        'V'       : IF x <> 0.0 THEN x := 1/x
  321.                                ELSE Err(Float);
  322.                                               { Kehrwert   }
  323.        'W'       : BEGIN                 { x  ---> m[0..9] }
  324.                      m[InputNr('Store x in m')] := x;
  325.                      WriteStr('M stored', 1);
  326.                      Delay(300);
  327.                    END;
  328.        'X'       : x := Exp(x);             { e - Funktion }
  329.        'Z'       : Str(x:14, Zahl);
  330.        '+', '-',
  331.        'Y',                   { Verknüpfungen zw. x und y1 }
  332.        '*','/'   : IF EPtr <> NIL THEN BEGIN
  333.                                          { Operand y1 da ? }
  334.                      error := 0;
  335.                      IF zahl <> '' THEN TestX; { umwandeln }
  336.                      IF error = 0 THEN BEGIN
  337.                        temp  := Pop;
  338.                        CASE ch OF
  339.                          '+': IF NOT Overflow(temp, x, '+')
  340.                                 THEN x := temp + x
  341.                                 ELSE Err(Overfl);
  342.                          '-': IF NOT Overflow(temp, x, '-')
  343.                                 THEN x := temp - x
  344.                                 ELSE Err(Overfl);
  345.                          '*': IF NOT Overflow(temp, x, '*')
  346.                                 THEN x := temp * x
  347.                                 ELSE Err(Overfl);
  348.                          '/': BEGIN
  349.                                 IF x = 0.0 THEN
  350.                                   Err(Float)
  351.                                 ELSE
  352.                                   IF Overflow(temp, x, '/')
  353.                                     THEN Err(Overfl)
  354.                                     ELSE x := temp/x ;
  355.                               END;
  356.                         'Y' : BEGIN
  357.                                 x := PotenzXY(temp, x);
  358.                                 IF error = 8 THEN
  359.                                   Err(Overfl)
  360.                                 ELSE
  361.                                   IF error <> 0 THEN
  362.                                     Err(Float);
  363.                               END;
  364.                        END;
  365.                      END;
  366.                      IF EPtr = NIL THEN Push(x);
  367.                        Zahl   := '';
  368.                    END ELSE
  369.                      Err(Liste);            { sonst Fehler }
  370.        #8        : IF Length(Zahl) > 0 THEN
  371.                      Zahl := Copy(Zahl, 1,
  372.                                   Pred(Length(Zahl)));
  373.                                  { letztes Zeichen löschen }
  374.        #13       : BEGIN
  375.                      TestX;
  376.                      IF error = 0 THEN Push(x);
  377.                                    { Zahl gültig -> Keller }
  378.                      Zahl  := '';
  379.                    END;
  380.       END;
  381.  
  382.       WriteR(x, 1);                       { Werte ausgeben }
  383.       IF EPtr <> NIL THEN WriteR(EPtr^.fig, 2)
  384.                      ELSE WriteStr(ndef, 2);
  385.       WriteStr(Zahl, 3);
  386.     UNTIL ch = 'Q';           { und wiederholen bis 'QUIT' }
  387.   END;
  388.  
  389.   PROCEDURE upn;
  390.   BEGIN
  391.     Init;                        { Taschenrechner ausgeben }
  392.     DrawCalc;
  393.     WriteR(x, 1);                { erste Werte ausgeben    }
  394.     WriteStr(ndef, 2);
  395.     GotoXY(2, 3);
  396.     Execute;                     { ... und los geht's      }
  397.     Move(Buffer, Screen, SizeOF(Screen));
  398.     Window(Succ(LO(OldWMin)), Succ(Hi(OldWMin)),
  399.            Succ(LO(OldWMax)), Succ(Hi(OldWMax)));
  400.                            { alten Bildschirm restaurieren }
  401.     GotoXY(OldX, OldY);    { alte Cursorpos. ansteuern     }
  402.   END;
  403.  
  404. BEGIN                            { Beginn UPN-Installation }
  405.   IF ParamCount > 1 THEN BEGIN
  406.     Val(ParamStr(1), XPos, error);
  407.     Val(ParamStr(2), YPos, error);
  408.     IF (XPos < 1) OR (XPos > 60) OR (YPos < 1)
  409.                   OR (YPos > 13) OR (error <> 0) THEN BEGIN
  410.       XPos   := ErsatzX;
  411.       YPos   := ErsatzY;     { Default bei unvollständiger }
  412.                              { oder unsinniger Eingabe     }
  413.     END;
  414.     IF ParamCount > 2 THEN BEGIN  { Eingabe des Scan-Codes }
  415.       Val(ParamStr(3), SoftKey, error);
  416.       IF error <> 0 THEN SoftKey := HotKey;
  417.     END ELSE
  418.       SoftKey := HotKey;         { oder Default einsetzen. }
  419.   END ELSE BEGIN
  420.     XPos    := ErsatzX;
  421.     YPos    := ErsatzY;
  422.     SoftKey := HotKey;                              { s.o. }
  423.   END;
  424.   MakeResident(@upn, SoftKey);
  425.                            { Programm im Speicher behalten }
  426.                            { Voila! Viel Spass mit UPN !!  }
  427. END.
  428. (* ------------------------------------------------------ *)
  429. (*                  Ende von UPN.PAS                      *)
  430.