📄 cpplib.c
字号:
/* CPP Library. Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. Written by Per Bothner, 1994-95. Based on CCCP program by 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. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */#ifdef EMACS#define NO_SHORTNAMES#include "../src/config.h"#ifdef open#undef open#undef read#undef write#endif /* open */#endif /* EMACS *//* The macro EMACS is defined when cpp is distributed as part of Emacs, for the sake of machines with limited C compilers. */#ifndef EMACS#include "config.h"#endif /* not EMACS */#ifndef STANDARD_INCLUDE_DIR#define STANDARD_INCLUDE_DIR "/usr/include"#endif#ifndef LOCAL_INCLUDE_DIR#define LOCAL_INCLUDE_DIR "/usr/local/include"#endif#if 0 /* We can't get ptrdiff_t, so I arranged not to need PTR_INT_TYPE. */#ifdef __STDC__#define PTR_INT_TYPE ptrdiff_t#else#define PTR_INT_TYPE long#endif#endif /* 0 */#include "cpplib.h"#include "cpphash.h"#ifndef STDC_VALUE#define STDC_VALUE 1#endif/* By default, colon separates directories in a path. */#ifndef PATH_SEPARATOR#define PATH_SEPARATOR ':'#endif#include <ctype.h>#include <stdio.h>#include <signal.h>#ifdef __STDC__#include <stdlib.h>#endif#ifndef VMS#ifndef USG#include <sys/time.h> /* for __DATE__ and __TIME__ */#include <sys/resource.h>#else#include <sys/param.h> /* CYGNUS LOCAL: shebs -noquiet */#include <sys/times.h>#include <time.h>#include <fcntl.h>#endif /* USG */#endif /* not VMS *//* This defines "errno" properly for VMS, and gives us EACCES. */#include <errno.h>extern char *index ();extern char *rindex ();#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. */#ifndef HOST_BITS_PER_WIDE_INT#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG#define HOST_WIDE_INT long#else#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT#define HOST_WIDE_INT int#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/* Define a generic NULL if one hasn't already been defined. */#ifndef NULL#define NULL 0#endif#ifndef GENERIC_PTR#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)#define GENERIC_PTR void *#else#define GENERIC_PTR char *#endif#endif#ifndef NULL_PTR#define NULL_PTR ((GENERIC_PTR)0)#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. */extern char *xmalloc ();static void add_import ();static void append_include_chain ();static void make_undef ();static void make_assertion ();static void path_include ();static void initialize_builtins ();static void initialize_char_syntax ();static void dump_arg_n ();static void dump_defn_1 ();extern void delete_macro ();static void trigraph_pcp ();static int finclude ();static void validate_else ();static int comp_def_part ();extern void fancy_abort ();static void pipe_closed ();static void print_containing_files ();static 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_preconditions ();static void pcfinclude ();static void pcstring_used ();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 int file_size_and_mode ();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 ();extern 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 char *getenv ();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. */ 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, 1, 1 },#ifdef CROSS_COMPILE /* This is the dir for fixincludes. Put it just before the files that we fix. */ { GCC_INCLUDE_DIR, 0, 0 }, /* For cross-compilation, this dir name is generated automatically in Makefile.in. */ { CROSS_INCLUDE_DIR, 0, 0 }, /* This is another place that the target system's headers might be. */ { TOOL_INCLUDE_DIR, 0, 1 },#else /* not CROSS_COMPILE */ /* This should be /usr/local/include and should come before the fixincludes-fixed header files. */ { LOCAL_INCLUDE_DIR, 0, 1 }, /* 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, 0, 1 }, /* This is the dir for fixincludes. Put it just before the files that we fix. */ { GCC_INCLUDE_DIR, 0, 0 }, /* Some systems have an extra dir of include files. */#ifdef SYSTEM_INCLUDE_DIR { SYSTEM_INCLUDE_DIR, 0, 0 },#endif { STANDARD_INCLUDE_DIR, 0, 0 },#endif /* not CROSS_COMPILE */ { 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. */ char traditional_comments; /* Nonzero: keep comments if -traditional. */ char pass_thru; /* Copy preprocessed directive to output file.*/};/* 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, 0, 1}, { 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, 0, 0, 1}, { 4, do_line, "line", T_LINE, 1}, { 5, do_ident, "ident", T_IDENT, 1, 0, 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; char *src;{ U_CHAR c; CPP_PUTC_Q (pfile, '\"'); for (;;) switch ((c = *src++)) { default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -