home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / calcultr / calculat.arc / CALCULAT.PAS < prev   
Pascal/Delphi Source File  |  1986-02-27  |  35KB  |  943 lines

  1. PROGRAM calc(INPUT,OUTPUT); 
  2.   {
  3.          This program uses recursive descent to evaluate expressions        
  4.     written in infix notation.  The operations addition (+),
  5.     subtraction (-), multiplication (*), and division (/) are supported,
  6.     as are the functions ABS, ARCTAN, COS, EXP, LN, SQR, and SQRT.
  7.     PI returns the value for pi.  Results exceeding 1.0E37 are reported
  8.     as overflows.  Results less than 1.0E-37 are set to zero.
  9.  
  10.          Written by James L. Dean
  11.                     406 40th Street
  12.                     New Orleans, LA 70124
  13.                     February 25, 1985
  14.  
  15.   }
  16.   TYPE
  17.     argument_record_ptr = ^argument_record;
  18.     argument_record = RECORD
  19.                         value : REAL;
  20.                         next_ptr : argument_record_ptr
  21.                       END;
  22.     string_1 = STRING[1];
  23.     string_255 = STRING[255];
  24.   VAR
  25.     error_detected              : BOOLEAN;
  26.     error_msg                   : string_255;  
  27.     expression                  : string_255; 
  28.     expression_index            : INTEGER;       
  29.     expression_length           : INTEGER;
  30.     result                      : REAL;
  31.   PROCEDURE set_error(msg : string_255);
  32.     BEGIN
  33.       error_detected:=TRUE;
  34.       error_msg
  35.        :='Error:  '+msg+'.'
  36.     END;
  37.   PROCEDURE eat_leading_spaces;
  38.     VAR
  39.       non_blank_found           : BOOLEAN;
  40.     BEGIN
  41.       non_blank_found:=FALSE;
  42.       WHILE((expression_index <= expression_length)
  43.       AND   (NOT non_blank_found)) DO
  44.         IF expression[expression_index] = ' ' THEN
  45.           expression_index:=expression_index+1
  46.         ELSE
  47.           non_blank_found:=TRUE
  48.     END;
  49.   FUNCTION unsigned_integer : REAL;
  50.     VAR
  51.       non_digit_found           : BOOLEAN;
  52.       overflow                  : BOOLEAN;
  53.       result                    : REAL;
  54.       tem_char                  : CHAR;
  55.       tem_real                  : REAL;
  56.     BEGIN
  57.       non_digit_found:=FALSE;
  58.       result:=0.0;
  59.       overflow:=FALSE;
  60.       REPEAT
  61.         tem_char:=expression[expression_index];
  62.         IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  63.           BEGIN
  64.             tem_real:=ORD(tem_char)-ORD('0');
  65.             IF result > 1.0E36 THEN
  66.               overflow:=TRUE
  67.             ELSE
  68.               BEGIN
  69.                 result:=10.0*result+tem_real;
  70.                 expression_index:=expression_index+1;
  71.                 IF expression_index > expression_length THEN
  72.                   non_digit_found:=TRUE
  73.               END
  74.           END
  75.         ELSE
  76.           non_digit_found:=TRUE
  77.       UNTIL ((non_digit_found) OR (overflow));
  78.       IF overflow THEN
  79.         set_error('constant is too big');
  80.       unsigned_integer:=result
  81.     END;
  82.   FUNCTION unsigned_number : REAL;
  83.     VAR
  84.       exponent_value            : REAL;
  85.       exponent_sign             : CHAR;
  86.       factor                    : REAL;
  87.       non_digit_found           : BOOLEAN;
  88.       result                    : REAL;
  89.       tem_char                  : CHAR;
  90.       tem_real_1                : REAL;
  91.       tem_real_2                : REAL;
  92.     BEGIN
  93.       result:=unsigned_integer;
  94.       IF (NOT error_detected) THEN
  95.         BEGIN
  96.           IF expression_index <= expression_length THEN
  97.             BEGIN
  98.               tem_char:=expression[expression_index];
  99.               IF tem_char = '.' THEN
  100.                 BEGIN
  101.                   tem_real_1:=result;
  102.                   expression_index:=expression_index+1;
  103.                   IF expression_index > expression_length THEN
  104.                     set_error(
  105.             'end of expression encountered where decimal part expected')
  106.                   ELSE
  107.                     BEGIN
  108.                       tem_char:=expression[expression_index];
  109.                       IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  110.                         BEGIN
  111.                           factor:=1.0;
  112.                           non_digit_found:=FALSE;
  113.                           WHILE (NOT non_digit_found) DO
  114.                             BEGIN
  115.                               factor:=factor/10.0;
  116.                               tem_real_2:=ORD(tem_char)-ORD('0');
  117.                               tem_real_1:=tem_real_1+factor*tem_real_2;
  118.                               expression_index:=expression_index+1;
  119.                               IF expression_index > expression_length THEN
  120.                                non_digit_found:=TRUE
  121.                               ELSE
  122.                                 BEGIN
  123.                                   tem_char
  124.                                    :=expression[expression_index];
  125.                                   IF ((tem_char < '0')
  126.                                   OR  (tem_char > '9')) THEN
  127.                                     non_digit_found:=TRUE
  128.                                 END
  129.                             END;
  130.                           result:=tem_real_1
  131.                         END
  132.                       ELSE
  133.                         set_error(
  134.                          'decimal part of real number is missing')
  135.                     END
  136.                 END;
  137.               IF (NOT error_detected) THEN
  138.                 BEGIN
  139.                   IF expression_index <= expression_length THEN
  140.                     BEGIN
  141.                       IF ((tem_char = 'e') OR (tem_char = 'E')) THEN
  142.                         BEGIN
  143.                           expression_index:=expression_index+1;
  144.                           IF expression_index > expression_length THEN
  145.                             set_error(
  146.                'end of expression encountered where exponent expected')
  147.                          ELSE
  148.                             BEGIN
  149.                               tem_char
  150.                                :=expression[expression_index];
  151.                               IF ((tem_char = '+')
  152.                               OR  (tem_char = '-')) THEN
  153.                                 BEGIN
  154.                                   exponent_sign:=tem_char;
  155.                                   expression_index:=expression_index+1
  156.                                 END
  157.                               ELSE
  158.                                 exponent_sign:=' ';
  159.                               IF expression_index > expression_length
  160.                                THEN
  161.                                 set_error(
  162.      'end of expression encountered where exponent magnitude expected')
  163.                               ELSE
  164.                                 BEGIN
  165.                                   tem_char:=expression[expression_index];
  166.                                  IF ((tem_char >= '0')
  167.                                   AND (tem_char <= '9')) THEN
  168.                                     BEGIN
  169.                                       exponent_value
  170.                                        :=unsigned_integer;
  171.                                       IF (NOT error_detected) THEN
  172.                                         BEGIN
  173.                                           IF exponent_value > 37.0 THEN
  174.                                             set_error(
  175.                                    'magnitude of exponent is too large')
  176.                                           ELSE
  177.                                             BEGIN
  178.                                               tem_real_1:=1.0;
  179.                                               WHILE (exponent_value > 0.0) DO
  180.                                                 BEGIN
  181.                                                   exponent_value
  182.                                                    :=exponent_value-1.0;
  183.                                                   tem_real_1:=10.0*tem_real_1
  184.                                                 END;
  185.                                               IF exponent_sign = '-' THEN
  186.                                                tem_real_1
  187.                                                 :=1.0/tem_real_1;
  188.                                               IF result <> 0.0 THEN
  189.                                                 BEGIN
  190.                                                   tem_real_2
  191.                                                    :=(LN(tem_real_1)
  192.                                                    +LN(ABS(result)))
  193.                                                    /LN(10.0);
  194.                                                   IF tem_real_2 < -37.0 THEN
  195.                                                     result:=0.0
  196.                                                   ELSE
  197.                                                     IF tem_real_2 > 37.0 THEN
  198.                                                       set_error(
  199.                                                        'constant is too big')
  200.                                                     ELSE
  201.                                                       result:=result*tem_real_1
  202.                                                 END
  203.                                             END
  204.                                         END
  205.                                     END
  206.                                   ELSE
  207.                                     set_error(
  208.                                      'nonnumeric exponent encountered')
  209.                                 END
  210.                             END
  211.                         END
  212.                     END
  213.                 END
  214.             END
  215.         END;
  216.       unsigned_number:=result
  217.     END;
  218.   FUNCTION pop_argument(VAR argument_stack_head : argument_record_ptr) : REAL;
  219.     VAR
  220.       argument_stack_ptr        : argument_record_ptr;
  221.       result                    : REAL;
  222.     BEGIN
  223.       result
  224.        :=argument_stack_head^.value;
  225.       argument_stack_ptr
  226.        :=argument_stack_head^.next_ptr;
  227.       DISPOSE(argument_stack_head);
  228.       argument_stack_head:=argument_stack_ptr;
  229.       pop_argument:=result
  230.     END;
  231.   FUNCTION abs_function(VAR argument_stack_head : argument_record_ptr;
  232.    VAR function_name : string_255) : REAL;
  233.     VAR
  234.       argument                  : REAL;
  235.       result                    : REAL;
  236.     BEGIN
  237.       result:=0.0;
  238.       IF argument_stack_head = NIL THEN
  239.         set_error(
  240.          'argument to "'+function_name+'" is missing')
  241.       ELSE
  242.         BEGIN
  243.           argument:=pop_argument(argument_stack_head);
  244.           IF argument_stack_head = NIL THEN
  245.             IF argument >= 0.0 THEN
  246.               result:=argument
  247.             ELSE
  248.               result:=-argument
  249.           ELSE
  250.             set_error(
  251.              'extraneous argument supplied to function "'+
  252.              function_name+'"')
  253.         END;
  254.       abs_function:=result
  255.     END;
  256.   FUNCTION arctan_function(VAR argument_stack_head : argument_record_ptr;
  257.    VAR function_name : string_255) : REAL;
  258.     VAR
  259.       argument                  : REAL;
  260.       result                    : REAL;
  261.     BEGIN
  262.       result:=0.0;
  263.       IF argument_stack_head = NIL THEN
  264.        set_error(
  265.         'argument to "'+function_name+'" is missing')
  266.       ELSE
  267.         BEGIN
  268.           argument:=pop_argument(argument_stack_head);
  269.           IF argument_stack_head = NIL THEN
  270.             result:=ARCTAN(argument)
  271.           ELSE
  272.             set_error(
  273.              'extraneous argument supplied to function "'+
  274.              function_name+'"')
  275.         END;
  276.       arctan_function:=result
  277.     END;
  278.   FUNCTION cos_function(VAR argument_stack_head : argument_record_ptr;
  279.    VAR function_name : string_255) : REAL;
  280.     VAR
  281.       argument                  : REAL;
  282.       result                    : REAL;
  283.     BEGIN
  284.       result:=0.0;
  285.       IF argument_stack_head = NIL THEN
  286.         set_error(
  287.          'argument to "'+function_name+'" is missing')
  288.       ELSE
  289.         BEGIN
  290.           argument:=pop_argument(argument_stack_head);
  291.           IF argument_stack_head = NIL THEN
  292.             result:=COS(argument)
  293.           ELSE
  294.             set_error(
  295.              'extraneous argument supplied to function "'+
  296.              function_name+'"')
  297.         END;
  298.       cos_function:=result
  299.     END;
  300.   FUNCTION exp_function(VAR argument_stack_head : argument_record_ptr;
  301.    VAR function_name : string_255) : REAL;
  302.     VAR
  303.       argument                  : REAL;
  304.       result                    : REAL;
  305.       tem_real                  : REAL;
  306.     BEGIN
  307.       result:=0.0;
  308.       IF argument_stack_head = NIL THEN
  309.         set_error(
  310.          'argument to "'+function_name+'" is missing')
  311.       ELSE
  312.         BEGIN
  313.           argument:=pop_argument(argument_stack_head);
  314.           IF argument_stack_head = NIL THEN
  315.             BEGIN
  316.               tem_real:=argument/LN(10.0);
  317.               IF tem_real < -37.0 THEN
  318.                 result:=0.0
  319.               ELSE
  320.                 IF tem_real > 37.0 THEN
  321.                   set_error(
  322.                    'overflow detected while calculating "'+
  323.                    function_name+'"')
  324.                 ELSE
  325.                   result:=EXP(argument)
  326.             END
  327.           ELSE
  328.             set_error(
  329.              'extraneous argument supplied to function "'+
  330.              function_name+'"')
  331.         END;
  332.       exp_function:=result
  333.     END;
  334.   FUNCTION ln_function(VAR argument_stack_head : argument_record_ptr;
  335.    VAR function_name : string_255) : REAL;
  336.     VAR
  337.       argument                  : REAL;
  338.       result                    : REAL;
  339.     BEGIN
  340.       result:=0.0;
  341.       IF argument_stack_head = NIL THEN
  342.         set_error(
  343.          'argument to "'+function_name+'" is missing')
  344.       ELSE
  345.         BEGIN
  346.           argument:=pop_argument(argument_stack_head);
  347.           IF argument_stack_head = NIL THEN
  348.             IF argument <= 0.0 THEN
  349.               set_error(
  350.                'argument to "'+function_name+
  351.                '" is other than positive')
  352.             ELSE
  353.               result:=LN(argument)
  354.           ELSE
  355.             set_error(
  356.              'extraneous argument supplied to function "'+
  357.              function_name+'"')
  358.         END;
  359.       ln_function:=result
  360.     END;
  361.   FUNCTION pi_function(VAR argument_stack_head : argument_record_ptr;
  362.    VAR function_name : string_255) : REAL;
  363.     VAR
  364.       argument                  : REAL;
  365.       result                    : REAL;
  366.     BEGIN
  367.       result:=0.0;
  368.       IF argument_stack_head = NIL THEN
  369.         result:=4.0*ARCTAN(1.0)
  370.       ELSE
  371.         set_error(
  372.          'extraneous argument supplied to function "'+
  373.          function_name+'"');
  374.       pi_function:=result
  375.     END;
  376.   FUNCTION sin_function(VAR argument_stack_head : argument_record_ptr;
  377.    VAR function_name : string_255) : REAL;
  378.     VAR
  379.       argument                  : REAL;
  380.       result                    : REAL;
  381.     BEGIN
  382.       result:=0.0;
  383.       IF argument_stack_head = NIL THEN
  384.         set_error(
  385.          'argument to "'+function_name+'" is missing')
  386.       ELSE
  387.         BEGIN
  388.           argument:=pop_argument(argument_stack_head);
  389.           IF argument_stack_head = NIL THEN
  390.             result:=SIN(argument)
  391.           ELSE
  392.             set_error(
  393.              'extraneous argument supplied to function "'+
  394.              function_name+'"')
  395.         END;
  396.       sin_function:=result
  397.     END;
  398.   FUNCTION sqr_function(VAR argument_stack_head : argument_record_ptr;
  399.    VAR function_name : string_255) : REAL;
  400.     VAR
  401.       argument                  : REAL;
  402.       result                    : REAL;
  403.       tem_real                  : REAL;
  404.     BEGIN
  405.       result:=0.0;
  406.       IF argument_stack_head = NIL THEN
  407.         set_error(
  408.          'argument to "'+function_name+'" is missing')
  409.       ELSE
  410.         BEGIN
  411.           argument:=pop_argument(argument_stack_head);
  412.           IF argument_stack_head = NIL THEN
  413.             IF argument = 0.0 THEN
  414.               result:=0.0
  415.             ELSE
  416.               BEGIN
  417.                 tem_real:=2.0*LN(ABS(argument))/LN(10.0);
  418.                 IF tem_real < -37.0 THEN
  419.                   result:=0.0
  420.                 ELSE
  421.                   IF tem_real > 37.0 THEN
  422.                     set_error(
  423.                      'overflow detected during calculation of "'+
  424.                      function_name+'"')
  425.                   ELSE
  426.                     result:=argument*argument
  427.               END
  428.           ELSE
  429.             set_error(
  430.              'extraneous argument supplied to function "'+
  431.              function_name+'"')
  432.         END;
  433.       sqr_function:=result
  434.     END;
  435.   FUNCTION sqrt_function(VAR argument_stack_head : argument_record_ptr;
  436.    VAR function_name : string_255) : REAL;
  437.     VAR
  438.       argument                  : REAL;
  439.       result                    : REAL;
  440.     BEGIN
  441.       result:=0.0;
  442.       IF argument_stack_head = NIL THEN
  443.         set_error(
  444.          'argument to "'+function_name+'" is missing')
  445.       ELSE
  446.         BEGIN
  447.           argument:=pop_argument(argument_stack_head);
  448.           IF argument_stack_head = NIL THEN
  449.             IF argument < 0.0 THEN
  450.               set_error(
  451.                'argument to "'+function_name+
  452.                '" is negative')
  453.             ELSE
  454.               result:=SQRT(argument)
  455.           ELSE
  456.             set_error(
  457.              'extraneous argument supplied to function "'+
  458.              function_name+'"')
  459.         END;
  460.       sqrt_function:=result
  461.     END;
  462.   FUNCTION simple_expression : REAL; FORWARD;
  463.   FUNCTION funct : REAL;
  464.     VAR
  465.       argument                  : REAL;
  466.       argument_stack_head       : argument_record_ptr;
  467.       argument_stack_ptr        : argument_record_ptr;
  468.       arguments_okay            : BOOLEAN;
  469.       function_name             : string_255;
  470.       non_alphanumeric_found    : BOOLEAN;
  471.       result                    : REAL;
  472.       right_parenthesis_found   : BOOLEAN;
  473.       tem_char                  : CHAR;
  474.     BEGIN    
  475.       result:=0.0;
  476.       non_alphanumeric_found:=FALSE;
  477.       function_name:='';
  478.       WHILE((expression_index <= expression_length)
  479.       AND   (NOT non_alphanumeric_found)) DO
  480.         BEGIN
  481.           tem_char:=expression[expression_index];
  482.           tem_char:=UPCASE(tem_char);
  483.           IF ((tem_char >= 'A') AND (tem_char <= 'Z')) THEN
  484.             BEGIN
  485.               function_name:=function_name+tem_char;
  486.               expression_index:=expression_index+1
  487.             END
  488.           ELSE
  489.             non_alphanumeric_found:=TRUE
  490.         END;
  491.       argument_stack_head:=NIL;
  492.       arguments_okay:=TRUE;
  493.       eat_leading_spaces;
  494.       IF expression_index <= expression_length THEN
  495.         BEGIN
  496.           tem_char:=expression[expression_index];
  497.           IF tem_char = '(' THEN
  498.             BEGIN
  499.               expression_index:=expression_index+1;
  500.               right_parenthesis_found:=FALSE;
  501.               WHILE ((NOT right_parenthesis_found)
  502.               AND    (arguments_okay)
  503.               AND    (expression_index <= expression_length)) DO
  504.                 BEGIN
  505.                   argument:=simple_expression;
  506.                   IF error_detected THEN
  507.                     arguments_okay:=FALSE
  508.                   ELSE
  509.                     BEGIN
  510.                       IF argument_stack_head = NIL THEN
  511.                         BEGIN
  512.                           NEW(argument_stack_head);
  513.                           argument_stack_head^.value:=argument;
  514.                           argument_stack_head^.next_ptr:=NIL
  515.                         END
  516.                       ELSE
  517.                         BEGIN
  518.                           NEW(argument_stack_ptr);
  519.                           argument_stack_ptr^.value:=argument;
  520.                           argument_stack_ptr^.next_ptr
  521.                            :=argument_stack_head;
  522.                           argument_stack_head:=argument_stack_ptr
  523.                         END;
  524.                       eat_leading_spaces;
  525.                       IF expression_index <= expression_length THEN
  526.                         BEGIN
  527.                           tem_char:=expression[expression_index];
  528.                           IF tem_char = ')' THEN
  529.                             BEGIN
  530.                               right_parenthesis_found:=TRUE;
  531.                               expression_index:=expression_index+1
  532.                             END
  533.                           ELSE
  534.                             IF tem_char = ',' THEN
  535.                               expression_index:=expression_index+1
  536.                             ELSE
  537.                               BEGIN
  538.                                 arguments_okay:=FALSE;
  539.                                 set_error(
  540.                             'comma missing from function arguments')
  541.                               END
  542.                         END
  543.                     END
  544.                 END;
  545.               IF arguments_okay THEN
  546.                 BEGIN
  547.                   IF (NOT right_parenthesis_found) THEN
  548.                     BEGIN
  549.                       arguments_okay:=FALSE;
  550.                       set_error(
  551.                    '")" to terminate function arguments is missing')
  552.                     END
  553.                 END
  554.             END
  555.         END;
  556.       IF arguments_okay THEN
  557.         BEGIN
  558.           IF function_name = 'ABS' THEN
  559.             result
  560.              :=abs_function(argument_stack_head,function_name) 
  561.           ELSE
  562.             IF function_name = 'ARCTAN' THEN
  563.               result
  564.                :=arctan_function(argument_stack_head,function_name)
  565.             ELSE
  566.               IF function_name = 'COS' THEN
  567.                 result
  568.                  :=cos_function(argument_stack_head,function_name)
  569.               ELSE
  570.                 IF function_name = 'EXP' THEN
  571.                   result
  572.                    :=exp_function(argument_stack_head,function_name)
  573.                 ELSE
  574.                   IF function_name = 'LN' THEN
  575.                     result
  576.                      :=ln_function(argument_stack_head,function_name)
  577.                   ELSE
  578.                     IF function_name = 'PI' THEN
  579.                       result
  580.                        :=pi_function(argument_stack_head,function_name)
  581.                     ELSE
  582.                       IF function_name = 'SIN' THEN
  583.                         result
  584.                          :=sin_function(argument_stack_head,function_name)
  585.                       ELSE
  586.                         IF function_name = 'SQR' THEN
  587.                           result
  588.                            :=sqr_function(argument_stack_head,function_name)
  589.                         ELSE
  590.                           IF function_name = 'SQRT' THEN
  591.                             result
  592.                              :=sqrt_function(argument_stack_head,function_name)
  593.                           ELSE
  594.                             set_error('the function "'+
  595.                              function_name+'" is unrecognized')
  596.         END;
  597.       WHILE (argument_stack_head <> NIL) DO
  598.         BEGIN
  599.           argument_stack_ptr:=argument_stack_head^.next_ptr;
  600.           DISPOSE(argument_stack_head);
  601.           argument_stack_head:=argument_stack_ptr
  602.         END;
  603.       funct:=result
  604.     END;
  605.   FUNCTION factor : REAL;
  606.     VAR
  607.       result                    : REAL;
  608.       tem_char                  : CHAR;
  609.     BEGIN
  610.       result:=0.0;
  611.       eat_leading_spaces;
  612.       IF expression_index > expression_length THEN
  613.         set_error(
  614.          'end of expression encountered where factor expected')
  615.       ELSE
  616.         BEGIN
  617.           tem_char:=expression[expression_index];
  618.           BEGIN
  619.             IF tem_char = '(' THEN
  620.               BEGIN
  621.                 expression_index:=expression_index+1;
  622.                 result:=simple_expression;
  623.                 IF (NOT error_detected) THEN
  624.                   BEGIN
  625.                     eat_leading_spaces;
  626.                     IF expression_index > expression_length THEN
  627.                       set_error(
  628.                        'end of expression encountered '+
  629.                        'where ")" was expected')
  630.                     ELSE
  631.                       IF expression[expression_index] = ')' THEN
  632.                         expression_index:=expression_index+1
  633.                       ELSE
  634.                         set_error('expression not followed by ")"')
  635.                   END
  636.               END
  637.             ELSE
  638.               IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  639.                 result:=unsigned_number
  640.               ELSE
  641.                 IF (((tem_char >= 'a') AND (tem_char <= 'z'))
  642.                 OR  ((tem_char >= 'A') AND (tem_char <= 'Z'))) THEN
  643.                   result:=funct
  644.                 ELSE
  645.                   set_error(
  646.                    'function, unsigned number, or "(" expected')
  647.           END
  648.         END;
  649.       factor:=result
  650.     END;
  651.   FUNCTION quotient_of_factors(VAR left_value,right_value : REAL) : REAL;
  652.     VAR
  653.       result                    : REAL;
  654.       tem_real                  : REAL;
  655.     BEGIN
  656.       result:=0.0;
  657.       IF right_value = 0.0 THEN
  658.         set_error('division by zero attempted')
  659.       ELSE
  660.         BEGIN
  661.           IF left_value = 0.0 THEN
  662.             result:=0.0
  663.           ELSE
  664.             BEGIN
  665.               tem_real:=(LN(ABS(left_value))-LN(ABS(right_value)))/LN(10.0);
  666.               IF tem_real < -37.0 THEN 
  667.                 result:=0.0
  668.               ELSE
  669.                 IF tem_real > 37.0 THEN
  670.                   set_error(
  671.                    'overflow detected during division')
  672.                 ELSE
  673.                   result:=left_value/right_value
  674.             END
  675.         END;
  676.       quotient_of_factors:=result
  677.     END;
  678.   FUNCTION product_of_factors(VAR left_value,right_value : REAL) : REAL;
  679.     VAR
  680.       result                    : REAL;
  681.       tem_real                  : REAL;
  682.     BEGIN
  683.       result:=0.0;
  684.       IF ((left_value <> 0.0) AND (right_value <> 0.0)) THEN
  685.         BEGIN
  686.           tem_real:=(LN(ABS(left_value))+LN(ABS(right_value)))/LN(10.0); 
  687.           IF tem_real < -37.0 THEN
  688.             result:=0.0
  689.           ELSE
  690.             IF tem_real > 37.0 THEN
  691.               set_error(
  692.                'overflow detected during multiplication')
  693.             ELSE
  694.               result:=left_value*right_value
  695.         END;
  696.       product_of_factors:=result
  697.     END;
  698.   FUNCTION factor_operator : string_1;
  699.     VAR
  700.       result                    : string_1;
  701.     BEGIN
  702.       eat_leading_spaces;
  703.       IF expression_index <= expression_length THEN
  704.         BEGIN
  705.           result:=expression[expression_index];
  706.           IF ((result = '*')
  707.           OR  (result = '/')) THEN
  708.             expression_index:=expression_index+1
  709.         END
  710.       ELSE
  711.         result:='';
  712.       factor_operator:=result
  713.     END;
  714.   FUNCTION term : REAL;
  715.     VAR
  716.       operator                  : string_1;
  717.       operator_found            : BOOLEAN;
  718.       result                    : REAL;
  719.       right_value               : REAL;
  720.     BEGIN
  721.       result:=0;
  722.       eat_leading_spaces;
  723.       IF expression_index > expression_length THEN
  724.         set_error(
  725.          'end of expression encountered where term was expected')
  726.       ELSE
  727.         BEGIN
  728.           result:=factor;
  729.           operator_found:=TRUE;
  730.           WHILE((NOT error_detected)
  731.           AND   (operator_found)) DO
  732.             BEGIN
  733.               operator:=factor_operator;
  734.               IF LENGTH(operator) = 0 THEN
  735.                 operator_found:=FALSE
  736.               ELSE
  737.                 IF ((operator <> '*')
  738.                 AND (operator <> '/')) THEN
  739.                   operator_found:=FALSE
  740.                 ELSE
  741.                   BEGIN
  742.                     right_value:=factor;
  743.                     IF (NOT error_detected) THEN
  744.                       BEGIN
  745.                         IF operator = '*' THEN
  746.                             result:=product_of_factors(
  747.                              result,right_value)
  748.                         ELSE
  749.                             result:=quotient_of_factors(
  750.                              result,right_value)
  751.                       END
  752.                   END
  753.             END
  754.         END;
  755.       term:=result
  756.     END;
  757.   FUNCTION sum_of_terms(VAR left_value,right_value : REAL) : REAL;
  758.     VAR
  759.       result                    : REAL;
  760.     BEGIN
  761.       result:=0.0;
  762.       IF ((left_value > 0.0) AND (right_value > 0.0)) THEN
  763.         IF left_value > (1.0E37 - right_value) THEN
  764.           set_error('overflow detected during addition')
  765.         ELSE
  766.           result:=left_value+right_value
  767.       ELSE
  768.         IF ((left_value < 0.0) AND (right_value < 0.0)) THEN
  769.           IF left_value < (-1.0E37 - right_value) THEN
  770.             set_error('overflow detected during addition')
  771.           ELSE
  772.             result:=left_value+right_value
  773.         ELSE
  774.           result:=left_value+right_value;
  775.       sum_of_terms:=result
  776.     END;
  777.   FUNCTION difference_of_terms(VAR left_value,right_value : REAL) : REAL;
  778.     VAR
  779.       result                    : REAL;
  780.     BEGIN
  781.       IF ((left_value < 0.0) AND (right_value > 0.0)) THEN
  782.         IF left_value < (right_value - 1.0E37) THEN
  783.           set_error('overflow detected during subtraction')
  784.         ELSE
  785.           result:=left_value-right_value
  786.       ELSE
  787.         IF ((left_value > 0.0) AND (right_value < 0.0)) THEN
  788.           IF left_value > (right_value + 1.0E37) THEN
  789.             set_error('overflow detected during subtraction')
  790.           ELSE
  791.             result:=left_value-right_value
  792.         ELSE
  793.           result:=left_value-right_value;
  794.       difference_of_terms:=result
  795.     END;
  796.   FUNCTION term_operator : string_1;
  797.     VAR
  798.       result                    : string_1;
  799.     BEGIN
  800.       eat_leading_spaces;
  801.       IF expression_index <= expression_length THEN
  802.         BEGIN
  803.           result:=expression[expression_index];
  804.           IF ((result = '+')
  805.           OR  (result = '-')) THEN
  806.             expression_index:=expression_index+1
  807.         END
  808.       ELSE
  809.         result:='';
  810.       term_operator:=result
  811.     END;
  812.   FUNCTION simple_expression;
  813.     VAR
  814.       leading_sign              : CHAR;
  815.       operator                  : string_1;
  816.       operator_found            : BOOLEAN;
  817.       result                    : REAL;
  818.       right_value               : REAL;
  819.       tem_char                  : CHAR;
  820.     BEGIN
  821.       result:=0.0;
  822.       eat_leading_spaces;
  823.       IF expression_index > expression_length THEN
  824.         set_error(
  825.        'end of expression encountered where simple expression expected')
  826.       ELSE
  827.         BEGIN
  828.           leading_sign:=' ';
  829.           tem_char:=expression[expression_index];
  830.           IF ((tem_char = '+') OR (tem_char = '-')) THEN
  831.             BEGIN
  832.               leading_sign:=tem_char;
  833.               expression_index:=expression_index+1
  834.             END;
  835.           result:=term;
  836.           IF (NOT error_detected) THEN
  837.             BEGIN
  838.               IF leading_sign <> ' ' THEN
  839.                 BEGIN
  840.                   IF leading_sign = '-' THEN
  841.                     result:=-result
  842.                 END;
  843.               operator_found:=TRUE;
  844.               WHILE((NOT error_detected)
  845.               AND   (operator_found)) DO
  846.                 BEGIN
  847.                   operator:=term_operator;
  848.                   IF LENGTH(operator) = 0 THEN
  849.                     operator_found:=FALSE
  850.                   ELSE
  851.                     IF ((operator <> '+')
  852.                     AND (operator <> '-')) THEN
  853.                       operator_found:=FALSE
  854.                     ELSE
  855.                       BEGIN
  856.                         right_value:=term;
  857.                         IF (NOT error_detected) THEN
  858.                           BEGIN
  859.                             IF operator = '+' THEN
  860.                               result:=sum_of_terms(
  861.                                result,right_value)
  862.                             ELSE
  863.                               result:=difference_of_terms(
  864.                                result,right_value)
  865.                           END
  866.                       END
  867.                 END
  868.             END
  869.         END;
  870.       simple_expression:=result
  871.     END;
  872.   PROCEDURE output_value(VAR result : REAL);
  873.     VAR
  874.       digits_in_integer_part       : INTEGER;
  875.       magnitude_of_result          : REAL;
  876.     BEGIN
  877.       WRITE(OUTPUT,'Value:  ');
  878.       IF result >= 0.0 THEN
  879.         magnitude_of_result:=result
  880.       ELSE
  881.         magnitude_of_result:=-result;
  882.       IF magnitude_of_result >= 5.0E-3 THEN
  883.         BEGIN
  884.           digits_in_integer_part:=0;
  885.           WHILE ((digits_in_integer_part <= 8)
  886.           AND    (magnitude_of_result >= 1.0)) DO
  887.             BEGIN
  888.               magnitude_of_result:=magnitude_of_result/10.0;
  889.               digits_in_integer_part:=digits_in_integer_part+1
  890.             END;
  891.           IF digits_in_integer_part > 8 THEN
  892.             WRITELN(OUTPUT,result:13)
  893.           ELSE
  894.             WRITELN(OUTPUT,result:10:8-digits_in_integer_part)
  895.         END
  896.       ELSE
  897.         WRITELN(OUTPUT,result:13)
  898.     END;
  899.   PROCEDURE output_error(
  900.    error_msg : string_255;
  901.    VAR expression : string_255;
  902.    VAR expression_index : INTEGER);
  903.     VAR
  904.       error_index               : INTEGER;
  905.     BEGIN
  906.       WRITELN(OUTPUT,error_msg);
  907.       WRITELN(OUTPUT,expression);
  908.       error_index:=1;
  909.       WHILE (error_index < expression_index) DO
  910.         BEGIN
  911.           WRITE(OUTPUT,' ');
  912.           error_index:=error_index+1
  913.         END;
  914.       WRITELN(OUTPUT,'*')
  915.     END;
  916.   BEGIN
  917.     REPEAT
  918.       WRITELN(OUTPUT,' ');
  919.       WRITE(OUTPUT,'Expression (RETURN to exit)?  ');
  920.       READLN(INPUT,expression);
  921.       expression_length:=LENGTH(expression);
  922.       IF expression_length > 0 THEN
  923.         BEGIN
  924.           error_detected:=FALSE;
  925.           expression_index:=1;
  926.           result:=simple_expression;
  927.           IF error_detected THEN
  928.             output_error(error_msg,expression,expression_index)
  929.           ELSE
  930.             BEGIN
  931.               eat_leading_spaces;
  932.               IF expression_index <= expression_length THEN
  933.                 output_error(
  934.                  'Error:  expression followed by garbage',
  935.                  expression,expression_index)
  936.               ELSE
  937.                 output_value(result)
  938.             END
  939.         END
  940.     UNTIL (expression_length = 0)
  941.   END.
  942. 
  943.