transput-formatting.c

     
   1  //! @file transput-formatting.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis 
  23  //!
  24  //! Formatting routines for transput.
  25  
  26  #include "a68g.h"
  27  #include "a68g-genie.h"
  28  #include "a68g-prelude.h"
  29  #include "a68g-mp.h"
  30  #include "a68g-double.h"
  31  #include "a68g-conversion.h"
  32  #include "a68g-transput.h"
  33  
  34  // Next are formatting routines "whole", "fixed" and "float" for mode
  35  // INT, LONG INT and LONG LONG INT, and REAL, LONG REAL and LONG LONG REAL.
  36  // They are direct implementations of the routines described in the
  37  // Revised Report, although those were only meant as a specification.
  38  
  39  
  40  //! @brief Generate a string of error chars.
  41  
  42  char *error_chars (char *s, int width)
  43  {
  44    int k = (width == 0 ? 1 : ABS (width));
  45    s[k] = NULL_CHAR;
  46    while (--k >= 0) {
  47      s[k] = ERROR_CHAR;
  48    }
  49    return s;
  50  }
  51  
  52  
  53  //! @brief Generate a string of error chars.
  54  
  55  char *error_chars_exception (char *s, char *msg, char *alt, int width)
  56  {
  57    size_t N = strlen (msg);
  58    if (width < N) {
  59      if (alt == NO_TEXT) {
  60        return error_chars (s, width);
  61      } else {
  62        return error_chars_exception (s, alt, NO_TEXT, width);
  63      }
  64    } else {
  65      int k = (width < 1 ? 1 : ABS (width));
  66      a68g_bufcpy (s, msg, k);
  67      s[k] = NULL_CHAR;
  68      while (--k >= N) {
  69        s[k] = ' '; // ERROR_CHAR;
  70      }
  71      return s;
  72    }
  73  }
  74  
  75  
  76  //! @brief Convert temporary C string to A68 string.
  77  
  78  A68G_REF tmp_to_a68g_string (NODE_T * p, char *temp_string)
  79  {
  80    // no compaction allowed since temp_string might be up for garbage collecting ...
  81    return c_to_a_string (p, temp_string, DEFAULT_WIDTH);
  82  }
  83  
  84  
  85  //! @brief Add c to str, assuming that "str" is large enough.
  86  
  87  char *plusto (char c, char *str)
  88  {
  89    MOVE (&str[1], &str[0], strlen (str) + 1);
  90    str[0] = c;
  91    return str;
  92  }
  93  
  94  
  95  //! @brief Add c to str, assuming that "str" is large enough.
  96  
  97  char *string_plusab_char (char *str, char c, int strwid)
  98  {
  99    char z[2];
 100    z[0] = c;
 101    z[1] = NULL_CHAR;
 102    a68g_bufcat (str, z, strwid);
 103    return str;
 104  }
 105  
 106  
 107  //! @brief Add leading spaces to str until length is width.
 108  
 109  char *leading_spaces (char *str, int width)
 110  {
 111    int j = width - strlen (str);
 112    while (--j >= 0) {
 113      (void) plusto (BLANK_CHAR, str);
 114    }
 115    return str;
 116  }
 117  
 118  
 119  //! @brief Convert int to char using a table.
 120  
 121  char digchar (int k)
 122  {
 123    char *s = "0123456789abcdefghijklmnopqrstuvwxyz";
 124    if (k >= 0 && k < strlen (s)) {
 125      return s[k];
 126    } else {
 127      return ERROR_CHAR;
 128    }
 129  }
 130  
 131  
 132  //! @brief Formatted string for HEX_NUMBER.
 133  
 134  char *bits_to_string (NODE_T * p)
 135  {
 136    A68G_INT width, base;
 137    POP_OBJECT (p, &base, A68G_INT);
 138    POP_OBJECT (p, &width, A68G_INT);
 139    DECREMENT_STACK_POINTER (p, SIZE (M_HEX_NUMBER));
 140    CHECK_INT_SHORTEN (p, VALUE (&base));
 141    CHECK_INT_SHORTEN (p, VALUE (&width));
 142    MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
 143    ADDR_T pop_sp = A68G_SP;
 144    int length = ABS (VALUE (&width)), radix = ABS (VALUE (&base));
 145    if (radix < 2 || radix > 16) {
 146      diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
 147      exit_genie (p, A68G_RUNTIME_ERROR);
 148    }
 149    reset_transput_buffer (EDIT_BUFFER);
 150    #if (A68G_LEVEL <= 2)
 151      (void) mode;
 152      (void) length;
 153      (void) error_chars (get_transput_buffer (EDIT_BUFFER), VALUE (&width));
 154    #else
 155      {
 156        BOOL_T ret = A68G_TRUE;
 157        if (mode == M_BOOL) {
 158          UNSIGNED_T z = VALUE ((A68G_BOOL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 159          ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
 160        } else if (mode == M_CHAR) {
 161          INT_T z = VALUE ((A68G_CHAR *) (STACK_OFFSET (A68G_UNION_SIZE)));
 162          ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
 163        } else if (mode == M_INT) {
 164          INT_T z = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 165          ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
 166        } else if (mode == M_REAL) {
 167          // A trick to copy a REAL into an unt without truncating
 168          UNSIGNED_T z;
 169          memcpy (&z, (void *) &VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))), 8);
 170          ret = convert_radix (p, z, radix, length);
 171        } else if (mode == M_BITS) {
 172          UNSIGNED_T z = VALUE ((A68G_BITS *) (STACK_OFFSET (A68G_UNION_SIZE)));
 173          ret = convert_radix (p, (UNSIGNED_T) z, radix, length);
 174        } else if (mode == M_LONG_INT) {
 175          DOUBLE_NUM_T z = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 176          ret = convert_radix_double (p, z, radix, length);
 177        } else if (mode == M_LONG_REAL) {
 178          DOUBLE_NUM_T z = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 179          ret = convert_radix_double (p, z, radix, length);
 180        } else if (mode == M_LONG_BITS) {
 181          DOUBLE_NUM_T z = VALUE ((A68G_LONG_BITS *) (STACK_OFFSET (A68G_UNION_SIZE)));
 182          ret = convert_radix_double (p, z, radix, length);
 183        }
 184        if (ret == A68G_FALSE) {
 185          errno = EDOM;
 186          PRELUDE_ERROR (A68G_TRUE, p, ERROR_OUT_OF_BOUNDS, mode);
 187        }
 188      }
 189    #endif
 190    A68G_SP = pop_sp;
 191    return get_transput_buffer (EDIT_BUFFER);
 192  }
 193  
 194  
 195  //! @brief Standard string for LONG INT.
 196  
 197  char *sub_whole_mp (NODE_T * p, MP_T * m, int digits, int width)
 198  {
 199    int len = 0;
 200    char *s = stack_string (p, 8 + width);
 201    s[0] = NULL_CHAR;
 202    ADDR_T pop_sp = A68G_SP;
 203    MP_T *n = nil_mp (p, digits);
 204    (void) move_mp (n, m, digits);
 205    do {
 206      if (len < width) {
 207        // Sic transit gloria mundi.
 208        int n_mod_10 = (MP_INT_T) MP_DIGIT (n, (int) (1 + MP_EXPONENT (n))) % 10;
 209        (void) plusto (digchar (n_mod_10), s);
 210      }
 211      len++;
 212      (void) over_mp_digit (p, n, n, (MP_T) 10, digits);
 213    } while (MP_DIGIT (n, 1) > 0);
 214    if (len > width) {
 215      (void) error_chars (s, width);
 216    }
 217    A68G_SP = pop_sp;
 218    return s;
 219  }
 220  
 221  
 222  //! @brief Formatted string for NUMBER.
 223  
 224  char *whole (NODE_T * p)
 225  {
 226    A68G_INT width;
 227    POP_OBJECT (p, &width, A68G_INT);
 228    CHECK_INT_SHORTEN (p, VALUE (&width));
 229    DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 230    ADDR_T pop_sp = A68G_SP;
 231    MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
 232    //
 233    if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 234      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 235      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 236      PUSH_VALUE (p, 0, A68G_INT);
 237      return fixed (p);
 238    } else if (mode == M_INT) {
 239      INT_T x = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 240      int digits = DIGITS (M_LONG_LONG_INT);
 241      PUSH_UNION (p, (void *) M_LONG_LONG_INT);
 242      MP_T *z = nil_mp (p, digits);
 243      (void) int_to_mp (p, z, x, digits);
 244      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 245      return whole (p);
 246    }
 247    #if (A68G_LEVEL >= 3)
 248      if (mode == M_LONG_INT) {
 249        DOUBLE_NUM_T x = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 250        int digits = DIGITS (M_LONG_LONG_INT);
 251        PUSH_UNION (p, (void *) M_LONG_LONG_INT);
 252        MP_T *z = nil_mp (p, digits);
 253        (void) double_int_to_mp (p, z, x, digits);
 254        PUSH_VALUE (p, VALUE (&width), A68G_INT);
 255        return whole (p);
 256      }
 257    #endif
 258    if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 259      int digits = DIGITS (mode);
 260      MP_T *n = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
 261      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 262      if (MP_EXPONENT (n) >= (MP_T) digits) {
 263        int max_length = (mode == M_LONG_INT ? A68G_LONG_INT_WIDTH : A68G_LONG_LONG_INT_WIDTH);
 264        int length = (VALUE (&width) == 0 ? max_length : VALUE (&width));
 265        char *s = stack_string (p, 1 + length);
 266        (void) error_chars (s, length);
 267        A68G_SP = pop_sp;
 268        return s;
 269      }
 270      BOOL_T ltz = (BOOL_T) (MP_DIGIT (n, 1) < 0);
 271      int length = ABS (VALUE (&width)) - (ltz || VALUE (&width) > 0 ? 1 : 0);
 272      size_t size = (ltz ? 1 : (VALUE (&width) > 0 ? 1 : 0));
 273      MP_DIGIT (n, 1) = ABS (MP_DIGIT (n, 1));
 274      if (VALUE (&width) == 0) {
 275        MP_T *m = nil_mp (p, digits);
 276        (void) move_mp (m, n, digits);
 277        length = 0;
 278        while ((over_mp_digit (p, m, m, (MP_T) 10, digits), length++, MP_DIGIT (m, 1) != 0)) {
 279          ;
 280        }
 281      }
 282      size += length;
 283      int abs_width = ABS (VALUE (&width));
 284      size = 8 + A68G_MAX (size, abs_width);
 285      char *s = stack_string (p, size);
 286      a68g_bufcpy (s, sub_whole_mp (p, n, digits, length), size);
 287      if (length == 0 || strchr (s, ERROR_CHAR) != NO_TEXT) {
 288        (void) error_chars (s, abs_width);
 289      } else {
 290        if (ltz) {
 291          (void) plusto ('-', s);
 292        } else if (VALUE (&width) > 0) {
 293          (void) plusto ('+', s);
 294        }
 295        if (VALUE (&width) != 0) {
 296          (void) leading_spaces (s, abs_width);
 297        }
 298      }
 299      A68G_SP = pop_sp;
 300      return s;
 301    }
 302    ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 303    return NO_TEXT;
 304  }
 305  
 306  
 307  //! @brief Fetch next digit from LONG.
 308  
 309  char choose_dig_mp (NODE_T * p, MP_T * y, int digits)
 310  {
 311    // Assuming positive "y".
 312    ADDR_T pop_sp = A68G_SP;
 313    (void) mul_mp_digit (p, y, y, (MP_T) 10, digits);
 314    int c = MP_EXPONENT (y) == 0 ? (MP_INT_T) MP_DIGIT (y, 1) : 0;
 315    if (c > 9) {
 316      c = 9;
 317    }
 318    MP_T *t = lit_mp (p, c, 0, digits);
 319    (void) sub_mp (p, y, y, t, digits);
 320    // Reset the stack to prevent overflow, there may be many digits.
 321    A68G_SP = pop_sp;
 322    return digchar (c);
 323  }
 324  
 325  
 326  //! @brief Standard string for LONG.
 327  
 328  char *sub_fixed_mp (NODE_T * p, MP_T * x, int digits, int width, int after)
 329  {
 330    ADDR_T pop_sp = A68G_SP;
 331    MP_T *y = nil_mp (p, digits);
 332    MP_T *s = nil_mp (p, digits);
 333    MP_T *t = nil_mp (p, digits);
 334    (void) ten_up_mp (p, t, -after, digits);
 335    (void) half_mp (p, t, t, digits);
 336    (void) add_mp (p, y, x, t, digits);
 337    int before = 0;
 338    // Not RR - argument reduction.
 339    while (MP_EXPONENT (y) > 1) {
 340      int k = (int) round (MP_EXPONENT (y) - 1);
 341      MP_EXPONENT (y) -= k;
 342      before += k * LOG_MP_RADIX;
 343    }
 344    // Follow RR again.
 345    SET_MP_ONE (s, digits);
 346    while ((sub_mp (p, t, y, s, digits), MP_DIGIT (t, 1) >= 0)) {
 347      before++;
 348      (void) div_mp_digit (p, y, y, (MP_T) 10, digits);
 349    }
 350    // Compose the number.
 351    if (before + after + (after > 0 ? 1 : 0) > width) {
 352      char *str = stack_string (p, width + 1);
 353      (void) error_chars (str, width);
 354      A68G_SP = pop_sp;
 355      return str;
 356    }
 357    int strwid = 8 + before + after;
 358    char *str = stack_string (p, strwid);
 359    str[0] = NULL_CHAR;
 360    int len = 0;
 361    for (int j = 0; j < before; j++) {
 362      char ch = (char) (len < A68G_LONG_LONG_REAL_WIDTH ? choose_dig_mp (p, y, digits) : '0');
 363      (void) string_plusab_char (str, ch, strwid);
 364      len++;
 365    }
 366    if (after > 0) {
 367      (void) string_plusab_char (str, POINT_CHAR, strwid);
 368    }
 369    for (int j = 0; j < after; j++) {
 370      char ch = (char) (len < A68G_LONG_LONG_REAL_WIDTH ? choose_dig_mp (p, y, digits) : '0');
 371      (void) string_plusab_char (str, ch, strwid);
 372      len++;
 373    }
 374    if (strlen (str) > width) {
 375      (void) error_chars (str, width);
 376    }
 377    A68G_SP = pop_sp;
 378    return str;
 379  }
 380  
 381  
 382  //! @brief Formatted string for NUMBER.
 383  
 384  char *fixed (NODE_T * p)
 385  {
 386    A68G_INT width, after;
 387    POP_OBJECT (p, &after, A68G_INT);
 388    POP_OBJECT (p, &width, A68G_INT);
 389    CHECK_INT_SHORTEN (p, VALUE (&after));
 390    CHECK_INT_SHORTEN (p, VALUE (&width));
 391    DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 392    ADDR_T pop_sp = A68G_SP;
 393    MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
 394    if (mode == M_INT) {
 395      INT_T k = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 396      PUSH_UNION (p, M_REAL);
 397      PUSH_VALUE (p, (REAL_T) k, A68G_REAL);
 398      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_REAL)));
 399      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 400      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 401      return fixed (p);
 402    } else if (mode == M_REAL) {
 403      REAL_T x = VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 404      CHECK_REAL (p, x, M_REAL);
 405      int digits = DIGITS (M_LONG_LONG_REAL);
 406      PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 407      MP_T *z = nil_mp (p, digits);
 408      #if (A68G_LEVEL >= 3)
 409        (void) double_to_mp (p, z, (DOUBLE_T) x, digits);
 410      #else
 411        (void) real_to_mp (p, z, x, digits);
 412      #endif
 413      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 414      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 415      return fixed (p);
 416    }
 417    #if (A68G_LEVEL >= 3)
 418      if (mode == M_LONG_INT) {
 419        DOUBLE_NUM_T x = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 420        int digits = DIGITS (M_LONG_LONG_REAL);
 421        PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 422        MP_T *z = nil_mp (p, digits);
 423        (void) double_int_to_mp (p, z, x, digits);
 424        PUSH_VALUE (p, VALUE (&width), A68G_INT);
 425        PUSH_VALUE (p, VALUE (&after), A68G_INT);
 426        return fixed (p);
 427      } else if (mode == M_LONG_REAL) {
 428        DOUBLE_T x = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))).f;
 429        CHECK_DOUBLE_REAL (p, x, M_LONG_REAL);
 430        int digits = DIGITS (M_LONG_LONG_REAL);
 431        PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 432        MP_T *z = nil_mp (p, digits);
 433        (void) double_to_mp (p, z, x, digits);
 434        PUSH_VALUE (p, VALUE (&width), A68G_INT);
 435        PUSH_VALUE (p, VALUE (&after), A68G_INT);
 436        return fixed (p);
 437      }
 438    #endif
 439    if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 440      if (mode == M_LONG_INT) {
 441        VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_REAL;
 442      } else {
 443        VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_LONG_REAL;
 444      } 
 445      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 446      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 447      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 448      return fixed (p);
 449    } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 450      int digits = DIGITS (mode);
 451      MP_T *x = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
 452      CHECK_LONG_REAL (p, x, mode);
 453      if (A68G_PLUS_INF_MP (x)) {
 454        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 455        A68G_SP = pop_sp;
 456        return error_chars_exception (s, "+infinity", "+inf", VALUE (&width));
 457      } else if (A68G_MINUS_INF_MP (x)) {
 458        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 459        A68G_SP = pop_sp;
 460        return error_chars_exception (s, "-infinity", "-inf", VALUE (&width));
 461      } else if (A68G_NAN_MP (x)) {
 462        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 463        A68G_SP = pop_sp;
 464        return error_chars_exception (s, "nan", NO_TEXT, VALUE (&width));
 465      } else {
 466        INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 467        BOOL_T ltz = (BOOL_T) (MP_DIGIT (x, 1) < 0);
 468        MP_DIGIT (x, 1) = ABS (MP_DIGIT (x, 1));
 469        int length = ABS (VALUE (&width)) - (ltz || VALUE (&width) > 0 ? 1 : 0);
 470        if (VALUE (&after) >= 0 && (length > VALUE (&after) || VALUE (&width) == 0)) {
 471          MP_T *z0 = nil_mp (p, digits);
 472          MP_T *z1 = nil_mp (p, digits);
 473          MP_T *t = nil_mp (p, digits);
 474          if (VALUE (&width) == 0) {
 475            length = (VALUE (&after) == 0 ? 1 : 0);
 476            (void) set_mp (z0, (MP_T) (MP_RADIX / 10), -1, digits);
 477            (void) set_mp (z1, (MP_T) 10, 0, digits);
 478            (void) pow_mp_int (p, z0, z0, VALUE (&after), digits);
 479            (void) pow_mp_int (p, z1, z1, length, digits);
 480            while ((div_mp_digit (p, t, z0, (MP_T) 2, digits), add_mp (p, t, x, t, digits), sub_mp (p, t, t, z1, digits), MP_DIGIT (t, 1) > 0)) {
 481              length++;
 482              (void) mul_mp_digit (p, z1, z1, (MP_T) 10, digits);
 483            }
 484            length += (VALUE (&after) == 0 ? 0 : VALUE (&after) + 1);
 485          }
 486          char *s = sub_fixed_mp (p, x, digits, length, VALUE (&after));
 487          if (strchr (s, ERROR_CHAR) == NO_TEXT) {
 488            if (length > strlen (s) && (s[0] != NULL_CHAR ? s[0] == POINT_CHAR : A68G_TRUE) && (MP_EXPONENT (x) < 0 || MP_DIGIT (x, 1) == 0)) {
 489              (void) plusto ('0', s);
 490            }
 491            if (ltz) {
 492              (void) plusto ('-', s);
 493            } else if (VALUE (&width) > 0) {
 494              (void) plusto ('+', s);
 495            }
 496            if (VALUE (&width) != 0) {
 497              (void) leading_spaces (s, ABS (VALUE (&width)));
 498            }
 499            A68G_SP = pop_sp;
 500            return s;
 501          } else if (VALUE (&after) > 0) {
 502            A68G_SP = pop_sp;
 503            MP_DIGIT (x, 1) = ltz ? -ABS (MP_DIGIT (x, 1)) : ABS (MP_DIGIT (x, 1));
 504            INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 505            PUSH_VALUE (p, VALUE (&width), A68G_INT);
 506            PUSH_VALUE (p, VALUE (&after) - 1, A68G_INT);
 507            return fixed (p);
 508          } else {
 509            A68G_SP = pop_sp;
 510            return error_chars (s, VALUE (&width));
 511          }
 512        } else {
 513          char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 514          A68G_SP = pop_sp;
 515          return error_chars (s, VALUE (&width));
 516        }
 517      }
 518    }
 519    ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 520    return NO_TEXT;
 521  }
 522  
 523  
 524  //! @brief Scale LONG for formatting.
 525  
 526  void standardize_mp (NODE_T * p, MP_T * y, int digits, int before, int after, int *q)
 527  {
 528    ADDR_T pop_sp = A68G_SP;
 529    MP_T *f = nil_mp (p, digits);
 530    MP_T *g = nil_mp (p, digits);
 531    MP_T *h = nil_mp (p, digits);
 532    MP_T *t = nil_mp (p, digits);
 533    ten_up_mp (p, g, before, digits);
 534    (void) div_mp_digit (p, h, g, (MP_T) 10, digits);
 535    // Speed huge exponents.
 536    if ((MP_EXPONENT (y) - MP_EXPONENT (g)) > 1) {
 537      (*q) += LOG_MP_RADIX * ((int) MP_EXPONENT (y) - (int) MP_EXPONENT (g) - 1);
 538      MP_EXPONENT (y) = MP_EXPONENT (g) + 1;
 539    }
 540    while ((sub_mp (p, t, y, g, digits), MP_DIGIT (t, 1) >= 0)) {
 541      (void) div_mp_digit (p, y, y, (MP_T) 10, digits);
 542      (*q)++;
 543    }
 544    if (MP_DIGIT (y, 1) != 0) {
 545      // Speed huge exponents.
 546      if ((MP_EXPONENT (y) - MP_EXPONENT (h)) < -1) {
 547        (*q) -= LOG_MP_RADIX * ((int) MP_EXPONENT (h) - (int) MP_EXPONENT (y) - 1);
 548        MP_EXPONENT (y) = MP_EXPONENT (h) - 1;
 549      }
 550      while ((sub_mp (p, t, y, h, digits), MP_DIGIT (t, 1) < 0)) {
 551        (void) mul_mp_digit (p, y, y, (MP_T) 10, digits);
 552        (*q)--;
 553      }
 554    }
 555    ten_up_mp (p, f, -after, digits);
 556    (void) div_mp_digit (p, t, f, (MP_T) 2, digits);
 557    (void) add_mp (p, t, y, t, digits);
 558    (void) sub_mp (p, t, t, g, digits);
 559    if (MP_DIGIT (t, 1) >= 0) {
 560      (void) move_mp (y, h, digits);
 561      (*q)++;
 562    }
 563    A68G_SP = pop_sp;
 564  }
 565  
 566  
 567  //! @brief Formatted string for NUMBER.
 568  
 569  char *real (NODE_T * p)
 570  {
 571  // POP arguments.
 572    A68G_INT width, after, expo, frmt;
 573    POP_OBJECT (p, &frmt, A68G_INT);
 574    POP_OBJECT (p, &expo, A68G_INT);
 575    POP_OBJECT (p, &after, A68G_INT);
 576    POP_OBJECT (p, &width, A68G_INT);
 577    CHECK_INT_SHORTEN (p, VALUE (&frmt));
 578    CHECK_INT_SHORTEN (p, VALUE (&expo));
 579    CHECK_INT_SHORTEN (p, VALUE (&after));
 580    CHECK_INT_SHORTEN (p, VALUE (&width));
 581    ADDR_T arg_sp = A68G_SP;
 582    DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 583    MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
 584    ADDR_T pop_sp = A68G_SP;
 585    //
 586    if (mode == M_INT) {
 587      INT_T k = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 588      PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 589      int digits = DIGITS (M_LONG_LONG_REAL);
 590      MP_T *z = nil_mp (p, digits);
 591      int_to_mp (p, z, k, digits);
 592      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 593      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 594      PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 595      PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 596      return real (p);
 597    } else if (mode == M_REAL) {
 598      REAL_T x = VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 599      CHECK_REAL (p, x, M_REAL);
 600      PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 601      int digits = DIGITS (M_LONG_LONG_REAL);
 602      MP_T *z = nil_mp (p, digits);
 603      #if (A68G_LEVEL >= 3)
 604        (void) double_to_mp (p, z, (DOUBLE_T) x, digits);
 605      #else
 606        (void) real_to_mp (p, z, x, digits);
 607      #endif
 608      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 609      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 610      PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 611      PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 612      return real (p);
 613    }
 614    #if (A68G_LEVEL >= 3)
 615      if (mode == M_LONG_INT) {
 616        DOUBLE_NUM_T k = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 617        int digits = DIGITS (M_LONG_LONG_REAL);
 618        PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 619        MP_T *z = nil_mp (p, digits);
 620        (void) double_int_to_mp (p, z, k, digits);
 621        PUSH_VALUE (p, VALUE (&width), A68G_INT);
 622        PUSH_VALUE (p, VALUE (&after), A68G_INT);
 623        PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 624        PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 625        return real (p);
 626      } else if (mode == M_LONG_REAL) {
 627        DOUBLE_T x = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE))).f;
 628        CHECK_DOUBLE_REAL (p, x, M_LONG_REAL);
 629        int digits = DIGITS (M_LONG_LONG_REAL);
 630        PUSH_UNION (p, (void *) M_LONG_LONG_REAL);
 631        MP_T *z = nil_mp (p, digits);
 632        (void) double_to_mp (p, z, (DOUBLE_T) x, digits);
 633        PUSH_VALUE (p, VALUE (&width), A68G_INT);
 634        PUSH_VALUE (p, VALUE (&after), A68G_INT);
 635        PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 636        PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 637        return real (p);
 638      }
 639    #endif
 640    if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 641      A68G_SP = pop_sp;
 642      if (mode == M_LONG_INT) {
 643        VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_REAL;
 644      } else {
 645        VALUE ((A68G_UNION *) STACK_TOP) = (void *) M_LONG_LONG_REAL;
 646      } 
 647      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 648      PUSH_VALUE (p, VALUE (&width), A68G_INT);
 649      PUSH_VALUE (p, VALUE (&after), A68G_INT);
 650      PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 651      PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 652      return real (p);
 653    } else if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 654      int digits = DIGITS (mode);
 655      MP_T *x = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
 656      CHECK_LONG_REAL (p, x, mode);
 657      if (A68G_PLUS_INF_MP (x)) {
 658        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 659        A68G_SP = pop_sp;
 660        return error_chars_exception (s, "+infinity", "+inf", VALUE (&width));
 661      } else if (A68G_MINUS_INF_MP (x)) {
 662        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 663        A68G_SP = pop_sp;
 664        return error_chars_exception (s, "-infinity", "-inf", VALUE (&width));
 665      } else if (A68G_NAN_MP (x)) {
 666        char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 667        A68G_SP = pop_sp;
 668        return error_chars_exception (s, "nan", NO_TEXT, VALUE (&width));
 669      } else {
 670        CHECK_LONG_REAL (p, x, mode);
 671        A68G_SP = arg_sp;
 672        MP_T x1 = MP_DIGIT (x, 1); // Save digit for recursion.
 673        BOOL_T ltz = (BOOL_T) (x1 < 0);
 674        MP_DIGIT (x, 1) = ABS (x1);
 675        int before = ABS (VALUE (&width)) - ABS (VALUE (&expo)) - (VALUE (&after) != 0 ? VALUE (&after) + 1 : 0) - 2;
 676        if (SIGN (before) + SIGN (VALUE (&after)) > 0) {
 677          int q = 0;
 678          MP_T *z = nil_mp (p, digits);
 679          (void) move_mp (z, x, digits);
 680          standardize_mp (p, z, digits, before, VALUE (&after), &q);
 681          if (VALUE (&frmt) > 0) {
 682            while (q % VALUE (&frmt) != 0) {
 683              (void) mul_mp_digit (p, z, z, (MP_T) 10, digits);
 684              q--;
 685              if (VALUE (&after) > 0) {
 686                VALUE (&after)--;
 687              }
 688            }
 689          } else {
 690            ADDR_T pop_sp_2 = A68G_SP;
 691            MP_T *dif = nil_mp (p, digits);
 692            MP_T *lim = nil_mp (p, digits);
 693            (void) ten_up_mp (p, lim, -VALUE (&frmt) - 1, digits);
 694            (void) sub_mp (p, dif, z, lim, digits);
 695            while (MP_DIGIT (dif, 1) < 0) {
 696              (void) mul_mp_digit (p, z, z, (MP_T) 10, digits);
 697              q--;
 698              if (VALUE (&after) > 0) {
 699                VALUE (&after)--;
 700              }
 701              (void) sub_mp (p, dif, z, lim, digits);
 702            }
 703            (void) mul_mp_digit (p, lim, lim, (MP_T) 10, digits);
 704            (void) sub_mp (p, dif, z, lim, digits);
 705            while (MP_DIGIT (dif, 1) > 0) {
 706              (void) div_mp_digit (p, z, z, (MP_T) 10, digits);
 707              q++;
 708              if (VALUE (&after) > 0) {
 709                VALUE (&after)++;
 710              }
 711              (void) sub_mp (p, dif, z, lim, digits);
 712            }
 713            A68G_SP = pop_sp_2;
 714          }
 715          //
 716          int strwid = 8 + ABS (VALUE (&width));
 717          char *s = stack_string (p, strwid);
 718          // Mantissa.
 719          PUSH_UNION (p, mode);
 720          MP_DIGIT (z, 1) = (ltz ? -MP_DIGIT (z, 1) : MP_DIGIT (z, 1)); // Restore sign.
 721          size_t N_mp = SIZE (mode);
 722          PUSH (p, z, N_mp);
 723          INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (mode)));
 724          PUSH_VALUE (p, SIGN (VALUE (&width)) * (ABS (VALUE (&width)) - ABS (VALUE (&expo)) - 1), A68G_INT);
 725          PUSH_VALUE (p, VALUE (&after), A68G_INT);
 726          a68g_bufcpy (s, fixed (p), strwid);
 727          // Exponent.
 728          PUSH_UNION (p, M_INT);
 729          PUSH_VALUE (p, q, A68G_INT);
 730          INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER) - (A68G_UNION_SIZE + SIZE (M_INT)));
 731          PUSH_VALUE (p, VALUE (&expo), A68G_INT);
 732          (void) string_plusab_char (s, EXPONENT_CHAR, strwid);
 733          a68g_bufcat (s, whole (p), strwid);
 734          // Recursion in case of error chars.
 735          if (VALUE (&expo) == 0 || strchr (s, ERROR_CHAR) != NO_TEXT) {
 736            A68G_SP = arg_sp;
 737            // INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 738            PUSH_VALUE (p, VALUE (&width), A68G_INT);
 739            PUSH_VALUE (p, VALUE (&after) != 0 ? VALUE (&after) - 1 : 0, A68G_INT);
 740            PUSH_VALUE (p, VALUE (&expo) > 0 ? VALUE (&expo) + 1 : VALUE (&expo) - 1, A68G_INT);
 741            PUSH_VALUE (p, VALUE (&frmt), A68G_INT);
 742            MP_DIGIT (x, 1) = x1; // Restore original sign.
 743            return real (p);
 744          } else {
 745            A68G_SP = pop_sp;
 746            return s;
 747          }
 748        } else {
 749          char *s = stack_string (p, 8 + ABS (VALUE (&width)));
 750          A68G_SP = pop_sp;
 751          return error_chars (s, VALUE (&width));
 752        }
 753      }
 754    }
 755    ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 756    return NO_TEXT;
 757  }
 758  
 759  
 760  //! @brief Formatted string for NUMBER.
 761  
 762  char *hex (NODE_T *p, BYTE_T *q, int size, int mod, MOID_T *mode)
 763  {
 764    ADDR_T pop_sp = A68G_SP;
 765    char *z = "0123456789abcdef";
 766    char *s = stack_string (p, SMALL_BUFFER_SIZE);
 767    s[0] = NULL_CHAR;
 768    int n = 0;
 769    if (mod < 0) {
 770      a68g_bufcpy (s, moid_to_string (mode, 80, NO_NODE), SMALL_BUFFER_SIZE);
 771      n = strlen (s);
 772      s[n++] = BLANK_CHAR;
 773    }
 774    for (int k = 0, m = 0; k < size; k++) {
 775      int i = size - k - 1;
 776      s[n++] = z[q[i] / 16];
 777      s[n++] = z[q[i] % 16];
 778      m ++;
 779      if (mod != 0) {
 780        if (m % ABS (mod) == 0 && k < size - 1) {
 781          s[n++] = BLANK_CHAR;
 782        }
 783      }
 784    }
 785    s[n] = NULL_CHAR;
 786    A68G_SP = pop_sp;
 787    return s;
 788  }
 789  
 790  
 791  //! @brief Formatted string for NUMBER.
 792  
 793  char *raw_mp (NODE_T *p, MP_T *z, int digs, int mod, MOID_T *mode)
 794  {
 795    ADDR_T pop_sp = A68G_SP;
 796    UNSIGNED_T size = digs * LOG_MP_RADIX + BUFFER_SIZE;
 797    char *s = stack_string (p, size), *fmt, *zfmt;
 798    char d[SMALL_BUFFER_SIZE];
 799    s[0] = NULL_CHAR;
 800    if (mod < 0) {
 801      a68g_bufcpy (s, moid_to_string (mode, 80, NO_NODE), size);
 802      a68g_bufcat (s, " ", size);
 803    }
 804    #if (A68G_LEVEL >= 3)
 805       fmt = "%lld";
 806       zfmt = "%0*lld";
 807    #else
 808       fmt = "%d";
 809       zfmt = "%0*d";
 810    #endif
 811    snprintf (d, SMALL_BUFFER_SIZE, fmt, (MP_INT_T) MP_DIGIT (z, 1));
 812    a68g_bufcat (s, d, size);
 813    if (ABS (mod) == 1 && digs > 1) {
 814      a68g_bufcat (s, " ", size);
 815    }
 816    for (int k = 2; k <= digs; k++) {
 817      snprintf (d, SMALL_BUFFER_SIZE, zfmt, LOG_MP_RADIX, (MP_INT_T) MP_DIGIT (z, k));
 818      a68g_bufcat (s, d, size);
 819      if (ABS (mod) == 1) {
 820        if (k < digs) {
 821          a68g_bufcat (s, " ", size);
 822        }
 823      }
 824    }
 825    a68g_bufcat (s, "e", size);
 826    snprintf (d, SMALL_BUFFER_SIZE, fmt, (MP_INT_T) MP_EXPONENT (z));
 827    a68g_bufcat (s, d, size);
 828    A68G_SP = pop_sp;
 829    snprintf (d, SMALL_BUFFER_SIZE, " N=%d", digs);
 830    a68g_bufcat (s, d, size);
 831    if (A68G_NAN_MP (z)) {
 832      a68g_bufcat (s, " nan", size);
 833    } else if (A68G_PLUS_INF_MP (z)) {
 834      a68g_bufcat (s, " +inf", size);
 835    } else if (A68G_MINUS_INF_MP (z)) {
 836      a68g_bufcat (s, " -inf", size);
 837    }
 838    return s;
 839  }
 840  
 841  
 842  //! @brief Formatted string for NUMBER.
 843  
 844  char *rawout (NODE_T * p)
 845  {
 846    A68G_INT mod;
 847    POP_OBJECT (p, &mod, A68G_INT);
 848    CHECK_INT_SHORTEN (p, VALUE (&mod));
 849    DECREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 850    ADDR_T pop_sp = A68G_SP;
 851    MOID_T *mode = (MOID_T *) (VALUE ((A68G_UNION *) STACK_TOP));
 852    //
 853    if (mode == M_INT) {
 854      INT_T k = VALUE ((A68G_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 855      char *s = hex (p, (BYTE_T *) &k, sizeof (k), VALUE (&mod), mode);
 856      A68G_SP = pop_sp;
 857      return s;
 858    }
 859    if (mode == M_REAL) {
 860      REAL_T z = VALUE ((A68G_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 861      char *s = hex (p, (BYTE_T *) &z, sizeof (z), VALUE (&mod), mode);
 862      A68G_SP = pop_sp;
 863      return s;
 864    }
 865    #if (A68G_LEVEL >= 3)
 866      if (mode == M_LONG_INT) {
 867        DOUBLE_NUM_T k = VALUE ((A68G_LONG_INT *) (STACK_OFFSET (A68G_UNION_SIZE)));
 868        char *s = hex (p, (BYTE_T *) &(k).u, sizeof (DOUBLE_NUM_T), VALUE (&mod), mode);
 869        A68G_SP = pop_sp;
 870        return s;
 871      }
 872      if (mode == M_LONG_REAL) {
 873        DOUBLE_NUM_T z = VALUE ((A68G_LONG_REAL *) (STACK_OFFSET (A68G_UNION_SIZE)));
 874        char *s = hex (p, (BYTE_T *) &(z).f, sizeof (DOUBLE_NUM_T), VALUE (&mod), mode);
 875        A68G_SP = pop_sp;
 876        return s;
 877      }
 878    #endif
 879    if (mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
 880      int digs = DIGITS (mode);
 881      MP_T *z = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
 882      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 883      char *s = raw_mp (p, z, digs, VALUE (&mod), mode);
 884      A68G_SP = pop_sp;
 885      return s;
 886    }
 887    if (mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
 888      int digs = DIGITS (mode);
 889      MP_T *z = (MP_T *) (STACK_OFFSET (A68G_UNION_SIZE));
 890      INCREMENT_STACK_POINTER (p, SIZE (M_NUMBER));
 891      char *s = raw_mp (p, z, digs, VALUE (&mod), mode);
 892      A68G_SP = pop_sp;
 893      return s;
 894    }
 895    ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
 896    return NO_TEXT;
 897  }
     

This website is archived by the National Library of the Netherlands.

© J.M. van der Veer   •   jmvdveer@algol68genie.nl