/* CPP Library. (Directive handling.)
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Per Bothner, 1994-95.
Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
-
struct if_stack
{
struct if_stack *next;
int type; /* Most recent conditional, for diagnostics. */
};
+/* Contains a registered pragma or pragma namespace. */
+typedef void (*pragma_cb) PARAMS ((cpp_reader *));
+struct pragma_entry
+{
+ struct pragma_entry *next;
+ const cpp_hashnode *pragma; /* Name and length. */
+ int is_nspace;
+ union {
+ pragma_cb handler;
+ struct pragma_entry *space;
+ } u;
+};
+
/* Values for the origin field of struct directive. KANDR directives
come from traditional (K&R) C. STDC89 directives come from the
1989 C standard. EXTENSION directives are extensions. */
static void do_diagnostic PARAMS ((cpp_reader *, enum error_type, int));
static cpp_hashnode *lex_macro_node PARAMS ((cpp_reader *));
static void do_include_common PARAMS ((cpp_reader *, enum include_type));
+static struct pragma_entry *lookup_pragma_entry
+ PARAMS ((struct pragma_entry *, const cpp_hashnode *pragma));
+static struct pragma_entry *insert_pragma_entry
+ PARAMS ((cpp_reader *, struct pragma_entry **, const cpp_hashnode *,
+ pragma_cb));
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 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 void destringize_and_run PARAMS ((cpp_reader *, const cpp_string *));
static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
int));
/* Output diagnostics for a directive DIR. INDENTED is non-zero if
the '#' was indented. */
-
static void
directive_diagnostics (pfile, dir, indented)
cpp_reader *pfile;
compilers, directives added by C89 must have their #
indented, and directives present in traditional C must not.
This is true even of directives in skipped conditional
- blocks. */
+ blocks. #elif cannot be used at all. */
if (CPP_WTRADITIONAL (pfile))
{
if (dir == &dtable[T_ELIF])
to save unnecessarily exporting dtable etc. to cpplex.c. Returns
non-zero if the line of tokens has been handled, zero if we should
continue processing the line. */
-
int
_cpp_handle_directive (pfile, indented)
cpp_reader *pfile;
{
const directive *dir = 0;
const cpp_token *dname;
+ bool was_parsing_args = pfile->state.parsing_args;
int skip = 1;
+ if (was_parsing_args)
+ {
+ if (CPP_OPTION (pfile, pedantic))
+ cpp_pedwarn (pfile,
+ "embedding a directive within macro arguments is not portable");
+ pfile->state.parsing_args = 0;
+ pfile->state.prevent_expansion = 0;
+ }
start_directive (pfile);
dname = _cpp_lex_token (pfile);
does not cause '#define foo bar' to get executed when
compiled with -save-temps, we recognize directives in
-fpreprocessed mode only if the # is in column 1. cppmacro.c
- puts a space in fron of any '#' at the start of a macro. */
+ puts a space in front of any '#' at the start of a macro. */
if (CPP_OPTION (pfile, preprocessed)
&& (indented || !(dir->flags & IN_I)))
{
_cpp_backup_tokens (pfile, 1);
end_directive (pfile, skip);
+ if (was_parsing_args)
+ {
+ /* Restore state when within macro args. */
+ pfile->state.parsing_args = 2;
+ pfile->state.prevent_expansion = 1;
+ pfile->buffer->saved_flags |= PREV_WHITE;
+ }
return skip;
}
}
}
-/* Handle #undef. Marks the identifier NT_VOID in the hash table. */
+/* Handle #undef. Mark the identifier NT_VOID in the hash table. */
static void
do_undef (pfile)
cpp_reader *pfile;
{
cpp_token *header = NULL;
const cpp_token *token;
- unsigned char *dest;
- size_t len;
+ unsigned char *buffer;
+ size_t len, total_len = 0, capacity = 1024;
/* To avoid lexed tokens overwriting our glued name, we can only
allocate from the string pool once we've lexed everything. */
-
- dest = BUFF_FRONT (pfile->u_buff);
+ buffer = (unsigned char *) xmalloc (capacity);
for (;;)
{
token = cpp_get_token (pfile);
if (token->type == CPP_GREATER || token->type == CPP_EOF)
break;
- /* + 1 for terminating NUL. */
- len = cpp_token_len (token) + 1;
- if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
+ len = cpp_token_len (token);
+ if (total_len + len > capacity)
{
- size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
- _cpp_extend_buff (pfile, &pfile->u_buff, len);
- dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
+ capacity = (capacity + len) * 2;
+ buffer = (unsigned char *) xrealloc (buffer, capacity);
}
if (token->flags & PREV_WHITE)
- *dest++ = ' ';
+ buffer[total_len++] = ' ';
- dest = cpp_spell_token (pfile, token, dest);
+ total_len = cpp_spell_token (pfile, token, &buffer[total_len]) - buffer;
}
if (token->type == CPP_EOF)
cpp_error (pfile, "missing terminating > character");
else
{
+ unsigned char *token_mem = _cpp_unaligned_alloc (pfile, total_len + 1);
+ memcpy (token_mem, buffer, total_len);
+ token_mem[total_len] = '\0';
+
header = _cpp_temp_token (pfile);
header->type = CPP_HEADER_NAME;
header->flags = 0;
- header->val.str.len = dest - BUFF_FRONT (pfile->u_buff);
- header->val.str.text = BUFF_FRONT (pfile->u_buff);
- *dest++ = '\0';
- BUFF_FRONT (pfile->u_buff) = dest;
+ header->val.str.len = total_len;
+ header->val.str.text = token_mem;
}
+ free ((PTR) buffer);
return header;
}
/* Subroutine of do_line. Read possible flags after file name. LAST
is the last flag seen; 0 if this is the first flag. Return the flag
if it is valid, 0 at the end of the directive. Otherwise complain. */
-
static unsigned int
read_flag (pfile, last)
cpp_reader *pfile;
/* Interpret #line command.
Note that the filename string (if any) is treated as if it were an
include filename. That means no escape handling. */
-
static void
do_line (pfile)
cpp_reader *pfile;
/* Arrange the file_change callback. pfile->line has changed to
FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system
- header, 2 for a sytem header that needs to be extern "C" protected,
+ header, 2 for a system header that needs to be extern "C" protected,
and zero otherwise. */
void
_cpp_do_file_change (pfile, reason, to_file, file_line, sysp)
(*pfile->cb.file_change) (pfile, pfile->map);
}
-/*
- * Report a warning or error detected by the program we are
- * processing. Use the directive's tokens in the error message.
- */
-
+/* Report a warning or error detected by the program we are
+ processing. Use the directive's tokens in the error message. */
static void
do_diagnostic (pfile, code, print_dir)
cpp_reader *pfile;
}
/* Report program identification. */
-
static void
do_ident (pfile)
cpp_reader *pfile;
check_eol (pfile);
}
-/* Pragmata handling. We handle some of these, and pass the rest on
- to the front end. C99 defines three pragmas and says that no macro
- expansion is to be performed on them; whether or not macro
- expansion happens for other pragmas is implementation defined.
- This implementation never macro-expands the text after #pragma. */
-
-/* Sub-handlers for the pragmas needing treatment here.
- They return 1 if the token buffer is to be popped, 0 if not. */
-typedef void (*pragma_cb) PARAMS ((cpp_reader *));
-struct pragma_entry
+/* Lookup a PRAGMA name in a singly-linked CHAIN. Returns the
+ matching entry, or NULL if none is found. The returned entry could
+ be the start of a namespace chain, or a pragma. */
+static struct pragma_entry *
+lookup_pragma_entry (chain, pragma)
+ struct pragma_entry *chain;
+ const cpp_hashnode *pragma;
{
- struct pragma_entry *next;
- const char *name;
- size_t len;
- int isnspace;
- union {
- pragma_cb handler;
- struct pragma_entry *space;
- } u;
-};
+ while (chain && chain->pragma != pragma)
+ chain = chain->next;
-void
-cpp_register_pragma (pfile, space, name, handler)
+ return chain;
+}
+
+/* Create and insert a pragma entry for NAME at the beginning of a
+ singly-linked CHAIN. If handler is NULL, it is a namespace,
+ otherwise it is a pragma and its handler. */
+static struct pragma_entry *
+insert_pragma_entry (pfile, chain, pragma, handler)
cpp_reader *pfile;
- const char *space;
- const char *name;
+ struct pragma_entry **chain;
+ const cpp_hashnode *pragma;
pragma_cb handler;
{
- struct pragma_entry **x, *new;
- size_t len;
-
- x = &pfile->pragmas;
- if (space)
- {
- struct pragma_entry *p = pfile->pragmas;
- len = strlen (space);
- while (p)
- {
- if (p->isnspace && p->len == len && !memcmp (p->name, space, len))
- {
- x = &p->u.space;
- goto found;
- }
- p = p->next;
- }
- cpp_ice (pfile, "unknown #pragma namespace %s", space);
- return;
- }
+ struct pragma_entry *new;
- found:
new = (struct pragma_entry *)
_cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
- new->name = name;
- new->len = strlen (name);
- new->isnspace = 0;
- new->u.handler = handler;
+ new->pragma = pragma;
+ if (handler)
+ {
+ new->is_nspace = 0;
+ new->u.handler = handler;
+ }
+ else
+ {
+ new->is_nspace = 1;
+ new->u.space = NULL;
+ }
- new->next = *x;
- *x = new;
+ new->next = *chain;
+ *chain = new;
+ return new;
}
+/* Register a pragma NAME in namespace SPACE. If SPACE is null, it
+ goes in the global namespace. HANDLER is the handler it will call,
+ which must be non-NULL. */
void
-cpp_register_pragma_space (pfile, space)
+cpp_register_pragma (pfile, space, name, handler)
cpp_reader *pfile;
const char *space;
+ const char *name;
+ pragma_cb handler;
{
- struct pragma_entry *new;
- const struct pragma_entry *p = pfile->pragmas;
- size_t len = strlen (space);
+ struct pragma_entry **chain = &pfile->pragmas;
+ struct pragma_entry *entry;
+ const cpp_hashnode *node;
+
+ if (!handler)
+ abort ();
- while (p)
+ if (space)
{
- if (p->isnspace && p->len == len && !memcmp (p->name, space, len))
- /* Multiple different callers are allowed to register the same
- namespace. */
- return;
- p = p->next;
+ node = cpp_lookup (pfile, U space, strlen (space));
+ entry = lookup_pragma_entry (*chain, node);
+ if (!entry)
+ entry = insert_pragma_entry (pfile, chain, node, NULL);
+ else if (!entry->is_nspace)
+ goto clash;
+ chain = &entry->u.space;
}
- new = (struct pragma_entry *)
- _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
- new->name = space;
- new->len = len;
- new->isnspace = 1;
- new->u.space = 0;
-
- new->next = pfile->pragmas;
- pfile->pragmas = new;
+ /* Check for duplicates. */
+ node = cpp_lookup (pfile, U name, strlen (name));
+ entry = lookup_pragma_entry (*chain, node);
+ if (entry)
+ {
+ if (entry->is_nspace)
+ clash:
+ cpp_ice (pfile,
+ "registering \"%s\" as both a pragma and a pragma namespace",
+ NODE_NAME (node));
+ else if (space)
+ cpp_ice (pfile, "#pragma %s %s is already registered", space, name);
+ else
+ cpp_ice (pfile, "#pragma %s is already registered", name);
+ }
+ else
+ insert_pragma_entry (pfile, chain, node, handler);
}
-
+
+/* Register the pragmas the preprocessor itself handles. */
void
_cpp_init_internal_pragmas (pfile)
cpp_reader *pfile;
{
- /* top level */
+ /* Pragmas in the global namespace. */
cpp_register_pragma (pfile, 0, "poison", do_pragma_poison);
cpp_register_pragma (pfile, 0, "once", do_pragma_once);
- /* GCC namespace */
- cpp_register_pragma_space (pfile, "GCC");
-
+ /* New GCC-specific pragmas should be put in the GCC namespace. */
cpp_register_pragma (pfile, "GCC", "poison", do_pragma_poison);
cpp_register_pragma (pfile, "GCC", "system_header", do_pragma_system_header);
cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency);
}
+/* Pragmata handling. We handle some, and pass the rest on to the
+ front end. C99 defines three pragmas and says that no macro
+ expansion is to be performed on them; whether or not macro
+ expansion happens for other pragmas is implementation defined.
+ This implementation never macro-expands the text after #pragma. */
static void
do_pragma (pfile)
cpp_reader *pfile;
{
- pragma_cb handler = NULL;
- const struct pragma_entry *p;
+ const struct pragma_entry *p = NULL;
const cpp_token *token;
- unsigned int count = 0;
+ unsigned int count = 1;
- p = pfile->pragmas;
pfile->state.prevent_expansion++;
- new_space:
- count++;
token = cpp_get_token (pfile);
if (token->type == CPP_NAME)
{
- const cpp_hashnode *node = token->val.node;
- size_t len = NODE_LEN (node);
-
- while (p)
+ p = lookup_pragma_entry (pfile->pragmas, token->val.node);
+ if (p && p->is_nspace)
{
- if (strlen (p->name) == len
- && !memcmp (p->name, NODE_NAME (node), len))
- {
- if (p->isnspace)
- {
- p = p->u.space;
- goto new_space;
- }
- else
- {
- handler = p->u.handler;
- break;
- }
- }
- p = p->next;
+ count = 2;
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_NAME)
+ p = lookup_pragma_entry (p->u.space, token->val.node);
+ else
+ p = NULL;
}
}
if (pfile->cb.line_change)
(*pfile->cb.line_change)(pfile, token, 1);
- if (handler)
- (*handler) (pfile);
+ if (p)
+ (*p->u.handler) (pfile);
else if (pfile->cb.def_pragma)
{
_cpp_backup_tokens (pfile, count);
(*pfile->cb.def_pragma) (pfile, pfile->directive_line);
}
+
pfile->state.prevent_expansion--;
}
+/* Handle #pragma once. */
static void
do_pragma_once (pfile)
cpp_reader *pfile;
check_eol (pfile);
}
+/* Handle #pragma poison, to poison one or more identifiers so that
+ the lexer produces a hard error for each subsequent usage. */
static void
do_pragma_poison (pfile)
cpp_reader *pfile;
{
- /* Poison these symbols so that all subsequent usage produces an
- error message. */
const cpp_token *tok;
cpp_hashnode *hp;
return string;
}
-/* Returns a malloced buffer containing a destringized cpp_string by
- removing the first \ of \" and \\ sequences. */
-static unsigned char *
-destringize (in, len)
+/* Destringize IN into a temporary buffer, by removing the first \ of
+ \" and \\ sequences, and process the result as a #pragma directive. */
+static void
+destringize_and_run (pfile, in)
+ cpp_reader *pfile;
const cpp_string *in;
- unsigned int *len;
{
const unsigned char *src, *limit;
- unsigned char *dest, *result;
+ char *dest, *result;
- dest = result = (unsigned char *) xmalloc (in->len);
+ dest = result = alloca (in->len + 1);
for (src = in->text, limit = src + in->len; src < limit;)
{
/* We know there is a character following the backslash. */
src++;
*dest++ = *src++;
}
+ *dest = '\0';
- *len = dest - result;
- return result;
+ run_directive (pfile, T_PRAGMA, result, dest - result);
}
+/* Handle the _Pragma operator. */
void
_cpp_do__Pragma (pfile)
cpp_reader *pfile;
{
const cpp_token *string = get__Pragma_string (pfile);
- unsigned char *buffer;
- unsigned int len;
if (!string)
cpp_error (pfile, "_Pragma takes a parenthesized string literal");
Getting these correct line markers is a little tricky. */
unsigned int orig_line = pfile->line;
- buffer = destringize (&string->val.str, &len);
- run_directive (pfile, T_PRAGMA, (char *) buffer, len);
- free ((PTR) buffer);
+ destringize_and_run (pfile, &string->val.str);
pfile->line = orig_line;
pfile->buffer->saved_flags = BOL;
}
}
#endif
+/* Handle #ifdef. */
static void
do_ifdef (pfile)
cpp_reader *pfile;
push_conditional (pfile, skip, T_IFDEF, 0);
}
+/* Handle #ifndef. */
static void
do_ifndef (pfile)
cpp_reader *pfile;
optimisations. If macro expansion occurs in the expression, we
cannot treat it as a controlling conditional, since the expansion
could change in the future. That is handled by cpp_get_token. */
-
static void
do_if (pfile)
cpp_reader *pfile;
/* Flip skipping state if appropriate and continue without changing
if_stack; this is so that the error message for missing #endif's
etc. will point to the original #if. */
-
static void
do_else (pfile)
cpp_reader *pfile;
}
}
-/* handle a #elif directive by not changing if_stack either. see the
+/* Handle a #elif directive by not changing if_stack either. See the
comment above do_else. */
-
static void
do_elif (pfile)
cpp_reader *pfile;
}
/* #endif pops the if stack and resets pfile->state.skipping. */
-
static void
do_endif (pfile)
cpp_reader *pfile;
}
}
-/* Push an if_stack entry and set pfile->state.skipping accordingly.
- If this is a #if or #ifndef, CMACRO is a potentially controlling
- macro - we need to check here that we are at the top of the file. */
-
+/* Push an if_stack entry for a preprocessor conditional, and set
+ pfile->state.skipping to SKIP. If TYPE indicates the conditional
+ is #if or #ifndef, CMACRO is a potentially controlling macro, and
+ we need to check here that we are at the top of the file. */
static void
push_conditional (pfile, skip, type, cmacro)
cpp_reader *pfile;
buffer->if_stack = ifs;
}
-/* Read the tokens of the answer into the macro pool. Only commit the
- memory if we intend it as permanent storage, i.e. the #assert case.
- Returns 0 on success. */
-
+/* Read the tokens of the answer into the macro pool, in a directive
+ of type TYPE. Only commit the memory if we intend it as permanent
+ storage, i.e. the #assert case. Returns 0 on success, and sets
+ ANSWERP to point to the answer. */
static int
parse_answer (pfile, answerp, type)
cpp_reader *pfile;
return 0;
}
-/* Parses an assertion, returning a pointer to the hash node of the
- predicate, or 0 on error. If an answer was supplied, it is placed
- in ANSWERP, otherwise it is set to 0. */
+/* Parses an assertion directive of type TYPE, returning a pointer to
+ the hash node of the predicate, or 0 on error. If an answer was
+ supplied, it is placed in ANSWERP, otherwise it is set to 0. */
static cpp_hashnode *
parse_assertion (pfile, answerp, type)
cpp_reader *pfile;
return result;
}
-/* Returns a pointer to the pointer to the answer in the answer chain,
+/* Returns a pointer to the pointer to CANDIDATE in the answer chain,
or a pointer to NULL if the answer is not in the chain. */
static struct answer **
find_answer (node, candidate)
return node == 0;
}
+/* Handle #assert. */
static void
do_assert (pfile)
cpp_reader *pfile;
}
}
+/* Handle #unassert. */
static void
do_unassert (pfile)
cpp_reader *pfile;
If STR is just an identifier, define it with value 1.
If STR has anything after the identifier, then it should
be identifier=definition. */
-
void
cpp_define (pfile, str)
cpp_reader *pfile;
Change the first "=" in the string to a space. If there is none,
tack " 1" on the end. */
- /* Length including the null. */
count = strlen (str);
- buf = (char *) alloca (count + 2);
+ buf = (char *) alloca (count + 3);
memcpy (buf, str, count);
p = strchr (str, '=');
buf[count++] = ' ';
buf[count++] = '1';
}
+ buf[count] = '\0';
run_directive (pfile, T_DEFINE, buf, count);
}
{
/* Copy the entire option so we can modify it. Change the first
"=" in the string to a '(', and tack a ')' on the end. */
- char *buf = (char *) alloca (count + 1);
+ char *buf = (char *) alloca (count + 2);
memcpy (buf, str, count);
buf[p - str] = '(';
buf[count++] = ')';
+ buf[count] = '\0';
str = buf;
}
new->line_base = new->buf = new->cur = buffer;
new->rlimit = buffer + len;
-
- /* No read ahead or extra char initially. */
- new->read_ahead = EOF;
- new->extra_char = EOF;
new->from_stage3 = from_stage3;
new->prev = pfile->buffer;
new->return_at_eof = return_at_eof;
{
cpp_buffer *buffer = pfile->buffer;
struct if_stack *ifs;
+ bool pushed = false;
/* Walk back up the conditional stack till we reach its level at
entry to this file, issuing error messages. */
pfile->buffer = buffer->prev;
if (buffer->inc)
- _cpp_pop_file_buffer (pfile, buffer->inc);
+ pushed = _cpp_pop_file_buffer (pfile, buffer->inc);
- obstack_free (&pfile->buffer_ob, buffer);
+ if (!pushed)
+ obstack_free (&pfile->buffer_ob, buffer);
}
+/* Enter all recognised directives in the hash table. */
void
_cpp_init_directives (pfile)
cpp_reader *pfile;
unsigned int i;
cpp_hashnode *node;
- /* Register the directives. */
for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
{
node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);