fpp.c

     1  //! @file fpp.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  //! Fortran preprocessor.
    25  
    26  #include <vif.h>
    27  
    28  void fpp (char *, char *, int_4 nest);
    29  
    30  int_4 register_file(char *name)
    31  {
    32    for (int_4 k = 1; k <= nfiles; k++) {
    33      if (strcmp (files[k].text, name) == 0) {
    34         return k;
    35      }
    36    }
    37    nfiles++;
    38    if (nfiles >= MAX_SOURCE_FILES) {
    39      FATAL (2001, "too many source files", NO_TEXT);
    40    }
    41    files[nfiles].num = nfiles;
    42    files[nfiles].text = f_stralloc (name);
    43    return nfiles;
    44  }
    45  
    46  void get_source (char *name, int_4 nest)
    47  {
    48    FILE *in;
    49    char *ext;
    50    int_4 lines = 1, nisn = 0, actfile, cntrls = 0;
    51    if (nest > MAX_NEST) {
    52      FATAL (2002, "include nesting too deep", name);
    53    }
    54    if (strlen (name) < 3) {
    55      FATAL (2003, "source file name", name);
    56    }
    57    ext = &name[strlen (name) - 2];
    58    if (EQUAL (ext, ".f") || EQUAL (ext, ".F")) {
    59      ;// Ok
    60    } else if (EQUAL (ext, ".f66") || EQUAL (ext, ".F66")) {
    61      ;// Ok
    62    } else if (EQUAL (ext, ".f77") || EQUAL (ext, ".F77")) {
    63      ;// Ok
    64    } else if (EQUAL (ext, ".ftn") || EQUAL (ext, ".FTN")) {
    65      ;// Ok
    66    } else if (EQUAL (ext, ".h") || EQUAL (ext, ".H")) {
    67      ;// Ok
    68    } else {
    69      FATAL (2004, "source file format", name);
    70    }
    71    if ((in = fopen (name, "r")) == NO_FILE) {
    72      FATAL (2005, "cannot read", name);
    73    };
    74    NEW_RECORD (path);
    75    _srecordf (path, "%s", dirname (name));
    76    actfile = register_file(name);
    77    while (!feof (in)) {
    78      NEW_RECORD (fetch);
    79      if (fgets (fetch, RECLN, in) != NO_TEXT) {
    80        int_4 len = strlen (fetch);
    81        if (len > 0) {
    82          for (int k = 0; k < len; k++) {
    83            if (fetch[k] == EOF || fetch[k] == '\0' || fetch[k] == '\n') {
    84              ;
    85            } else if (fetch[k] == '\r' && fetch[k + 1] == '\n') {
    86  // Assume ms-dos that has \r\n line ends.
    87              fetch[k] = '\n';
    88              fetch[k + 1] = '\0';
    89              len--;
    90            } else {
    91              if (!isprint (fetch[k])) {
    92                cntrls++;
    93                fetch[k] = '?';
    94              }
    95            }
    96          }
    97          if (fetch[0] == '#') {
    98            int_4 savfile = actfile;
    99            fpp (fetch, path, nest);
   100            actfile = savfile;
   101            lines++;
   102          } else {
   103            if (fetch[len - 1] == '\n') {
   104              fetch[--len] = '\0';
   105            }
   106            if (nftnlines == MAX_FTN_LINES - 1) { // One less - always terminating NULL line.
   107              MAX_FTN_LINES += INCREMENT;
   108              source = (FTN_LINE *) f_realloc (source, MAX_FTN_LINES * sizeof (FTN_LINE));
   109              memset (&source[nftnlines], 0, INCREMENT * sizeof (FTN_LINE));
   110            }
   111            source[nftnlines].file = &files[actfile];
   112            source[nftnlines].num = lines;
   113            source[nftnlines].len = len;
   114            source[nftnlines].jcl = FALSE;
   115            source[nftnlines].text = f_stralloc (fetch);
   116            if (fetch[0] == '\0' || IS_COMMENT (fetch[0])) {
   117              source[nftnlines].isn = 0;
   118            } else if (nisn > 0 && fetch[5] != ' ') {
   119              source[nftnlines].isn = nisn;
   120            } else {
   121              source[nftnlines].isn = ++nisn;
   122            }
   123            lines++;
   124            nftnlines++;
   125          }
   126        }
   127      }
   128    }
   129    files[nfiles].len = lines - 1;
   130    fclose (in);
   131    if (cntrls > 0) {
   132      WARNING (2006, "source has unrecognized characters", NO_TEXT);
   133    }
   134  }
   135  
   136  void fpp (char *cmd, char *path, int_4 nest)
   137  {
   138    if (cmd[0] == '#') {
   139      cmd++;
   140    }
   141    while (cmd[0] == ' ') {
   142      cmd++;
   143    }
   144    if (LEQUAL ("echo", cmd)) {
   145      cmd = &cmd[strlen ("echo")];
   146      while (cmd[0] == ' ') {
   147        cmd++;
   148      }
   149      int_4 N = strlen (cmd);
   150      if (N > 0 && cmd[N - 1] == '\n') {
   151        cmd[N - 1] = '\0';
   152      }
   153      ECHO (2007, cmd, NO_TEXT);
   154    } else if (LEQUAL ("pragma", cmd)) {
   155      cmd = &cmd[strlen ("pragma")];
   156      while (cmd[0] == ' ') {
   157        cmd++;
   158      }
   159      int_4 N = strlen (cmd);
   160      if (N > 0 && cmd[N - 1] == '\n') {
   161        cmd[N - 1] = '\0';
   162      }
   163      option (cmd);
   164    } else if (LEQUAL ("include", cmd)) {
   165      NEW_RECORD (fn);
   166      (void) strtok (cmd, "'");
   167      char *str = strtok (NO_TEXT, "'");
   168      if (str != NO_TEXT) {
   169        _srecordf (fn, "%s/%s", path, str);
   170        get_source (fn, nest + 1);
   171      } else {
   172        FATAL (2008, "filename required", cmd);
   173      }
   174    } else {
   175      FATAL (2009, "preprocessor directive", cmd);
   176    }
   177  }


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