code.c

     
   1  //! @file code.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  //! Routines to emit C object code.
  25  
  26  #include <vif.h>
  27  
  28  #undef LIST_IMPLICIT
  29  
  30  #define MAX_UNIQ_STR 5000
  31  static char *uniq_str[MAX_UNIQ_STR];
  32  static int_4 uniq_index[MAX_UNIQ_STR];
  33  static int_4 n_uniq_str = 0;
  34  int_4 n_dc = 0;
  35  
  36  char *idf_full_c_name (RECORD ldf, IDENT *idf)
  37  {
  38    RECCLR (ldf);
  39    if (NOT_LOCAL (idf)) {
  40      bufcpy (ldf, commons[idf->common], RECLN);
  41      if (idf->common == EXTERN) {
  42        bufcat (ldf, "->", RECLN);
  43      } else {
  44        bufcat (ldf, ".", RECLN);
  45      }
  46    }
  47    bufcat (ldf, C_NAME (idf), RECLN);
  48    return ldf;
  49  }
  50  
  51  int_4 code_uniq_str (char *nstr)
  52  {
  53    int_4 k;
  54    for (k = 0; k < n_uniq_str; k++) {
  55      if (strcmp (nstr, uniq_str[k]) == 0) {
  56        return uniq_index[k];
  57      }
  58    }
  59    if (k == MAX_UNIQ_STR) {
  60      OVERFLOW (501, "code_uniq_str");
  61    }
  62    RECORD idf, str;
  63    int_4 rc = n_dc;
  64    uniq_index[n_uniq_str] = rc;
  65    _srecordf (idf, "_dc_%d", n_dc++);
  66    _srecordf (str, "#define %s %s", idf, nstr);
  67    code (0, STRINGS, str);
  68    code (0, STRINGS, "\n");
  69    uniq_str[n_uniq_str++] = f_stralloc (nstr);
  70    return rc;
  71  }
  72  
  73  char *get_uniq_str (char *dc, char *buf)
  74  {
  75    for (int_4 k = 0; k < n_uniq_str; k++) {
  76      RECORD idf;
  77      _srecordf (idf, "_dc_%d", uniq_index[k]);
  78      if (strcmp (idf, dc) == 0) {
  79        int_4 j;
  80        for (j = 1; j < strlen (uniq_str[k]) - 1; j++) {
  81          buf[j - 1] = uniq_str[k][j];
  82        }
  83        buf[j] = '\0';
  84        return buf;
  85      }
  86    }
  87    return NO_TEXT;
  88  }
  89  
  90  int_4 code_real_32_const (char *num)
  91  {
  92    RECORD str;
  93    int_4 rc = n_dc;
  94    _srecordf (str, "real_32 _dc_%d = { // %s\n", n_dc++, curlex);
  95    code (0, CONSTANTS, str);
  96    real_32 x = atox (num);
  97    for (int_4 k = 0; k <= FLT256_LEN; k++) {
  98      if (k < FLT256_LEN) {
  99        _srecordf (str, "0x%04x,", (x.value)[k]);
 100      } else {
 101        _srecordf (str, "0x%04x", (x.value)[k]);
 102      }
 103      code (0, CONSTANTS, str);
 104      if ((k + 1) % 4 == 0) {
 105        code (0, CONSTANTS, "\n");
 106      }
 107    }
 108    code (0, CONSTANTS, "};");
 109    code (0, CONSTANTS, "\n");
 110    code (0, CONSTANTS, "\n");
 111    return rc;
 112  }
 113  
 114  int_4 code (int_4 proc, int_4 phase, char *str)
 115  {
 116    if (n_c_src >= MAX_C_SRC) {
 117      MAX_C_SRC += INCREMENT;
 118      object = (C_SRC *) f_realloc (object, MAX_C_SRC * sizeof (C_SRC));
 119    }
 120  // Add to list.
 121    C_SRC *lin = &object[n_c_src];
 122    int_4 patch = n_c_src;
 123    lin->text = f_stralloc (str);
 124    lin->phase = phase;
 125    lin->proc = proc;
 126    n_c_src++;
 127    return patch;
 128  }
 129  
 130  void cpp_direct (int_4 proc, int_4 lin, int_4 phase)
 131  {
 132    if (!gcc_ftn_lines) {
 133      return;
 134    }
 135    if (source[lin].cpp == FALSE) {
 136      RECORD str;
 137      char *q = source[lin].text;
 138      if (q != NO_TEXT) {
 139        for (int_4 k = 0; q[k] != '\0' && k < 5; k++) {
 140          q++;
 141        }
 142        while (q[0] != '\0' && q[0] == ' ') {
 143          q++;
 144        }
 145        RECORD edit;
 146        int_4 n = 0, m = 0;
 147        while (q[n] != '\0') {
 148          if (q[n] == '"') {
 149            edit[m++] = '\\';
 150          } else if (q[n] == '%') {
 151            edit[m++] = '%';
 152          }
 153          edit[m++] = q[n++];
 154        }
 155        edit[m] = '\0';
 156        RECORD loc;
 157        _srecordf (loc, "** %-10s ** isn %d %s", modnam, source[lin].isn, edit);
 158        _srecordf (str, "# line %d \"%s\"", source[lin].num, loc);
 159        code (proc, phase, str);
 160        if (trace) {
 161          _srecordf (str, "~fprintf (stderr, \"%s\\n\");", loc);
 162          code (proc, phase, str);
 163          code (proc, phase, "\n");
 164        }
 165      }
 166      source[lin].cpp = TRUE;
 167    }
 168  }
 169  
 170  static int_4 idf_code (IDENT *idf, int_4 save, int_4 src)
 171  {
 172  // Must we declare this identifier?
 173    if (idf == NO_IDENT) {
 174      return FALSE; // Oops!
 175    }
 176    if (idf->mode.save != save || idf->source != src) {
 177      return FALSE; // Wrong category
 178    }
 179    if (idf->parm != NO_TEXT) {
 180      return FALSE; // Parameter to subprogram
 181    }
 182    if (idf->external || idf->intrinsic) {
 183      return FALSE; // Otherwise declared
 184    }
 185    if (idf->nest > 0) {
 186      return FALSE; // Macro parameter, declared inline
 187    }
 188    return TRUE;
 189  }
 190  
 191  void code_one_type (IDENT * table, int_4 M, int_4 type, int_4 len, int_4 blck, int_4 proc, int_4 save, int_4 src, int_4 phase)
 192  {
 193    int_4 k, N;
 194    for (k = 0, N = 0; k < M; k++) {
 195      IDENT *idf = &table[k];
 196      if (idf_code (idf, save, src)) {
 197        if (idf->const_ref) {
 198          ;
 199        } else if (idf->alias != NO_IDENT && idf->mode.type == type && idf->mode.len == len) {
 200          N++;
 201        } else if (!idf->arg && idf->mode.type == type && idf->mode.len == len && idf->common == blck) {
 202          N++;
 203        }
 204      }
 205    }
 206    if (N > 0) {
 207      RECORD str;
 208      MODE mode = (MODE) {.type = type,.len = len,.dim = 0 };
 209      if (table == locals && (save == STATIC && src == SOURCE)) {
 210        _srecordf (str, "static %s ", wtype (&mode, NOARG, NOFUN));
 211      } else {
 212        _srecordf (str, "%s ", wtype (&mode, NOARG, NOFUN));
 213      }
 214      code (proc, phase, str);
 215      for (k = 0; k < M; k++) {
 216        IDENT *idf = &table[k];
 217        if (idf_code (idf, save, src)) {
 218          if (idf->const_ref) {
 219            ;
 220          } else if (idf->alias != NO_IDENT && idf->mode.type == type && idf->mode.len == len) {
 221            code (proc, phase, ptr_to_array (idf, NOCONST, NOCAST, ACTUAL));
 222            if (--N > 0) {
 223              code (proc, phase, ", ");
 224            }
 225          } else if (!idf->arg && idf->mode.type == type && idf->mode.len == len && idf->common == blck) {
 226            str[0] = '\0';
 227            if (IS_ROW (idf->mode)) {
 228              RECORD buf;
 229              compute_row_size (buf, idf);
 230              if (EQUAL (buf, "VARY")) {
 231                ERROR (502, "only argument rows can vary", NO_TEXT);
 232              }
 233              _srecordf (str, "%s[%s]", C_NAME (idf), buf);
 234              code (proc, phase, str);
 235            } else {
 236              code (proc, phase, C_NAME (idf));
 237            }
 238            if (--N > 0) {
 239              code (proc, phase, ", ");
 240            }
 241          }
 242        }
 243      }
 244      code (proc, phase, ";\n");
 245    }
 246  }
 247  
 248  void code_idfs (IDENT * table, int_4 M, int_4 blck, int_4 proc, int_4 phase)
 249  {
 250    for (int_4 n = STATIC; n <= AUTOMATIC; n++) {
 251      for (int_4 m = SOURCE; m <= TEMP; m++) {
 252        code_one_type (table, M, INTEGER, 2, blck, proc, n, m, phase);
 253        code_one_type (table, M, INTEGER, 4, blck, proc, n, m, phase);
 254        code_one_type (table, M, INTEGER, 8, blck, proc, n, m, phase);
 255        code_one_type (table, M, LOGICAL, 4, blck, proc, n, m, phase);
 256        code_one_type (table, M, REAL, 4, blck, proc, n, m, phase);
 257        code_one_type (table, M, REAL, 8, blck, proc, n, m, phase);
 258        code_one_type (table, M, REAL, 16, blck, proc, n, m, phase);
 259        code_one_type (table, M, REAL, 32, blck, proc, n, m, phase);
 260        code_one_type (table, M, COMPLEX, 8, blck, proc, n, m, phase);
 261        code_one_type (table, M, COMPLEX, 16, blck, proc, n, m, phase);
 262        code_one_type (table, M, COMPLEX, 32, blck, proc, n, m, phase);
 263        code_one_type (table, M, COMPLEX, 64, blck, proc, n, m, phase);
 264        for (int_4 k = 0, len = 2; k < MAX_STRLENS; k++, len *= 2) {
 265          if (strlens[k]) {
 266            code_one_type (table, M, CHARACTER, len - 1, blck, proc, n, m, phase);
 267          }
 268        }
 269      }
 270    }
 271  }
 272  
 273  void code_common (void)
 274  {
 275    int_4 k;
 276    for (k = EXTERN + 1; k < ncommons; k++) {
 277      RECORD name;
 278      code (0, COMMON, "\n");
 279      _srecordf (name, "// common /%s/\n", commons[k]);
 280      code (0, COMMON, name);
 281      _srecordf (name, "static struct {\n");
 282      code (0, COMMON, name);
 283      code_idfs (globals, nglobals, k, 0, COMMON);
 284      _srecordf (name, "} %s;\n", commons[k]);
 285      code (0, COMMON, name);
 286    }
 287  }
 288  
 289  void code_exts (IDENT * table, int_4 M, int_4 eblck, int_4 proc, int_4 phase)
 290  {
 291    int_4 k;
 292    (void) eblck;
 293    for (k = 0; k < M; k++) {
 294      IDENT *idf = &table[k];
 295      if (idf->external && idf->arg == NOARG) {
 296        if (!find_module (C_NAME (idf))) { // Avoid prototype error.
 297          RECORD str;
 298          MODE *mode = &(idf->mode);
 299          if (!idf->used) {
 300            code (proc, phase, "// ");
 301          }
 302          _srecordf (str, "extern %s %s ();\n", wtype (mode, NOARG, NOFUN), edit_f (C_NAME (idf)));
 303          code (proc, phase, str);
 304        }
 305      }
 306    }
 307  }
 308  
 309  void code_row_len (IDENT * idf)
 310  {
 311    int_4 k, tlen = 1, npack = 0;
 312    RECORD pack, str;
 313    pack[0] = '\0';
 314    for (k = 0; k < idf->mode.dim; k++) {
 315      int_4 len;
 316      if (EQUAL (idf->len[k], "VARY")) {
 317        ERROR (503, "array has varying size", NO_TEXT);
 318      } else if (isint_4 (idf->len[k], &len)) {
 319        tlen *= len;
 320      } else {
 321        if (npack > 0) {
 322          bufcat (pack, " * ", RECLN);
 323        }
 324        bufcat (pack, "(", RECLN);
 325        bufcat (pack, idf->len[k], RECLN);
 326        bufcat (pack, ")", RECLN);
 327        npack++;
 328      }
 329    }
 330    if (tlen == 1 && npack > 0) {
 331      _srecordf (str, "%s", pack);
 332    } else if (npack == 0) {
 333      _srecordf (str, "%d", tlen);
 334    } else {
 335      _srecordf (str, "%d * %s", tlen, pack);
 336    }
 337    code (nprocs, BODY, str);
 338  }
 339  
 340  void proc_listing (int_4 proc)
 341  {
 342    int_4 k, n, l_i, l_f;
 343    RECORD lin;
 344    code (nprocs, SYMBOLS, newpage (modnam, "symbol-table"));
 345  #if defined (LIST_IMPLICIT)
 346  // Implicit modes
 347    strcpy (lin, "//  ");
 348    for (k = ord ('a'); k <= ord ('z'); k++) {
 349      RECORD str;
 350      _srecordf (str, "'%c' %-12s", 'a' + k, qtype (&implic[k].mode));
 351      bufcat (lin, str, RECLN);
 352      if ((k + 1) % 6 == 0) {
 353        bufcat (lin, "\n", RECLN);
 354        code (nprocs, SYMBOLS, lin);
 355        strcpy (lin, "//  ");
 356      }
 357    }
 358    code (nprocs, SYMBOLS, lin);
 359    code (nprocs, SYMBOLS, "\n");
 360  #endif
 361  // Local variables
 362    if (nlocals > 0) {
 363      for (k = 0; k < nlocals; k++) {
 364        IDENT *idf = &locals[k];
 365        if (idf->source != SOURCE || idf->external || idf->intrinsic) {
 366          continue;
 367        }
 368        RECORD str;
 369        _srecordf (lin, "// line %6d %4s %-12s %-8s", idf->line, (idf->mode.save == STATIC ? "save" : "auto"), qtype (&idf->mode), C_NAME (idf));
 370        for (n = 0; n < idf->mode.dim; n++) {
 371          _srecordf (str, " (%s, %s)", idf->lwb[n], idf->upb[n]);
 372          bufcat (lin, str, RECLN);
 373        }
 374        if (idf->parm != NO_TEXT) {
 375          bufcat (lin, " parm", RECLN);
 376        } else if (idf->used) {
 377          bufcat (lin, " used", RECLN);
 378        } else {
 379          bufcat (lin, " idle", RECLN);
 380        }
 381        if (idf->alias != NO_IDENT) {
 382          _srecordf (str, " aliased to %s", C_NAME (idf->alias));
 383          bufcat (lin, str, RECLN);
 384        }
 385        if (idf->equiv != NO_IDENT) {
 386          _srecordf (str, " aliased by %s", C_NAME (idf->equiv));
 387          bufcat (lin, str, RECLN);
 388        }
 389        if (idf->parm != NO_TEXT) {
 390          _srecordf (str, " = %s", idf->parm);
 391          bufcat (lin, str, RECLN);
 392        }
 393        code (nprocs, SYMBOLS, lin);
 394      }
 395      code (nprocs, SYMBOLS, "\n");
 396    }
 397    if (nlabels > 0) {
 398      for (k = 1; k < nlabels; k++) {
 399        LBL *L = &labels[k];
 400        if (L->jumped > 0) {
 401          _srecordf (lin, "// label %5d %5d in line %5d, goto\n", L->index, L->num, L->line);
 402        } else if (L->nonexe) {
 403          _srecordf (lin, "// label %5d %5d in line %5d, non-executable\n", L->index, L->num, L->line);
 404        } else {
 405          _srecordf (lin, "// label %5d %5d in line %5d\n", L->index, L->index, L->line);
 406        }
 407        code (nprocs, SYMBOLS, lin);
 408      }
 409      code (nprocs, SYMBOLS, "\n");
 410    }
 411  // Unclassified comments need a place.
 412    int_4 xproc = nprocs;
 413    int_4 lisn = curlin;
 414    if (source[lisn].isn != 0) {
 415  // If there is next module, delay comments after 'END' to the next module.
 416  // We assume they belong there.
 417      lisn--;
 418      while (lisn >= 0 && source[lisn].isn == 0) {
 419        source[lisn].proc = 0;
 420        lisn--;
 421      }
 422    }
 423  // Now assign comments to a module.
 424    for (k = lisn; k >= 0; k--) {
 425      FTN_LINE *flin = &source[k];
 426      if (xproc > 1 && flin->proc > 0 && flin->proc < xproc) {
 427        xproc = flin->proc;
 428      }
 429      if (flin->text != NO_TEXT && IS_COMMENT (flin->text[0]) && flin->proc == 0) {
 430        flin->proc = xproc;
 431      }
 432    }
 433  //  
 434    l_i = l_f = ERR;
 435    for (k = 1; k < nftnlines && l_i == ERR; k++) {
 436      FTN_LINE *flin = &source[k];
 437      if (flin->proc == proc) {
 438        l_i = k;
 439      }
 440    }
 441    for (k = nftnlines - 1; k >= 1 && l_f == ERR; k--) {
 442      FTN_LINE *flin = &source[k];
 443      if (flin->proc == proc) {
 444        l_f = k;
 445      }
 446    }
 447    code (nprocs, LIST, newpage (modnam, "source-code"));
 448    for (k = l_i; k <= l_f; k++) {
 449      FTN_LINE *flin = &source[k];
 450      if (!flin->jcl) { // JCL is listed elsewhere.
 451        RECORD lrec;
 452        if (flin->isn > 0) {
 453          _srecordf (lrec, "// %6d %6d %s\n", flin->num, flin->isn, flin->text);
 454        } else {
 455          _srecordf (lrec, "// %6d        %s\n", flin->num, flin->text);
 456        }
 457        code (nprocs, LIST, lrec);
 458      }
 459    }
 460  }
 461  
     


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