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


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