summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cpphash.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-10-16 06:09:09 +0000
committerobrien <obrien@FreeBSD.org>1999-10-16 06:09:09 +0000
commitcae8fa8120c70195f34a2456f18c4c848a2d3e0c (patch)
treef7d3a3ab9c32694206552e767626366f016f2062 /contrib/gcc/cpphash.c
parent84656b55b6e25e30322dc903a05de53706361d3d (diff)
downloadFreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.zip
FreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.tar.gz
Virgin import of the GCC 2.95.1 compilers
Diffstat (limited to 'contrib/gcc/cpphash.c')
-rw-r--r--contrib/gcc/cpphash.c1613
1 files changed, 1572 insertions, 41 deletions
diff --git a/contrib/gcc/cpphash.c b/contrib/gcc/cpphash.c
index 6aa9e9c..1d8a104 100644
--- a/contrib/gcc/cpphash.c
+++ b/contrib/gcc/cpphash.c
@@ -1,5 +1,5 @@
-/* Part of CPP library. (Macro hash table support.)
- Copyright (C) 1986, 87, 89, 92-95, 1996 Free Software Foundation, Inc.
+/* Part of CPP library. (Macro handling.)
+ Copyright (C) 1986, 87, 89, 92-95, 1996, 1998 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -24,11 +24,66 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config.h"
#include "system.h"
-#include "gansidecl.h"
#include "cpplib.h"
#include "cpphash.h"
+#undef abort
+
+static int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *,
+ int, int));
+static int change_newlines PARAMS ((U_CHAR *, int));
+static void push_macro_expansion PARAMS ((cpp_reader *,
+ U_CHAR *, int, HASHNODE *));
+static int unsafe_chars PARAMS ((int, int));
+
+#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
+#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
+#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
+
+extern char *version_string;
+
+/* The arglist structure is built by create_definition to tell
+ collect_expansion 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_expansion 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;
+};
+
+/* 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;
+};
-extern char *xmalloc PARAMS ((unsigned));
/* Return hash function on name. must be compatible with the one
computed a step at a time, elsewhere */
@@ -48,7 +103,7 @@ hashf (name, len, hashsize)
}
/* Find the most recent hash node for name "name" (ending with first
- non-identifier char) installed by install
+ non-identifier char) installed by cpp_install
If LEN is >= 0, it is the length of the name.
Otherwise, compute the length by scanning the entire name.
@@ -68,19 +123,20 @@ cpp_lookup (pfile, name, len, hash)
if (len < 0)
{
- for (bp = name; is_idchar[*bp]; bp++) ;
+ for (bp = name; is_idchar[*bp]; bp++);
len = bp - name;
}
if (hash < 0)
hash = hashf (name, len, HASHSIZE);
- bucket = hashtab[hash];
- while (bucket) {
- if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
- return bucket;
- bucket = bucket->next;
- }
+ bucket = pfile->hashtab[hash];
+ while (bucket)
+ {
+ if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
+ return bucket;
+ bucket = bucket->next;
+ }
return (HASHNODE *) 0;
}
@@ -132,9 +188,9 @@ delete_macro (hp)
}
/* Install a name in the main hash table, even if it is already there.
- name stops with first non alphanumeric, except leading '#'.
- caller must check against redefinition if that is desired.
- delete_macro () removes things installed by install () in fifo order.
+ Name stops with first non alphanumeric, except leading '#'.
+ Caller must check against redefinition if that is desired.
+ delete_macro () removes things installed by cpp_install () in fifo order.
this is important because of the `defined' special symbol used
in #if, and also if pushdef/popdef directives are ever implemented.
@@ -145,24 +201,25 @@ delete_macro (hp)
Otherwise, compute the hash code. */
HASHNODE *
-install (name, len, type, ivalue, value, hash)
+cpp_install (pfile, name, len, type, value, hash)
+ cpp_reader *pfile;
U_CHAR *name;
int len;
enum node_type type;
- int ivalue;
- char *value;
+ const char *value;
int hash;
{
register HASHNODE *hp;
register int i, bucket;
- register U_CHAR *p, *q;
+ register U_CHAR *p;
- if (len < 0) {
- p = name;
- while (is_idchar[*p])
- p++;
- len = p - name;
- }
+ if (len < 0)
+ {
+ p = name;
+ while (is_idchar[*p])
+ p++;
+ len = p - name;
+ }
if (hash < 0)
hash = hashf (name, len, HASHSIZE);
@@ -170,35 +227,1509 @@ install (name, len, type, ivalue, value, hash)
i = sizeof (HASHNODE) + len + 1;
hp = (HASHNODE *) xmalloc (i);
bucket = hash;
- hp->bucket_hdr = &hashtab[bucket];
- hp->next = hashtab[bucket];
- hashtab[bucket] = hp;
+ hp->bucket_hdr = &pfile->hashtab[bucket];
+ hp->next = pfile->hashtab[bucket];
+ pfile->hashtab[bucket] = hp;
hp->prev = NULL;
if (hp->next != NULL)
hp->next->prev = hp;
hp->type = type;
hp->length = len;
- if (hp->type == T_CONST)
- hp->value.ival = ivalue;
- else
- hp->value.cpval = value;
+ hp->value.cpval = value;
hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
- p = hp->name;
- q = name;
- for (i = 0; i < len; i++)
- *p++ = *q++;
+ bcopy (name, hp->name, len);
hp->name[len] = 0;
return hp;
}
-void
-cpp_hash_cleanup (pfile)
+static int
+macro_cleanup (pbuf, pfile)
+ cpp_buffer *pbuf;
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
+ 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;
+}
+
+
+/* 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)
+ {
+ cpp_fatal (pfile, "internal error: limit < buf in collect_expansion");
+ limit = buf; /* treat it like a null defn */
+ }
+
+ /* 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);
+ 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++ = '\r';
+ *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 '#':
+ /* # 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
+ 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;
+ 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 "\r " marker to prevent token pasting.
+ But not if "inside a string" (which in ANSI mode
+ happens only for -D option). */
+ *exp_p++ = '\r';
+ *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. */
+
+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, 0);
+ 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 ((size_t) (limit - bp) > REST_EXTENSION_LENGTH
+ && !strncmp (rest_extension, bp, REST_EXTENSION_LENGTH))
+ {
+ 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
+ /* Per C9x, missing white space after the name in a #define
+ of an object-like macro is always a constraint violation. */
+ cpp_pedwarn (pfile,
+ "missing white space after `#define %.*s'",
+ sym_length, symname);
+ }
+ /* 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;
+}
+
+/*
+ * 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;
+ 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++;
+ CPP_OPTIONS (pfile)->no_line_commands++;
+ 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;
+ CPP_OPTIONS (pfile)->no_line_commands--;
+ 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;
+{
+ const char *buf;
+ int len;
+ cpp_buffer *ip;
+
+ switch (hp->type)
+ {
+ case T_FILE:
+ case T_BASE_FILE:
+ {
+ ip = CPP_BUFFER (pfile);
+ if (hp->type == T_BASE_FILE)
+ {
+ while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile))
+ ip = CPP_PREV_BUFFER (ip);
+ }
+ else
+ {
+ ip = CPP_BUFFER (pfile);
+ while (!ip->nominal_fname && ip != CPP_NULL_BUFFER (pfile))
+ ip = CPP_PREV_BUFFER (ip);
+ }
+
+ buf = ip->nominal_fname;
+
+ if (!buf)
+ buf = "";
+ CPP_RESERVE (pfile, 3 + 4 * strlen (buf));
+ quote_string (pfile, buf);
+ return;
+ }
+
+ case T_INCLUDE_LEVEL:
+ {
+ int true_indepth = 0;
+ ip = CPP_BUFFER (pfile);
+ for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip))
+ if (ip->fname != NULL)
+ true_indepth++;
+
+ CPP_RESERVE (pfile, 10);
+ sprintf (CPP_PWRITTEN (pfile), "%d", true_indepth);
+ CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
+ return;
+ }
+
+ case T_VERSION:
+ len = strlen (version_string);
+ CPP_RESERVE (pfile, 3 + len);
+ CPP_PUTC_Q (pfile, '"');
+ CPP_PUTS_Q (pfile, version_string, len);
+ CPP_PUTC_Q (pfile, '"');
+ CPP_NUL_TERMINATE_Q (pfile);
+ return;
+
+ case T_CONST:
+ buf = hp->value.cpval;
+ if (!buf)
+ return;
+ if (*buf == '\0')
+ buf = "\r ";
+
+ len = strlen (buf);
+ CPP_RESERVE (pfile, len + 1);
+ CPP_PUTS_Q (pfile, buf, len);
+ CPP_NUL_TERMINATE_Q (pfile);
+ return;
+
+ case T_STDC:
+ CPP_RESERVE (pfile, 2);
+#ifdef STDC_0_IN_SYSTEM_HEADERS
+ ip = CPP_BUFFER (pfile);
+ while (!ip->nominal_fname && ip != CPP_NULL_BUFFER (pfile))
+ ip = CPP_PREV_BUFFER (ip);
+ if (ip->system_header_p
+ && !cpp_lookup (pfile, (U_CHAR *) "__STRICT_ANSI__", 15, -1))
+ CPP_PUTC_Q (pfile, '0');
+ else
+#endif
+ CPP_PUTC_Q (pfile, '1');
+ CPP_NUL_TERMINATE_Q (pfile);
+ return;
+
+ case T_SPECLINE:
+ {
+ long line;
+ cpp_buf_line_and_col (cpp_file_buffer (pfile), &line, NULL);
+
+ CPP_RESERVE (pfile, 10);
+ sprintf (CPP_PWRITTEN (pfile), "%ld", line);
+ CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
+ return;
+ }
+
+ case T_DATE:
+ case T_TIME:
+ {
+ struct tm *timebuf;
+
+ CPP_RESERVE (pfile, 20);
+ timebuf = timestamp (pfile);
+ if (hp->type == T_DATE)
+ sprintf (CPP_PWRITTEN (pfile), "\"%s %2d %4d\"",
+ monthnames[timebuf->tm_mon],
+ timebuf->tm_mday, timebuf->tm_year + 1900);
+ else
+ sprintf (CPP_PWRITTEN (pfile), "\"%02d:%02d:%02d\"",
+ timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
+
+ CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
+ return;
+ }
+
+ default:
+ cpp_fatal (pfile, "cpplib internal error: invalid special hash type");
+ return;
+ }
+}
+
+/* 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. */
+
+void
+macroexpand (pfile, hp)
+ cpp_reader *pfile;
+ HASHNODE *hp;
+{
+ int nargs;
+ DEFINITION *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;
- for (i = HASHSIZE; --i >= 0; )
+
+#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
+
+ cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
+
+ /* Check for and handle special symbols. */
+ if (hp->type != T_MACRO)
+ {
+ special_symbol (hp, pfile);
+ xbuf_len = CPP_WRITTEN (pfile) - old_written;
+ xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
+ CPP_SET_WRITTEN (pfile, old_written);
+ bcopy (CPP_PWRITTEN (pfile), xbuf, xbuf_len + 1);
+ push_macro_expansion (pfile, xbuf, xbuf_len, hp);
+ CPP_BUFFER (pfile)->has_escapes = 1;
+ return;
+ }
+
+ defn = hp->value.defn;
+ nargs = defn->nargs;
+ pfile->output_escapes++;
+
+ if (nargs >= 0)
+ {
+ enum cpp_token token = CPP_EOF;
+
+ 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 open-parenthesis before 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 if 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
+ a string or char token. */
+ if (is_space[c])
+ {
+ if (CPP_WRITTEN (pfile) > (unsigned) arg->stringified
+ && (CPP_PWRITTEN (pfile))[-1] == '\r')
+ {
+ /* "\r " 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 ((char *) 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++;
+ }
+ 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] == '\r')
+ l1--;
+ else if (l1[-1] == '-')
+ {
+ if (l1 != p1 + 1 && l1[-2] == '\r')
+ l1 -= 2;
+ else
+ break;
+ }
+ else
+ break;
+ }
+ }
+
+ /* Delete any no-reexpansion marker that precedes
+ an identifier at the beginning of the argument. */
+ if (p1[0] == '\r' && p1[1] == '-')
+ p1 += 2;
+
+ 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++] = '\r';
+ 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++] = '\r';
+ 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)
+ {
+ cpp_fatal (pfile, "internal_error: buffer overrun in macroexpand");
+ return;
+ }
+ }
+
+ /* 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;
+}
+
+/* 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;
+
+ 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':
+ letter:
+ /* 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;
+}
+
+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 "\r " 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 (xbuf[0] == '\r' && xbuf[1] == ' '
+ && (is_idchar[xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\''
+ || xbuf[2] == '\"'))
+ mbuf->cur += 2;
+
+ /* Likewise, avoid the extra space at the end of the macro expansion
+ if this is safe. We can do a better job here since we can know
+ what the next char will be. */
+ if (xbuf_len >= 3
+ && mbuf->rlimit[-2] == '\r'
+ && mbuf->rlimit[-1] == ' ')
+ {
+ int c1 = mbuf->rlimit[-3];
+ int c2 = CPP_BUF_PEEK (CPP_PREV_BUFFER (CPP_BUFFER (pfile)));
+ if (c2 == EOF || !unsafe_chars (c1, c2))
+ mbuf->rlimit -= 2;
+ }
+}
+
+/* Return zero if two DEFINITIONs are isomorphic. */
+
+int
+compare_defs (pfile, d1, d2)
+ cpp_reader *pfile;
+ 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 (CPP_PEDANTIC (pfile)
+ && 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;
+
+ return comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
+ p2, d2->length - (p2 - d2->expansion), 1);
+}
+
+/* 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)
{
- while (hashtab[i])
- delete_macro (hashtab[i]);
+ 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);
+}
+
+/* Dump the definition of macro MACRO on stdout. The format is suitable
+ to be read back in again. */
+
+void
+dump_definition (pfile, macro)
+ cpp_reader *pfile;
+ MACRODEF macro;
+{
+ DEFINITION *defn = macro.defn;
+
+ CPP_RESERVE (pfile, macro.symlen + sizeof "#define ");
+ CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1);
+ CPP_PUTS_Q (pfile, macro.symnam, macro.symlen);
+
+ if (defn->nargs == -1)
+ {
+ CPP_PUTC_Q (pfile, ' ');
+
+ /* The first and last two characters of a macro expansion are
+ always "\r "; this needs to be trimmed out.
+ So we need length-4 chars of space, plus one for the NUL. */
+ CPP_RESERVE (pfile, defn->length - 4 + 1);
+ CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4);
+ CPP_NUL_TERMINATE_Q (pfile);
+ }
+ else
+ {
+ struct reflist *r;
+ unsigned char *argnames = xstrdup (defn->args.argnames);
+ unsigned char **argv = alloca (defn->nargs * sizeof(char *));
+ int *argl = alloca (defn->nargs * sizeof(int));
+ unsigned char *x;
+ int i;
+
+ /* First extract the argument list. */
+ x = argnames;
+ i = defn->nargs;
+ while (i--)
+ {
+ argv[i] = x;
+ while (*x != ',' && *x != '\0') x++;
+ argl[i] = x - argv[i];
+ if (*x == ',')
+ {
+ *x = '\0';
+ x += 2; /* skip the space after the comma */
+ }
+ }
+
+ /* Now print out the argument list. */
+ CPP_PUTC_Q (pfile, '(');
+ for (i = 0; i < defn->nargs; i++)
+ {
+ CPP_RESERVE (pfile, argl[i] + 2);
+ CPP_PUTS_Q (pfile, argv[i], argl[i]);
+ if (i < defn->nargs-1)
+ CPP_PUTS_Q (pfile, ", ", 2);
+ }
+
+ if (defn->rest_args)
+ CPP_PUTS (pfile, "...) ", 5);
+ else
+ CPP_PUTS (pfile, ") ", 2);
+
+ /* Now the definition. */
+ x = defn->expansion;
+ for (r = defn->pattern; r; r = r->next)
+ {
+ i = r->nchars;
+ if (*x == '\r') x += 2, i -= 2;
+ /* i chars for macro text, plus the length of the macro
+ argument name, plus one for a stringify marker, plus two for
+ each concatenation marker. */
+ CPP_RESERVE (pfile,
+ i + argl[r->argno] + r->stringify
+ + (r->raw_before + r->raw_after) * 2);
+
+ if (i > 0) CPP_PUTS_Q (pfile, x, i);
+ if (r->raw_before)
+ CPP_PUTS_Q (pfile, "##", 2);
+ if (r->stringify)
+ CPP_PUTC_Q (pfile, '#');
+ CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
+ if (r->raw_after && !(r->next && r->next->nchars == 0
+ && r->next->raw_before))
+ CPP_PUTS_Q (pfile, "##", 2);
+
+ x += i;
+ }
+
+ i = defn->length - (x - defn->expansion) - 2;
+ if (*x == '\r') x += 2, i -= 2;
+ if (i > 0) CPP_PUTS (pfile, x, i);
+ CPP_NUL_TERMINATE (pfile);
}
}
OpenPOWER on IntegriCloud