cppfiles.c (stack_include_file): Check for stacked contexts here.
* cppfiles.c (stack_include_file): Check for stacked contexts here. * cpphash.h (_cpp_do__Pragma): New prototype. * cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table. * cpplex.c (skip_escaped_newlines): Only process trigraphs and escaped newlines if !(buffer->from_stage3). (_cpp_lex_token): Warn about missing newlines iff !buffer->from_stage3. * cpplib.c (get__Pragma_string, destringize, _cpp_do__Pragma): New functions. (run_directive): Set output_line for _Pragma to avoid line markers in output. Set from_stage3 and prevent macro expansion for _Pragma and command-line options. Check buffer exhaustion. (cpp_push_buffer): Don't check for stacked macro contexts, as this is perfectly legitimate for _Pragma. Move the check to stack_include_file instead. Set from_stage3 iff buffer is preprocessed input. * cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments unsigned. New boolean from_stage3. (struct spec_nodes): Add n__Pragma. * cppmacro.c (enter_macro_context): Flip sense of return value. (_cpp_get_token): Handle _Pragma operator. From-SVN: r37147
This commit is contained in:
parent
dbdaea4110
commit
a5c3cccda4
@ -1,3 +1,32 @@
|
||||
2000-10-30 Neil Booth <neilb@earthling.net>
|
||||
|
||||
* cppfiles.c (stack_include_file): Check for stacked contexts
|
||||
here.
|
||||
* cpphash.h (_cpp_do__Pragma): New prototype.
|
||||
* cppinit.c (cpp_reader_init): Add _Pragma keyword to hash table.
|
||||
|
||||
* cpplex.c (skip_escaped_newlines): Only process trigraphs and
|
||||
escaped newlines if !(buffer->from_stage3).
|
||||
(_cpp_lex_token): Warn about missing newlines iff
|
||||
!buffer->from_stage3.
|
||||
|
||||
* cpplib.c (get__Pragma_string, destringize,
|
||||
_cpp_do__Pragma): New functions.
|
||||
(run_directive): Set output_line for _Pragma to avoid line
|
||||
markers in output. Set from_stage3 and prevent macro expansion
|
||||
for _Pragma and command-line options. Check buffer exhaustion.
|
||||
(cpp_push_buffer): Don't check for stacked macro contexts, as
|
||||
this is perfectly legitimate for _Pragma. Move the check to
|
||||
stack_include_file instead. Set from_stage3 iff buffer is
|
||||
preprocessed input.
|
||||
|
||||
* cpplib.h (struct cpp_buffer): Make warned_cplusplus_comments
|
||||
unsigned. New boolean from_stage3.
|
||||
(struct spec_nodes): Add n__Pragma.
|
||||
|
||||
* cppmacro.c (enter_macro_context): Flip sense of return value.
|
||||
(_cpp_get_token): Handle _Pragma operator.
|
||||
|
||||
2000-10-30 Phil Edwards <pme@sources.redhat.com>
|
||||
|
||||
* gcc.texi: The C++ standard isn't "draft" anymore.
|
||||
|
@ -206,6 +206,9 @@ stack_include_file (pfile, inc)
|
||||
{
|
||||
cpp_buffer *fp;
|
||||
|
||||
if (pfile->context->prev)
|
||||
cpp_ice (pfile, "attempt to push file buffer with contexts stacked");
|
||||
|
||||
if (DO_NOT_REREAD (inc))
|
||||
return 0;
|
||||
|
||||
|
@ -203,6 +203,7 @@ extern void _cpp_unlock_pool PARAMS ((cpp_pool *));
|
||||
extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
|
||||
extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
|
||||
extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *));
|
||||
extern void _cpp_do__Pragma PARAMS ((cpp_reader *));
|
||||
extern void _cpp_init_stacks PARAMS ((cpp_reader *));
|
||||
extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *));
|
||||
extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
|
||||
|
@ -487,6 +487,7 @@ cpp_reader_init (pfile)
|
||||
s = &pfile->spec_nodes;
|
||||
s->n_L = cpp_lookup (pfile, DSC("L"));
|
||||
s->n_defined = cpp_lookup (pfile, DSC("defined"));
|
||||
s->n__Pragma = cpp_lookup (pfile, DSC("_Pragma"));
|
||||
s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
|
||||
s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
|
||||
s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
|
||||
|
116
gcc/cpplex.c
116
gcc/cpplex.c
@ -181,71 +181,77 @@ trigraph_ok (pfile, from_char)
|
||||
|
||||
/* Skips any escaped newlines introduced by NEXT, which is either a
|
||||
'?' or a '\\'. Returns the next character, which will also have
|
||||
been placed in buffer->read_ahead. */
|
||||
been placed in buffer->read_ahead. This routine performs
|
||||
preprocessing stages 1 and 2 of the ISO C standard. */
|
||||
static cppchar_t
|
||||
skip_escaped_newlines (buffer, next)
|
||||
cpp_buffer *buffer;
|
||||
cppchar_t next;
|
||||
{
|
||||
cppchar_t next1;
|
||||
const unsigned char *saved_cur;
|
||||
int space;
|
||||
|
||||
do
|
||||
/* Only do this if we apply stages 1 and 2. */
|
||||
if (!buffer->from_stage3)
|
||||
{
|
||||
if (buffer->cur == buffer->rlimit)
|
||||
break;
|
||||
|
||||
SAVE_STATE ();
|
||||
if (next == '?')
|
||||
{
|
||||
next1 = *buffer->cur++;
|
||||
if (next1 != '?' || buffer->cur == buffer->rlimit)
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
cppchar_t next1;
|
||||
const unsigned char *saved_cur;
|
||||
int space;
|
||||
|
||||
next1 = *buffer->cur++;
|
||||
if (!_cpp_trigraph_map[next1] || !trigraph_ok (buffer->pfile, next1))
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* We have a full trigraph here. */
|
||||
next = _cpp_trigraph_map[next1];
|
||||
if (next != '\\' || buffer->cur == buffer->rlimit)
|
||||
break;
|
||||
SAVE_STATE ();
|
||||
}
|
||||
|
||||
/* We have a backslash, and room for at least one more character. */
|
||||
space = 0;
|
||||
do
|
||||
{
|
||||
next1 = *buffer->cur++;
|
||||
if (!is_nvspace (next1))
|
||||
if (buffer->cur == buffer->rlimit)
|
||||
break;
|
||||
space = 1;
|
||||
|
||||
SAVE_STATE ();
|
||||
if (next == '?')
|
||||
{
|
||||
next1 = *buffer->cur++;
|
||||
if (next1 != '?' || buffer->cur == buffer->rlimit)
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
|
||||
next1 = *buffer->cur++;
|
||||
if (!_cpp_trigraph_map[next1]
|
||||
|| !trigraph_ok (buffer->pfile, next1))
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* We have a full trigraph here. */
|
||||
next = _cpp_trigraph_map[next1];
|
||||
if (next != '\\' || buffer->cur == buffer->rlimit)
|
||||
break;
|
||||
SAVE_STATE ();
|
||||
}
|
||||
|
||||
/* We have a backslash, and room for at least one more character. */
|
||||
space = 0;
|
||||
do
|
||||
{
|
||||
next1 = *buffer->cur++;
|
||||
if (!is_nvspace (next1))
|
||||
break;
|
||||
space = 1;
|
||||
}
|
||||
while (buffer->cur < buffer->rlimit);
|
||||
|
||||
if (!is_vspace (next1))
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (space)
|
||||
cpp_warning (buffer->pfile,
|
||||
"backslash and newline separated by space");
|
||||
|
||||
next = handle_newline (buffer, next1);
|
||||
if (next == EOF)
|
||||
cpp_pedwarn (buffer->pfile, "backslash-newline at end of file");
|
||||
}
|
||||
while (buffer->cur < buffer->rlimit);
|
||||
|
||||
if (!is_vspace (next1))
|
||||
{
|
||||
RESTORE_STATE ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (space)
|
||||
cpp_warning (buffer->pfile,
|
||||
"backslash and newline separated by space");
|
||||
|
||||
next = handle_newline (buffer, next1);
|
||||
if (next == EOF)
|
||||
cpp_pedwarn (buffer->pfile, "backslash-newline at end of file");
|
||||
while (next == '\\' || next == '?');
|
||||
}
|
||||
while (next == '\\' || next == '?');
|
||||
|
||||
buffer->read_ahead = next;
|
||||
return next;
|
||||
@ -863,8 +869,8 @@ _cpp_lex_token (pfile, result)
|
||||
{
|
||||
case EOF:
|
||||
/* Non-empty files should end in a newline. Ignore for command
|
||||
line - we get e.g. -A options with no trailing \n. */
|
||||
if (pfile->lexer_pos.col != 0 && pfile->done_initializing)
|
||||
line and _Pragma buffers. */
|
||||
if (pfile->lexer_pos.col != 0 && !buffer->from_stage3)
|
||||
cpp_pedwarn (pfile, "no newline at end of file");
|
||||
pfile->state.skip_newlines = 1;
|
||||
result->type = CPP_EOF;
|
||||
|
89
gcc/cpplib.c
89
gcc/cpplib.c
@ -99,6 +99,9 @@ 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 unsigned char *destringize PARAMS ((const cpp_string *,
|
||||
unsigned int *));
|
||||
static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
|
||||
static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
|
||||
int));
|
||||
@ -345,7 +348,7 @@ run_directive (pfile, dir_no, buf, count, name)
|
||||
size_t count;
|
||||
const char *name;
|
||||
{
|
||||
if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
|
||||
if (cpp_push_buffer (pfile, (const U_CHAR *) buf, count) != NULL)
|
||||
{
|
||||
const struct directive *dir = &dtable[dir_no];
|
||||
|
||||
@ -353,15 +356,27 @@ run_directive (pfile, dir_no, buf, count, name)
|
||||
CPP_BUFFER (pfile)->nominal_fname = name;
|
||||
else
|
||||
CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
|
||||
CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
|
||||
|
||||
/* A kludge to avoid line markers for _Pragma. */
|
||||
if (dir_no == T_PRAGMA)
|
||||
pfile->lexer_pos.output_line = CPP_BUFFER (pfile)->prev->lineno;
|
||||
|
||||
/* For _Pragma, the text is passed through preprocessing stage 3
|
||||
only, i.e. no trigraphs, no escaped newline removal, and no
|
||||
macro expansion. Do the same for command-line directives. */
|
||||
pfile->buffer->from_stage3 = 1;
|
||||
pfile->state.in_directive = 1;
|
||||
pfile->directive = dir;
|
||||
pfile->state.prevent_expansion++;
|
||||
(void) (*dir->handler) (pfile);
|
||||
pfile->state.prevent_expansion--;
|
||||
pfile->directive = 0;
|
||||
pfile->state.in_directive = 0;
|
||||
|
||||
skip_rest_of_line (pfile);
|
||||
if (pfile->buffer->cur != pfile->buffer->rlimit)
|
||||
cpp_error (pfile, "extra text after end of #%s directive",
|
||||
dtable[dir_no].name);
|
||||
cpp_pop_buffer (pfile);
|
||||
}
|
||||
}
|
||||
@ -1069,6 +1084,68 @@ do_pragma_dependency (pfile)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check syntax is "(string-literal)". Returns 0 on success. */
|
||||
static int
|
||||
get__Pragma_string (pfile, string)
|
||||
cpp_reader *pfile;
|
||||
cpp_token *string;
|
||||
{
|
||||
cpp_token paren;
|
||||
|
||||
cpp_get_token (pfile, &paren);
|
||||
if (paren.type != CPP_OPEN_PAREN)
|
||||
return 1;
|
||||
|
||||
cpp_get_token (pfile, string);
|
||||
if (string->type != CPP_STRING && string->type != CPP_WSTRING)
|
||||
return 1;
|
||||
|
||||
cpp_get_token (pfile, &paren);
|
||||
return paren.type != CPP_CLOSE_PAREN;
|
||||
}
|
||||
|
||||
/* Returns a malloced buffer containing a destringized cpp_string by
|
||||
removing the first \ of \" and \\ sequences. */
|
||||
static unsigned char *
|
||||
destringize (in, len)
|
||||
const cpp_string *in;
|
||||
unsigned int *len;
|
||||
{
|
||||
const unsigned char *src, *limit;
|
||||
unsigned char *dest, *result;
|
||||
|
||||
dest = result = (unsigned char *) xmalloc (in->len);
|
||||
for (src = in->text, limit = src + in->len; src < limit;)
|
||||
{
|
||||
/* We know there is a character following the backslash. */
|
||||
if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
|
||||
src++;
|
||||
*dest++ = *src++;
|
||||
}
|
||||
|
||||
*len = dest - result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
_cpp_do__Pragma (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
cpp_token string;
|
||||
unsigned char *buffer;
|
||||
unsigned int len;
|
||||
|
||||
if (get__Pragma_string (pfile, &string))
|
||||
{
|
||||
cpp_error (pfile, "_Pragma takes a parenthesized string literal");
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = destringize (&string.val.str, &len);
|
||||
run_directive (pfile, T_PRAGMA, (char *) buffer, len, _("<_Pragma>"));
|
||||
free ((PTR) buffer);
|
||||
}
|
||||
|
||||
/* Just ignore #sccs, on systems where we define it at all. */
|
||||
#ifdef SCCS_DIRECTIVE
|
||||
static void
|
||||
@ -1626,12 +1703,6 @@ cpp_push_buffer (pfile, buffer, length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pfile->context->prev)
|
||||
{
|
||||
cpp_ice (pfile, "buffer pushed with contexts stacked");
|
||||
skip_rest_of_line (pfile);
|
||||
}
|
||||
|
||||
new = xobnew (pfile->buffer_ob, cpp_buffer);
|
||||
/* Clears, amongst other things, if_stack and mi_cmacro. */
|
||||
memset (new, 0, sizeof (cpp_buffer));
|
||||
@ -1641,6 +1712,8 @@ cpp_push_buffer (pfile, buffer, length)
|
||||
new->rlimit = buffer + length;
|
||||
new->prev = buf;
|
||||
new->pfile = pfile;
|
||||
/* Preprocessed files don't do trigraph and escaped newline processing. */
|
||||
new->from_stage3 = CPP_OPTION (pfile, preprocessed);
|
||||
/* No read ahead or extra char initially. */
|
||||
new->read_ahead = EOF;
|
||||
new->extra_char = EOF;
|
||||
|
@ -287,7 +287,12 @@ struct cpp_buffer
|
||||
The warning happens only for C89 extended mode with -pedantic on,
|
||||
or for -Wtraditional, and only once per file (otherwise it would
|
||||
be far too noisy). */
|
||||
char warned_cplusplus_comments;
|
||||
unsigned char warned_cplusplus_comments;
|
||||
|
||||
/* True if we don't process trigraphs and escaped newlines. True
|
||||
for preprocessed input, command line directives, and _Pragma
|
||||
buffers. */
|
||||
unsigned char from_stage3;
|
||||
};
|
||||
|
||||
/* Maximum nesting of cpp_buffers. We use a static limit, partly for
|
||||
@ -509,6 +514,7 @@ struct spec_nodes
|
||||
{
|
||||
cpp_hashnode *n_L; /* L"str" */
|
||||
cpp_hashnode *n_defined; /* defined operator */
|
||||
cpp_hashnode *n__Pragma; /* _Pragma operator */
|
||||
cpp_hashnode *n__STRICT_ANSI__; /* STDC_0_IN_SYSTEM_HEADERS */
|
||||
cpp_hashnode *n__CHAR_UNSIGNED__; /* plain char is unsigned */
|
||||
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
|
||||
|
@ -689,7 +689,8 @@ funlike_invocation_p (pfile, node, list)
|
||||
|
||||
/* Push the context of a macro onto the context stack. TOKEN is the
|
||||
macro name. If we can successfully start expanding the macro,
|
||||
TOKEN is replaced with the first token of the expansion. */
|
||||
TOKEN is replaced with the first token of the expansion, and we
|
||||
return non-zero. */
|
||||
static int
|
||||
enter_macro_context (pfile, token)
|
||||
cpp_reader *pfile;
|
||||
@ -704,7 +705,7 @@ enter_macro_context (pfile, token)
|
||||
if (macro->disabled)
|
||||
{
|
||||
token->flags |= NO_EXPAND;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the position of the outermost macro invocation. */
|
||||
@ -718,7 +719,7 @@ enter_macro_context (pfile, token)
|
||||
{
|
||||
if (!pfile->context->prev)
|
||||
unlock_pools (pfile);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now push its context. */
|
||||
@ -740,7 +741,7 @@ enter_macro_context (pfile, token)
|
||||
/* Disable the macro within its expansion. */
|
||||
macro->disabled = 1;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Move to the next context. Create one if there is none. */
|
||||
@ -922,6 +923,7 @@ _cpp_get_token (pfile, token)
|
||||
cpp_reader *pfile;
|
||||
cpp_token *token;
|
||||
{
|
||||
next_token:
|
||||
for (;;)
|
||||
{
|
||||
cpp_context *context = pfile->context;
|
||||
@ -959,22 +961,34 @@ _cpp_get_token (pfile, token)
|
||||
if (token->flags & PASTE_LEFT)
|
||||
paste_all_tokens (pfile, token);
|
||||
|
||||
if (token->type != CPP_NAME
|
||||
|| token->val.node->type != NT_MACRO
|
||||
|| pfile->state.prevent_expansion
|
||||
|| token->flags & NO_EXPAND)
|
||||
if (token->type != CPP_NAME)
|
||||
break;
|
||||
|
||||
/* Macros, built-in or not, invalidate controlling macros. */
|
||||
pfile->mi_state = MI_FAILED;
|
||||
|
||||
if (token->val.node->flags & NODE_BUILTIN)
|
||||
/* Handle macros and the _Pragma operator. */
|
||||
if (token->val.node->type == NT_MACRO
|
||||
&& !pfile->state.prevent_expansion
|
||||
&& !(token->flags & NO_EXPAND))
|
||||
{
|
||||
builtin_macro (pfile, token);
|
||||
break;
|
||||
/* Macros invalidate controlling macros. */
|
||||
pfile->mi_state = MI_FAILED;
|
||||
|
||||
if (token->val.node->flags & NODE_BUILTIN)
|
||||
{
|
||||
builtin_macro (pfile, token);
|
||||
break;
|
||||
}
|
||||
|
||||
if (enter_macro_context (pfile, token))
|
||||
continue;
|
||||
}
|
||||
else if (enter_macro_context (pfile, token))
|
||||
|
||||
if (token->val.node != pfile->spec_nodes.n__Pragma)
|
||||
break;
|
||||
|
||||
/* Invalidate controlling macros. */
|
||||
pfile->mi_state = MI_FAILED;
|
||||
_cpp_do__Pragma (pfile);
|
||||
goto next_token;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user