📄 cccp.c
字号:
static int done_initializing = 0;/* I/O buffer structure. The `fname' field is nonzero for source files and #include files and for the dummy text used for -D and -U. It is zero for rescanning results of macro expansion and for expanding macro arguments. */#define INPUT_STACK_MAX 200static struct file_buf { char *fname; /* Filename specified with #line command. */ char *nominal_fname; /* Record where in the search path this file was found. For #include_next. */ struct file_name_list *dir; int lineno; int length; U_CHAR *buf; U_CHAR *bufp; /* Macro that this level is the expansion of. Included so that we can reenable the macro at the end of this level. */ struct hashnode *macro; /* Value of if_stack at start of this file. Used to prohibit unmatched #endif (etc) in an include file. */ struct if_stack *if_stack; /* Object to be freed at end of input at this level. */ U_CHAR *free_ptr; /* True if this is a header file included using <FILENAME>. */ char system_header_p;} instack[INPUT_STACK_MAX];static int last_error_tick; /* Incremented each time we print it. */static int input_file_stack_tick; /* Incremented when the status changes. *//* Current nesting level of input sources. `instack[indepth]' is the level currently being read. */static int indepth = -1;#define CHECK_DEPTH(code) \ if (indepth >= (INPUT_STACK_MAX - 1)) \ { \ error_with_line (line_for_error (instack[indepth].lineno), \ "macro or `#include' recursion too deep"); \ code; \ }/* Current depth in #include directives that use <...>. */static int system_include_depth = 0;typedef struct file_buf FILE_BUF;/* The output buffer. Its LENGTH field is the amount of room allocated for the buffer, not the number of chars actually present. To get that, subtract outbuf.buf from outbuf.bufp. */#define OUTBUF_SIZE 10 /* initial size of output buffer */static FILE_BUF outbuf;/* Grow output buffer OBUF points at so it can hold at least NEEDED more chars. */#define check_expand(OBUF, NEEDED) \ (((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED)) \ ? grow_outbuf ((OBUF), (NEEDED)) : 0)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; };/* #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. */static struct default_include { char *fname; int cplusplus; } include_defaults_array[]#ifdef INCLUDE_DEFAULTS = INCLUDE_DEFAULTS;#else = { /* Pick up GNU C++ specific include files. */ { GPLUSPLUS_INCLUDE_DIR, 1}, { GCC_INCLUDE_DIR, 0},#ifdef CROSS_COMPILE /* For cross-compilation, this dir name is generated automatically in Makefile.in. */ { CROSS_INCLUDE_DIR, 0 },#else /* not CROSS_COMPILE */ { LOCAL_INCLUDE_DIR, 0}, /* Some systems have an extra dir of include files. */#ifdef SYSTEM_INCLUDE_DIR { SYSTEM_INCLUDE_DIR, 0},#endif { STANDARD_INCLUDE_DIR, 0},#endif /* not CROSS_COMPILE */ { 0, 0} };#endif /* no INCLUDE_DEFAULTS *//* The code looks at the defaults through this pointer, rather than through the constant structure above. This pointer gets changed if an environment variable specifies other defaults. */static struct default_include *include_defaults = include_defaults_array;static struct file_name_list *include = 0; /* First dir to search */ /* First dir to search for <file> *//* This is the first element to use for #include <...>. If it is 0, use the entire chain for such includes. */static struct file_name_list *first_bracket_include = 0;/* This is the first element in the chain that corresponds to a directory of system header files. */static struct file_name_list *first_system_include = 0;static struct file_name_list *last_include = 0; /* Last in chain *//* Chain of include directories to put at the end of the other chain. */static struct file_name_list *after_include = 0;static struct file_name_list *last_after_include = 0; /* Last in chain *//* List of included files that contained #pragma once. */static struct file_name_list *dont_repeat_files = 0;/* List of other included files. If ->control_macro if nonzero, the file had a #ifndef around the entire contents, and ->control_macro gives the macro name. */static struct file_name_list *all_include_files = 0;/* Directory prefix that should replace `/usr' in the standard include file directories. */static char *include_prefix;/* Global list of strings read in from precompiled files. This list is kept in the order the strings are read in, with new strings being added at the end through stringlist_tailp. We use this list to output the strings at the end of the run. */static STRINGDEF *stringlist;static STRINGDEF **stringlist_tailp = &stringlist;/* Structure returned by create_definition */typedef struct macrodef MACRODEF;struct macrodef{ struct definition *defn; U_CHAR *symnam; int symlen;};static struct macrodef create_definition ();/* Structure allocated for every #define. For a simple replacement such as #define foo bar , nargs = -1, the `pattern' list is null, and the expansion is just the replacement text. Nargs = 0 means a functionlike macro with no args, e.g., #define getchar() getc (stdin) . When there are args, the expansion is the replacement text with the args squashed out, and the reflist is a list describing how to build the output from the input: e.g., "3 chars, then the 1st arg, then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". The chars here come from the expansion. Whatever is left of the expansion after the last arg-occurrence is copied after that arg. Note that the reflist can be arbitrarily long--- its length depends on the number of times the arguments appear in the replacement text, not how many args there are. Example: #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and pattern list { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } where (x, y) means (nchars, argno). */typedef struct definition DEFINITION;struct definition { int nargs; int length; /* length of expansion string */ int predefined; /* True if the macro was builtin or */ /* came from the command line */ U_CHAR *expansion; int line; /* Line number of definition */ char *file; /* File of definition */ char rest_args; /* Nonzero if last arg. absorbs the rest */ struct reflist { struct reflist *next; char stringify; /* nonzero if this arg was preceded by a # operator. */ char raw_before; /* Nonzero if a ## operator before arg. */ char raw_after; /* Nonzero if a ## operator after arg. */ char rest_args; /* Nonzero if this arg. absorbs the rest */ int nchars; /* Number of literal chars to copy before this arg occurrence. */ int argno; /* Number of arg to substitute (origin-0) */ } *pattern; union { /* Names of macro args, concatenated in reverse order with comma-space between them. The only use of this is that we warn on redefinition if this differs between the old and new definitions. */ U_CHAR *argnames; } args;};/* different kinds of things that can appear in the value field of a hash node. Actually, this may be useless now. */union hashval { int ival; char *cpval; DEFINITION *defn; KEYDEF *keydef;};/* * special extension string that can be added to the last macro argument to * allow it to absorb the "rest" of the arguments when expanded. Ex: * #define wow(a, b...) process(b, a, b) * { wow(1, 2, 3); } -> { process( 2, 3, 1, 2, 3); } * { wow(one, two); } -> { process( two, one, two); } * if this "rest_arg" is used with the concat token '##' and if it is not * supplied then the token attached to with ## will not be outputted. Ex: * #define wow(a, b...) process(b ## , a, ## b) * { wow(1, 2); } -> { process( 2, 1,2); } * { wow(one); } -> { process( one); { */static char rest_extension[] = "...";#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)/* The structure of a node in the hash table. The hash table has entries for all tokens defined by #define commands (type T_MACRO), plus some special tokens like __LINE__ (these each have their own type, and the appropriate code is run when that type of node is seen. It does not contain control words like "#define", which are recognized by a separate piece of code. *//* different flavors of hash nodes --- also used in keyword table */enum node_type { T_DEFINE = 1, /* the `#define' keyword */ T_INCLUDE, /* the `#include' keyword */ T_INCLUDE_NEXT, /* the `#include_next' keyword */ T_IMPORT, /* the `#import' keyword */ T_IFDEF, /* the `#ifdef' keyword */ T_IFNDEF, /* the `#ifndef' keyword */ T_IF, /* the `#if' keyword */ T_ELSE, /* `#else' */ T_PRAGMA, /* `#pragma' */ T_ELIF, /* `#elif' */ T_UNDEF, /* `#undef' */ T_LINE, /* `#line' */ T_ERROR, /* `#error' */ T_WARNING, /* `#warning' */ T_ENDIF, /* `#endif' */ T_SCCS, /* `#sccs', used on system V. */ T_IDENT, /* `#ident', used on system V. */ T_ASSERT, /* `#assert', taken from system V. */ T_UNASSERT, /* `#unassert', taken from system V. */ T_SPECLINE, /* special symbol `__LINE__' */ T_DATE, /* `__DATE__' */ T_FILE, /* `__FILE__' */ T_BASE_FILE, /* `__BASE_FILE__' */ T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ T_VERSION, /* `__VERSION__' */ T_SIZE_TYPE, /* `__SIZE_TYPE__' */ T_PTRDIFF_TYPE, /* `__PTRDIFF_TYPE__' */ T_WCHAR_TYPE, /* `__WCHAR_TYPE__' */ T_TIME, /* `__TIME__' */ T_CONST, /* Constant value, used by `__STDC__' */ T_MACRO, /* macro defined by `#define' */ T_DISABLED, /* macro temporarily turned off for rescan */ T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */ T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */ T_UNUSED /* Used for something not defined. */ };struct hashnode { struct hashnode *next; /* double links for easy deletion */ struct hashnode *prev; struct hashnode **bucket_hdr; /* 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. */ enum node_type type; /* type of special token */ int length; /* length of token, for quick comparison */ U_CHAR *name; /* the actual name */ union hashval value; /* pointer to expansion, or whatever */};typedef struct hashnode HASHNODE;/* Some definitions for the hash table. The hash function MUST be computed as shown in hashf () below. That is because the rescan loop computes the hash value `on the fly' for most tokens, in order to avoid the overhead of a lot of procedure calls to the hashf () function. Hashf () only exists for the sake of politeness, for use when speed isn't so important. */#define HASHSIZE 1403static HASHNODE *hashtab[HASHSIZE];#define HASHSTEP(old, c) ((old << 2) + c)#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive *//* 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/* 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;};typedef struct assertion_hashnode ASSERTION_HASHNODE;/* Some definitions for the hash table. The hash function MUST be computed as shown in hashf below. That is because the rescan loop computes the hash value `on the fly' for most tokens, in order to avoid the overhead of a lot of procedure calls to the hashf function. hashf only exists for the sake of politeness, for use when speed isn't so important. */#define ASSERTION_HASHSIZE 37static ASSERTION_HASHNODE *assertion_hashtab[ASSERTION_HASHSIZE];/* Nonzero means inhibit macroexpansion of what seem to be assertion tests, in rescan. For #if. */static int assertions_flag;/* `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 angle_brackets; /* Nonzero => <...> is special. */ 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. */static struct directive directive_table[] = { { 6, do_define, "define", T_DEFINE, 0, 1}, { 2, do_if, "if", T_IF}, { 5, do_xifdef, "ifdef", T_IFDEF}, { 6, do_xifdef, "ifndef", T_IFNDEF}, { 5, do_endif, "endif", T_ENDIF}, { 4, do_else, "else", T_ELSE}, { 4, do_elif, "elif", T_ELIF}, { 4, do_line, "line", T_LINE}, { 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_undef, "undef", T_UNDEF}, { 5, do_error, "error", T_ERROR}, { 7, do_warning, "warning", T_WARNING},#ifdef SCCS_DIRECTIVE { 4, do_sccs, "sccs", T_SCCS},#endif { 6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1}, { 5, do_ident, "ident", T_IDENT, 0, 0, 1}, { 6, do_assert, "assert", T_ASSERT}, { 8, do_unassert, "unassert", T_UNASSERT}, { -1, 0, "", T_UNUSED},};/* When a directive handler is called, this points to the # that started the directive. */U_CHAR *directive_start;/* 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];#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) static int errors = 0; /* Error counter for exit code *//* Zero means dollar signs are punctuation. -$ stores 0; -traditional may store 1. Default is 1 for VMS, 0 otherwise. This must be 0 for correct processing of this ANSI C program: #define foo(a) #a #define lose(b) foo(b) #define test$ lose(test) */static int dollars_in_ident;#ifndef DOLLARS_IN_IDENTIFIERS#define DOLLARS_IN_IDENTIFIERS 1#endifstatic FILE_BUF expand_to_temp_buffer ();static DEFINITION *collect_expansion ();/* Stack of conditionals currently in progress (including both successful and failing conditionals). */struct if_stack { struct if_stack *next; /* for chaining to the next stack frame */ char *fname; /* copied from input when frame is made */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -