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