modules.c

     1  //! @file modules.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 BLOCK DATA, FUNCTION, PROGRAM and SUBROUTINE.
    25  
    26  #include <vif.h>
    27  
    28  #define ALLOW_ANON (nprocs >= 0)
    29  
    30  int_4 aborted;
    31  int_4 nmodules = 0;
    32  char *modules[MAX_MODULES];
    33  
    34  void common_errors (int_4 *nest)
    35  {
    36    NEW_RECORD (str);
    37    _srecordf (str, "%s %s", prelex, curlex);
    38    if (TOKEN ("(")) {
    39      (*nest)++;
    40    } else if (TOKEN (")")) {
    41      (*nest)--;
    42    } else if (strlen (curlex) == 1 && strchr ("{}[];\\?~`@#$%", curlex[0]) != NO_TEXT) {
    43      SYNTAX (2601, "stray symbol");
    44    } else if (preret == WORD && curret == WORD) {
    45      if (!reserved (prelex)) {
    46        ADJACENT (2602, str);
    47      }
    48    } else if (IS_NUMBER (preret) && IS_NUMBER (curret)) {
    49      ADJACENT (2603, str);
    50    }
    51  }
    52  
    53  void skip_to_end (void)
    54  {
    55    int_4 rc, go_on = TRUE;
    56    while (go_on && (rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
    57      if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
    58        go_on = FALSE;
    59      } else {
    60        rc = scan (EXPECT_NONE);
    61        while (WITHIN) {
    62          rc = scan (EXPECT_NONE);
    63        }
    64      }
    65    }
    66    aborted = TRUE;
    67  }
    68  
    69  void prescan (void)
    70  {
    71    SAVE_POS (1);
    72    int_4 rc, go_on = TRUE;
    73    while (go_on && (rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
    74      LBL *statlbl = NO_LABEL;
    75      if (curlex[0] == '\0') {
    76        continue;
    77      }
    78      if (rc == LABEL) {
    79        sscanf (curlex, "%d", &CUR_LIN.label);
    80        if (nlabels >= MAX_LABELS) {
    81          ERROR (2604, "too many labels", NO_TEXT);
    82        }
    83        for (int_4 k = 1; k < nlabels; k++) {
    84          if (labels[k].num == CUR_LIN.label) {
    85            ERROR (2605, "duplicate label", curlex);
    86            break;
    87          }
    88        }
    89        statlbl = &labels[nlabels];
    90        statlbl->index = nlabels;
    91        statlbl->num = CUR_LIN.label;
    92        statlbl->line = curlin;
    93        statlbl->nonexe = FALSE;
    94        statlbl->data = FALSE;
    95        statlbl->format = FALSE;
    96        statlbl->jumped = FALSE;
    97        statlbl->renum = nlabels++;
    98        rc = scan (EXPECT_NONE);
    99      }
   100      if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
   101        go_on = FALSE;
   102      } else if (TOKEN ("data") && IS_NOT_ASSIGNMENT) {
   103        if (statlbl != NO_LABEL) {
   104          statlbl->nonexe = TRUE;
   105          statlbl->data = TRUE;
   106        }
   107        skip_card (FALSE);
   108      } else if (TOKEN ("format") && IS_NOT_ASSIGNMENT) {
   109        if (statlbl == NO_LABEL) {
   110          ERROR (2606, "format statement needs a label", NO_TEXT);
   111        }
   112        statlbl->nonexe = TRUE;
   113        statlbl->format = TRUE;
   114        skip_card (FALSE);
   115      } else {
   116        int_4 nest = 0;
   117        rc = scan (EXPECT_NONE);
   118        while (WITHIN) {
   119          common_errors (&nest);
   120          rc = scan (EXPECT_NONE);
   121        }
   122        if (nest != 0) {
   123          SYNTAX (2607, "unbalanced parentheses");
   124        }
   125      }
   126    }
   127    RESTORE_POS (1);
   128  }
   129  
   130  void code_args (int_4 proc, int_4 phase)
   131  {
   132    int_4 rc;
   133    code (proc, phase, procnam);
   134    code (proc, phase, " ");
   135    rc = scan (EXPECT_NONE);
   136    if (TOKEN ("(")) {
   137      rc = scan (EXPECT_NONE);
   138      if (TOKEN (")")) {
   139        code (proc, phase, "(void)");
   140      } else if (rc == WORD) {
   141        int_4 go_on;
   142        code (proc, phase, "(");
   143        do {
   144          int_4 apatch = code (proc, phase, NO_TEXT);
   145          if (rc == WORD) {
   146            add_local (curlex, NOTYPE, NOLEN, UNIQ, apatch, ARG, LOCAL, SOURCE);
   147          } else {
   148            EXPECT (2608, "variable");
   149          }
   150          rc = scan (EXPECT_NONE);
   151          if (TOKEN (",")) {
   152            go_on = TRUE;
   153            code (proc, phase, ", ");
   154            rc = scan (EXPECT_NONE);
   155          } else if (TOKEN (")")) {
   156            go_on = FALSE;
   157            code (proc, phase, ")");
   158          } else {
   159            go_on = FALSE;
   160            EXPECT (2609, ", or )");
   161          }
   162        } while (go_on);
   163      }
   164    } else {
   165      code (proc, phase, "(void)");
   166    }
   167    (void) rc;
   168    skip_card (FALSE);
   169  }
   170  
   171  void gen_code (void)
   172  {
   173  // Generate code for one module.
   174    code (nprocs, TITLE, newpage (modnam, "generated-code"));
   175    code (nprocs, PARAMETERS, newpage (modnam, "parameters"));
   176    code (nprocs, MESSAGES, newpage (modnam, "diagnostics"));
   177    merrors = 0;
   178    prescan ();
   179  //
   180    SAVE_POS (1);
   181    if (merrors == 0) {
   182      get_impl ();
   183      RESTORE_POS (1);
   184      get_decls ();
   185      RESTORE_POS (1);
   186      decl_autosave ();
   187      RESTORE_POS (1);
   188      decl_equiv ();
   189      merge_commons ();
   190      RESTORE_POS (1);
   191      decl_data ();
   192    }
   193    if (merrors == 0) {
   194      idfs_unused ();
   195      RESTORE_POS (1);
   196      decl_macros ();
   197    } else {
   198      skip_to_end ();
   199      return;
   200    }
   201    if (merrors == 0) {
   202      gen_statements (NO_LABEL, 0);
   203      code_idfs (locals, nlocals, LOCAL, nprocs, DECL);
   204      code_exts (locals, nlocals, LOCAL, nprocs, DECL);
   205    } else {
   206      skip_to_end ();
   207      return;
   208    }
   209    if (merrors == 0) {
   210      patch_args ();
   211    }
   212  }
   213  
   214  void gen_program (void)
   215  {
   216    int_4 rc;
   217  // PROGRAM
   218    nprocs++;
   219    code (0, PROTOTYPE, "\n");
   220    code (0, PROTOTYPE, "prototype int_4 ");
   221    code (nprocs, PRE, "int_4 ");
   222    SAVE_POS (1);
   223    rc = scan (EXPECT_NONE);
   224    if (rc != WORD) {
   225      ERROR (2610, "missing name for ", "program");
   226      RECCPY (modnam, "program");
   227    } else {
   228      RECCPY (modnam, curlex);
   229    }
   230    _srecordf (procnam, "%s", edit_f (modnam));
   231    RECCPY (retnam, "");
   232    if (strlen (program) == 0) {
   233      RECCPY (program, procnam);
   234    } else {
   235      ERROR (2611, "redefinition", "program");
   236    }
   237    code_args (0, PROTOTYPE);
   238    code (0, PROTOTYPE, ";");
   239    RESTORE_POS (1);
   240    rc = scan (EXPECT_NONE);
   241    code_args (nprocs, PRE);
   242    code (nprocs, PRE, "\n");
   243    code (nprocs, PRE, "{\n");
   244    cpp_direct (nprocs, prelin, PRE);
   245    gen_code ();
   246    code (nprocs, POST, "}");
   247  }
   248  
   249  void gen_anon_program (void)
   250  {
   251    if (! ALLOW_ANON) {
   252      EXPECT (2612, "valid subprogram");
   253      return; 
   254    }
   255    if (nprocs == 0) {
   256      curlin = 1; 
   257    }
   258      curcol = START_OF_LINE;
   259    nprocs++;
   260    RECCPY (modnam, "anonymous");
   261    _srecordf (procnam, "%s", edit_f (modnam));
   262    RECCPY (retnam, "");
   263    if (strlen (program) == 0) {
   264      RECCPY (program, procnam);
   265    } else {
   266      ERROR (2613, "redefinition", "program");
   267    }
   268    code (0, PROTOTYPE, "\n");
   269    code (0, PROTOTYPE, "prototype int_4 ");
   270    code (0, PROTOTYPE, procnam);
   271    code (0, PROTOTYPE, " (void);");
   272    code (nprocs, PRE, "int_4 ");
   273    code (nprocs, PRE, procnam);
   274    code (nprocs, PRE, " (void)");
   275    code (nprocs, PRE, "\n");
   276    code (nprocs, PRE, "{\n");
   277    cpp_direct (nprocs, prelin, PRE);
   278    gen_code ();
   279    code (nprocs, POST, "}");
   280  }
   281  
   282  void gen_subroutine (void)
   283  {
   284  // SUBROUTINE
   285    int_4 rc;
   286    nprocs++;
   287    code (0, PROTOTYPE, "\n");
   288    if (compile_only || optimise < 3) {
   289      code (0, PROTOTYPE, "prototype int_4 ");
   290      code (nprocs, PRE, "int_4 ");
   291    } else {
   292      code (0, PROTOTYPE, "prototype static inline int_4 ");
   293      code (nprocs, PRE, "static inline int_4 ");
   294    }
   295    SAVE_POS (1);
   296    rc = scan (EXPECT_NONE);
   297    if (rc != WORD) {
   298      ERROR (2614, "missing name for ", "subroutine");
   299      RECCPY (modnam, "routine");
   300    } else {
   301      RECCPY (modnam, curlex);
   302    }
   303    _srecordf (procnam, "%s", edit_f (modnam));
   304    RECCPY (retnam, "");
   305    code_args (0, PROTOTYPE);
   306    code (0, PROTOTYPE, ";");
   307    RESTORE_POS (1);
   308    rc = scan (EXPECT_NONE);
   309    code_args (nprocs, PRE);
   310    code (nprocs, PRE, "\n");
   311    code (nprocs, PRE, "{\n");
   312    cpp_direct (nprocs, prelin, PRE);
   313    gen_code ();
   314    code (nprocs, POST, "}");
   315  }
   316  
   317  void gen_block_data (void)
   318  {
   319  // BLOCK DATA
   320    NEW_RECORD (str);
   321    int_4 rc = scan (EXPECT_NONE);
   322    nprocs++;
   323    if (!TOKEN ("data")) {
   324      EXPECT (2615, "block data");
   325    }
   326    rc = scan (EXPECT_NONE);
   327    if (prelin == curlin) {
   328      RECCPY (modnam, curlex);
   329      rc = scan (EXPECT_NONE);
   330    } else {
   331      RECCPY (modnam, "block_data");
   332    }
   333    RECCPY (retnam, "");
   334    _srecordf (block, "%s", edit_f (modnam));
   335    if (compile_only || optimise < 3) {
   336      _srecordf (str, "int_4 %s (void)", block);
   337    } else {
   338      _srecordf (str, "static inline int_4 %s (void)", block);
   339    }
   340    code (0, PROTOTYPE, "\n");
   341    code (0, PROTOTYPE, "prototype ");
   342    code (0, PROTOTYPE, str);
   343    code (0, PROTOTYPE, ";");
   344    code (nprocs, PRE, str);
   345    code (nprocs, PRE, "{\n");
   346    cpp_direct (nprocs, prelin, PRE);
   347    gen_code ();
   348    code (nprocs, POST, "}");
   349    (void) rc;
   350  }
   351  
   352  void gen_function (void)
   353  {
   354    int_4 rc;
   355  // FUNCTION with implicit type.
   356    int_4 patchp, patchf;
   357    SAVE_POS (1);
   358    IDENT *ret;
   359    NEW_RECORD (str);
   360    nprocs++;
   361    func = TRUE;
   362    code (0, PROTOTYPE, "\n");
   363    code (0, PROTOTYPE, "prototype ");
   364    if (compile_only == FALSE || optimise >= 3) {
   365      code (0, PROTOTYPE, "static inline ");
   366    }
   367    patchp = code (0, PROTOTYPE, NO_TEXT);
   368    code (0, PROTOTYPE, " ");
   369    if (compile_only == FALSE || optimise >= 3) {
   370      code (nprocs, PRE, "static inline ");
   371    }
   372    patchf = code (nprocs, PRE, NO_TEXT);
   373    code (nprocs, PRE, " ");
   374    rc = scan (EXPECT_NONE);
   375    if (rc != WORD) {
   376      ERROR (2616, "missing name for ", "function");
   377      RECCPY (modnam, "function");
   378    } else {
   379      RECCPY (modnam, curlex);
   380    }
   381    _srecordf (procnam, "%s", edit_f (modnam));
   382    ret = add_local (modnam, NOTYPE, NOLEN, UNIQ, NOPATCH, NOARG, LOCAL, SOURCE);
   383    ret->mode.fun = TRUE;
   384    ret->mode.save = AUTOMATIC;
   385    _srecordf (retnam, "%s", C_NAME (ret));
   386    code_args (0, PROTOTYPE);
   387    code (0, PROTOTYPE, ";");
   388    RESTORE_POS (1);
   389    rc = scan (EXPECT_NONE);
   390    code_args (nprocs, PRE);
   391    code (nprocs, PRE, "\n");
   392    code (nprocs, PRE, "{\n");
   393    cpp_direct (nprocs, prelin, PRE);
   394    gen_code ();
   395    code (nprocs, POST, "}\n");
   396    _srecordf (str, "%s", wtype (&ret->mode, NOARG, FUN));
   397    patch (patchp, str);
   398    patch (patchf, str);
   399  }
   400  
   401  MODE gen_typed_function (void)
   402  {
   403    int_4 rc;
   404  // TYPE FUNCTION
   405    MODE mode;
   406    f2c_type (curlex, &mode, NOARG, NOFUN);
   407    rc = scan (EXPECT_NONE);
   408    if (!TOKEN ("function")) {
   409      mode.type = NOTYPE;
   410      mode.len = 0;
   411      return mode;
   412    } else {
   413      SAVE_POS (1);
   414      IDENT *ret;
   415      nprocs++;
   416      func = TRUE;
   417      code (0, PROTOTYPE, "\n");
   418      code (0, PROTOTYPE, "prototype ");
   419      if (compile_only == FALSE || optimise >= 3) {
   420        code (0, PROTOTYPE, "static inline ");
   421      }
   422      code (0, PROTOTYPE, f2c_type (prelex, NO_MODE, NOARG, FUN));
   423      code (0, PROTOTYPE, " ");
   424      if (compile_only == FALSE || optimise >= 3) {
   425        code (nprocs, PRE, "static inline ");
   426      }
   427      code (nprocs, PRE, f2c_type (prelex, NO_MODE, NOARG, FUN));
   428      code (nprocs, PRE, " ");
   429      rc = scan (EXPECT_NONE);
   430      if (rc != WORD) {
   431        ERROR (2617, "missing name for ", "function");
   432        RECCPY (modnam, "function");
   433      } else {
   434        RECCPY (modnam, curlex);
   435      }
   436      _srecordf (procnam, "%s", edit_f (modnam));
   437      ret = add_local (modnam, mode.type, mode.len, UNIQ, NOPATCH, NOARG, LOCAL, SOURCE);
   438      ret->mode.fun = TRUE;
   439      ret->mode.save = AUTOMATIC;
   440      _srecordf (retnam, "%s", C_NAME (ret));
   441      code_args (0, PROTOTYPE);
   442      code (0, PROTOTYPE, ";");
   443      RESTORE_POS (1);
   444      rc = scan (EXPECT_NONE);
   445      code_args (nprocs, PRE);
   446      code (nprocs, PRE, "\n");
   447      code (nprocs, PRE, "{\n");
   448      cpp_direct (nprocs, prelin, PRE);
   449      gen_code ();
   450      code (nprocs, POST, "}");
   451    }
   452    return mode;
   453  }
   454  
   455  void subprograms (void)
   456  {
   457    int_4 rc;
   458    NEW_RECORD (type);
   459    NEW_RECORD (kind);
   460    NEW_RECORD (str);
   461    NEW_RECORD (endof);
   462    while (!abend) {
   463      SAVE_POS (1);
   464      rc = scan (EXPECT_NONE);
   465      if (rc == END_OF_MODULE) {
   466        break;
   467      }
   468      nlocals = 0;
   469      type[0] = '\0';
   470  // Label '0' is the label for subprogram exit.
   471      labels[0].num = 0;
   472      labels[0].line = 0;
   473      labels[0].jumped = FALSE;
   474      nlabels = 1;
   475  //
   476      lbl = NO_LABEL;
   477      nloctmps = 0;
   478      func = FALSE;
   479      if (rc == END_OF_LINE) {
   480        continue;
   481      }
   482      kind[0] = '\0';
   483      end_statements = 0;
   484      aborted = FALSE;
   485      if (rc == WORD) {
   486        if (TOKEN ("program")) {
   487          bufcpy (kind, "program", RECLN);
   488          gen_program ();
   489        } else if (TOKEN ("subroutine")) {
   490          bufcpy (kind, "subroutine", RECLN);
   491          gen_subroutine ();
   492          if (renum && merrors == 0) {
   493            RESTORE_POS (1);
   494            tidy_source (procnam);
   495          }
   496        } else if (TOKEN ("block")) {
   497          bufcpy (kind, "block data", RECLN);
   498          gen_block_data ();
   499          if (renum && merrors == 0) {
   500            RESTORE_POS (1);
   501            tidy_source (procnam);
   502          }
   503        } else if (TOKEN ("function")) {
   504          bufcpy (kind, "function", RECLN);
   505          gen_function ();
   506          if (renum && merrors == 0) {
   507            RESTORE_POS (1);
   508            tidy_source (procnam);
   509          }
   510        } else {
   511          if (ALLOW_ANON) {
   512            gen_anon_program ();
   513            bufcpy (kind, "program", RECLN);
   514            if (renum && merrors == 0) {
   515              RESTORE_POS (1);
   516              tidy_source (procnam);
   517            }
   518          }
   519        }
   520      } else if (rc == DECLAR) {
   521        bufcpy (kind, "function", RECLN);
   522        MODE ret = gen_typed_function ();
   523        if (ret.type == NOTYPE && ALLOW_ANON) {
   524          gen_anon_program ();
   525          bufcpy (kind, "program", RECLN);
   526        } else {
   527          _srecordf (type, qtype (&ret));
   528        }
   529        if (renum && merrors == 0) {
   530          RESTORE_POS (1);
   531          tidy_source (procnam);
   532        }
   533  //  } else if (rc == LABEL) {
   534  //    WARNING (2618, "ignored label", curlex);
   535      } else {
   536        if (ALLOW_ANON) {
   537          gen_anon_program ();
   538          bufcpy (kind, "program", RECLN);
   539          if (renum && merrors == 0) {
   540            RESTORE_POS (1);
   541            tidy_source (procnam);
   542          }
   543        } else {
   544          EXPECT (2619, "valid subprogram");
   545        }
   546        return;
   547      }
   548      if (!aborted && end_statements == 0) {
   549        EXPECT (2620, "end statement");
   550      }
   551      if (nprocs == 0) {
   552  //    BUG ("no subprogram found");
   553        FATAL (2621, "no subprogram", "check program statement");
   554      }
   555  // Prune 'sleeping' labels.
   556      for (int_4 k = 0; k < nlabels; k++) {
   557        LBL *L = &labels[k];
   558        if (!L->jumped) {
   559          patch (L->patch, NO_TEXT);
   560        }
   561      }
   562  //
   563      if (nprocs == pnprocs) {
   564        FATAL (2622, "invalid fortran source", modnam);
   565      }
   566      NEW_RECORD (sub);
   567      _srecordf (endof, "** %-10s ** end of compilation %d", _bufsub (sub, modnam, 1, 10), nprocs);
   568      pnprocs = nprocs;
   569      code (nprocs, BANNER, newpage (modnam, modnam));
   570      if (strlen (type) > 0) {
   571        banner (nprocs, BANNER, _strupper (type));
   572        code (nprocs, BANNER, "\n");
   573        _srecordf (str, "  {\"%s\", 0}, // %s %s\n", modnam, type, kind);
   574        code (0, FREQ, str);
   575      } else {
   576        _srecordf (str, "  {\"%s\", 0}, // %s\n", modnam, kind);
   577        code (0, FREQ, str);
   578      }
   579      banner (nprocs, BANNER, _strupper (kind));
   580      code (nprocs, BANNER, "\n");
   581      banner (nprocs, BANNER, _strupper (modnam));
   582      code (nprocs, BANNER, "\n");
   583      if (!quiet_mode) {
   584        diagnostic (nprocs, endof);
   585      }
   586      proc_listing (nprocs);
   587    }
   588  }
   589  
   590  logical_4 find_module (char *name)
   591  {
   592    for (int_4 k = 0; k < nmodules; k++) {
   593      if (same_name (name, modules[k])) {
   594        return TRUE;
   595      }
   596    }
   597    return FALSE;
   598  }
   599  
   600  void list_module (void)
   601  {
   602    int_4 rc = scan (EXPECT_NONE);
   603    if (rc == WORD) {
   604      if (nmodules >= MAX_MODULES) {
   605        FATAL (2623, "too many modules", NO_TEXT);
   606      }
   607      modules[nmodules++] = f_stralloc (curlex);
   608    } else {
   609      ERROR (2624, "missing name", "module");
   610    }
   611  }
   612  
   613  void scan_modules (void)
   614  {
   615    int_4 rc;
   616    while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE && !abend) {
   617      if (rc == WORD) {
   618        if (TOKEN ("program")) {
   619          list_module ();
   620        } else if (TOKEN ("subroutine")) {
   621          list_module ();
   622        } else if (TOKEN ("function")) {
   623          list_module ();
   624        } else if (rc == DECLAR) {
   625          rc = scan (EXPECT_NONE);
   626          if (TOKEN ("function")) {
   627            list_module ();
   628          }
   629        } else if (TOKEN ("block")) {
   630          rc = scan (EXPECT_NONE);
   631          if (TOKEN ("data")) {
   632            list_module ();
   633          }
   634        }
   635      }
   636    }
   637  }


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