%{ /* * Copyright (C) 2000-2006 Erik Edelmann * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public * License version 2 as published by the Free Software * Foundation. * * This program 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 this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ #include #include #include #include #ifdef HAVE_ALLOCA_H # include #endif #include "finddep.h" #include "utils.h" #include "errormesg.h" #include "global.h" #include "macro.h" #include "modfile_name.h" static char *sourcefile; static char *curr_file; static Dependency *dep; /* Dependencies of the file */ static List *modules; /* Modules defined in the file */ static List *macrolist; static char *filestack[INCLUDE_RECURSION_LIMIT+1]; static int filestack_i; static int pp_ignore; /* In 'false'-branch of a pre-processor 'if' */ static bool skip_to_end[20]; static int skip_i; static bool in_interface = false; int yyerror(const char *s); static int modcmp(const void *m1, const void *m2); SourceFmt get_format(const char *filename); void handle_include(const char *incfile); Macro *defmac; /* Defined in lexer.l */ int yylex(); bool lex_include_file(const char *incfile); void lex_set_format(SourceFmt fmt); %} %union { char *string; int number; } %token EOSTMT ASSIGNMENT_OP GARBAGE %token CPP_INCLUDE F90PPR_INCLUDE COCO_INCLUDE %token F90PPR_DEFINE CPP_DEFINE F90PPR_UNDEF CPP_UNDEF %token CPP_IFDEF CPP_IFNDEF CPP_IF CPP_ELSE CPP_ELIF CPP_ENDIF %token F90PPR_IFDEF F90PPR_IFNDEF F90PPR_IF F90PPR_ELSE F90PPR_ELIF F90PPR_ENDIF %token CPP_TOENDL %token UNTERMINATED_STRING %token STRING WORD %% code: /* empty */ | code stmt ; stmt: keyword_stmt | assignment_stmt ; assignment_stmt: WORD ASSIGNMENT_OP other EOSTMT /* Ignore */ keyword_stmt: WORD EOSTMT { if (strcasecmp($1, "interface") == 0) in_interface = true; free($1); } | WORD WORD other EOSTMT { if (strcasecmp($1, "use") == 0) { if (!pp_ignore) { DEBUG_PRINT("Use '%s'\n", $2); if (!list_find(options.ignore_mods, $2,COMP_FUN(&strcasecmp))) { if (!list_find(dep->modules, $2, COMP_FUN(&strcasecmp))) dep->modules = list_prepend(dep->modules, $2); } } } else if (strcasecmp($1, "module") == 0) { if (!pp_ignore && !in_interface) { if (!list_find(options.ignore_mods, $2,COMP_FUN(&strcasecmp))) { Module *mod; mod = module_new(); mod->sourcefile = xstrdup(sourcefile); mod->modulename = $2; mod->modfile_name = modfile_name($2, mod->sourcefile); if (list_find(modules, mod, &modcmp)) warning("Several modules named '%s'", $2); else modules = list_prepend(modules, mod); if (!list_find(dep->targets, mod->modfile_name, COMP_FUN(&strcasecmp))) dep->targets=list_prepend(dep->targets, mod->modfile_name); } } } else if (strcasecmp($1, "interface") == 0) { in_interface = true; free($2); } else if (strcasecmp($2, "interface") == 0 && strcasecmp($1, "end") == 0) { in_interface = false; free($2); } free($1); } | WORD STRING other EOSTMT { if (strcasecmp($1, "include") == 0) { handle_include($2); } free($1); free($2); } | include STRING other EOSTMT { handle_include($2); free($2); } | CPP_INCLUDE GARBAGE other EOSTMT /* Ignore #include */ | define WORD other EOSTMT{ if (!pp_ignore) { DEBUG_PRINT("%s defined\n", $2); defmac = macro_new(); macro_setname(defmac, $2); if (!list_find(macrolist, defmac, ¯ocmp)) macrolist = list_prepend(macrolist, defmac); } } | undef WORD other EOSTMT { if (!pp_ignore) { Macro *mac; List *l; mac = macro_new(); macro_setname(mac, $2); l = list_find(macrolist, mac, ¯ocmp); if (l) { macrolist = list_remove(macrolist, l); macro_free(l->data); list_free(l); } macro_free(mac); } } | ifdef WORD other EOSTMT { Macro *mac; mac = macro_new(); macro_setname(mac, $2); skip_i++; if (pp_ignore) pp_ignore++; else if (!list_find(macrolist, mac, ¯ocmp)) pp_ignore = 1; else skip_to_end[skip_i] = true; macro_free(mac); } | ifndef WORD other EOSTMT { Macro *mac; mac = macro_new(); macro_setname(mac, $2); skip_i++; if (pp_ignore) pp_ignore++; if (list_find(macrolist, mac, ¯ocmp)) pp_ignore = 1; else skip_to_end[skip_i] = true; macro_free(mac); } | if other EOSTMT { /* #if:s can't be completely ignored, since #else:s, #elif:s and * #endif:s aren't. An #if branch is allways taken, and so are any * following #else or #elif:s (ie. no 'skip_to_end'). */ skip_i++; if (pp_ignore) pp_ignore++; skip_to_end[skip_i] = false; } | elif other EOSTMT { /* Allways taken unless an #ifdef or #ifndef-branch has been taken * allready. */ if (skip_to_end[skip_i] && pp_ignore == 0) pp_ignore = 1; } | else other EOSTMT { if (pp_ignore == 1 && skip_to_end[skip_i] == false) pp_ignore = 0; else if (pp_ignore == 0) pp_ignore = 1; } | endif other EOSTMT { skip_to_end[skip_i] = false; if (skip_i > 0) skip_i--; if (pp_ignore) pp_ignore--; } | WORD GARBAGE other EOSTMT /* Ignore */ | GARBAGE other EOSTMT | EOSTMT | error { yyerrok; } ; include: CPP_INCLUDE | F90PPR_INCLUDE | COCO_INCLUDE ; define: CPP_DEFINE | F90PPR_DEFINE ; undef: CPP_UNDEF | F90PPR_UNDEF ; ifdef: CPP_IFDEF | F90PPR_IFDEF ; ifndef: CPP_IFNDEF | F90PPR_IFNDEF ; if: CPP_IF | F90PPR_IF ; elif: CPP_ELIF | F90PPR_ELIF ; else: CPP_ELSE | F90PPR_ELSE ; endif: CPP_ENDIF | F90PPR_ENDIF ; other: /* empty */ | other misc_code ; misc_code: WORD { free ($1); } | STRING { free ($1); } | GARBAGE | ASSIGNMENT_OP | UNTERMINATED_STRING { if (options.warn_confused) warning ("Unterminated string in file '%s' on line %i", curr_file, $1); } ; %% int yyerror(const char *s) { extern int yylineno; if (options.warn_confused) warning("Line %i in file '%s' confuses me\n", yylineno, curr_file); return 0; } /* Return false for failure reading file, else return true. */ bool find_dep(char *file, Dependency *d, List **mods, const List *predef_macro) { extern FILE *yyin; extern int yylineno; Macro *mac; const List *h; /* Initialize */ sourcefile = file; curr_file = file; dep = d; modules = *mods; yylineno = 1; filestack_i = 0; pp_ignore = 0; yyin = open_src_file(file, options.src_path); if (yyin == NULL) { warning("Skipping file '%s': %s", file, strerror(errno)); return false; } /* Check source format */ if (options.src_fmt == SUFFIX) lex_set_format(get_format(file)); else lex_set_format(options.src_fmt); /* Initialize a list of macros, and fill it with macrodefinitions from -D * flags at the command line */ macrolist = NULL; for (h = predef_macro; h; h = h->next) { mac = macro_new(); macro_copy(mac, (Macro *)h->data); if (!list_find(macrolist, mac, ¯ocmp)) macrolist = list_prepend(macrolist, mac); } yyparse(); *mods = modules; /* Delete macrolist */ for (h = macrolist; h; h = h->next) macro_free((Macro *)h->data); list_free(macrolist); fclose(yyin); return true; } int modstrcmp(const void *s, const void *m) { return strcasecmp(((Module *)m)->modulename, (char *)s); } static int modcmp (const void *m1, const void *m2) { return strcasecmp(((Module *)m1)->modulename, ((Module *)m2)->modulename); } static char *fixed_suffixes[] = {".f", ".F", ".for", ".FOR", ".ftn", ".FTN"}; static char *free_suffixes[] = {".f90", ".F90", ".f95", ".F95"}; static const int fixsuffn = sizeof(fixed_suffixes)/sizeof(void *); static const int freesuffn = sizeof(free_suffixes)/sizeof(void *); SourceFmt get_format(const char *filename) { const char *p; int i; /* Search for the end */ for (p = filename; *p; p++); /* Search backwards for the last '.' */ for (; *p != '.' && p != filename; p--); /* Check for any of the free suffixes */ for (i = 0; i < freesuffn; i++) if (strcmp(p, free_suffixes[i]) == 0) return FREE; /* Check for any of the fixed suffixes */ for (i = 0; i < fixsuffn; i++) if (strcmp(p, fixed_suffixes[i]) == 0) return FIXED; return UNKNOWN; } void pop_filestack() { curr_file = filestack[--filestack_i]; } void handle_include(const char *incfile) { if (!pp_ignore) { filestack[filestack_i++] = curr_file; curr_file = remove_citation(incfile); if (lex_include_file(curr_file)) { DEBUG_PRINT("including file '%s'\n", curr_file); if (!list_find(dep->includes, curr_file, COMP_FUN(&strcasecmp))) dep->includes = list_prepend(dep->includes, curr_file); } else { pop_filestack(); } } } Module *module_new() { Module *m; m = (Module *) xmalloc(sizeof(Module)); m->modulename = m->modfile_name = m->sourcefile = NULL; return m; } Dependency *dependency_new() { Dependency *d; d = (Dependency *) xmalloc(sizeof(Dependency)); d->sourcefile = NULL; d->targets = d->modules = d->includes = NULL; return d; }