format.c

     
   1  //! @file format.c
   2  //! @author J. Marcel van der Veer
   3  //
   4  //! @section Copyright
   5  //
   6  // This file is part of VIF - vintage FORTRAN compiler.
   7  // Copyright 2020-2024 J. Marcel van der Veer <algol68g@xs4all.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  //! Compile FORMAT statements.
  25  
  26  #include <vif.h>
  27  
  28  static void format_elem (char *lex, int_4 *elems)
  29  {
  30    if (lex == NULL || strlen (lex) == 0) {
  31      return;
  32    }
  33    RECORD rstr, wstr;
  34    int_4 width, digits, expwid;
  35    if (LEQUAL ("a", lex)) {
  36      if (sscanf (&lex[1], "%d", &width) != 1) {
  37        _srecordf (rstr, "%%s");
  38        _srecordf (wstr, "%%s");
  39      } else if (width < 1) {
  40        SYNTAX (1601, lex);
  41        _srecordf (rstr, "%%s");
  42        _srecordf (wstr, "%%s");
  43      } else {
  44        _srecordf (rstr, "%%%ds", width);
  45        _srecordf (wstr, "%%-%ds", width);
  46      }
  47      code (nprocs, FMT, "FMT_CHAR");
  48      (*elems)++;
  49    } else if (LEQUAL ("i", lex)) {
  50      if (sscanf (&lex[1], "%d", &width) != 1) {
  51        EXPECT (1602, "width");
  52        _srecordf (rstr, "%%d");
  53        _srecordf (wstr, "%%d");
  54      } else if (width < 1) {
  55        SYNTAX (1603, lex);
  56        _srecordf (rstr, "%%d");
  57        _srecordf (wstr, "%%d");
  58      } else {
  59        _srecordf (rstr, "%%%dd", width);
  60        _srecordf (wstr, "%%%dd", width);
  61      }
  62      code (nprocs, FMT, "FMT_INT");
  63      (*elems)++;
  64    } else if (LEQUAL ("l", lex)) {
  65      if (sscanf (&lex[1], "%d", &width) != 1) {
  66        EXPECT (1604, "width");
  67        _srecordf (rstr, "%%s");
  68        _srecordf (wstr, "%%s");
  69      } else if (width < 1) {
  70        SYNTAX (1605, lex);
  71        _srecordf (rstr, "%%s");
  72        _srecordf (wstr, "%%s");
  73      } else {
  74        _srecordf (rstr, "%%%ds", width);
  75        _srecordf (wstr, "%%-%ds", width);
  76      }
  77      code (nprocs, FMT, "FMT_INT");
  78      (*elems)++;
  79    } else if (LEQUAL ("d", lex) || LEQUAL ("e", lex) || LEQUAL ("g", lex) || LEQUAL ("n", lex)) {
  80      width = digits = expwid = 0;
  81      if (sscanf (&lex[1], "%d.%d.%d", &width, &digits, &expwid) == 3) {
  82        ;
  83      } else if (sscanf (&lex[1], "%d.%d", &width, &digits) == 2) {
  84        ;
  85      } else {
  86        EXPECT (1606, "width, decimals, [width]");
  87      }
  88      if (width < 0 || digits < 0) {
  89        SYNTAX (1607, lex);
  90      }
  91  // Reading a REAL - specify width only!
  92      _srecordf (rstr, "%%%de", width);
  93  // Writing a REAL - specify all. 
  94      if (tolower (lex[0]) == 'n') {
  95        if (islower (lex[0])) {
  96          _srecordf (wstr, "%%%d.%d.%dn", width, digits, expwid);
  97        } else {
  98          _srecordf (wstr, "%%%d.%d.%dN", width, digits, expwid);
  99        }
 100      } else {
 101        if (islower (lex[0])) {
 102          _srecordf (wstr, "%%%d.%d.%de", width, digits, expwid);
 103        } else {
 104          _srecordf (wstr, "%%%d.%d.%dE", width, digits, expwid);
 105        }
 106      }
 107      code (nprocs, FMT, "FMT_REAL");
 108      (*elems)++;
 109    } else if (LEQUAL ("f", lex)) {
 110      sscanf (&lex[1], "%d.%d", &width, &digits);
 111      if (sscanf (&lex[1], "%d.%d", &width, &digits) != 2) {
 112        EXPECT (1608, "width, decimals");
 113        _srecordf (rstr, "%%f");
 114        _srecordf (wstr, "%%f");
 115      } else if (width < 1 || digits < 0) {
 116        SYNTAX (1609, lex);
 117        _srecordf (rstr, "%%f");
 118        _srecordf (wstr, "%%f");
 119      } else {
 120        _srecordf (rstr, "%%%df", width);
 121        _srecordf (wstr, "%%%d.%df", width, digits);
 122      }
 123      code (nprocs, FMT, "FMT_REAL");
 124      (*elems)++;
 125    } else {
 126      SYNTAX (1610, lex);
 127      rstr[0] = wstr[0] = '\0';
 128      (*elems)++;
 129    }
 130    RECORD fstr;
 131    code (nprocs, FMT, ", ");
 132    _srecordf (fstr, "\"%s\"", rstr);
 133    code (nprocs, FMT, fstr);
 134    code (nprocs, FMT, ",");
 135    _srecordf (fstr, "\"%s\"", wstr);
 136    code (nprocs, FMT, fstr);
 137    code (nprocs, FMT, ",\n");
 138  }
 139  
 140  static void format_scale (int_4 N)
 141  {
 142    code (nprocs, FMT, "FMT_TEXT,");
 143    code (nprocs, FMT, "\"\"");
 144    code (nprocs, FMT, ",");
 145    if (N == 0) {
 146      code (nprocs, FMT, "\"0\"");
 147    } else if (N == 1) {
 148      code (nprocs, FMT, "\"1\"");
 149    } else if (N == 2) {
 150      code (nprocs, FMT, "\"2\"");
 151    } else if (N == 3) {
 152      code (nprocs, FMT, "\"3\"");
 153    } else {
 154      code (nprocs, FMT, "\"1\"");
 155    }
 156  }
 157  
 158  static void format_x (int_4 N)
 159  {
 160    RECORD idf, str;
 161    str[0] = '\0';
 162    bufcat (str, "\"", RECLN);
 163    for (int_4 k = 0; k < N && k < RECLN; k ++) {
 164      bufcat (str, " ", RECLN);
 165    }
 166    bufcat (str, "\"", RECLN);
 167    _srecordf (idf, "_dc_%d", code_uniq_str (str));
 168    code (nprocs, FMT, "FMT_TEXT,");
 169    code (nprocs, FMT, idf);
 170    code (nprocs, FMT, ",");
 171    code (nprocs, FMT, idf);
 172    code (nprocs, FMT, ",\n");
 173  }
 174  
 175  static void format_nl (int_4 N)
 176  {
 177    RECORD str;
 178    _srecordf (str, "\"\\n\"");
 179    for (int_4 k = 0; k < N; k ++) {
 180      code (nprocs, FMT, "FMT_TEXT,");
 181      code (nprocs, FMT, str);
 182      code (nprocs, FMT, ",");
 183      code (nprocs, FMT, str);
 184      code (nprocs, FMT, ",\n");
 185    }
 186  }
 187  
 188  static void format_text (int_4 N, char *lex)
 189  {
 190    RECORD idf;
 191    _srecordf (idf, "_dc_%d", code_uniq_str (lex));
 192    for (int_4 k = 0; k < N; k ++) {
 193      code (nprocs, FMT, "FMT_TEXT, ");
 194      code (nprocs, FMT, idf);
 195      code (nprocs, FMT, ", ");
 196      code (nprocs, FMT, idf);
 197      code (nprocs, FMT, ",\n");
 198    }
 199  }
 200  
 201  void format_list (int_4 *nest, int_4 *elems)
 202  {
 203    int_4 rc; 
 204    int_4 crd = curlin, col = curcol;
 205    while (WITHIN && (rc = scan_fmt ()) != END_OF_LINE) {
 206      if ((*nest) == 0 && (*elems) == 0 && !TOKEN ("(")) {
 207        SYNTAX (1611, "symbol outside parentheses");
 208      } else if (TOKEN (",")) {
 209        ;
 210      } else {
 211        int_4 k, N;
 212        if (rc != INT_NUMBER) {
 213          N = 1;
 214        } else {
 215          sscanf (curlex, "%d", &N);
 216          crd = curlin;
 217          col = curcol;
 218          rc = scan_fmt ();
 219        }
 220        if (TOKEN ("p")) {
 221          format_scale (N);
 222          code (nprocs, FMT, ",\n");
 223          (*elems)++;
 224        } else if (TOKEN ("x")) {
 225          format_x (N);
 226          (*elems)++;
 227        } else if (TOKEN ("/")) {
 228          format_nl (N);
 229          (*elems)++;
 230        } else if (LEQUAL ("\"", curlex)) {
 231          format_text (N, curlex);
 232          (*elems)++;
 233        } else {
 234          for (k = 0; k < N; k ++) {
 235            if (TOKEN ("(")) {
 236              (*nest) ++;
 237              format_list (nest, elems);
 238              if (k < N - 1) {
 239                curlin = crd;
 240                curcol = col;
 241                rc = scan_fmt ();
 242              }
 243            } else if (TOKEN (")")) {
 244              (*nest) --;
 245              return;
 246            } else {
 247              format_elem (curlex, elems);
 248            }
 249          }
 250        }
 251      }
 252      crd = curlin; col = curcol;
 253    }
 254  }
 255  
 256  char *format_str_list (char *fmt, int_4 *nest, int_4 *elems)
 257  {
 258  #define LETTER(ch) (tolower (fmt[0]) == ch)
 259    if (fmt[0] == '(') {
 260      fmt++;
 261    } else {
 262      EXPECT (1612, "("); 
 263    }
 264    while (fmt[0] != ')' && fmt[0] != '\0') {
 265      if (fmt[0] == ',') {
 266        fmt++;
 267      }
 268      while (isspace (fmt[0])) {
 269        fmt++;
 270      }
 271      int_4 N;
 272      if (!isdigit (fmt[0])) {
 273        N = 1;
 274      } else {
 275        char *end;
 276        N = strtol (fmt, &end, 10);
 277        fmt = end;
 278      }
 279      if (LETTER ('p')) {
 280        format_scale (N);
 281        code (nprocs, FMT, ",\n");
 282        (*elems)++;
 283        fmt++;
 284      } else if (LETTER ('x')) {
 285        format_x (N);
 286        (*elems)++;
 287        fmt++;
 288      } else if (fmt[0] == '/') {
 289        format_nl (N);
 290        (*elems)++;
 291        fmt++;
 292      } else if (LETTER ('h')) {
 293        fmt++;
 294        RECORD str;
 295        RECCLR (str);
 296        int_4 k = 0;
 297        str[k++] = '"';
 298        for (int_4 M = 0; M < N && fmt[0] != '\0'; M++) {
 299          str[k++] = (fmt++)[0];
 300        }
 301        str[k++] = '"';
 302        format_text (1, str);
 303        (*elems)++;
 304      } else if (fmt[0] == '\"') {
 305        fmt++;
 306        RECORD str;
 307        RECCLR (str);
 308        int_4 k = 0;
 309        str[k++] = '"';
 310        int_4 go_on = TRUE;
 311        while (go_on) {
 312          if (fmt[0] == '\0') {
 313            go_on = FALSE;
 314          } else if (fmt[0] == '"') {
 315            if ((++fmt)[0] == '"') {
 316              str[k++] = '"';
 317              fmt++;
 318            } else {
 319              go_on = FALSE;
 320            }
 321          } else {
 322            str[k++] = (fmt++)[0];
 323          }
 324        }
 325        str[k++] = '"';
 326        format_text (N, str);
 327        (*elems)++;
 328      } else if (fmt[0] == '\'') {
 329        fmt++;
 330        RECORD str;
 331        RECCLR (str);
 332        int_4 k = 0;
 333        str[k++] = '"';
 334        int_4 go_on = TRUE;
 335        while (go_on) {
 336          if (fmt[0] == '\0') {
 337            go_on = FALSE;
 338          } else if (fmt[0] == '\'') {
 339            if ((++fmt)[0] == '\'') {
 340              str[k++] = '\'';
 341              fmt++;
 342            } else {
 343              go_on = FALSE;
 344            }
 345          } else {
 346            str[k++] = (fmt++)[0];
 347          }
 348        }
 349        str[k++] = '"';
 350        format_text (N, str);
 351        (*elems)++;
 352      } else {
 353        for (int_4 k = 0; k < N; k++) {
 354          char *sav = fmt, *rtn = NULL;
 355          if (fmt[0] == '(') {
 356            (*nest)++;
 357            rtn = format_str_list (fmt, nest, elems);
 358          } else if (fmt[0] == ')') {
 359            break;
 360          } else if (strchr ("adefgiln", tolower (fmt[0])) == NULL) {
 361            SYNTAX (1613, fmt++);
 362          } else {
 363            RECORD lex;
 364            RECCLR (lex);
 365            char *p = lex;
 366            do {
 367              (p++)[0] = (fmt++)[0];
 368              while (isdigit (fmt[0])) {
 369                (p++)[0] = (fmt++)[0];
 370              }
 371            } while (fmt[0] == '.');
 372            format_elem (lex, elems);
 373          }
 374          if (k < N - 1) {
 375            fmt = sav;
 376          } else if (rtn != NULL) {
 377            fmt = rtn;
 378          }
 379        }
 380      }
 381    }
 382    if (fmt[0] != ')') {
 383      EXPECT (1614, ")"); 
 384      return fmt;
 385    } else if (*nest > 0) {
 386      (*nest)--;
 387    }
 388    return &fmt[1];
 389  #undef LETTER
 390  }
 391  
 392  void format (LBL *statlbl)
 393  {
 394    int_4 nest = 0, elems = 0;
 395    RECORD str;
 396    if (statlbl == NULL) {
 397      SYNTAX (1615, "format without label");
 398    }
 399    code (nprocs, FMT, "\n");
 400    _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (statlbl->num));
 401    code (nprocs, FMT, str);
 402    format_list (&nest, &elems);
 403    code (nprocs, FMT, "NULL, NULL, NULL\n");
 404    code (nprocs, FMT, "};\n");
 405    if (nest != 0) {
 406      SYNTAX (1616, "unbalanced parentheses");
 407    }
 408    if (elems == 0) {
 409      SYNTAX (1617, "empty format");
 410    }
 411    skip_card ();
 412  }
 413  
 414  int_4 format_str (char *fmt)
 415  {
 416    int_4 nest = 0, elems = 0;
 417    int_4 lab = source[curlin].isn + 100000;
 418    RECORD str;
 419    if (fmt[0] == '"') {
 420      fmt++;
 421    }
 422    if (fmt[strlen (fmt) - 1] == '"') {
 423      fmt[strlen (fmt) - 1] = '\0';
 424    }
 425    code (nprocs, FMT, "\n");
 426    _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (lab));
 427    code (nprocs, FMT, str);
 428    (void) format_str_list (fmt, &nest, &elems);
 429    code (nprocs, FMT, "NULL, NULL, NULL\n");
 430    code (nprocs, FMT, "};\n");
 431    if (nest != 0) {
 432      SYNTAX (1618, "unbalanced parentheses");
 433    }
 434    if (elems == 0) {
 435      SYNTAX (1619, "empty format");
 436    }
 437    return lab;
 438  }
     


© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)