cpplib.c

来自「GCC编译器源代码」· C语言 代码 · 共 2,518 行 · 第 1/5 页

C
2,518
字号
/* CPP Library.   Copyright (C) 1986, 87, 89, 92-6, 1997 Free Software Foundation, Inc.   Contributed by Per Bothner, 1994-95.   Based on CCCP program by Paul Rubin, June 1986   Adapted to ANSI C, Richard Stallman, Jan 1987This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#include "config.h"#ifndef STDC_VALUE#define STDC_VALUE 1#endif#include <ctype.h>#include <stdio.h>#include <signal.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else#  include <time.h>#endif#endif#ifdef HAVE_SYS_TIMES_H#include <sys/times.h>#endif#ifdef HAVE_SYS_RESOURCE_H# include <sys/resource.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#if HAVE_LIMITS_H# include <limits.h>#endif#ifdef HAVE_STDLIB_H# include <stdlib.h>#endif#ifdef HAVE_STRING_H# include <string.h># else# ifdef HAVE_STRINGS_H#  include <strings.h>#endif#endif/* This defines "errno" properly for VMS, and gives us EACCES.  */#include <errno.h>#include "cpplib.h"#include "cpphash.h"#include "gansidecl.h"#ifdef NEED_DECLARATION_INDEXextern char *index ();#endif#ifdef NEED_DECLARATION_RINDEXextern char *rindex ();#endif#ifdef NEED_DECLARATION_GETENVextern char *getenv ();#endifextern char *update_path ();#ifndef O_RDONLY#define O_RDONLY 0#endif#undef MIN#undef MAX#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))/* Find the largest host integer type and set its size and type.   Watch out: on some crazy hosts `long' is shorter than `int'.  */#ifndef HOST_WIDE_INT# if HAVE_INTTYPES_H#  include <inttypes.h>#  define HOST_WIDE_INT intmax_t# else#  if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT \       && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)#   define HOST_WIDE_INT int#  else#  if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG \       || ! (defined LONG_LONG_MAX || defined LLONG_MAX))#   define HOST_WIDE_INT long#  else#   define HOST_WIDE_INT long long#  endif#  endif# endif#endif#ifndef S_ISREG#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)#endif#ifndef S_ISDIR#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)#endif/* By default, colon separates directories in a path.  */#ifndef PATH_SEPARATOR#define PATH_SEPARATOR ':'#endif#ifndef STANDARD_INCLUDE_DIR#define STANDARD_INCLUDE_DIR "/usr/include"#endif#ifndef INCLUDE_LEN_FUDGE#define INCLUDE_LEN_FUDGE 0#endif/* Symbols to predefine.  */#ifdef CPP_PREDEFINESstatic char *predefs = CPP_PREDEFINES;#elsestatic char *predefs = "";#endif/* We let tm.h override the types used here, to handle trivial differences   such as the choice of unsigned int or long unsigned int for size_t.   When machines start needing nontrivial differences in the size type,   it would be best to do something here to figure out automatically   from other information what type to use.  *//* The string value for __SIZE_TYPE__.  */#ifndef SIZE_TYPE#define SIZE_TYPE "long unsigned int"#endif/* The string value for __PTRDIFF_TYPE__.  */#ifndef PTRDIFF_TYPE#define PTRDIFF_TYPE "long int"#endif/* The string value for __WCHAR_TYPE__.  */#ifndef WCHAR_TYPE#define WCHAR_TYPE "int"#endif#define CPP_WCHAR_TYPE(PFILE) \	(CPP_OPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE)/* The string value for __USER_LABEL_PREFIX__ */#ifndef USER_LABEL_PREFIX#define USER_LABEL_PREFIX ""#endif/* The string value for __REGISTER_PREFIX__ */#ifndef REGISTER_PREFIX#define REGISTER_PREFIX ""#endif/* In the definition of a #assert name, this structure forms   a list of the individual values asserted.   Each value is itself a list of "tokens".   These are strings that are compared by name.  */struct tokenlist_list {  struct tokenlist_list *next;  struct arglist *tokens;};struct assertion_hashnode {  struct assertion_hashnode *next;	/* double links for easy deletion */  struct assertion_hashnode *prev;  /* also, a back pointer to this node's hash     chain is kept, in case the node is the head     of the chain and gets deleted.  */  struct assertion_hashnode **bucket_hdr;  int length;			/* length of token, for quick comparison */  U_CHAR *name;			/* the actual name */  /* List of token-sequences.  */  struct tokenlist_list *value;};#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)#define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF)#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))#define GETC() CPP_BUF_GET (CPP_BUFFER (pfile))#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.   (Note that it is false while we're expanding marco *arguments*.) */#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->cleanup == macro_cleanup)/* Move all backslash-newline pairs out of embarrassing places.   Exchange all such pairs following BP   with any potentially-embarrassing characters that follow them.   Potentially-embarrassing characters are / and *   (because a backslash-newline inside a comment delimiter   would cause it not to be recognized).  */#define NEWLINE_FIX \  do {while (PEEKC() == '\\' && PEEKN(1) == '\n') FORWARD(2); } while(0)/* Same, but assume we've already read the potential '\\' into C.  */#define NEWLINE_FIX1(C) do { \    while ((C) == '\\' && PEEKC() == '\n') { FORWARD(1); (C) = GETC(); }\  } while(0)struct cpp_pending {  struct cpp_pending *next;  char *cmd;  char *arg;};/* Forward declarations.  */char *xmalloc ();void cpp_fatal ();void cpp_file_line_for_message PARAMS ((cpp_reader *, char *, int, int));void cpp_hash_cleanup PARAMS ((cpp_reader *));void cpp_message ();void cpp_print_containing_files PARAMS ((cpp_reader *));static void add_import ();static void append_include_chain ();static void make_assertion ();static void path_include ();static void initialize_builtins ();static void initialize_char_syntax ();extern void delete_macro ();#if 0static void trigraph_pcp ();#endifstatic int finclude ();static void validate_else ();static int comp_def_part ();#ifdef abortextern void fancy_abort ();#endifstatic int lookup_import ();static int redundant_include_p ();static is_system_include ();static struct file_name_map *read_name_map ();static char *read_filename_string ();static int open_include_file ();static int check_macro_name ();static int compare_defs ();static int compare_token_lists ();static HOST_WIDE_INT eval_if_expression ();static int change_newlines ();extern int hashf ();static struct arglist *read_token_list ();static void free_token_list ();static int safe_read ();static void push_macro_expansion PARAMS ((cpp_reader *,					  U_CHAR *, int, HASHNODE *));static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending *));extern char *xrealloc ();static char *xcalloc ();static char *savestring ();static void conditional_skip ();static void skip_if_group ();/* Last arg to output_line_command.  */enum file_change_code {same_file, enter_file, leave_file};/* External declarations.  */extern HOST_WIDE_INT cpp_parse_expr PARAMS ((cpp_reader *));extern FILE *fdopen ();extern char *version_string;extern struct tm *localtime ();/* These functions are declared to return int instead of void since they   are going to be placed in a table and some old compilers have trouble with   pointers to functions returning void.  */static int do_define ();static int do_line ();static int do_include ();static int do_undef ();static int do_error ();static int do_pragma ();static int do_ident ();static int do_if ();static int do_xifdef ();static int do_else ();static int do_elif ();static int do_endif ();static int do_sccs ();static int do_once ();static int do_assert ();static int do_unassert ();static int do_warning ();struct file_name_list  {    struct file_name_list *next;    char *fname;    /* If the following is nonzero, it is a macro name.       Don't include the file again if that macro is defined.  */    U_CHAR *control_macro;    /* If the following is nonzero, it is a C-language system include       directory.  */    int c_system_include_path;    /* Mapping of file names for this directory.  */    struct file_name_map *name_map;    /* Non-zero if name_map is valid.  */    int got_name_map;  };/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found   via the same directory as the file that #included it.  */#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))/* #include "file" looks in source file dir, then stack.  *//* #include <file> just looks in the stack.  *//* -I directories are added to the end, then the defaults are added.  *//* The */static struct default_include {  char *fname;			/* The name of the directory.  */  char *component;		/* The component containing the directory */  int cplusplus;		/* Only look here if we're compiling C++.  */  int cxx_aware;		/* Includes in this directory don't need to				   be wrapped in extern "C" when compiling				   C++.  */} include_defaults_array[]#ifdef INCLUDE_DEFAULTS  = INCLUDE_DEFAULTS;#else  = {    /* Pick up GNU C++ specific include files.  */    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },    { OLD_GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 },#ifdef CROSS_COMPILE    /* This is the dir for fixincludes.  Put it just before       the files that we fix.  */    { GCC_INCLUDE_DIR, "GCC", 0, 0 },    /* For cross-compilation, this dir name is generated       automatically in Makefile.in.  */    { CROSS_INCLUDE_DIR, "GCC",0, 0 },#ifdef TOOL_INCLUDE_DIR    /* This is another place that the target system's headers might be.  */    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 },#endif#else /* not CROSS_COMPILE */#ifdef LOCAL_INCLUDE_DIR    /* This should be /usr/local/include and should come before       the fixincludes-fixed header files.  */    { LOCAL_INCLUDE_DIR, 0, 0, 1 },#endif#ifdef TOOL_INCLUDE_DIR    /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.       Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h.  */    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 },#endif    /* This is the dir for fixincludes.  Put it just before       the files that we fix.  */    { GCC_INCLUDE_DIR, "GCC", 0, 0 },    /* Some systems have an extra dir of include files.  */#ifdef SYSTEM_INCLUDE_DIR    { SYSTEM_INCLUDE_DIR, 0, 0, 0 },#endif#ifndef STANDARD_INCLUDE_COMPONENT#define STANDARD_INCLUDE_COMPONENT 0#endif    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },#endif /* not CROSS_COMPILE */    { 0, 0, 0, 0 }    };#endif /* no INCLUDE_DEFAULTS *//* `struct directive' defines one #-directive, including how to handle it.  */struct directive {  int length;			/* Length of name */  int (*func)();		/* Function to handle directive */  char *name;			/* Name of directive */  enum node_type type;		/* Code which describes which directive.  */  char command_reads_line;      /* One if rest of line is read by func.  */};#define IS_INCLUDE_DIRECTIVE_TYPE(t) (T_INCLUDE <= (t) && (t) <= T_IMPORT)/* Here is the actual list of #-directives, most-often-used first.   The initialize_builtins function assumes #define is the very first.  */static struct directive directive_table[] = {  {  6, do_define, "define", T_DEFINE},  {  5, do_xifdef, "ifdef", T_IFDEF, 1},  {  6, do_xifdef, "ifndef", T_IFNDEF, 1},  {  7, do_include, "include", T_INCLUDE, 1},  { 12, do_include, "include_next", T_INCLUDE_NEXT, 1},  {  6, do_include, "import", T_IMPORT, 1},  {  5, do_endif, "endif", T_ENDIF, 1},  {  4, do_else, "else", T_ELSE, 1},  {  2, do_if, "if", T_IF, 1},  {  4, do_elif, "elif", T_ELIF, 1},  {  5, do_undef, "undef", T_UNDEF},  {  5, do_error, "error", T_ERROR},  {  7, do_warning, "warning", T_WARNING},  {  6, do_pragma, "pragma", T_PRAGMA},  {  4, do_line, "line", T_LINE, 1},  {  5, do_ident, "ident", T_IDENT, 1},#ifdef SCCS_DIRECTIVE  {  4, do_sccs, "sccs", T_SCCS},#endif  {  6, do_assert, "assert", T_ASSERT, 1},  {  8, do_unassert, "unassert", T_UNASSERT, 1},  {  -1, 0, "", T_UNUSED},};/* table to tell if char can be part of a C identifier.  */U_CHAR is_idchar[256];/* table to tell if char can be first char of a c identifier.  */U_CHAR is_idstart[256];/* table to tell if c is horizontal space.  */U_CHAR is_hor_space[256];/* table to tell if c is horizontal or vertical space.  */static U_CHAR is_space[256];/* Initialize syntactic classifications of characters.  */static voidinitialize_char_syntax (opts)     struct cpp_options *opts;{  register int i;  /*   * Set up is_idchar and is_idstart tables.  These should be   * faster than saying (is_alpha (c) || c == '_'), etc.   * Set up these things before calling any routines tthat   * refer to them.   */  for (i = 'a'; i <= 'z'; i++) {    is_idchar[i - 'a' + 'A'] = 1;    is_idchar[i] = 1;    is_idstart[i - 'a' + 'A'] = 1;    is_idstart[i] = 1;  }  for (i = '0'; i <= '9'; i++)    is_idchar[i] = 1;  is_idchar['_'] = 1;  is_idstart['_'] = 1;  is_idchar['$'] = opts->dollars_in_ident;  is_idstart['$'] = opts->dollars_in_ident;  /* horizontal space table */  is_hor_space[' '] = 1;  is_hor_space['\t'] = 1;  is_hor_space['\v'] = 1;  is_hor_space['\f'] = 1;  is_hor_space['\r'] = 1;  is_space[' '] = 1;  is_space['\t'] = 1;  is_space['\v'] = 1;  is_space['\f'] = 1;  is_space['\n'] = 1;  is_space['\r'] = 1;}/* Place into PFILE a quoted string representing the string SRC.   Caller must reserve enough space in pfile->token_buffer.  */static voidquote_string (pfile, src)     cpp_reader *pfile;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?