c-lex.c (cb_def_pragma): Update.

* c-lex.c (cb_def_pragma): Update.
	(c_lex): Update, and skip padding.
	* cppexp.c (lex, parse_defined): Update, remove unused variable.
	* cpphash.h (struct toklist): Delete.
	(union utoken): New.
	(struct cpp_context): Update.
	(struct cpp_reader): New members eof, avoid_paste.
	(_cpp_temp_token): New.
	* cppinit.c (cpp_create_reader): Update.
	* cpplex.c (_cpp_temp_token): New.
	(_cpp_lex_direct): Add PREV_WHITE when parsing args.
	(cpp_output_token): Don't print leading whitespace.
	(cpp_output_line): Update.
	* cpplib.c (glue_header_name, parse_include, get__Pragma_string,
	do_include_common, do_line, do_ident, do_pragma,
	do_pragma_dependency, _cpp_do__Pragma, parse_answer,
	parse_assertion): Update.
	(get_token_no_padding): New.
	* cpplib.h (CPP_PADDING): New.
	(AVOID_LPASTE): Delete.
	(struct cpp_token): New union member source.
	(cpp_get_token): Update.
	* cppmacro.c (macro_arg): Convert to use pointers to const tokens.
	(builtin_macro, paste_all_tokens, paste_tokens, funlike_invocation_p,
	replace_args, quote_string, stringify_arg, parse_arg, next_context,
	enter_macro_context, expand_arg, _cpp_pop_context, cpp_scan_nooutput,
	_cpp_backup_tokens, _cpp_create_definition): Update.
	(push_arg_context): Delete.
	(padding_token, push_token_context, push_ptoken_context): New.
	(make_string_token, make_number_token): Update, rename.
	(cpp_get_token): Update to handle tokens as pointers to const,
	and insert padding appropriately.
	* cppmain.c (struct printer): New member prev.
	(check_multiline_token): Constify.
	(do_preprocessing, cb_line_change): Update.
	(scan_translation_unit): Update to handle spacing.
	* scan-decls.c (get_a_token): New.
	(skip_to_closing_brace, scan_decls): Update.
	* fix-header.c (read_scan_file): Update.

	* doc/cpp.texi: Update.

	* gcc.dg/cpp/macro10.c: New test.
	* gcc.dg/cpp/strify3.c: New test.
	* gcc.dg/cpp/spacing1.c: Add tests.
	* gcc.dg/cpp/19990703-1.c: Remove bogus test.
	* gcc.dg/cpp/20000625-2.c: Fudge to pass.

From-SVN: r45793
This commit is contained in:
Neil Booth 2001-09-24 22:53:12 +00:00 committed by Neil Booth
parent ad43d46f3a
commit 4ed5bcfb1e
19 changed files with 799 additions and 571 deletions

View File

@ -1,3 +1,47 @@
2001-09-24 Neil Booth <neil@daikokuya.demon.co.uk>
* c-lex.c (cb_def_pragma): Update.
(c_lex): Update, and skip padding.
* cppexp.c (lex, parse_defined): Update, remove unused variable.
* cpphash.h (struct toklist): Delete.
(union utoken): New.
(struct cpp_context): Update.
(struct cpp_reader): New members eof, avoid_paste.
(_cpp_temp_token): New.
* cppinit.c (cpp_create_reader): Update.
* cpplex.c (_cpp_temp_token): New.
(_cpp_lex_direct): Add PREV_WHITE when parsing args.
(cpp_output_token): Don't print leading whitespace.
(cpp_output_line): Update.
* cpplib.c (glue_header_name, parse_include, get__Pragma_string,
do_include_common, do_line, do_ident, do_pragma,
do_pragma_dependency, _cpp_do__Pragma, parse_answer,
parse_assertion): Update.
(get_token_no_padding): New.
* cpplib.h (CPP_PADDING): New.
(AVOID_LPASTE): Delete.
(struct cpp_token): New union member source.
(cpp_get_token): Update.
* cppmacro.c (macro_arg): Convert to use pointers to const tokens.
(builtin_macro, paste_all_tokens, paste_tokens, funlike_invocation_p,
replace_args, quote_string, stringify_arg, parse_arg, next_context,
enter_macro_context, expand_arg, _cpp_pop_context, cpp_scan_nooutput,
_cpp_backup_tokens, _cpp_create_definition): Update.
(push_arg_context): Delete.
(padding_token, push_token_context, push_ptoken_context): New.
(make_string_token, make_number_token): Update, rename.
(cpp_get_token): Update to handle tokens as pointers to const,
and insert padding appropriately.
* cppmain.c (struct printer): New member prev.
(check_multiline_token): Constify.
(do_preprocessing, cb_line_change): Update.
(scan_translation_unit): Update to handle spacing.
* scan-decls.c (get_a_token): New.
(skip_to_closing_brace, scan_decls): Update.
* fix-header.c (read_scan_file): Update.
* doc/cpp.texi: Update.
2001-09-24 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* c-aux-info.c (affix_data_type): Use ATTRIBUTE_MALLOC. Avoid

View File

@ -335,13 +335,13 @@ cb_def_pragma (pfile, line)
if (warn_unknown_pragmas > in_system_header)
{
const unsigned char *space, *name = 0;
cpp_token s;
const cpp_token *s;
cpp_get_token (pfile, &s);
space = cpp_token_as_text (pfile, &s);
cpp_get_token (pfile, &s);
if (s.type == CPP_NAME)
name = cpp_token_as_text (pfile, &s);
s = cpp_get_token (pfile);
space = cpp_token_as_text (pfile, s);
s = cpp_get_token (pfile);
if (s->type == CPP_NAME)
name = cpp_token_as_text (pfile, s);
lineno = SOURCE_LINE (map, line);
if (name)
@ -767,12 +767,13 @@ int
c_lex (value)
tree *value;
{
cpp_token tok;
enum cpp_ttype type;
const cpp_token *tok;
retry:
timevar_push (TV_CPP);
cpp_get_token (parse_in, &tok);
do
tok = cpp_get_token (parse_in);
while (tok->type == CPP_PADDING);
timevar_pop (TV_CPP);
/* The C++ front end does horrible things with the current line
@ -781,37 +782,36 @@ c_lex (value)
lineno = src_lineno;
*value = NULL_TREE;
type = tok.type;
switch (type)
switch (tok->type)
{
case CPP_OPEN_BRACE: indent_level++; break;
case CPP_CLOSE_BRACE: indent_level--; break;
/* Issue this error here, where we can get at tok.val.c. */
/* Issue this error here, where we can get at tok->val.c. */
case CPP_OTHER:
if (ISGRAPH (tok.val.c))
error ("stray '%c' in program", tok.val.c);
if (ISGRAPH (tok->val.c))
error ("stray '%c' in program", tok->val.c);
else
error ("stray '\\%o' in program", tok.val.c);
error ("stray '\\%o' in program", tok->val.c);
goto retry;
case CPP_NAME:
*value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok.val.node));
*value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node));
break;
case CPP_NUMBER:
*value = lex_number ((const char *)tok.val.str.text, tok.val.str.len);
*value = lex_number ((const char *)tok->val.str.text, tok->val.str.len);
break;
case CPP_CHAR:
case CPP_WCHAR:
*value = lex_charconst (&tok);
*value = lex_charconst (tok);
break;
case CPP_STRING:
case CPP_WSTRING:
*value = lex_string ((const char *)tok.val.str.text,
tok.val.str.len, tok.type == CPP_WSTRING);
*value = lex_string ((const char *)tok->val.str.text,
tok->val.str.len, tok->type == CPP_WSTRING);
break;
/* These tokens should not be visible outside cpplib. */
@ -823,7 +823,7 @@ c_lex (value)
default: break;
}
return type;
return tok->type;
}
#define ERROR(msgid) do { error(msgid); goto syntax_error; } while(0)

View File

@ -36,7 +36,7 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
unsigned HOST_WIDEST_INT));
static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_defined PARAMS ((cpp_reader *));
static struct op lex PARAMS ((cpp_reader *, int, cpp_token *));
static struct op lex PARAMS ((cpp_reader *, int));
static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
struct op
@ -217,44 +217,40 @@ parse_defined (pfile)
{
int paren = 0;
cpp_hashnode *node = 0;
cpp_token token;
const cpp_token *token;
struct op op;
/* Don't expand macros. */
pfile->state.prevent_expansion++;
cpp_get_token (pfile, &token);
if (token.type == CPP_OPEN_PAREN)
token = cpp_get_token (pfile);
if (token->type == CPP_OPEN_PAREN)
{
paren = 1;
cpp_get_token (pfile, &token);
token = cpp_get_token (pfile);
}
if (token.type == CPP_NAME)
if (token->type == CPP_NAME)
{
node = token.val.node;
if (paren)
node = token->val.node;
if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
{
cpp_get_token (pfile, &token);
if (token.type != CPP_CLOSE_PAREN)
{
cpp_error (pfile, "missing ')' after \"defined\"");
node = 0;
}
cpp_error (pfile, "missing ')' after \"defined\"");
node = 0;
}
}
else
{
cpp_error (pfile, "operator \"defined\" requires an identifier");
if (token.flags & NAMED_OP)
if (token->flags & NAMED_OP)
{
cpp_token op;
op.flags = 0;
op.type = token.type;
op.type = token->type;
cpp_error (pfile,
"(\"%s\" is an alternative token for \"%s\" in C++)",
cpp_token_as_text (pfile, &token),
cpp_token_as_text (pfile, token),
cpp_token_as_text (pfile, &op));
}
}
@ -282,14 +278,12 @@ parse_defined (pfile)
CPP_EOF, or the type of an operator token. */
static struct op
lex (pfile, skip_evaluation, token)
lex (pfile, skip_evaluation)
cpp_reader *pfile;
int skip_evaluation;
cpp_token *token;
{
struct op op;
cpp_get_token (pfile, token);
const cpp_token *token = cpp_get_token (pfile);
switch (token->type)
{
@ -578,7 +572,6 @@ _cpp_parse_expr (pfile)
struct op init_stack[INIT_STACK_SIZE];
struct op *stack = init_stack;
struct op *limit = stack + INIT_STACK_SIZE;
cpp_token token;
register struct op *top = stack + 1;
int skip_evaluation = 0;
int result;
@ -603,7 +596,7 @@ _cpp_parse_expr (pfile)
struct op op;
/* Read a token */
op = lex (pfile, skip_evaluation, &token);
op = lex (pfile, skip_evaluation);
lex_count++;
/* If the token is an operand, push its value and get next

View File

@ -95,11 +95,10 @@ struct search_path
/* #include types. */
enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
typedef struct toklist toklist;
struct toklist
union utoken
{
cpp_token *first;
cpp_token *limit;
const cpp_token *token;
const cpp_token **ptoken;
};
typedef struct tokenrun tokenrun;
@ -117,10 +116,14 @@ struct cpp_context
/* Contexts other than the base context are contiguous tokens.
e.g. macro expansions, expanded argument tokens. */
struct toklist list;
union utoken first;
union utoken last;
/* For a macro context, these are the macro and its arguments. */
cpp_macro *macro;
/* True if utoken element is token, else ptoken. */
bool direct_p;
};
struct lexer_state
@ -294,6 +297,10 @@ struct cpp_reader
cpp_token date;
cpp_token time;
/* EOF token, and a token forcing paste avoidance. */
cpp_token avoid_paste;
cpp_token eof;
/* Opaque handle to the dependencies of mkdeps.c. Used by -M etc. */
struct deps *deps;
@ -398,6 +405,7 @@ extern void _cpp_pop_file_buffer PARAMS ((cpp_reader *,
extern int _cpp_parse_expr PARAMS ((cpp_reader *));
/* In cpplex.c */
extern cpp_token *_cpp_temp_token PARAMS ((cpp_reader *));
extern const cpp_token *_cpp_lex_token PARAMS ((cpp_reader *));
extern cpp_token *_cpp_lex_direct PARAMS ((cpp_reader *));
extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,

View File

@ -510,8 +510,12 @@ cpp_create_reader (table, lang)
/* Initialize lexer state. */
pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
/* Indicate date and time not yet calculated. */
/* Set up static tokens. */
pfile->date.type = CPP_EOF;
pfile->avoid_paste.type = CPP_PADDING;
pfile->avoid_paste.val.source = NULL;
pfile->eof.type = CPP_EOF;
pfile->eof.flags = 0;
/* Create a token buffer for the lexer. */
_cpp_init_tokenrun (&pfile->base_run, 250);

View File

@ -931,6 +931,29 @@ next_tokenrun (run)
return run->next;
}
/* Allocate a single token that is invalidated at the same time as the
rest of the tokens on the line. Has its line and col set to the
same as the last lexed token, so that diagnostics appear in the
right place. */
cpp_token *
_cpp_temp_token (pfile)
cpp_reader *pfile;
{
cpp_token *old, *result;
old = pfile->cur_token - 1;
if (pfile->cur_token == pfile->cur_run->limit)
{
pfile->cur_run = next_tokenrun (pfile->cur_run);
pfile->cur_token = pfile->cur_run->base;
}
result = pfile->cur_token++;
result->line = old->line;
result->col = old->col;
return result;
}
/* Lex a token into RESULT (external interface). Takes care of issues
like directive handling, token lookahead, multiple include
opimisation and skipping. */
@ -1057,6 +1080,8 @@ _cpp_lex_direct (pfile)
buffer->saved_flags = BOL;
if (! pfile->state.in_directive)
{
if (pfile->state.parsing_args == 2)
buffer->saved_flags |= PREV_WHITE;
if (!pfile->keep_tokens)
{
pfile->cur_run = &pfile->base_run;
@ -1476,17 +1501,14 @@ cpp_type2name (type)
return (const char *) token_spellings[type].name;
}
/* Writes the spelling of token to FP. Separate from cpp_spell_token
for efficiency - to avoid double-buffering. Also, outputs a space
if PREV_WHITE is flagged. */
/* Writes the spelling of token to FP, without any preceding space.
Separated from cpp_spell_token for efficiency - to avoid stdio
double-buffering. */
void
cpp_output_token (token, fp)
const cpp_token *token;
FILE *fp;
{
if (token->flags & PREV_WHITE)
putc (' ', fp);
switch (TOKEN_SPELL (token))
{
case SPELL_OPERATOR:
@ -1729,20 +1751,22 @@ cpp_avoid_paste (pfile, token1, token2)
}
/* Output all the remaining tokens on the current line, and a newline
character, to FP. Leading whitespace is removed. */
character, to FP. Leading whitespace is removed. If there are
macros, special token padding is not performed. */
void
cpp_output_line (pfile, fp)
cpp_reader *pfile;
FILE *fp;
{
cpp_token token;
const cpp_token *token;
cpp_get_token (pfile, &token);
token.flags &= ~PREV_WHITE;
while (token.type != CPP_EOF)
token = cpp_get_token (pfile);
while (token->type != CPP_EOF)
{
cpp_output_token (&token, fp);
cpp_get_token (pfile, &token);
cpp_output_token (token, fp);
token = cpp_get_token (pfile);
if (token->flags & PREV_WHITE)
putc (' ', fp);
}
putc ('\n', fp);

View File

@ -86,8 +86,8 @@ static void directive_diagnostics
PARAMS ((cpp_reader *, const directive *, int));
static void run_directive PARAMS ((cpp_reader *, int,
const char *, size_t));
static int glue_header_name PARAMS ((cpp_reader *, cpp_token *));
static int parse_include PARAMS ((cpp_reader *, cpp_token *));
static const cpp_token *glue_header_name PARAMS ((cpp_reader *));
static const cpp_token *parse_include PARAMS ((cpp_reader *));
static void push_conditional PARAMS ((cpp_reader *, int, int,
const cpp_hashnode *));
static unsigned int read_flag PARAMS ((cpp_reader *, unsigned int));
@ -100,7 +100,8 @@ static void do_pragma_once PARAMS ((cpp_reader *));
static void do_pragma_poison PARAMS ((cpp_reader *));
static void do_pragma_system_header PARAMS ((cpp_reader *));
static void do_pragma_dependency PARAMS ((cpp_reader *));
static int get__Pragma_string PARAMS ((cpp_reader *, cpp_token *));
static const cpp_token *get_token_no_padding PARAMS ((cpp_reader *));
static const cpp_token *get__Pragma_string PARAMS ((cpp_reader *));
static unsigned char *destringize PARAMS ((const cpp_string *,
unsigned int *));
static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
@ -485,13 +486,13 @@ do_undef (pfile)
/* Helper routine used by parse_include. Reinterpret the current line
as an h-char-sequence (< ... >); we are looking at the first token
after the <. Returns zero on success. */
static int
glue_header_name (pfile, header)
after the <. Returns the header as a token, or NULL on failure. */
static const cpp_token *
glue_header_name (pfile)
cpp_reader *pfile;
cpp_token *header;
{
cpp_token token;
cpp_token *header = NULL;
const cpp_token *token;
unsigned char *buffer, *token_mem;
size_t len, total_len = 0, capacity = 1024;
@ -501,25 +502,25 @@ glue_header_name (pfile, header)
buffer = (unsigned char *) xmalloc (capacity);
for (;;)
{
cpp_get_token (pfile, &token);
token = cpp_get_token (pfile);
if (token.type == CPP_GREATER || token.type == CPP_EOF)
if (token->type == CPP_GREATER || token->type == CPP_EOF)
break;
len = cpp_token_len (&token);
len = cpp_token_len (token);
if (total_len + len > capacity)
{
capacity = (capacity + len) * 2;
buffer = (unsigned char *) xrealloc (buffer, capacity);
}
if (token.flags & PREV_WHITE)
if (token->flags & PREV_WHITE)
buffer[total_len++] = ' ';
total_len = cpp_spell_token (pfile, &token, &buffer[total_len]) - buffer;
total_len = cpp_spell_token (pfile, token, &buffer[total_len]) - buffer;
}
if (token.type == CPP_EOF)
if (token->type == CPP_EOF)
cpp_error (pfile, "missing terminating > character");
else
{
@ -527,6 +528,7 @@ glue_header_name (pfile, header)
memcpy (token_mem, buffer, total_len);
token_mem[total_len] = '\0';
header = _cpp_temp_token (pfile);
header->type = CPP_HEADER_NAME;
header->flags &= ~PREV_WHITE;
header->val.str.len = total_len;
@ -534,17 +536,17 @@ glue_header_name (pfile, header)
}
free ((PTR) buffer);
return token.type == CPP_EOF;
return header;
}
/* Parse the header name of #include, #include_next, #import and
#pragma dependency. Returns zero on success. */
static int
parse_include (pfile, header)
/* Returns the header string of #include, #include_next, #import and
#pragma dependency. Returns NULL on error. */
static const cpp_token *
parse_include (pfile)
cpp_reader *pfile;
cpp_token *header;
{
const unsigned char *dir;
const cpp_token *header;
if (pfile->directive == &dtable[T_PRAGMA])
dir = U"pragma dependency";
@ -552,25 +554,27 @@ parse_include (pfile, header)
dir = pfile->directive->name;
/* Allow macro expansion. */
cpp_get_token (pfile, header);
header = cpp_get_token (pfile);
if (header->type != CPP_STRING && header->type != CPP_HEADER_NAME)
{
if (header->type != CPP_LESS)
{
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
return 1;
return NULL;
}
if (glue_header_name (pfile, header))
return 1;
header = glue_header_name (pfile);
if (header == NULL)
return header;
}
if (header->val.str.len == 0)
{
cpp_error (pfile, "empty file name in #%s", dir);
return 1;
return NULL;
}
return 0;
return header;
}
/* Handle #include, #include_next and #import. */
@ -579,7 +583,7 @@ do_include_common (pfile, type)
cpp_reader *pfile;
enum include_type type;
{
cpp_token header;
const cpp_token *header;
/* For #include_next, if this is the primary source file, warn and
use the normal search logic. */
@ -595,7 +599,8 @@ do_include_common (pfile, type)
"#import is obsolete, use an #ifndef wrapper in the header file");
}
if (!parse_include (pfile, &header))
header = parse_include (pfile);
if (header)
{
/* Prevent #include recursion. */
if (pfile->line_maps.depth >= CPP_STACK_MAX)
@ -607,9 +612,9 @@ do_include_common (pfile, type)
skip_rest_of_line (pfile);
if (pfile->cb.include)
(*pfile->cb.include) (pfile, pfile->directive_line,
pfile->directive->name, &header);
pfile->directive->name, header);
_cpp_execute_include (pfile, &header, type);
_cpp_execute_include (pfile, header, type);
}
}
}
@ -693,7 +698,7 @@ static void
do_line (pfile)
cpp_reader *pfile;
{
cpp_token token;
const cpp_token *token;
const char *new_file = pfile->map->to_file;
unsigned long new_lineno;
unsigned int cap, new_sysp = pfile->map->sysp;
@ -708,12 +713,13 @@ do_line (pfile)
_cpp_backup_tokens (pfile, 1);
/* #line commands expand macros. */
cpp_get_token (pfile, &token);
if (token.type != CPP_NUMBER
|| strtoul_for_line (token.val.str.text, token.val.str.len, &new_lineno))
token = cpp_get_token (pfile);
if (token->type != CPP_NUMBER
|| strtoul_for_line (token->val.str.text, token->val.str.len,
&new_lineno))
{
cpp_error (pfile, "\"%s\" after #line is not a positive integer",
cpp_token_as_text (pfile, &token));
cpp_token_as_text (pfile, token));
return;
}
@ -721,10 +727,10 @@ do_line (pfile)
&& (new_lineno == 0 || new_lineno > cap))
cpp_pedwarn (pfile, "line number out of range");
cpp_get_token (pfile, &token);
if (token.type == CPP_STRING)
token = cpp_get_token (pfile);
if (token->type == CPP_STRING)
{
new_file = (const char *) token.val.str.text;
new_file = (const char *) token->val.str.text;
/* Only accept flags for the # 55 form. */
if (pfile->state.line_extension)
@ -755,10 +761,10 @@ do_line (pfile)
}
check_eol (pfile);
}
else if (token.type != CPP_EOF)
else if (token->type != CPP_EOF)
{
cpp_error (pfile, "\"%s\" is not a valid filename",
cpp_token_as_text (pfile, &token));
cpp_token_as_text (pfile, token));
return;
}
@ -827,13 +833,12 @@ static void
do_ident (pfile)
cpp_reader *pfile;
{
cpp_token str;
const cpp_token *str = cpp_get_token (pfile);
cpp_get_token (pfile, &str);
if (str.type != CPP_STRING)
cpp_error (pfile, "invalid #ident");
if (str->type != CPP_STRING)
cpp_error (pfile, "invalid #ident directive");
else if (pfile->cb.ident)
(*pfile->cb.ident) (pfile, pfile->directive_line, &str.val.str);
(*pfile->cb.ident) (pfile, pfile->directive_line, &str->val.str);
check_eol (pfile);
}
@ -950,7 +955,7 @@ do_pragma (pfile)
{
pragma_cb handler = NULL;
const struct pragma_entry *p;
cpp_token tok;
const cpp_token *token;
unsigned int count = 0;
p = pfile->pragmas;
@ -958,10 +963,10 @@ do_pragma (pfile)
new_space:
count++;
cpp_get_token (pfile, &tok);
if (tok.type == CPP_NAME)
token = cpp_get_token (pfile);
if (token->type == CPP_NAME)
{
const cpp_hashnode *node = tok.val.node;
const cpp_hashnode *node = token->val.node;
size_t len = NODE_LEN (node);
while (p)
@ -990,7 +995,7 @@ do_pragma (pfile)
themselves. Stand-alone CPP must ignore us, otherwise it will
prefix the directive with spaces, hence the 1. Ugh. */
if (pfile->cb.line_change)
(*pfile->cb.line_change)(pfile, &tok, 1);
(*pfile->cb.line_change)(pfile, token, 1);
if (handler)
(*handler) (pfile);
@ -1078,22 +1083,22 @@ static void
do_pragma_dependency (pfile)
cpp_reader *pfile;
{
cpp_token header, msg;
const cpp_token *header;
int ordering;
if (parse_include (pfile, &header))
header = parse_include (pfile);
if (!header)
return;
ordering = _cpp_compare_file_date (pfile, &header);
ordering = _cpp_compare_file_date (pfile, header);
if (ordering < 0)
cpp_warning (pfile, "cannot find source %s",
cpp_token_as_text (pfile, &header));
cpp_token_as_text (pfile, header));
else if (ordering > 0)
{
cpp_warning (pfile, "current file is older than %s",
cpp_token_as_text (pfile, &header));
cpp_get_token (pfile, &msg);
if (msg.type != CPP_EOF)
cpp_token_as_text (pfile, header));
if (cpp_get_token (pfile)->type != CPP_EOF)
{
_cpp_backup_tokens (pfile, 1);
do_diagnostic (pfile, WARNING, 0);
@ -1101,24 +1106,38 @@ do_pragma_dependency (pfile)
}
}
/* Check syntax is "(string-literal)". Returns 0 on success. */
static int
get__Pragma_string (pfile, string)
/* Get a token but skip padding. */
static const cpp_token *
get_token_no_padding (pfile)
cpp_reader *pfile;
cpp_token *string;
{
cpp_token paren;
for (;;)
{
const cpp_token *result = cpp_get_token (pfile);
if (result->type != CPP_PADDING)
return result;
}
}
cpp_get_token (pfile, &paren);
if (paren.type != CPP_OPEN_PAREN)
return 1;
/* Check syntax is "(string-literal)". Returns the string on success,
or NULL on failure. */
static const cpp_token *
get__Pragma_string (pfile)
cpp_reader *pfile;
{
const cpp_token *string;
cpp_get_token (pfile, string);
if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN)
return NULL;
string = get_token_no_padding (pfile);
if (string->type != CPP_STRING && string->type != CPP_WSTRING)
return 1;
return NULL;
cpp_get_token (pfile, &paren);
return paren.type != CPP_CLOSE_PAREN;
if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
return NULL;
return string;
}
/* Returns a malloced buffer containing a destringized cpp_string by
@ -1148,11 +1167,11 @@ void
_cpp_do__Pragma (pfile)
cpp_reader *pfile;
{
cpp_token string;
const cpp_token *string = get__Pragma_string (pfile);
unsigned char *buffer;
unsigned int len;
if (get__Pragma_string (pfile, &string))
if (!string)
cpp_error (pfile, "_Pragma takes a parenthesized string literal");
else
{
@ -1167,7 +1186,7 @@ _cpp_do__Pragma (pfile)
Getting these correct line markers is a little tricky. */
unsigned int orig_line = pfile->line;
buffer = destringize (&string.val.str, &len);
buffer = destringize (&string->val.str, &len);
run_directive (pfile, T_PRAGMA, (char *) buffer, len);
free ((PTR) buffer);
pfile->line = orig_line;
@ -1386,7 +1405,7 @@ parse_answer (pfile, answerp, type)
struct answer **answerp;
int type;
{
cpp_token paren, *token;
const cpp_token *paren;
struct answer *answer;
if (POOL_FRONT (&pfile->macro_pool) + sizeof (struct answer) >
@ -1397,10 +1416,10 @@ parse_answer (pfile, answerp, type)
/* In a conditional, it is legal to not have an open paren. We
should save the following token in this case. */
cpp_get_token (pfile, &paren);
paren = cpp_get_token (pfile);
/* If not a paren, see if we're OK. */
if (paren.type != CPP_OPEN_PAREN)
if (paren->type != CPP_OPEN_PAREN)
{
/* In a conditional no answer is a test for any answer. It
could be followed by any token. */
@ -1411,7 +1430,7 @@ parse_answer (pfile, answerp, type)
}
/* #unassert with no answer is valid - it removes all answers. */
if (type == T_UNASSERT && paren.type == CPP_EOF)
if (type == T_UNASSERT && paren->type == CPP_EOF)
return 0;
cpp_error (pfile, "missing '(' after predicate");
@ -1420,7 +1439,7 @@ parse_answer (pfile, answerp, type)
for (;;)
{
token = &answer->first[answer->count];
cpp_token *token = &answer->first[answer->count];
/* Check we have room for the token. */
if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
{
@ -1429,7 +1448,7 @@ parse_answer (pfile, answerp, type)
token = &answer->first[answer->count];
}
cpp_get_token (pfile, token);
*token = *cpp_get_token (pfile);
if (token->type == CPP_CLOSE_PAREN)
break;
@ -1466,25 +1485,25 @@ parse_assertion (pfile, answerp, type)
int type;
{
cpp_hashnode *result = 0;
cpp_token predicate;
const cpp_token *predicate;
/* We don't expand predicates or answers. */
pfile->state.prevent_expansion++;
*answerp = 0;
cpp_get_token (pfile, &predicate);
if (predicate.type == CPP_EOF)
predicate = cpp_get_token (pfile);
if (predicate->type == CPP_EOF)
cpp_error (pfile, "assertion without predicate");
else if (predicate.type != CPP_NAME)
else if (predicate->type != CPP_NAME)
cpp_error (pfile, "predicate must be an identifier");
else if (parse_answer (pfile, answerp, type) == 0)
{
unsigned int len = NODE_LEN (predicate.val.node);
unsigned int len = NODE_LEN (predicate->val.node);
unsigned char *sym = alloca (len + 1);
/* Prefix '#' to get it out of macro namespace. */
sym[0] = '#';
memcpy (sym + 1, NODE_NAME (predicate.val.node), len);
memcpy (sym + 1, NODE_NAME (predicate->val.node), len);
result = cpp_lookup (pfile, sym, len + 1);
}

View File

@ -134,6 +134,7 @@ struct file_name_map_list;
\
TK(CPP_COMMENT, SPELL_STRING) /* Only if output comments. */ \
TK(CPP_MACRO_ARG, SPELL_NONE) /* Macro argument. */ \
OP(CPP_PADDING, "") /* Whitespace for cpp0. */ \
OP(CPP_EOF, "EOL") /* End of line or file. */
#define OP(e, s) e,
@ -164,8 +165,7 @@ struct cpp_string
#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */
#define NAMED_OP (1 << 4) /* C++ named operators. */
#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */
#define AVOID_LPASTE (1 << 6) /* Check left for accidental pastes. */
#define BOL (1 << 7) /* Token at beginning of line. */
#define BOL (1 << 6) /* Token at beginning of line. */
/* A preprocessing token. This has been carefully packed and should
occupy 12 bytes on 32-bit hosts and 16 bytes on 64-bit hosts. */
@ -179,6 +179,7 @@ struct cpp_token
union
{
cpp_hashnode *node; /* An identifier. */
const cpp_token *source; /* Inherit padding from this token. */
struct cpp_string str; /* A string, or number. */
unsigned int arg_no; /* Argument no. for a CPP_MACRO_ARG. */
unsigned char c; /* Character represented by CPP_OTHER. */
@ -235,6 +236,9 @@ struct cpp_options
/* The language we're preprocessing. */
enum c_lang lang;
/* Nonzero means to return spacing characters for stand-alone CPP. */
unsigned char spacing;
/* Non-0 means -v, so print the full set of include dirs. */
unsigned char verbose;
@ -497,7 +501,7 @@ extern int cpp_avoid_paste PARAMS ((cpp_reader *, const cpp_token *,
const cpp_token *));
extern enum cpp_ttype cpp_can_paste PARAMS ((cpp_reader *, const cpp_token *,
const cpp_token *, int *));
extern void cpp_get_token PARAMS ((cpp_reader *, cpp_token *));
extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *));
extern const unsigned char *cpp_macro_definition PARAMS ((cpp_reader *,
const cpp_hashnode *));
extern void _cpp_backup_tokens PARAMS ((cpp_reader *, unsigned int));

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ struct printer
{
FILE *outf; /* Stream to write to. */
const struct line_map *map; /* Logical to physical line mappings. */
const cpp_token *prev; /* Previous token. */
unsigned int line; /* Line currently being written. */
unsigned char printed; /* Nonzero if something output at line. */
};
@ -43,7 +44,7 @@ static void setup_callbacks PARAMS ((void));
/* General output routines. */
static void scan_translation_unit PARAMS ((cpp_reader *));
static void check_multiline_token PARAMS ((cpp_string *));
static void check_multiline_token PARAMS ((const cpp_string *));
static int dump_macro PARAMS ((cpp_reader *, cpp_hashnode *, void *));
static void print_line PARAMS ((const struct line_map *, unsigned int,
@ -144,6 +145,7 @@ do_preprocessing (argc, argv)
cause a linemarker to be output by maybe_print_line. */
print.line = (unsigned int) -1;
print.printed = 0;
print.prev = 0;
print.map = 0;
/* Open the output now. We must do so even if no_output is on,
@ -219,22 +221,43 @@ static void
scan_translation_unit (pfile)
cpp_reader *pfile;
{
unsigned int index;
cpp_token tokens[2], *token;
bool avoid_paste = false;
const cpp_token *source = NULL;
for (index = 0;; index = 1 - index)
for (;;)
{
token = &tokens[index];
cpp_get_token (pfile, token);
const cpp_token *token = cpp_get_token (pfile);
if (token->type == CPP_PADDING)
{
avoid_paste = true;
if (source == NULL
|| (!(source->flags & PREV_WHITE) && token->val.source == NULL))
source = token->val.source;
continue;
}
if (token->type == CPP_EOF)
break;
if ((token->flags & (PREV_WHITE | AVOID_LPASTE | BOL)) == AVOID_LPASTE
&& cpp_avoid_paste (pfile, &tokens[1 - index], token))
token->flags |= PREV_WHITE;
/* Subtle logic to output a space if and only if necessary. */
if (avoid_paste)
{
if (source == NULL)
source = token;
if (source->flags & PREV_WHITE
|| (print.prev && cpp_avoid_paste (pfile, print.prev, token))
|| (print.prev == NULL && token->type == CPP_HASH))
putc (' ', print.outf);
}
else if (token->flags & PREV_WHITE)
putc (' ', print.outf);
avoid_paste = false;
source = NULL;
print.prev = token;
cpp_output_token (token, print.outf);
if (token->type == CPP_STRING || token->type == CPP_WSTRING
|| token->type == CPP_COMMENT)
check_multiline_token (&token->val.str);
@ -244,7 +267,7 @@ scan_translation_unit (pfile)
/* Adjust print.line for newlines embedded in tokens. */
static void
check_multiline_token (str)
cpp_string *str;
const cpp_string *str;
{
unsigned int i;
@ -324,6 +347,7 @@ cb_line_change (pfile, token, parsing_args)
maybe_print_line (print.map, token->line);
print.printed = 1;
print.prev = 0;
/* Supply enough spaces to put this token in its original column,
one space per column greater than 2, since scan_translation_unit

View File

@ -1515,10 +1515,10 @@ token pasting.
However, two tokens that don't together form a valid token cannot be
pasted together. For example, you cannot concatenate @code{x} with
@code{+} in either order. If you try, the preprocessor issues a warning
and emits the two tokens as if they had been written next to each other.
It is common to find unnecessary uses of @samp{##} in complex macros.
If you get this warning, it is likely that you can simply remove the
@samp{##}.
and emits the two tokens. Whether it puts white space between the
tokens is undefined. It is common to find unnecessary uses of @samp{##}
in complex macros. If you get this warning, it is likely that you can
simply remove the @samp{##}.
Both the tokens combined by @samp{##} could come from the macro body,
but you could just as well write them as one token in the first place.

View File

@ -661,12 +661,11 @@ read_scan_file (in_fname, argc, argv)
/* from_stage3 */ true, 1);
for (;;)
{
cpp_token t;
const cpp_token *t = cpp_get_token (scan_in);
cpp_get_token (scan_in, &t);
if (t.type == CPP_EOF)
if (t->type == CPP_EOF)
break;
else if (cpp_ideq (&t, "_filbuf"))
else if (cpp_ideq (t, "_filbuf"))
seen_filbuf++;
}

View File

@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "scan.h"
static void skip_to_closing_brace PARAMS ((cpp_reader *));
static const cpp_token *get_a_token PARAMS ((cpp_reader *));
int brace_nesting = 0;
@ -38,6 +39,19 @@ char extern_C_braces[20];
prefixed by extern "C". */
int current_extern_C = 0;
/* Get a token but skip padding. */
static const cpp_token *
get_a_token (pfile)
cpp_reader *pfile;
{
for (;;)
{
const cpp_token *result = cpp_get_token (pfile);
if (result->type != CPP_PADDING)
return result;
}
}
static void
skip_to_closing_brace (pfile)
cpp_reader *pfile;
@ -45,11 +59,8 @@ skip_to_closing_brace (pfile)
int nesting = 1;
for (;;)
{
cpp_token tok;
enum cpp_ttype token;
enum cpp_ttype token = get_a_token (pfile)->type;
cpp_get_token (pfile, &tok);
token = tok.type;
if (token == CPP_EOF)
break;
if (token == CPP_OPEN_BRACE)
@ -88,16 +99,17 @@ scan_decls (pfile, argc, argv)
char **argv ATTRIBUTE_UNUSED;
{
int saw_extern, saw_inline;
cpp_token token, prev_id;
cpp_token prev_id;
const cpp_token *token;
new_statement:
cpp_get_token (pfile, &token);
token = get_a_token (pfile);
handle_statement:
current_extern_C = 0;
saw_extern = 0;
saw_inline = 0;
if (token.type == CPP_OPEN_BRACE)
if (token->type == CPP_OPEN_BRACE)
{
/* Pop an 'extern "C"' nesting level, if appropriate. */
if (extern_C_braces_length
@ -106,24 +118,24 @@ scan_decls (pfile, argc, argv)
brace_nesting--;
goto new_statement;
}
if (token.type == CPP_OPEN_BRACE)
if (token->type == CPP_OPEN_BRACE)
{
brace_nesting++;
goto new_statement;
}
if (token.type == CPP_EOF)
if (token->type == CPP_EOF)
return 0;
if (token.type == CPP_SEMICOLON)
if (token->type == CPP_SEMICOLON)
goto new_statement;
if (token.type != CPP_NAME)
if (token->type != CPP_NAME)
goto new_statement;
prev_id.type = CPP_EOF;
for (;;)
{
switch (token.type)
switch (token->type)
{
default:
goto handle_statement;
@ -138,7 +150,7 @@ scan_decls (pfile, argc, argv)
{
recognized_extern (&prev_id);
}
if (token.type == CPP_COMMA)
if (token->type == CPP_COMMA)
break;
/* ... fall through ... */
case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE:
@ -155,27 +167,27 @@ scan_decls (pfile, argc, argv)
int have_arg_list = 0;
for (;;)
{
cpp_get_token (pfile, &token);
if (token.type == CPP_OPEN_PAREN)
token = get_a_token (pfile);
if (token->type == CPP_OPEN_PAREN)
nesting++;
else if (token.type == CPP_CLOSE_PAREN)
else if (token->type == CPP_CLOSE_PAREN)
{
nesting--;
if (nesting == 0)
break;
}
else if (token.type == CPP_EOF)
else if (token->type == CPP_EOF)
break;
else if (token.type == CPP_NAME
|| token.type == CPP_ELLIPSIS)
else if (token->type == CPP_NAME
|| token->type == CPP_ELLIPSIS)
have_arg_list = 1;
}
recognized_function (&prev_id, token.line,
recognized_function (&prev_id, token->line,
(saw_inline ? 'I'
: in_extern_C_brace || current_extern_C
? 'F' : 'f'), have_arg_list);
cpp_get_token (pfile, &token);
if (token.type == CPP_OPEN_BRACE)
token = get_a_token (pfile);
if (token->type == CPP_OPEN_BRACE)
{
/* skip body of (normally) inline function */
skip_to_closing_brace (pfile);
@ -184,28 +196,28 @@ scan_decls (pfile, argc, argv)
/* skip a possible __attribute__ or throw expression after the
parameter list */
while (token.type != CPP_SEMICOLON && token.type != CPP_EOF)
cpp_get_token (pfile, &token);
while (token->type != CPP_SEMICOLON && token->type != CPP_EOF)
token = get_a_token (pfile);
goto new_statement;
}
break;
case CPP_NAME:
/* "inline" and "extern" are recognized but skipped */
if (cpp_ideq (&token, "inline"))
if (cpp_ideq (token, "inline"))
{
saw_inline = 1;
}
else if (cpp_ideq (&token, "extern"))
else if (cpp_ideq (token, "extern"))
{
saw_extern = 1;
cpp_get_token (pfile, &token);
if (token.type == CPP_STRING
&& token.val.str.len == 1
&& token.val.str.text[0] == 'C')
token = get_a_token (pfile);
if (token->type == CPP_STRING
&& token->val.str.len == 1
&& token->val.str.text[0] == 'C')
{
current_extern_C = 1;
cpp_get_token (pfile, &token);
if (token.type == CPP_OPEN_BRACE)
token = get_a_token (pfile);
if (token->type == CPP_OPEN_BRACE)
{
brace_nesting++;
extern_C_braces[extern_C_braces_length++]
@ -218,9 +230,9 @@ scan_decls (pfile, argc, argv)
break;
}
/* This may be the name of a variable or function. */
prev_id = token;
prev_id = *token;
break;
}
cpp_get_token (pfile, &token);
token = get_a_token (pfile);
}
}

View File

@ -1,3 +1,11 @@
2001-09-24 Neil Booth <neil@daikokuya.demon.co.uk>
* gcc.dg/cpp/macro10.c: New test.
* gcc.dg/cpp/strify3.c: New test.
* gcc.dg/cpp/spacing1.c: Add tests.
* gcc.dg/cpp/19990703-1.c: Remove bogus test.
* gcc.dg/cpp/20000625-2.c: Fudge to pass.
2001-09-24 DJ Delorie <dj@redhat.com>
* gcc.c-torture/execute/20010924-1.c: New test.

View File

@ -1,24 +0,0 @@
/* { dg-do run } */
/* Test of obscure case in token pasting in the preprocessor.
I can't think of any way to make this problem provoke a syntax error.
Based on a bug report by Manfred Hollstein. */
#include <string.h>
#define SP1(x, y) SP2(x, y)
#define SP2(x, y) SP3(x##y)
#define SP3(x) #x
#define MZ -0
int
main(void)
{
char *x = SP1(0,MZ); /* { dg-warning "valid preprocessing token" "" } */
char *y = "0-0"; /* should be the expansion of SP1(0,MZ) */
if(strcmp(x, y))
return 1;
else
return 0;
}

View File

@ -8,7 +8,10 @@
#define str(x) xstr(x)
#define xstr(x) #x
const char a[] = str(symbol_version(getrlimit, GLIBC_2.0));
/* This testcase is bogus, as it testing undefined behaviour. We can
get the behaviour GLIBC desires by removing the space before
GCLIB_2.0 in this line. */
const char a[] = str(symbol_version(getrlimit,GLIBC_2.0));
/* { dg-warning "valid preprocessing token" "" { target *-*-* } 11 } */
const char b[] = str(getrlimit@GLIBC_2.0);
const char c[] = "getrlimit@GLIBC_2.0";

View File

@ -0,0 +1,25 @@
/* Copyright (C) 2001 Free Software Foundation, Inc. */
/* { dg-do preprocess } */
/* Source: Neil Booth, 23 Sep 2001.
A tricky, pathological corner case we used to get wrong. Expansion
should go as follows. The asterisk indicates the token has "blue
paint" can no longer be macro expanded. We used to lose that
information when parsing arguments and dropping to the lexer to get
the ')'.
foo )
bar foo* )
func (foo* )
foo*
If we try and expand the final foo, we get an "unterminated
argument list invoking macro <func>" error. If we do the right
thing and leave it as is, no diagnostics are emitted. */
#define func(x) x
#define bar func(
#define foo bar foo
foo )

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. */
/* { dg-do preprocess } */
@ -8,20 +8,24 @@
not be a macro invocation. Also, multiple macro invocations spread
across many lines.
Neil Booth, 1 Dec 2000. */
Neil Booth, 1 Dec 2000, 23 Sep 2001. */
#define str(x) #x
#define f(x) x
#define glue(x, y) x ## y
#define EMPTY
/* The correct output is shown here. Note the spaces, and the way
everything after the invocation of f appears on the same line.
44 ;
f
bar
g "1 2" bam baz
*/
glue (EMPTY 4, 4) EMPTY;
f
bar
f (g) str
@ -33,9 +37,10 @@ f (g) str
/*
{ dg-final { if ![file exists spacing1.i] { return } } }
{ dg-final { if \{ [grep spacing1.i " 44 ;"] != "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "f.*bar"] == "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "^bar"] != "" \} \{ } }
{ dg-final { if \{ [grep spacing1.i "g \"1 2\" bam baz"] != "" \} \{ } }
{ dg-final { return \} \} \} } }
{ dg-final { return \} \} \} \} } }
{ dg-final { fail "spacing1.c: spacing and new-line preservation" } }
*/

View File

@ -0,0 +1,29 @@
/* Copyright (C) 2001 Free Software Foundation, Inc. */
/* { dg-do run } */
/* Tests we stringify without inserting a space. GCC 2.95.x and
earlier would insert a bogus space before bar in the string, simply
because a space was there in the invocation.
Neil Booth, 24 Sep 2001. */
extern int strcmp (const char *, const char *);
extern int puts (const char *);
extern void abort (void);
#define err(str) do { puts(str); abort(); } while (0)
#define str(x) #x
#define xstr(x) str(x)
#define glibc_hack(x, y) x@y
int main (int argc, char *argv[])
{
/* The space before "bar" here is vital. */
char a[] = xstr(glibc_hack(foo, bar));
if (strcmp (a, "foo@bar"))
err ("stringification without spaces");
return 0;
}