rts-jit.c

     1  //! @file jit.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  //! Just-in-time compilation of FORMAT strings.
    25  
    26  #include <vif.h>
    27  
    28  #define HEAP_SIZE 8192
    29  #define MAX_ITEMS 256
    30  
    31  static char heap[HEAP_SIZE];
    32  static char *fmtarr[MAX_ITEMS];
    33  static size_t heaptr, arrptr;
    34  
    35  static char *jit_str_list (char *, char *, int *, int *);
    36  
    37  static void jit_error (char *where, char *msg)
    38  {
    39    NEW_RECORD (diag);
    40    _srecordf (diag, "format compiler: %s", msg);
    41    RTE (where, diag);
    42  }
    43  
    44  static char *alloc (char *where, char *elem)
    45  {
    46    size_t N = strlen (elem) + 1;
    47    if ((heaptr + N) >= (HEAP_SIZE - 1)) {
    48      jit_error (where, "heap overflow");
    49      return NO_TEXT;
    50    } else {
    51      char *q = &heap[heaptr];
    52      strcpy (q, elem);
    53      heaptr += N;
    54      return q;
    55    }
    56  }
    57  
    58  static void add_mark (char *where, char *elem)
    59  {
    60    if (arrptr == (MAX_ITEMS - 1)) {
    61      jit_error (where, "too many items");
    62    } else {
    63      fmtarr[arrptr ++] = elem;
    64    }
    65  }
    66  
    67  static void add_item (char *where, char *elem)
    68  {
    69    if (arrptr == (MAX_ITEMS - 1)) {
    70      jit_error (where, "too many items");
    71    } else {
    72      if (elem == NO_TEXT) {
    73        fmtarr[arrptr ++] = NO_TEXT;
    74      } else {
    75        fmtarr[arrptr ++] = alloc (where, elem);
    76      }
    77    }
    78  }
    79  
    80  static void jit_elem (char *where, char *lex, int_4 *elems)
    81  {
    82    NEW_RECORD (rstr);
    83    NEW_RECORD (wstr);
    84    int_4 width, digits, expwid;
    85    if (LEQUAL ("a", lex)) {
    86      if (sscanf (&lex[1], "%d", &width) != 1) {
    87        _srecordf (rstr, "%%s");
    88        _srecordf (wstr, "%%s");
    89      } else if (width < 1) {
    90        jit_error (where, lex);
    91        _srecordf (rstr, "%%s");
    92        _srecordf (wstr, "%%s");
    93      } else {
    94        _srecordf (rstr, "%%%ds", width);
    95        _srecordf (wstr, "%%-%ds", width);
    96      }
    97      add_mark (where, FMT_CHAR);
    98      (*elems)++;
    99    } else if (LEQUAL ("i", lex)) {
   100      if (sscanf (&lex[1], "%d", &width) != 1) {
   101        jit_error (where, "expected width");
   102        _srecordf (rstr, "%%d");
   103        _srecordf (wstr, "%%d");
   104      } else if (width < 1) {
   105        jit_error (where, lex);
   106        _srecordf (rstr, "%%d");
   107        _srecordf (wstr, "%%d");
   108      } else {
   109        _srecordf (rstr, "%%%dd", width);
   110        _srecordf (wstr, "%%%dd", width);
   111      }
   112      add_mark (where, FMT_INT);
   113      (*elems)++;
   114    } else if (LEQUAL ("l", lex)) {
   115      if (sscanf (&lex[1], "%d", &width) != 1) {
   116        jit_error (where, "expected width");
   117        _srecordf (rstr, "%%s");
   118        _srecordf (wstr, "%%s");
   119      } else if (width < 1) {
   120        jit_error (where, lex);
   121        _srecordf (rstr, "%%s");
   122        _srecordf (wstr, "%%s");
   123      } else {
   124        _srecordf (rstr, "%%%ds", width);
   125        _srecordf (wstr, "%%-%ds", width);
   126      }
   127      add_mark (where, FMT_INT);
   128      (*elems)++;
   129    } else if (LEQUAL ("d", lex) || LEQUAL ("e", lex) || LEQUAL ("g", lex) || LEQUAL ("n", lex)) {
   130      width = digits = expwid = 0;
   131      if (sscanf (&lex[1], "%d.%d.%d", &width, &digits, &expwid) == 3) {
   132        ;
   133      } else if (sscanf (&lex[1], "%d.%d", &width, &digits) == 2) {
   134        ;
   135      } else {
   136        jit_error (where, "expected width, decimals, [width]");
   137      }
   138      if (width < 0 || digits < 0) {
   139        jit_error (where, lex);
   140      }
   141  // Reading a REAL - specify width only!
   142      _srecordf (rstr, "%%%de", width);
   143  // Writing a REAL - specify all. 
   144      if (tolower (lex[0]) == 'n') {
   145        if (islower (lex[0])) {
   146          _srecordf (wstr, "%%%d.%d.%dn", width, digits, expwid);
   147        } else {
   148          _srecordf (wstr, "%%%d.%d.%dN", width, digits, expwid);
   149        }
   150      } else {
   151        if (islower (lex[0])) {
   152          _srecordf (wstr, "%%%d.%d.%de", width, digits, expwid);
   153        } else {
   154          _srecordf (wstr, "%%%d.%d.%dE", width, digits, expwid);
   155        }
   156      }
   157      add_mark (where, FMT_REAL);
   158      (*elems)++;
   159    } else if (LEQUAL ("f", lex)) {
   160      sscanf (&lex[1], "%d.%d", &width, &digits);
   161      if (sscanf (&lex[1], "%d.%d", &width, &digits) != 2) {
   162        jit_error (where, "expected width, decimals");
   163        _srecordf (rstr, "%%f");
   164        _srecordf (wstr, "%%f");
   165      } else if (width < 1 || digits < 0) {
   166        jit_error (where, lex);
   167        _srecordf (rstr, "%%f");
   168        _srecordf (wstr, "%%f");
   169      } else {
   170        _srecordf (rstr, "%%%df", width);
   171        _srecordf (wstr, "%%%d.%df", width, digits);
   172      }
   173      add_mark (where, FMT_REAL);
   174      (*elems)++;
   175    } else {
   176      jit_error (where, lex);
   177      rstr[0] = wstr[0] = '\0';
   178      (*elems)++;
   179    }
   180    NEW_RECORD (fstr);
   181    _srecordf (fstr, "%s", rstr);
   182    add_item (where, fstr);
   183    _srecordf (fstr, "%s", wstr);
   184    add_item (where, fstr);
   185  }
   186  
   187  static void jit_scale (char *where, int_4 N)
   188  {
   189    add_mark (where, FMT_TEXT);
   190    add_item (where, "");
   191    if (N == 0) {
   192      add_item (where, "0");
   193    } else if (N == 1) {
   194      add_item (where, "1");
   195    } else if (N == 2) {
   196      add_item (where, "2");
   197    } else if (N == 3) {
   198      add_item (where, "3");
   199    } else {
   200      add_item (where, "1");
   201    }
   202  }
   203  
   204  static void jit_x (char *where, int_4 N)
   205  {
   206    NEW_RECORD (str);
   207    str[0] = '\0';
   208    for (int_4 k = 0; k < N && k < RECLN; k ++) {
   209      bufcat (str, " ", RECLN);
   210    }
   211    add_mark (where, FMT_TEXT);
   212    add_item (where, str);
   213    add_item (where, str);
   214  }
   215  
   216  static void jit_nl (char *where, int_4 N)
   217  {
   218    NEW_RECORD (str);
   219    _srecordf (str, "\\n");
   220    for (int_4 k = 0; k < N; k ++) {
   221      add_mark (where, FMT_TEXT);
   222      add_item (where, str);
   223      add_item (where, str);
   224    }
   225  }
   226  
   227  static void jit_text (char *where, int_4 N, char *lex)
   228  {
   229    for (int_4 k = 0; k < N; k ++) {
   230      add_mark (where, FMT_TEXT);
   231      add_item (where, lex);
   232      add_item (where, lex);
   233    }
   234  }
   235  
   236  static char *jit_str_list (char *where, char *fmt, int *nest, int *elems)
   237  {
   238    #define LETTER(ch) (tolower (fmt[0]) == ch)
   239    if (fmt[0] == '(') {
   240      fmt++;
   241    } else {
   242      jit_error (where, "expected '('"); 
   243    }
   244    while (fmt[0] != ')' && fmt[0] != '\0') {
   245      if (fmt[0] == ',') {
   246        fmt++;
   247      }
   248      while (isspace (fmt[0])) {
   249        fmt++;
   250      }
   251      int_4 N;
   252      if (!isdigit (fmt[0])) {
   253        N = 1;
   254      } else {
   255        char *end;
   256        N = strtol (fmt, &end, 10);
   257        fmt = end;
   258      }
   259      if (LETTER ('p')) {
   260        jit_scale (where, N);
   261        (*elems)++;
   262        fmt++;
   263      } else if (LETTER ('x')) {
   264        jit_x (where, N);
   265        (*elems)++;
   266        fmt++;
   267      } else if (fmt[0] == '/') {
   268        jit_nl (where, N);
   269        (*elems)++;
   270        fmt++;
   271      } else if (LETTER ('h')) {
   272        fmt++;
   273        NEW_RECORD (str);
   274        int_4 k = 0;
   275        for (int_4 M = 0; M < N && fmt[0] != '\0'; M++) {
   276          str[k++] = (fmt++)[0];
   277        }
   278        jit_text (where, 1, str);
   279        (*elems)++;
   280      } else if (fmt[0] == '\"') {
   281        fmt++;
   282        NEW_RECORD (str);
   283        int_4 k = 0;
   284        int_4 go_on = TRUE;
   285        while (go_on) {
   286          if (fmt[0] == '\0') {
   287            go_on = FALSE;
   288          } else if (fmt[0] == '"') {
   289            if ((++fmt)[0] == '"') {
   290              str[k++] = '"';
   291              fmt++;
   292            } else {
   293              go_on = FALSE;
   294            }
   295          } else {
   296            str[k++] = (fmt++)[0];
   297          }
   298        }
   299        jit_text (where, N, str);
   300        (*elems)++;
   301      } else if (fmt[0] == '\'') {
   302        fmt++;
   303        NEW_RECORD (str);
   304        int_4 k = 0;
   305        int_4 go_on = TRUE;
   306        while (go_on) {
   307          if (fmt[0] == '\0') {
   308            go_on = FALSE;
   309          } else if (fmt[0] == '\'') {
   310            if ((++fmt)[0] == '\'') {
   311              str[k++] = '\'';
   312              fmt++;
   313            } else {
   314              go_on = FALSE;
   315            }
   316          } else {
   317            str[k++] = (fmt++)[0];
   318          }
   319        }
   320        jit_text (where, N, str);
   321        (*elems)++;
   322      } else {
   323        for (int_4 k = 0; k < N; k++) {
   324          char *sav = fmt, *rtn = NO_TEXT;
   325          if (fmt[0] == '(') {
   326            (*nest)++;
   327            rtn = jit_str_list (where, fmt, nest, elems);
   328          } else if (fmt[0] == ')') {
   329            break;
   330          } else if (strchr ("adefgiln", tolower (fmt[0])) == NO_TEXT) {
   331            jit_error (where, fmt);
   332          } else {
   333            NEW_RECORD (lex);
   334            char *p = lex;
   335            do {
   336              (p++)[0] = (fmt++)[0];
   337              while (isdigit (fmt[0])) {
   338                (p++)[0] = (fmt++)[0];
   339              }
   340            } while (fmt[0] == '.');
   341            jit_elem (where, lex, elems);
   342          }
   343          if (k < N - 1) {
   344            fmt = sav;
   345          } else if (rtn != NO_TEXT) {
   346            fmt = rtn;
   347          }
   348        }
   349      }
   350    }
   351    if (fmt[0] != ')') {
   352      jit_error (where, "expected ')'"); 
   353      return fmt;
   354    } else if (*nest > 0) {
   355      (*nest)--;
   356    }
   357    return &fmt[1];
   358  #undef LETTER
   359  }
   360  
   361  char **_vif_jit (char *where, char *arg)
   362  {
   363    int_4 nest = 0, elems = 0;
   364    NEW_RECORD (cpy);
   365    fmtarr[0] = NO_TEXT;
   366    heaptr = 0;
   367    arrptr = 0;
   368    strcpy (cpy, arg);
   369    char *fmt = (char *) cpy;
   370    if (fmt[0] == '"') {
   371      fmt++;
   372    }
   373    if (fmt[strlen (fmt) - 1] == '"') {
   374      fmt[strlen (fmt) - 1] = '\0';
   375    }
   376    (void) jit_str_list (where, fmt, &nest, &elems);
   377    if (nest != 0) {
   378      jit_error (where, "unbalanced parentheses");
   379    }
   380    if (elems == 0) {
   381      jit_error (where, "empty format");
   382    }
   383    add_item (where, NO_TEXT);
   384    add_item (where, NO_TEXT);
   385    add_item (where, NO_TEXT);
   386    return fmtarr;
   387  }


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