  { CALCUTIL:  Calculator Utilities. }
  { Copyright (C) 1984 by QCAD Systems Inc., All Rights Reserved. }

  {******************}
  procedure WRITE_VALUE(R:  real);
    { writes r to the screen in a 'reasonable' format.  must resort
      to Turbo's exponential notation in extreme cases. }
    const
      MIN_MAGNITUDE = -38;
      { Turbo Pascal has roughly 12 decimal digits of precision;
        keep the last one as a guard digit. }
      PRECISION = 11;
    var
      MAGNITUDE:  integer;
      FRACTION:  real;
      FUZZ:  real;  { number to compare against for roundoff }

    {..................}
    procedure WRITE_FRACTION(FRACTION: real;  DIGITS: integer);
      { chunk out zero or more digits of the fraction, until either
        the digit count gives out, or we run into the fuzz. }
    begin
      while (abs(fraction) > fuzz) and (digits > 0) do begin
        fraction := fraction * 10.0;
        write(trunc(fraction):1);
        fuzz := fuzz * 10.0;
        digits := digits-1;
        fraction := frac(fraction)
      end
    end;

  begin { write_value }
    { first, establish some useful information about R. }
    if r = 0.0 then
      magnitude := 0
    else
      magnitude := trunc(ln(abs(r))/ln(10.0));
    if magnitude-precision >= min_magnitude then begin
      fuzz := exp((magnitude-precision+1)*ln(10.0));
      { Turbo reals tend to err toward zero; use the fuzz to
        compensate for this effect. }
      if r<0.0 then
        r := r-fuzz
      else if r>0.0 then
        r := r+fuzz
      end
    else
      fuzz := 0.0;
    fraction := abs(frac(r));
    { now, decide what to do with R. }
    if (abs(r) >= maxint) or (magnitude < -3) then
      { big enough or small enough for a possible loss of precision:
        use exponential notation. }
      write(r)
    else if fraction < fuzz then
      { essentially whole number of small magnitude }
      write(trunc(r):1)
    else begin
      { real number in ddd.ddd format. }
      if (-1.0 < r) and (r < 0.0) then
        write('-');  { trunc eliminates minus sign for these numbers }
      write(trunc(r):1, '.');
      write_fraction(fraction, precision-magnitude)
    end
  end { write_value };

  {******************}
  procedure EVAL_BINOP(OP: operator;  OPND1, OPND2: semrecp;
                       RESULT:  semrecp);
    { evaluate the given binary operator, setting up the result
      semantic record with the resulting value.  if there is an
      error, result will generally contain a non-value (because
      it is set up to be 'other' rather than 'float' by default).
      most of the code here is for error handling. }
    var V1, V2:  real;  { operand values }
        SEM_TYPE:  semtype;  { type of result }
  begin
    if opnd2 = nil then begin
      { actually, its a unary operator }
      if opnd1^.semt = float then begin
        case op of
          uminus:   result^.rval := -opnd1^.rval;
          ELSE error('internal problems in eval_binop')
        end;
        result^.semt := float
      end
    end
    else if opnd1^.semt <> float then
      result^ := opnd2^
    else if opnd2^.semt <> float then
      result^ := opnd1^
    else begin
      { both values are good }
      v1 := opnd1^.rval;
      v2 := opnd2^.rval;
      sem_type := float;
      case op of
        divide:  if v2 <> 0.0 then
                   v1 := v1/v2
                 else begin
                   write('Attempt to divide ');
                   write_value(v1);
                   writeln(' by zero.');
                   sem_type := other
                 end;
        mpy:     v1 := v1*v2;
        plus:    v1 := v1+v2;
        minus:   v1 := v1-v2;
      end;
      result^.semt := sem_type;
      result^.rval := v1
    end
  end;

  {******************}
  procedure INIT_SEM;
    { No semantics initialization needed. }
  begin
  end;

  {******************}
  procedure END_SEM;
    { No semantics conclusion needed. }
  begin
  end;

