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


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