renum.c

     
   1  //! @file renum.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  //! Vintage Fortran statement renumbering tool.
  25  //
  26  // I wrote a first version in Pascal, in the 1980's.
  27  // That explains the unity lower bounds in this code.
  28  
  29  #include <vif.h>
  30  
  31  #define MODLEN 5000 // Max size of a subprogram
  32  
  33  typedef RECORD DECK[MODLEN];
  34  
  35  static RECORD name;
  36  
  37  static int_4 routines, errors;
  38  static int_4 old_label[MODLEN];
  39  
  40  static void renum_jcl (RECORD *b, int_4 *flin, int_4 *size)
  41  {
  42    if (b[*flin - 1][0] == '/' && b[*flin - 1][1] == '*') {
  43      return;
  44    } else if (b[*flin - 1][0] == '/' && b[*flin - 1][1] == '/') {
  45      RECORD step, snam, oper, parm;
  46      int_4 k = 0, l = 2, N = 0, fn;
  47  // Parse step and snam field.
  48      RECCLR (step);
  49      RECCLR (snam);
  50      RECCLR (oper);
  51      RECCLR (parm);
  52      while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (snam) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
  53        snam[k++] = tolower (b[*flin - 1][l]);
  54        l++;
  55        N++;
  56      }
  57      if (b[*flin - 1][l] == '.') {
  58        strcpy (step, snam);
  59        l++;
  60        k = 0;
  61        N = 0;
  62        while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (snam) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
  63          snam[k++] = tolower (b[*flin - 1][l]);
  64          l++;
  65          N++;
  66        }
  67      }
  68  // Parse operation field.
  69      while (isspace (b[*flin - 1][l])) {
  70        l++;
  71      }
  72      k = 0;
  73      while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (oper) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
  74        oper[k++] = tolower (b[*flin - 1][l]);
  75        l++;
  76        N++;
  77      }
  78  // Parse parameter field.
  79      while (isspace (b[*flin - 1][l])) {
  80        l++;
  81      }
  82      k = 0;
  83      while (N <= RECLN && b[*flin - 1][l] != '\0' && isprint (b[*flin - 1][l])) {
  84        parm[k++] = b[*flin - 1][l];
  85        l++;
  86        N++;
  87      }
  88  // Match FT..F001.
  89      if (sscanf(snam, "ft%02df001", &fn) == 1 && LEQUAL ("dd", oper)) {
  90        if (LEQUAL ("*", parm)) {
  91          while (*flin <= *size && !LEQUAL ("/*", b[*flin - 1])) {
  92            (*flin)++;
  93          }
  94        }
  95      }
  96    }
  97  }
  98  
  99  static int_4 P_eof (FILE * f)
 100  {
 101    if (feof (f)) {
 102      return TRUE;
 103    }
 104    int_4 ch = getc (f);
 105    if (ch == EOF) {
 106      return TRUE;
 107    }
 108    ungetc (ch, f);
 109    return FALSE;
 110  }
 111  
 112  static int_4 P_eoln (FILE *f)
 113  {
 114    int_4 ch = getc (f);
 115    if (ch == EOF) {
 116      return TRUE;
 117    }
 118    ungetc (ch, f);
 119    return (ch == '\n');
 120  }
 121  
 122  static void write_sym (char *s)
 123  {
 124    for (int_4 i = 1; i <= RECLN && s[i - 1] != ' '; i++) {
 125      putchar (s[i - 1]);
 126    }
 127    putchar ('\n');
 128  }
 129  
 130  static void cram_symbol (char *b, char *s)
 131  {
 132    RECCLR (s);
 133    for (int_4 i = 0, j = 0; i <= RECLN; i++) {
 134      if (b[i] != ' ') {
 135        s[j++] = b[i];
 136      }
 137    }
 138  }
 139  
 140  static int_4 blank_card (char *a)
 141  {
 142    int_4 eq = TRUE;
 143    for (int_4 i = 0; i <= RECLN; i++) {
 144      eq = (eq && a[i] == ' ');
 145    }
 146    return eq;
 147  }
 148  
 149  static void fill_buffer (FILE **f, RECORD *fsrc, int_4 *i)
 150  {
 151    int_4 j, kontinue = TRUE;
 152    RECORD current_card, s;
 153    RECCLR (s);
 154    *i = 0;
 155    while (kontinue) {
 156      if (P_eof (*f) || *i >= MODLEN) {
 157        continue;
 158      }
 159      memset (current_card, ' ', RECLN);
 160      j = 0;
 161      while (!P_eoln (*f) && j <= RECLN) {
 162        j++;
 163        current_card[j - 1] = getc (*f);
 164        if (current_card[j - 1] == '\n') {
 165          current_card[j - 1] = ' ';
 166        }
 167      }
 168      cram_symbol (current_card, s);
 169      kontinue = !EQUAL (s, "end");
 170      if (!blank_card (current_card)) {
 171        (*i)++;
 172        for (j = 0; j <= RECLN; j++) {
 173          fsrc[*i - 1][j] = current_card[j];
 174        }
 175      }
 176      (void) fscanf (*f, "%*[^\n]");
 177      getc (*f);
 178      if (P_eof (*f)) {
 179        kontinue = FALSE;
 180      }
 181    }
 182  }
 183  
 184  static void write_buffer (FILE **f, RECORD *fsrc, int_4 size)
 185  {
 186    int_4 i, j, last;
 187  
 188    if (routines > 1) {
 189      putc ('\n', *f);
 190    }
 191    for (i = 0; i < size; i++) {
 192      last = strlen (fsrc[i]);
 193      while (last > 0 && fsrc[i][last - 1] == ' ') {
 194        last--;
 195      }
 196      for (j = 0; j < last; j++) {
 197        putc (fsrc[i][j], *f);
 198      }
 199      putc ('\n', *f);
 200    }
 201    fflush (*f);
 202  }
 203  
 204  static int_4 isidchar (char c)
 205  {
 206    return (isalpha (c) || c == '$');
 207  }
 208  
 209  static int_4 isspecial (char c)
 210  {
 211    return (((!isidchar (c)) & (!isdigit (c))) && c != ' ');
 212  }
 213  
 214  static int_4 read_label (RECORD *b, int_4 *flin, int_4 *size)
 215  {
 216    int_4 signif, labval, column, digit;
 217  
 218    if (IS_JCL ((b[*flin - 1][0]))) {
 219      renum_jcl (b, flin, size);
 220      return 0;
 221    } else if (IS_COMMENT ((b[*flin - 1][0]))) {
 222      return 0;
 223    } else {
 224      signif = 1;
 225      column = 5;
 226      labval = 0;
 227      while (column != 0) {
 228        if (isdigit (b[*flin - 1][column - 1])) {
 229          digit = b[*flin - 1][column - 1] - '0';
 230          labval += signif * digit;
 231          signif *= 10;
 232        }
 233        column--;
 234      }
 235      return labval;
 236    }
 237  }
 238  
 239  static void write_label (RECORD *b, int_4 flin, int_4 lab)
 240  {
 241    int_4 i, digit;
 242    int_4 column = 5, labval = lab;
 243  
 244    do {
 245      i = labval / 10;
 246      digit = labval - i * 10;
 247      labval = i;
 248      b[flin - 1][column - 1] = (char) (digit + '0');
 249      column--;
 250    } while (labval != 0);
 251    while (column != 0) {
 252      b[flin - 1][column - 1] = ' ';
 253      column--;
 254    }
 255  }
 256  
 257  static void replace_label (RECORD *b, int_4 *flin, int_4 *first, int_4 *last, int_4 lab)
 258  {
 259    int_4 i;
 260    int_4 j = 0;
 261    int_4 k, digit, labval, FORLIM;
 262  
 263    FORLIM = RECLN - *last;
 264    for (i = 1; i <= FORLIM; i++) {
 265      b[*flin - 1][*first + i - 1] = b[*flin - 1][*last + i - 2];
 266    }
 267    *last = *first + 1;
 268    labval = lab;
 269    do {
 270      j++;
 271      i = labval / 10;
 272      digit = labval - i * 10;
 273      labval = i;
 274      b[*flin - 1][*first - 1] = (char) (digit + '0');
 275      if (labval != 0) {
 276        FORLIM = *first;
 277        for (k = RECLN - 1; k >= FORLIM; k--) {
 278          b[*flin - 1][k] = b[*flin - 1][k - 1];
 279        }
 280        (*last)++;
 281      }
 282    } while (labval != 0);
 283  }
 284  
 285  static void advance (RECORD *b, int_4 *eol, int_4 *cont, int_4 *flin, int_4 *column, int_4 *size)
 286  {
 287    if (*column != RECLN) {
 288      (*column)++;
 289      return;
 290    }
 291    do {
 292      if (*flin == *size) {
 293        *cont = FALSE;
 294      } else {
 295        (*flin)++;
 296      }
 297    } while (IS_COMMENT ((*b[*flin - 1])) && *cont);
 298    if (!*cont) {
 299      *column = 1;
 300      *eol = TRUE;
 301      return;
 302    }
 303    if (b[*flin - 1][5] != ' ') {
 304      *column = 7;
 305      return;
 306    }
 307    *column = 1;
 308    *eol = TRUE;
 309    *cont = FALSE;
 310  }
 311  
 312  static void scan_symbol (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
 313  {
 314    int_4 i, cont = TRUE;
 315    *eol = FALSE;
 316    memset (s, ' ', RECLN);
 317    while (b[*flin - 1][*column - 1] == ' ' && cont) {
 318      advance (b, eol, &cont, flin, column, size);
 319    }
 320    if (cont && b[*flin - 1][*column - 1] == '\'') {
 321      do {
 322        advance (b, eol, &cont, flin, column, size);
 323        while (cont && b[*flin - 1][*column - 1] != '\'') {
 324          advance (b, eol, &cont, flin, column, size);
 325        }
 326        advance (b, eol, &cont, flin, column, size);
 327      } while (cont && b[*flin - 1][*column - 1] == '\'');
 328    }
 329    *first = *column;
 330    i = 0;
 331    if (cont & isidchar (b[*flin - 1][*column - 1])) {
 332      while ((isidchar (b[*flin - 1][*column - 1]) || isdigit (b[*flin - 1][*column - 1])) && cont) {
 333        i++;
 334        s[i - 1] = b[*flin - 1][*column - 1];
 335        advance (b, eol, &cont, flin, column, size);
 336      }
 337  // Provision for 'endif' or 'end if' etcetera.
 338      if (tolower (s[0]) == 'e' && tolower (s[1]) == 'n' && tolower (s[2]) == 'd') {
 339        while (b[*flin - 1][*column - 1] == ' ' && cont) {
 340          advance (b, eol, &cont, flin, column, size);
 341        }
 342        while (isidchar (b[*flin - 1][*column - 1]) && cont) {
 343          i++;
 344          s[i - 1] = b[*flin - 1][*column - 1];
 345          advance (b, eol, &cont, flin, column, size);
 346        }
 347      }
 348      s[i] = '\0';
 349      cont = FALSE;
 350    }
 351    if (cont && isdigit (b[*flin - 1][*column - 1])) {
 352      while (isdigit (b[*flin - 1][*column - 1]) && cont) {
 353        i++;
 354        s[i - 1] = b[*flin - 1][*column - 1];
 355        advance (b, eol, &cont, flin, column, size);
 356      }
 357      s[i] = '\0';
 358      cont = FALSE;
 359    }
 360    if (!(cont & isspecial (b[*flin - 1][*column - 1]))) {
 361      return;
 362    }
 363    s[0] = b[*flin - 1][*column - 1];
 364    advance (b, eol, &cont, flin, column, size);
 365    s[1] = '\0';
 366    cont = FALSE;
 367  }
 368  
 369  static int_4 new_label (char *c)
 370  {
 371    int_4 flin = 1;
 372    int_4 labval = atoi (c);
 373    while (old_label[flin - 1] != labval && flin < MODLEN) {
 374      flin++;
 375    }
 376    if (flin < MODLEN) {
 377      return flin;
 378    }
 379    message (NO_FTN_LINE, ERR, "error", 0, "undefined label", c);
 380    errors++;
 381    return 0;
 382  }
 383  
 384  static void skip_to_comma (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
 385  {
 386    int_4 nest = 0;
 387    while (! (s[0] == ',' && nest == 0)) {
 388      scan_symbol (b, s, eol, flin, column, first, size);
 389      if (s[0] == '(') {
 390        nest++;
 391      } else if (s[0] == ')') {
 392        if (nest == 0) {
 393          return;
 394        } else {
 395          nest--;
 396        }
 397      }
 398    }
 399  }
 400  
 401  static void relabel_io (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
 402  {
 403    scan_symbol (b, s, eol, flin, column, first, size);
 404    if (s[0] == '*') {
 405  // print_4 *, ...
 406      ;
 407    } else if (isdigit (s[0])) {
 408  // print_4 10, ...
 409      replace_label (b, flin, first, column, new_label (s));
 410    } else if (s[0] == '(') {
 411  // print_4 (UNIT [,FMT=n],FILE=expr][,FORM=str][,ACTION=str][,DISP=str][,END=n][,ERR=n])
 412      int_4 pos = 0;
 413      do {
 414        pos++;
 415        scan_symbol (b, s, eol, flin, column, first, size);
 416        if (s[0] == ',') {
 417            ;
 418        } else if (EQUAL (s, ")")) {
 419          return;
 420        } else if (EQUAL (s, "access")) {
 421          skip_to_comma (b, s, eol, flin, column, first, size);
 422        } else if (EQUAL (s, "action")) {
 423          skip_to_comma (b, s, eol, flin, column, first, size);
 424        } else if (EQUAL (s, "disp")) {
 425          skip_to_comma (b, s, eol, flin, column, first, size);
 426        } else if (EQUAL (s, "file")) {
 427          skip_to_comma (b, s, eol, flin, column, first, size);
 428        } else if (EQUAL (s, "form")) {
 429          skip_to_comma (b, s, eol, flin, column, first, size);
 430        } else if (EQUAL (s, "fmt") || EQUAL (s, "end") || EQUAL (s, "err")) {
 431          scan_symbol (b, s, eol, flin, column, first, size);
 432          scan_symbol (b, s, eol, flin, column, first, size);
 433          replace_label (b, flin, first, column, new_label (s));
 434          scan_symbol (b, s, eol, flin, column, first, size);
 435        } else if (isdigit (s[0]) && pos == 2) {
 436          replace_label (b, flin, first, column, new_label (s));
 437          scan_symbol (b, s, eol, flin, column, first, size);
 438        } else {
 439          skip_to_comma (b, s, eol, flin, column, first, size);
 440        }
 441      } while (s[0] == ',');
 442    }
 443  }
 444  
 445  static void relabel_goto (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
 446  {
 447    do {
 448      scan_symbol (b, s, eol, flin, column, first, size);
 449      replace_label (b, flin, first, column, new_label (s));
 450      scan_symbol (b, s, eol, flin, column, first, size);
 451    } while (s[0] != ')');
 452  }
 453  
 454  static logical_4 relabel_statement (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
 455  {
 456    if (EQUAL (s, "do")) {
 457      scan_symbol (b, s, eol, flin, column, first, size);
 458      if (isdigit (s[0])) {
 459        replace_label (b, flin, first, column, new_label (s));
 460      }
 461      return TRUE;
 462    }
 463    if (EQUAL (s, "assign")) {
 464      scan_symbol (b, s, eol, flin, column, first, size);
 465      replace_label (b, flin, first, column, new_label (s));
 466      return TRUE;
 467    }
 468    if (EQUAL (s, "read") || EQUAL (s, "accept")) {
 469      relabel_io (b, s, eol, flin, column, first, size);
 470      return TRUE;
 471    }
 472    if (EQUAL (s, "write") || EQUAL (s, "print") || EQUAL (s, "punch")) {
 473      relabel_io (b, s, eol, flin, column, first, size);
 474      return TRUE;
 475    }
 476    if (EQUAL (s, "goto") || EQUAL (s, "go")) {
 477      if (EQUAL (s, "go")) {
 478        scan_symbol (b, s, eol, flin, column, first, size);
 479      }
 480      scan_symbol (b, s, eol, flin, column, first, size);
 481      if (s[0] == '(') {
 482        relabel_goto (b, s, eol, flin, column, first, size);
 483      } else if (isalpha (s[0])) {
 484        scan_symbol (b, s, eol, flin, column, first, size);
 485        if (s[0] == ',') {
 486          scan_symbol (b, s, eol, flin, column, first, size);
 487        }
 488        relabel_goto (b, s, eol, flin, column, first, size);
 489      } else {
 490        replace_label (b, flin, first, column, new_label (s));
 491      }
 492      return TRUE;
 493    }
 494    if (EQUAL (s, "if")) {
 495      scan_symbol (b, s, eol, flin, column, first, size);
 496      int_4 nest = 1;
 497      do {
 498        scan_symbol (b, s, eol, flin, column, first, size);
 499        if (s[0] == '(') {
 500          nest++;
 501        } else if (s[0] == ')') {
 502          nest--;
 503        }
 504      } while (nest != 0);
 505      scan_symbol (b, s, eol, flin, column, first, size);
 506      if (isdigit (s[0])) {
 507        replace_label (b, flin, first, column, new_label (s));
 508        scan_symbol (b, s, eol, flin, column, first, size);
 509        scan_symbol (b, s, eol, flin, column, first, size);
 510        replace_label (b, flin, first, column, new_label (s));
 511        scan_symbol (b, s, eol, flin, column, first, size);
 512        if (EQUAL (s, ",")) {
 513          scan_symbol (b, s, eol, flin, column, first, size);
 514          replace_label (b, flin, first, column, new_label (s));
 515        }
 516      } else if (EQUAL (s, "goto") | EQUAL (s, "go")) {
 517        relabel_statement (b, s, eol, flin, column, first, size);
 518      } else if (EQUAL (s, "read") || EQUAL (s, "accept")) {
 519        relabel_statement (b, s, eol, flin, column, first, size);
 520      } else if (EQUAL (s, "write") || EQUAL (s, "print") || EQUAL (s, "punch")) {
 521        relabel_statement (b, s, eol, flin, column, first, size);
 522      } else if (EQUAL (s, "assign")) {
 523        relabel_statement (b, s, eol, flin, column, first, size);
 524      }
 525      return TRUE;
 526    }
 527  
 528    return FALSE;
 529  }
 530  
 531  static void scan_statement (RECORD *b, int_4 size)
 532  {
 533    RECORD s;
 534    RECCLR (s);
 535    int_4 eol = FALSE, column, first;
 536    int_4 flin = 1;
 537    do {
 538      column = 1;
 539      do {
 540        if (flin > size) {
 541          eol = TRUE;
 542          flin = size;
 543        }
 544        if (IS_JCL (b[flin -1][0])) {
 545          renum_jcl (b, &flin, &size);
 546          flin++;
 547        } else {
 548          scan_symbol (b, s, &eol, &flin, &column, &first, &size);
 549          if (relabel_statement (b, s, &eol, &flin, &column, &first, &size)) {
 550            /* skip */;
 551          }
 552        }
 553      } while (!eol);
 554    } while (flin < size);
 555  }
 556  
 557  static void scan_name (RECORD *b, int_4 size, char *n)
 558  {
 559    RECORD s;
 560    int_4 eol, column, first, i;
 561  
 562    int_4 flin = 1;
 563    memset (n, ' ', RECLN);
 564    memcpy (n, "anonymous", 9);
 565    do {
 566      column = 1;
 567      if (IS_COMMENT (*(b[flin - 1]))) {
 568        flin++;
 569      } else {
 570        do {
 571          scan_symbol (b, s, &eol, &flin, &column, &first, &size);
 572          if (EQUAL (s, "end")) {
 573            eol = TRUE;
 574            flin = size;
 575          } else if (EQUAL (s, "program") || EQUAL (s, "subroutine") || EQUAL (s, "function")) {
 576            memset (n, ' ', RECLN);
 577            scan_symbol (b, s, &eol, &flin, &column, &first, &size);
 578            i = 1;
 579            while (i <= RECLN && s[i - 1] != '\0') {
 580              n[i - 1] = tolower (s[i - 1]);
 581              i++;
 582            }
 583          }
 584        } while (!eol);
 585      }
 586    } while (flin < size);
 587  }
 588  
 589  void relabel (char *fname)
 590  {
 591    RECORD gname;
 592    FILE *infile, *outfile;
 593    int_4 number;
 594    static DECK fsrc;
 595    RECCLR (gname);
 596    if ((infile = fopen (fname, "r")) == NO_FILE) {
 597      FATAL (2501, "cannot open", fname);
 598    };
 599    strcpy (gname, fname);
 600    for (int_4 k = (int_4) strlen (gname); k >= 0; k--) {
 601      if (gname[k] == '.') {
 602        gname[k] = '\0';
 603        break;
 604      }
 605    }
 606  //
 607    strcat (gname, ".f~");
 608    if ((outfile = fopen (gname, "w")) == NO_FILE) {
 609      FATAL (2502, "cannot open", gname);
 610    };
 611  //
 612    routines = 0;
 613    errors = 0;
 614    do {
 615      int_4 size;
 616      fill_buffer (&infile, fsrc, &size);
 617      if (size > 0) {
 618        for (int_4 i = 1; i <= size; i++) {
 619          old_label[i - 1] = 0;
 620        }
 621        number = 0;
 622        int_4 flin = 1;
 623        while (flin <= size) {
 624          int_4 labval = read_label (fsrc, &flin, &size);
 625          if (labval != 0) {
 626            number++;
 627            write_label (fsrc, flin, number);
 628            old_label[number - 1] = labval;
 629          }
 630          flin++;
 631        }
 632        if (number == 0) {
 633          write_buffer (&outfile, fsrc, size);
 634        } else {
 635          routines++;
 636          scan_name (fsrc, size, name);
 637          scan_statement (fsrc, size);
 638          write_buffer (&outfile, fsrc, size);
 639          printf ("** ");
 640          for (int_4 i = 1; i <= 10; i++) {
 641            putchar (name[i - 1]);
 642          }
 643          printf (" ** renumbered subprogram %d\n", routines);
 644        }
 645      }
 646    } while (!P_eof (infile));
 647    fclose (infile);
 648    fclose (outfile);
 649    return;
 650  }
     


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