aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/cppfiles.c3
-rw-r--r--gcc/cpphash.h1
-rw-r--r--gcc/cppinit.c1
-rw-r--r--gcc/cpplex.c104
-rw-r--r--gcc/cpplib.c89
-rw-r--r--gcc/cpplib.h8
-rw-r--r--gcc/cppmacro.c44
8 files changed, 206 insertions, 73 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 70b9172..0cc78db 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c
index f54fe8a..1009fa7 100644
--- a/gcc/cppfiles.c
+++ b/gcc/cppfiles.c
@@ -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;
diff --git a/gcc/cpphash.h b/gcc/cpphash.h
index bba1ba9..a1c859d 100644
--- a/gcc/cpphash.h
+++ b/gcc/cpphash.h
@@ -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 *));
diff --git a/gcc/cppinit.c b/gcc/cppinit.c
index 20dfc63..512a0ff 100644
--- a/gcc/cppinit.c
+++ b/gcc/cppinit.c
@@ -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__"));
diff --git a/gcc/cpplex.c b/gcc/cpplex.c
index ac8c3c4..43e090b 100644
--- a/gcc/cpplex.c
+++ b/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 == '?')
+ cppchar_t next1;
+ const unsigned char *saved_cur;
+ int space;
+
+ do
{
- next1 = *buffer->cur++;
- if (next1 != '?' || buffer->cur == buffer->rlimit)
+ if (buffer->cur == buffer->rlimit)
+ break;
+
+ SAVE_STATE ();
+ if (next == '?')
{
- RESTORE_STATE ();
- break;
+ 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);
- next1 = *buffer->cur++;
- if (!_cpp_trigraph_map[next1] || !trigraph_ok (buffer->pfile, next1))
+ if (!is_vspace (next1))
{
RESTORE_STATE ();
break;
}
- /* We have a full trigraph here. */
- next = _cpp_trigraph_map[next1];
- if (next != '\\' || buffer->cur == buffer->rlimit)
- break;
- SAVE_STATE ();
- }
+ if (space)
+ cpp_warning (buffer->pfile,
+ "backslash and newline separated by space");
- /* 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;
+ next = handle_newline (buffer, next1);
+ if (next == EOF)
+ cpp_pedwarn (buffer->pfile, "backslash-newline at end of file");
}
-
- 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;
diff --git a/gcc/cpplib.c b/gcc/cpplib.c
index 18b44be..12fa982 100644
--- a/gcc/cpplib.c
+++ b/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;
diff --git a/gcc/cpplib.h b/gcc/cpplib.h
index 747ff18..de7a1a5 100644
--- a/gcc/cpplib.h
+++ b/gcc/cpplib.h
@@ -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 */
diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c
index 9bd8884..484ce03 100644
--- a/gcc/cppmacro.c
+++ b/gcc/cppmacro.c
@@ -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;
}
}