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


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