+2000-02-29 Zack Weinberg <zack@wolery.cumb.org>
+
+ * cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New
+ token types.
+ (struct cpp_reader): Add parsing_if_directive and
+ parsing_define_directive flags.
+ (struct cpp_options): Remove output_conditionals flag.
+ (check_macro_name): Delete prototype.
+
+ * cpphash.h (struct macrodef): Delete.
+ (struct reflist): Separate from struct definition.
+ (struct definition): Remove unused fields. Add column number.
+ (create_definition): Returns a DEFINITION *. Takes a
+ cpp_reader * and an int.
+
+ * cpphash.c (SKIP_WHITE_SPACE): Delete.
+ (PEEKC): Copy defn from cpplib.c.
+ (rest_extension, REST_EXTENSION_LENGTH): Delete.
+ (struct arg): New.
+ (struct arglist): Simplify.
+ (collect_expansion): Rewrite. Get tokens by calling
+ cpp_get_token. Add more error checking.
+ (collect_formal_parameters): New function, broken out of
+ create_definition and reworked to use get_directive_token.
+ (create_definition): All real work is now in collect_expansion
+ and collect_formal_parameters. do_define handles finding the
+ macro name. Return a DEFINITION, not a MACRODEF.
+ (macroexpand): Replace bcopy with memcpy throughout. Replace
+ character-at-a-time copy loop with memcpy and pointer increments.
+ (compare-defs): d1->argnames / d2->argnames might be null.
+
+ * cpplib.c (copy_rest_of_line): Delete function.
+ (skip_rest_of_line): Do all the work ourselves.
+ (skip_string): New function.
+ (parse_string): Use skip_string.
+ (get_macro_name): New function.
+ (check_macro_name): Delete.
+ (copy_comment): Use CPP_RESERVE and CPP_PUTC_Q.
+ (cpp_skip_hspace): Use CPP_BUMP_LINE.
+ (handle_directive): ICE if we're called on a macro buffer.
+ (do_define): Determine macro name and type (funlike/objlike)
+ here. Expunge all uses of MACRODEF.
+ (cpp_push_buffer): Set line_base to NULL.
+ (do_undef, read_line_number): Don't worry about getting a POP token.
+ (eval_if_expression): Set/reset parsing_if_directive around
+ cpp_parse_expr. Don't clear only_seen_white.
+ (skip_if_group): Remove output_conditionals logic. Use
+ skip_rest_of_line.
+ (cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE
+ tokens under appropriate conditions.
+ (cpp_unassert): Call do_unassert not do_assert. Oops.
+
+ * cppexp.c (parse_defined): New function, break out of
+ cpp_lex.
+ (cpp_lex): We now get CPP_ASSERTION tokens and can check them
+ ourselves, with cpp_defined.
+ * cppinit.c (cpp_handle_option, print_help): Delete -ifoutput.
+
+ * gcc.dg/20000209-2.c: Turn off -pedantic-errors.
+ * gcc.dg/strpaste-2.c: New.
+
2000-02-29 Mark Mitchell <mark@codesourcery.com>
* fold-const.c (size_binop): Don't asert inputs are the same and
static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, unsigned HOST_WIDEST_INT));
static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
+static struct operation parse_defined PARAMS ((cpp_reader *));
static struct operation cpp_lex PARAMS ((cpp_reader *, int));
extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
static HOST_WIDEST_INT cpp_parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT));
return op;
}
+static struct operation
+parse_defined (pfile)
+ cpp_reader *pfile;
+{
+ int paren = 0, len;
+ U_CHAR *tok;
+ enum cpp_token token;
+ struct operation op;
+ long old_written = CPP_WRITTEN (pfile);
+
+ op.unsignedp = 0;
+ op.op = INT;
+
+ pfile->no_macro_expand++;
+ token = get_directive_token (pfile);
+ if (token == CPP_LPAREN)
+ {
+ paren++;
+ CPP_SET_WRITTEN (pfile, old_written);
+ token = get_directive_token (pfile);
+ }
+
+ if (token != CPP_NAME)
+ goto oops;
+
+ tok = pfile->token_buffer + old_written;
+ len = CPP_PWRITTEN (pfile) - tok;
+ op.value = cpp_defined (pfile, tok, len);
+
+ if (paren)
+ {
+ if (get_directive_token (pfile) != CPP_RPAREN)
+ goto oops;
+ }
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->no_macro_expand--;
+ return op;
+
+ oops:
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->no_macro_expand--;
+ cpp_error (pfile, "`defined' without an identifier");
+
+ op.op = ERROR;
+ return op;
+}
+
struct token {
const char *operator;
tok_end = CPP_PWRITTEN (pfile);
CPP_SET_WRITTEN (pfile, old_written);
switch (token)
- {
+ {
case CPP_EOF: /* Should not happen ... */
case CPP_VSPACE:
op.op = 0;
return parse_charconst (pfile, tok_start, tok_end);
case CPP_NAME:
+ if (!strcmp (tok_start, "defined"))
+ return parse_defined (pfile);
+
op.op = INT;
op.unsignedp = 0;
op.value = 0;
- if (strcmp (tok_start, "defined"))
- {
- if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
- cpp_warning (pfile, "`%.*s' is not defined",
- (int) (tok_end - tok_start), tok_start);
- }
- else
- {
- int paren = 0, len;
- U_CHAR *tok;
-
- pfile->no_macro_expand++;
- token = get_directive_token (pfile);
- if (token == CPP_LPAREN)
- {
- paren++;
- CPP_SET_WRITTEN (pfile, old_written);
- token = get_directive_token (pfile);
- }
- if (token != CPP_NAME)
- goto oops;
-
- tok = pfile->token_buffer + old_written;
- len = CPP_PWRITTEN (pfile) - tok;
- if (cpp_defined (pfile, tok, len))
- op.value = 1;
-
- if (paren)
- {
- if (get_directive_token (pfile) != CPP_RPAREN)
- goto oops;
- }
- CPP_SET_WRITTEN (pfile, old_written);
- pfile->no_macro_expand--;
- }
+ if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
+ cpp_warning (pfile, "`%.*s' is not defined",
+ (int) (tok_end - tok_start), tok_start);
return op;
- oops:
- CPP_SET_WRITTEN (pfile, old_written);
- pfile->no_macro_expand--;
- cpp_error (pfile, "`defined' without an identifier");
+ case CPP_ASSERTION:
+ op.op = INT;
+ op.unsignedp = 0;
+ op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
return op;
case CPP_OTHER:
op.op = toktab->token;
return op;
}
- else if (tok_start + 1 == tok_end && *tok_start == '#')
- {
- CPP_FORWARD (CPP_BUFFER (pfile), -1);
- op.op = INT;
- op.value = cpp_read_check_assertion (pfile);
- return op;
- }
/* fall through */
default:
op.op = *tok_start;
static struct tm *timestamp PARAMS ((cpp_reader *));
static void special_symbol PARAMS ((HASHNODE *, cpp_reader *));
-
-#define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0)
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
+#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))
/* The arglist structure is built by create_definition to tell
collect_expansion where the argument names begin. That
the current #define has been processed and entered into the
hash table. */
-struct arglist
+struct arg
{
- struct arglist *next;
U_CHAR *name;
- int length;
- int argno;
- char rest_args;
+ int len;
+ char rest_arg;
+};
+
+struct arglist
+{
+ U_CHAR *namebuf;
+ struct arg *argv;
+ int argc;
};
-static DEFINITION *collect_expansion PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *,
- int, struct arglist *));
+
+static DEFINITION *collect_expansion PARAMS ((cpp_reader *, struct arglist *));
+static struct arglist *collect_formal_parameters PARAMS ((cpp_reader *));
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
}
-/* 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. */
+/* Read a replacement list for a macro, and build the DEFINITION
+ structure. ARGLIST specifies the formal parameters to look for in
+ the text of the definition. If ARGLIST is null, this is an
+ object-like macro; if it points to an empty arglist, this is a
+ function-like macro with no arguments.
+
+ A good half of this is devoted to supporting -traditional.
+ Kill me now. */
static DEFINITION *
-collect_expansion (pfile, buf, limit, nargs, arglist)
+collect_expansion (pfile, 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)
+ struct reflist *pat = 0, *endpat = 0;
+ enum cpp_token token;
+ long start, here, last;
+ int i;
+ int argc;
+ size_t len;
+ struct arg *argv;
+ U_CHAR *tok, *exp;
+ enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
+
+ if (arglist)
{
- cpp_ice (pfile, "limit < buf in collect_expansion");
- limit = buf; /* treat it like a null defn */
+ argv = arglist->argv;
+ argc = arglist->argc;
}
-
- /* 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 escape-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] == '#')
+ else
{
- cpp_error (pfile, "`##' at start of macro definition");
- p += 2;
+ argv = 0;
+ argc = 0;
}
- /* Process the main body of the definition. */
- while (p < limit)
+ last = start = CPP_WRITTEN (pfile);
+ last -= 2; /* two extra chars for the leading escape */
+ for (;;)
{
- int skipped_arg = 0;
- register U_CHAR c = *p++;
+ /* We use cpp_get_token because get_directive_token would
+ discard whitespace and we can't cope with that yet. Macro
+ expansion is off, so we are guaranteed not to see POP or EOF. */
- *exp_p++ = c;
-
- if (!CPP_TRADITIONAL (pfile))
+ while (PEEKC () == '\r')
{
- 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_hspace(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;
- }
+ FORWARD (1);
+ CPP_BUMP_LINE (pfile);
}
- else
+ if (PEEKC () == '\n')
+ goto done;
+ here = CPP_WRITTEN (pfile);
+ token = cpp_get_token (pfile);
+ tok = pfile->token_buffer + here;
+ switch (token)
{
- /* 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 CPP_POP:
+ case CPP_EOF:
+ case CPP_VSPACE:
+ cpp_ice (pfile, "EOF or VSPACE in collect_expansion");
+ goto done;
+
+ case CPP_HSPACE:
+ if (last_token == STRIZE || last_token == PASTE
+ || last_token == START)
+ CPP_SET_WRITTEN (pfile, here);
+ 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 CPP_STRINGIZE:
+ if (last_token == PASTE)
+ /* Not really a stringifier. */
+ goto norm;
+ last_token = STRIZE;
+ CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */
+ 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++;
- }
+ case CPP_TOKPASTE:
+ /* If the last token was an argument, discard this token and
+ any hspace between it and the argument's position. Then
+ mark the arg raw_after. */
+ if (last_token == ARG)
+ {
+ endpat->raw_after = 1;
+ last_token = PASTE;
+ CPP_SET_WRITTEN (pfile, last);
break;
}
- }
+ else if (last_token == PASTE)
+ /* ## ## - the second ## is ordinary. */
+ goto norm;
+
+ /* Discard the token and any hspace before it. */
+ while (is_hspace (pfile->token_buffer[here-1]))
+ here--;
+ CPP_SET_WRITTEN (pfile, here);
+
+ if (last_token == STRIZE)
+ /* Oops - that wasn't a stringify operator. */
+ CPP_PUTC (pfile, '#');
+ last_token = PASTE;
+ break;
- /* Handle the start of a symbol. */
- if (is_idchar(c) && nargs > 0)
- {
- U_CHAR *id_beg = p - 1;
- int id_len;
+ case CPP_COMMENT:
+ /* We must be in -traditional mode. Pretend this was a
+ token paste, but only if there was no leading or
+ trailing space. */
+ CPP_SET_WRITTEN (pfile, here);
+ if (is_hspace (pfile->token_buffer[here-1]))
+ break;
+ if (is_hspace (PEEKC ()))
+ break;
+ if (last_token == ARG)
+ endpat->raw_after = 1;
+ last_token = PASTE;
+ break;
- --exp_p;
- while (p != limit && is_idchar(*p))
- p++;
- id_len = p - id_beg;
+ case CPP_STRING:
+ case CPP_CHAR:
+ if (last_token == STRIZE)
+ cpp_error (pfile, "`#' is not followed by a macro argument name");
- if (is_idstart(c)
- && !(id_len == 1 && c == 'L' && (*p == '\'' || *p == '"')))
- {
- register struct arglist *arg;
+ if (CPP_TRADITIONAL (pfile) || CPP_OPTIONS (pfile)->warn_stringify)
+ goto maybe_trad_stringify;
+ else
+ goto norm;
+
+ case CPP_NAME:
+ for (i = 0; i < argc; i++)
+ if (!strncmp (tok, argv[i].name, argv[i].len)
+ && ! is_idchar (tok[argv[i].len]))
+ goto addref;
+
+ /* fall through */
+ default:
+ norm:
+ if (last_token == STRIZE)
+ cpp_error (pfile, "`#' is not followed by a macro argument name");
+ last_token = NORM;
+ break;
+ }
+ continue;
- for (arg = arglist; arg != NULL; arg = arg->next)
- {
- struct reflist *tpat;
+ addref:
+ {
+ struct reflist *tpat;
+
+ /* Make a pat node for this arg and add it to the pat list */
+ tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
+ tpat->next = NULL;
+ tpat->raw_before = (last_token == PASTE);
+ tpat->raw_after = 0;
+ tpat->stringify = (last_token == STRIZE);
+ tpat->rest_args = argv[i].rest_arg;
+ tpat->argno = i;
+ tpat->nchars = here - last;
+
+ if (endpat == NULL)
+ pat = tpat;
+ else
+ endpat->next = tpat;
+ endpat = tpat;
+ last = here;
+ }
+ CPP_SET_WRITTEN (pfile, here); /* discard arg name */
+ last_token = ARG;
+ continue;
- 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;
- }
- }
- }
+ maybe_trad_stringify:
+ {
+ U_CHAR *base, *p, *limit;
+ struct reflist *tpat;
- /* 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");
- }
+ base = p = pfile->token_buffer + here;
+ limit = CPP_PWRITTEN (pfile);
+
+ while (++p < limit)
+ {
+ if (is_idstart (*p))
+ continue;
+ for (i = 0; i < argc; i++)
+ if (!strncmp (tok, argv[i].name, argv[i].len)
+ && ! is_idchar (tok[argv[i].len]))
+ goto mts_addref;
+ continue;
+
+ mts_addref:
+ if (!CPP_TRADITIONAL (pfile))
+ {
+ /* Must have got here because of -Wtraditional. */
+ cpp_warning (pfile,
+ "macro argument `%.*s' would be stringified with -traditional",
+ (int) argv[i].len, argv[i].name);
+ continue;
+ }
+ if (CPP_OPTIONS (pfile)->warn_stringify)
+ cpp_warning (pfile, "macro argument `%.*s' is stringified",
+ (int) argv[i].len, argv[i].name);
+
+ /* Remove the argument from the string. */
+ memmove (p, p + argv[i].len, limit - (p + argv[i].len));
+ limit -= argv[i].len;
+
+ /* Make a pat node for this arg and add it to the pat list */
+ tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
+ tpat->next = NULL;
+
+ /* Don't attempt to paste this with anything. */
+ tpat->raw_before = 0;
+ tpat->raw_after = 0;
+ tpat->stringify = 1;
+ tpat->rest_args = argv[i].rest_arg;
+ tpat->argno = i;
+ tpat->nchars = (p - base) + here - last;
+
+ if (endpat == NULL)
+ pat = tpat;
+ else
+ endpat->next = tpat;
+ endpat = tpat;
+ last = (p - base) + here;
+ }
+ CPP_ADJUST_WRITTEN (pfile, CPP_PWRITTEN (pfile) - limit);
+ }
+ }
+ done:
+
+ if (last_token == STRIZE)
+ cpp_error (pfile, "`#' is not followed by a macro argument name");
+ else if (last_token == PASTE)
+ cpp_error (pfile, "`##' at end of macro definition");
+
+ CPP_NUL_TERMINATE (pfile);
+ len = CPP_WRITTEN (pfile) - start + 1;
+ exp = xmalloc (len + 4); /* space for no-concat markers at either end */
+ exp[0] = '\r';
+ exp[1] = ' ';
+ exp[len + 1] = '\r';
+ exp[len + 2] = ' ';
+ exp[len + 3] = '\0';
+ memcpy (&exp[2], pfile->token_buffer + start, len - 1);
+ CPP_SET_WRITTEN (pfile, start);
+
+ defn = (DEFINITION *) xmalloc (sizeof (DEFINITION));
+ defn->length = len + 3;
+ defn->expansion = exp;
+ defn->pattern = pat;
+ defn->rest_args = 0;
+ if (arglist)
+ {
+ defn->nargs = argc;
+ defn->argnames = arglist->namebuf;
+ if (argv)
+ {
+ defn->rest_args = argv[argc - 1].rest_arg;
+ free (argv);
}
+ free (arglist);
}
-
- if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0)
+ else
{
- /* 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++ = ' ';
+ defn->nargs = -1;
+ defn->argnames = 0;
+ defn->rest_args = 0;
}
-
- *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)
- U_CHAR *buf, *limit;
+static struct arglist *
+collect_formal_parameters (pfile)
cpp_reader *pfile;
{
- 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;
- const 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;
+ struct arglist *result = 0;
+ struct arg *argv = 0;
+ U_CHAR *namebuf = xstrdup ("");
- while (is_hspace(*bp))
- bp++;
+ U_CHAR *name, *tok;
+ size_t argslen = 1;
+ int len;
+ int argc = 0;
+ int i;
+ enum cpp_token token;
+ long old_written;
- symname = bp; /* remember where it starts */
+ old_written = CPP_WRITTEN (pfile);
+ token = get_directive_token (pfile);
+ if (token != CPP_LPAREN)
+ {
+ cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
+ token, CPP_LPAREN);
+ goto invalid;
+ }
- sym_length = check_macro_name (pfile, bp);
- bp += sym_length;
+ argv = (struct arg *) xmalloc (sizeof (struct arg));
+ argv[argc].len = 0;
+ argv[argc].rest_arg = 0;
+ for (;;)
+ {
+ CPP_SET_WRITTEN (pfile, old_written);
+ token = get_directive_token (pfile);
+ switch (token)
+ {
+ case CPP_NAME:
+ tok = pfile->token_buffer + old_written;
+ len = CPP_PWRITTEN (pfile) - tok;
+ if (namebuf
+ && (name = strstr (namebuf, tok))
+ && name[len] == ','
+ && (name == namebuf || name[-1] == ','))
+ {
+ cpp_error (pfile, "duplicate macro argument name `%s'", tok);
+ continue;
+ }
+ namebuf = xrealloc (namebuf, argslen + len + 1);
+ name = &namebuf[argslen - 1];
+ argslen += len + 1;
+
+ memcpy (name, tok, len);
+ name[len] = ',';
+ name[len+1] = '\0';
+ argv[argc].len = len;
+ argv[argc].rest_arg = 0;
+ break;
- /* 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. */
+ case CPP_COMMA:
+ argc++;
+ argv = xrealloc (argv, (argc + 1)*sizeof(struct arg));
+ argv[argc].len = 0;
+ break;
- if (*bp == '(')
- {
- struct arglist *arg_ptrs = NULL;
- int argno = 0;
+ case CPP_RPAREN:
+ goto done;
- bp++; /* skip '(' */
- SKIP_WHITE_SPACE (bp);
+ case CPP_3DOTS:
+ goto rest_arg;
- /* Loop over macro argument names. */
- while (*bp != ')')
- {
- struct arglist *temp;
+ case CPP_VSPACE:
+ cpp_error (pfile, "missing right paren in macro argument list");
+ goto invalid;
- temp = (struct arglist *) alloca (sizeof (struct arglist));
- temp->name = bp;
- temp->next = arg_ptrs;
- temp->argno = argno++;
- temp->rest_args = 0;
- arg_ptrs = temp;
+ default:
+ cpp_error (pfile, "syntax error in #define");
+ goto invalid;
+ }
+ }
- if (rest_args)
- cpp_pedwarn (pfile, "another parameter follows `%s'",
- rest_extension);
+ rest_arg:
+ /* There are two possible styles for a vararg macro:
+ the C99 way: #define foo(a, ...) a, __VA_ARGS__
+ the gnu way: #define foo(a, b...) a, b
+ The C99 way can be considered a special case of the gnu way.
+ There are also some constraints to worry about, but we'll handle
+ those elsewhere. */
+ if (argv[argc].len == 0)
+ {
+ if (CPP_PEDANTIC (pfile) && ! CPP_OPTIONS (pfile)->c99)
+ cpp_pedwarn (pfile, "C89 does not permit varargs macros");
- if (!is_idstart(*bp))
- cpp_pedwarn (pfile, "invalid character in macro parameter name");
+ len = sizeof "__VA_ARGS__" - 1;
+ namebuf = xrealloc (namebuf, argslen + len + 1);
+ name = &namebuf[argslen - 1];
+ argslen += len;
+ memcpy (name, "__VA_ARGS__", len);
- /* 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;
+ argslen += len + 1;
+ argv[argc].len = len;
+ }
+ else
+ if (CPP_PEDANTIC (pfile))
+ cpp_pedwarn (pfile, "ISO C does not permit named varargs macros");
+
+ argv[argc].rest_arg = 1;
+ namebuf = xrealloc (namebuf, argslen + 3);
+ memcpy (&namebuf[argslen - 1], "...", 4);
+ argslen += 3;
+
+ token = get_directive_token (pfile);
+ if (token != CPP_RPAREN)
+ {
+ cpp_error (pfile, "another parameter follows `...'");
+ goto invalid;
+ }
- 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;
- }
- }
- }
+ done:
+ /* Go through argv and fix up the pointers. */
+ len = 0;
+ for (i = 0; i <= argc; i++)
+ {
+ argv[i].name = namebuf + len;
+ len += argv[i].len + 1;
+ }
- ++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;
+ CPP_SET_WRITTEN (pfile, old_written);
- /* Now set defn->argnames to the result of concatenating
- the argument names in reverse order
- with comma-space between them. */
- defn->argnames = (U_CHAR *) xmalloc (arglengths + 1);
- {
- struct arglist *temp;
- int i = 0;
- for (temp = arg_ptrs; temp; temp = temp->next)
- {
- bcopy (temp->name, &defn->argnames[i], temp->length);
- i += temp->length;
- if (temp->next != 0)
- {
- defn->argnames[i++] = ',';
- defn->argnames[i++] = ' ';
- }
- }
- defn->argnames[i] = 0;
- }
+ result = (struct arglist *) xmalloc (sizeof (struct arglist));
+ if (namebuf[0] != '\0')
+ {
+ result->namebuf = namebuf;
+ result->argc = argc + 1;
+ result->argv = argv;
}
else
{
- /* Simple expansion or empty definition. */
+ free (namebuf);
+ result->namebuf = 0;
+ result->argc = 0;
+ result->argv = 0;
+ }
- if (bp < limit)
- {
- if (is_hspace(*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->argnames = (U_CHAR *) "";
+ return result;
+
+ invalid:
+ if (argv)
+ free (argv);
+ if (namebuf)
+ free (namebuf);
+ return 0;
+}
+
+/* Create a DEFINITION node for a macro. The reader's point is just
+ after the macro name. If FUNLIKE is true, this is a function-like
+ macro. */
+
+DEFINITION *
+create_definition (pfile, funlike)
+ cpp_reader *pfile;
+ int funlike;
+{
+ struct arglist *args = 0;
+ long line, col;
+ const char *file;
+ DEFINITION *defn;
+
+ cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
+ file = CPP_BUFFER (pfile)->nominal_fname;
+
+ pfile->no_macro_expand++;
+ pfile->parsing_define_directive++;
+ CPP_OPTIONS (pfile)->discard_comments++;
+
+ if (funlike)
+ {
+ args = collect_formal_parameters (pfile);
+ if (args == 0)
+ goto err;
}
+ defn = collect_expansion (pfile, args);
+ if (defn == 0)
+ goto err;
+
defn->line = line;
defn->file = file;
+ defn->col = col;
- mdef.defn = defn;
- mdef.symnam = symname;
- mdef.symlen = sym_length;
-
- return mdef;
+ pfile->no_macro_expand--;
+ pfile->parsing_define_directive--;
+ CPP_OPTIONS (pfile)->discard_comments--;
+ return defn;
-nope:
- mdef.defn = 0;
- return mdef;
+ err:
+ pfile->no_macro_expand--;
+ pfile->parsing_define_directive--;
+ CPP_OPTIONS (pfile)->discard_comments--;
+ return 0;
}
/*
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);
+ memcpy (xbuf, CPP_PWRITTEN (pfile), xbuf_len + 1);
push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1;
return;
int count_before = totlen;
/* Add chars to XBUF. */
- for (i = 0; i < ap->nchars; i++, offset++)
- xbuf[totlen++] = exp[offset];
+ i = ap->nchars;
+ memcpy (&xbuf[totlen], &exp[offset], i);
+ totlen += i;
+ offset += i;
/* If followed by an empty rest arg with concatenation,
delete the last run of nonwhite chars. */
if (ap->stringify != 0)
{
- bcopy (ARG_BASE + arg->stringified,
- xbuf + totlen, arg->stringified_length);
+ memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
+ arg->stringified_length);
totlen += arg->stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
if (p1[0] == '\r' && p1[1] == '-')
p1 += 2;
- bcopy (p1, xbuf + totlen, l1 - p1);
+ memcpy (xbuf + totlen, p1, l1 - p1);
totlen += l1 - p1;
}
else
xbuf[totlen++] = ' ';
}
- bcopy (expanded, xbuf + totlen, arg->expand_length);
+ memcpy (xbuf + totlen, expanded, arg->expand_length);
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
if (d1->nargs != d2->nargs)
return 1;
if (CPP_PEDANTIC (pfile)
+ && d1->argnames && d2->argnames
&& strcmp ((char *) d1->argnames, (char *) d2->argnames))
return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
#ifndef __GCC_CPPHASH__
#define __GCC_CPPHASH__
-/* Structure returned by create_definition */
-typedef struct macrodef MACRODEF;
-struct macrodef
-{
- struct definition *defn;
- const U_CHAR *symnam;
- int symlen;
-};
-
/* Structure allocated for every #define. For a simple replacement
such as
#define foo bar ,
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
where (x, y) means (nchars, argno). */
+struct reflist
+{
+ struct reflist *next;
+ char stringify; /* nonzero if this arg was preceded by a
+ # operator. */
+ char raw_before; /* Nonzero if a ## operator before arg. */
+ char raw_after; /* Nonzero if a ## operator after arg. */
+ char rest_args; /* Nonzero if this arg. absorbs the rest */
+ int nchars; /* Number of literal chars to copy before
+ this arg occurrence. */
+ int argno; /* Number of arg to substitute (origin-0) */
+};
+
typedef struct definition DEFINITION;
-struct definition {
+struct definition
+{
int nargs;
int length; /* length of expansion string */
- unsigned char *expansion;
+ U_CHAR *expansion;
int line; /* Line number of definition */
+ int col;
const char *file; /* File of definition */
char rest_args; /* Nonzero if last arg. absorbs the rest */
- struct reflist {
- struct reflist *next;
- char stringify; /* nonzero if this arg was preceded by a
- # operator. */
- char raw_before; /* Nonzero if a ## operator before arg. */
- char raw_after; /* Nonzero if a ## operator after arg. */
- char rest_args; /* Nonzero if this arg. absorbs the rest */
- int nchars; /* Number of literal chars to copy before
- this arg occurrence. */
- int argno; /* Number of arg to substitute (origin-0) */
- } *pattern;
- /* Names of macro args, concatenated in reverse order
- with comma-space between them.
- The only use of this is that we warn on redefinition
- if this differs between the old and new definitions. */
- unsigned char *argnames;
+ struct reflist *pattern;
+
+ /* Names of macro args, concatenated in order with commas between
+ them. The only use of this is that we warn on redefinition if
+ this differs between the old and new definitions. */
+ U_CHAR *argnames;
};
/* different kinds of things that can appear in the value field
extern void free_definition PARAMS ((DEFINITION *));
extern void delete_macro PARAMS ((HASHNODE *));
-extern MACRODEF create_definition PARAMS ((U_CHAR *, U_CHAR *,
- cpp_reader *));
+extern DEFINITION *create_definition PARAMS ((cpp_reader *, int));
extern int compare_defs PARAMS ((cpp_reader *, DEFINITION *,
DEFINITION *));
extern void macroexpand PARAMS ((cpp_reader *, HASHNODE *));
opts->include_prefix_len = strlen (argv[i]);
}
}
- else if (!strcmp (argv[i], "-ifoutput"))
- opts->output_conditionals = 1;
-
break;
case 'o':
-dD Preserve macro definitions in output\n\
-dN As -dD except that only the names are preserved\n\
-dI Include #include directives in the output\n\
- -ifoutput Describe skipped code blocks in output \n\
-P Do not generate #line directives\n\
-$ Do not allow '$' in identifiers\n\
-remap Remap file names when including files.\n\
/* `struct directive' defines one #-directive, including how to handle it. */
-struct directive {
+struct directive
+{
int length; /* Length of name */
int (*func) /* Function to handle directive */
PARAMS ((cpp_reader *, const struct directive *));
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
static int skip_comment PARAMS ((cpp_reader *, int));
static int copy_comment PARAMS ((cpp_reader *, int));
-static void copy_rest_of_line PARAMS ((cpp_reader *));
+static void skip_string PARAMS ((cpp_reader *, int));
static void skip_rest_of_line PARAMS ((cpp_reader *));
static void cpp_skip_hspace PARAMS ((cpp_reader *));
static int handle_directive PARAMS ((cpp_reader *));
static void skip_line_comment PARAMS ((cpp_reader *));
static void parse_set_mark PARAMS ((cpp_reader *));
static void parse_goto_mark PARAMS ((cpp_reader *));
+static int get_macro_name PARAMS ((cpp_reader *));
/* Here is the actual list of #-directives.
This table is ordered by frequency of occurrence; the numbers
if (skip_comment (pfile, m) == m)
return m;
- CPP_PUTC (pfile, m);
- for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++)
+ limit = CPP_BUFFER (pfile)->cur;
+ CPP_RESERVE (pfile, limit - start + 2);
+ CPP_PUTC_Q (pfile, m);
+ for (; start <= limit; start++)
if (*start != '\r')
- CPP_PUTC (pfile, *start);
+ CPP_PUTC_Q (pfile, *start);
+
return ' ';
}
break;
}
else
- CPP_BUFFER (pfile)->lineno++;
+ CPP_BUMP_LINE (pfile);
}
else if (c == '/' || c == '-')
{
FORWARD(-1);
}
-/* Read the rest of the current line.
- The line is appended to PFILE's output buffer. */
+/* Read and discard the rest of the current line. */
static void
-copy_rest_of_line (pfile)
+skip_rest_of_line (pfile)
cpp_reader *pfile;
{
for (;;)
case '\n':
FORWARD(-1);
case EOF:
- CPP_NUL_TERMINATE (pfile);
return;
case '\r':
- if (CPP_BUFFER (pfile)->has_escapes)
- break;
- else
- {
- CPP_BUFFER (pfile)->lineno++;
- continue;
- }
+ if (! CPP_BUFFER (pfile)->has_escapes)
+ CPP_BUMP_LINE (pfile);
+ break;
+
case '\'':
case '\"':
- parse_string (pfile, c);
- continue;
+ skip_string (pfile, c);
+ break;
+
case '/':
- if (PEEKC() == '*')
- {
- if (CPP_TRADITIONAL (pfile))
- CPP_PUTS (pfile, "/**/", 4);
- skip_block_comment (pfile);
- continue;
- }
- /* else fall through */
case '-':
- c = skip_comment (pfile, c);
+ skip_comment (pfile, c);
break;
case '\f':
break;
}
- CPP_PUTC (pfile, c);
}
}
-/* FIXME: It is almost definitely a performance win to make this do
- the scan itself. >75% of calls to copy_r_o_l are from here or
- skip_if_group, which means the common case is to copy stuff into the
- token_buffer only to discard it. */
-static 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. */
U_CHAR *ident;
long old_written = CPP_WRITTEN (pfile);
+ if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
+ {
+ cpp_ice (pfile, "handle_directive called on macro buffer");
+ return 0;
+ }
+
cpp_skip_hspace (pfile);
c = PEEKC ();
CPP_PUTS_Q (pfile, buf, len);
}
-/* Check a purported macro name SYMNAME, and yield its length. */
+/* Subroutine of do_define: determine the name of the macro to be
+ defined. */
-int
-check_macro_name (pfile, symname)
+static int
+get_macro_name (pfile)
cpp_reader *pfile;
- const U_CHAR *symname;
{
- const 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 macro name");
- else if (!is_idstart(*symname)
- || (! strncmp (symname, "defined", 7) && sym_length == 7)) {
- 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 macro name `%s'", msg);
- }
- return sym_length;
+ long here, len;
+
+ here = CPP_WRITTEN (pfile);
+ pfile->no_macro_expand++;
+ if (get_directive_token (pfile) != CPP_NAME)
+ {
+ cpp_error (pfile, "`#define' must be followed by an identifier");
+ goto invalid;
+ }
+
+ len = CPP_WRITTEN (pfile) - here;
+ if (len == 7 && !strncmp (pfile->token_buffer + here, "defined", 7))
+ {
+ cpp_error (pfile, "`defined' is not a legal macro name");
+ goto invalid;
+ }
+
+ pfile->no_macro_expand--;
+ return len;
+
+ invalid:
+ skip_rest_of_line (pfile);
+ pfile->no_macro_expand--;
+ return 0;
}
/* Process a #define command.
KEYWORD is the keyword-table entry for #define,
- or NULL for a "predefined" macro,
- or the keyword-table entry for #pragma in the case of a #pragma poison. */
+ or NULL for a "predefined" macro. */
static int
do_define (pfile, keyword)
cpp_reader *pfile;
const struct directive *keyword;
{
- MACRODEF mdef;
HASHNODE *hp;
+ DEFINITION *def;
long here;
- U_CHAR *macro, *buf, *end;
+ int len, c;
+ int funlike = 0;
+ U_CHAR *sym;
here = CPP_WRITTEN (pfile);
- copy_rest_of_line (pfile);
-
- /* Copy out the line so we can pop the token buffer. */
- buf = pfile->token_buffer + here;
- end = CPP_PWRITTEN (pfile);
- macro = (U_CHAR *) alloca (end - buf + 1);
- memcpy (macro, buf, end - buf + 1);
- end = macro + (end - buf);
+ len = get_macro_name (pfile);
+ if (len == 0)
+ return 0;
+ /* Copy out the name so we can pop the token buffer. */
+ len = CPP_WRITTEN (pfile) - here;
+ sym = (U_CHAR *) alloca (len + 1);
+ memcpy (sym, pfile->token_buffer + here, len);
+ sym[len] = '\0';
CPP_SET_WRITTEN (pfile, here);
- mdef = create_definition (macro, end, pfile);
- if (mdef.defn == 0)
+ /* If the next character, with no intervening whitespace, is '(',
+ then this is a function-like macro. */
+ c = PEEKC ();
+ if (c == '(')
+ funlike = 1;
+ else if (c != '\n' && !is_hspace (c))
+ /* Otherwise, C99 requires white space after the name. We treat it
+ as an object-like macro if this happens, with a warning. */
+ cpp_pedwarn (pfile, "missing white space after `#define %.*s'", len, sym);
+
+ def = create_definition (pfile, funlike);
+ if (def == 0)
return 0;
- if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL)
+ if ((hp = cpp_lookup (pfile, sym, len)) != NULL)
{
int ok;
/* Redefining a macro is ok if the definitions are the same. */
if (hp->type == T_MACRO)
- ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
+ ok = ! compare_defs (pfile, def, hp->value.defn);
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST || hp->type == T_STDC)
ok = ! CPP_OPTIONS (pfile)->done_initializing;
if (! ok)
{
if (hp->type == T_POISON)
- cpp_error (pfile, "redefining poisoned `%.*s'",
- mdef.symlen, mdef.symnam);
+ cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
else
- cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
+ cpp_pedwarn (pfile, "`%.*s' redefined", len, sym);
if (hp->type == T_MACRO && CPP_OPTIONS (pfile)->done_initializing)
- cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
- hp->value.defn->line, -1,
+ {
+ DEFINITION *d = hp->value.defn;
+ cpp_pedwarn_with_file_and_line (pfile, d->file, d->line, d->col,
"this is the location of the previous definition");
+ }
}
if (hp->type != T_POISON)
{
if (hp->type == T_MACRO)
free_definition (hp->value.defn);
hp->type = T_MACRO;
- hp->value.defn = mdef.defn;
+ hp->value.defn = def;
}
}
else
- cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO, (char *)mdef.defn);
+ cpp_install (pfile, sym, len, T_MACRO, (char *) def);
if (keyword != NULL && keyword->type == T_DEFINE)
{
if (CPP_OPTIONS (pfile)->debug_output
|| CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
- dump_definition (pfile, mdef.symnam, mdef.symlen, mdef.defn);
+ dump_definition (pfile, sym, len, def);
else if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
- pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword);
+ pass_thru_directive (sym, len, pfile, keyword);
}
return 0;
new->alimit = new->rlimit = buffer + length;
new->prev = buf;
new->mark = -1;
+ new->line_base = NULL;
CPP_BUFFER (pfile) = new;
return new;
}
else
{
- if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+ if (token != CPP_VSPACE && token != CPP_EOF)
cpp_error (pfile, "invalid format `#line' command");
return 0;
}
len = limit - buf;
name = (U_CHAR *) alloca (len + 1);
memcpy (name, buf, len);
- name[limit - buf] = '\0';
+ name[len] = '\0';
token = get_directive_token (pfile);
- if (token != CPP_VSPACE && token != CPP_POP)
+ if (token != CPP_VSPACE)
{
cpp_pedwarn (pfile, "junk on line after #undef");
skip_rest_of_line (pfile);
}
-
CPP_SET_WRITTEN (pfile, here);
while ((hp = cpp_lookup (pfile, name, len)) != NULL)
HOST_WIDEST_INT value;
long old_written = CPP_WRITTEN (pfile);
- /* Work around bug in cpp_get_token where it may mistake an
- assertion for a directive. */
- pfile->only_seen_white = 0;
-
+ pfile->parsing_if_directive++;
value = cpp_parse_expr (pfile);
+ pfile->parsing_if_directive--;
skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
U_CHAR *beg_of_line;
long old_written;
- if (CPP_OPTIONS (pfile)->output_conditionals)
- {
- CPP_PUTS (pfile, "#failed\n", 8);
- pfile->lineno++;
- output_line_command (pfile, same_file);
- }
-
old_written = CPP_WRITTEN (pfile);
for (;;)
c = GETC();
if (c == '\n')
{
- if (CPP_OPTIONS (pfile)->output_conditionals)
- CPP_PUTC (pfile, c);
CPP_BUMP_LINE (pfile);
continue;
}
return; /* Caller will issue error. */
FORWARD(-1);
- if (CPP_OPTIONS (pfile)->output_conditionals)
- {
- CPP_PUTS (pfile, beg_of_line, CPP_BUFFER (pfile)->cur - beg_of_line);
- copy_rest_of_line (pfile);
- }
- else
- {
- copy_rest_of_line (pfile);
- CPP_SET_WRITTEN (pfile, old_written); /* discard it */
- }
+ skip_rest_of_line (pfile);
c = GETC();
if (c == EOF)
return; /* Caller will issue error. */
else
- {
- /* \n */
- if (CPP_OPTIONS (pfile)->output_conditionals)
- {
- CPP_PUTC (pfile, c);
- pfile->lineno++;
- }
- CPP_BUMP_LINE (pfile);
- }
+ CPP_BUMP_LINE (pfile);
}
/* Back up to the beginning of this line. Caller will process the
directive. */
CPP_BUFFER (pfile)->cur = beg_of_line;
pfile->only_seen_white = 1;
- if (CPP_OPTIONS (pfile)->output_conditionals)
- {
- CPP_PUTS (pfile, "#endfailed\n", 11);
- pfile->lineno++;
- }
}
/*
}
case '#':
+ if (pfile->parsing_if_directive)
+ {
+ cpp_skip_hspace (pfile);
+ parse_assertion (pfile);
+ return CPP_ASSERTION;
+ }
+
+ if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
+ {
+ CPP_RESERVE (pfile, 3);
+ CPP_PUTC_Q (pfile, '#');
+ CPP_NUL_TERMINATE_Q (pfile);
+ if (PEEKC () != '#')
+ return CPP_STRINGIZE;
+
+ FORWARD (1);
+ CPP_PUTC_Q (pfile, '#');
+ CPP_NUL_TERMINATE_Q (pfile);
+ return CPP_TOKPASTE;
+ }
+
if (!pfile->only_seen_white)
goto randomchar;
/* -traditional directives are recognized only with the # in
return;
}
-/* Parse a string starting with C. A single quoted string is treated
- like a double -- some programs (e.g., troff) are perverse this way.
- (However, a single quoted string is not allowed to extend over
- multiple lines.) */
+/* Parse and skip over a string starting with C. A single quoted
+ string is treated like a double -- some programs (e.g., troff) are
+ perverse this way. (However, a single quoted string is not allowed
+ to extend over multiple lines.) */
static void
-parse_string (pfile, c)
+skip_string (pfile, c)
cpp_reader *pfile;
int c;
{
long start_line, start_column;
-
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
- CPP_PUTC (pfile, c);
while (1)
{
int cc = GETC();
- if (cc == EOF)
+ switch (cc)
{
- if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
- {
- /* try harder: this string crosses a macro expansion
- boundary. This can happen naturally if -traditional.
- Otherwise, only -D can make a macro with an unmatched
- quote. */
- cpp_pop_buffer (pfile);
- continue;
- }
-
+ case EOF:
cpp_error_with_line (pfile, start_line, start_column,
"unterminated string or character constant");
if (pfile->multiline_string_line != start_line
pfile->multiline_string_line, -1,
"possible real start of unterminated constant");
pfile->multiline_string_line = 0;
- break;
- }
- CPP_PUTC (pfile, cc);
- switch (cc)
- {
+ return;
+
case '\n':
CPP_BUMP_LINE (pfile);
- pfile->lineno++;
-
/* In Fortran and assembly language, silently terminate
strings of either variety at end of line. This is a
kludge around not knowing where comments are in these
languages. */
if (CPP_OPTIONS (pfile)->lang_fortran
|| CPP_OPTIONS (pfile)->lang_asm)
- return;
+ {
+ FORWARD(-1);
+ return;
+ }
/* Character constants may not extend over multiple lines.
In Standard C, neither may strings. We accept multiline
strings as an extension. */
{
cpp_error_with_line (pfile, start_line, start_column,
"unterminated character constant");
+ FORWARD(-1);
return;
}
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
break;
case '\r':
- CPP_ADJUST_WRITTEN (pfile, -1);
if (CPP_BUFFER (pfile)->has_escapes)
{
cpp_ice (pfile, "\\r escape inside string constant");
break;
case '\\':
- cc = GETC();
- if (cc != EOF)
- CPP_PUTC (pfile, cc);
+ FORWARD(1);
break;
case '\"':
}
}
+/* Parse a string and copy it to the output. */
+
+static void
+parse_string (pfile, c)
+ cpp_reader *pfile;
+ int c;
+{
+ U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */
+ U_CHAR *limit;
+
+ skip_string (pfile, c);
+
+ limit = CPP_BUFFER (pfile)->cur;
+ CPP_RESERVE (pfile, limit - start + 2);
+ CPP_PUTC_Q (pfile, c);
+ for (; start < limit; start++)
+ if (*start != '\r')
+ CPP_PUTC_Q (pfile, *start);
+}
+
/* Read an assertion into the token buffer, converting to
canonical form: `#predicate(a n swe r)' The next non-whitespace
character to read should be the first letter of the predicate.
{
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
{
- do_assert (pfile, NULL);
+ do_unassert (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
-int
-cpp_read_check_assertion (pfile)
- cpp_reader *pfile;
-{
- U_CHAR *name;
- int result;
- long written = CPP_WRITTEN (pfile);
-
- FORWARD (1); /* Skip '#' */
- cpp_skip_hspace (pfile);
- if (! parse_assertion (pfile))
- result = 0;
- else
- {
- name = pfile->token_buffer + written;
- result = cpp_defined (pfile, name, CPP_PWRITTEN (pfile) - name);
- }
-
- CPP_SET_WRITTEN (pfile, written);
- return result;
-}
-
/* Remember the current position of PFILE so it may be returned to
after looking ahead a bit.
CPP_STRING,
CPP_WSTRING,
CPP_DIRECTIVE,
- CPP_LPAREN, /* "(" */
- CPP_RPAREN, /* ")" */
- CPP_LBRACE, /* "{" */
- CPP_RBRACE, /* "}" */
- CPP_COMMA, /* "," */
- CPP_SEMICOLON,/* ";" */
- CPP_3DOTS, /* "..." */
- CPP_POP /* We're about to pop the buffer stack. */
+ CPP_ASSERTION, /* #machine(a29k) */
+ CPP_STRINGIZE, /* stringize macro argument */
+ CPP_TOKPASTE, /* paste macro arg with next/prev token */
+ CPP_LPAREN, /* "(" */
+ CPP_RPAREN, /* ")" */
+ CPP_LBRACE, /* "{" */
+ CPP_RBRACE, /* "}" */
+ CPP_COMMA, /* "," */
+ CPP_SEMICOLON, /* ";" */
+ CPP_3DOTS, /* "..." */
+ CPP_POP /* We're about to pop the buffer stack. */
};
typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
/* If non-zero, directives cause a hard error. Used when parsing
macro arguments. */
-
char no_directives;
/* Print column number in error messages. */
/* If true, character between '<' and '>' are a single (string) token. */
char parsing_include_directive;
+ /* If true, # introduces an assertion (see do_assert) */
+ char parsing_if_directive;
+
+ /* If true, # and ## are the STRINGIZE and TOKPASTE operators */
+ char parsing_define_directive;
+
/* True if escape sequences (as described for has_escapes in
parse_buffer) should be emitted. */
char output_escapes;
/* Nonzero means this file was included with a -imacros or -include
command line and should not be recorded as an include file. */
- int no_record_file;
+ char no_record_file;
long lineno;
char no_line_commands;
-/* Nonzero means output the text in failing conditionals,
- inside #failed ... #endfailed. */
-
- char output_conditionals;
-
/* Nonzero means -I- has been seen,
so don't look for #include "foo" the source-file directory. */
char ignore_srcdir;
extern void cpp_reader_init PARAMS ((cpp_reader *));
extern void cpp_options_init PARAMS ((cpp_options *));
extern int cpp_start_read PARAMS ((cpp_reader *, char *));
-extern int cpp_read_check_assertion PARAMS ((cpp_reader *));
extern void cpp_finish PARAMS ((cpp_reader *));
extern void quote_string PARAMS ((cpp_reader *, const char *));
extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, const U_CHAR *,
int));
extern void cpp_scan_buffer PARAMS ((cpp_reader *));
-extern int check_macro_name PARAMS ((cpp_reader *, const U_CHAR *));
/* Last arg to output_line_command. */
enum file_change_code {same_file, rename_file, enter_file, leave_file};
/* { dg-do compile } */
-/* Distilled from glibc sources. Tests preprocessor corner cases. */
+/* { dg-options "-Wall" } */
+/* Distilled from glibc sources. Tests preprocessor corner cases.
+ Since it uses rest args, we must turn off -pedantic-errors. */
#define NO_PAREN(rest...) rest
#define DEFINE_CATEGORY(category, items) \
--- /dev/null
+/* { dg-do run } */
+
+/* Test for odd corner cases in stringizing/pasting.
+ Taken more or less verbatim from C99 section 6.10.3.3. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+
+const char p[] = join(x, y);
+const char q[] = "x ## y";
+
+int
+main (void)
+{
+ if (strcmp (p, q))
+ abort ();
+ return 0;
+}