Commit ba412f14 by Zack Weinberg Committed by Zack Weinberg

cpplib.h (CPP_ASSERTION, [...]): New token types.

	* 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.

From-SVN: r32274
parent 38769add
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> 2000-02-29 Mark Mitchell <mark@codesourcery.com>
* fold-const.c (size_binop): Don't asert inputs are the same and * fold-const.c (size_binop): Don't asert inputs are the same and
......
...@@ -81,6 +81,7 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, u ...@@ -81,6 +81,7 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, u
static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, unsigned HOST_WIDEST_INT)); 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_number PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
static struct operation parse_charconst 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)); static struct operation cpp_lex PARAMS ((cpp_reader *, int));
extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *)); 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)); static HOST_WIDEST_INT cpp_parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT));
...@@ -349,6 +350,53 @@ parse_charconst (pfile, start, end) ...@@ -349,6 +350,53 @@ parse_charconst (pfile, start, end)
return op; 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 { struct token {
const char *operator; const char *operator;
...@@ -389,7 +437,7 @@ cpp_lex (pfile, skip_evaluation) ...@@ -389,7 +437,7 @@ cpp_lex (pfile, skip_evaluation)
tok_end = CPP_PWRITTEN (pfile); tok_end = CPP_PWRITTEN (pfile);
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
switch (token) switch (token)
{ {
case CPP_EOF: /* Should not happen ... */ case CPP_EOF: /* Should not happen ... */
case CPP_VSPACE: case CPP_VSPACE:
op.op = 0; op.op = 0;
...@@ -407,51 +455,22 @@ cpp_lex (pfile, skip_evaluation) ...@@ -407,51 +455,22 @@ cpp_lex (pfile, skip_evaluation)
return parse_charconst (pfile, tok_start, tok_end); return parse_charconst (pfile, tok_start, tok_end);
case CPP_NAME: case CPP_NAME:
if (!strcmp (tok_start, "defined"))
return parse_defined (pfile);
op.op = INT; op.op = INT;
op.unsignedp = 0; op.unsignedp = 0;
op.value = 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) if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
goto oops; cpp_warning (pfile, "`%.*s' is not defined",
(int) (tok_end - tok_start), tok_start);
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--;
}
return op; return op;
oops: case CPP_ASSERTION:
CPP_SET_WRITTEN (pfile, old_written); op.op = INT;
pfile->no_macro_expand--; op.unsignedp = 0;
cpp_error (pfile, "`defined' without an identifier"); op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
return op; return op;
case CPP_OTHER: case CPP_OTHER:
...@@ -468,13 +487,6 @@ cpp_lex (pfile, skip_evaluation) ...@@ -468,13 +487,6 @@ cpp_lex (pfile, skip_evaluation)
op.op = toktab->token; op.op = toktab->token;
return op; 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 */ /* fall through */
default: default:
op.op = *tok_start; op.op = *tok_start;
......
...@@ -41,10 +41,9 @@ static enum cpp_token macarg PARAMS ((cpp_reader *, int)); ...@@ -41,10 +41,9 @@ static enum cpp_token macarg PARAMS ((cpp_reader *, int));
static struct tm *timestamp PARAMS ((cpp_reader *)); static struct tm *timestamp PARAMS ((cpp_reader *));
static void special_symbol PARAMS ((HASHNODE *, 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 CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N)) #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 /* The arglist structure is built by create_definition to tell
collect_expansion where the argument names begin. That collect_expansion where the argument names begin. That
...@@ -57,17 +56,23 @@ static void special_symbol PARAMS ((HASHNODE *, cpp_reader *)); ...@@ -57,17 +56,23 @@ static void special_symbol PARAMS ((HASHNODE *, cpp_reader *));
the current #define has been processed and entered into the the current #define has been processed and entered into the
hash table. */ hash table. */
struct arglist struct arg
{ {
struct arglist *next;
U_CHAR *name; U_CHAR *name;
int length; int len;
int argno; char rest_arg;
char rest_args; };
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. /* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length). `raw' points to the argument text as written (`raw_length' is its length).
...@@ -251,502 +256,470 @@ macro_cleanup (pbuf, pfile) ...@@ -251,502 +256,470 @@ macro_cleanup (pbuf, pfile)
} }
/* Read a replacement list for a macro with parameters. /* Read a replacement list for a macro, and build the DEFINITION
Build the DEFINITION structure. structure. ARGLIST specifies the formal parameters to look for in
Reads characters of text starting at BUF until END. the text of the definition. If ARGLIST is null, this is an
ARGLIST specifies the formal parameters to look for object-like macro; if it points to an empty arglist, this is a
in the text of the definition; NARGS is the number of args function-like macro with no arguments.
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) A good half of this is devoted to supporting -traditional.
and NAMELEN is its length in characters. Kill me now. */
Note that comments, backslash-newlines, and leading white space
have already been deleted from the argument. */
static DEFINITION * static DEFINITION *
collect_expansion (pfile, buf, limit, nargs, arglist) collect_expansion (pfile, arglist)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR *buf, *limit;
int nargs;
struct arglist *arglist; struct arglist *arglist;
{ {
DEFINITION *defn; DEFINITION *defn;
register U_CHAR *p, *lastp, *exp_p; struct reflist *pat = 0, *endpat = 0;
struct reflist *endpat = NULL; enum cpp_token token;
/* Pointer to first nonspace after last ## seen. */ long start, here, last;
U_CHAR *concat = 0; int i;
/* Pointer to first nonspace after last single-# seen. */ int argc;
U_CHAR *stringify = 0; size_t len;
int maxsize; struct arg *argv;
int expected_delimiter = '\0'; U_CHAR *tok, *exp;
enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
/* Scan thru the replacement list, ignoring comments and quoted
strings, picking up on the macro calls. It does a linear search if (arglist)
thru the arg list on every potential symbol. Profiling might say
that something smarter should happen. */
if (limit < buf)
{ {
cpp_ice (pfile, "limit < buf in collect_expansion"); argv = arglist->argv;
limit = buf; /* treat it like a null defn */ argc = arglist->argc;
} }
else
/* 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] == '#')
{ {
cpp_error (pfile, "`##' at start of macro definition"); argv = 0;
p += 2; argc = 0;
} }
/* Process the main body of the definition. */ last = start = CPP_WRITTEN (pfile);
while (p < limit) last -= 2; /* two extra chars for the leading escape */
for (;;)
{ {
int skipped_arg = 0; /* We use cpp_get_token because get_directive_token would
register U_CHAR c = *p++; 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; while (PEEKC () == '\r')
if (!CPP_TRADITIONAL (pfile))
{ {
switch (c) FORWARD (1);
{ CPP_BUMP_LINE (pfile);
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;
}
} }
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 case CPP_POP:
character constants, and ignore special properties of #. case CPP_EOF:
Arguments inside strings are considered "stringified", but no case CPP_VSPACE:
extra quote marks are supplied. */ cpp_ice (pfile, "EOF or VSPACE in collect_expansion");
switch (c) goto done;
{
case '\'': case CPP_HSPACE:
case '\"': if (last_token == STRIZE || last_token == PASTE
if (expected_delimiter != '\0') || last_token == START)
{ CPP_SET_WRITTEN (pfile, here);
if (c == expected_delimiter) break;
expected_delimiter = '\0';
}
else
expected_delimiter = c;
break;
case '\\': case CPP_STRINGIZE:
/* Backslash quotes delimiters and itself, if (last_token == PASTE)
but not macro args. */ /* Not really a stringifier. */
if (expected_delimiter != 0 && p < limit goto norm;
&& (*p == expected_delimiter || *p == '\\')) last_token = STRIZE;
{ CPP_SET_WRITTEN (pfile, here); /* delete from replacement text */
*exp_p++ = *p++; break;
continue;
}
break;
case '/': case CPP_TOKPASTE:
if (expected_delimiter != '\0') /* If the last token was an argument, discard this token and
/* No comments inside strings. */ any hspace between it and the argument's position. Then
break; mark the arg raw_after. */
if (*p == '*') if (last_token == ARG)
{ {
/* If we find a comment that wasn't removed by endpat->raw_after = 1;
handle_directive, this must be -traditional. last_token = PASTE;
So replace the comment with nothing at all. */ CPP_SET_WRITTEN (pfile, last);
exp_p--;
p += 1;
while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
p++;
}
break; 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. */ case CPP_COMMENT:
if (is_idchar(c) && nargs > 0) /* We must be in -traditional mode. Pretend this was a
{ token paste, but only if there was no leading or
U_CHAR *id_beg = p - 1; trailing space. */
int id_len; 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; case CPP_STRING:
while (p != limit && is_idchar(*p)) case CPP_CHAR:
p++; if (last_token == STRIZE)
id_len = p - id_beg; cpp_error (pfile, "`#' is not followed by a macro argument name");
if (is_idstart(c) if (CPP_TRADITIONAL (pfile) || CPP_OPTIONS (pfile)->warn_stringify)
&& !(id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) goto maybe_trad_stringify;
{ else
register struct arglist *arg; 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) addref:
{ {
struct reflist *tpat; 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 maybe_trad_stringify:
&& arg->length == id_len {
&& strncmp (arg->name, id_beg, id_len) == 0) U_CHAR *base, *p, *limit;
{ struct reflist *tpat;
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. */ base = p = pfile->token_buffer + here;
if (!skipped_arg) limit = CPP_PWRITTEN (pfile);
{
register U_CHAR *lim1 = p; while (++p < limit)
p = id_beg; {
while (p != lim1) if (is_idstart (*p))
*exp_p++ = *p++; continue;
if (stringify == id_beg) for (i = 0; i < argc; i++)
cpp_error (pfile, if (!strncmp (tok, argv[i].name, argv[i].len)
"`#' operator should be followed by a macro argument name"); && ! 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);
} }
else
if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0)
{ {
/* If ANSI, put in a "\r " marker to prevent token pasting. defn->nargs = -1;
But not if "inside a string" (which in ANSI mode defn->argnames = 0;
happens only for -D option). */ defn->rest_args = 0;
*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; return defn;
} }
/* static struct arglist *
* special extension string that can be added to the last macro argument to collect_formal_parameters (pfile)
* 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;
cpp_reader *pfile; cpp_reader *pfile;
{ {
U_CHAR *bp; /* temp ptr into input buffer */ struct arglist *result = 0;
U_CHAR *symname; /* remember where symbol name starts */ struct arg *argv = 0;
int sym_length; /* and how long it is */ U_CHAR *namebuf = xstrdup ("");
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;
while (is_hspace(*bp)) U_CHAR *name, *tok;
bp++; 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); argv = (struct arg *) xmalloc (sizeof (struct arg));
bp += sym_length; 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 case CPP_COMMA:
across lines using backslash. This is not the right place to take argc++;
care of that. */ argv = xrealloc (argv, (argc + 1)*sizeof(struct arg));
argv[argc].len = 0;
break;
if (*bp == '(') case CPP_RPAREN:
{ goto done;
struct arglist *arg_ptrs = NULL;
int argno = 0;
bp++; /* skip '(' */ case CPP_3DOTS:
SKIP_WHITE_SPACE (bp); goto rest_arg;
/* Loop over macro argument names. */ case CPP_VSPACE:
while (*bp != ')') cpp_error (pfile, "missing right paren in macro argument list");
{ goto invalid;
struct arglist *temp;
temp = (struct arglist *) alloca (sizeof (struct arglist)); default:
temp->name = bp; cpp_error (pfile, "syntax error in #define");
temp->next = arg_ptrs; goto invalid;
temp->argno = argno++; }
temp->rest_args = 0; }
arg_ptrs = temp;
if (rest_args) rest_arg:
cpp_pedwarn (pfile, "another parameter follows `%s'", /* There are two possible styles for a vararg macro:
rest_extension); 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)) len = sizeof "__VA_ARGS__" - 1;
cpp_pedwarn (pfile, "invalid character in macro parameter name"); namebuf = xrealloc (namebuf, argslen + len + 1);
name = &namebuf[argslen - 1];
argslen += len;
memcpy (name, "__VA_ARGS__", len);
/* Find the end of the arg name. */ argslen += len + 1;
while (is_idchar(*bp)) argv[argc].len = len;
{ }
bp++; else
/* do we have a "special" rest-args extension here? */ if (CPP_PEDANTIC (pfile))
if ((size_t) (limit - bp) > REST_EXTENSION_LENGTH cpp_pedwarn (pfile, "ISO C does not permit named varargs macros");
&& !strncmp (rest_extension, bp, REST_EXTENSION_LENGTH))
{ argv[argc].rest_arg = 1;
rest_args = 1; namebuf = xrealloc (namebuf, argslen + 3);
temp->rest_args = 1; memcpy (&namebuf[argslen - 1], "...", 4);
break; argslen += 3;
}
} token = get_directive_token (pfile);
temp->length = bp - temp->name; if (token != CPP_RPAREN)
if (rest_args == 1) {
bp += REST_EXTENSION_LENGTH; cpp_error (pfile, "another parameter follows `...'");
arglengths += temp->length + 2; goto invalid;
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) done:
if (temp->length == otemp->length /* Go through argv and fix up the pointers. */
&& strncmp (temp->name, otemp->name, temp->length) == 0) len = 0;
{ for (i = 0; i <= argc; i++)
U_CHAR *name; {
argv[i].name = namebuf + len;
name = (U_CHAR *) alloca (temp->length + 1); len += argv[i].len + 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 */ CPP_SET_WRITTEN (pfile, old_written);
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->argnames to the result of concatenating result = (struct arglist *) xmalloc (sizeof (struct arglist));
the argument names in reverse order if (namebuf[0] != '\0')
with comma-space between them. */ {
defn->argnames = (U_CHAR *) xmalloc (arglengths + 1); result->namebuf = namebuf;
{ result->argc = argc + 1;
struct arglist *temp; result->argv = argv;
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;
}
} }
else else
{ {
/* Simple expansion or empty definition. */ free (namebuf);
result->namebuf = 0;
result->argc = 0;
result->argv = 0;
}
if (bp < limit) return result;
{
if (is_hspace(*bp)) invalid:
{ if (argv)
bp++; free (argv);
SKIP_WHITE_SPACE (bp); if (namebuf)
} free (namebuf);
else return 0;
/* Per C9x, missing white space after the name in a #define }
of an object-like macro is always a constraint violation. */
cpp_pedwarn (pfile, /* Create a DEFINITION node for a macro. The reader's point is just
"missing white space after `#define %.*s'", after the macro name. If FUNLIKE is true, this is a function-like
sym_length, symname); macro. */
}
/* now everything from bp before limit is the definition. */ DEFINITION *
defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); create_definition (pfile, funlike)
defn->argnames = (U_CHAR *) ""; 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->line = line;
defn->file = file; defn->file = file;
defn->col = col;
mdef.defn = defn; pfile->no_macro_expand--;
mdef.symnam = symname; pfile->parsing_define_directive--;
mdef.symlen = sym_length; CPP_OPTIONS (pfile)->discard_comments--;
return defn;
return mdef;
nope: err:
mdef.defn = 0; pfile->no_macro_expand--;
return mdef; pfile->parsing_define_directive--;
CPP_OPTIONS (pfile)->discard_comments--;
return 0;
} }
/* /*
...@@ -987,7 +960,7 @@ macroexpand (pfile, hp) ...@@ -987,7 +960,7 @@ macroexpand (pfile, hp)
xbuf_len = CPP_WRITTEN (pfile) - old_written; xbuf_len = CPP_WRITTEN (pfile) - old_written;
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
CPP_SET_WRITTEN (pfile, old_written); 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); push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1; CPP_BUFFER (pfile)->has_escapes = 1;
return; return;
...@@ -1244,8 +1217,10 @@ macroexpand (pfile, hp) ...@@ -1244,8 +1217,10 @@ macroexpand (pfile, hp)
int count_before = totlen; int count_before = totlen;
/* Add chars to XBUF. */ /* Add chars to XBUF. */
for (i = 0; i < ap->nchars; i++, offset++) i = ap->nchars;
xbuf[totlen++] = exp[offset]; memcpy (&xbuf[totlen], &exp[offset], i);
totlen += i;
offset += i;
/* If followed by an empty rest arg with concatenation, /* If followed by an empty rest arg with concatenation,
delete the last run of nonwhite chars. */ delete the last run of nonwhite chars. */
...@@ -1265,8 +1240,8 @@ macroexpand (pfile, hp) ...@@ -1265,8 +1240,8 @@ macroexpand (pfile, hp)
if (ap->stringify != 0) if (ap->stringify != 0)
{ {
bcopy (ARG_BASE + arg->stringified, memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
xbuf + totlen, arg->stringified_length); arg->stringified_length);
totlen += arg->stringified_length; totlen += arg->stringified_length;
} }
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile)) else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
...@@ -1314,7 +1289,7 @@ macroexpand (pfile, hp) ...@@ -1314,7 +1289,7 @@ macroexpand (pfile, hp)
if (p1[0] == '\r' && p1[1] == '-') if (p1[0] == '\r' && p1[1] == '-')
p1 += 2; p1 += 2;
bcopy (p1, xbuf + totlen, l1 - p1); memcpy (xbuf + totlen, p1, l1 - p1);
totlen += l1 - p1; totlen += l1 - p1;
} }
else else
...@@ -1328,7 +1303,7 @@ macroexpand (pfile, hp) ...@@ -1328,7 +1303,7 @@ macroexpand (pfile, hp)
xbuf[totlen++] = ' '; xbuf[totlen++] = ' ';
} }
bcopy (expanded, xbuf + totlen, arg->expand_length); memcpy (xbuf + totlen, expanded, arg->expand_length);
totlen += arg->expand_length; totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length if (!ap->raw_after && totlen > 0 && offset < defn->length
...@@ -1493,6 +1468,7 @@ compare_defs (pfile, d1, d2) ...@@ -1493,6 +1468,7 @@ compare_defs (pfile, d1, d2)
if (d1->nargs != d2->nargs) if (d1->nargs != d2->nargs)
return 1; return 1;
if (CPP_PEDANTIC (pfile) if (CPP_PEDANTIC (pfile)
&& d1->argnames && d2->argnames
&& strcmp ((char *) d1->argnames, (char *) d2->argnames)) && strcmp ((char *) d1->argnames, (char *) d2->argnames))
return 1; return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
......
...@@ -18,15 +18,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -18,15 +18,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef __GCC_CPPHASH__ #ifndef __GCC_CPPHASH__
#define __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 /* Structure allocated for every #define. For a simple replacement
such as such as
#define foo bar , #define foo bar ,
...@@ -48,30 +39,35 @@ struct macrodef ...@@ -48,30 +39,35 @@ struct macrodef
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
where (x, y) means (nchars, argno). */ 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; typedef struct definition DEFINITION;
struct definition { struct definition
{
int nargs; int nargs;
int length; /* length of expansion string */ int length; /* length of expansion string */
unsigned char *expansion; U_CHAR *expansion;
int line; /* Line number of definition */ int line; /* Line number of definition */
int col;
const char *file; /* File of definition */ const char *file; /* File of definition */
char rest_args; /* Nonzero if last arg. absorbs the rest */ char rest_args; /* Nonzero if last arg. absorbs the rest */
struct reflist { struct reflist *pattern;
struct reflist *next;
char stringify; /* nonzero if this arg was preceded by a /* Names of macro args, concatenated in order with commas between
# operator. */ them. The only use of this is that we warn on redefinition if
char raw_before; /* Nonzero if a ## operator before arg. */ this differs between the old and new definitions. */
char raw_after; /* Nonzero if a ## operator after arg. */ U_CHAR *argnames;
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;
}; };
/* different kinds of things that can appear in the value field /* different kinds of things that can appear in the value field
...@@ -102,8 +98,7 @@ extern HASHNODE *cpp_lookup PARAMS ((cpp_reader *, const U_CHAR *, int)); ...@@ -102,8 +98,7 @@ extern HASHNODE *cpp_lookup PARAMS ((cpp_reader *, const U_CHAR *, int));
extern void free_definition PARAMS ((DEFINITION *)); extern void free_definition PARAMS ((DEFINITION *));
extern void delete_macro PARAMS ((HASHNODE *)); extern void delete_macro PARAMS ((HASHNODE *));
extern MACRODEF create_definition PARAMS ((U_CHAR *, U_CHAR *, extern DEFINITION *create_definition PARAMS ((cpp_reader *, int));
cpp_reader *));
extern int compare_defs PARAMS ((cpp_reader *, DEFINITION *, extern int compare_defs PARAMS ((cpp_reader *, DEFINITION *,
DEFINITION *)); DEFINITION *));
extern void macroexpand PARAMS ((cpp_reader *, HASHNODE *)); extern void macroexpand PARAMS ((cpp_reader *, HASHNODE *));
......
...@@ -1256,9 +1256,6 @@ cpp_handle_option (pfile, argc, argv) ...@@ -1256,9 +1256,6 @@ cpp_handle_option (pfile, argc, argv)
opts->include_prefix_len = strlen (argv[i]); opts->include_prefix_len = strlen (argv[i]);
} }
} }
else if (!strcmp (argv[i], "-ifoutput"))
opts->output_conditionals = 1;
break; break;
case 'o': case 'o':
...@@ -1736,7 +1733,6 @@ Switches:\n\ ...@@ -1736,7 +1733,6 @@ Switches:\n\
-dD Preserve macro definitions in output\n\ -dD Preserve macro definitions in output\n\
-dN As -dD except that only the names are preserved\n\ -dN As -dD except that only the names are preserved\n\
-dI Include #include directives in the output\n\ -dI Include #include directives in the output\n\
-ifoutput Describe skipped code blocks in output \n\
-P Do not generate #line directives\n\ -P Do not generate #line directives\n\
-$ Do not allow '$' in identifiers\n\ -$ Do not allow '$' in identifiers\n\
-remap Remap file names when including files.\n\ -remap Remap file names when including files.\n\
......
...@@ -46,7 +46,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *)); ...@@ -46,7 +46,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
/* `struct directive' defines one #-directive, including how to handle it. */ /* `struct directive' defines one #-directive, including how to handle it. */
struct directive { struct directive
{
int length; /* Length of name */ int length; /* Length of name */
int (*func) /* Function to handle directive */ int (*func) /* Function to handle directive */
PARAMS ((cpp_reader *, const struct directive *)); PARAMS ((cpp_reader *, const struct directive *));
...@@ -93,7 +94,7 @@ static enum cpp_token null_underflow PARAMS ((cpp_reader *)); ...@@ -93,7 +94,7 @@ static enum cpp_token null_underflow PARAMS ((cpp_reader *));
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *)); static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
static int skip_comment PARAMS ((cpp_reader *, int)); static int skip_comment PARAMS ((cpp_reader *, int));
static int copy_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 skip_rest_of_line PARAMS ((cpp_reader *));
static void cpp_skip_hspace PARAMS ((cpp_reader *)); static void cpp_skip_hspace PARAMS ((cpp_reader *));
static int handle_directive PARAMS ((cpp_reader *)); static int handle_directive PARAMS ((cpp_reader *));
...@@ -108,6 +109,7 @@ static void skip_block_comment PARAMS ((cpp_reader *)); ...@@ -108,6 +109,7 @@ static void skip_block_comment PARAMS ((cpp_reader *));
static void skip_line_comment PARAMS ((cpp_reader *)); static void skip_line_comment PARAMS ((cpp_reader *));
static void parse_set_mark PARAMS ((cpp_reader *)); static void parse_set_mark PARAMS ((cpp_reader *));
static void parse_goto_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. /* Here is the actual list of #-directives.
This table is ordered by frequency of occurrence; the numbers This table is ordered by frequency of occurrence; the numbers
...@@ -410,10 +412,13 @@ copy_comment (pfile, m) ...@@ -410,10 +412,13 @@ copy_comment (pfile, m)
if (skip_comment (pfile, m) == m) if (skip_comment (pfile, m) == m)
return m; return m;
CPP_PUTC (pfile, m); limit = CPP_BUFFER (pfile)->cur;
for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++) CPP_RESERVE (pfile, limit - start + 2);
CPP_PUTC_Q (pfile, m);
for (; start <= limit; start++)
if (*start != '\r') if (*start != '\r')
CPP_PUTC (pfile, *start); CPP_PUTC_Q (pfile, *start);
return ' '; return ' ';
} }
...@@ -447,7 +452,7 @@ cpp_skip_hspace (pfile) ...@@ -447,7 +452,7 @@ cpp_skip_hspace (pfile)
break; break;
} }
else else
CPP_BUFFER (pfile)->lineno++; CPP_BUMP_LINE (pfile);
} }
else if (c == '/' || c == '-') else if (c == '/' || c == '-')
{ {
...@@ -461,11 +466,10 @@ cpp_skip_hspace (pfile) ...@@ -461,11 +466,10 @@ cpp_skip_hspace (pfile)
FORWARD(-1); FORWARD(-1);
} }
/* Read the rest of the current line. /* Read and discard the rest of the current line. */
The line is appended to PFILE's output buffer. */
static void static void
copy_rest_of_line (pfile) skip_rest_of_line (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
for (;;) for (;;)
...@@ -476,32 +480,21 @@ copy_rest_of_line (pfile) ...@@ -476,32 +480,21 @@ copy_rest_of_line (pfile)
case '\n': case '\n':
FORWARD(-1); FORWARD(-1);
case EOF: case EOF:
CPP_NUL_TERMINATE (pfile);
return; return;
case '\r': case '\r':
if (CPP_BUFFER (pfile)->has_escapes) if (! CPP_BUFFER (pfile)->has_escapes)
break; CPP_BUMP_LINE (pfile);
else break;
{
CPP_BUFFER (pfile)->lineno++;
continue;
}
case '\'': case '\'':
case '\"': case '\"':
parse_string (pfile, c); skip_string (pfile, c);
continue; break;
case '/': case '/':
if (PEEKC() == '*')
{
if (CPP_TRADITIONAL (pfile))
CPP_PUTS (pfile, "/**/", 4);
skip_block_comment (pfile);
continue;
}
/* else fall through */
case '-': case '-':
c = skip_comment (pfile, c); skip_comment (pfile, c);
break; break;
case '\f': case '\f':
...@@ -512,23 +505,9 @@ copy_rest_of_line (pfile) ...@@ -512,23 +505,9 @@ copy_rest_of_line (pfile)
break; 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. /* Handle a possible # directive.
'#' has already been read. */ '#' has already been read. */
...@@ -542,6 +521,12 @@ handle_directive (pfile) ...@@ -542,6 +521,12 @@ handle_directive (pfile)
U_CHAR *ident; U_CHAR *ident;
long old_written = CPP_WRITTEN (pfile); 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); cpp_skip_hspace (pfile);
c = PEEKC (); c = PEEKC ();
...@@ -629,71 +614,88 @@ pass_thru_directive (buf, len, pfile, keyword) ...@@ -629,71 +614,88 @@ pass_thru_directive (buf, len, pfile, keyword)
CPP_PUTS_Q (pfile, buf, len); 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 static int
check_macro_name (pfile, symname) get_macro_name (pfile)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *symname;
{ {
const U_CHAR *p; long here, len;
int sym_length;
here = CPP_WRITTEN (pfile);
for (p = symname; is_idchar(*p); p++) pfile->no_macro_expand++;
; if (get_directive_token (pfile) != CPP_NAME)
sym_length = p - symname; {
if (sym_length == 0 cpp_error (pfile, "`#define' must be followed by an identifier");
|| (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"'))) goto invalid;
cpp_error (pfile, "invalid macro name"); }
else if (!is_idstart(*symname)
|| (! strncmp (symname, "defined", 7) && sym_length == 7)) { len = CPP_WRITTEN (pfile) - here;
U_CHAR *msg; /* what pain... */ if (len == 7 && !strncmp (pfile->token_buffer + here, "defined", 7))
msg = (U_CHAR *) alloca (sym_length + 1); {
bcopy (symname, msg, sym_length); cpp_error (pfile, "`defined' is not a legal macro name");
msg[sym_length] = 0; goto invalid;
cpp_error (pfile, "invalid macro name `%s'", msg); }
}
return sym_length; pfile->no_macro_expand--;
return len;
invalid:
skip_rest_of_line (pfile);
pfile->no_macro_expand--;
return 0;
} }
/* Process a #define command. /* Process a #define command.
KEYWORD is the keyword-table entry for #define, KEYWORD is the keyword-table entry for #define,
or NULL for a "predefined" macro, or NULL for a "predefined" macro. */
or the keyword-table entry for #pragma in the case of a #pragma poison. */
static int static int
do_define (pfile, keyword) do_define (pfile, keyword)
cpp_reader *pfile; cpp_reader *pfile;
const struct directive *keyword; const struct directive *keyword;
{ {
MACRODEF mdef;
HASHNODE *hp; HASHNODE *hp;
DEFINITION *def;
long here; long here;
U_CHAR *macro, *buf, *end; int len, c;
int funlike = 0;
U_CHAR *sym;
here = CPP_WRITTEN (pfile); here = CPP_WRITTEN (pfile);
copy_rest_of_line (pfile); len = get_macro_name (pfile);
if (len == 0)
/* Copy out the line so we can pop the token buffer. */ return 0;
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);
/* 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); CPP_SET_WRITTEN (pfile, here);
mdef = create_definition (macro, end, pfile); /* If the next character, with no intervening whitespace, is '(',
if (mdef.defn == 0) 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; return 0;
if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL) if ((hp = cpp_lookup (pfile, sym, len)) != NULL)
{ {
int ok; int ok;
/* Redefining a macro is ok if the definitions are the same. */ /* Redefining a macro is ok if the definitions are the same. */
if (hp->type == T_MACRO) 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. */ /* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST || hp->type == T_STDC) else if (hp->type == T_CONST || hp->type == T_STDC)
ok = ! CPP_OPTIONS (pfile)->done_initializing; ok = ! CPP_OPTIONS (pfile)->done_initializing;
...@@ -704,14 +706,15 @@ do_define (pfile, keyword) ...@@ -704,14 +706,15 @@ do_define (pfile, keyword)
if (! ok) if (! ok)
{ {
if (hp->type == T_POISON) if (hp->type == T_POISON)
cpp_error (pfile, "redefining poisoned `%.*s'", cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
mdef.symlen, mdef.symnam);
else 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) 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"); "this is the location of the previous definition");
}
} }
if (hp->type != T_POISON) if (hp->type != T_POISON)
{ {
...@@ -719,19 +722,19 @@ do_define (pfile, keyword) ...@@ -719,19 +722,19 @@ do_define (pfile, keyword)
if (hp->type == T_MACRO) if (hp->type == T_MACRO)
free_definition (hp->value.defn); free_definition (hp->value.defn);
hp->type = T_MACRO; hp->type = T_MACRO;
hp->value.defn = mdef.defn; hp->value.defn = def;
} }
} }
else 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 (keyword != NULL && keyword->type == T_DEFINE)
{ {
if (CPP_OPTIONS (pfile)->debug_output if (CPP_OPTIONS (pfile)->debug_output
|| CPP_OPTIONS (pfile)->dump_macros == dump_definitions) || 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) 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; return 0;
...@@ -766,6 +769,7 @@ cpp_push_buffer (pfile, buffer, length) ...@@ -766,6 +769,7 @@ cpp_push_buffer (pfile, buffer, length)
new->alimit = new->rlimit = buffer + length; new->alimit = new->rlimit = buffer + length;
new->prev = buf; new->prev = buf;
new->mark = -1; new->mark = -1;
new->line_base = NULL;
CPP_BUFFER (pfile) = new; CPP_BUFFER (pfile) = new;
return new; return new;
...@@ -1309,7 +1313,7 @@ read_line_number (pfile, num) ...@@ -1309,7 +1313,7 @@ read_line_number (pfile, num)
} }
else 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"); cpp_error (pfile, "invalid format `#line' command");
return 0; return 0;
} }
...@@ -1467,15 +1471,14 @@ do_undef (pfile, keyword) ...@@ -1467,15 +1471,14 @@ do_undef (pfile, keyword)
len = limit - buf; len = limit - buf;
name = (U_CHAR *) alloca (len + 1); name = (U_CHAR *) alloca (len + 1);
memcpy (name, buf, len); memcpy (name, buf, len);
name[limit - buf] = '\0'; name[len] = '\0';
token = get_directive_token (pfile); token = get_directive_token (pfile);
if (token != CPP_VSPACE && token != CPP_POP) if (token != CPP_VSPACE)
{ {
cpp_pedwarn (pfile, "junk on line after #undef"); cpp_pedwarn (pfile, "junk on line after #undef");
skip_rest_of_line (pfile); skip_rest_of_line (pfile);
} }
CPP_SET_WRITTEN (pfile, here); CPP_SET_WRITTEN (pfile, here);
while ((hp = cpp_lookup (pfile, name, len)) != NULL) while ((hp = cpp_lookup (pfile, name, len)) != NULL)
...@@ -1950,11 +1953,9 @@ eval_if_expression (pfile) ...@@ -1950,11 +1953,9 @@ eval_if_expression (pfile)
HOST_WIDEST_INT value; HOST_WIDEST_INT value;
long old_written = CPP_WRITTEN (pfile); long old_written = CPP_WRITTEN (pfile);
/* Work around bug in cpp_get_token where it may mistake an pfile->parsing_if_directive++;
assertion for a directive. */
pfile->only_seen_white = 0;
value = cpp_parse_expr (pfile); value = cpp_parse_expr (pfile);
pfile->parsing_if_directive--;
skip_rest_of_line (pfile); skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* Pop */ CPP_SET_WRITTEN (pfile, old_written); /* Pop */
...@@ -2148,13 +2149,6 @@ skip_if_group (pfile) ...@@ -2148,13 +2149,6 @@ skip_if_group (pfile)
U_CHAR *beg_of_line; U_CHAR *beg_of_line;
long old_written; 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); old_written = CPP_WRITTEN (pfile);
for (;;) for (;;)
...@@ -2166,8 +2160,6 @@ skip_if_group (pfile) ...@@ -2166,8 +2160,6 @@ skip_if_group (pfile)
c = GETC(); c = GETC();
if (c == '\n') if (c == '\n')
{ {
if (CPP_OPTIONS (pfile)->output_conditionals)
CPP_PUTC (pfile, c);
CPP_BUMP_LINE (pfile); CPP_BUMP_LINE (pfile);
continue; continue;
} }
...@@ -2180,41 +2172,19 @@ skip_if_group (pfile) ...@@ -2180,41 +2172,19 @@ skip_if_group (pfile)
return; /* Caller will issue error. */ return; /* Caller will issue error. */
FORWARD(-1); FORWARD(-1);
if (CPP_OPTIONS (pfile)->output_conditionals) skip_rest_of_line (pfile);
{
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 */
}
c = GETC(); c = GETC();
if (c == EOF) if (c == EOF)
return; /* Caller will issue error. */ return; /* Caller will issue error. */
else else
{ CPP_BUMP_LINE (pfile);
/* \n */
if (CPP_OPTIONS (pfile)->output_conditionals)
{
CPP_PUTC (pfile, c);
pfile->lineno++;
}
CPP_BUMP_LINE (pfile);
}
} }
/* Back up to the beginning of this line. Caller will process the /* Back up to the beginning of this line. Caller will process the
directive. */ directive. */
CPP_BUFFER (pfile)->cur = beg_of_line; CPP_BUFFER (pfile)->cur = beg_of_line;
pfile->only_seen_white = 1; pfile->only_seen_white = 1;
if (CPP_OPTIONS (pfile)->output_conditionals)
{
CPP_PUTS (pfile, "#endfailed\n", 11);
pfile->lineno++;
}
} }
/* /*
...@@ -2443,6 +2413,27 @@ cpp_get_token (pfile) ...@@ -2443,6 +2413,27 @@ cpp_get_token (pfile)
} }
case '#': 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) if (!pfile->only_seen_white)
goto randomchar; goto randomchar;
/* -traditional directives are recognized only with the # in /* -traditional directives are recognized only with the # in
...@@ -2886,35 +2877,24 @@ parse_name (pfile, c) ...@@ -2886,35 +2877,24 @@ parse_name (pfile, c)
return; return;
} }
/* Parse a string starting with C. A single quoted string is treated /* Parse and skip over a string starting with C. A single quoted
like a double -- some programs (e.g., troff) are perverse this way. string is treated like a double -- some programs (e.g., troff) are
(However, a single quoted string is not allowed to extend over perverse this way. (However, a single quoted string is not allowed
multiple lines.) */ to extend over multiple lines.) */
static void static void
parse_string (pfile, c) skip_string (pfile, c)
cpp_reader *pfile; cpp_reader *pfile;
int c; int c;
{ {
long start_line, start_column; long start_line, start_column;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column); cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
CPP_PUTC (pfile, c);
while (1) while (1)
{ {
int cc = GETC(); int cc = GETC();
if (cc == EOF) switch (cc)
{ {
if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) case EOF:
{
/* 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;
}
cpp_error_with_line (pfile, start_line, start_column, cpp_error_with_line (pfile, start_line, start_column,
"unterminated string or character constant"); "unterminated string or character constant");
if (pfile->multiline_string_line != start_line if (pfile->multiline_string_line != start_line
...@@ -2923,22 +2903,20 @@ parse_string (pfile, c) ...@@ -2923,22 +2903,20 @@ parse_string (pfile, c)
pfile->multiline_string_line, -1, pfile->multiline_string_line, -1,
"possible real start of unterminated constant"); "possible real start of unterminated constant");
pfile->multiline_string_line = 0; pfile->multiline_string_line = 0;
break; return;
}
CPP_PUTC (pfile, cc);
switch (cc)
{
case '\n': case '\n':
CPP_BUMP_LINE (pfile); CPP_BUMP_LINE (pfile);
pfile->lineno++;
/* In Fortran and assembly language, silently terminate /* In Fortran and assembly language, silently terminate
strings of either variety at end of line. This is a strings of either variety at end of line. This is a
kludge around not knowing where comments are in these kludge around not knowing where comments are in these
languages. */ languages. */
if (CPP_OPTIONS (pfile)->lang_fortran if (CPP_OPTIONS (pfile)->lang_fortran
|| CPP_OPTIONS (pfile)->lang_asm) || CPP_OPTIONS (pfile)->lang_asm)
return; {
FORWARD(-1);
return;
}
/* Character constants may not extend over multiple lines. /* Character constants may not extend over multiple lines.
In Standard C, neither may strings. We accept multiline In Standard C, neither may strings. We accept multiline
strings as an extension. */ strings as an extension. */
...@@ -2946,6 +2924,7 @@ parse_string (pfile, c) ...@@ -2946,6 +2924,7 @@ parse_string (pfile, c)
{ {
cpp_error_with_line (pfile, start_line, start_column, cpp_error_with_line (pfile, start_line, start_column,
"unterminated character constant"); "unterminated character constant");
FORWARD(-1);
return; return;
} }
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0) if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
...@@ -2956,7 +2935,6 @@ parse_string (pfile, c) ...@@ -2956,7 +2935,6 @@ parse_string (pfile, c)
break; break;
case '\r': case '\r':
CPP_ADJUST_WRITTEN (pfile, -1);
if (CPP_BUFFER (pfile)->has_escapes) if (CPP_BUFFER (pfile)->has_escapes)
{ {
cpp_ice (pfile, "\\r escape inside string constant"); cpp_ice (pfile, "\\r escape inside string constant");
...@@ -2968,9 +2946,7 @@ parse_string (pfile, c) ...@@ -2968,9 +2946,7 @@ parse_string (pfile, c)
break; break;
case '\\': case '\\':
cc = GETC(); FORWARD(1);
if (cc != EOF)
CPP_PUTC (pfile, cc);
break; break;
case '\"': case '\"':
...@@ -2982,6 +2958,26 @@ parse_string (pfile, c) ...@@ -2982,6 +2958,26 @@ parse_string (pfile, c)
} }
} }
/* 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 /* Read an assertion into the token buffer, converting to
canonical form: `#predicate(a n swe r)' The next non-whitespace canonical form: `#predicate(a n swe r)' The next non-whitespace
character to read should be the first letter of the predicate. character to read should be the first letter of the predicate.
...@@ -3199,33 +3195,11 @@ cpp_unassert (pfile, str) ...@@ -3199,33 +3195,11 @@ cpp_unassert (pfile, str)
{ {
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL) if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
{ {
do_assert (pfile, NULL); do_unassert (pfile, NULL);
cpp_pop_buffer (pfile); 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 /* Remember the current position of PFILE so it may be returned to
after looking ahead a bit. after looking ahead a bit.
......
...@@ -47,14 +47,17 @@ enum cpp_token { ...@@ -47,14 +47,17 @@ enum cpp_token {
CPP_STRING, CPP_STRING,
CPP_WSTRING, CPP_WSTRING,
CPP_DIRECTIVE, CPP_DIRECTIVE,
CPP_LPAREN, /* "(" */ CPP_ASSERTION, /* #machine(a29k) */
CPP_RPAREN, /* ")" */ CPP_STRINGIZE, /* stringize macro argument */
CPP_LBRACE, /* "{" */ CPP_TOKPASTE, /* paste macro arg with next/prev token */
CPP_RBRACE, /* "}" */ CPP_LPAREN, /* "(" */
CPP_COMMA, /* "," */ CPP_RPAREN, /* ")" */
CPP_SEMICOLON,/* ";" */ CPP_LBRACE, /* "{" */
CPP_3DOTS, /* "..." */ CPP_RBRACE, /* "}" */
CPP_POP /* We're about to pop the buffer stack. */ 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 *)); typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
...@@ -193,7 +196,6 @@ struct cpp_reader ...@@ -193,7 +196,6 @@ struct cpp_reader
/* If non-zero, directives cause a hard error. Used when parsing /* If non-zero, directives cause a hard error. Used when parsing
macro arguments. */ macro arguments. */
char no_directives; char no_directives;
/* Print column number in error messages. */ /* Print column number in error messages. */
...@@ -205,6 +207,12 @@ struct cpp_reader ...@@ -205,6 +207,12 @@ struct cpp_reader
/* If true, character between '<' and '>' are a single (string) token. */ /* If true, character between '<' and '>' are a single (string) token. */
char parsing_include_directive; 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 /* True if escape sequences (as described for has_escapes in
parse_buffer) should be emitted. */ parse_buffer) should be emitted. */
char output_escapes; char output_escapes;
...@@ -217,7 +225,7 @@ struct cpp_reader ...@@ -217,7 +225,7 @@ struct cpp_reader
/* Nonzero means this file was included with a -imacros or -include /* Nonzero means this file was included with a -imacros or -include
command line and should not be recorded as an include file. */ command line and should not be recorded as an include file. */
int no_record_file; char no_record_file;
long lineno; long lineno;
...@@ -427,11 +435,6 @@ struct cpp_options { ...@@ -427,11 +435,6 @@ struct cpp_options {
char no_line_commands; char no_line_commands;
/* Nonzero means output the text in failing conditionals,
inside #failed ... #endfailed. */
char output_conditionals;
/* Nonzero means -I- has been seen, /* Nonzero means -I- has been seen,
so don't look for #include "foo" the source-file directory. */ so don't look for #include "foo" the source-file directory. */
char ignore_srcdir; char ignore_srcdir;
...@@ -689,14 +692,12 @@ extern int cpp_defined PARAMS ((cpp_reader *, const U_CHAR *, int)); ...@@ -689,14 +692,12 @@ extern int cpp_defined PARAMS ((cpp_reader *, const U_CHAR *, int));
extern void cpp_reader_init PARAMS ((cpp_reader *)); extern void cpp_reader_init PARAMS ((cpp_reader *));
extern void cpp_options_init PARAMS ((cpp_options *)); extern void cpp_options_init PARAMS ((cpp_options *));
extern int cpp_start_read PARAMS ((cpp_reader *, char *)); 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 cpp_finish PARAMS ((cpp_reader *));
extern void quote_string PARAMS ((cpp_reader *, const char *)); extern void quote_string PARAMS ((cpp_reader *, const char *));
extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, const U_CHAR *, extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, const U_CHAR *,
int)); int));
extern void cpp_scan_buffer PARAMS ((cpp_reader *)); 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. */ /* Last arg to output_line_command. */
enum file_change_code {same_file, rename_file, enter_file, leave_file}; enum file_change_code {same_file, rename_file, enter_file, leave_file};
......
/* { dg-do compile } */ /* { 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 NO_PAREN(rest...) rest
#define DEFINE_CATEGORY(category, items) \ #define DEFINE_CATEGORY(category, items) \
......
/* { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment