home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol064 / handcalc.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1984-04-29  |  13.8 KB  |  568 lines

  1. {$S+}  { Turn on recursion ability, must be first line in Pascal/MT+    }
  2. {$X+}  { Turn on run-time error checking                }
  3.  
  4. Program Handcalc ;
  5.  
  6. {   This program is intended to act as a scientific calculator, with    }
  7. {   exponentiation and trancendental functions.                }
  8.  
  9. Const
  10.     Func_Len  = 6;    { No. of characters allowed in a function name    }
  11.     Num_Funcs = 20;    { No. of functions recognized            }
  12.     Pi        = 3.1415926535897323846264338;
  13.  
  14. Type
  15.     Functions = (ArcTangent, Cosine, Logrithm, Sine, Square, Square_Root,
  16.             Exponent, Tangent, CoTangent, Secant, CoSecant,
  17.             ArcSine, ArcCosine, ArcCotangent, ArcSecant,
  18.             ArcCoSecant, Pie, Radians, Log, Factorial,
  19.             Non_Function);
  20.  
  21.     Set_of_Funcs = Set of Functions;
  22.     Func_Name = array [1..Func_Len] of char;
  23.     Func_Rec  = record
  24.             Name    : Func_Name;
  25.             Func_Type : Functions
  26.             end;
  27.     Func_List = array [1..Num_Funcs] of Func_Rec;
  28.  
  29. Var
  30.     Answer        : real;
  31.     Buf        : String;
  32.     Z        : integer;    { Index into Buf }
  33.     F_Names        : Func_List;
  34.     Non_Parm_Funcs    : Set_of_Funcs;
  35.     Debug_Mode    : boolean;
  36.  
  37. Procedure Initialization;
  38.  
  39.      Var
  40.     I : integer;
  41.  
  42.      Procedure Init_Funcs;
  43.  
  44.     begin { Init_Funcs }
  45.         { The order of the strings in F_Names must be alphabetical }
  46.         { This should be remembered when adding new functions       }
  47.     F_Names[1].Name := 'ARCCOS';    F_Names[1].Func_Type := ArcCosine;
  48.     F_Names[2].Name := 'ARCCOT';    F_Names[2].Func_Type := ArcCoTangent;
  49.     F_Names[3].Name := 'ARCCSC';    F_Names[3].Func_Type := ArcCoSecant;
  50.     F_Names[4].Name := 'ARCSEC';    F_Names[4].Func_Type := ArcSecant;
  51.     F_Names[5].Name := 'ARCSIN';    F_Names[5].Func_Type := ArcSine;
  52.     F_Names[6].Name := 'ARCTAN';    F_Names[6].Func_Type := ArcTangent;
  53.     F_Names[7].Name := 'COS   ';    F_Names[7].Func_Type := Cosine;
  54.     F_Names[8].Name := 'COT   ';    F_Names[8].Func_Type := CoTangent;
  55.     F_Names[9].Name := 'CSC   ';    F_Names[9].Func_Type := CoSecant;
  56.     F_Names[10].Name:= 'EXP   ';    F_Names[10].Func_Type:= Exponent;
  57.     F_Names[11].Name:= 'FACTOR';    F_Names[11].Func_Type:= Factorial;
  58.     F_Names[12].Name:= 'LN    ';    F_Names[12].Func_Type:= Logrithm;
  59.     F_Names[13].Name:= 'LOG   ';    F_Names[13].Func_Type:= Log;
  60.     F_Names[14].Name:= 'PI    ';    F_Names[14].Func_Type:= Pie;
  61.     F_Names[15].Name:= 'RADIAN';    F_Names[15].Func_Type:= Radians;
  62.     F_Names[16].Name:= 'SEC   ';    F_Names[16].Func_Type:= Secant;
  63.     F_Names[17].Name:= 'SIN   ';    F_Names[17].Func_Type:= Sine;
  64.     F_Names[18].Name:= 'SQR   ';    F_Names[18].Func_Type:= Square;
  65.     F_Names[19].Name:= 'SQRT  ';    F_Names[19].Func_Type:= Square_Root;
  66.     F_Names[20].Name:= 'TAN   ';    F_Names[20].Func_Type:= Tangent;
  67.     Non_Parm_Funcs := [Pie]
  68.     end;  { Init_Funcs }
  69.  
  70.      begin { Initialization }
  71.         { Clear the screen }
  72.      For I := 1 to 24 do
  73.         Writeln;
  74.      Writeln ('Calculator');
  75.      Writeln;
  76.      Writeln ('by Warren A. Smith  --  July 29, 1981');
  77.      Write (Skip_Line(4));
  78.      Writeln ('A ''?'' at the beginning of a line will bring up a listing');
  79.      Writeln ('  of possible functions and operators that may be used.');
  80.      Writeln;
  81.      Writeln ('A dollar sign ''$'' at the beginning of a line will');
  82.      Writeln ('  cause this program to terminate.');
  83.      Writeln;
  84.      Debug_Mode := FALSE;
  85.      Init_Funcs
  86.      end;  { Initialization }
  87.  
  88. Function Skip_Line (N : integer) : char;
  89.  
  90.     Var
  91.     I : integer;
  92.  
  93.     begin { Skip_Line }
  94.     For I := 1 to N do
  95.     Writeln;
  96.     Skip_Line := chr(0)
  97.     end;  { Skip_Line }
  98.  
  99. Function Tab (N : integer) : char;
  100.  
  101.     Var
  102.     I : integer;
  103.  
  104.     begin { Tab }
  105.     For I := 1 to N do
  106.     Write (' ')
  107.     end;  { Tab }
  108.  
  109. Function Upper (In_Char : char) : char;
  110.  
  111.      begin { Upper }
  112.      If (In_Char >= 'a') AND (In_Char <= 'z') then
  113.          Upper := chr(ord(In_Char) + (ord('A') - ord('a')))
  114.      else
  115.          Upper := In_Char
  116.      end;  { Upper }
  117.  
  118. Procedure Help;
  119.  
  120.     Var
  121.     Response : char;
  122.  
  123.     begin { Help }
  124.     Write (Skip_Line (24));    { clear the screen }
  125.      Writeln ('  The currently available functions are :');
  126.      Writeln;
  127.      Writeln ('    ArcCosine   - ArcCos    ArcCotangent     - ArcCot');
  128.      Writeln ('    ArcCosecant - ArcCsc    ArcSecant        - ArcSec');
  129.      Writeln ('    ArcSine     - ArcSin    ArcTangent       - ArcTan');
  130.      Writeln ('    Cosine      - Cos       CoTangent        - Cot   ');
  131.      Writeln ('    CoSecant    - Csc       Natural Exponent - Exp   ');
  132.      Writeln ('    Natural Log - Ln        Secant           - Sec   ');
  133.      Writeln ('    Sine        - Sin       Square           - Sqr   ');
  134.      Writeln ('    Square Root - Sqrt      Tangent          - Tan   ');
  135.      Writeln ('    Log base 10 - Log       Factorial        - Factor');
  136.      Writeln ('    Value of Pi - Pi                    ');
  137.      Writeln;
  138.      Writeln ('  Allowable operators are:');
  139.      Writeln ('      ''+'', ''-'', ''*'', ''/'', and ''^'' (exponentiation)');
  140.      Writeln;
  141.      Writeln ('  Upper case and lower case are irrelevant in function names');
  142.      Writeln ('  A ''$'' will end the program, a ''!'' turns on debug mode ');
  143.      Writeln;
  144.      Writeln ('Hit the carriage return to proceed.');
  145.      Read (Response);
  146.     end;  { Help }
  147.  
  148. Function Eoln : boolean;
  149.  
  150.     begin { Eoln }
  151.     Eoln := Z > Length(Buf)
  152.     end;  { Eoln }
  153.  
  154. Procedure Slough_Blanks;
  155.  
  156.     begin { Slough_Blanks }
  157.     While (Buf[Z] = ' ') AND (not Eoln) do
  158.        Z := Z + 1
  159.     end;  { Slough_Blanks }
  160.  
  161. Procedure Get_Expr;
  162.  
  163.     begin { Get_Expr }
  164.     Repeat
  165.     Writeln;
  166.     Writeln ('Type in an expression to be solved.');
  167.     Readln (Buf);
  168.     Z := 1;
  169.     Slough_Blanks
  170.     Until not Eoln
  171.     end;  { Get_Expr }
  172.  
  173. Function Expr : real;
  174.  
  175.      Var
  176.     Unary,
  177.     Answer    : real;
  178.  
  179.      Function Term : real;
  180.  
  181.     Var
  182.         Answer    : real;
  183.  
  184.     Function Expon : real;
  185.  
  186.         Var
  187.         Answer : real;
  188.  
  189.         Function XtoY (X, Y : real) : real;
  190.  
  191.         begin { XtoY }
  192.         If X >= 0.0 then
  193.             XtoY := exp(Y * Ln(X))
  194.         else
  195.             XtoY := 0.0
  196.         end;  { XtoY }
  197.  
  198.         Function Factor : real;
  199.  
  200.            Var
  201.             Answer,
  202.             X    : real;
  203.             Func    : Functions;
  204.  
  205.         Procedure Read (Var Answer : real);
  206.  
  207.              Var
  208.             Fact_Power : real;
  209.  
  210.              begin { Read }
  211.              Answer := 0.0;
  212.              Slough_Blanks;
  213.              While Digit (Buf[Z]) AND not Eoln do
  214.             begin
  215.             Answer := Answer * 10.0 + (Ord(Buf[Z])-Ord('0'));
  216.             Z := Z + 1
  217.             end;
  218.              If (Buf[Z] = '.') AND not Eoln then
  219.             begin
  220.             Z := Z + 1;
  221.             Fact_Power := 1.0;
  222.             While Digit (Buf[Z]) AND not Eoln do
  223.                 begin
  224.                 Fact_Power := Fact_Power / 10.0;
  225.                 Answer := Answer+(Ord(Buf[Z])-Ord('0'))*Fact_Power;
  226.                 Z := Z + 1
  227.                 end
  228.             end
  229.              end;  { Read }
  230.  
  231.         Function Digit (In_Char : char) : boolean ;
  232.  
  233.              begin { Digit }
  234.              Digit := In_Char in ['0','1','2','3','4','5','6','7',
  235.                       '8','9']
  236.              end;  { Digit }
  237.  
  238.         Function Letter (Var In_Char : char) : boolean;
  239.  
  240.              begin { Letter }
  241.              In_Char := Upper (In_Char);
  242.              Letter := In_Char in ['A','B','C','D','E','F','G','H',
  243.                        'I','J','K','L','M','N','O','P',
  244.                        'Q','R','S','T','U','V','W','X',
  245.                        'Y','Z']
  246.              end;  { Letter }
  247.  
  248.         Function Get_Func_Type : Functions;
  249.  
  250.              Var
  251.             ID : Func_Name;
  252.             Index : integer;
  253.  
  254.              Function Search_Funcs (ID : Func_Name) : Functions;
  255.  
  256.               Var
  257.                 I, J, K    : integer;
  258.  
  259.               begin { Search_Funcs }
  260.               I := 1;
  261.                J := Num_Funcs;
  262.               Repeat
  263.                    K := (I+J) DIV 2;      { Binary search }
  264.                    With F_Names[K] do
  265.                    begin
  266.                    If Name <= ID  then
  267.                     I := K+1;
  268.  
  269.                    If Name >= ID then
  270.                     J := K-1
  271.                    end
  272.  
  273.               Until I > J;
  274.                If F_Names[K].Name <> ID then
  275.                    Search_Funcs := Non_Function
  276.               else
  277.                    Search_Funcs := F_Names[K].Func_Type
  278.               end;  { Search_Funcs }
  279.  
  280.              begin { Get_Func_Type }
  281.              Index := 1;
  282.              Repeat
  283.               ID [Index] := Buf[Z];
  284.               Z := Z + 1;
  285.               Index := Index + 1
  286.              Until Not Letter(Buf[Z]) OR Eoln OR (Index > Func_Len);
  287.              While Index <= Func_Len do
  288.               begin
  289.               ID [Index] := ' ';
  290.               Index := Index + 1
  291.               end;
  292.  
  293.              Get_Func_Type := Search_Funcs (ID)
  294.              end;  { Get_Func_Type }
  295.  
  296.         Function Tan (X : real) : real;
  297.  
  298.             begin { Tan }
  299.             Tan := Sin(X) / Cos(X)
  300.             end;  { Tan }
  301.  
  302.         Function Cot (X : real) : real;
  303.  
  304.             begin { Cot }
  305.             Cot := Cos(X) / Sin(X)
  306.             end;  { Cot }
  307.  
  308.         Function Sec (X : real) : real;
  309.  
  310.             begin { Sec }
  311.             Sec := 1.0 / Cos(X)
  312.             end;  { Sec }
  313.  
  314.         Function Csc (X : real) : real;
  315.  
  316.             begin { Csc }
  317.             Csc := 1.0 / Sin(X)
  318.             end;  { Csc }
  319.  
  320.         Function ArcSin (X : real) : real;
  321.  
  322.             begin { ArcSin }
  323.             ArcSin := ArcTan(X / Sqrt(1.0 - Sqr(X)))
  324.             end;  { ArcSin }
  325.  
  326.         Function ArcCos (X : real) : real;
  327.  
  328.             begin { ArcCos }
  329.             ArcCos := Pi / 2.0 - ArcTan (X / Sqrt(1.0 - Sqr(X)))
  330.             end;  { ArcCos }
  331.  
  332.         Function ArcCot (X : real) : real;
  333.  
  334.             begin { ArcCot }
  335.             ArcCot := Pi / 2.0 - ArcTan (X)
  336.             end;  { ArcCot }
  337.  
  338.         Function ArcSec (X : real) : real;
  339.  
  340.             begin { ArcSec }
  341.             ArcSec := ArcTan (Sqrt(Sqr(X) - 1.0))
  342.             end;  { ArcSec }
  343.  
  344.         Function ArcCsc (X : real) : real;
  345.  
  346.             begin { ArcCsc }
  347.             ArcCsc := ArcTan (1.0 / Sqrt(Sqr(X) - 1.0))
  348.             end;  { ArcCsc }
  349.  
  350.         Function Radian (X : real) : real;
  351.  
  352.             begin { Radian }
  353.             Radian := X * (Pi / 180.0)
  354.             end;  { Radian }
  355.  
  356.         Function Log10 (X : real) : real;
  357.  
  358.             begin { Log10 }
  359.             Log10 := Ln(X) / Ln(10.0)
  360.             end;  { Log10 }
  361.  
  362.         Function Factorl (X : real) : real;
  363.  
  364.             Var
  365.             Int_X, I    : integer;
  366.             Product        : real;
  367.  
  368.             begin { Factorl }
  369.             Int_X := Round(X);
  370.             If Int_X = 0 then
  371.             Factorl := 1.0
  372.             else
  373.             begin
  374.             Product := 1.0;
  375.             For I := 2 to Int_X do
  376.                 Product := Product * I;
  377.             Factorl := Product
  378.             end
  379.             end;  { Factorl }
  380.  
  381.         begin { Factor }
  382.         Slough_Blanks;
  383.         If Digit (Buf[Z]) OR (Buf[Z] = '.') then
  384.              Read (Answer)
  385.         else
  386.              If Buf[Z] = '(' then
  387.               begin
  388.               Z := Z + 1;
  389.               Answer := Expr;
  390.               If Buf[Z] <> ')' then
  391.                 begin
  392.                 Write (Tab(Z-1),'^ ');
  393.                 Writeln ('*** '')'' expected')
  394.                 end
  395.               else
  396.                 Z := Z + 1
  397.               end
  398.              else
  399.               If Letter (Buf[Z]) then
  400.                 begin
  401.                 Func := Get_Func_Type;
  402.                 Slough_Blanks;
  403.                 If not (Func in Non_Parm_Funcs) then
  404.                     begin
  405.                     If Buf[Z] = '(' then
  406.                     begin
  407.                     Z := Z + 1;
  408.                     Answer := Expr
  409.                     end
  410.                     else
  411.                     begin
  412.                     Write (Tab(Z-1), '^ ');
  413.                     Write ('*** ''('' expected, answer ');
  414.                     Writeln ('may be in error')
  415.                     end;
  416.                     Slough_Blanks;
  417.                     If Buf[Z] = ')' then
  418.                     Z := Z + 1
  419.                     else
  420.                     begin
  421.                     Write (Tab(Z-1), '^ ');
  422.                     Write ('*** '')'' expected, answer ');
  423.                     Writeln ('may be in error')
  424.                     end
  425.                     end;
  426.                 Case Func of
  427.                     Logrithm    : Answer := Ln (Answer);
  428.                     Exponent    : Answer := Exp (Answer);
  429.                     Log        : Answer := Log10 (Answer);
  430.                     Square      : Answer := Sqr (Answer);
  431.                     Square_Root : Answer := Sqrt (Answer);
  432.                     Factorial    : Answer := Factorl (Answer);
  433.                     Cosine    : Answer :=
  434.                             Cos (Radian(Answer));
  435.                     Sine    : Answer :=
  436.                             Sin (Radian(Answer));
  437.                     ArcTangent  : Answer :=
  438.                                ArcTan (Radian(Answer));
  439.                     Tangent    : Answer :=
  440.                              Tan (Radian(Answer));
  441.                     CoTangent   : Answer :=
  442.                              Cot (Radian(Answer));
  443.                     Secant    : Answer :=
  444.                              Sec (Radian(Answer));
  445.                     CoSecant    : Answer :=
  446.                              Cos (Radian(Answer));
  447.                     ArcSine    : Answer :=
  448.                                ArcSin (Radian(Answer));
  449.                     ArcCosine   : Answer :=
  450.                                ArcCos (Radian(Answer));
  451.                     ArcCoTangent: Answer :=
  452.                                ArcCot (Radian(Answer));
  453.                     ArcSecant   : Answer :=
  454.                                ArcSec (Radian(Answer));
  455.                     ArcCoSecant : Answer :=
  456.                             ArcCsc (Answer);
  457.                     Pie        : Answer := Pi;
  458.                     Radians    : Answer := Radian (Answer);
  459.                     Non_Function: begin
  460.                           Write (Tab(Z-1), '^ ');
  461.                           Writeln
  462.                         ('*** Unknown function name')
  463.                           end
  464.                     end; { CASE }
  465.                 Slough_Blanks
  466.                 end
  467.               else
  468.                 begin
  469.                 Write (Tab(Z-1), '^ ');
  470.                 Write ('*** Unknown Syntax, answer may ');
  471.                 Writeln ('be in error')
  472.                 end;
  473.         If Debug_Mode then
  474.             Writeln ('Result from FACTOR = ', Answer:20:8);
  475.         Factor := Answer
  476.         end;  { Factor }
  477.  
  478.         begin { Expon }
  479.         Answer := Factor;
  480.         Slough_Blanks;
  481.         While Buf[Z] = '^' do
  482.         begin
  483.         Z := Z + 1;
  484.         Answer := XtoY (Answer, Factor);
  485.         Slough_Blanks
  486.         end;
  487.         If Debug_Mode then
  488.         Writeln ('Result from EXPON = ', Answer:20:8);
  489.         Expon := Answer
  490.         end;  { Expon }
  491.  
  492.       begin { Term }
  493.       Answer := Expon;
  494.       Slough_Blanks;
  495.       While Buf[Z] in ['*', '/'] do
  496.         begin
  497.         If Buf[Z] = '*' then
  498.              begin
  499.              Z := Z + 1;
  500.              Answer := Answer * Expon
  501.              end
  502.         else
  503.              begin
  504.              Z := Z + 1;
  505.              Answer := Answer / Expon;
  506.              end;
  507.         Slough_Blanks
  508.         end;
  509.       If Debug_Mode then
  510.         Writeln ('Result from TERM = ', Answer:20:8);
  511.       Term := Answer
  512.       end;  { Term }
  513.  
  514.      begin { Expr }
  515.      Slough_Blanks;
  516.      Unary := 1.0;
  517.      If Buf[Z] in ['+','-'] then
  518.     begin
  519.     If Buf[Z] = '-' then
  520.         Unary := -1.0;
  521.     Z := Z + 1
  522.     end;
  523.      Answer := Unary * Term;
  524.      Slough_Blanks;
  525.      While Buf[Z] in ['+', '-'] do
  526.     begin
  527.     If Buf[Z] = '+' then
  528.         begin
  529.         Z := Z + 1;
  530.         Answer := Answer + Term
  531.         end
  532.     else
  533.         begin
  534.         Z := Z + 1;
  535.         Answer := Answer - Term
  536.         end;
  537.     Slough_Blanks
  538.     end;
  539.      If Debug_Mode then
  540.     Writeln ('Result from EXPR =', Answer:20:8);
  541.      Expr := Answer
  542.      end;  { Expr }
  543.  
  544. begin { Main }
  545. Initialize;
  546. Get_Expr;
  547. While Buf[Z] <> '$' do
  548.      begin
  549.      If Buf[Z] = '?' then
  550.     Help
  551.      else
  552.     If Buf[Z] = '!' then
  553.         Debug_Mode := not Debug_Mode
  554.     else
  555.         If Buf[Z] <> '$' then
  556.         begin
  557.         Answer := Expr;
  558.         Write ('The answer is ');
  559.         Write ( Answer:9:6 );
  560.         Writeln
  561.         end;
  562.      Get_Expr
  563.      end;
  564. Writeln;
  565. Writeln ('Program ended');
  566. Writeln
  567. end.
  568.