home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / apps / spread / opusprg / opussrc / e.pas < prev    next >
Pascal/Delphi Source File  |  1988-05-16  |  75KB  |  1,858 lines

  1.  
  2. {$M+}
  3. {$E+}
  4.  
  5. PROGRAM Mock;
  6.  
  7. {$I i:\opus.i}
  8. {$I i:\gctv.inc}
  9.  
  10. {$I d:\pascal\opus\xbios.def}
  11.  
  12. PROCEDURE STRIP_NUM ( VAR num_str : LorFstr;
  13.                       VAR str     : LorFstr;
  14.                       VAR str_pos,
  15.                           len     : INTEGER );
  16.    EXTERNAL;
  17. FUNCTION TRANSLATE_CELL ( VAR str      : LorFstr;    { cell_str or formula  }
  18.                           VAR str_pos  : INTEGER;    { position; 1 for cell }
  19.                               len      : INTEGER;    { length of string     }
  20.                           VAR row,col  : INTEGER;
  21.                           VAR row_rel,               { relative reference?  }
  22.                               col_rel  : BOOLEAN ) : StatusType;
  23.    EXTERNAL;
  24. PROCEDURE ALL_LISTS ( action : INTEGER; ptr : CellPtr; row,col : INTEGER );
  25.    EXTERNAL;
  26. FUNCTION VALID_NUMBER ( VAR num_str : LorFstr ) : StatusType;
  27.    EXTERNAL;
  28. FUNCTION STRING_TO_REAL ( VAR string_real : STR30 ) : REAL;
  29.    EXTERNAL;
  30. FUNCTION REQUEST_MEMORY ( what : ReqType ) : BOOLEAN;
  31.    EXTERNAL;
  32. FUNCTION LOCATE_CELL ( row,col : INTEGER ) : CellPtr;
  33.    EXTERNAL;
  34. FUNCTION NEW_CELL ( row,col : INTEGER ) : CellPtr;
  35.    EXTERNAL;
  36. PROCEDURE DELETE_CELL ( r,c      : INTEGER; 
  37.                         free_dep : BOOLEAN  );
  38.    EXTERNAL;
  39. PROCEDURE FIND_SCREEN_POS (     row,col             : INTEGER;
  40.                             VAR l_scr_row,l_scr_col : INTEGER );
  41.    EXTERNAL;
  42. PROCEDURE CELL_ON_SCREEN ( draw_or_toggle,row,col : INTEGER; force : BOOLEAN );
  43.    EXTERNAL;
  44. FUNCTION ASSIGNED ( row,col : INTEGER; VAR ptr : CellPtr ) : AssignedStatus;
  45.    EXTERNAL;
  46. PROCEDURE Set_Mouse ( a : Mouse_Type );
  47.    EXTERNAL;
  48.  
  49. PROCEDURE ERROR_MESSAGE ( VAR str     : LorFstr; 
  50.                           error       : StatusType;
  51.                           str_pos,len : INTEGER     );
  52.    EXTERNAL;
  53.    
  54. { following are EXP & LN functions to use instead of library, since lib is
  55.   only accurate to 6-9 digits. These are reasonably quick and accurate to 10+
  56.   digits. Use range reduction to get a number favorable for power-series
  57.   calculations, then laws of exponents/logarithms for final result. }
  58.  
  59. FUNCTION MY_EXP ( x : REAL ) : REAL;
  60.    VAR n,whole_num,i      : INTEGER;
  61.        sum,prod,frac,term : REAL;
  62.        neg                : BOOLEAN;
  63.    BEGIN
  64.        i := 1; { index into e_table }
  65.        prod := 1;
  66.        whole_num := TRUNC(x); { got the integer part }
  67.        neg := whole_num < 0;
  68.        frac := x-whole_num; { keeps sign of x }
  69.        whole_num := ABS(whole_num);
  70.        WHILE whole_num <> 0 DO BEGIN
  71.           IF whole_num & 1 <> 0 THEN { LSB set? }
  72.              IF neg THEN
  73.                 prod := prod/e_table[i]
  74.              ELSE
  75.                 prod := prod*e_table[i];
  76.           whole_num := ShR(whole_num,1); { prepare to test next bit }
  77.           i := i+1
  78.        END;
  79.        { so now, e^(x - x MOD 1) has been calculated. ( MOD being a REAL mod )
  80.          Next calculate e^(x MOD 1), which will satisfy |x| < 1, using the
  81.          MacLaurin series }
  82.        n := 0 ;
  83.        sum := 1;
  84.        term := 1;
  85.        REPEAT
  86.           n := n+1;
  87.           term := term*frac/n;
  88.           sum := sum+term
  89.        UNTIL ABS(term/sum) < 5E-12;
  90.        { and finally combine prod & sum }
  91.        my_exp := prod*sum
  92.    END; { MY_EXP }
  93.  
  94. FUNCTION MY_LN ( x : REAL ) : REAL;
  95.    VAR j,c2,c10,sign  : INTEGER;
  96.        sum,term,power : REAL;
  97.    BEGIN
  98.        { First, normalize the number so that 0.5 < x < 1.0, so we can use the
  99.          series described below. }
  100.        IF x = 1 THEN
  101.           my_ln := 0
  102.        ELSE BEGIN
  103.           c10 := 0;
  104.           WHILE x > 1 DO BEGIN
  105.              x := x/10;
  106.              c10 := c10+1 { have to 'multiply' later so positive c10 }
  107.           END;
  108.           WHILE x < 0.1 DO BEGIN
  109.              x := x*10;
  110.              c10 := c10-1 { have to 'divide' later so negative c10 }
  111.           END;
  112.           c2 := 0;
  113.           WHILE x < 0.5 DO BEGIN
  114.              x := x*2;
  115.              c2 := c2-1;
  116.           END;
  117.           sum := 0;
  118.           IF x < 1 THEN BEGIN
  119.              { since we're between 0.5 and 1.0, we must subtract one from x so
  120.                we in fact calculate ln(x), using the series which GIVES
  121.                ln(1+x) }
  122.              x := x-1;
  123.              { Now calculate the Taylor series
  124.                  ln(1+X) = X-(1/2X^2)+(1/3X^3)-(1/4X^4)...,
  125.                valid in the interval -1 < X <= -1,
  126.                where incr = a term in the series, until
  127.                ABS(incr/sum) < 5E-12, since a maximum of ten digits are
  128.                available in the fractional part of the mantissa. Caveat: since
  129.                the series include terms that alternate in sign, significant
  130.                cancellation error can occur with numbers like 1.00001. The lib
  131.                provides 5 digits. The worst case for this one is about 7 digit
  132.                precision. The real problem is that the lib mult/div routines
  133.                apparently work with a number format identical to the one
  134.                "visible" TO us, 6 bytes. It SHOULD work with an expanded prec
  135.                number and round the final result }
  136.              j := 1;
  137.              sign := 1;
  138.              power := x;
  139.              REPEAT
  140.                 term := 1/j*power;
  141.                 sum := sum+term;
  142.                 sign := -sign;
  143.                 j := (abs(j)+1)*sign;
  144.                 power := power*x
  145.              UNTIL ABS(term/sum) < 5E-12
  146.           END;
  147.           my_ln := sum+c10*Ln10+c2*Ln2 { combine }
  148.        END
  149.    END; { MY_LN }
  150.              
  151. PROCEDURE EVALUATE_FORMULA ( row,col  : INTEGER;
  152.                              force,
  153.                              new_form : BOOLEAN;
  154.                              cell     : CellPtr );
  155.  
  156.    LABEL 1,2;
  157.    VAR str_pos,len     : INTEGER;
  158.        result,old_num  : REAL;
  159.        dep             : DepPtr;
  160.        stat,old_status : StatusType;
  161.        ptr             : CellPtr;
  162.  
  163. (*************************************************************************)
  164. (* EVALUATE_FORMULA is the parent proc; see body of it for details       *) 
  165. (*************************************************************************)
  166.  
  167. PROCEDURE FULL_EXPR ( VAR str      : LorFstr;
  168.                       do_it        : BOOLEAN;
  169.                       VAR result   : REAL );
  170.    FORWARD; 
  171. FUNCTION CHECK_BOOLOP ( VAR str      : LorFstr;
  172.                         VAR bool_op  : BoolOps;
  173.                         VAR stat     : StatusType ) : BOOLEAN;
  174.    FORWARD; 
  175. FUNCTION EVAL_BOOLOP ( VAR bool_op : BoolOps;
  176.                        VAR arg_1,
  177.                            arg_2   : REAL ) : BOOLEAN;
  178.    FORWARD; 
  179. PROCEDURE VAL_EXPR ( VAR str      : LorFstr;
  180.                      do_it        : BOOLEAN;
  181.                      VAR result   : REAL );
  182.    FORWARD; 
  183. PROCEDURE TERM ( VAR str      : LorFstr;
  184.                  do_it        : BOOLEAN;
  185.                  VAR result   : REAL );
  186.    FORWARD; 
  187. PROCEDURE FACTOR ( VAR str     : LorFstr;
  188.                    do_it,
  189.                    get_neg     : BOOLEAN;
  190.                    VAR result  : REAL );
  191.    FORWARD;
  192. PROCEDURE EXPONENTIATION_EXPR ( VAR str      : LorFstr;
  193.                                 do_it,
  194.                                 get_neg      : BOOLEAN;
  195.                                 VAR result   : REAL );
  196.    FORWARD;
  197. PROCEDURE EVAL_FUNCTION ( VAR str      : LorFstr;
  198.                           do_it        : BOOLEAN;
  199.                           VAR result   : REAL;
  200.                           func_code    : AllFunctions );
  201.    FORWARD;
  202. PROCEDURE DO_SINGLE ( VAR str      : LorFstr;
  203.                       do_it        : BOOLEAN;
  204.                       VAR result   : REAL;
  205.                       func_code    : AllFunctions );
  206.    FORWARD;
  207. PROCEDURE DO_MULTIPLE ( VAR str      : LorFstr;
  208.                         do_it        : BOOLEAN;
  209.                         VAR result   : REAL;
  210.                         func_code    : AllFunctions );
  211.    FORWARD;
  212. PROCEDURE DO_DOUBLE ( VAR str      : LorFstr;
  213.                       do_it        : BOOLEAN;
  214.                       VAR result   : REAL;
  215.                       func_code    : AllFunctions );
  216.    FORWARD;
  217. PROCEDURE DO_AGGREGATE ( VAR str      : LorFstr;
  218.                          do_it        : BOOLEAN;
  219.                          VAR result   : REAL;
  220.                          func_code    : AllFunctions );
  221.    FORWARD;
  222. PROCEDURE DO_FINANCIAL ( VAR str      : LorFstr;
  223.                          do_it        : BOOLEAN;
  224.                          VAR result   : REAL;
  225.                          func_code    : AllFunctions );
  226.    FORWARD;
  227. PROCEDURE DO_LOOKUP ( VAR str      : LorFstr;
  228.                       do_it        : BOOLEAN;
  229.                       VAR result   : REAL;
  230.                       func_code    : AllFunctions );
  231.    FORWARD;
  232. PROCEDURE IF_EXPR ( VAR str      : LorFstr;
  233.                     do_it        : BOOLEAN; 
  234.                     VAR result   : REAL );
  235.    FORWARD; 
  236.  
  237. PROCEDURE ITS_PENDING;
  238.    BEGIN
  239.       cell^.format := cell^.format & no_recalc_mask & not_pending_mask;
  240.       GOTO 2
  241.    END;
  242.    
  243. PROCEDURE DO_ERROR ( VAR str : LorFstr );
  244.    { only invoke error-dialog if a new formula is being parsed }
  245.    BEGIN
  246.        IF new_form THEN BEGIN
  247.           Set_Mouse(M_Arrow);
  248.           error_message(str,stat,str_pos,len);
  249.           Set_Mouse(M_Bee)
  250.        END;
  251.        GOTO 1
  252.    END; { DO_ERROR }
  253.  
  254. FUNCTION FIND_FUNCTION ( VAR str       : STR10; 
  255.                          VAR func_code : AllFunctions ) : BOOLEAN;
  256.    { binary search for function name in array functions }
  257.    VAR low,mid,high : INTEGER;
  258.    BEGIN
  259.        find_function := FALSE;
  260.        low := 1;
  261.        high := n_functions;
  262.        WHILE low <= high DO BEGIN
  263.           mid := ( low+high ) DIV 2;
  264.           IF str < functions[mid].func_name THEN
  265.              high := mid-1
  266.           ELSE IF str > functions[mid].func_name THEN
  267.              low := mid+1
  268.           ELSE BEGIN
  269.              find_function := TRUE;
  270.              func_code := functions[mid].func_type;
  271.              low := high+1; { break }
  272.           END
  273.        END
  274.    END; { FIND_FUNCTION }
  275.  
  276. PROCEDURE GET_RANGE ( VAR str             : LorFstr;
  277.                       do_it               : BOOLEAN;
  278.                       VAR s_r,s_c,e_r,e_c : INTEGER );
  279.    { <cellrange> ::= <cellref>:<cellref> }
  280.    VAR i,j        : INTEGER;
  281.        dummy,quit : BOOLEAN;
  282.        ptr        : CellPtr;
  283.    BEGIN
  284.        IF str_pos < len THEN
  285.           IF str[str_pos] IN up_case+['$'] THEN BEGIN
  286.              stat := translate_cell(str,str_pos,len,s_r,s_c,dummy,dummy);
  287.              IF stat = OK THEN
  288.                 IF str_pos < len THEN
  289.                    IF str[str_pos] <> ':' THEN
  290.                       stat := SyntaxErr
  291.                    ELSE BEGIN
  292.                       str_pos := str_pos+1;
  293.                       stat := translate_cell(str,str_pos,len,e_r,e_c,
  294.                                              dummy,dummy);
  295.                       IF stat = OK THEN
  296.                          IF (s_r > e_r) OR (s_c > e_c) THEN
  297.                             stat := BadRef
  298.                          ELSE IF do_it THEN
  299.                             IF natural THEN 
  300.                                FOR i := s_r TO e_r DO BEGIN
  301.                                    ptr := data[i];
  302.                                    quit := FALSE;
  303.                                    WHILE (ptr <> NIL) AND (NOT quit) DO BEGIN
  304.                                       IF (ptr^.c >= s_c) AND
  305.                                          (ptr^.c <= e_c) THEN
  306.                                          IF ptr^.class = Expr THEN
  307.                                             IF ptr^.format & 
  308.                                                pending_mask <> 0 THEN
  309.                                                its_pending
  310.                                             ELSE IF ptr^.format & recalc_mask = 0 
  311.                                             THEN BEGIN
  312.                                                evaluate_formula(i,ptr^.c,
  313.                                                                 force,FALSE,
  314.                                                                 ptr);
  315.                                                IF ptr^.format & recalc_mask = 0
  316.                                                THEN
  317.                                                   its_pending
  318.                                             END
  319.                                             ELSE
  320.                                          ELSE   
  321.                                       ELSE IF ptr^.c > e_c THEN
  322.                                          quit := TRUE;   
  323.                                       ptr := ptr^.next
  324.                                    END
  325.                                END
  326.                             ELSE
  327.                          ELSE
  328.                       ELSE
  329.                    END
  330.                 ELSE
  331.                    stat := SyntaxErr
  332.              ELSE
  333.           END
  334.           ELSE
  335.              stat := SyntaxErr
  336.        ELSE
  337.           stat := SyntaxErr;
  338.        IF stat <> OK THEN
  339.           do_error(str)
  340.    END; { GET_RANGE }
  341.  
  342. FUNCTION ADD_OP ( a_char : CHAR; VAR op : CHAR ) : BOOLEAN;
  343.    BEGIN
  344.        op := a_char;
  345.        add_op := (a_char = '+') OR (a_char = '-')
  346.    END; { ADD_OP }
  347. FUNCTION MUL_OP ( a_char : CHAR; VAR op : CHAR ) : BOOLEAN;
  348.    BEGIN
  349.        op := a_char;
  350.        mul_op := (a_char = '*') OR (a_char = '/')
  351.    END; { ADD_OP }
  352.  
  353.  
  354. { some general crash-proofing routines; NOT exhaustive }
  355.  
  356. FUNCTION CHECK_EXP ( what : REAL ) : BOOLEAN;
  357.    BEGIN
  358.        IF ABS(what) < 85 THEN 
  359.           check_exp := TRUE
  360.        ELSE
  361.           check_exp := FALSE
  362.    END; { CHECK_EXP }       
  363.  
  364. FUNCTION CHECK_SQUARE ( what : REAL ) : BOOLEAN;
  365.    BEGIN
  366.        IF (ABS(what) > MaxSquare) OR
  367.           (
  368.             (ABS(what) < MinSquare) AND
  369.             (what <> 0)
  370.           ) THEN
  371.           check_square := FALSE
  372.        ELSE
  373.           check_square := TRUE
  374.    END; { CHECK_SQUARE }
  375.  
  376. FUNCTION FRACTION ( what            : REAL;
  377.                     VAR str         : LorFstr ) : REAL;
  378.    BEGIN  
  379.        what := ABS(what);
  380.        IF what > Long_Maxint THEN BEGIN
  381.           stat := Overflow;
  382.           do_error(str)
  383.        END
  384.        ELSE
  385.           fraction := what-LONG_TRUNC(what)
  386.    END; { FRACTION }
  387.  
  388. FUNCTION ODD_REAL ( what            : REAL;
  389.                     VAR str         : LorFstr ) : BOOLEAN;
  390.    BEGIN
  391.        IF fraction(what/2.0,str) > 0.25 THEN 
  392.           odd_real := TRUE                  { really should be = 0.5, but  }
  393.        ELSE                                 { best to account for rounding }
  394.           odd_real := FALSE                 { errors! }
  395.    END; { ODD_REAL }
  396.  
  397. { in general, status is checked at the end of all routines that can modify it,
  398.   and if it isn't = OK, a jump is made to do_error, and evaluation is stopped
  399.   at that point. Thus, when one routine calls another, if the "callee" returns,
  400.   status is guaranteed to be OK and no checking of this by the "caller" is
  401.   neccessary. Also, this ensures that the error returned is the "first" one
  402.   encountered, which may not be the case if handled less rigorously. }
  403.  
  404. PROCEDURE FULL_EXPR;
  405.    {
  406.      <fullexpr> ::= <valexpr> | <valexpr><boolop><valexpr>
  407.  
  408.      expr, val_expr, term, & factor are set up so that
  409.      all arithmetic operations and functions preceding and following
  410.      a boolop are executed before the conditional is tested, so that in
  411.      effect, the boolop has lowest precedence of all, and  1+2+3<1+2*5 means
  412.      6 < 11. Note that expr like 1<2<3 won't be flagged as an error unless
  413.      str_pos < len is checked upon return to evaluate_formula, since this
  414.      routine can't look for this because it may be called by factor, and we
  415.      wouldn't want to prematurely end with an error! }
  416.    VAR result_1 : REAL;
  417.        bool_op  : BoolOps;
  418.    BEGIN
  419.        val_expr(str,do_it,result);
  420.        IF str_pos < len THEN
  421.           IF check_boolop(str,bool_op,stat) THEN BEGIN
  422.              val_expr(str,do_it,result_1);
  423.              IF do_it THEN
  424.                 IF eval_boolop(bool_op,result,result_1) THEN
  425.                    result := 1.0
  426.                 ELSE
  427.                    result := 0.0
  428.           END;
  429.        IF stat <> OK THEN
  430.           do_error(str)
  431.    END; { FULL_EXPR }
  432.  
  433. FUNCTION CHECK_BOOLOP;
  434.    { called by full_expr; at least 2 chars in str }
  435.    BEGIN
  436.        check_boolop := TRUE;
  437.        IF str[str_pos] = '=' THEN BEGIN
  438.           bool_op := Equal;
  439.           str_pos := str_pos+1
  440.        END
  441.        ELSE IF str[str_pos] = '>' THEN
  442.           IF str[str_pos+1] = '=' THEN BEGIN
  443.              bool_op := GreaterOrEqual;
  444.              str_pos := str_pos+2
  445.           END
  446.           ELSE BEGIN
  447.              bool_op := Greater;
  448.              str_pos := str_pos+1
  449.           END
  450.        ELSE IF str[str_pos] = '<' THEN
  451.           IF str[str_pos+1] = '=' THEN BEGIN
  452.              bool_op := LesserOrEqual;
  453.              str_pos := str_pos+2
  454.           END
  455.           ELSE IF str[str_pos+1] = '>' THEN BEGIN
  456.              bool_op := NotEqual;
  457.              str_pos := str_pos+2
  458.           END
  459.           ELSE BEGIN
  460.              bool_op := Lesser;
  461.              str_pos := str_pos+1
  462.           END
  463.        ELSE
  464.           check_boolop := FALSE
  465.    END; { CHECK_BOOLOP }
  466.  
  467. FUNCTION EVAL_BOOLOP;
  468.    BEGIN
  469.        CASE bool_op OF
  470.           Equal          : eval_boolop := arg_1 = arg_2;
  471.           NotEqual       : eval_boolop := arg_1 <> arg_2;
  472.           Lesser         : eval_boolop := arg_1 < arg_2;
  473.           LesserOrEqual  : eval_boolop := arg_1 <= arg_2;
  474.           Greater        : eval_boolop := arg_1 > arg_2;
  475.           GreaterOrEqual : eval_boolop := arg_1 >= arg_2
  476.        END
  477.    END; { EVAL_BOOLOP }
  478.  
  479. PROCEDURE VAL_EXPR;
  480.    (*
  481.      <valexpr> ::= <term> { <addop><term> }
  482.    *)
  483.    VAR result_1 : REAL;
  484.        continue : BOOLEAN;
  485.        op       : CHAR;
  486.    BEGIN
  487.        term(str,do_it,result);
  488.        continue := TRUE;
  489.        WHILE (str_pos < len) AND (continue) DO
  490.           IF add_op(str[str_pos],op) THEN BEGIN
  491.              str_pos := str_pos+1;
  492.              term(str,do_it,result_1);
  493.              IF do_it THEN
  494.                 IF op = '+' THEN
  495.                    result := result+result_1
  496.                 ELSE
  497.                    result := result-result_1
  498.           END
  499.           ELSE
  500.              continue := FALSE; { break }
  501.        IF stat <> OK THEN
  502.           do_error(str)
  503.    END; { VAL_EXPR }
  504.  
  505. PROCEDURE TERM;
  506.    (*
  507.      <term> ::= <factor> { <mulop><factor> }
  508.    *)
  509.    VAR result_1 : REAL;
  510.        continue : BOOLEAN;
  511.        op       : CHAR;
  512.    BEGIN
  513.        factor(str,do_it,FALSE,result);
  514.        continue := TRUE;
  515.        WHILE (str_pos < len) AND (continue) DO
  516.           IF mul_op(str[str_pos],op) THEN BEGIN
  517.              str_pos := str_pos+1;
  518.              factor(str,do_it,FALSE,result_1);
  519.              IF do_it THEN
  520.                 IF op = '*' THEN
  521.                    result := result*result_1
  522.                 ELSE IF result_1 = 0.0 THEN
  523.                    stat := DivBy0
  524.                 ELSE
  525.                    result := result/result_1
  526.           END
  527.           ELSE
  528.              continue := FALSE; { break }
  529.        IF stat <> OK THEN
  530.           do_error(str)
  531.    END; { TERM }
  532.  
  533. PROCEDURE FACTOR;
  534.    {
  535.      <factor> ::= real | <cell ref> | <function call> | (<expr>) |
  536.                   <exponentiation expr> | -<factor>
  537.      <exponentiation expr> ::= <factor><^><factor> }
  538.    VAR old_pos,row,col,temp_len : INTEGER;
  539.        dummy,a_cell             : BOOLEAN;
  540.        func_code                : AllFunctions;
  541.        ptr                      : CellPtr;
  542.    BEGIN
  543.        { the things which come under the initial IF's scope all look for
  544.          character patterns that indicate the start of a factor, a factor
  545.          representing the fundamental data "chunk-size" the evaluator handles.
  546.          And as can be seen from the grammar, all the operands indeed reduce
  547.          to a factor, in one of its forms. In sum, a factor is an entity that
  548.          is meant to be taken as a single number; in 1+2*3, 1,2,3 are factors,
  549.          but 1+2 & 2*3 are NOT, while in 1*(2+3), 1,2,3 are factors but so is
  550.          (2+3). Hence precedence is maintained. However, the
  551.          exponentiation operator has highest precedence, so can't look for it
  552.          in val_expr or term. And since the two operands joined by this op
  553.          are meant to be taken as single numbers, it makes sense to define this
  554.          type of expr as above, and check for the exp. op whenever a factor is
  555.          retrieved. This is done at the end of this proc. Note that expressions
  556.          such as 3^4^5 are perfectly legal and are evaluated right-to-left,
  557.          so that 3 is raised to the 5th power of 4, NOT the the power 20, as
  558.          is the case for (3^4)^5. Last point(!). If a^b is a factor, what
  559.          happens if -a^b? Well, - expects a factor, and since a factor = a^b,
  560.          we erroneously get negation AFTER the exponentiation. So, include
  561.          a boolean to be passed to exponentiation_expr to indicate whether
  562.          factor was called from the unary minus operator, and if so, DON'T
  563.          look for ^. Rather, upon return to unary minus code, the factor is
  564.          negated, and THEN we look for ^. }
  565.  
  566.        IF str_pos > len THEN
  567.           stat := SyntaxErr
  568.        ELSE IF str[str_pos] IN digits+['.'] THEN BEGIN
  569.           strip_num(num_str,str,str_pos,len);
  570.           IF (new_form) OR (cell^.status < Full) THEN
  571.              stat := valid_number(num_str);
  572.           IF (stat = OK) AND (do_it) THEN BEGIN
  573.              result := string_to_real(num_str);
  574.              IF num_str = 'OVERFLOW' THEN
  575.                 stat := Overflow
  576.              ELSE IF str_pos <= len THEN
  577.                 IF str[str_pos] = '%' THEN BEGIN
  578.                    result := result/100;
  579.                    str_pos := str_pos+1
  580.                 END      
  581.           END
  582.           ELSE IF NOT do_it THEN
  583.              IF str_pos <= len THEN
  584.                 IF str[str_pos] = '%' THEN
  585.                    str_pos := str_pos+1
  586.                 ELSE
  587.              ELSE
  588.           ELSE      
  589.        END 
  590.        ELSE IF str_pos < len THEN
  591.           IF str[str_pos] IN up_case+['$'] THEN BEGIN
  592.              a_cell := FALSE;
  593.              IF (str[str_pos] = '$') OR (str[str_pos+1] IN digits+['$']) THEN
  594.                 a_cell := TRUE
  595.              ELSE IF str_pos+1 < len THEN
  596.                 IF (str[str_pos+1] IN up_case) AND
  597.                    (str[str_pos+2] IN digits+['$']) THEN
  598.                    a_cell := TRUE;
  599.              IF a_cell THEN BEGIN
  600.                 stat := translate_cell(str,str_pos,len,row,col,dummy,dummy);
  601.                 IF (stat = OK) AND (do_it) THEN BEGIN
  602.                    ptr := locate_cell(row,col);
  603.                    IF ptr <> NIL THEN
  604.                       WITH ptr^ DO
  605.                          IF class <> Labl THEN BEGIN
  606.                             IF (class = Expr) AND (natural) THEN
  607.                                IF format & pending_mask <> 0 THEN
  608.                                   its_pending
  609.                                ELSE IF format & recalc_mask = 0 THEN BEGIN
  610.                                   evaluate_formula(row,col,force,FALSE,ptr);
  611.                                   IF format & recalc_mask = 0 THEN
  612.                                      its_pending
  613.                                END;
  614.                             IF status = Full THEN
  615.                                result := num
  616.                             ELSE IF status = Empty THEN
  617.                                result := 0
  618.                             ELSE
  619.                                stat := status
  620.                          END
  621.                          ELSE
  622.                             result := 0
  623.                    ELSE
  624.                       result := 0
  625.                 END
  626.                 ELSE
  627.              END
  628.              ELSE BEGIN { function name? }
  629.                 old_pos := str_pos;
  630.                 WHILE (str[str_pos] IN up_case) AND (str_pos < len) DO
  631.                    str_pos := str_pos+1;
  632.                 { when done, str_pos = pos following "name" }
  633.                 temp_len := str_pos-old_pos;
  634.                 IF (temp_len > 7) OR (temp_len < 2) OR
  635.                    (str_pos = len) THEN
  636.                    stat := SyntaxErr
  637.                 ELSE BEGIN
  638.                    temp := COPY(str,old_pos,temp_len);
  639.                    IF find_function(temp,func_code) THEN
  640.                       eval_function(str,do_it,result,func_code )
  641.                    ELSE
  642.                       stat := SyntaxErr
  643.                 END
  644.              END
  645.           END
  646.           ELSE BEGIN
  647.              str_pos := str_pos+1;
  648.              CASE str[str_pos-1] OF
  649.                 '(' : BEGIN
  650.                    { something in parentheses can be a 'full' expression,
  651.                      so we can have things like (1+COS(2*A1))/2 and
  652.                      A1>(A2+A3)*5 }
  653.                    full_expr(str,do_it,result);
  654.                    IF str_pos <= len THEN
  655.                       IF str[str_pos] <> ')' THEN
  656.                          stat := SyntaxErr
  657.                       ELSE
  658.                          str_pos := str_pos+1
  659.                    ELSE
  660.                       stat := SyntaxErr
  661.                 END;
  662.                 '-' : BEGIN
  663.                    { use factor because negation such as -5+3 would result in
  664.                      evaluation as if it were written -(5+3), possible if
  665.                      full_expr was used, giving an addop higher precedence than
  666.                      the negation op. Note that 3^-3 is handled correctly. }
  667.                    factor(str,do_it,TRUE,result);
  668.                    IF do_it THEN
  669.                       result := -result
  670.                 END;
  671.                 OTHERWISE : stat := SyntaxErr
  672.              END { CASE }
  673.           END
  674.        ELSE { str_pos did = len; a number was the only valid possibility }
  675.           stat := SyntaxErr; { and it has already been looked for }
  676.        IF stat <> OK THEN
  677.           do_error(str)
  678.        ELSE
  679.           exponentiation_expr(str,do_it,get_neg,result)
  680.    END; { FACTOR }
  681.  
  682. PROCEDURE EXPONENTIATION_EXPR;
  683.    { <exponentiation expr> ::= <factor>^<factor> }
  684.    { stat guaranteed to be OK; only one call to this, in FACTOR }
  685.    VAR sign               : INTEGER;
  686.        result_1,work_real : REAL;
  687.    BEGIN
  688.        IF NOT get_neg THEN
  689.           IF str_pos < len THEN
  690.              IF str[str_pos] = '^' THEN BEGIN
  691.                 str_pos := str_pos+1;
  692.                 factor(str,do_it,FALSE,result_1);
  693.                 IF do_it THEN
  694.                    IF result = 0.0 THEN { check for crash }
  695.                       stat := Undefined
  696.                    ELSE IF result < 0.0 THEN BEGIN
  697.                       IF fraction(result_1,str) <> 0.0 THEN
  698.                          stat := Undefined  { can't do -2^8.5; what would }
  699.                       ELSE BEGIN            { the sign be? }
  700.                          IF odd_real(result_1,str) THEN
  701.                             sign := -1
  702.                          ELSE
  703.                             sign := 1;
  704.                          IF check_exp(result_1*my_ln(ABS(result))) THEN
  705.                             result := sign*my_exp(result_1*my_ln(ABS(result)))
  706.                          ELSE
  707.                             stat := Overflow
  708.                       END
  709.                    END
  710.                    ELSE IF check_exp(result_1*my_ln(result)) THEN
  711.                       result := my_exp(result_1*my_ln(result))
  712.                    ELSE
  713.                       stat := Overflow
  714.              END;
  715.        IF stat <> OK THEN
  716.           do_error(str)
  717.    END; { EXPONENTIATION_EXPR }
  718.  
  719. PROCEDURE EVAL_FUNCTION;
  720.    BEGIN
  721.        IF str_pos > len THEN
  722.           stat := SyntaxErr
  723.        ELSE IF str[str_pos] <> '(' THEN
  724.           stat := SyntaxErr
  725.        ELSE BEGIN
  726.           str_pos := str_pos+1;
  727.           IF func_code IN Single THEN
  728.              do_single(str,do_it,result,func_code)
  729.           ELSE IF func_code IN Double THEN
  730.              do_double(str,do_it,result,func_code)
  731.           ELSE IF func_code IN Multiple THEN
  732.              do_multiple(str,do_it,result,func_code)
  733.           ELSE IF func_code IN Aggregate THEN
  734.              do_aggregate(str,do_it,result,func_code)
  735.           ELSE IF func_code IN Financial THEN
  736.              do_financial(str,do_it,result,func_code)
  737.           ELSE IF func_code IN LookUp THEN
  738.              do_lookup(str,do_it,result,func_code)
  739.           ELSE IF func_code = IfOp THEN
  740.              if_expr(str,do_it,result);
  741.           IF str_pos > len THEN
  742.              stat := SyntaxErr
  743.           ELSE IF str[str_pos] <> ')' THEN
  744.              stat := SyntaxErr
  745.           ELSE
  746.              str_pos := str_pos+1
  747.        END;
  748.        IF stat <> OK THEN
  749.           do_error(str)
  750.    END; { EVAL_FUNCTION }
  751.  
  752. (**************************************************************************)
  753. (* Single/No Argument Functions: Transcendental, Conversion, Factorial... *)
  754. (**************************************************************************)
  755.  
  756. PROCEDURE DO_SINGLE;
  757.    { simple_function ::= <functname()> | <functname(fullexpr)> }
  758.    VAR i,limit     : INTEGER;
  759.        mag_num,temp : REAL;
  760.    BEGIN
  761.        (*********************************************)
  762.        (* functions with no arguments; result = f() *)
  763.        (*********************************************)
  764.        IF func_code = PiOp THEN
  765.           IF do_it THEN
  766.              result := pi
  767.           ELSE
  768.        (*************************************************)
  769.        (* functions with single argument; result = f(x) *)
  770.        (*************************************************)
  771.        ELSE BEGIN
  772.           full_expr(str,do_it,result);
  773.           IF do_it THEN BEGIN
  774.              mag_num := ABS(result);
  775.              CASE func_code OF
  776.                 (***************************)
  777.                 (* transfer-like functions *)
  778.                 (***************************)
  779.                 AbsOp :
  780.                    result := mag_num;
  781.                 DegOp :
  782.                    result := result*DegPerRad;
  783.                 RadOp :
  784.                    result := result/DegPerRad;
  785.                 (******************)
  786.                 (* trig functions *)
  787.                 (******************)
  788.                 SinOp :
  789.                    result := SIN(result);
  790.                 CosOp :
  791.                    result := COS(result);
  792.                 TanOp :
  793.                    IF COS(result) <> 0 THEN { best to use Pascal rather  }
  794.                                             { than magnum<>halfpi; avoid }
  795.                       result := SIN(result)/COS(result) { roundoff error }
  796.                    ELSE
  797.                       stat := Undefined;
  798.                 AsinOp :
  799.                    IF (mag_num > 1) OR
  800.                       ((result <> 0) AND (mag_num < MinSquare)) THEN
  801.                       stat := Undefined
  802.                    ELSE IF mag_num = 1 THEN
  803.                       result := HalfPi*result
  804.                    ELSE
  805.                       result := ArcTan(result/SQRT(1-result*result));
  806.                 ACosOp :
  807.                    IF (mag_num > 1) OR
  808.                       ((result <> 0) AND (mag_num < MinSquare)) THEN
  809.                       stat := Undefined
  810.                    ELSE IF mag_num = 1 THEN
  811.                       result := 0
  812.                    ELSE
  813.                       result := -ArcTan(result/SQRT(1-result*result))+
  814.                                  HalfPi;
  815.                 AtanOp :
  816.                    result := ArcTan(result);
  817.                 (*******************)
  818.                 (* power functions *)
  819.                 (*******************)
  820.                 LogOp :
  821.                    IF result > 0 THEN
  822.                       result := my_ln(result)/ln10
  823.                    ELSE
  824.                       stat := Undefined;
  825.                 LnOp  :
  826.                    IF result > 0 THEN
  827.                       result := my_ln(result)
  828.                    ELSE
  829.                       stat := Undefined;
  830.                 ExpOp :
  831.                    IF check_exp(result) THEN
  832.                       result := my_exp(result)
  833.                    ELSE
  834.                       stat := Overflow;
  835.                 SqrOp :
  836.                    IF NOT check_square(mag_num) THEN
  837.                       stat := Overflow
  838.                    ELSE
  839.                       result := SQR(result);
  840.                 SqrtOp :
  841.                    IF result >= 0 THEN
  842.                       result := SQRT(result)
  843.                    ELSE
  844.                       stat := Undefined;
  845.                 (*****************)
  846.                 (* miscellaneous *)
  847.                 (*****************)
  848.                 FacOp :
  849.                    IF result > 33 THEN
  850.                       stat := Overflow
  851.                    ELSE IF result < 0 THEN
  852.                       stat := Undefined
  853.                    ELSE IF result <> ROUND(result) THEN
  854.                       stat := Undefined { we don't do gamma functions }
  855.                    ELSE BEGIN
  856.                       limit := ROUND(result);
  857.                       temp := 1;
  858.                       FOR i := 2 TO limit DO
  859.                           temp := temp*i;
  860.                       result := temp
  861.                    END;
  862.                 NotOp :
  863.                    IF result = 0 THEN
  864.                       result := 1
  865.                    ELSE
  866.                       result := 0
  867.              END { CASE }
  868.           END { IF do_it }
  869.        END; { ELSE; func_code <> pi }
  870.    END; { DO_SINGLE }
  871.  
  872. (***********************************************)
  873. (* Functions with 2 arguments                  *)
  874. (* <funct> ::= funcname(<fullexpr>,<fullexpr>) *)
  875. (***********************************************)
  876.  
  877. PROCEDURE DO_DOUBLE;
  878.    VAR rmag2                    : INTEGER;
  879.        temp,arg1,arg2,mag1,mag2 : REAL;
  880.    BEGIN
  881.        full_expr(str,do_it,arg1);
  882.        IF str_pos < len THEN
  883.           IF str[str_pos] <> ',' THEN
  884.              stat := SyntaxErr
  885.           ELSE BEGIN
  886.              str_pos := str_pos+1;
  887.              full_expr(str,do_it,arg2);
  888.              IF do_it THEN BEGIN
  889.                 mag1 := ABS(arg1);
  890.                 mag2 := ABS(arg2);
  891.                 CASE func_code OF
  892.                    DivOp : { integer division }
  893.                       IF arg2 = 0 THEN
  894.                          stat := DivBy0
  895.                       ELSE IF (mag1 > Long_Maxint) OR (mag2 > Long_Maxint) THEN
  896.                          stat := Overflow
  897.                       ELSE
  898.                          result := LONG_TRUNC(arg1) DIV LONG_TRUNC(arg2);
  899.                    ModOp : { REAL modulo function }
  900.                       IF arg2 = 0 THEN
  901.                          stat := DivBy0
  902.                       ELSE IF mag1/mag2 > Long_Maxint THEN
  903.                          stat := Overflow
  904.                       ELSE
  905.                          result := arg1-LONG_TRUNC(arg1/arg2)*arg2;
  906.                    RoundOp,TruncOp :
  907.                       IF mag2 > 10 THEN
  908.                          stat := Overflow
  909.                       ELSE BEGIN
  910.                          rmag2 := ROUND(mag2);
  911.                          IF arg2 > 0 THEN
  912.                             temp := arg1*PwrOfTen(rmag2)
  913.                          ELSE
  914.                             temp := arg1/PwrOfTen(rmag2);
  915.                          IF ABS(temp) > Long_Maxint THEN
  916.                             stat := Overflow
  917.                          ELSE IF arg2 > 0 THEN
  918.                             IF func_code = RoundOp THEN
  919.                                result := LONG_ROUND(temp)/PwrOfTen(rmag2)
  920.                             ELSE
  921.                                result := LONG_TRUNC(temp)/PwrOfTen(rmag2)
  922.                          ELSE IF func_code = RoundOp THEN
  923.                             result := LONG_ROUND(temp)*PwrOfTen(rmag2)
  924.                          ELSE
  925.                             result := LONG_TRUNC(temp)*PwrOfTen(rmag2)
  926.                       END;
  927.                       RandOp : BEGIN
  928.                         result := ABS(Random_Number/16777215.0);
  929.                         IF ABS(result*(arg2-arg1+1)) > Long_Maxint THEN
  930.                            stat := Overflow
  931.                         ELSE
  932.                            result := arg1+result*(arg2-arg1);
  933.                       END
  934.                 END { CASE }
  935.              END { IF do_it }
  936.           END { ELSE }
  937.        ELSE
  938.           stat := SyntaxErr;
  939.        IF stat <> OK THEN
  940.           do_error(str)
  941.    END; { DO_DOUBLE }
  942.  
  943. PROCEDURE DO_MULTIPLE;
  944.    VAR count,i : INTEGER;
  945.        quit    : BOOLEAN;
  946.        args    : ARRAY [1..20] OF REAL;
  947.    BEGIN
  948.        quit := FALSE;
  949.        count := 1;
  950.        full_expr(str,do_it,args[count]);
  951.        IF str_pos < len THEN
  952.           IF str[str_pos] <> ',' THEN
  953.              stat := SyntaxErr
  954.           ELSE BEGIN
  955.              WHILE (str_pos < len) AND (NOT quit) AND (stat = OK) DO
  956.                 IF str[str_pos] = ',' THEN BEGIN
  957.                    str_pos := str_pos+1;
  958.                    count := count+1;
  959.                    full_expr(str,do_it,args[count])
  960.                 END
  961.                 ELSE IF str_pos > len THEN
  962.                    stat := SyntaxErr
  963.                 ELSE
  964.                    quit := TRUE;
  965.              IF (stat = OK) AND (do_it) THEN
  966.                 IF func_code = AndOp THEN BEGIN
  967.                    result := 1;
  968.                    FOR i := 1 TO count DO
  969.                        IF args[i] = 0 THEN
  970.                           result := 0
  971.                        ELSE
  972.                 END
  973.                 ELSE IF func_code = OrOp THEN BEGIN
  974.                    result := 0;
  975.                    FOR i := 1 TO count DO
  976.                        IF args[i] <> 0 THEN
  977.                           result := 1
  978.                        ELSE
  979.                 END
  980.           END
  981.        ELSE
  982.           stat := SyntaxErr;
  983.        IF stat <> OK THEN
  984.           do_error(str)
  985.    END; { DO_MULTIPLE }
  986.  
  987. (*************************************************************)
  988. (* Aggregate/Statistical Functions; main routine is DO_STATS *)
  989. (*************************************************************)
  990.  
  991. PROCEDURE DO_MAX_MIN ( s_r,s_c,e_r,e_c : INTEGER;
  992.                        VAR str         : LorFstr;
  993.                        VAR result      : REAL;
  994.                        func_code       : AllFunctions );
  995.    VAR i,j        : INTEGER;
  996.        found,quit : BOOLEAN;
  997.        a          : AssignedStatus;
  998.        ptr,dummy  : CellPtr;
  999.    BEGIN
  1000.        found := FALSE;
  1001.        i := s_r;
  1002.        { first get a value within the range }
  1003.        WHILE (i <= e_r) AND (NOT found) DO BEGIN
  1004.           ptr := data[i];
  1005.           WHILE (ptr <> NIL) AND (NOT found) DO BEGIN
  1006.              IF (ptr^.c >= s_c) AND (ptr^.c <= e_c) THEN BEGIN
  1007.                 a := assigned(i,ptr^.c,dummy);
  1008.                 IF a = Value THEN BEGIN
  1009.                    result := ptr^.num;
  1010.                    found := TRUE
  1011.                 END
  1012.              END;
  1013.              ptr := ptr^.next
  1014.           END;
  1015.           i := i+1;
  1016.        END;
  1017.        IF NOT found THEN { no value in range }
  1018.           stat := GenError
  1019.        ELSE
  1020.           FOR i := s_r TO e_r DO BEGIN
  1021.               quit := FALSE;
  1022.               ptr := data[i];
  1023.               WHILE (ptr <> NIL) AND (NOT (quit)) DO BEGIN
  1024.                  IF (ptr^.c >= s_c) AND (ptr^.c <= e_c) THEN BEGIN
  1025.                     a := assigned(i,ptr^.c,dummy);
  1026.                     IF a = Value THEN
  1027.                        IF func_code = MaxOp THEN
  1028.                           IF ptr^.num > result THEN
  1029.                              result := ptr^.num
  1030.                           ELSE
  1031.                        ELSE { MinOp }
  1032.                           IF ptr^.num < result THEN
  1033.                              result := ptr^.num
  1034.                  END
  1035.                  ELSE IF ptr^.c > e_c THEN
  1036.                     quit := TRUE;
  1037.                  ptr := ptr^.next
  1038.               END
  1039.           END;
  1040.        IF stat <> OK THEN
  1041.           do_error(str)
  1042.    END; { DO_MAX_MIN }
  1043.  
  1044. PROCEDURE DO_SUM_AND_MULT ( s_r,s_c,e_r,e_c : INTEGER;
  1045.                             VAR str         : LorFstr;
  1046.                             VAR result      : REAL;
  1047.                             VAR count       : INTEGER;
  1048.                             action          : SumSqrProd );
  1049.    { returns the _____ of cells with AssignedStatus = Value within a range:
  1050.          1. SUM (Sum) , 2. SUM of SQUARES (SumSquares), 3. PRODUCT (Product). }
  1051.    VAR i         : INTEGER;
  1052.        quit      : BOOLEAN;
  1053.        a         : AssignedStatus;
  1054.        ptr,dummy : CellPtr;
  1055.    BEGIN
  1056.        IF action = Product THEN
  1057.           result := 1
  1058.        ELSE
  1059.           result := 0;
  1060.        count := 0;
  1061.        i := s_r;
  1062.        WHILE (i <= e_r) AND (stat = OK) DO BEGIN
  1063.           quit := FALSE;
  1064.           ptr := data[i];
  1065.           WHILE (ptr <> NIL) AND (NOT quit) DO BEGIN
  1066.              IF (ptr^.c >= s_c) AND (ptr^.c <= e_c) THEN BEGIN
  1067.                 a := assigned(i,ptr^.c,dummy);
  1068.                 IF a = Value THEN BEGIN
  1069.                    count := count+1;
  1070.                    IF action = Product THEN
  1071.                       result := result*ptr^.num
  1072.                    ELSE IF action = Sum THEN
  1073.                       result := result+ptr^.num
  1074.                    ELSE IF check_square(ptr^.num) THEN
  1075.                       result := result+SQR(ptr^.num)
  1076.                    ELSE
  1077.                       stat := Overflow
  1078.                 END
  1079.                 ELSE IF a = Error THEN
  1080.                    stat := ptr^.status
  1081.              END
  1082.              ELSE IF ptr^.c > e_c THEN
  1083.                 quit := TRUE;
  1084.              ptr := ptr^.next
  1085.           END;
  1086.           i := i+1
  1087.        END;
  1088.        IF stat <> OK THEN
  1089.           do_error(str)
  1090.    END; { DO_SUM_AND_MULT }
  1091.  
  1092. PROCEDURE DO_REGRESSION ( ys_r,ys_c,ye_r,ye_c : INTEGER;
  1093.                           VAR str             : LorFstr;
  1094.                           do_it               : BOOLEAN;
  1095.                           VAR result          : REAL;
  1096.                           func_code           : AllFunctions );
  1097.    { Note: the arrays needn't be adjacent, oriented in the same direction, or
  1098.            even linear in shape; however, they must both contain the same
  1099.            number of Value = AssignedStatus, and its the users duty to ensure
  1100.            that the correspondence between items is what he wants. Sums are
  1101.            done in ROW-MAJOR order, so for arrays spanning > 1 column:
  1102.                A   B |  C   D
  1103.            1   1   5 |  10  14
  1104.            2   2   6 |  11  15
  1105.            3   3   7 |  12  16
  1106.            4   4   8 |  13  17
  1107.  
  1108.            A1 relates to C1, B2 relates to D2, etc. if called as
  1109.            func(A1:B4,C1:D4). Thus have to use an iterative method to traverse
  1110.            range, rather than a simple list traversal, to make the routine
  1111.            reasonable }
  1112.    VAR i,j,xs_r,xs_c,xe_r,xe_c,y_n,x_n,n    : INTEGER;
  1113.        y_sum,y_sumsqr,x_sum,x_sumsqr,xy_sum,
  1114.        denom,slope,y_int,predict_arg        : REAL;
  1115.        ptr                                  : CellPtr;
  1116.    PROCEDURE DO_XYSUM ( VAR xy_sum : REAL );
  1117.       { guaranteed to be = # values in y and x arrays; use both y_done & x_done
  1118.         even though they both must be out of data at the same time, in order
  1119.         to clarify things. So, user can have arrays where there isn't explicit
  1120.         1-1 coorespondence between items; matching of items is on a
  1121.         column-major basis }
  1122.       VAR y_r,y_c,x_r,x_c,y_row,y_col,x_row,x_col : INTEGER;
  1123.           y_done,x_done,y_found,x_found           : BOOLEAN;
  1124.           ptrx,ptry                               : CellPtr;
  1125.       BEGIN
  1126.           xy_sum := 0;
  1127.           y_done := FALSE;
  1128.           x_done := FALSE;
  1129.           y_r := ys_r;
  1130.           y_c := ys_c;
  1131.           x_r := xs_r;
  1132.           x_c := xs_c;
  1133.           REPEAT
  1134.              y_found := FALSE;
  1135.              x_found := FALSE;
  1136.              { get a y-value }
  1137.              WHILE (NOT y_found) AND (NOT y_done) DO BEGIN
  1138.                 IF assigned(y_r,y_c,ptry) = Value THEN BEGIN
  1139.                    y_found := TRUE;
  1140.                    y_row := y_r;
  1141.                    y_col := y_c;
  1142.                 END;
  1143.                 IF y_r = ye_r THEN BEGIN { last row? }
  1144.                    y_r := ys_r;          { make it first row }
  1145.                    IF y_c = ye_c THEN    { last col? }
  1146.                       y_done := TRUE     { we're through }
  1147.                    ELSE
  1148.                       y_c := y_c+1       { no we're not! }
  1149.                 END
  1150.                 ELSE
  1151.                    y_r := y_r+1          { down a row }
  1152.              END;
  1153.              { go for x-value }
  1154.              WHILE (NOT x_found) AND (NOT x_done) DO BEGIN
  1155.                 IF assigned(x_r,x_c,ptrx) = Value THEN BEGIN
  1156.                    x_found := TRUE;
  1157.                    x_row := x_r;
  1158.                    x_col := x_c;
  1159.                 END;
  1160.                 IF x_r = xe_r THEN BEGIN
  1161.                    x_r := xs_r;
  1162.                    IF x_c = xe_c THEN
  1163.                       x_done := TRUE
  1164.                    ELSE
  1165.                       x_c := x_c+1
  1166.                 END
  1167.                 ELSE
  1168.                    x_r := x_r+1
  1169.              END;
  1170.              IF (y_found) AND (x_found) THEN
  1171.                 xy_sum := xy_sum+ptry^.num*ptrx^.num
  1172.           UNTIL (y_done) AND (x_done)
  1173.       END; { DO_XYSUM }
  1174.    BEGIN { DO_REGRESSION }
  1175.        IF str_pos < len THEN
  1176.           IF str[str_pos] <> ',' THEN
  1177.              stat := SyntaxErr
  1178.           ELSE BEGIN
  1179.              str_pos := str_pos+1;
  1180.              get_range(str,do_it,xs_r,xs_c,xe_r,xe_c);
  1181.              IF func_code = PredVOp THEN
  1182.                 IF str_pos < len THEN
  1183.                    IF str[str_pos] <> ',' THEN
  1184.                       stat := SyntaxErr
  1185.                    ELSE BEGIN
  1186.                       str_pos := str_pos+1;
  1187.                       full_expr(str,do_it,predict_arg);
  1188.                    END
  1189.                 ELSE
  1190.                    stat := SyntaxErr;
  1191.              IF stat = OK THEN BEGIN
  1192.                 do_sum_and_mult(ys_r,ys_c,ye_r,ye_c,str,y_sum,y_n,Sum);
  1193.                 do_sum_and_mult(xs_r,xs_c,xe_r,xe_c,str,x_sum,x_n,Sum);
  1194.                 IF NOT check_square(x_sum) THEN
  1195.                    stat := Overflow
  1196.                 ELSE IF (y_n <> x_n) OR (y_n < 2) THEN
  1197.                    stat := Undefined
  1198.                 ELSE BEGIN
  1199.                    n := y_n;
  1200.                    do_sum_and_mult(ys_r,ys_c,ye_r,ye_c,str,
  1201.                                    y_sumsqr,n,SumSquares);
  1202.                    do_sum_and_mult(xs_r,xs_c,xe_r,xe_c,str,
  1203.                                    x_sumsqr,n,SumSquares);
  1204.                    do_xysum(xy_sum);
  1205.                    IF (func_code = LinROp) OR
  1206.                       (func_code = PredVOp) THEN BEGIN
  1207.                       denom := n*x_sumsqr-SQR(x_sum);
  1208.                       IF denom = 0 THEN
  1209.                          stat := DivBy0
  1210.                       ELSE BEGIN
  1211.                          slope := (n*xy_sum-x_sum*y_sum)/denom;
  1212.                          y_int := (y_sum*x_sumsqr-x_sum*xy_sum)/denom;
  1213.                          IF func_code = PredVOp THEN
  1214.                             result := slope*predict_arg+y_int { y = mx+b }
  1215.                          ELSE BEGIN
  1216.                             result := slope;
  1217.                             IF col < n_cols THEN BEGIN
  1218.                                delete_cell(row,col+1,FALSE);
  1219.                                ptr := new_cell(row,col+1);
  1220.                                ptr^.num := y_int;
  1221.                                ptr^.status := Full;
  1222.                                cell_on_screen(1,row,col+1,TRUE)
  1223.                             END
  1224.                          END
  1225.                       END
  1226.                    END
  1227.                    ELSE IF NOT check_square(y_sum) THEN
  1228.                       stat := Overflow
  1229.                    ELSE BEGIN { CorrOp }
  1230.                       denom := (x_sumsqr-n*SQR(x_sum/n)) *
  1231.                                (y_sumsqr-n*SQR(y_sum/n));
  1232.                       IF denom = 0 THEN
  1233.                          stat := DivBy0
  1234.                       ELSE IF denom < 0 THEN
  1235.                          stat := Undefined
  1236.                       ELSE BEGIN
  1237.                          denom := SQRT(denom);
  1238.                          result := (xy_sum-n*x_sum/n*y_sum/n)/denom
  1239.                       END
  1240.                    END
  1241.                 END
  1242.              END
  1243.           END
  1244.        ELSE
  1245.           stat := SyntaxErr;
  1246.        IF stat <> OK THEN
  1247.           do_error(str)
  1248.    END; { DO_REGRESSION }
  1249.  
  1250. PROCEDURE DO_STATS ( s_r,s_c,e_r,e_c : INTEGER;
  1251.                      VAR str         : LorFstr;
  1252.                      do_it           : BOOLEAN;
  1253.                      VAR result      : REAL;
  1254.                      func_code       : AllFunctions );
  1255.    VAR i,j,count : INTEGER;
  1256.        result_1  : REAL;
  1257.    BEGIN
  1258.        CASE func_code OF
  1259.           (**************************************)
  1260.           (* Arithmetic aggregate functions     *)
  1261.           (* <arith> ::= funcname(<cellrange>)  *)
  1262.           (**************************************)
  1263.           SumOp,MeanOp : BEGIN
  1264.              do_sum_and_mult(s_r,s_c,e_r,e_c,str,result,count,Sum);
  1265.              IF func_code = MeanOp THEN
  1266.                 IF count = 0 THEN
  1267.                    stat := DivBy0
  1268.                 ELSE
  1269.                    result := result/count
  1270.           END;
  1271.           ProdOp : BEGIN
  1272.              do_sum_and_mult(s_r,s_c,e_r,e_c,str,result,count,Product);
  1273.              IF count = 0 THEN
  1274.                 result := 0
  1275.           END;
  1276.           (****************************************)
  1277.           (* Sample Statistics ( NOT population ) *)
  1278.           (* <stat> ::= funcname(<cellrange>)     *)
  1279.           (****************************************)
  1280.           VarOp,SdevOp,SerrOp : BEGIN
  1281.              do_sum_and_mult(s_r,s_c,e_r,e_c,str,result,count,Sum);
  1282.              IF count < 2 THEN
  1283.                 stat := Undefined
  1284.              ELSE IF NOT check_square(result) THEN
  1285.                 stat := Overflow
  1286.              ELSE BEGIN
  1287.                 do_sum_and_mult(s_r,s_c,e_r,e_c,str,result_1,count,SumSquares);
  1288.                 IF count*result_1-SQR(result) < 0 THEN
  1289.                    stat := Undefined
  1290.                 ELSE BEGIN
  1291.                    result := SQRT(
  1292.                                    (count*result_1-SQR(result)) /
  1293.                                    (count*(count-1))
  1294.                                  );
  1295.                    IF func_code = VarOp THEN
  1296.                       IF check_square(result) THEN
  1297.                          result := SQR(result)
  1298.                       ELSE
  1299.                          stat := Overflow
  1300.                    ELSE IF func_code = SerrOp THEN
  1301.                       result := result/SQRT(count)
  1302.                 END
  1303.              END
  1304.           END;
  1305.           (****************************************************************)
  1306.           (* Linear Regression functions                                  *)
  1307.           (* <Linreg> & <Corr> ::= funcname(<y-cellrange>,<x-cellrange>)  *)
  1308.           (* <Trend> ::= funcname(<y-cellrange>,<x-cellrange>,<fullexpr>) *)
  1309.           (****************************************************************)
  1310.           LinROp,PredVOp,CorrOp :
  1311.              do_regression(s_r,s_c,e_r,e_c,str,do_it,result,func_code);
  1312.        END; { CASE }
  1313.        IF stat <> OK THEN
  1314.           do_error(str)
  1315.    END; { DO_STATS }
  1316.  
  1317. PROCEDURE DO_AGGREGATE;
  1318.    VAR s_r,s_c,e_r,e_c,i,j : INTEGER;
  1319.        quit                : BOOLEAN;
  1320.        ptr,dummy           : CellPtr;
  1321.    BEGIN
  1322.        { checks for str_pos > len }
  1323.        get_range(str,do_it,s_r,s_c,e_r,e_c);
  1324.        { if returns, stat = ok }
  1325.        IF do_it THEN
  1326.           CASE func_code OF
  1327.              CountOp : BEGIN
  1328.                 result := 0;
  1329.                 FOR i := s_r TO e_r DO BEGIN
  1330.                     quit := FALSE;
  1331.                     ptr := data[i];
  1332.                     WHILE (ptr <> NIL) AND (NOT quit) DO BEGIN
  1333.                        IF (ptr^.c >= s_c) AND (ptr^.c <= e_c) THEN
  1334.                           IF assigned(i,ptr^.c,dummy) = Value THEN
  1335.                              result := result+1
  1336.                           ELSE
  1337.                        ELSE IF ptr^.c > e_c THEN
  1338.                           quit := TRUE;
  1339.                        ptr := ptr^.next
  1340.                     END;
  1341.                 END
  1342.              END;
  1343.              MaxOp,
  1344.              MinOp :
  1345.                 do_max_min(s_r,s_c,e_r,e_c,str,result,func_code);
  1346.              SumOp,
  1347.              MeanOp,
  1348.              ProdOp,
  1349.              VarOp,
  1350.              SdevOp,
  1351.              SerrOp,
  1352.              LinROp,
  1353.              CorrOp,
  1354.              PredVOp :
  1355.                 do_stats(s_r,s_c,e_r,e_c,str,do_it,result,func_code)
  1356.  
  1357.           END { CASE }
  1358.        ELSE IF func_code IN [LinROp..PredVOp] THEN { additional args }
  1359.           IF str_pos < len THEN
  1360.              IF str[str_pos] <> ',' THEN
  1361.                 stat := SyntaxErr
  1362.              ELSE BEGIN
  1363.                 str_pos := str_pos+1;
  1364.                 get_range(str,do_it,s_r,s_c,e_r,e_c);
  1365.                 IF func_code = PredVOp THEN
  1366.                    IF str_pos < len THEN
  1367.                       IF str[str_pos] <> ',' THEN
  1368.                          stat := SyntaxErr
  1369.                       ELSE BEGIN
  1370.                          str_pos := str_pos+1;
  1371.                          full_expr(str,do_it,result)
  1372.                       END
  1373.                    ELSE
  1374.                       stat := SyntaxErr
  1375.              END
  1376.           ELSE
  1377.              stat := SyntaxErr;
  1378.        IF stat <> OK THEN
  1379.           do_error(str)
  1380.    END; { DO_AGGREGATE }
  1381.  
  1382. PROCEDURE DO_FINANCIAL;
  1383.    TYPE
  1384.         Parms    = RECORD
  1385.                       parm    : REAL;
  1386.                       present : BOOLEAN
  1387.                    END;     
  1388.         ArgArray = ARRAY [1..6] OF Parms;
  1389.    VAR 
  1390.         i    : INTEGER;
  1391.         cont : BOOLEAN;  
  1392.         arg  : ArgArray;
  1393.    FUNCTION POWER ( a,y : REAL ) : REAL;
  1394.       { efficiently and more accurately then e^xlny calc an integer power;
  1395.         used by the Financial functions PV, FV, PMT, NPER }
  1396.       VAR n   : LONG_INTEGER;
  1397.           b,c : REAL; 
  1398.       BEGIN
  1399.           IF ABS(y) >= Long_MaxInt THEN
  1400.              stat := Overflow
  1401.           ELSE BEGIN
  1402.              n := ABS(LONG_ROUND(y));
  1403.              b := 1;
  1404.              c := a;
  1405.              WHILE n <> 0 DO BEGIN
  1406.                 IF n & 1 <> 0 THEN
  1407.                    b := b*c;
  1408.                 IF check_square(c) THEN   
  1409.                    c := SQR(c)
  1410.                 ELSE BEGIN
  1411.                    stat := Overflow;
  1412.                    do_error(str)
  1413.                 END;      
  1414.                 n := ShR(n,1)
  1415.              END;
  1416.              IF y >= 0 THEN
  1417.                 power := b
  1418.              ELSE
  1419.                 power := 1/b   
  1420.           END;
  1421.           IF stat <> OK THEN
  1422.              do_error(str)
  1423.       END; { POWER }       
  1424.    PROCEDURE EVAL;
  1425.       VAR temp,rate : REAL;
  1426.       BEGIN
  1427.           rate := 1+arg[1].parm;
  1428.           CASE func_code OF
  1429.              PvOp : { ( rate , nper , rent , fv , type ) }
  1430.                 IF (NOT arg[1].present) OR (NOT arg[2].present) THEN
  1431.                    stat := SyntaxErr
  1432.                 ELSE IF arg[1].parm <= 0 THEN
  1433.                    stat := Undefined
  1434.                 ELSE IF arg[3].present THEN { annuity }
  1435.                    IF arg[4].present THEN
  1436.                       stat := SyntaxErr
  1437.                    ELSE BEGIN
  1438.                       { ordinary annuity by default }
  1439.                       result := arg[3].parm*(1-power(rate,
  1440.                                    -arg[2].parm))/arg[1].parm;
  1441.                       IF arg[5].present THEN 
  1442.                          IF arg[5].parm < 1 THEN { annuity due }
  1443.                             result := arg[3].parm*((1-power(rate,
  1444.                                          1-arg[2].parm))/arg[1].parm+1)
  1445.                    END
  1446.                 ELSE IF arg[4].present THEN { compound interest }
  1447.                    IF arg[5].present THEN { type is meaningless }
  1448.                       stat := SyntaxErr
  1449.                    ELSE
  1450.                       result := arg[4].parm/power(rate,arg[2].parm)
  1451.                 ELSE
  1452.                    stat := SyntaxErr;
  1453.              { end of PvOp }
  1454.              FvOp : { ( rate , nper , rent , fv , type ) }
  1455.                 IF (NOT arg[1].present) OR (NOT arg[2].present) THEN
  1456.                    stat := SyntaxErr
  1457.                 ELSE IF arg[1].parm <= 0 THEN
  1458.                    stat := Undefined
  1459.                 ELSE IF arg[3].present THEN { annuity }
  1460.                    IF arg[4].present THEN
  1461.                       stat := SyntaxErr
  1462.                    ELSE BEGIN
  1463.                       { ordinary annuity by default }
  1464.                       result := arg[3].parm*
  1465.                                  (power(rate,arg[2].parm)-1)/arg[1].parm;
  1466.                       IF arg[5].present THEN 
  1467.                          IF arg[5].parm < 1 THEN { annuity due }
  1468.                             result := arg[3].parm*((power(rate,
  1469.                                           arg[2].parm+1)-1)/arg[1].parm-1)
  1470.                    END
  1471.                 ELSE IF arg[4].present THEN { compound interest }
  1472.                    IF arg[5].present THEN { type is meaningless }
  1473.                       stat := SyntaxErr
  1474.                    ELSE
  1475.                       result := arg[4].parm*power(rate,arg[2].parm)
  1476.                 ELSE
  1477.                    stat := SyntaxErr;
  1478.              { end of FvOp } 
  1479.              NperOp : BEGIN { ( rate , pmt , pv , fv , type ) }
  1480.                 IF (NOT arg[1].present) OR
  1481.                    ((NOT arg[2].present) AND (arg[5].present)) THEN 
  1482.                    stat := SyntaxErr
  1483.                 ELSE IF (arg[1].parm <= 0) OR 
  1484.                         ((arg[2].present) AND (arg[2].parm = 0)) THEN
  1485.                    stat := Undefined
  1486.                 ELSE IF (arg[3].present) AND (arg[4].present) THEN
  1487.                    { nper to get from pv to fv, i.e. compound interest }
  1488.                    IF (arg[2].present) OR (arg[5].present) THEN
  1489.                       stat := SyntaxErr
  1490.                    ELSE IF arg[3].parm = 0 THEN
  1491.                       stat := Undefined
  1492.                    ELSE IF arg[4].parm/arg[3].parm <= 0 THEN
  1493.                       stat := Undefined
  1494.                    ELSE
  1495.                       result := my_ln(arg[4].parm/arg[3].parm)/my_ln(rate)
  1496.                 ELSE IF arg[2].present THEN { annuity }
  1497.                    IF arg[3].present THEN { present value }
  1498.                       IF (NOT arg[5].present) OR { default is ordinary }
  1499.                          ((arg[5].present) AND (arg[5].parm > 0)) THEN BEGIN
  1500.                          temp := arg[3].parm*arg[1].parm/arg[2].parm;
  1501.                          IF temp >= 1 THEN
  1502.                             stat := Undefined
  1503.                          ELSE
  1504.                             result := -my_ln(1-temp)/my_ln(rate)
  1505.                       END
  1506.                       ELSE BEGIN { annuity due }
  1507.                          temp := arg[1].parm*(arg[3].parm/arg[2].parm-1);
  1508.                          IF temp >= 1 THEN
  1509.                             stat := SyntaxErr
  1510.                          ELSE
  1511.                             result := 1-my_ln(1-temp)/my_ln(rate)
  1512.                       END   
  1513.                    ELSE IF arg[4].present THEN { future value }
  1514.                       { ordinary by default }
  1515.                       IF (NOT arg[5].present) OR 
  1516.                          ((arg[5].present) AND (arg[5].parm > 0)) THEN BEGIN
  1517.                          temp := arg[4].parm*arg[1].parm/arg[2].parm;
  1518.                          IF temp <= -1 THEN
  1519.                             stat := Undefined
  1520.                          ELSE
  1521.                             result := my_ln(temp+1)/my_ln(rate)
  1522.                       END
  1523.                       ELSE BEGIN { annuity due }
  1524.                          temp := arg[1].parm*(arg[4].parm/arg[2].parm+1);
  1525.                          IF temp <= -1 THEN
  1526.                             stat := Undefined
  1527.                          ELSE
  1528.                             result := my_ln(temp+1)/my_ln(rate)-1
  1529.                       END      
  1530.                    ELSE
  1531.                       stat := SyntaxErr
  1532.                 ELSE
  1533.                    stat := SyntaxErr;
  1534.                 IF stat = OK THEN
  1535.                    IF ABS(result) <= Long_MaxInt THEN
  1536.                       result := LONG_ROUND(result)   
  1537.              END;{ CASE NperOp }
  1538.              PmtOp : { ( rate , nper , pv , fv , type ) }
  1539.                 IF (NOT arg[1].present) OR (NOT arg[2].present) OR
  1540.                    ((arg[3].present) AND (arg[4].present)) THEN
  1541.                    stat := SyntaxErr
  1542.                 ELSE IF arg[1].parm <= 0 THEN
  1543.                    stat := Undefined
  1544.                 ELSE IF arg[3].present THEN
  1545.                    { ordinary annuity by default }
  1546.                    IF (NOT arg[5].present) OR
  1547.                       ((arg[5].present) AND (arg[5].parm > 0)) THEN BEGIN
  1548.                       temp := power(rate,-arg[2].parm);
  1549.                       IF temp = 1 THEN
  1550.                          stat := Undefined
  1551.                       ELSE 
  1552.                          result := arg[3].parm/((1-temp)/arg[1].parm)
  1553.                    END      
  1554.                    ELSE BEGIN { annuity due }
  1555.                       temp := power(rate,1-arg[2].parm);
  1556.                       IF temp = 1 THEN
  1557.                          stat := Undefined
  1558.                       ELSE
  1559.                          result := arg[3].parm/((1-temp)/arg[1].parm+1)
  1560.                    END
  1561.                 ELSE IF arg[4].present THEN { future value }
  1562.                    { ordinary by default }
  1563.                    IF (NOT arg[5].present) OR
  1564.                       ((arg[5].present) AND (arg[5].parm > 0)) THEN BEGIN
  1565.                       temp := power(rate,arg[2].parm);
  1566.                       IF temp = 1 THEN
  1567.                          stat := Undefined
  1568.                       ELSE
  1569.                          result := arg[4].parm/((temp-1)/arg[1].parm)
  1570.                    END
  1571.                    ELSE BEGIN { annuity due }
  1572.                       temp := power(rate,arg[2].parm+1);
  1573.                       IF temp = 1 THEN
  1574.                          stat := Undefined
  1575.                       ELSE
  1576.                          result := arg[4].parm/((temp-1)/arg[1].parm-1)
  1577.                    END 
  1578.                 ELSE 
  1579.                    stat := SyntaxErr
  1580.           END { CASE }   
  1581.       END; { EVAL }
  1582.    BEGIN { DO_FINANCIAL }
  1583.        FOR i := 1 TO 5 DO
  1584.            arg[i].present := FALSE;
  1585.        i := 1;
  1586.        cont := TRUE;
  1587.        WHILE (cont) AND (i <= 5) DO BEGIN
  1588.           IF str_pos > len THEN
  1589.              stat := SyntaxErr
  1590.           ELSE   
  1591.              CASE str[str_pos] OF
  1592.                 ',' : BEGIN
  1593.                    str_pos := str_pos+1;
  1594.                    IF str_pos <= len THEN
  1595.                       IF str[str_pos] = ')' THEN
  1596.                          stat := SyntaxErr
  1597.                 END;
  1598.                 ')' : cont := FALSE;
  1599.                 OTHERWISE : BEGIN
  1600.                    full_expr(str,do_it,arg[i].parm);
  1601.                    arg[i].present := TRUE;
  1602.                    IF str_pos < len THEN
  1603.                       IF str[str_pos] = ',' THEN
  1604.                          str_pos := str_pos+1
  1605.                       ELSE IF str[str_pos] <> ')' THEN
  1606.                          stat := SyntaxErr
  1607.                 END
  1608.              END; { CASE }
  1609.           IF stat <> OK THEN
  1610.              do_error(str);
  1611.           i := i+1
  1612.        END;
  1613.        IF do_it THEN
  1614.           eval;
  1615.        IF stat <> OK THEN
  1616.           do_error(str)
  1617.    END; { DO_FINANCIAL }
  1618.  
  1619. PROCEDURE DO_LOOKUP;
  1620.    VAR index,s_r,s_c,e_r,e_c,i,row,col : INTEGER;
  1621.        tag,temp                        : REAL;
  1622.        found,equal                     : BOOLEAN;
  1623.        a                               : AssignedStatus;
  1624.        ptr                             : CellPtr;
  1625.    BEGIN
  1626.        full_expr(str,do_it,tag);
  1627.        IF func_code = IndexOp THEN
  1628.           IF (tag < -MaxInt) OR (tag > MaxInt) THEN
  1629.              stat := OutOfRange;
  1630.        IF (str_pos < len) AND (stat = OK) THEN
  1631.           IF str[str_pos] <> ',' THEN
  1632.              stat := SyntaxErr
  1633.           ELSE BEGIN
  1634.              str_pos := str_pos+1;
  1635.              full_expr(str,do_it,temp);
  1636.              IF (temp < -MaxInt) OR (temp > MaxInt) THEN
  1637.                 stat := OutOfRange
  1638.              ELSE IF str_pos < len THEN
  1639.                 IF str[str_pos] <> ',' THEN
  1640.                    stat := SyntaxErr
  1641.                 ELSE BEGIN
  1642.                    str_pos := str_pos+1;
  1643.                    index := ROUND(temp);
  1644.                    IF index < 1 THEN
  1645.                       stat := OutOfRange
  1646.                    ELSE BEGIN
  1647.                       get_range(str,do_it,s_r,s_c,e_r,e_c);
  1648.                       IF func_code = VLookUpOp THEN
  1649.                          IF s_c+index-1 > e_c THEN
  1650.                             stat := OutOfRange
  1651.                          ELSE
  1652.                       ELSE IF func_code = HLookUpOp THEN   
  1653.                          IF s_r+index-1 > e_r THEN
  1654.                             stat := OutOfRange
  1655.                          ELSE
  1656.                       ELSE BEGIN { IndexOp }
  1657.                          row := ROUND(tag);
  1658.                          col := index;
  1659.                          IF (row < 1) OR (col < 1) OR
  1660.                             (row > e_r-s_r+1) OR (col > e_c-s_c+1) THEN
  1661.                             stat := OutOfRange
  1662.                       END;
  1663.                       IF (do_it) AND (stat = OK) THEN
  1664.                          IF func_code = VLookUpOp THEN BEGIN
  1665.                             found := FALSE;
  1666.                             equal := FALSE;
  1667.                             i := s_r;
  1668.                             WHILE (NOT found) AND (i <= e_r) DO BEGIN
  1669.                                a := assigned(i,s_c,ptr);
  1670.                                IF a = Value THEN
  1671.                                   IF ptr^.num >= tag THEN BEGIN
  1672.                                      found := TRUE;
  1673.                                      IF ptr^.num = tag THEN
  1674.                                         equal := TRUE
  1675.                                   END;      
  1676.                                i := i+1
  1677.                             END;
  1678.                             IF (equal) OR (NOT found) THEN
  1679.                                i := i-1
  1680.                             ELSE
  1681.                                i := i-2;
  1682.                             found := FALSE;
  1683.                             WHILE (NOT found) AND (i >= s_r) DO BEGIN
  1684.                                a := assigned(i,s_c,ptr);
  1685.                                IF a = Value THEN BEGIN
  1686.                                   found := TRUE;
  1687.                                   a := assigned(i,s_c+index-1,ptr);
  1688.                                   IF a = Value THEN
  1689.                                      result := ptr^.num
  1690.                                   ELSE IF a = Error THEN
  1691.                                      stat := ptr^.status
  1692.                                   ELSE
  1693.                                      result := 0
  1694.                                END;
  1695.                                i := i-1
  1696.                             END;
  1697.                             IF NOT found THEN
  1698.                                stat := OutOfRange
  1699.                          END
  1700.                          ELSE IF func_code = HLookUpOp THEN BEGIN
  1701.                             found := FALSE;
  1702.                             equal := FALSE;
  1703.                             i := s_c;
  1704.                             WHILE (NOT found) AND (i <= e_c) DO BEGIN
  1705.                                a := assigned(s_r,i,ptr);
  1706.                                IF a = Value THEN
  1707.                                   IF ptr^.num > tag THEN BEGIN
  1708.                                      found := TRUE;
  1709.                                      IF ptr^.num = tag THEN
  1710.                                         equal := TRUE
  1711.                                   END;
  1712.                                i := i+1
  1713.                             END;
  1714.                             IF (equal) OR (NOT found) THEN
  1715.                                i := i-1
  1716.                             ELSE
  1717.                                i := i-2;
  1718.                             found := FALSE;
  1719.                             WHILE (NOT found) AND (i >= s_c) DO BEGIN
  1720.                                a := assigned(s_r,i,ptr);
  1721.                                IF a = Value THEN BEGIN
  1722.                                   found := TRUE;
  1723.                                   a := assigned(s_r+index-1,i,ptr);
  1724.                                   IF a = Value THEN
  1725.                                      result := ptr^.num
  1726.                                   ELSE IF a = Error THEN
  1727.                                      stat := ptr^.status
  1728.                                   ELSE
  1729.                                      result := 0
  1730.                                END;
  1731.                                i := i-1
  1732.                             END;
  1733.                             IF NOT found THEN
  1734.                                stat := OutOfRange
  1735.                          END
  1736.                          ELSE BEGIN { IndexOp }
  1737.                             a := assigned(s_r+row-1,s_c+col-1,ptr);
  1738.                             IF a = Value THEN
  1739.                                result := ptr^.num
  1740.                             ELSE IF a = Error THEN
  1741.                                stat := ptr^.status
  1742.                             ELSE
  1743.                                result := 0
  1744.                          END
  1745.                    END
  1746.                 END               
  1747.              ELSE
  1748.                 stat := SyntaxErr   
  1749.           END;
  1750.        IF stat <> OK THEN
  1751.           do_error(str)
  1752.    END; { DO_LOOKUP }       
  1753.              
  1754. PROCEDURE IF_EXPR;
  1755.    { <ifexpr> ::= IF(<fullexpr>,<fullexpr>,<fullexpr>) }
  1756.    VAR T_result,F_result : REAL;
  1757.    BEGIN
  1758.        IF str_pos < len THEN BEGIN
  1759.           full_expr(str,do_it,result);
  1760.           IF str_pos < len THEN
  1761.              IF str[str_pos] <> ',' THEN
  1762.                 stat := SyntaxErr
  1763.              ELSE BEGIN
  1764.                 str_pos := str_pos+1;
  1765.                 { first action; must "pseudo-evaluate" if the boolean expr
  1766.                   was FALSE in order to get str_pos to the correct pos. }
  1767.                 full_expr(str,result<>0,T_result);
  1768.                 IF str_pos < len THEN
  1769.                    IF (str[str_pos] <> ',') THEN
  1770.                       stat := SyntaxErr
  1771.                    ELSE BEGIN { alternate action; ditto as for 1st }
  1772.                       str_pos := str_pos+1;
  1773.                       full_expr(str,result=0,F_result);
  1774.                       IF do_it THEN
  1775.                          IF result <> 0 THEN
  1776.                             result := T_result
  1777.                          ELSE
  1778.                             result := F_result
  1779.                    END
  1780.                 ELSE
  1781.                    stat := SyntaxErr
  1782.              END
  1783.           ELSE { can't call this an error }
  1784.        END
  1785.        ELSE { str_pos did = len }
  1786.           stat := SyntaxErr;
  1787.        IF stat <> OK THEN
  1788.           do_error(str)
  1789.    END; { IF_EXPR }
  1790.  
  1791.  
  1792. (**************************************************************************)
  1793. (* EVALUATE_FORMULA, the parent, begins here. Had to make the other       *)
  1794. (*     routines local to this one so that if an error is encountered, can *)
  1795. (*     abort to a label in this routine.                                  *)
  1796. (**************************************************************************)
  1797.  
  1798. { class of cell passed here should be Expr, but NIL str and recalc flag are
  1799.   checked to be certain }
  1800.  
  1801.    BEGIN { EVALUATE_FORMULA }
  1802.       IF cell^.str <> NIL THEN BEGIN
  1803.          cell^.format := cell^.format | pending_mask;
  1804.          str_pos := 1;
  1805.          stat := OK;
  1806.          result := 0;
  1807.          WITH cell^ DO BEGIN
  1808.             len := LENGTH(str^);
  1809.             full_expr(str^,TRUE,result);
  1810. 1:          cell^.format := (cell^.format | recalc_mask) & not_pending_mask;
  1811.             old_num := num;
  1812.             old_status := status;
  1813.             IF (str_pos <= len) AND (stat = OK) THEN BEGIN
  1814.                stat := SyntaxErr;
  1815.                IF new_form THEN BEGIN
  1816.                   Set_Mouse(M_Arrow);
  1817.                   error_message(str^,stat,str_pos,len);
  1818.                   Set_Mouse(M_Bee)
  1819.                END 
  1820.             END;               { Catch things like 1 < A1 < 2,   }
  1821.                                { as FULL_EXPR only looks for the }
  1822.             IF stat = OK THEN  { 1st clause. Can't check there   }
  1823.                status := Full  { because some valid expr may be  }
  1824.             ELSE               { left, following the boolean...  }
  1825.                status := stat;
  1826.                                { NOTE: all cells dependent on this  }
  1827.             num := result;     { will assume its status if an error }
  1828.             IF format & perc_mask <> 0 THEN
  1829.                num := num/100;
  1830.             IF (auto_recalc) AND
  1831.                ((old_num <> num) OR (old_status <> status)) THEN BEGIN
  1832.                dep := sub;
  1833.                WHILE dep <> NIL DO BEGIN
  1834.                   ptr := locate_cell(dep^.r,dep^.c);
  1835.                   IF ptr <> NIL THEN
  1836.                      IF (ptr^.class = Expr) AND
  1837.                         (ptr^.format & recalc_mask = 0) AND 
  1838.                         (ptr^.format & pending_mask = 0) THEN
  1839.                         evaluate_formula(dep^.r,dep^.c,force,FALSE,ptr);
  1840.                   dep := dep^.next
  1841.                END;
  1842.             END { IF }
  1843.          END; { WITH }
  1844.          IF (row <> data_row) OR (col <> data_col) THEN
  1845.             IF (old_num <> cell^.num) OR (old_status <> cell^.status) THEN
  1846.                cell_on_screen(1,row,col,TRUE)
  1847.       END      
  1848.       ELSE { str did = NIL }
  1849.          cell^.format := cell^.format | recalc_mask;
  1850. 2: END; { EVALUATE_FORMULA }    
  1851.      
  1852.  
  1853. BEGIN
  1854. END.
  1855.  
  1856.  
  1857.  
  1858.