| /* 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 1987 |
| |
| This program 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 2, or (at your option) any |
| later version. |
| |
| 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, 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 |
| |
| #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/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_PREDEFINES |
| static char *predefs = CPP_PREDEFINES; |
| #else |
| static 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 (); |
| #ifdef abort |
| extern void fancy_abort (); |
| #endif |
| 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 (); |
| 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 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 }, |
| { OLD_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 }, |
| #ifdef TOOL_INCLUDE_DIR |
| /* This is another place that the target system's headers might be. */ |
| { TOOL_INCLUDE_DIR, 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, 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, 0, 1 }, |
| #endif |
| /* 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 void |
| initialize_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 void |
| quote_string (pfile, src) |
| cpp_reader *pfile; |
| char *src; |
| { |
| U_CHAR c; |
| |
| CPP_PUTC_Q (pfile, '\"'); |
| for (;;) |
| switch ((c = *src++)) |
| { |
| default: |
| if (isprint (c)) |
| CPP_PUTC_Q (pfile, c); |
| else |
| { |
| sprintf (CPP_PWRITTEN (pfile), "\\%03o", c); |
| CPP_ADJUST_WRITTEN (pfile, 4); |
| } |
| break; |
| |
| case '\"': |
| case '\\': |
| CPP_PUTC_Q (pfile, '\\'); |
| CPP_PUTC_Q (pfile, c); |
| break; |
| |
| case '\0': |
| CPP_PUTC_Q (pfile, '\"'); |
| CPP_NUL_TERMINATE_Q (pfile); |
| return; |
| } |
| } |
| |
| /* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */ |
| |
| void |
| cpp_grow_buffer (pfile, n) |
| cpp_reader *pfile; |
| long n; |
| { |
| long old_written = CPP_WRITTEN (pfile); |
| pfile->token_buffer_size = n + 2 * pfile->token_buffer_size; |
| pfile->token_buffer = (U_CHAR *) |
| xrealloc(pfile->token_buffer, pfile->token_buffer_size); |
| CPP_SET_WRITTEN (pfile, old_written); |
| } |
| |
| |
| /* |
| * process a given definition string, for initialization |
| * If STR is just an identifier, define it with value 1. |
| * If STR has anything after the identifier, then it should |
| * be identifier=definition. |
| */ |
| |
| void |
| cpp_define (pfile, str) |
| cpp_reader *pfile; |
| U_CHAR *str; |
| { |
| U_CHAR *buf, *p; |
| |
| buf = str; |
| p = str; |
| if (!is_idstart[*p]) |
| { |
| cpp_error (pfile, "malformed option `-D %s'", str); |
| return; |
| } |
| while (is_idchar[*++p]) |
| ; |
| if (*p == 0) |
| { |
| buf = (U_CHAR *) alloca (p - buf + 4); |
| strcpy ((char *)buf, str); |
| strcat ((char *)buf, " 1"); |
| } |
| else if (*p != '=') |
| { |
| cpp_error (pfile, "malformed option `-D %s'", str); |
| return; |
| } |
| else |
| { |
| U_CHAR *q; |
| /* Copy the entire option so we can modify it. */ |
| buf = (U_CHAR *) alloca (2 * strlen (str) + 1); |
| strncpy (buf, str, p - str); |
| /* Change the = to a space. */ |
| buf[p - str] = ' '; |
| /* Scan for any backslash-newline and remove it. */ |
| p++; |
| q = &buf[p - str]; |
| while (*p) |
| { |
| if (*p == '\\' && p[1] == '\n') |
| p += 2; |
| else |
| *q++ = *p++; |
| } |
| *q = 0; |
| } |
| |
| do_define (pfile, NULL, buf, buf + strlen (buf)); |
| } |
| |
| /* Process the string STR as if it appeared as the body of a #assert. |
| OPTION is the option name for which STR was the argument. */ |
| |
| static void |
| make_assertion (pfile, option, str) |
| cpp_reader *pfile; |
| char *option; |
| U_CHAR *str; |
| { |
| struct directive *kt; |
| U_CHAR *buf, *p, *q; |
| |
| /* Copy the entire option so we can modify it. */ |
| buf = (U_CHAR *) alloca (strlen (str) + 1); |
| strcpy ((char *) buf, str); |
| /* Scan for any backslash-newline and remove it. */ |
| p = q = buf; |
| while (*p) { |
| #if 0 |
| if (*p == '\\' && p[1] == '\n') |
| p += 2; |
| else |
| #endif |
| *q++ = *p++; |
| } |
| *q = 0; |
| |
| p = buf; |
| if (!is_idstart[*p]) { |
| cpp_error (pfile, "malformed option `%s %s'", option, str); |
| return; |
| } |
| while (is_idchar[*++p]) |
| ; |
| while (*p == ' ' || *p == '\t') p++; |
| if (! (*p == 0 || *p == '(')) { |
| cpp_error (pfile, "malformed option `%s %s'", option, str); |
| return; |
| } |
| |
| if (cpp_push_buffer (pfile, buf, strlen (buf)) != NULL) |
| { |
| do_assert (pfile, NULL, NULL, NULL); |
| cpp_pop_buffer (pfile); |
| } |
| } |
| |
| /* Append a chain of `struct file_name_list's |
| to the end of the main include chain. |
| FIRST is the beginning of the chain to append, and LAST is the end. */ |
| |
| static void |
| append_include_chain (pfile, first, last) |
| cpp_reader *pfile; |
| struct file_name_list *first, *last; |
| { |
| struct cpp_options *opts = CPP_OPTIONS (pfile); |
| struct file_name_list *dir; |
| |
| if (!first || !last) |
| return; |
| |
| if (opts->include == 0) |
| opts->include = first; |
| else |
| opts->last_include->next = first; |
| |
| if (opts->first_bracket_include == 0) |
| opts->first_bracket_include = first; |
| |
| for (dir = first; ; dir = dir->next) { |
| int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE; |
| if (len > pfile->max_include_len) |
| pfile->max_include_len = len; |
| if (dir == last) |
| break; |
| } |
| |
| last->next = NULL; |
| opts->last_include = last; |
| } |
| |
| /* Add output to `deps_buffer' for the -M switch. |
| STRING points to the text to be output. |
| SPACER is ':' for targets, ' ' for dependencies, zero for text |
| to be inserted literally. */ |
| |
| static void |
| deps_output (pfile, string, spacer) |
| cpp_reader *pfile; |
| char *string; |
| int spacer; |
| { |
| int size = strlen (string); |
| |
| if (size == 0) |
| return; |
| |
| #ifndef MAX_OUTPUT_COLUMNS |
| #define MAX_OUTPUT_COLUMNS 72 |
| #endif |
| if (spacer |
| && pfile->deps_column > 0 |
| && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS) |
| { |
| deps_output (pfile, " \\\n ", 0); |
| pfile->deps_column = 0; |
| } |
| |
| if (pfile->deps_size + size + 8 > pfile->deps_allocated_size) |
| { |
| pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2; |
| pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer, |
| pfile->deps_allocated_size); |
| } |
| if (spacer == ' ' && pfile->deps_column > 0) |
| pfile->deps_buffer[pfile->deps_size++] = ' '; |
| bcopy (string, &pfile->deps_buffer[pfile->deps_size], size); |
| pfile->deps_size += size; |
| pfile->deps_column += size; |
| if (spacer == ':') |
| pfile->deps_buffer[pfile->deps_size++] = ':'; |
| pfile->deps_buffer[pfile->deps_size] = 0; |
| } |
| |
| /* Given a colon-separated list of file names PATH, |
| add all the names to the search path for include files. */ |
| |
| static void |
| path_include (pfile, path) |
| cpp_reader *pfile; |
| char *path; |
| { |
| char *p; |
| |
| p = path; |
| |
| if (*p) |
| while (1) { |
| char *q = p; |
| char *name; |
| struct file_name_list *dirtmp; |
| |
| /* Find the end of this name. */ |
| while (*q != 0 && *q != PATH_SEPARATOR) q++; |
| if (p == q) { |
| /* An empty name in the path stands for the current directory. */ |
| name = (char *) xmalloc (2); |
| name[0] = '.'; |
| name[1] = 0; |
| } else { |
| /* Otherwise use the directory that is named. */ |
| name = (char *) xmalloc (q - p + 1); |
| bcopy (p, name, q - p); |
| name[q - p] = 0; |
| } |
| |
| dirtmp = (struct file_name_list *) |
| xmalloc (sizeof (struct file_name_list)); |
| dirtmp->next = 0; /* New one goes on the end */ |
| dirtmp->control_macro = 0; |
| dirtmp->c_system_include_path = 0; |
| dirtmp->fname = name; |
| dirtmp->got_name_map = 0; |
| append_include_chain (pfile, dirtmp, dirtmp); |
| |
| /* Advance past this name. */ |
| p = q; |
| if (*p == 0) |
| break; |
| /* Skip the colon. */ |
| p++; |
| } |
| } |
| |
| void |
| cpp_options_init (opts) |
| cpp_options *opts; |
| { |
| bzero ((char *) opts, sizeof *opts); |
| opts->in_fname = NULL; |
| opts->out_fname = NULL; |
| |
| /* Initialize is_idchar to allow $. */ |
| opts->dollars_in_ident = 1; |
| initialize_char_syntax (opts); |
| |
| opts->no_line_commands = 0; |
| opts->no_trigraphs = 1; |
| opts->put_out_comments = 0; |
| opts->print_include_names = 0; |
| opts->dump_macros = dump_none; |
| opts->no_output = 0; |
| opts->cplusplus = 0; |
| opts->cplusplus_comments = 0; |
| |
| opts->verbose = 0; |
| opts->objc = 0; |
| opts->lang_asm = 0; |
| opts->for_lint = 0; |
| opts->chill = 0; |
| opts->pedantic_errors = 0; |
| opts->inhibit_warnings = 0; |
| opts->warn_comments = 0; |
| opts->warn_import = 1; |
| opts->warnings_are_errors = 0; |
| } |
| |
| enum cpp_token |
| null_underflow (pfile) |
| cpp_reader *pfile; |
| { |
| return CPP_EOF; |
| } |
| |
| int |
| null_cleanup (pbuf, pfile) |
| cpp_buffer *pbuf; |
| cpp_reader *pfile; |
| { |
| return 0; |
| } |
| |
| int |
| macro_cleanup (pbuf, pfile) |
| cpp_buffer *pbuf; |
| cpp_reader *pfile; |
| { |
| HASHNODE *macro = (HASHNODE *) pbuf->data; |
| if (macro->type == T_DISABLED) |
| macro->type = T_MACRO; |
| if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion) |
| free (pbuf->buf); |
| return 0; |
| } |
| |
| int |
| file_cleanup (pbuf, pfile) |
| cpp_buffer *pbuf; |
| cpp_reader *pfile; |
| { |
| if (pbuf->buf) |
| { |
| free (pbuf->buf); |
| pbuf->buf = 0; |
| } |
| return 0; |
| } |
| |
| /* Assuming we have read '/'. |
| If this is the start of a comment (followed by '*' or '/'), |
| skip to the end of the comment, and return ' '. |
| Return EOF if we reached the end of file before the end of the comment. |
| If not the start of a comment, return '/'. */ |
| |
| static int |
| skip_comment (pfile, linep) |
| cpp_reader *pfile; |
| long *linep; |
| { |
| int c = 0; |
| while (PEEKC() == '\\' && PEEKN(1) == '\n') |
| { |
| if (linep) |
| (*linep)++; |
| FORWARD(2); |
| } |
| if (PEEKC() == '*') |
| { |
| FORWARD(1); |
| for (;;) |
| { |
| int prev_c = c; |
| c = GETC (); |
| if (c == EOF) |
| return EOF; |
| while (c == '\\' && PEEKC() == '\n') |
| { |
| if (linep) |
| (*linep)++; |
| FORWARD(1), c = GETC(); |
| } |
| if (prev_c == '*' && c == '/') |
| return ' '; |
| if (c == '\n' && linep) |
| (*linep)++; |
| } |
| } |
| else if (PEEKC() == '/' && CPP_OPTIONS (pfile)->cplusplus_comments) |
| { |
| FORWARD(1); |
| for (;;) |
| { |
| c = GETC (); |
| if (c == EOF) |
| return ' '; /* Allow // to be terminated by EOF. */ |
| while (c == '\\' && PEEKC() == '\n') |
| { |
| FORWARD(1); |
| c = GETC(); |
| if (linep) |
| (*linep)++; |
| } |
| if (c == '\n') |
| { |
| /* Don't consider final '\n' to be part of comment. */ |
| FORWARD(-1); |
| return ' '; |
| } |
| } |
| } |
| else |
| return '/'; |
| } |
| |
| /* Skip whitespace \-newline and comments. Does not macro-expand. */ |
| |
| void |
| cpp_skip_hspace (pfile) |
| cpp_reader *pfile; |
| { |
| while (1) |
| { |
| int c = PEEKC(); |
| if (c == EOF) |
| return; /* FIXME */ |
| if (is_hor_space[c]) |
| { |
| if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile)) |
| cpp_pedwarn (pfile, "%s in preprocessing directive", |
| c == '\f' ? "formfeed" : "vertical tab"); |
| FORWARD(1); |
| } |
| else if (c == '/') |
| { |
| FORWARD (1); |
| c = skip_comment (pfile, NULL); |
| if (c == '/') |
| FORWARD(-1); |
| if (c == EOF || c == '/') |
| return; |
| } |
| else if (c == '\\' && PEEKN(1) == '\n') { |
| FORWARD(2); |
| } |
| else if (c == '@' && CPP_BUFFER (pfile)->has_escapes |
| && is_hor_space[PEEKN(1)]) |
| FORWARD(2); |
| else return; |
| } |
| } |
| |
| /* Read the rest of the current line. |
| The line is appended to PFILE's output buffer. */ |
| |
| static void |
| copy_rest_of_line (pfile) |
| cpp_reader *pfile; |
| { |
| struct cpp_options *opts = CPP_OPTIONS (pfile); |
| for (;;) |
| { |
| int c = GETC(); |
| int nextc; |
| switch (c) |
| { |
| case EOF: |
| goto end_directive; |
| case '\\': |
| if (PEEKC() == '\n') |
| { |
| FORWARD (1); |
| continue; |
| } |
| case '\'': |
| case '\"': |
| goto scan_directive_token; |
| break; |
| case '/': |
| nextc = PEEKC(); |
| if (nextc == '*' || (opts->cplusplus_comments && nextc == '*')) |
| goto scan_directive_token; |
| break; |
| case '\f': |
| case '\v': |
| if (CPP_PEDANTIC (pfile)) |
| cpp_pedwarn (pfile, "%s in preprocessing directive", |
| c == '\f' ? "formfeed" : "vertical tab"); |
| break; |
| |
| case '\n': |
| FORWARD(-1); |
| goto end_directive; |
| scan_directive_token: |
| FORWARD(-1); |
| cpp_get_token (pfile); |
| continue; |
| } |
| CPP_PUTC (pfile, c); |
| } |
| end_directive: ; |
| CPP_NUL_TERMINATE (pfile); |
| } |
| |
| void |
| skip_rest_of_line (pfile) |
| cpp_reader *pfile; |
| { |
| long old = CPP_WRITTEN (pfile); |
| copy_rest_of_line (pfile); |
| CPP_SET_WRITTEN (pfile, old); |
| } |
| |
| /* Handle a possible # directive. |
| '#' has already been read. */ |
| |
| int |
| handle_directive (pfile) |
| cpp_reader *pfile; |
| { int c; |
| register struct directive *kt; |
| int ident_length; |
| long after_ident; |
| U_CHAR *ident, *line_end; |
| long old_written = CPP_WRITTEN (pfile); |
| |
| cpp_skip_hspace (pfile); |
| |
| c = PEEKC (); |
| if (c >= '0' && c <= '9') |
| { |
| /* Handle # followed by a line number. */ |
| if (CPP_PEDANTIC (pfile)) |
| cpp_pedwarn (pfile, "`#' followed by integer"); |
| do_line (pfile, NULL); |
| goto done_a_directive; |
| } |
| |
| /* Now find the directive name. */ |
| CPP_PUTC (pfile, '#'); |
| parse_name (pfile, GETC()); |
| ident = pfile->token_buffer + old_written + 1; |
| ident_length = CPP_PWRITTEN (pfile) - ident; |
| if (ident_length == 0 && PEEKC() == '\n') |
| { |
| /* A line of just `#' becomes blank. */ |
| goto done_a_directive; |
| } |
| |
| #if 0 |
| if (ident_length == 0 || !is_idstart[*ident]) { |
| U_CHAR *p = ident; |
| while (is_idchar[*p]) { |
| if (*p < '0' || *p > '9') |
| break; |
| p++; |
| } |
| /* Avoid error for `###' and similar cases unless -pedantic. */ |
| if (p == ident) { |
| while (*p == '#' || is_hor_space[*p]) p++; |
| if (*p == '\n') { |
| if (pedantic && !lang_asm) |
| cpp_warning (pfile, "invalid preprocessor directive"); |
| return 0; |
| } |
| } |
| |
| if (!lang_asm) |
| cpp_error (pfile, "invalid preprocessor directive name"); |
| |
| return 0; |
| } |
| #endif |
| /* |
| * Decode the keyword and call the appropriate expansion |
| * routine, after moving the input pointer up to the next line. |
| */ |
| for (kt = directive_table; ; kt++) { |
| if (kt->length <= 0) |
| goto not_a_directive; |
| if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length)) |
| break; |
| } |
| |
| if (kt->command_reads_line) |
| after_ident = 0; |
| else |
| { |
| /* Nonzero means do not delete comments within the directive. |
| #define needs this when -traditional. */ |
| int comments = CPP_TRADITIONAL (pfile) && kt->traditional_comments; |
| int save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments; |
| CPP_OPTIONS (pfile)->put_out_comments = comments; |
| after_ident = CPP_WRITTEN (pfile); |
| copy_rest_of_line (pfile); |
| CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments; |
| } |
| |
| /* For #pragma and #define, we may want to pass through the directive. |
| Other directives may create output, but we don't want the directive |
| itself out, so we pop it now. For example #include may write a #line |
| command (see comment in do_include), and conditionals may emit |
| #failed ... #endfailed stuff. But note that popping the buffer |
| means the parameters to kt->func may point after pfile->limit |
| so these parameters are invalid as soon as something gets appended |
| to the token_buffer. */ |
| |
| line_end = CPP_PWRITTEN (pfile); |
| if (!kt->pass_thru && kt->type != T_DEFINE) |
| CPP_SET_WRITTEN (pfile, old_written); |
| |
| (*kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end); |
| if (kt->pass_thru |
| || (kt->type == T_DEFINE |
| && CPP_OPTIONS (pfile)->dump_macros == dump_definitions)) |
| { |
| /* Just leave the entire #define in the output stack. */ |
| } |
| else if (kt->type == T_DEFINE |
| && CPP_OPTIONS (pfile)->dump_macros == dump_names) |
| { |
| U_CHAR *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */ |
| SKIP_WHITE_SPACE (p); |
| while (is_idchar[*p]) p++; |
| pfile->limit = p; |
| CPP_PUTC (pfile, '\n'); |
| } |
| else if (kt->type == T_DEFINE) |
| CPP_SET_WRITTEN (pfile, old_written); |
| done_a_directive: |
| return 1; |
| |
| not_a_directive: |
| return 0; |
| } |
| |
| /* Pass a directive through to the output file. |
| BUF points to the contents of the directive, as a contiguous string. |
| LIMIT points to the first character past the end of the directive. |
| KEYWORD is the keyword-table entry for the directive. */ |
| |
| static void |
| pass_thru_directive (buf, limit, pfile, keyword) |
| U_CHAR *buf, *limit; |
| cpp_reader *pfile; |
| struct directive *keyword; |
| { |
| register unsigned keyword_length = keyword->length; |
| |
| CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf)); |
| CPP_PUTC_Q (pfile, '#'); |
| CPP_PUTS_Q (pfile, keyword->name, keyword_length); |
| if (limit != buf && buf[0] != ' ') |
| CPP_PUTC_Q (pfile, ' '); |
| CPP_PUTS_Q (pfile, buf, limit - buf); |
| #if 0 |
| CPP_PUTS_Q (pfile, '\n'); |
| /* Count the line we have just made in the output, |
| to get in sync properly. */ |
| pfile->lineno++; |
| #endif |
| } |
| |
| /* The arglist structure is built by do_define to tell |
| collect_definition where the argument names begin. That |
| is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist |
| would contain pointers to the strings x, y, and z. |
| Collect_definition would then build a DEFINITION node, |
| with reflist nodes pointing to the places x, y, and z had |
| appeared. So the arglist is just convenience data passed |
| between these two routines. It is not kept around after |
| the current #define has been processed and entered into the |
| hash table. */ |
| |
| struct arglist { |
| struct arglist *next; |
| U_CHAR *name; |
| int length; |
| int argno; |
| char rest_args; |
| }; |
| |
| /* Read a replacement list for a macro with parameters. |
| Build the DEFINITION structure. |
| Reads characters of text starting at BUF until END. |
| ARGLIST specifies the formal parameters to look for |
| in the text of the definition; NARGS is the number of args |
| in that list, or -1 for a macro name that wants no argument list. |
| MACRONAME is the macro name itself (so we can avoid recursive expansion) |
| and NAMELEN is its length in characters. |
| |
| Note that comments, backslash-newlines, and leading white space |
| have already been deleted from the argument. */ |
| |
| static DEFINITION * |
| collect_expansion (pfile, buf, limit, nargs, arglist) |
| cpp_reader *pfile; |
| U_CHAR *buf, *limit; |
| int nargs; |
| struct arglist *arglist; |
| { |
| DEFINITION *defn; |
| register U_CHAR *p, *lastp, *exp_p; |
| struct reflist *endpat = NULL; |
| /* Pointer to first nonspace after last ## seen. */ |
| U_CHAR *concat = 0; |
| /* Pointer to first nonspace after last single-# seen. */ |
| U_CHAR *stringify = 0; |
| int maxsize; |
| int expected_delimiter = '\0'; |
| |
| /* Scan thru the replacement list, ignoring comments and quoted |
| strings, picking up on the macro calls. It does a linear search |
| thru the arg list on every potential symbol. Profiling might say |
| that something smarter should happen. */ |
| |
| if (limit < buf) |
| abort (); |
| |
| /* Find the beginning of the trailing whitespace. */ |
| p = buf; |
| while (p < limit && is_space[limit[-1]]) limit--; |
| |
| /* Allocate space for the text in the macro definition. |
| Leading and trailing whitespace chars need 2 bytes each. |
| Each other input char may or may not need 1 byte, |
| so this is an upper bound. The extra 5 are for invented |
| leading and trailing newline-marker and final null. */ |
| maxsize = (sizeof (DEFINITION) |
| + (limit - p) + 5); |
| /* Occurrences of '@' get doubled, so allocate extra space for them. */ |
| while (p < limit) |
| if (*p++ == '@') |
| maxsize++; |
| defn = (DEFINITION *) xcalloc (1, maxsize); |
| |
| defn->nargs = nargs; |
| exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); |
| lastp = exp_p; |
| |
| p = buf; |
| |
| /* Add one initial space escape-marker to prevent accidental |
| token-pasting (often removed by macroexpand). */ |
| *exp_p++ = '@'; |
| *exp_p++ = ' '; |
| |
| if (limit - p >= 2 && p[0] == '#' && p[1] == '#') { |
| cpp_error (pfile, "`##' at start of macro definition"); |
| p += 2; |
| } |
| |
| /* Process the main body of the definition. */ |
| while (p < limit) { |
| int skipped_arg = 0; |
| register U_CHAR c = *p++; |
| |
| *exp_p++ = c; |
| |
| if (!CPP_TRADITIONAL (pfile)) { |
| switch (c) { |
| case '\'': |
| case '\"': |
| if (expected_delimiter != '\0') { |
| if (c == expected_delimiter) |
| expected_delimiter = '\0'; |
| } else |
| expected_delimiter = c; |
| break; |
| |
| case '\\': |
| if (p < limit && expected_delimiter) { |
| /* In a string, backslash goes through |
| and makes next char ordinary. */ |
| *exp_p++ = *p++; |
| } |
| break; |
| |
| case '@': |
| /* An '@' in a string or character constant stands for itself, |
| and does not need to be escaped. */ |
| if (!expected_delimiter) |
| *exp_p++ = c; |
| break; |
| |
| case '#': |
| /* # is ordinary inside a string. */ |
| if (expected_delimiter) |
| break; |
| if (p < limit && *p == '#') { |
| /* ##: concatenate preceding and following tokens. */ |
| /* Take out the first #, discard preceding whitespace. */ |
| exp_p--; |
| while (exp_p > lastp && is_hor_space[exp_p[-1]]) |
| --exp_p; |
| /* Skip the second #. */ |
| p++; |
| /* Discard following whitespace. */ |
| SKIP_WHITE_SPACE (p); |
| concat = p; |
| if (p == limit) |
| cpp_error (pfile, "`##' at end of macro definition"); |
| } else if (nargs >= 0) { |
| /* Single #: stringify following argument ref. |
| Don't leave the # in the expansion. */ |
| exp_p--; |
| SKIP_WHITE_SPACE (p); |
| if (p == limit || ! is_idstart[*p] |
| || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"'))) |
| cpp_error (pfile, |
| "`#' operator is not followed by a macro argument name"); |
| else |
| stringify = p; |
| } |
| break; |
| } |
| } else { |
| /* In -traditional mode, recognize arguments inside strings and |
| and character constants, and ignore special properties of #. |
| Arguments inside strings are considered "stringified", but no |
| extra quote marks are supplied. */ |
| switch (c) { |
| case '\'': |
| case '\"': |
| if (expected_delimiter != '\0') { |
| if (c == expected_delimiter) |
| expected_delimiter = '\0'; |
| } else |
| expected_delimiter = c; |
| break; |
| |
| case '\\': |
| /* Backslash quotes delimiters and itself, but not macro args. */ |
| if (expected_delimiter != 0 && p < limit |
| && (*p == expected_delimiter || *p == '\\')) { |
| *exp_p++ = *p++; |
| continue; |
| } |
| break; |
| |
| case '/': |
| if (expected_delimiter != '\0') /* No comments inside strings. */ |
| break; |
| if (*p == '*') { |
| /* If we find a comment that wasn't removed by handle_directive, |
| this must be -traditional. So replace the comment with |
| nothing at all. */ |
| exp_p--; |
| p += 1; |
| while (p < limit && !(p[-2] == '*' && p[-1] == '/')) |
| p++; |
| #if 0 |
| /* Mark this as a concatenation-point, as if it had been ##. */ |
| concat = p; |
| #endif |
| } |
| break; |
| } |
| } |
| |
| /* Handle the start of a symbol. */ |
| if (is_idchar[c] && nargs > 0) { |
| U_CHAR *id_beg = p - 1; |
| int id_len; |
| |
| --exp_p; |
| while (p != limit && is_idchar[*p]) p++; |
| id_len = p - id_beg; |
| |
| if (is_idstart[c] |
| && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) { |
| register struct arglist *arg; |
| |
| for (arg = arglist; arg != NULL; arg = arg->next) { |
| struct reflist *tpat; |
| |
| if (arg->name[0] == c |
| && arg->length == id_len |
| && strncmp (arg->name, id_beg, id_len) == 0) { |
| if (expected_delimiter && CPP_OPTIONS (pfile)->warn_stringify) { |
| if (CPP_TRADITIONAL (pfile)) { |
| cpp_warning (pfile, "macro argument `%.*s' is stringified.", |
| id_len, arg->name); |
| } else { |
| cpp_warning (pfile, |
| "macro arg `%.*s' would be stringified with -traditional.", |
| id_len, arg->name); |
| } |
| } |
| /* If ANSI, don't actually substitute inside a string. */ |
| if (!CPP_TRADITIONAL (pfile) && expected_delimiter) |
| break; |
| /* make a pat node for this arg and append it to the end of |
| the pat list */ |
| tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); |
| tpat->next = NULL; |
| tpat->raw_before = concat == id_beg; |
| tpat->raw_after = 0; |
| tpat->rest_args = arg->rest_args; |
| tpat->stringify = (CPP_TRADITIONAL (pfile) |
| ? expected_delimiter != '\0' |
| : stringify == id_beg); |
| |
| if (endpat == NULL) |
| defn->pattern = tpat; |
| else |
| endpat->next = tpat; |
| endpat = tpat; |
| |
| tpat->argno = arg->argno; |
| tpat->nchars = exp_p - lastp; |
| { |
| register U_CHAR *p1 = p; |
| SKIP_WHITE_SPACE (p1); |
| if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#') |
| tpat->raw_after = 1; |
| } |
| lastp = exp_p; /* place to start copying from next time */ |
| skipped_arg = 1; |
| break; |
| } |
| } |
| } |
| |
| /* If this was not a macro arg, copy it into the expansion. */ |
| if (! skipped_arg) { |
| register U_CHAR *lim1 = p; |
| p = id_beg; |
| while (p != lim1) |
| *exp_p++ = *p++; |
| if (stringify == id_beg) |
| cpp_error (pfile, |
| "`#' operator should be followed by a macro argument name"); |
| } |
| } |
| } |
| |
| if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0) |
| { |
| /* If ANSI, put in a "@ " marker to prevent token pasting. |
| But not if "inside a string" (which in ANSI mode |
| happens only for -D option). */ |
| *exp_p++ = '@'; |
| *exp_p++ = ' '; |
| } |
| |
| *exp_p = '\0'; |
| |
| defn->length = exp_p - defn->expansion; |
| |
| /* Crash now if we overrun the allocated size. */ |
| if (defn->length + 1 > maxsize) |
| abort (); |
| |
| #if 0 |
| /* This isn't worth the time it takes. */ |
| /* give back excess storage */ |
| defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); |
| #endif |
| |
| return defn; |
| } |
| |
| /* |
| * 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) |
| |
| /* Create a DEFINITION node from a #define directive. Arguments are |
| as for do_define. */ |
| |
| static MACRODEF |
| create_definition (buf, limit, pfile, predefinition) |
| U_CHAR *buf, *limit; |
| cpp_reader *pfile; |
| int predefinition; |
| { |
| U_CHAR *bp; /* temp ptr into input buffer */ |
| U_CHAR *symname; /* remember where symbol name starts */ |
| int sym_length; /* and how long it is */ |
| int rest_args = 0; |
| long line, col; |
| char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : ""; |
| DEFINITION *defn; |
| int arglengths = 0; /* Accumulate lengths of arg names |
| plus number of args. */ |
| MACRODEF mdef; |
| cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); |
| |
| bp = buf; |
| |
| while (is_hor_space[*bp]) |
| bp++; |
| |
| symname = bp; /* remember where it starts */ |
| |
| sym_length = check_macro_name (pfile, bp, "macro"); |
| bp += sym_length; |
| |
| /* Lossage will occur if identifiers or control keywords are broken |
| across lines using backslash. This is not the right place to take |
| care of that. */ |
| |
| if (*bp == '(') { |
| struct arglist *arg_ptrs = NULL; |
| int argno = 0; |
| |
| bp++; /* skip '(' */ |
| SKIP_WHITE_SPACE (bp); |
| |
| /* Loop over macro argument names. */ |
| while (*bp != ')') { |
| struct arglist *temp; |
| |
| temp = (struct arglist *) alloca (sizeof (struct arglist)); |
| temp->name = bp; |
| temp->next = arg_ptrs; |
| temp->argno = argno++; |
| temp->rest_args = 0; |
| arg_ptrs = temp; |
| |
| if (rest_args) |
| cpp_pedwarn (pfile, "another parameter follows `%s'", rest_extension); |
| |
| if (!is_idstart[*bp]) |
| cpp_pedwarn (pfile, "invalid character in macro parameter name"); |
| |
| /* Find the end of the arg name. */ |
| while (is_idchar[*bp]) { |
| bp++; |
| /* do we have a "special" rest-args extension here? */ |
| if (limit - bp > REST_EXTENSION_LENGTH |
| && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) { |
| rest_args = 1; |
| temp->rest_args = 1; |
| break; |
| } |
| } |
| temp->length = bp - temp->name; |
| if (rest_args == 1) |
| bp += REST_EXTENSION_LENGTH; |
| arglengths += temp->length + 2; |
| SKIP_WHITE_SPACE (bp); |
| if (temp->length == 0 || (*bp != ',' && *bp != ')')) { |
| cpp_error (pfile, "badly punctuated parameter list in `#define'"); |
| goto nope; |
| } |
| if (*bp == ',') { |
| bp++; |
| SKIP_WHITE_SPACE (bp); |
| } |
| if (bp >= limit) { |
| cpp_error (pfile, "unterminated parameter list in `#define'"); |
| goto nope; |
| } |
| { |
| struct arglist *otemp; |
| |
| for (otemp = temp->next; otemp != NULL; otemp = otemp->next) |
| if (temp->length == otemp->length |
| && strncmp (temp->name, otemp->name, temp->length) == 0) { |
| U_CHAR *name; |
| |
| name = (U_CHAR *) alloca (temp->length + 1); |
| (void) strncpy (name, temp->name, temp->length); |
| name[temp->length] = '\0'; |
| cpp_error (pfile, |
| "duplicate argument name `%s' in `#define'", name); |
| goto nope; |
| } |
| } |
| } |
| |
| ++bp; /* skip paren */ |
| SKIP_WHITE_SPACE (bp); |
| /* now everything from bp before limit is the definition. */ |
| defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs); |
| defn->rest_args = rest_args; |
| |
| /* Now set defn->args.argnames to the result of concatenating |
| the argument names in reverse order |
| with comma-space between them. */ |
| defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1); |
| { |
| struct arglist *temp; |
| int i = 0; |
| for (temp = arg_ptrs; temp; temp = temp->next) { |
| bcopy (temp->name, &defn->args.argnames[i], temp->length); |
| i += temp->length; |
| if (temp->next != 0) { |
| defn->args.argnames[i++] = ','; |
| defn->args.argnames[i++] = ' '; |
| } |
| } |
| defn->args.argnames[i] = 0; |
| } |
| } else { |
| /* Simple expansion or empty definition. */ |
| |
| if (bp < limit) |
| { |
| if (is_hor_space[*bp]) { |
| bp++; |
| SKIP_WHITE_SPACE (bp); |
| } else { |
| switch (*bp) { |
| case '!': case '"': case '#': case '%': case '&': case '\'': |
| case ')': case '*': case '+': case ',': case '-': case '.': |
| case '/': case ':': case ';': case '<': case '=': case '>': |
| case '?': case '[': case '\\': case ']': case '^': case '{': |
| case '|': case '}': case '~': |
| cpp_warning (pfile, "missing white space after `#define %.*s'", |
| sym_length, symname); |
| break; |
| |
| default: |
| cpp_pedwarn (pfile, "missing white space after `#define %.*s'", |
| sym_length, symname); |
| break; |
| } |
| } |
| } |
| /* now everything from bp before limit is the definition. */ |
| defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); |
| defn->args.argnames = (U_CHAR *) ""; |
| } |
| |
| defn->line = line; |
| defn->file = file; |
| |
| /* OP is null if this is a predefinition */ |
| defn->predefined = predefinition; |
| mdef.defn = defn; |
| mdef.symnam = symname; |
| mdef.symlen = sym_length; |
| |
| return mdef; |
| |
| nope: |
| mdef.defn = 0; |
| return mdef; |
| } |
| |
| /* Check a purported macro name SYMNAME, and yield its length. |
| USAGE is the kind of name this is intended for. */ |
| |
| static int |
| check_macro_name (pfile, symname, usage) |
| cpp_reader *pfile; |
| U_CHAR *symname; |
| char *usage; |
| { |
| U_CHAR *p; |
| int sym_length; |
| |
| for (p = symname; is_idchar[*p]; p++) |
| ; |
| sym_length = p - symname; |
| if (sym_length == 0 |
| || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"'))) |
| cpp_error (pfile, "invalid %s name", usage); |
| else if (!is_idstart[*symname]) { |
| U_CHAR *msg; /* what pain... */ |
| msg = (U_CHAR *) alloca (sym_length + 1); |
| bcopy (symname, msg, sym_length); |
| msg[sym_length] = 0; |
| cpp_error (pfile, "invalid %s name `%s'", usage, msg); |
| } else { |
| if (! strncmp (symname, "defined", 7) && sym_length == 7) |
| cpp_error (pfile, "invalid %s name `defined'", usage); |
| } |
| return sym_length; |
| } |
| |
| /* Return zero if two DEFINITIONs are isomorphic. */ |
| |
| static int |
| compare_defs (d1, d2) |
| DEFINITION *d1, *d2; |
| { |
| register struct reflist *a1, *a2; |
| register U_CHAR *p1 = d1->expansion; |
| register U_CHAR *p2 = d2->expansion; |
| int first = 1; |
| |
| if (d1->nargs != d2->nargs) |
| return 1; |
| if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames)) |
| return 1; |
| for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; |
| a1 = a1->next, a2 = a2->next) { |
| if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars)) |
| || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0)) |
| || a1->argno != a2->argno |
| || a1->stringify != a2->stringify |
| || a1->raw_before != a2->raw_before |
| || a1->raw_after != a2->raw_after) |
| return 1; |
| first = 0; |
| p1 += a1->nchars; |
| p2 += a2->nchars; |
| } |
| if (a1 != a2) |
| return 1; |
| if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion), |
| p2, d2->length - (p2 - d2->expansion), 1)) |
| return 1; |
| return 0; |
| } |
| |
| /* Return 1 if two parts of two macro definitions are effectively different. |
| One of the parts starts at BEG1 and has LEN1 chars; |
| the other has LEN2 chars at BEG2. |
| Any sequence of whitespace matches any other sequence of whitespace. |
| FIRST means these parts are the first of a macro definition; |
| so ignore leading whitespace entirely. |
| LAST means these parts are the last of a macro definition; |
| so ignore trailing whitespace entirely. */ |
| |
| static int |
| comp_def_part (first, beg1, len1, beg2, len2, last) |
| int first; |
| U_CHAR *beg1, *beg2; |
| int len1, len2; |
| int last; |
| { |
| register U_CHAR *end1 = beg1 + len1; |
| register U_CHAR *end2 = beg2 + len2; |
| if (first) { |
| while (beg1 != end1 && is_space[*beg1]) beg1++; |
| while (beg2 != end2 && is_space[*beg2]) beg2++; |
| } |
| if (last) { |
| while (beg1 != end1 && is_space[end1[-1]]) end1--; |
| while (beg2 != end2 && is_space[end2[-1]]) end2--; |
| } |
| while (beg1 != end1 && beg2 != end2) { |
| if (is_space[*beg1] && is_space[*beg2]) { |
| while (beg1 != end1 && is_space[*beg1]) beg1++; |
| while (beg2 != end2 && is_space[*beg2]) beg2++; |
| } else if (*beg1 == *beg2) { |
| beg1++; beg2++; |
| } else break; |
| } |
| return (beg1 != end1) || (beg2 != end2); |
| } |
| |
| /* Process a #define command. |
| BUF points to the contents of the #define command, as a contiguous string. |
| LIMIT points to the first character past the end of the definition. |
| KEYWORD is the keyword-table entry for #define, |
| or NULL for a "predefined" macro. */ |
| |
| static int |
| do_define (pfile, keyword, buf, limit) |
| cpp_reader *pfile; |
| struct directive *keyword; |
| U_CHAR *buf, *limit; |
| { |
| int hashcode; |
| MACRODEF mdef; |
| HASHNODE *hp; |
| |
| #if 0 |
| /* If this is a precompiler run (with -pcp) pass thru #define commands. */ |
| if (pcp_outfile && keyword) |
| pass_thru_directive (buf, limit, pfile, keyword); |
| #endif |
| |
| mdef = create_definition (buf, limit, pfile, keyword == NULL); |
| if (mdef.defn == 0) |
| goto nope; |
| |
| hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE); |
| |
| if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen, hashcode)) != NULL) |
| { |
| int ok = 0; |
| /* Redefining a precompiled key is ok. */ |
| if (hp->type == T_PCSTRING) |
| ok = 1; |
| /* Redefining a macro is ok if the definitions are the same. */ |
| else if (hp->type == T_MACRO) |
| ok = ! compare_defs (mdef.defn, hp->value.defn); |
| /* Redefining a constant is ok with -D. */ |
| else if (hp->type == T_CONST) |
| ok = ! CPP_OPTIONS (pfile)->done_initializing; |
| /* Print the warning if it's not ok. */ |
| if (!ok) |
| { |
| U_CHAR *msg; /* what pain... */ |
| |
| /* If we are passing through #define and #undef directives, do |
| that for this re-definition now. */ |
| if (CPP_OPTIONS (pfile)->debug_output && keyword) |
| pass_thru_directive (buf, limit, pfile, keyword); |
| |
| msg = (U_CHAR *) alloca (mdef.symlen + 22); |
| *msg = '`'; |
| bcopy (mdef.symnam, msg + 1, mdef.symlen); |
| strcpy ((char *) (msg + mdef.symlen + 1), "' redefined"); |
| cpp_pedwarn (pfile, msg); |
| if (hp->type == T_MACRO) |
| cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line, |
| "this is the location of the previous definition"); |
| } |
| /* Replace the old definition. */ |
| hp->type = T_MACRO; |
| hp->value.defn = mdef.defn; |
| } |
| else |
| { |
| /* If we are passing through #define and #undef directives, do |
| that for this new definition now. */ |
| if (CPP_OPTIONS (pfile)->debug_output && keyword) |
| pass_thru_directive (buf, limit, pfile, keyword); |
| install (mdef.symnam, mdef.symlen, T_MACRO, 0, |
| (char *) mdef.defn, hashcode); |
| } |
| |
| return 0; |
| |
| nope: |
| |
| return 1; |
| } |
| |
| /* This structure represents one parsed argument in a macro call. |
| `raw' points to the argument text as written (`raw_length' is its length). |
| `expanded' points to the argument's macro-expansion |
| (its length is `expand_length'). |
| `stringified_length' is the length the argument would have |
| if stringified. |
| `use_count' is the number of times this macro arg is substituted |
| into the macro. If the actual use count exceeds 10, |
| the value stored is 10. */ |
| |
| /* raw and expanded are relative to ARG_BASE */ |
| #define ARG_BASE ((pfile)->token_buffer) |
| |
| struct argdata { |
| /* Strings relative to pfile->token_buffer */ |
| long raw, expanded, stringified; |
| int raw_length, expand_length; |
| int stringified_length; |
| char newlines; |
| char use_count; |
| }; |
| |
| /* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack. |
| If BUFFER != NULL, then use the LENGTH characters in BUFFER |
| as the new input buffer. |
| Return the new buffer, or NULL on failure. */ |
| |
| cpp_buffer * |
| cpp_push_buffer (pfile, buffer, length) |
| cpp_reader *pfile; |
| U_CHAR *buffer; |
| long length; |
| { |
| register cpp_buffer *buf = CPP_BUFFER (pfile); |
| if (buf == pfile->buffer_stack) |
| { |
| cpp_fatal (pfile, "%s: macro or `#include' recursion too deep", |
| buf->fname); |
| return NULL; |
| } |
| buf--; |
| bzero ((char *) buf, sizeof (cpp_buffer)); |
| CPP_BUFFER (pfile) = buf; |
| buf->if_stack = pfile->if_stack; |
| buf->cleanup = null_cleanup; |
| buf->underflow = null_underflow; |
| buf->buf = buf->cur = buffer; |
| buf->alimit = buf->rlimit = buffer + length; |
| |
| return buf; |
| } |
| |
| cpp_buffer * |
| cpp_pop_buffer (pfile) |
| cpp_reader *pfile; |
| { |
| cpp_buffer *buf = CPP_BUFFER (pfile); |
| (*buf->cleanup) (buf, pfile); |
| return ++CPP_BUFFER (pfile); |
| } |
| |
| /* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer. |
| Pop the buffer when done. */ |
| |
| void |
| cpp_scan_buffer (pfile) |
| cpp_reader *pfile; |
| { |
| cpp_buffer *buffer = CPP_BUFFER (pfile); |
| for (;;) |
| { |
| enum cpp_token token = cpp_get_token (pfile); |
| if (token == CPP_EOF) /* Should not happen ... */ |
| break; |
| if (token == CPP_POP && CPP_BUFFER (pfile) == buffer) |
| { |
| cpp_pop_buffer (pfile); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Rescan a string (which may have escape marks) into pfile's buffer. |
| * Place the result in pfile->token_buffer. |
| * |
| * The input is copied before it is scanned, so it is safe to pass |
| * it something from the token_buffer that will get overwritten |
| * (because it follows CPP_WRITTEN). This is used by do_include. |
| */ |
| |
| static void |
| cpp_expand_to_buffer (pfile, buf, length) |
| cpp_reader *pfile; |
| U_CHAR *buf; |
| int length; |
| { |
| register cpp_buffer *ip; |
| cpp_buffer obuf; |
| U_CHAR *limit = buf + length; |
| U_CHAR *buf1; |
| #if 0 |
| int odepth = indepth; |
| #endif |
| |
| if (length < 0) |
| abort (); |
| |
| /* Set up the input on the input stack. */ |
| |
| buf1 = (U_CHAR *) alloca (length + 1); |
| { |
| register U_CHAR *p1 = buf; |
| register U_CHAR *p2 = buf1; |
| |
| while (p1 != limit) |
| *p2++ = *p1++; |
| } |
| buf1[length] = 0; |
| |
| ip = cpp_push_buffer (pfile, buf1, length); |
| if (ip == NULL) |
| return; |
| ip->has_escapes = 1; |
| #if 0 |
| ip->lineno = obuf.lineno = 1; |
| #endif |
| |
| /* Scan the input, create the output. */ |
| cpp_scan_buffer (pfile); |
| |
| #if 0 |
| if (indepth != odepth) |
| abort (); |
| #endif |
| |
| CPP_NUL_TERMINATE (pfile); |
| } |
| |
| |
| static void |
| adjust_position (buf, limit, linep, colp) |
| U_CHAR *buf; |
| U_CHAR *limit; |
| long *linep; |
| long *colp; |
| { |
| while (buf < limit) |
| { |
| U_CHAR ch = *buf++; |
| if (ch == '\n') |
| (*linep)++, (*colp) = 1; |
| else |
| (*colp)++; |
| } |
| } |
| |
| /* Move line_base forward, updating lineno and colno. */ |
| |
| static void |
| update_position (pbuf) |
| register cpp_buffer *pbuf; |
| { |
| unsigned char *old_pos = pbuf->buf + pbuf->line_base; |
| unsigned char *new_pos = pbuf->cur; |
| register struct parse_marker *mark; |
| for (mark = pbuf->marks; mark != NULL; mark = mark->next) |
| { |
| if (pbuf->buf + mark->position < new_pos) |
| new_pos = pbuf->buf + mark->position; |
| } |
| pbuf->line_base += new_pos - old_pos; |
| adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno); |
| } |
| |
| void |
| cpp_buf_line_and_col (pbuf, linep, colp) |
| register cpp_buffer *pbuf; |
| long *linep, *colp; |
| { |
| long dummy; |
| if (colp == NULL) |
| colp = &dummy; |
| if (pbuf) |
| { |
| *linep = pbuf->lineno; |
| *colp = pbuf->colno; |
| adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp); |
| } |
| else |
| { |
| *linep = 0; |
| *colp = 0; |
| } |
| } |
| |
| /* Return the cpp_buffer that corresponds to a file (not a macro). */ |
| |
| cpp_buffer * |
| cpp_file_buffer (pfile) |
| cpp_reader *pfile; |
| { |
| cpp_buffer *ip = CPP_BUFFER (pfile); |
| |
| for ( ; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip)) |
| if (ip->fname != NULL) |
| return ip; |
| return NULL; |
| } |
| |
| static long |
| count_newlines (buf, limit) |
| register U_CHAR *buf; |
| register U_CHAR *limit; |
| { |
| register long count = 0; |
| while (buf < limit) |
| { |
| U_CHAR ch = *buf++; |
| if (ch == '\n') |
| count++; |
| } |
| return count; |
| } |
| |
| /* |
| * write out a #line command, for instance, after an #include file. |
| * If CONDITIONAL is nonzero, we can omit the #line if it would |
| * appear to be a no-op, and we can output a few newlines instead |
| * if we want to increase the line number by a small amount. |
| * FILE_CHANGE says whether we are entering a file, leaving, or neither. |
| */ |
| |
| static void |
| output_line_command (pfile, conditional, file_change) |
| cpp_reader *pfile; |
| int conditional; |
| enum file_change_code file_change; |
| { |
| int len; |
| char *line_cmd_buf, *line_end; |
| long line, col; |
| cpp_buffer *ip = CPP_BUFFER (pfile); |
| |
| if (ip->fname == NULL) |
| return; |
| |
| update_position (ip); |
| |
| if (CPP_OPTIONS (pfile)->no_line_commands |
| || CPP_OPTIONS (pfile)->no_output) |
| return; |
| |
| line = CPP_BUFFER (pfile)->lineno; |
| col = CPP_BUFFER (pfile)->colno; |
| adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col); |
| |
| if (CPP_OPTIONS (pfile)->no_line_commands) |
| return; |
| |
| if (conditional) { |
| if (line == pfile->lineno) |
| return; |
| |
| /* If the inherited line number is a little too small, |
| output some newlines instead of a #line command. */ |
| if (line > pfile->lineno && line < pfile->lineno + 8) { |
| CPP_RESERVE (pfile, 20); |
| while (line > pfile->lineno) { |
| CPP_PUTC_Q (pfile, '\n'); |
| pfile->lineno++; |
| } |
| return; |
| } |
| } |
| |
| #if 0 |
| /* Don't output a line number of 0 if we can help it. */ |
| if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length |
| && *ip->bufp == '\n') { |
| ip->lineno++; |
| ip->bufp++; |
| } |
| #endif |
| |
| CPP_RESERVE (pfile, 4 * strlen (ip->nominal_fname) + 50); |
| { |
| #ifdef OUTPUT_LINE_COMMANDS |
| static char sharp_line[] = "#line "; |
| #else |
| static char sharp_line[] = "# "; |
| #endif |
| CPP_PUTS_Q (pfile, sharp_line, sizeof(sharp_line)-1); |
| } |
| |
| sprintf (CPP_PWRITTEN (pfile), "%d ", line); |
| CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile))); |
| |
| quote_string (pfile, ip->nominal_fname); |
| if (file_change != same_file) { |
| CPP_PUTC_Q (pfile, ' '); |
| CPP_PUTC_Q (pfile, file_change == enter_file ? '1' : '2'); |
| } |
| /* Tell cc1 if following text comes from a system header file. */ |
| if (ip->system_header_p) { |
| CPP_PUTC_Q (pfile, ' '); |
| CPP_PUTC_Q (pfile, '3'); |
| } |
| #ifndef NO_IMPLICIT_EXTERN_C |
| /* Tell cc1plus if following text should be treated as C. */ |
| if (ip->system_header_p == 2 && CPP_OPTIONS (pfile)->cplusplus) { |
| CPP_PUTC_Q (pfile, ' '); |
| CPP_PUTC_Q (pfile, '4'); |
| } |
| #endif |
| CPP_PUTC_Q (pfile, '\n'); |
| pfile->lineno = line; |
| } |
| |
| /* |
| * Parse a macro argument and append the info on PFILE's token_buffer. |
| * REST_ARGS means to absorb the rest of the args. |
| * Return nonzero to indicate a syntax error. |
| */ |
| |
| static enum cpp_token |
| macarg (pfile, rest_args) |
| cpp_reader *pfile; |
| int rest_args; |
| { |
| int paren = 0; |
| enum cpp_token token; |
| long arg_start = CPP_WRITTEN (pfile); |
| char save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments; |
| CPP_OPTIONS (pfile)->put_out_comments = 0; |
| |
| /* Try to parse as much of the argument as exists at this |
| input stack level. */ |
| pfile->no_macro_expand++; |
| for (;;) |
| { |
| token = cpp_get_token (pfile); |
| switch (token) |
| { |
| case CPP_EOF: |
| goto done; |
| case CPP_POP: |
| /* If we've hit end of file, it's an error (reported by caller). |
| Ditto if it's the end of cpp_expand_to_buffer text. |
| If we've hit end of macro, just continue. */ |
| if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) |
| goto done; |
| break; |
| case CPP_LPAREN: |
| paren++; |
| break; |
| case CPP_RPAREN: |
| if (--paren < 0) |
| goto found; |
| break; |
| case CPP_COMMA: |
| /* if we've returned to lowest level and |
| we aren't absorbing all args */ |
| if (paren == 0 && rest_args == 0) |
| goto found; |
| break; |
| found: |
| /* Remove ',' or ')' from argument buffer. */ |
| CPP_ADJUST_WRITTEN (pfile, -1); |
| goto done; |
| default: ; |
| } |
| } |
| |
| done: |
| CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments; |
| pfile->no_macro_expand--; |
| |
| return token; |
| } |
| |
| /* Turn newlines to spaces in the string of length LENGTH at START, |
| except inside of string constants. |
| The string is copied into itself with its beginning staying fixed. */ |
| |
| static int |
| change_newlines (start, length) |
| U_CHAR *start; |
| int length; |
| { |
| register U_CHAR *ibp; |
| register U_CHAR *obp; |
| register U_CHAR *limit; |
| register int c; |
| |
| ibp = start; |
| limit = start + length; |
| obp = start; |
| |
| while (ibp < limit) { |
| *obp++ = c = *ibp++; |
| switch (c) { |
| |
| case '\'': |
| case '\"': |
| /* Notice and skip strings, so that we don't delete newlines in them. */ |
| { |
| int quotec = c; |
| while (ibp < limit) { |
| *obp++ = c = *ibp++; |
| if (c == quotec) |
| break; |
| if (c == '\n' && quotec == '\'') |
| break; |
| } |
| } |
| break; |
| } |
| } |
| |
| return obp - start; |
| } |
| |
| |
| static struct tm * |
| timestamp (pfile) |
| cpp_reader *pfile; |
| { |
| if (!pfile->timebuf) { |
| time_t t = time ((time_t *) 0); |
| pfile->timebuf = localtime (&t); |
| } |
| return pfile->timebuf; |
| } |
| |
| static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", |
| }; |
| |
| /* |
| * expand things like __FILE__. Place the expansion into the output |
| * buffer *without* rescanning. |
| */ |
| |
| static void |
| special_symbol (hp, pfile) |
| HASHNODE *hp; |
| cpp_reader *pfile; |
| { |
| char *buf; |
| int i, len; |
| int true_indepth; |
| cpp_buffer *ip = NULL; |
| struct tm *timebuf; |
| |
| int paren = 0; /* For special `defined' keyword */ |
| |
| #if 0 |
| if (pcp_outfile && pcp_inside_if |
| && hp->type != T_SPEC_DEFINED && hp->type != T_CONST) |
| cpp_error (pfile, |
| "Predefined macro `%s' used inside `#if' during precompilation", |
| hp->name); |
| #endif |
| |
| for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip)) |
| { |
| if (ip == CPP_NULL_BUFFER (pfile)) |
| { |
| cpp_error (pfile, "cccp error: not in any file?!"); |
| return; /* the show must go on */ |
| } |
| if (ip->fname != NULL) |
| break; |
| } |
| |
| switch (hp->type) |
| { |
| case T_FILE: |
| case T_BASE_FILE: |
| { |
| char *string; |
| if (hp->type == T_BASE_FILE) |
| { |
| while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile)) |
| ip = CPP_PREV_BUFFER (ip); |
| } |
| string = ip->nominal_fname; |
| |
| if (!string) |
| string = ""; |
| CPP_RESERVE (pfile, 3 + 4 * strlen (string)); |
| quote_string (pfile, string); |
| return; |
| } |
| |
| case T_INCLUDE_LEVEL: |
| true_indepth = 0; |
| ip = CPP_BUFFER (pfile); |
| for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip)) |
| if (ip->fname != NULL) |
| true_indepth++; |
| |
| buf = (char *) alloca (8); /* Eight bytes ought to be more than enough */ |
| sprintf (buf, "%d", true_indepth - 1); |
| break; |
| |
| case T_VERSION: |
| buf = (char *) alloca (3 + strlen (version_string)); |
| sprintf (buf, "\"%s\"", version_string); |
| break; |
| |
| #ifndef NO_BUILTIN_SIZE_TYPE |
| case T_SIZE_TYPE: |
| buf = SIZE_TYPE; |
| break; |
| #endif |
| |
| #ifndef NO_BUILTIN_PTRDIFF_TYPE |
| case T_PTRDIFF_TYPE: |
| buf = PTRDIFF_TYPE; |
| break; |
| #endif |
| |
| case T_WCHAR_TYPE: |
| buf = CPP_WCHAR_TYPE (pfile); |
| break; |
| |
| case T_USER_LABEL_PREFIX_TYPE: |
| buf = USER_LABEL_PREFIX; |
| break; |
| |
| case T_REGISTER_PREFIX_TYPE: |
| buf = REGISTER_PREFIX; |
| break; |
| |
| case T_CONST: |
| buf = (char *) alloca (4 * sizeof (int)); |
| sprintf (buf, "%d", hp->value.ival); |
| #if 0 |
| if (pcp_inside_if && pcp_outfile) |
| /* Output a precondition for this macro use */ |
| fprintf (pcp_outfile, "#define %s %d\n", hp->name, hp->value.ival); |
| #endif |
| break; |
| |
| case T_SPECLINE: |
| { |
| long line = ip->lineno; |
| long col = ip->colno; |
| adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col); |
| |
| buf = (char *) alloca (10); |
| sprintf (buf, "%d", line); |
| } |
| break; |
| |
| case T_DATE: |
| case T_TIME: |
| buf = (char *) alloca (20); |
| timebuf = timestamp (pfile); |
| if (hp->type == T_DATE) |
| sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon], |
| timebuf->tm_mday, timebuf->tm_year + 1900); |
| else |
| sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, |
| timebuf->tm_sec); |
| break; |
| |
| case T_SPEC_DEFINED: |
| buf = " 0 "; /* Assume symbol is not defined */ |
| ip = CPP_BUFFER (pfile); |
| SKIP_WHITE_SPACE (ip->cur); |
| if (*ip->cur == '(') |
| { |
| paren++; |
| ip->cur++; /* Skip over the paren */ |
| SKIP_WHITE_SPACE (ip->cur); |
| } |
| |
| if (!is_idstart[*ip->cur]) |
| goto oops; |
| if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"')) |
| goto oops; |
| if (hp = cpp_lookup (pfile, ip->cur, -1, -1)) |
| { |
| #if 0 |
| if (pcp_outfile && pcp_inside_if |
| && (hp->type == T_CONST |
| || (hp->type == T_MACRO && hp->value.defn->predefined))) |
| /* Output a precondition for this macro use. */ |
| fprintf (pcp_outfile, "#define %s\n", hp->name); |
| #endif |
| buf = " 1 "; |
| } |
| #if 0 |
| else |
| if (pcp_outfile && pcp_inside_if) |
| { |
| /* Output a precondition for this macro use */ |
| U_CHAR *cp = ip->bufp; |
| fprintf (pcp_outfile, "#undef "); |
| while (is_idchar[*cp]) /* Ick! */ |
| fputc (*cp++, pcp_outfile); |
| putc ('\n', pcp_outfile); |
| } |
| #endif |
| while (is_idchar[*ip->cur]) |
| ++ip->cur; |
| SKIP_WHITE_SPACE (ip->cur); |
| if (paren) |
| { |
| if (*ip->cur != ')') |
| goto oops; |
| ++ip->cur; |
| } |
| break; |
| |
| oops: |
| |
| cpp_error (pfile, "`defined' without an identifier"); |
| break; |
| |
| default: |
| cpp_error (pfile, "cccp error: invalid special hash type"); /* time for gdb */ |
| abort (); |
| } |
| len = strlen (buf); |
| CPP_RESERVE (pfile, len + 1); |
| CPP_PUTS_Q (pfile, buf, len); |
| CPP_NUL_TERMINATE_Q (pfile); |
| |
| return; |
| } |
| |
| /* Write out a #define command for the special named MACRO_NAME |
| to PFILE's token_buffer. */ |
| |
| static void |
| dump_special_to_buffer (pfile, macro_name) |
| cpp_reader *pfile; |
| char *macro_name; |
| { |
| static char define_directive[] = "#define "; |
| int macro_name_length = strlen (macro_name); |
| output_line_command (pfile, 0, same_file); |
| CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length); |
| CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1); |
| CPP_PUTS_Q (pfile, macro_name, macro_name_length); |
| CPP_PUTC_Q (pfile, ' '); |
| cpp_expand_to_buffer (pfile, macro_name, macro_name_length); |
| CPP_PUTC (pfile, '\n'); |
| } |
| |
| /* Initialize the built-in macros. */ |
| |
| static void |
| initialize_builtins (pfile) |
| cpp_reader *pfile; |
| { |
| install ("__LINE__", -1, T_SPECLINE, 0, 0, -1); |
| install ("__DATE__", -1, T_DATE, 0, 0, -1); |
| install ("__FILE__", -1, T_FILE, 0, 0, -1); |
| install ("__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1); |
| install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1); |
| install ("__VERSION__", -1, T_VERSION, 0, 0, -1); |
| #ifndef NO_BUILTIN_SIZE_TYPE |
| install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1); |
| #endif |
| #ifndef NO_BUILTIN_PTRDIFF_TYPE |
| install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1); |
| #endif |
| install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1); |
| install ("__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1); |
| install ("__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1); |
| install ("__TIME__", -1, T_TIME, 0, 0, -1); |
| if (!CPP_TRADITIONAL (pfile)) |
| install ("__STDC__", -1, T_CONST, STDC_VALUE, 0, -1); |
| if (CPP_OPTIONS (pfile)->objc) |
| install ("__OBJC__", -1, T_CONST, 1, 0, -1); |
| /* This is supplied using a -D by the compiler driver |
| so that it is present only when truly compiling with GNU C. */ |
| /* install ("__GNUC__", -1, T_CONST, 2, 0, -1); */ |
| |
| if (CPP_OPTIONS (pfile)->debug_output) |
| { |
| dump_special_to_buffer (pfile, "__BASE_FILE__"); |
| dump_special_to_buffer (pfile, "__VERSION__"); |
| #ifndef NO_BUILTIN_SIZE_TYPE |
| dump_special_to_buffer (pfile, "__SIZE_TYPE__"); |
| #endif |
| #ifndef NO_BUILTIN_PTRDIFF_TYPE |
| dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__"); |
| #endif |
| dump_special_to_buffer (pfile, "__WCHAR_TYPE__"); |
| dump_special_to_buffer (pfile, "__DATE__"); |
| dump_special_to_buffer (pfile, "__TIME__"); |
| if (!CPP_TRADITIONAL (pfile)) |
| dump_special_to_buffer (pfile, "__STDC__"); |
| if (CPP_OPTIONS (pfile)->objc) |
| dump_special_to_buffer (pfile, "__OBJC__"); |
| } |
| } |
| |
| /* Return 1 iff a token ending in C1 followed directly by a token C2 |
| could cause mis-tokenization. */ |
| |
| static int |
| unsafe_chars (c1, c2) |
| int c1, c2; |
| { |
| switch (c1) |
| { |
| case '+': case '-': |
| if (c2 == c1 || c2 == '=') |
| return 1; |
| goto letter; |
| case '.': |
| case '0': case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| case 'e': case 'E': case 'p': case 'P': |
| if (c2 == '-' || c2 == '+') |
| return 1; /* could extend a pre-processing number */ |
| goto letter; |
| case 'L': |
| if (c2 == '\'' || c2 == '\"') |
| return 1; /* Could turn into L"xxx" or L'xxx'. */ |
| goto letter; |
| letter: |
| case '_': |
| case 'a': case 'b': case 'c': case 'd': case 'f': |
| case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': |
| case 'm': case 'n': case 'o': case 'q': case 'r': |
| case 's': case 't': case 'u': case 'v': case 'w': case 'x': |
| case 'y': case 'z': |
| case 'A': case 'B': case 'C': case 'D': case 'F': |
| case 'G': case 'H': case 'I': case 'J': case 'K': |
| case 'M': case 'N': case 'O': case 'Q': case 'R': |
| case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': |
| case 'Y': case 'Z': |
| /* We're in the middle of either a name or a pre-processing number. */ |
| return (is_idchar[c2] || c2 == '.'); |
| case '<': case '>': case '!': case '%': case '#': case ':': |
| case '^': case '&': case '|': case '*': case '/': case '=': |
| return (c2 == c1 || c2 == '='); |
| } |
| return 0; |
| } |
| |
| /* Expand a macro call. |
| HP points to the symbol that is the macro being called. |
| Put the result of expansion onto the input stack |
| so that subsequent input by our caller will use it. |
| |
| If macro wants arguments, caller has already verified that |
| an argument list follows; arguments come from the input stack. */ |
| |
| static void |
| macroexpand (pfile, hp) |
| cpp_reader *pfile; |
| HASHNODE *hp; |
| { |
| int nargs; |
| DEFINITION *defn = hp->value.defn; |
| register U_CHAR *xbuf; |
| long start_line, start_column; |
| int xbuf_len; |
| struct argdata *args; |
| long old_written = CPP_WRITTEN (pfile); |
| #if 0 |
| int start_line = instack[indepth].lineno; |
| #endif |
| int rest_args, rest_zero; |
| register int i; |
| |
| #if 0 |
| CHECK_DEPTH (return;); |
| #endif |
| |
| #if 0 |
| /* This macro is being used inside a #if, which means it must be */ |
| /* recorded as a precondition. */ |
| if (pcp_inside_if && pcp_outfile && defn->predefined) |
| dump_single_macro (hp, pcp_outfile); |
| #endif |
| |
| pfile->output_escapes++; |
| cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column); |
| |
| nargs = defn->nargs; |
| |
| if (nargs >= 0) |
| { |
| enum cpp_token token; |
| |
| args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); |
| |
| for (i = 0; i < nargs; i++) |
| { |
| args[i].raw = args[i].expanded = 0; |
| args[i].raw_length = 0; |
| args[i].expand_length = args[i].stringified_length = -1; |
| args[i].use_count = 0; |
| } |
| |
| /* Parse all the macro args that are supplied. I counts them. |
| The first NARGS args are stored in ARGS. |
| The rest are discarded. If rest_args is set then we assume |
| macarg absorbed the rest of the args. */ |
| i = 0; |
| rest_args = 0; |
| rest_args = 0; |
| FORWARD(1); /* Discard the open-parenthesis before the first arg. */ |
| do |
| { |
| if (rest_args) |
| continue; |
| if (i < nargs || (nargs == 0 && i == 0)) |
| { |
| /* if we are working on last arg which absorbs rest of args... */ |
| if (i == nargs - 1 && defn->rest_args) |
| rest_args = 1; |
| args[i].raw = CPP_WRITTEN (pfile); |
| token = macarg (pfile, rest_args); |
| args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; |
| args[i].newlines = 0; /* FIXME */ |
| } |
| else |
| token = macarg (pfile, 0); |
| if (token == CPP_EOF || token == CPP_POP) |
| { |
| cpp_error_with_line (pfile, start_line, start_column, |
| "unterminated macro call"); |
| return; |
| } |
| i++; |
| } while (token == CPP_COMMA); |
| |
| /* If we got one arg but it was just whitespace, call that 0 args. */ |
| if (i == 1) |
| { |
| register U_CHAR *bp = ARG_BASE + args[0].raw; |
| register U_CHAR *lim = bp + args[0].raw_length; |
| /* cpp.texi says for foo ( ) we provide one argument. |
| However, if foo wants just 0 arguments, treat this as 0. */ |
| if (nargs == 0) |
| while (bp != lim && is_space[*bp]) bp++; |
| if (bp == lim) |
| i = 0; |
| } |
| |
| /* Don't output an error message if we have already output one for |
| a parse error above. */ |
| rest_zero = 0; |
| if (nargs == 0 && i > 0) |
| { |
| cpp_error (pfile, "arguments given to macro `%s'", hp->name); |
| } |
| else if (i < nargs) |
| { |
| /* traditional C allows foo() if foo wants one argument. */ |
| if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) |
| ; |
| /* the rest args token is allowed to absorb 0 tokens */ |
| else if (i == nargs - 1 && defn->rest_args) |
| rest_zero = 1; |
| else if (i == 0) |
| cpp_error (pfile, "macro `%s' used without args", hp->name); |
| else if (i == 1) |
| cpp_error (pfile, "macro `%s' used with just one arg", hp->name); |
| else |
| cpp_error (pfile, "macro `%s' used with only %d args", |
| hp->name, i); |
| } |
| else if (i > nargs) |
| { |
| cpp_error (pfile, |
| "macro `%s' used with too many (%d) args", hp->name, i); |
| } |
| } |
| |
| /* If macro wants zero args, we parsed the arglist for checking only. |
| Read directly from the macro definition. */ |
| if (nargs <= 0) |
| { |
| xbuf = defn->expansion; |
| xbuf_len = defn->length; |
| } |
| else |
| { |
| register U_CHAR *exp = defn->expansion; |
| register int offset; /* offset in expansion, |
| copied a piece at a time */ |
| register int totlen; /* total amount of exp buffer filled so far */ |
| |
| register struct reflist *ap, *last_ap; |
| |
| /* Macro really takes args. Compute the expansion of this call. */ |
| |
| /* Compute length in characters of the macro's expansion. |
| Also count number of times each arg is used. */ |
| xbuf_len = defn->length; |
| for (ap = defn->pattern; ap != NULL; ap = ap->next) |
| { |
| if (ap->stringify) |
| { |
| register struct argdata *arg = &args[ap->argno]; |
| /* Stringify it it hasn't already been */ |
| if (arg->stringified_length < 0) |
| { |
| int arglen = arg->raw_length; |
| int escaped = 0; |
| int in_string = 0; |
| int c; |
| /* Initially need_space is -1. Otherwise, 1 means the |
| previous character was a space, but we suppressed it; |
| 0 means the previous character was a non-space. */ |
| int need_space = -1; |
| i = 0; |
| arg->stringified = CPP_WRITTEN (pfile); |
| if (!CPP_TRADITIONAL (pfile)) |
| CPP_PUTC (pfile, '\"'); /* insert beginning quote */ |
| for (; i < arglen; i++) |
| { |
| c = (ARG_BASE + arg->raw)[i]; |
| |
| if (! in_string) |
| { |
| /* Internal sequences of whitespace are replaced by |
| one space except within an string or char token.*/ |
| if (is_space[c]) |
| { |
| if (CPP_WRITTEN (pfile) > arg->stringified |
| && (CPP_PWRITTEN (pfile))[-1] == '@') |
| { |
| /* "@ " escape markers are removed */ |
| CPP_ADJUST_WRITTEN (pfile, -1); |
| continue; |
| } |
| if (need_space == 0) |
| need_space = 1; |
| continue; |
| } |
| else if (need_space > 0) |
| CPP_PUTC (pfile, ' '); |
| need_space = 0; |
| } |
| |
| if (escaped) |
| escaped = 0; |
| else |
| { |
| if (c == '\\') |
| escaped = 1; |
| if (in_string) |
| { |
| if (c == in_string) |
| in_string = 0; |
| } |
| else if (c == '\"' || c == '\'') |
| in_string = c; |
| } |
| |
| /* Escape these chars */ |
| if (c == '\"' || (in_string && c == '\\')) |
| CPP_PUTC (pfile, '\\'); |
| if (isprint (c)) |
| CPP_PUTC (pfile, c); |
| else |
| { |
| CPP_RESERVE (pfile, 4); |
| sprintf (CPP_PWRITTEN (pfile), "\\%03o", |
| (unsigned int) c); |
| CPP_ADJUST_WRITTEN (pfile, 4); |
| } |
| } |
| if (!CPP_TRADITIONAL (pfile)) |
| CPP_PUTC (pfile, '\"'); /* insert ending quote */ |
| arg->stringified_length |
| = CPP_WRITTEN (pfile) - arg->stringified; |
| } |
| xbuf_len += args[ap->argno].stringified_length; |
| } |
| else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) |
| /* Add 4 for two newline-space markers to prevent |
| token concatenation. */ |
| xbuf_len += args[ap->argno].raw_length + 4; |
| else |
| { |
| /* We have an ordinary (expanded) occurrence of the arg. |
| So compute its expansion, if we have not already. */ |
| if (args[ap->argno].expand_length < 0) |
| { |
| args[ap->argno].expanded = CPP_WRITTEN (pfile); |
| cpp_expand_to_buffer (pfile, |
| ARG_BASE + args[ap->argno].raw, |
| args[ap->argno].raw_length); |
| |
| args[ap->argno].expand_length |
| = CPP_WRITTEN (pfile) - args[ap->argno].expanded; |
| } |
| |
| /* Add 4 for two newline-space markers to prevent |
| token concatenation. */ |
| xbuf_len += args[ap->argno].expand_length + 4; |
| } |
| if (args[ap->argno].use_count < 10) |
| args[ap->argno].use_count++; |
| } |
| |
| xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); |
| |
| /* Generate in XBUF the complete expansion |
| with arguments substituted in. |
| TOTLEN is the total size generated so far. |
| OFFSET is the index in the definition |
| of where we are copying from. */ |
| offset = totlen = 0; |
| for (last_ap = NULL, ap = defn->pattern; ap != NULL; |
| last_ap = ap, ap = ap->next) |
| { |
| register struct argdata *arg = &args[ap->argno]; |
| int count_before = totlen; |
| |
| /* Add chars to XBUF. */ |
| for (i = 0; i < ap->nchars; i++, offset++) |
| xbuf[totlen++] = exp[offset]; |
| |
| /* If followed by an empty rest arg with concatenation, |
| delete the last run of nonwhite chars. */ |
| if (rest_zero && totlen > count_before |
| && ((ap->rest_args && ap->raw_before) |
| || (last_ap != NULL && last_ap->rest_args |
| && last_ap->raw_after))) |
| { |
| /* Delete final whitespace. */ |
| while (totlen > count_before && is_space[xbuf[totlen - 1]]) |
| totlen--; |
| |
| /* Delete the nonwhites before them. */ |
| while (totlen > count_before && ! is_space[xbuf[totlen - 1]]) |
| totlen--; |
| } |
| |
| if (ap->stringify != 0) |
| { |
| bcopy (ARG_BASE + arg->stringified, |
| xbuf + totlen, arg->stringified_length); |
| totlen += arg->stringified_length; |
| } |
| else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) |
| { |
| U_CHAR *p1 = ARG_BASE + arg->raw; |
| U_CHAR *l1 = p1 + arg->raw_length; |
| if (ap->raw_before) |
| { |
| while (p1 != l1 && is_space[*p1]) p1++; |
| while (p1 != l1 && is_idchar[*p1]) |
| xbuf[totlen++] = *p1++; |
| /* Delete any no-reexpansion marker that follows |
| an identifier at the beginning of the argument |
| if the argument is concatenated with what precedes it. */ |
| if (p1[0] == '@' && p1[1] == '-') |
| p1 += 2; |
| } |
| if (ap->raw_after) |
| { |
| /* Arg is concatenated after: delete trailing whitespace, |
| whitespace markers, and no-reexpansion markers. */ |
| while (p1 != l1) |
| { |
| if (is_space[l1[-1]]) l1--; |
| else if (l1[-1] == '-') |
| { |
| U_CHAR *p2 = l1 - 1; |
| /* If a `-' is preceded by an odd number of newlines then it |
| and the last newline are a no-reexpansion marker. */ |
| while (p2 != p1 && p2[-1] == '\n') p2--; |
| if ((l1 - 1 - p2) & 1) { |
| l1 -= 2; |
| } |
| else break; |
| } |
| else break; |
| } |
| } |
| |
| bcopy (p1, xbuf + totlen, l1 - p1); |
| totlen += l1 - p1; |
| } |
| else |
| { |
| U_CHAR *expanded = ARG_BASE + arg->expanded; |
| if (!ap->raw_before && totlen > 0 && arg->expand_length |
| && !CPP_TRADITIONAL(pfile) |
| && unsafe_chars (xbuf[totlen-1], expanded[0])) |
| { |
| xbuf[totlen++] = '@'; |
| xbuf[totlen++] = ' '; |
| } |
| |
| bcopy (expanded, xbuf + totlen, arg->expand_length); |
| totlen += arg->expand_length; |
| |
| if (!ap->raw_after && totlen > 0 && offset < defn->length |
| && !CPP_TRADITIONAL(pfile) |
| && unsafe_chars (xbuf[totlen-1], exp[offset])) |
| { |
| xbuf[totlen++] = '@'; |
| xbuf[totlen++] = ' '; |
| } |
| |
| /* If a macro argument with newlines is used multiple times, |
| then only expand the newlines once. This avoids creating |
| output lines which don't correspond to any input line, |
| which confuses gdb and gcov. */ |
| if (arg->use_count > 1 && arg->newlines > 0) |
| { |
| /* Don't bother doing change_newlines for subsequent |
| uses of arg. */ |
| arg->use_count = 1; |
| arg->expand_length |
| = change_newlines (expanded, arg->expand_length); |
| } |
| } |
| |
| if (totlen > xbuf_len) |
| abort (); |
| } |
| |
| /* if there is anything left of the definition |
| after handling the arg list, copy that in too. */ |
| |
| for (i = offset; i < defn->length; i++) |
| { |
| /* if we've reached the end of the macro */ |
| if (exp[i] == ')') |
| rest_zero = 0; |
| if (! (rest_zero && last_ap != NULL && last_ap->rest_args |
| && last_ap->raw_after)) |
| xbuf[totlen++] = exp[i]; |
| } |
| |
| xbuf[totlen] = 0; |
| xbuf_len = totlen; |
| |
| } |
| |
| pfile->output_escapes--; |
| |
| /* Now put the expansion on the input stack |
| so our caller will commence reading from it. */ |
| push_macro_expansion (pfile, xbuf, xbuf_len, hp); |
| CPP_BUFFER (pfile)->has_escapes = 1; |
| |
| /* Pop the space we've used in the token_buffer for argument expansion. */ |
| CPP_SET_WRITTEN (pfile, old_written); |
| |
| /* Recursive macro use sometimes works traditionally. |
| #define foo(x,y) bar (x (y,0), y) |
| foo (foo, baz) */ |
| |
| if (!CPP_TRADITIONAL (pfile)) |
| hp->type = T_DISABLED; |
| } |
| |
| static void |
| push_macro_expansion (pfile, xbuf, xbuf_len, hp) |
| cpp_reader *pfile; |
| register U_CHAR *xbuf; |
| int xbuf_len; |
| HASHNODE *hp; |
| { |
| register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len); |
| if (mbuf == NULL) |
| return; |
| mbuf->cleanup = macro_cleanup; |
| mbuf->data = hp; |
| |
| /* The first chars of the expansion should be a "@ " added by |
| collect_expansion. This is to prevent accidental token-pasting |
| between the text preceding the macro invocation, and the macro |
| expansion text. |
| |
| We would like to avoid adding unneeded spaces (for the sake of |
| tools that use cpp, such as imake). In some common cases we can |
| tell that it is safe to omit the space. |
| |
| The character before the macro invocation cannot have been an |
| idchar (or else it would have been pasted with the idchars of |
| the macro name). Therefore, if the first non-space character |
| of the expansion is an idchar, we do not need the extra space |
| to prevent token pasting. |
| |
| Also, we don't need the extra space if the first char is '(', |
| or some other (less common) characters. */ |
| |
| if
|