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-2025 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.
    25  
    26  #include <vif.h>
    27  
    28  static void format_elem (char *lex, int_4 *elems)
    29  {
    30    if (lex == NO_TEXT || strlen (lex) == 0) {
    31      return;
    32    }
    33    NEW_RECORD (rstr); NEW_RECORD (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 (1801, 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 (1802, "width");
    52        _srecordf (rstr, "%%d");
    53        _srecordf (wstr, "%%d");
    54      } else if (width < 1) {
    55        SYNTAX (1803, 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 (1804, "width");
    67        _srecordf (rstr, "%%s");
    68        _srecordf (wstr, "%%s");
    69      } else if (width < 1) {
    70        SYNTAX (1805, 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 (1806, "width, decimals, [width]");
    87      }
    88      if (width < 0 || digits < 0) {
    89        SYNTAX (1807, 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 (1808, "width, decimals");
   113        _srecordf (rstr, "%%f");
   114        _srecordf (wstr, "%%f");
   115      } else if (width < 1 || digits < 0) {
   116        SYNTAX (1809, 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 (1810, lex);
   127      rstr[0] = wstr[0] = '\0';
   128      (*elems)++;
   129    }
   130    NEW_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    NEW_RECORD (idf); NEW_RECORD (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    NEW_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_term (int_4 N)
   189  {
   190    NEW_RECORD (str);
   191    _srecordf (str, "FMT_TERM");
   192    code (nprocs, FMT, "FMT_TEXT, ");
   193    code (nprocs, FMT, str);
   194    code (nprocs, FMT, ", ");
   195    code (nprocs, FMT, str);
   196    code (nprocs, FMT, ",\n");
   197  }
   198  
   199  static void format_text (int_4 N, char *lex)
   200  {
   201    NEW_RECORD (idf);
   202    _srecordf (idf, "_dc_%d", code_uniq_str (lex));
   203    for (int_4 k = 0; k < N; k ++) {
   204      code (nprocs, FMT, "FMT_TEXT, ");
   205      code (nprocs, FMT, idf);
   206      code (nprocs, FMT, ", ");
   207      code (nprocs, FMT, idf);
   208      code (nprocs, FMT, ",\n");
   209    }
   210  }
   211  
   212  void format_list (int_4 *nest, int_4 *elems)
   213  {
   214  #define LETTER(ch) (tolower (curlex[0]) == ch)
   215    int_4 rc; 
   216    int_4 crd = curlin, col = curcol;
   217    while (WITHIN && (rc = scan_fmt ()) != END_OF_LINE) {
   218      if ((*nest) == 0 && (*elems) == 0 && !TOKEN ("(")) {
   219        SYNTAX (1811, "symbol outside parentheses");
   220      } else if (TOKEN (",")) {
   221        ;
   222      } else {
   223        int_4 k, N;
   224        if (rc != INT_NUMBER) {
   225          N = 1;
   226        } else {
   227          sscanf (curlex, "%d", &N);
   228          crd = curlin;
   229          col = curcol;
   230          rc = scan_fmt ();
   231        }
   232        if (LETTER ('p')) {
   233          format_scale (N);
   234          code (nprocs, FMT, ",\n");
   235          (*elems)++;
   236          curlin = crd;
   237          curcol = col + 1; // continue after 'P'
   238        } else if (TOKEN ("x")) {
   239          format_x (N);
   240          (*elems)++;
   241        } else if (TOKEN (":")) {
   242          format_term (N);
   243          (*elems)++;
   244        } else if (TOKEN ("/")) {
   245          format_nl (N);
   246          (*elems)++;
   247        } else if (LEQUAL ("\"", curlex)) {
   248          format_text (N, curlex);
   249          (*elems)++;
   250        } else {
   251          for (k = 0; k < N; k ++) {
   252            if (TOKEN ("(")) {
   253              (*nest) ++;
   254              format_list (nest, elems);
   255              if (k < N - 1) {
   256                curlin = crd;
   257                curcol = col;
   258                rc = scan_fmt ();
   259              }
   260            } else if (TOKEN (")")) {
   261              (*nest) --;
   262              return;
   263            } else {
   264              format_elem (curlex, elems);
   265            }
   266          }
   267        }
   268      }
   269      crd = curlin; col = curcol;
   270    }
   271  #undef LETTER
   272  }
   273  
   274  char *format_str_list (char *fmt, int_4 *nest, int_4 *elems)
   275  {
   276  #define LETTER(ch) (tolower (fmt[0]) == ch)
   277    if (fmt[0] == '(') {
   278      fmt++;
   279    } else {
   280      EXPECT (1812, "("); 
   281    }
   282    while (fmt[0] != ')' && fmt[0] != '\0') {
   283      if (fmt[0] == ',') {
   284        fmt++;
   285      }
   286      while (isspace (fmt[0])) {
   287        fmt++;
   288      }
   289      int_4 N;
   290      if (!isdigit (fmt[0])) {
   291        N = 1;
   292      } else {
   293        char *end;
   294        N = strtol (fmt, &end, 10);
   295        fmt = end;
   296      }
   297      if (LETTER ('p')) {
   298        format_scale (N);
   299        code (nprocs, FMT, ",\n");
   300        (*elems)++;
   301        fmt++;
   302      } else if (LETTER ('x')) {
   303        format_x (N);
   304        (*elems)++;
   305        fmt++;
   306      } else if (fmt[0] == ':') {
   307        format_term (N);
   308        (*elems)++;
   309        fmt++;
   310      } else if (fmt[0] == '/') {
   311        format_nl (N);
   312        (*elems)++;
   313        fmt++;
   314      } else if (LETTER ('h')) {
   315        fmt++;
   316        NEW_RECORD (str);
   317        int_4 k = 0;
   318        str[k++] = '"';
   319        for (int_4 M = 0; M < N && fmt[0] != '\0'; M++) {
   320          str[k++] = (fmt++)[0];
   321        }
   322        str[k++] = '"';
   323        format_text (1, str);
   324        (*elems)++;
   325      } else if (fmt[0] == '\"') {
   326        fmt++;
   327        NEW_RECORD (str);
   328        int_4 k = 0;
   329        str[k++] = '"';
   330        int_4 go_on = TRUE;
   331        while (go_on) {
   332          if (fmt[0] == '\0') {
   333            go_on = FALSE;
   334          } else if (fmt[0] == '"') {
   335            if ((++fmt)[0] == '"') {
   336              str[k++] = '"';
   337              fmt++;
   338            } else {
   339              go_on = FALSE;
   340            }
   341          } else {
   342            str[k++] = (fmt++)[0];
   343          }
   344        }
   345        str[k++] = '"';
   346        format_text (N, str);
   347        (*elems)++;
   348      } else if (fmt[0] == '\'') {
   349        fmt++;
   350        NEW_RECORD (str);
   351        int_4 k = 0;
   352        str[k++] = '"';
   353        int_4 go_on = TRUE;
   354        while (go_on) {
   355          if (fmt[0] == '\0') {
   356            go_on = FALSE;
   357          } else if (fmt[0] == '\'') {
   358            if ((++fmt)[0] == '\'') {
   359              str[k++] = '\'';
   360              fmt++;
   361            } else {
   362              go_on = FALSE;
   363            }
   364          } else {
   365            str[k++] = (fmt++)[0];
   366          }
   367        }
   368        str[k++] = '"';
   369        format_text (N, str);
   370        (*elems)++;
   371      } else {
   372        for (int_4 k = 0; k < N; k++) {
   373          char *sav = fmt, *rtn = NO_TEXT;
   374          if (fmt[0] == '(') {
   375            (*nest)++;
   376            rtn = format_str_list (fmt, nest, elems);
   377          } else if (fmt[0] == ')') {
   378            break;
   379          } else if (strchr ("adefgiln", tolower (fmt[0])) == NO_TEXT) {
   380            SYNTAX (1813, fmt++);
   381          } else {
   382            NEW_RECORD (lex);
   383            char *p = lex;
   384            do {
   385              (p++)[0] = (fmt++)[0];
   386              while (isdigit (fmt[0])) {
   387                (p++)[0] = (fmt++)[0];
   388              }
   389            } while (fmt[0] == '.');
   390            format_elem (lex, elems);
   391          }
   392          if (k < N - 1) {
   393            fmt = sav;
   394          } else if (rtn != NO_TEXT) {
   395            fmt = rtn;
   396          }
   397        }
   398      }
   399    }
   400    if (fmt[0] != ')') {
   401      EXPECT (1814, ")"); 
   402      return fmt;
   403    } else if (*nest > 0) {
   404      (*nest)--;
   405    }
   406    return &fmt[1];
   407  #undef LETTER
   408  }
   409  
   410  void format (LBL *statlbl)
   411  {
   412    int_4 nest = 0, elems = 0;
   413    NEW_RECORD (str);
   414    if (statlbl == NO_LABEL) {
   415      SYNTAX (1815, "format without label");
   416    }
   417    code (nprocs, FMT, "\n");
   418    _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (statlbl->num));
   419    code (nprocs, FMT, str);
   420    format_list (&nest, &elems);
   421    code (nprocs, FMT, "NULL, NULL, NULL\n");
   422    code (nprocs, FMT, "};\n");
   423    if (nest != 0) {
   424      SYNTAX (1816, "unbalanced parentheses");
   425    }
   426    if (elems == 0) {
   427      SYNTAX (1817, "empty format");
   428    }
   429    skip_card (FALSE);
   430  }
   431  
   432  int_4 format_str (char *fmt)
   433  {
   434    int_4 nest = 0, elems = 0;
   435    int_4 lab = CUR_LIN.isn + 100000;
   436    NEW_RECORD (str);
   437    if (fmt[0] == '"') {
   438      fmt++;
   439    }
   440    if (fmt[strlen (fmt) - 1] == '"') {
   441      fmt[strlen (fmt) - 1] = '\0';
   442    }
   443    code (nprocs, FMT, "\n");
   444    _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (lab));
   445    code (nprocs, FMT, str);
   446    (void) format_str_list (fmt, &nest, &elems);
   447    code (nprocs, FMT, "NULL, NULL, NULL\n");
   448    code (nprocs, FMT, "};\n");
   449    if (nest != 0) {
   450      SYNTAX (1818, "unbalanced parentheses");
   451    }
   452    if (elems == 0) {
   453      SYNTAX (1819, "empty format");
   454    }
   455    return lab;
   456  }


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