aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/scanner.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/scanner.c')
-rw-r--r--gcc/fortran/scanner.c2903
1 files changed, 0 insertions, 2903 deletions
diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c
deleted file mode 100644
index 4df6576..0000000
--- a/gcc/fortran/scanner.c
+++ /dev/null
@@ -1,2903 +0,0 @@
-/* Character scanner.
- Copyright (C) 2000-2022 Free Software Foundation, Inc.
- Contributed by Andy Vaught
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-/* Set of subroutines to (ultimately) return the next character to the
- various matching subroutines. This file's job is to read files and
- build up lines that are parsed by the parser. This means that we
- handle continuation lines and "include" lines.
-
- The first thing the scanner does is to load an entire file into
- memory. We load the entire file into memory for a couple reasons.
- The first is that we want to be able to deal with nonseekable input
- (pipes, stdin) and there is a lot of backing up involved during
- parsing.
-
- The second is that we want to be able to print the locus of errors,
- and an error on line 999999 could conflict with something on line
- one. Given nonseekable input, we've got to store the whole thing.
-
- One thing that helps are the column truncation limits that give us
- an upper bound on the size of individual lines. We don't store the
- truncated stuff.
-
- From the scanner's viewpoint, the higher level subroutines ask for
- new characters and do a lot of jumping backwards. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "gfortran.h"
-#include "toplev.h" /* For set_src_pwd. */
-#include "debug.h"
-#include "options.h"
-#include "diagnostic-core.h" /* For fatal_error. */
-#include "cpp.h"
-#include "scanner.h"
-
-/* List of include file search directories. */
-gfc_directorylist *include_dirs, *intrinsic_modules_dirs;
-
-static gfc_file *file_head, *current_file;
-
-static int continue_flag, end_flag, gcc_attribute_flag;
-/* If !$omp/!$acc occurred in current comment line. */
-static int openmp_flag, openacc_flag;
-static int continue_count, continue_line;
-static locus openmp_locus;
-static locus openacc_locus;
-static locus gcc_attribute_locus;
-
-gfc_source_form gfc_current_form;
-static gfc_linebuf *line_head, *line_tail;
-
-locus gfc_current_locus;
-const char *gfc_source_file;
-static FILE *gfc_src_file;
-static gfc_char_t *gfc_src_preprocessor_lines[2];
-
-static struct gfc_file_change
-{
- const char *filename;
- gfc_linebuf *lb;
- int line;
-} *file_changes;
-static size_t file_changes_cur, file_changes_count;
-static size_t file_changes_allocated;
-
-static gfc_char_t *last_error_char;
-
-/* Functions dealing with our wide characters (gfc_char_t) and
- sequences of such characters. */
-
-int
-gfc_wide_fits_in_byte (gfc_char_t c)
-{
- return (c <= UCHAR_MAX);
-}
-
-static inline int
-wide_is_ascii (gfc_char_t c)
-{
- return (gfc_wide_fits_in_byte (c) && ((unsigned char) c & ~0x7f) == 0);
-}
-
-int
-gfc_wide_is_printable (gfc_char_t c)
-{
- return (gfc_wide_fits_in_byte (c) && ISPRINT ((unsigned char) c));
-}
-
-gfc_char_t
-gfc_wide_tolower (gfc_char_t c)
-{
- return (wide_is_ascii (c) ? (gfc_char_t) TOLOWER((unsigned char) c) : c);
-}
-
-gfc_char_t
-gfc_wide_toupper (gfc_char_t c)
-{
- return (wide_is_ascii (c) ? (gfc_char_t) TOUPPER((unsigned char) c) : c);
-}
-
-int
-gfc_wide_is_digit (gfc_char_t c)
-{
- return (c >= '0' && c <= '9');
-}
-
-static inline int
-wide_atoi (gfc_char_t *c)
-{
-#define MAX_DIGITS 20
- char buf[MAX_DIGITS+1];
- int i = 0;
-
- while (gfc_wide_is_digit(*c) && i < MAX_DIGITS)
- buf[i++] = *c++;
- buf[i] = '\0';
- return atoi (buf);
-}
-
-size_t
-gfc_wide_strlen (const gfc_char_t *str)
-{
- size_t i;
-
- for (i = 0; str[i]; i++)
- ;
-
- return i;
-}
-
-gfc_char_t *
-gfc_wide_memset (gfc_char_t *b, gfc_char_t c, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++)
- b[i] = c;
-
- return b;
-}
-
-static gfc_char_t *
-wide_strcpy (gfc_char_t *dest, const gfc_char_t *src)
-{
- gfc_char_t *d;
-
- for (d = dest; (*d = *src) != '\0'; ++src, ++d)
- ;
-
- return dest;
-}
-
-static gfc_char_t *
-wide_strchr (const gfc_char_t *s, gfc_char_t c)
-{
- do {
- if (*s == c)
- {
- return CONST_CAST(gfc_char_t *, s);
- }
- } while (*s++);
- return 0;
-}
-
-char *
-gfc_widechar_to_char (const gfc_char_t *s, int length)
-{
- size_t len, i;
- char *res;
-
- if (s == NULL)
- return NULL;
-
- /* Passing a negative length is used to indicate that length should be
- calculated using gfc_wide_strlen(). */
- len = (length >= 0 ? (size_t) length : gfc_wide_strlen (s));
- res = XNEWVEC (char, len + 1);
-
- for (i = 0; i < len; i++)
- {
- gcc_assert (gfc_wide_fits_in_byte (s[i]));
- res[i] = (unsigned char) s[i];
- }
-
- res[len] = '\0';
- return res;
-}
-
-gfc_char_t *
-gfc_char_to_widechar (const char *s)
-{
- size_t len, i;
- gfc_char_t *res;
-
- if (s == NULL)
- return NULL;
-
- len = strlen (s);
- res = gfc_get_wide_string (len + 1);
-
- for (i = 0; i < len; i++)
- res[i] = (unsigned char) s[i];
-
- res[len] = '\0';
- return res;
-}
-
-static int
-wide_strncmp (const gfc_char_t *s1, const char *s2, size_t n)
-{
- gfc_char_t c1, c2;
-
- while (n-- > 0)
- {
- c1 = *s1++;
- c2 = *s2++;
- if (c1 != c2)
- return (c1 > c2 ? 1 : -1);
- if (c1 == '\0')
- return 0;
- }
- return 0;
-}
-
-int
-gfc_wide_strncasecmp (const gfc_char_t *s1, const char *s2, size_t n)
-{
- gfc_char_t c1, c2;
-
- while (n-- > 0)
- {
- c1 = gfc_wide_tolower (*s1++);
- c2 = TOLOWER (*s2++);
- if (c1 != c2)
- return (c1 > c2 ? 1 : -1);
- if (c1 == '\0')
- return 0;
- }
- return 0;
-}
-
-
-/* Main scanner initialization. */
-
-void
-gfc_scanner_init_1 (void)
-{
- file_head = NULL;
- line_head = NULL;
- line_tail = NULL;
-
- continue_count = 0;
- continue_line = 0;
-
- end_flag = 0;
- last_error_char = NULL;
-}
-
-
-/* Main scanner destructor. */
-
-void
-gfc_scanner_done_1 (void)
-{
- gfc_linebuf *lb;
- gfc_file *f;
-
- while(line_head != NULL)
- {
- lb = line_head->next;
- free (line_head);
- line_head = lb;
- }
-
- while(file_head != NULL)
- {
- f = file_head->next;
- free (file_head->filename);
- free (file_head);
- file_head = f;
- }
-}
-
-static bool
-gfc_do_check_include_dir (const char *path, bool warn)
-{
- struct stat st;
- if (stat (path, &st))
- {
- if (errno != ENOENT)
- gfc_warning_now (0, "Include directory %qs: %s",
- path, xstrerror(errno));
- else if (warn)
- gfc_warning_now (OPT_Wmissing_include_dirs,
- "Nonexistent include directory %qs", path);
- return false;
- }
- else if (!S_ISDIR (st.st_mode))
- {
- gfc_fatal_error ("%qs is not a directory", path);
- return false;
- }
- return true;
-}
-
-/* In order that -W(no-)missing-include-dirs works, the diagnostic can only be
- run after processing the commandline. */
-static void
-gfc_do_check_include_dirs (gfc_directorylist **list, bool do_warn)
-{
- gfc_directorylist *prev, *q, *n;
- prev = NULL;
- n = *list;
- while (n)
- {
- q = n; n = n->next;
- if (gfc_do_check_include_dir (q->path, q->warn && do_warn))
- {
- prev = q;
- continue;
- }
- if (prev == NULL)
- *list = n;
- else
- prev->next = n;
- free (q->path);
- free (q);
- }
-}
-
-void
-gfc_check_include_dirs (bool verbose_missing_dir_warn)
-{
- /* This is a bit convoluted: If gfc_cpp_enabled () and
- verbose_missing_dir_warn, the warning is shown by libcpp. Otherwise,
- it is shown here, still conditional on OPT_Wmissing_include_dirs. */
- bool warn = !gfc_cpp_enabled () || !verbose_missing_dir_warn;
- gfc_do_check_include_dirs (&include_dirs, warn);
- gfc_do_check_include_dirs (&intrinsic_modules_dirs, verbose_missing_dir_warn);
- if (gfc_option.module_dir && gfc_cpp_enabled ())
- gfc_do_check_include_dirs (&include_dirs, true);
-}
-
-/* Adds path to the list pointed to by list. */
-
-static void
-add_path_to_list (gfc_directorylist **list, const char *path,
- bool use_for_modules, bool head, bool warn, bool defer_warn)
-{
- gfc_directorylist *dir;
- const char *p;
- char *q;
- size_t len;
- int i;
-
- p = path;
- while (*p == ' ' || *p == '\t') /* someone might do "-I include" */
- if (*p++ == '\0')
- return;
-
- /* Strip trailing directory separators from the path, as this
- will confuse Windows systems. */
- len = strlen (p);
- q = (char *) alloca (len + 1);
- memcpy (q, p, len + 1);
- i = len - 1;
- while (i >=0 && IS_DIR_SEPARATOR (q[i]))
- q[i--] = '\0';
-
- if (!defer_warn && !gfc_do_check_include_dir (q, warn))
- return;
-
- if (head || *list == NULL)
- {
- dir = XCNEW (gfc_directorylist);
- if (!head)
- *list = dir;
- }
- else
- {
- dir = *list;
- while (dir->next)
- dir = dir->next;
-
- dir->next = XCNEW (gfc_directorylist);
- dir = dir->next;
- }
-
- dir->next = head ? *list : NULL;
- if (head)
- *list = dir;
- dir->use_for_modules = use_for_modules;
- dir->warn = warn;
- dir->path = XCNEWVEC (char, strlen (p) + 2);
- strcpy (dir->path, p);
- strcat (dir->path, "/"); /* make '/' last character */
-}
-
-/* defer_warn is set to true while parsing the commandline. */
-
-void
-gfc_add_include_path (const char *path, bool use_for_modules, bool file_dir,
- bool warn, bool defer_warn)
-{
- add_path_to_list (&include_dirs, path, use_for_modules, file_dir, warn,
- defer_warn);
-
- /* For '#include "..."' these directories are automatically searched. */
- if (!file_dir)
- gfc_cpp_add_include_path (xstrdup(path), true);
-}
-
-
-void
-gfc_add_intrinsic_modules_path (const char *path)
-{
- add_path_to_list (&intrinsic_modules_dirs, path, true, false, false, false);
-}
-
-
-/* Release resources allocated for options. */
-
-void
-gfc_release_include_path (void)
-{
- gfc_directorylist *p;
-
- while (include_dirs != NULL)
- {
- p = include_dirs;
- include_dirs = include_dirs->next;
- free (p->path);
- free (p);
- }
-
- while (intrinsic_modules_dirs != NULL)
- {
- p = intrinsic_modules_dirs;
- intrinsic_modules_dirs = intrinsic_modules_dirs->next;
- free (p->path);
- free (p);
- }
-
- free (gfc_option.module_dir);
-}
-
-
-static FILE *
-open_included_file (const char *name, gfc_directorylist *list,
- bool module, bool system)
-{
- char *fullname;
- gfc_directorylist *p;
- FILE *f;
-
- for (p = list; p; p = p->next)
- {
- if (module && !p->use_for_modules)
- continue;
-
- fullname = (char *) alloca(strlen (p->path) + strlen (name) + 1);
- strcpy (fullname, p->path);
- strcat (fullname, name);
-
- f = gfc_open_file (fullname);
- if (f != NULL)
- {
- if (gfc_cpp_makedep ())
- gfc_cpp_add_dep (fullname, system);
-
- return f;
- }
- }
-
- return NULL;
-}
-
-
-/* Opens file for reading, searching through the include directories
- given if necessary. If the include_cwd argument is true, we try
- to open the file in the current directory first. */
-
-FILE *
-gfc_open_included_file (const char *name, bool include_cwd, bool module)
-{
- FILE *f = NULL;
-
- if (IS_ABSOLUTE_PATH (name) || include_cwd)
- {
- f = gfc_open_file (name);
- if (f && gfc_cpp_makedep ())
- gfc_cpp_add_dep (name, false);
- }
-
- if (!f)
- f = open_included_file (name, include_dirs, module, false);
-
- return f;
-}
-
-
-/* Test to see if we're at the end of the main source file. */
-
-int
-gfc_at_end (void)
-{
- return end_flag;
-}
-
-
-/* Test to see if we're at the end of the current file. */
-
-int
-gfc_at_eof (void)
-{
- if (gfc_at_end ())
- return 1;
-
- if (line_head == NULL)
- return 1; /* Null file */
-
- if (gfc_current_locus.lb == NULL)
- return 1;
-
- return 0;
-}
-
-
-/* Test to see if we're at the beginning of a new line. */
-
-int
-gfc_at_bol (void)
-{
- if (gfc_at_eof ())
- return 1;
-
- return (gfc_current_locus.nextc == gfc_current_locus.lb->line);
-}
-
-
-/* Test to see if we're at the end of a line. */
-
-int
-gfc_at_eol (void)
-{
- if (gfc_at_eof ())
- return 1;
-
- return (*gfc_current_locus.nextc == '\0');
-}
-
-static void
-add_file_change (const char *filename, int line)
-{
- if (file_changes_count == file_changes_allocated)
- {
- if (file_changes_allocated)
- file_changes_allocated *= 2;
- else
- file_changes_allocated = 16;
- file_changes = XRESIZEVEC (struct gfc_file_change, file_changes,
- file_changes_allocated);
- }
- file_changes[file_changes_count].filename = filename;
- file_changes[file_changes_count].lb = NULL;
- file_changes[file_changes_count++].line = line;
-}
-
-static void
-report_file_change (gfc_linebuf *lb)
-{
- size_t c = file_changes_cur;
- while (c < file_changes_count
- && file_changes[c].lb == lb)
- {
- if (file_changes[c].filename)
- (*debug_hooks->start_source_file) (file_changes[c].line,
- file_changes[c].filename);
- else
- (*debug_hooks->end_source_file) (file_changes[c].line);
- ++c;
- }
- file_changes_cur = c;
-}
-
-void
-gfc_start_source_files (void)
-{
- /* If the debugger wants the name of the main source file,
- we give it. */
- if (debug_hooks->start_end_main_source_file)
- (*debug_hooks->start_source_file) (0, gfc_source_file);
-
- file_changes_cur = 0;
- report_file_change (gfc_current_locus.lb);
-}
-
-void
-gfc_end_source_files (void)
-{
- report_file_change (NULL);
-
- if (debug_hooks->start_end_main_source_file)
- (*debug_hooks->end_source_file) (0);
-}
-
-/* Advance the current line pointer to the next line. */
-
-void
-gfc_advance_line (void)
-{
- if (gfc_at_end ())
- return;
-
- if (gfc_current_locus.lb == NULL)
- {
- end_flag = 1;
- return;
- }
-
- if (gfc_current_locus.lb->next
- && !gfc_current_locus.lb->next->dbg_emitted)
- {
- report_file_change (gfc_current_locus.lb->next);
- gfc_current_locus.lb->next->dbg_emitted = true;
- }
-
- gfc_current_locus.lb = gfc_current_locus.lb->next;
-
- if (gfc_current_locus.lb != NULL)
- gfc_current_locus.nextc = gfc_current_locus.lb->line;
- else
- {
- gfc_current_locus.nextc = NULL;
- end_flag = 1;
- }
-}
-
-
-/* Get the next character from the input, advancing gfc_current_file's
- locus. When we hit the end of the line or the end of the file, we
- start returning a '\n' in order to complete the current statement.
- No Fortran line conventions are implemented here.
-
- Requiring explicit advances to the next line prevents the parse
- pointer from being on the wrong line if the current statement ends
- prematurely. */
-
-static gfc_char_t
-next_char (void)
-{
- gfc_char_t c;
-
- if (gfc_current_locus.nextc == NULL)
- return '\n';
-
- c = *gfc_current_locus.nextc++;
- if (c == '\0')
- {
- gfc_current_locus.nextc--; /* Remain on this line. */
- c = '\n';
- }
-
- return c;
-}
-
-
-/* Skip a comment. When we come here the parse pointer is positioned
- immediately after the comment character. If we ever implement
- compiler directives within comments, here is where we parse the
- directive. */
-
-static void
-skip_comment_line (void)
-{
- gfc_char_t c;
-
- do
- {
- c = next_char ();
- }
- while (c != '\n');
-
- gfc_advance_line ();
-}
-
-
-int
-gfc_define_undef_line (void)
-{
- char *tmp;
-
- /* All lines beginning with '#' are either #define or #undef. */
- if (debug_info_level != DINFO_LEVEL_VERBOSE || gfc_peek_ascii_char () != '#')
- return 0;
-
- if (wide_strncmp (gfc_current_locus.nextc, "#define ", 8) == 0)
- {
- tmp = gfc_widechar_to_char (&gfc_current_locus.nextc[8], -1);
- (*debug_hooks->define) (gfc_linebuf_linenum (gfc_current_locus.lb),
- tmp);
- free (tmp);
- }
-
- if (wide_strncmp (gfc_current_locus.nextc, "#undef ", 7) == 0)
- {
- tmp = gfc_widechar_to_char (&gfc_current_locus.nextc[7], -1);
- (*debug_hooks->undef) (gfc_linebuf_linenum (gfc_current_locus.lb),
- tmp);
- free (tmp);
- }
-
- /* Skip the rest of the line. */
- skip_comment_line ();
-
- return 1;
-}
-
-
-/* Return true if GCC$ was matched. */
-static bool
-skip_gcc_attribute (locus start)
-{
- bool r = false;
- char c;
- locus old_loc = gfc_current_locus;
-
- if ((c = next_char ()) == 'g' || c == 'G')
- if ((c = next_char ()) == 'c' || c == 'C')
- if ((c = next_char ()) == 'c' || c == 'C')
- if ((c = next_char ()) == '$')
- r = true;
-
- if (r == false)
- gfc_current_locus = old_loc;
- else
- {
- gcc_attribute_flag = 1;
- gcc_attribute_locus = old_loc;
- gfc_current_locus = start;
- }
-
- return r;
-}
-
-/* Return true if CC was matched. */
-static bool
-skip_free_oacc_sentinel (locus start, locus old_loc)
-{
- bool r = false;
- char c;
-
- if ((c = next_char ()) == 'c' || c == 'C')
- if ((c = next_char ()) == 'c' || c == 'C')
- r = true;
-
- if (r)
- {
- if ((c = next_char ()) == ' ' || c == '\t'
- || continue_flag)
- {
- while (gfc_is_whitespace (c))
- c = next_char ();
- if (c != '\n' && c != '!')
- {
- openacc_flag = 1;
- openacc_locus = old_loc;
- gfc_current_locus = start;
- }
- else
- r = false;
- }
- else
- {
- gfc_warning_now (0, "!$ACC at %C starts a commented "
- "line as it neither is followed "
- "by a space nor is a "
- "continuation line");
- r = false;
- }
- }
-
- return r;
-}
-
-/* Return true if MP was matched. */
-static bool
-skip_free_omp_sentinel (locus start, locus old_loc)
-{
- bool r = false;
- char c;
-
- if ((c = next_char ()) == 'm' || c == 'M')
- if ((c = next_char ()) == 'p' || c == 'P')
- r = true;
-
- if (r)
- {
- if ((c = next_char ()) == ' ' || c == '\t'
- || continue_flag)
- {
- while (gfc_is_whitespace (c))
- c = next_char ();
- if (c != '\n' && c != '!')
- {
- openmp_flag = 1;
- openmp_locus = old_loc;
- gfc_current_locus = start;
- }
- else
- r = false;
- }
- else
- {
- gfc_warning_now (0, "!$OMP at %C starts a commented "
- "line as it neither is followed "
- "by a space nor is a "
- "continuation line");
- r = false;
- }
- }
-
- return r;
-}
-
-/* Comment lines are null lines, lines containing only blanks or lines
- on which the first nonblank line is a '!'.
- Return true if !$ openmp or openacc conditional compilation sentinel was
- seen. */
-
-static bool
-skip_free_comments (void)
-{
- locus start;
- gfc_char_t c;
- int at_bol;
-
- for (;;)
- {
- at_bol = gfc_at_bol ();
- start = gfc_current_locus;
- if (gfc_at_eof ())
- break;
-
- do
- c = next_char ();
- while (gfc_is_whitespace (c));
-
- if (c == '\n')
- {
- gfc_advance_line ();
- continue;
- }
-
- if (c == '!')
- {
- /* Keep the !GCC$ line. */
- if (at_bol && skip_gcc_attribute (start))
- return false;
-
- /* If -fopenmp/-fopenacc, we need to handle here 2 things:
- 1) don't treat !$omp/!$acc as comments, but directives
- 2) handle OpenMP/OpenACC conditional compilation, where
- !$ should be treated as 2 spaces (for initial lines
- only if followed by space). */
- if (at_bol)
- {
- if ((flag_openmp || flag_openmp_simd)
- && flag_openacc)
- {
- locus old_loc = gfc_current_locus;
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'o' || c == 'O')
- {
- if (skip_free_omp_sentinel (start, old_loc))
- return false;
- gfc_current_locus = old_loc;
- next_char ();
- c = next_char ();
- }
- else if (c == 'a' || c == 'A')
- {
- if (skip_free_oacc_sentinel (start, old_loc))
- return false;
- gfc_current_locus = old_loc;
- next_char ();
- c = next_char ();
- }
- if (continue_flag || c == ' ' || c == '\t')
- {
- gfc_current_locus = old_loc;
- next_char ();
- openmp_flag = openacc_flag = 0;
- return true;
- }
- }
- gfc_current_locus = old_loc;
- }
- else if ((flag_openmp || flag_openmp_simd)
- && !flag_openacc)
- {
- locus old_loc = gfc_current_locus;
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'o' || c == 'O')
- {
- if (skip_free_omp_sentinel (start, old_loc))
- return false;
- gfc_current_locus = old_loc;
- next_char ();
- c = next_char ();
- }
- if (continue_flag || c == ' ' || c == '\t')
- {
- gfc_current_locus = old_loc;
- next_char ();
- openmp_flag = 0;
- return true;
- }
- }
- gfc_current_locus = old_loc;
- }
- else if (flag_openacc
- && !(flag_openmp || flag_openmp_simd))
- {
- locus old_loc = gfc_current_locus;
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'a' || c == 'A')
- {
- if (skip_free_oacc_sentinel (start, old_loc))
- return false;
- gfc_current_locus = old_loc;
- next_char();
- c = next_char();
- }
- }
- gfc_current_locus = old_loc;
- }
- }
- skip_comment_line ();
- continue;
- }
-
- break;
- }
-
- if (openmp_flag && at_bol)
- openmp_flag = 0;
-
- if (openacc_flag && at_bol)
- openacc_flag = 0;
-
- gcc_attribute_flag = 0;
- gfc_current_locus = start;
- return false;
-}
-
-/* Return true if MP was matched in fixed form. */
-static bool
-skip_fixed_omp_sentinel (locus *start)
-{
- gfc_char_t c;
- if (((c = next_char ()) == 'm' || c == 'M')
- && ((c = next_char ()) == 'p' || c == 'P'))
- {
- c = next_char ();
- if (c != '\n'
- && (continue_flag
- || c == ' ' || c == '\t' || c == '0'))
- {
- if (c == ' ' || c == '\t' || c == '0')
- openacc_flag = 0;
- do
- c = next_char ();
- while (gfc_is_whitespace (c));
- if (c != '\n' && c != '!')
- {
- /* Canonicalize to *$omp. */
- *start->nextc = '*';
- openmp_flag = 1;
- gfc_current_locus = *start;
- return true;
- }
- }
- }
- return false;
-}
-
-/* Return true if CC was matched in fixed form. */
-static bool
-skip_fixed_oacc_sentinel (locus *start)
-{
- gfc_char_t c;
- if (((c = next_char ()) == 'c' || c == 'C')
- && ((c = next_char ()) == 'c' || c == 'C'))
- {
- c = next_char ();
- if (c != '\n'
- && (continue_flag
- || c == ' ' || c == '\t' || c == '0'))
- {
- if (c == ' ' || c == '\t' || c == '0')
- openmp_flag = 0;
- do
- c = next_char ();
- while (gfc_is_whitespace (c));
- if (c != '\n' && c != '!')
- {
- /* Canonicalize to *$acc. */
- *start->nextc = '*';
- openacc_flag = 1;
- gfc_current_locus = *start;
- return true;
- }
- }
- }
- return false;
-}
-
-/* Skip comment lines in fixed source mode. We have the same rules as
- in skip_free_comment(), except that we can have a 'c', 'C' or '*'
- in column 1, and a '!' cannot be in column 6. Also, we deal with
- lines with 'd' or 'D' in column 1, if the user requested this. */
-
-static void
-skip_fixed_comments (void)
-{
- locus start;
- int col;
- gfc_char_t c;
-
- if (! gfc_at_bol ())
- {
- start = gfc_current_locus;
- if (! gfc_at_eof ())
- {
- do
- c = next_char ();
- while (gfc_is_whitespace (c));
-
- if (c == '\n')
- gfc_advance_line ();
- else if (c == '!')
- skip_comment_line ();
- }
-
- if (! gfc_at_bol ())
- {
- gfc_current_locus = start;
- return;
- }
- }
-
- for (;;)
- {
- start = gfc_current_locus;
- if (gfc_at_eof ())
- break;
-
- c = next_char ();
- if (c == '\n')
- {
- gfc_advance_line ();
- continue;
- }
-
- if (c == '!' || c == 'c' || c == 'C' || c == '*')
- {
- if (skip_gcc_attribute (start))
- {
- /* Canonicalize to *$omp. */
- *start.nextc = '*';
- return;
- }
-
- if (gfc_current_locus.lb != NULL
- && continue_line < gfc_linebuf_linenum (gfc_current_locus.lb))
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb);
-
- /* If -fopenmp/-fopenacc, we need to handle here 2 things:
- 1) don't treat !$omp/!$acc|c$omp/c$acc|*$omp / *$acc as comments,
- but directives
- 2) handle OpenMP/OpenACC conditional compilation, where
- !$|c$|*$ should be treated as 2 spaces if the characters
- in columns 3 to 6 are valid fixed form label columns
- characters. */
- if ((flag_openmp || flag_openmp_simd) && !flag_openacc)
- {
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'o' || c == 'O')
- {
- if (skip_fixed_omp_sentinel (&start))
- return;
- }
- else
- goto check_for_digits;
- }
- gfc_current_locus = start;
- }
- else if (flag_openacc && !(flag_openmp || flag_openmp_simd))
- {
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'a' || c == 'A')
- {
- if (skip_fixed_oacc_sentinel (&start))
- return;
- }
- }
- gfc_current_locus = start;
- }
- else if (flag_openacc || flag_openmp || flag_openmp_simd)
- {
- if (next_char () == '$')
- {
- c = next_char ();
- if (c == 'a' || c == 'A')
- {
- if (skip_fixed_oacc_sentinel (&start))
- return;
- }
- else if (c == 'o' || c == 'O')
- {
- if (skip_fixed_omp_sentinel (&start))
- return;
- }
- else
- goto check_for_digits;
- }
- gfc_current_locus = start;
- }
-
- skip_comment_line ();
- continue;
-
-check_for_digits:
- {
- /* Required for OpenMP's conditional compilation sentinel. */
- int digit_seen = 0;
-
- for (col = 3; col < 6; col++, c = next_char ())
- if (c == ' ')
- continue;
- else if (c == '\t')
- {
- col = 6;
- break;
- }
- else if (c < '0' || c > '9')
- break;
- else
- digit_seen = 1;
-
- if (col == 6 && c != '\n'
- && ((continue_flag && !digit_seen)
- || c == ' ' || c == '\t' || c == '0'))
- {
- gfc_current_locus = start;
- start.nextc[0] = ' ';
- start.nextc[1] = ' ';
- continue;
- }
- }
- skip_comment_line ();
- continue;
- }
-
- if (gfc_option.flag_d_lines != -1 && (c == 'd' || c == 'D'))
- {
- if (gfc_option.flag_d_lines == 0)
- {
- skip_comment_line ();
- continue;
- }
- else
- *start.nextc = c = ' ';
- }
-
- col = 1;
-
- while (gfc_is_whitespace (c))
- {
- c = next_char ();
- col++;
- }
-
- if (c == '\n')
- {
- gfc_advance_line ();
- continue;
- }
-
- if (col != 6 && c == '!')
- {
- if (gfc_current_locus.lb != NULL
- && continue_line < gfc_linebuf_linenum (gfc_current_locus.lb))
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb);
- skip_comment_line ();
- continue;
- }
-
- break;
- }
-
- openmp_flag = 0;
- openacc_flag = 0;
- gcc_attribute_flag = 0;
- gfc_current_locus = start;
-}
-
-
-/* Skips the current line if it is a comment. */
-
-void
-gfc_skip_comments (void)
-{
- if (gfc_current_form == FORM_FREE)
- skip_free_comments ();
- else
- skip_fixed_comments ();
-}
-
-
-/* Get the next character from the input, taking continuation lines
- and end-of-line comments into account. This implies that comment
- lines between continued lines must be eaten here. For higher-level
- subroutines, this flattens continued lines into a single logical
- line. The in_string flag denotes whether we're inside a character
- context or not. */
-
-gfc_char_t
-gfc_next_char_literal (gfc_instring in_string)
-{
- static locus omp_acc_err_loc = {};
- locus old_loc;
- int i, prev_openmp_flag, prev_openacc_flag;
- gfc_char_t c;
-
- continue_flag = 0;
- prev_openacc_flag = prev_openmp_flag = 0;
-
-restart:
- c = next_char ();
- if (gfc_at_end ())
- {
- continue_count = 0;
- return c;
- }
-
- if (gfc_current_form == FORM_FREE)
- {
- bool openmp_cond_flag;
-
- if (!in_string && c == '!')
- {
- if (gcc_attribute_flag
- && memcmp (&gfc_current_locus, &gcc_attribute_locus,
- sizeof (gfc_current_locus)) == 0)
- goto done;
-
- if (openmp_flag
- && memcmp (&gfc_current_locus, &openmp_locus,
- sizeof (gfc_current_locus)) == 0)
- goto done;
-
- if (openacc_flag
- && memcmp (&gfc_current_locus, &openacc_locus,
- sizeof (gfc_current_locus)) == 0)
- goto done;
-
- /* This line can't be continued */
- do
- {
- c = next_char ();
- }
- while (c != '\n');
-
- /* Avoid truncation warnings for comment ending lines. */
- gfc_current_locus.lb->truncated = 0;
-
- goto done;
- }
-
- /* Check to see if the continuation line was truncated. */
- if (warn_line_truncation && gfc_current_locus.lb != NULL
- && gfc_current_locus.lb->truncated)
- {
- int maxlen = flag_free_line_length;
- gfc_char_t *current_nextc = gfc_current_locus.nextc;
-
- gfc_current_locus.lb->truncated = 0;
- gfc_current_locus.nextc = gfc_current_locus.lb->line + maxlen;
- gfc_warning_now (OPT_Wline_truncation,
- "Line truncated at %L", &gfc_current_locus);
- gfc_current_locus.nextc = current_nextc;
- }
-
- if (c != '&')
- goto done;
-
- /* If the next nonblank character is a ! or \n, we've got a
- continuation line. */
- old_loc = gfc_current_locus;
-
- c = next_char ();
- while (gfc_is_whitespace (c))
- c = next_char ();
-
- /* Character constants to be continued cannot have commentary
- after the '&'. However, there are cases where we may think we
- are still in a string and we are looking for a possible
- doubled quote and we end up here. See PR64506. */
-
- if (in_string && c != '\n')
- {
- gfc_current_locus = old_loc;
- c = '&';
- goto done;
- }
-
- if (c != '!' && c != '\n')
- {
- gfc_current_locus = old_loc;
- c = '&';
- goto done;
- }
-
- if (flag_openmp)
- prev_openmp_flag = openmp_flag;
- if (flag_openacc)
- prev_openacc_flag = openacc_flag;
-
- /* This can happen if the input file changed or via cpp's #line
- without getting reset (e.g. via input_stmt). It also happens
- when pre-including files via -fpre-include=. */
- if (continue_count == 0
- && gfc_current_locus.lb
- && continue_line > gfc_linebuf_linenum (gfc_current_locus.lb) + 1)
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb) + 1;
-
- continue_flag = 1;
- if (c == '!')
- skip_comment_line ();
- else
- gfc_advance_line ();
-
- if (gfc_at_eof ())
- goto not_continuation;
-
- /* We've got a continuation line. If we are on the very next line after
- the last continuation, increment the continuation line count and
- check whether the limit has been exceeded. */
- if (gfc_linebuf_linenum (gfc_current_locus.lb) == continue_line + 1)
- {
- if (++continue_count == gfc_option.max_continue_free)
- {
- if (gfc_notification_std (GFC_STD_GNU) || pedantic)
- gfc_warning (0, "Limit of %d continuations exceeded in "
- "statement at %C", gfc_option.max_continue_free);
- }
- }
-
- /* Now find where it continues. First eat any comment lines. */
- openmp_cond_flag = skip_free_comments ();
-
- if (gfc_current_locus.lb != NULL
- && continue_line < gfc_linebuf_linenum (gfc_current_locus.lb))
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb);
-
- if (flag_openmp)
- if (prev_openmp_flag != openmp_flag && !openacc_flag)
- {
- gfc_current_locus = old_loc;
- openmp_flag = prev_openmp_flag;
- c = '&';
- goto done;
- }
-
- if (flag_openacc)
- if (prev_openacc_flag != openacc_flag && !openmp_flag)
- {
- gfc_current_locus = old_loc;
- openacc_flag = prev_openacc_flag;
- c = '&';
- goto done;
- }
-
- /* Now that we have a non-comment line, probe ahead for the
- first non-whitespace character. If it is another '&', then
- reading starts at the next character, otherwise we must back
- up to where the whitespace started and resume from there. */
-
- old_loc = gfc_current_locus;
-
- c = next_char ();
- while (gfc_is_whitespace (c))
- c = next_char ();
-
- if (openmp_flag && !openacc_flag)
- {
- for (i = 0; i < 5; i++, c = next_char ())
- {
- gcc_assert (gfc_wide_tolower (c) == (unsigned char) "!$omp"[i]);
- if (i == 4)
- old_loc = gfc_current_locus;
- }
- while (gfc_is_whitespace (c))
- c = next_char ();
- }
- if (openacc_flag && !openmp_flag)
- {
- for (i = 0; i < 5; i++, c = next_char ())
- {
- gcc_assert (gfc_wide_tolower (c) == (unsigned char) "!$acc"[i]);
- if (i == 4)
- old_loc = gfc_current_locus;
- }
- while (gfc_is_whitespace (c))
- c = next_char ();
- }
-
- /* In case we have an OpenMP directive continued by OpenACC
- sentinel, or vice versa, we get both openmp_flag and
- openacc_flag on. */
-
- if (openacc_flag && openmp_flag)
- {
- int is_openmp = 0;
- for (i = 0; i < 5; i++, c = next_char ())
- {
- if (gfc_wide_tolower (c) != (unsigned char) "!$acc"[i])
- is_openmp = 1;
- }
- if (omp_acc_err_loc.nextc != gfc_current_locus.nextc
- || omp_acc_err_loc.lb != gfc_current_locus.lb)
- gfc_error_now (is_openmp
- ? G_("Wrong OpenACC continuation at %C: "
- "expected !$ACC, got !$OMP")
- : G_("Wrong OpenMP continuation at %C: "
- "expected !$OMP, got !$ACC"));
- omp_acc_err_loc = gfc_current_locus;
- goto not_continuation;
- }
-
- if (c != '&')
- {
- if (in_string && gfc_current_locus.nextc)
- {
- gfc_current_locus.nextc--;
- if (warn_ampersand && in_string == INSTRING_WARN)
- gfc_warning (OPT_Wampersand,
- "Missing %<&%> in continued character "
- "constant at %C");
- }
- else if (!in_string && (c == '\'' || c == '"'))
- goto done;
- /* Both !$omp and !$ -fopenmp continuation lines have & on the
- continuation line only optionally. */
- else if (openmp_flag || openacc_flag || openmp_cond_flag)
- {
- if (gfc_current_locus.nextc)
- gfc_current_locus.nextc--;
- }
- else
- {
- c = ' ';
- gfc_current_locus = old_loc;
- goto done;
- }
- }
- }
- else /* Fixed form. */
- {
- /* Fixed form continuation. */
- if (in_string != INSTRING_WARN && c == '!')
- {
- /* Skip comment at end of line. */
- do
- {
- c = next_char ();
- }
- while (c != '\n');
-
- /* Avoid truncation warnings for comment ending lines. */
- gfc_current_locus.lb->truncated = 0;
- }
-
- if (c != '\n')
- goto done;
-
- /* Check to see if the continuation line was truncated. */
- if (warn_line_truncation && gfc_current_locus.lb != NULL
- && gfc_current_locus.lb->truncated)
- {
- gfc_current_locus.lb->truncated = 0;
- gfc_warning_now (OPT_Wline_truncation,
- "Line truncated at %L", &gfc_current_locus);
- }
-
- if (flag_openmp)
- prev_openmp_flag = openmp_flag;
- if (flag_openacc)
- prev_openacc_flag = openacc_flag;
-
- /* This can happen if the input file changed or via cpp's #line
- without getting reset (e.g. via input_stmt). It also happens
- when pre-including files via -fpre-include=. */
- if (continue_count == 0
- && gfc_current_locus.lb
- && continue_line > gfc_linebuf_linenum (gfc_current_locus.lb) + 1)
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb) + 1;
-
- continue_flag = 1;
- old_loc = gfc_current_locus;
-
- gfc_advance_line ();
- skip_fixed_comments ();
-
- /* See if this line is a continuation line. */
- if (flag_openmp && openmp_flag != prev_openmp_flag && !openacc_flag)
- {
- openmp_flag = prev_openmp_flag;
- goto not_continuation;
- }
- if (flag_openacc && openacc_flag != prev_openacc_flag && !openmp_flag)
- {
- openacc_flag = prev_openacc_flag;
- goto not_continuation;
- }
-
- /* In case we have an OpenMP directive continued by OpenACC
- sentinel, or vice versa, we get both openmp_flag and
- openacc_flag on. */
- if (openacc_flag && openmp_flag)
- {
- int is_openmp = 0;
- for (i = 0; i < 5; i++)
- {
- c = next_char ();
- if (gfc_wide_tolower (c) != (unsigned char) "*$acc"[i])
- is_openmp = 1;
- }
- if (omp_acc_err_loc.nextc != gfc_current_locus.nextc
- || omp_acc_err_loc.lb != gfc_current_locus.lb)
- gfc_error_now (is_openmp
- ? G_("Wrong OpenACC continuation at %C: "
- "expected !$ACC, got !$OMP")
- : G_("Wrong OpenMP continuation at %C: "
- "expected !$OMP, got !$ACC"));
- omp_acc_err_loc = gfc_current_locus;
- goto not_continuation;
- }
- else if (!openmp_flag && !openacc_flag)
- for (i = 0; i < 5; i++)
- {
- c = next_char ();
- if (c != ' ')
- goto not_continuation;
- }
- else if (openmp_flag)
- for (i = 0; i < 5; i++)
- {
- c = next_char ();
- if (gfc_wide_tolower (c) != (unsigned char) "*$omp"[i])
- goto not_continuation;
- }
- else if (openacc_flag)
- for (i = 0; i < 5; i++)
- {
- c = next_char ();
- if (gfc_wide_tolower (c) != (unsigned char) "*$acc"[i])
- goto not_continuation;
- }
-
- c = next_char ();
- if (c == '0' || c == ' ' || c == '\n')
- goto not_continuation;
-
- /* We've got a continuation line. If we are on the very next line after
- the last continuation, increment the continuation line count and
- check whether the limit has been exceeded. */
- if (gfc_linebuf_linenum (gfc_current_locus.lb) == continue_line + 1)
- {
- if (++continue_count == gfc_option.max_continue_fixed)
- {
- if (gfc_notification_std (GFC_STD_GNU) || pedantic)
- gfc_warning (0, "Limit of %d continuations exceeded in "
- "statement at %C",
- gfc_option.max_continue_fixed);
- }
- }
-
- if (gfc_current_locus.lb != NULL
- && continue_line < gfc_linebuf_linenum (gfc_current_locus.lb))
- continue_line = gfc_linebuf_linenum (gfc_current_locus.lb);
- }
-
- /* Ready to read first character of continuation line, which might
- be another continuation line! */
- goto restart;
-
-not_continuation:
- c = '\n';
- gfc_current_locus = old_loc;
- end_flag = 0;
-
-done:
- if (c == '\n')
- continue_count = 0;
- continue_flag = 0;
- return c;
-}
-
-
-/* Get the next character of input, folded to lowercase. In fixed
- form mode, we also ignore spaces. When matcher subroutines are
- parsing character literals, they have to call
- gfc_next_char_literal(). */
-
-gfc_char_t
-gfc_next_char (void)
-{
- gfc_char_t c;
-
- do
- {
- c = gfc_next_char_literal (NONSTRING);
- }
- while (gfc_current_form == FORM_FIXED && gfc_is_whitespace (c));
-
- return gfc_wide_tolower (c);
-}
-
-char
-gfc_next_ascii_char (void)
-{
- gfc_char_t c = gfc_next_char ();
-
- return (gfc_wide_fits_in_byte (c) ? (unsigned char) c
- : (unsigned char) UCHAR_MAX);
-}
-
-
-gfc_char_t
-gfc_peek_char (void)
-{
- locus old_loc;
- gfc_char_t c;
-
- old_loc = gfc_current_locus;
- c = gfc_next_char ();
- gfc_current_locus = old_loc;
-
- return c;
-}
-
-
-char
-gfc_peek_ascii_char (void)
-{
- gfc_char_t c = gfc_peek_char ();
-
- return (gfc_wide_fits_in_byte (c) ? (unsigned char) c
- : (unsigned char) UCHAR_MAX);
-}
-
-
-/* Recover from an error. We try to get past the current statement
- and get lined up for the next. The next statement follows a '\n'
- or a ';'. We also assume that we are not within a character
- constant, and deal with finding a '\'' or '"'. */
-
-void
-gfc_error_recovery (void)
-{
- gfc_char_t c, delim;
-
- if (gfc_at_eof ())
- return;
-
- for (;;)
- {
- c = gfc_next_char ();
- if (c == '\n' || c == ';')
- break;
-
- if (c != '\'' && c != '"')
- {
- if (gfc_at_eof ())
- break;
- continue;
- }
- delim = c;
-
- for (;;)
- {
- c = next_char ();
-
- if (c == delim)
- break;
- if (c == '\n')
- return;
- if (c == '\\')
- {
- c = next_char ();
- if (c == '\n')
- return;
- }
- }
- if (gfc_at_eof ())
- break;
- }
-}
-
-
-/* Read ahead until the next character to be read is not whitespace. */
-
-void
-gfc_gobble_whitespace (void)
-{
- static int linenum = 0;
- locus old_loc;
- gfc_char_t c;
-
- do
- {
- old_loc = gfc_current_locus;
- c = gfc_next_char_literal (NONSTRING);
- /* Issue a warning for nonconforming tabs. We keep track of the line
- number because the Fortran matchers will often back up and the same
- line will be scanned multiple times. */
- if (warn_tabs && c == '\t')
- {
- int cur_linenum = LOCATION_LINE (gfc_current_locus.lb->location);
- if (cur_linenum != linenum)
- {
- linenum = cur_linenum;
- gfc_warning_now (OPT_Wtabs, "Nonconforming tab character at %C");
- }
- }
- }
- while (gfc_is_whitespace (c));
-
- if (!ISPRINT(c) && c != '\n' && last_error_char != gfc_current_locus.nextc)
- {
- char buf[20];
- last_error_char = gfc_current_locus.nextc;
- snprintf (buf, 20, "%2.2X", c);
- gfc_error_now ("Invalid character 0x%s at %C", buf);
- }
-
- gfc_current_locus = old_loc;
-}
-
-
-/* Load a single line into pbuf.
-
- If pbuf points to a NULL pointer, it is allocated.
- We truncate lines that are too long, unless we're dealing with
- preprocessor lines or if the option -ffixed-line-length-none is set,
- in which case we reallocate the buffer to fit the entire line, if
- need be.
- In fixed mode, we expand a tab that occurs within the statement
- label region to expand to spaces that leave the next character in
- the source region.
-
- If first_char is not NULL, it's a pointer to a single char value holding
- the first character of the line, which has already been read by the
- caller. This avoids the use of ungetc().
-
- load_line returns whether the line was truncated.
-
- NOTE: The error machinery isn't available at this point, so we can't
- easily report line and column numbers consistent with other
- parts of gfortran. */
-
-static int
-load_line (FILE *input, gfc_char_t **pbuf, int *pbuflen, const int *first_char)
-{
- int c, maxlen, i, preprocessor_flag, buflen = *pbuflen;
- int quoted = ' ', comment_ix = -1;
- bool seen_comment = false;
- bool first_comment = true;
- bool trunc_flag = false;
- bool seen_printable = false;
- bool seen_ampersand = false;
- bool found_tab = false;
- bool warned_tabs = false;
- gfc_char_t *buffer;
-
- /* Determine the maximum allowed line length. */
- if (gfc_current_form == FORM_FREE)
- maxlen = flag_free_line_length;
- else if (gfc_current_form == FORM_FIXED)
- maxlen = flag_fixed_line_length;
- else
- maxlen = 72;
-
- if (*pbuf == NULL)
- {
- /* Allocate the line buffer, storing its length into buflen.
- Note that if maxlen==0, indicating that arbitrary-length lines
- are allowed, the buffer will be reallocated if this length is
- insufficient; since 132 characters is the length of a standard
- free-form line, we use that as a starting guess. */
- if (maxlen > 0)
- buflen = maxlen;
- else
- buflen = 132;
-
- *pbuf = gfc_get_wide_string (buflen + 1);
- }
-
- i = 0;
- buffer = *pbuf;
-
- if (first_char)
- c = *first_char;
- else
- c = getc (input);
-
- /* In order to not truncate preprocessor lines, we have to
- remember that this is one. */
- preprocessor_flag = (c == '#');
-
- for (;;)
- {
- if (c == EOF)
- break;
-
- if (c == '\n')
- {
- /* Check for illegal use of ampersand. See F95 Standard 3.3.1.3. */
- if (gfc_current_form == FORM_FREE
- && !seen_printable && seen_ampersand)
- {
- if (pedantic)
- gfc_error_now ("%<&%> not allowed by itself in line %d",
- current_file->line);
- else
- gfc_warning_now (0, "%<&%> not allowed by itself in line %d",
- current_file->line);
- }
- break;
- }
-
- if (c == '\r' || c == '\0')
- goto next_char; /* Gobble characters. */
-
- if (c == '&')
- {
- if (seen_ampersand)
- {
- seen_ampersand = false;
- seen_printable = true;
- }
- else
- seen_ampersand = true;
- }
-
- if ((c != '&' && c != '!' && c != ' ') || (c == '!' && !seen_ampersand))
- seen_printable = true;
-
- /* Is this a fixed-form comment? */
- if (gfc_current_form == FORM_FIXED && i == 0
- && (c == '*' || c == 'c' || c == 'C'
- || (gfc_option.flag_d_lines != -1 && (c == 'd' || c == 'D'))))
- {
- seen_comment = true;
- comment_ix = i;
- }
-
- if (quoted == ' ')
- {
- if (c == '\'' || c == '"')
- quoted = c;
- }
- else if (c == quoted)
- quoted = ' ';
-
- /* Is this a free-form comment? */
- if (c == '!' && quoted == ' ')
- {
- if (seen_comment)
- first_comment = false;
- seen_comment = true;
- comment_ix = i;
- }
-
- /* For truncation and tab warnings, set seen_comment to false if one has
- either an OpenMP or OpenACC directive - or a !GCC$ attribute. If
- OpenMP is enabled, use '!$' as as conditional compilation sentinel
- and OpenMP directive ('!$omp'). */
- if (seen_comment && first_comment && flag_openmp && comment_ix + 1 == i
- && c == '$')
- first_comment = seen_comment = false;
- if (seen_comment && first_comment && comment_ix + 4 == i)
- {
- if (((*pbuf)[comment_ix+1] == 'g' || (*pbuf)[comment_ix+1] == 'G')
- && ((*pbuf)[comment_ix+2] == 'c' || (*pbuf)[comment_ix+2] == 'C')
- && ((*pbuf)[comment_ix+3] == 'c' || (*pbuf)[comment_ix+3] == 'C')
- && c == '$')
- first_comment = seen_comment = false;
- if (flag_openacc
- && (*pbuf)[comment_ix+1] == '$'
- && ((*pbuf)[comment_ix+2] == 'a' || (*pbuf)[comment_ix+2] == 'A')
- && ((*pbuf)[comment_ix+3] == 'c' || (*pbuf)[comment_ix+3] == 'C')
- && (c == 'c' || c == 'C'))
- first_comment = seen_comment = false;
- }
-
- /* Vendor extension: "<tab>1" marks a continuation line. */
- if (found_tab)
- {
- found_tab = false;
- if (c >= '1' && c <= '9')
- {
- *(buffer-1) = c;
- goto next_char;
- }
- }
-
- if (gfc_current_form == FORM_FIXED && c == '\t' && i < 6)
- {
- found_tab = true;
-
- if (warn_tabs && seen_comment == 0 && !warned_tabs)
- {
- warned_tabs = true;
- gfc_warning_now (OPT_Wtabs,
- "Nonconforming tab character in column %d "
- "of line %d", i + 1, current_file->line);
- }
-
- while (i < 6)
- {
- *buffer++ = ' ';
- i++;
- }
-
- goto next_char;
- }
-
- *buffer++ = c;
- i++;
-
- if (maxlen == 0 || preprocessor_flag)
- {
- if (i >= buflen)
- {
- /* Reallocate line buffer to double size to hold the
- overlong line. */
- buflen = buflen * 2;
- *pbuf = XRESIZEVEC (gfc_char_t, *pbuf, (buflen + 1));
- buffer = (*pbuf) + i;
- }
- }
- else if (i >= maxlen)
- {
- bool trunc_warn = true;
-
- /* Enhancement, if the very next non-space character is an ampersand
- or comment that we would otherwise warn about, don't mark as
- truncated. */
-
- /* Truncate the rest of the line. */
- for (;;)
- {
- c = getc (input);
- if (c == '\r' || c == ' ')
- continue;
-
- if (c == '\n' || c == EOF)
- break;
-
- if (!trunc_warn && c != '!')
- trunc_warn = true;
-
- if (trunc_warn && ((gfc_current_form == FORM_FIXED && c == '&')
- || c == '!'))
- trunc_warn = false;
-
- if (c == '!')
- seen_comment = 1;
-
- if (trunc_warn && !seen_comment)
- trunc_flag = 1;
- }
-
- c = '\n';
- continue;
- }
-
-next_char:
- c = getc (input);
- }
-
- /* Pad lines to the selected line length in fixed form. */
- if (gfc_current_form == FORM_FIXED
- && flag_fixed_line_length != 0
- && flag_pad_source
- && !preprocessor_flag
- && c != EOF)
- {
- while (i++ < maxlen)
- *buffer++ = ' ';
- }
-
- *buffer = '\0';
- *pbuflen = buflen;
-
- return trunc_flag;
-}
-
-
-/* Get a gfc_file structure, initialize it and add it to
- the file stack. */
-
-static gfc_file *
-get_file (const char *name, enum lc_reason reason)
-{
- gfc_file *f;
-
- f = XCNEW (gfc_file);
-
- f->filename = xstrdup (name);
-
- f->next = file_head;
- file_head = f;
-
- f->up = current_file;
- if (current_file != NULL)
- f->inclusion_line = current_file->line;
-
- linemap_add (line_table, reason, false, f->filename, 1);
-
- return f;
-}
-
-
-/* Deal with a line from the C preprocessor. The
- initial octothorp has already been seen. */
-
-static void
-preprocessor_line (gfc_char_t *c)
-{
- bool flag[5];
- int i, line;
- gfc_char_t *wide_filename;
- gfc_file *f;
- int escaped, unescape;
- char *filename;
-
- c++;
- while (*c == ' ' || *c == '\t')
- c++;
-
- if (*c < '0' || *c > '9')
- goto bad_cpp_line;
-
- line = wide_atoi (c);
-
- c = wide_strchr (c, ' ');
- if (c == NULL)
- {
- /* No file name given. Set new line number. */
- current_file->line = line;
- return;
- }
-
- /* Skip spaces. */
- while (*c == ' ' || *c == '\t')
- c++;
-
- /* Skip quote. */
- if (*c != '"')
- goto bad_cpp_line;
- ++c;
-
- wide_filename = c;
-
- /* Make filename end at quote. */
- unescape = 0;
- escaped = false;
- while (*c && ! (!escaped && *c == '"'))
- {
- if (escaped)
- escaped = false;
- else if (*c == '\\')
- {
- escaped = true;
- unescape++;
- }
- ++c;
- }
-
- if (! *c)
- /* Preprocessor line has no closing quote. */
- goto bad_cpp_line;
-
- *c++ = '\0';
-
- /* Undo effects of cpp_quote_string. */
- if (unescape)
- {
- gfc_char_t *s = wide_filename;
- gfc_char_t *d = gfc_get_wide_string (c - wide_filename - unescape);
-
- wide_filename = d;
- while (*s)
- {
- if (*s == '\\')
- *d++ = *++s;
- else
- *d++ = *s;
- s++;
- }
- *d = '\0';
- }
-
- /* Get flags. */
-
- flag[1] = flag[2] = flag[3] = flag[4] = false;
-
- for (;;)
- {
- c = wide_strchr (c, ' ');
- if (c == NULL)
- break;
-
- c++;
- i = wide_atoi (c);
-
- if (i >= 1 && i <= 4)
- flag[i] = true;
- }
-
- /* Convert the filename in wide characters into a filename in narrow
- characters. */
- filename = gfc_widechar_to_char (wide_filename, -1);
-
- /* Interpret flags. */
-
- if (flag[1]) /* Starting new file. */
- {
- f = get_file (filename, LC_RENAME);
- add_file_change (f->filename, f->inclusion_line);
- current_file = f;
- }
-
- if (flag[2]) /* Ending current file. */
- {
- if (!current_file->up
- || filename_cmp (current_file->up->filename, filename) != 0)
- {
- linemap_line_start (line_table, current_file->line, 80);
- /* ??? One could compute the exact column where the filename
- starts and compute the exact location here. */
- gfc_warning_now_at (linemap_position_for_column (line_table, 1),
- 0, "file %qs left but not entered",
- filename);
- current_file->line++;
- if (unescape)
- free (wide_filename);
- free (filename);
- return;
- }
-
- add_file_change (NULL, line);
- current_file = current_file->up;
- linemap_add (line_table, LC_RENAME, false, current_file->filename,
- current_file->line);
- }
-
- /* The name of the file can be a temporary file produced by
- cpp. Replace the name if it is different. */
-
- if (filename_cmp (current_file->filename, filename) != 0)
- {
- /* FIXME: we leak the old filename because a pointer to it may be stored
- in the linemap. Alternative could be using GC or updating linemap to
- point to the new name, but there is no API for that currently. */
- current_file->filename = xstrdup (filename);
-
- /* We need to tell the linemap API that the filename changed. Just
- changing current_file is insufficient. */
- linemap_add (line_table, LC_RENAME, false, current_file->filename, line);
- }
-
- /* Set new line number. */
- current_file->line = line;
- if (unescape)
- free (wide_filename);
- free (filename);
- return;
-
- bad_cpp_line:
- linemap_line_start (line_table, current_file->line, 80);
- /* ??? One could compute the exact column where the directive
- starts and compute the exact location here. */
- gfc_warning_now_at (linemap_position_for_column (line_table, 2), 0,
- "Illegal preprocessor directive");
- current_file->line++;
-}
-
-
-static void load_file (const char *, const char *, bool);
-
-/* include_line()-- Checks a line buffer to see if it is an include
- line. If so, we call load_file() recursively to load the included
- file. We never return a syntax error because a statement like
- "include = 5" is perfectly legal. We return 0 if no include was
- processed, 1 if we matched an include or -1 if include was
- partially processed, but will need continuation lines. */
-
-static int
-include_line (gfc_char_t *line)
-{
- gfc_char_t quote, *c, *begin, *stop;
- char *filename;
- const char *include = "include";
- bool allow_continuation = flag_dec_include;
- int i;
-
- c = line;
-
- if (flag_openmp || flag_openmp_simd)
- {
- if (gfc_current_form == FORM_FREE)
- {
- while (*c == ' ' || *c == '\t')
- c++;
- if (*c == '!' && c[1] == '$' && (c[2] == ' ' || c[2] == '\t'))
- c += 3;
- }
- else
- {
- if ((*c == '!' || *c == 'c' || *c == 'C' || *c == '*')
- && c[1] == '$' && c[2] == ' ')
- c += 3;
- }
- }
-
- if (gfc_current_form == FORM_FREE)
- {
- while (*c == ' ' || *c == '\t')
- c++;
- if (gfc_wide_strncasecmp (c, "include", 7))
- {
- if (!allow_continuation)
- return 0;
- for (i = 0; i < 7; ++i)
- {
- gfc_char_t c1 = gfc_wide_tolower (*c);
- if (c1 != (unsigned char) include[i])
- break;
- c++;
- }
- if (i == 0 || *c != '&')
- return 0;
- c++;
- while (*c == ' ' || *c == '\t')
- c++;
- if (*c == '\0' || *c == '!')
- return -1;
- return 0;
- }
-
- c += 7;
- }
- else
- {
- while (*c == ' ' || *c == '\t')
- c++;
- if (flag_dec_include && *c == '0' && c - line == 5)
- {
- c++;
- while (*c == ' ' || *c == '\t')
- c++;
- }
- if (c - line < 6)
- allow_continuation = false;
- for (i = 0; i < 7; ++i)
- {
- gfc_char_t c1 = gfc_wide_tolower (*c);
- if (c1 != (unsigned char) include[i])
- break;
- c++;
- while (*c == ' ' || *c == '\t')
- c++;
- }
- if (!allow_continuation)
- {
- if (i != 7)
- return 0;
- }
- else if (i != 7)
- {
- if (i == 0)
- return 0;
-
- /* At the end of line or comment this might be continued. */
- if (*c == '\0' || *c == '!')
- return -1;
-
- return 0;
- }
- }
-
- while (*c == ' ' || *c == '\t')
- c++;
-
- /* Find filename between quotes. */
-
- quote = *c++;
- if (quote != '"' && quote != '\'')
- {
- if (allow_continuation)
- {
- if (gfc_current_form == FORM_FREE)
- {
- if (quote == '&')
- {
- while (*c == ' ' || *c == '\t')
- c++;
- if (*c == '\0' || *c == '!')
- return -1;
- }
- }
- else if (quote == '\0' || quote == '!')
- return -1;
- }
- return 0;
- }
-
- begin = c;
-
- bool cont = false;
- while (*c != quote && *c != '\0')
- {
- if (allow_continuation && gfc_current_form == FORM_FREE)
- {
- if (*c == '&')
- cont = true;
- else if (*c != ' ' && *c != '\t')
- cont = false;
- }
- c++;
- }
-
- if (*c == '\0')
- {
- if (allow_continuation
- && (cont || gfc_current_form != FORM_FREE))
- return -1;
- return 0;
- }
-
- stop = c++;
-
- while (*c == ' ' || *c == '\t')
- c++;
-
- if (*c != '\0' && *c != '!')
- return 0;
-
- /* We have an include line at this point. */
-
- *stop = '\0'; /* It's ok to trash the buffer, as this line won't be
- read by anything else. */
-
- filename = gfc_widechar_to_char (begin, -1);
- load_file (filename, NULL, false);
- free (filename);
- return 1;
-}
-
-/* Similarly, but try to parse an INCLUDE statement, using gfc_next_char etc.
- APIs. Return 1 if recognized as valid INCLUDE statement and load_file has
- been called, 0 if it is not a valid INCLUDE statement and -1 if eof has
- been encountered while parsing it. */
-static int
-include_stmt (gfc_linebuf *b)
-{
- int ret = 0, i, length;
- const char *include = "include";
- gfc_char_t c, quote = 0;
- locus str_locus;
- char *filename;
-
- continue_flag = 0;
- end_flag = 0;
- gcc_attribute_flag = 0;
- openmp_flag = 0;
- openacc_flag = 0;
- continue_count = 0;
- continue_line = 0;
- gfc_current_locus.lb = b;
- gfc_current_locus.nextc = b->line;
-
- gfc_skip_comments ();
- gfc_gobble_whitespace ();
-
- for (i = 0; i < 7; i++)
- {
- c = gfc_next_char ();
- if (c != (unsigned char) include[i])
- {
- if (gfc_current_form == FORM_FIXED
- && i == 0
- && c == '0'
- && gfc_current_locus.nextc == b->line + 6)
- {
- gfc_gobble_whitespace ();
- i--;
- continue;
- }
- gcc_assert (i != 0);
- if (c == '\n')
- {
- gfc_advance_line ();
- gfc_skip_comments ();
- if (gfc_at_eof ())
- ret = -1;
- }
- goto do_ret;
- }
- }
- gfc_gobble_whitespace ();
-
- c = gfc_next_char ();
- if (c == '\'' || c == '"')
- quote = c;
- else
- {
- if (c == '\n')
- {
- gfc_advance_line ();
- gfc_skip_comments ();
- if (gfc_at_eof ())
- ret = -1;
- }
- goto do_ret;
- }
-
- str_locus = gfc_current_locus;
- length = 0;
- do
- {
- c = gfc_next_char_literal (INSTRING_NOWARN);
- if (c == quote)
- break;
- if (c == '\n')
- {
- gfc_advance_line ();
- gfc_skip_comments ();
- if (gfc_at_eof ())
- ret = -1;
- goto do_ret;
- }
- length++;
- }
- while (1);
-
- gfc_gobble_whitespace ();
- c = gfc_next_char ();
- if (c != '\n')
- goto do_ret;
-
- gfc_current_locus = str_locus;
- ret = 1;
- filename = XNEWVEC (char, length + 1);
- for (i = 0; i < length; i++)
- {
- c = gfc_next_char_literal (INSTRING_WARN);
- gcc_assert (gfc_wide_fits_in_byte (c));
- filename[i] = (unsigned char) c;
- }
- filename[length] = '\0';
- load_file (filename, NULL, false);
- free (filename);
-
-do_ret:
- continue_flag = 0;
- end_flag = 0;
- gcc_attribute_flag = 0;
- openmp_flag = 0;
- openacc_flag = 0;
- continue_count = 0;
- continue_line = 0;
- memset (&gfc_current_locus, '\0', sizeof (locus));
- memset (&openmp_locus, '\0', sizeof (locus));
- memset (&openacc_locus, '\0', sizeof (locus));
- memset (&gcc_attribute_locus, '\0', sizeof (locus));
- return ret;
-}
-
-
-
-/* Load a file into memory by calling load_line until the file ends. */
-
-static void
-load_file (const char *realfilename, const char *displayedname, bool initial)
-{
- gfc_char_t *line;
- gfc_linebuf *b, *include_b = NULL;
- gfc_file *f;
- FILE *input;
- int len, line_len;
- bool first_line;
- struct stat st;
- int stat_result;
- const char *filename;
- /* If realfilename and displayedname are different and non-null then
- surely realfilename is the preprocessed form of
- displayedname. */
- bool preprocessed_p = (realfilename && displayedname
- && strcmp (realfilename, displayedname));
-
- filename = displayedname ? displayedname : realfilename;
-
- for (f = current_file; f; f = f->up)
- if (filename_cmp (filename, f->filename) == 0)
- fatal_error (linemap_line_start (line_table, current_file->line, 0),
- "File %qs is being included recursively", filename);
- if (initial)
- {
- if (gfc_src_file)
- {
- input = gfc_src_file;
- gfc_src_file = NULL;
- }
- else
- input = gfc_open_file (realfilename);
-
- if (input == NULL)
- gfc_fatal_error ("Cannot open file %qs", filename);
- }
- else
- {
- input = gfc_open_included_file (realfilename, false, false);
- if (input == NULL)
- {
- /* For -fpre-include file, current_file is NULL. */
- if (current_file)
- fatal_error (linemap_line_start (line_table, current_file->line, 0),
- "Cannot open included file %qs", filename);
- else
- gfc_fatal_error ("Cannot open pre-included file %qs", filename);
- }
- stat_result = stat (realfilename, &st);
- if (stat_result == 0 && !S_ISREG (st.st_mode))
- {
- fclose (input);
- if (current_file)
- fatal_error (linemap_line_start (line_table, current_file->line, 0),
- "Included file %qs is not a regular file", filename);
- else
- gfc_fatal_error ("Included file %qs is not a regular file", filename);
- }
- }
-
- /* Load the file.
-
- A "non-initial" file means a file that is being included. In
- that case we are creating an LC_ENTER map.
-
- An "initial" file means a main file; one that is not included.
- That file has already got at least one (surely more) line map(s)
- created by gfc_init. So the subsequent map created in that case
- must have LC_RENAME reason.
-
- This latter case is not true for a preprocessed file. In that
- case, although the file is "initial", the line maps created by
- gfc_init was used during the preprocessing of the file. Now that
- the preprocessing is over and we are being fed the result of that
- preprocessing, we need to create a brand new line map for the
- preprocessed file, so the reason is going to be LC_ENTER. */
-
- f = get_file (filename, (initial && !preprocessed_p) ? LC_RENAME : LC_ENTER);
- if (!initial)
- add_file_change (f->filename, f->inclusion_line);
- current_file = f;
- current_file->line = 1;
- line = NULL;
- line_len = 0;
- first_line = true;
-
- if (initial && gfc_src_preprocessor_lines[0])
- {
- preprocessor_line (gfc_src_preprocessor_lines[0]);
- free (gfc_src_preprocessor_lines[0]);
- gfc_src_preprocessor_lines[0] = NULL;
- if (gfc_src_preprocessor_lines[1])
- {
- preprocessor_line (gfc_src_preprocessor_lines[1]);
- free (gfc_src_preprocessor_lines[1]);
- gfc_src_preprocessor_lines[1] = NULL;
- }
- }
-
- for (;;)
- {
- int trunc = load_line (input, &line, &line_len, NULL);
- int inc_line;
-
- len = gfc_wide_strlen (line);
- if (feof (input) && len == 0)
- break;
-
- /* If this is the first line of the file, it can contain a byte
- order mark (BOM), which we will ignore:
- FF FE is UTF-16 little endian,
- FE FF is UTF-16 big endian,
- EF BB BF is UTF-8. */
- if (first_line
- && ((line_len >= 2 && line[0] == (unsigned char) '\xFF'
- && line[1] == (unsigned char) '\xFE')
- || (line_len >= 2 && line[0] == (unsigned char) '\xFE'
- && line[1] == (unsigned char) '\xFF')
- || (line_len >= 3 && line[0] == (unsigned char) '\xEF'
- && line[1] == (unsigned char) '\xBB'
- && line[2] == (unsigned char) '\xBF')))
- {
- int n = line[1] == (unsigned char) '\xBB' ? 3 : 2;
- gfc_char_t *new_char = gfc_get_wide_string (line_len);
-
- wide_strcpy (new_char, &line[n]);
- free (line);
- line = new_char;
- len -= n;
- }
-
- /* There are three things this line can be: a line of Fortran
- source, an include line or a C preprocessor directive. */
-
- if (line[0] == '#')
- {
- /* When -g3 is specified, it's possible that we emit #define
- and #undef lines, which we need to pass to the middle-end
- so that it can emit correct debug info. */
- if (debug_info_level == DINFO_LEVEL_VERBOSE
- && (wide_strncmp (line, "#define ", 8) == 0
- || wide_strncmp (line, "#undef ", 7) == 0))
- ;
- else
- {
- preprocessor_line (line);
- continue;
- }
- }
-
- /* Preprocessed files have preprocessor lines added before the byte
- order mark, so first_line is not about the first line of the file
- but the first line that's not a preprocessor line. */
- first_line = false;
-
- inc_line = include_line (line);
- if (inc_line > 0)
- {
- current_file->line++;
- continue;
- }
-
- /* Add line. */
-
- b = XCNEWVAR (gfc_linebuf, gfc_linebuf_header_size
- + (len + 1) * sizeof (gfc_char_t));
-
-
- b->location
- = linemap_line_start (line_table, current_file->line++, len);
- /* ??? We add the location for the maximum column possible here,
- because otherwise if the next call creates a new line-map, it
- will not reserve space for any offset. */
- if (len > 0)
- linemap_position_for_column (line_table, len);
-
- b->file = current_file;
- b->truncated = trunc;
- wide_strcpy (b->line, line);
-
- if (line_head == NULL)
- line_head = b;
- else
- line_tail->next = b;
-
- line_tail = b;
-
- while (file_changes_cur < file_changes_count)
- file_changes[file_changes_cur++].lb = b;
-
- if (flag_dec_include)
- {
- if (include_b && b != include_b)
- {
- int inc_line2 = include_stmt (include_b);
- if (inc_line2 == 0)
- include_b = NULL;
- else if (inc_line2 > 0)
- {
- do
- {
- if (gfc_current_form == FORM_FIXED)
- {
- for (gfc_char_t *p = include_b->line; *p; p++)
- *p = ' ';
- }
- else
- include_b->line[0] = '\0';
- if (include_b == b)
- break;
- include_b = include_b->next;
- }
- while (1);
- include_b = NULL;
- }
- }
- if (inc_line == -1 && !include_b)
- include_b = b;
- }
- }
-
- /* Release the line buffer allocated in load_line. */
- free (line);
-
- fclose (input);
-
- if (!initial)
- add_file_change (NULL, current_file->inclusion_line + 1);
- current_file = current_file->up;
- linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
-}
-
-
-/* Open a new file and start scanning from that file. Returns true
- if everything went OK, false otherwise. If form == FORM_UNKNOWN
- it tries to determine the source form from the filename, defaulting
- to free form. */
-
-void
-gfc_new_file (void)
-{
- if (flag_pre_include != NULL)
- load_file (flag_pre_include, NULL, false);
-
- if (gfc_cpp_enabled ())
- {
- gfc_cpp_preprocess (gfc_source_file);
- if (!gfc_cpp_preprocess_only ())
- load_file (gfc_cpp_temporary_file (), gfc_source_file, true);
- }
- else
- load_file (gfc_source_file, NULL, true);
-
- gfc_current_locus.lb = line_head;
- gfc_current_locus.nextc = (line_head == NULL) ? NULL : line_head->line;
-
-#if 0 /* Debugging aid. */
- for (; line_head; line_head = line_head->next)
- printf ("%s:%3d %s\n", LOCATION_FILE (line_head->location),
- LOCATION_LINE (line_head->location), line_head->line);
-
- exit (SUCCESS_EXIT_CODE);
-#endif
-}
-
-static char *
-unescape_filename (const char *ptr)
-{
- const char *p = ptr, *s;
- char *d, *ret;
- int escaped, unescape = 0;
-
- /* Make filename end at quote. */
- escaped = false;
- while (*p && ! (! escaped && *p == '"'))
- {
- if (escaped)
- escaped = false;
- else if (*p == '\\')
- {
- escaped = true;
- unescape++;
- }
- ++p;
- }
-
- if (!*p || p[1])
- return NULL;
-
- /* Undo effects of cpp_quote_string. */
- s = ptr;
- d = XCNEWVEC (char, p + 1 - ptr - unescape);
- ret = d;
-
- while (s != p)
- {
- if (*s == '\\')
- *d++ = *++s;
- else
- *d++ = *s;
- s++;
- }
- *d = '\0';
- return ret;
-}
-
-/* For preprocessed files, if the first tokens are of the form # NUM.
- handle the directives so we know the original file name. */
-
-const char *
-gfc_read_orig_filename (const char *filename, const char **canon_source_file)
-{
- int c, len;
- char *dirname, *tmp;
-
- gfc_src_file = gfc_open_file (filename);
- if (gfc_src_file == NULL)
- return NULL;
-
- c = getc (gfc_src_file);
-
- if (c != '#')
- return NULL;
-
- len = 0;
- load_line (gfc_src_file, &gfc_src_preprocessor_lines[0], &len, &c);
-
- if (wide_strncmp (gfc_src_preprocessor_lines[0], "# 1 \"", 5) != 0)
- return NULL;
-
- tmp = gfc_widechar_to_char (&gfc_src_preprocessor_lines[0][5], -1);
- filename = unescape_filename (tmp);
- free (tmp);
- if (filename == NULL)
- return NULL;
-
- c = getc (gfc_src_file);
-
- if (c != '#')
- return filename;
-
- len = 0;
- load_line (gfc_src_file, &gfc_src_preprocessor_lines[1], &len, &c);
-
- if (wide_strncmp (gfc_src_preprocessor_lines[1], "# 1 \"", 5) != 0)
- return filename;
-
- tmp = gfc_widechar_to_char (&gfc_src_preprocessor_lines[1][5], -1);
- dirname = unescape_filename (tmp);
- free (tmp);
- if (dirname == NULL)
- return filename;
-
- len = strlen (dirname);
- if (len < 3 || dirname[len - 1] != '/' || dirname[len - 2] != '/')
- {
- free (dirname);
- return filename;
- }
- dirname[len - 2] = '\0';
- set_src_pwd (dirname);
-
- if (! IS_ABSOLUTE_PATH (filename))
- {
- char *p = XCNEWVEC (char, len + strlen (filename));
-
- memcpy (p, dirname, len - 2);
- p[len - 2] = '/';
- strcpy (p + len - 1, filename);
- *canon_source_file = p;
- }
-
- free (dirname);
- return filename;
-}