#include "system.h"
#include "cpplib.h"
#include "internal.h"
+#include "mkdeps.h"
#include "obstack.h"
-/* Chained list of answers to an assertion. */
-struct answer
-{
- struct answer *next;
- unsigned int count;
- cpp_token first[1];
-};
-
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
struct if_stack
{
struct pragma_entry *next;
const cpp_hashnode *pragma; /* Name and length. */
- int is_nspace;
+ bool is_nspace;
+ bool is_internal;
union {
pragma_cb handler;
struct pragma_entry *space;
static struct pragma_entry *insert_pragma_entry (cpp_reader *,
struct pragma_entry **,
const cpp_hashnode *,
- pragma_cb);
+ pragma_cb,
+ bool);
+static void register_pragma (cpp_reader *, const char *, const char *,
+ pragma_cb, bool);
static int count_registered_pragmas (struct pragma_entry *);
static char ** save_registered_pragmas (struct pragma_entry *, char **);
static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *,
/* Setup in-directive state. */
pfile->state.in_directive = 1;
pfile->state.save_comments = 0;
+ pfile->directive_result.type = CPP_PADDING;
/* Some handlers need the position of the # for diagnostics. */
pfile->directive_line = pfile->line_table->highest_line;
const directive *dir = 0;
const cpp_token *dname;
bool was_parsing_args = pfile->state.parsing_args;
+ bool was_discarding_output = pfile->state.discarding_output;
int skip = 1;
+ if (was_discarding_output)
+ pfile->state.prevent_expansion = 0;
+
if (was_parsing_args)
{
if (CPP_OPTION (pfile, pedantic))
pfile->state.parsing_args = 2;
pfile->state.prevent_expansion = 1;
}
+ if (was_discarding_output)
+ pfile->state.prevent_expansion = 1;
return skip;
}
cpp_push_buffer (pfile, (const uchar *) buf, count,
/* from_stage3 */ true);
/* Disgusting hack. */
- if (dir_no == T_PRAGMA)
+ if (dir_no == T_PRAGMA && pfile->buffer->prev)
pfile->buffer->file = pfile->buffer->prev->file;
start_directive (pfile);
/* Undefine a single macro/assertion/whatever. */
static int
-undefine_macros (cpp_reader *pfile, cpp_hashnode *h,
+undefine_macros (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *h,
void *data_p ATTRIBUTE_UNUSED)
{
- switch (h->type)
- {
- case NT_VOID:
- break;
-
- case NT_MACRO:
- if (pfile->cb.undef)
- (*pfile->cb.undef) (pfile, pfile->directive_line, h);
-
- if (CPP_OPTION (pfile, warn_unused_macros))
- _cpp_warn_if_unused_macro (pfile, h, NULL);
-
- /* And fall through.... */
- case NT_ASSERTION:
- _cpp_free_definition (h);
- break;
-
- default:
- abort ();
- }
- h->flags &= ~NODE_POISONED;
+ /* Body of _cpp_free_definition inlined here for speed.
+ Macros and assertions no longer have anything to free. */
+ h->type = NT_VOID;
+ h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED);
return 1;
}
/* 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. */
+ otherwise it is a pragma and its handler. If INTERNAL is true
+ this pragma is being inserted by libcpp itself. */
static struct pragma_entry *
insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain,
- const cpp_hashnode *pragma, pragma_cb handler)
+ const cpp_hashnode *pragma, pragma_cb handler,
+ bool internal)
{
struct pragma_entry *new;
new->u.space = NULL;
}
+ new->is_internal = internal;
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 (cpp_reader *pfile, const char *space, const char *name,
- pragma_cb handler)
+ which must be non-NULL. INTERNAL is true if this is a pragma
+ registered by cpplib itself, false if it is registered via
+ cpp_register_pragma */
+static void
+register_pragma (cpp_reader *pfile, const char *space, const char *name,
+ pragma_cb handler, bool internal)
{
struct pragma_entry **chain = &pfile->pragmas;
struct pragma_entry *entry;
node = cpp_lookup (pfile, U space, strlen (space));
entry = lookup_pragma_entry (*chain, node);
if (!entry)
- entry = insert_pragma_entry (pfile, chain, node, NULL);
+ entry = insert_pragma_entry (pfile, chain, node, NULL, internal);
else if (!entry->is_nspace)
goto clash;
chain = &entry->u.space;
cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
}
else
- insert_pragma_entry (pfile, chain, node, handler);
+ insert_pragma_entry (pfile, chain, node, handler, internal);
+}
+
+/* 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. This function is exported from libcpp. */
+void
+cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
+ pragma_cb handler)
+{
+ register_pragma (pfile, space, name, handler, false);
}
/* Register the pragmas the preprocessor itself handles. */
_cpp_init_internal_pragmas (cpp_reader *pfile)
{
/* Pragmas in the global namespace. */
- cpp_register_pragma (pfile, 0, "once", do_pragma_once);
+ register_pragma (pfile, 0, "once", do_pragma_once, true);
/* 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);
+ register_pragma (pfile, "GCC", "poison", do_pragma_poison, true);
+ register_pragma (pfile, "GCC", "system_header", do_pragma_system_header, true);
+ register_pragma (pfile, "GCC", "dependency", do_pragma_dependency, true);
}
/* Return the number of registered pragmas in PE. */
_cpp_save_pragma_names (cpp_reader *pfile)
{
int ct = count_registered_pragmas (pfile->pragmas);
- char **result = xnewvec (char *, ct);
+ char **result = XNEWVEC (char *, ct);
(void) save_registered_pragmas (pfile->pragmas, result);
return result;
}
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. */
+ This implementation never macro-expands the text after #pragma.
+
+ The library user has the option of deferring execution of
+ #pragmas not handled by cpplib, in which case they are converted
+ to CPP_PRAGMA tokens and inserted into the output stream. */
static void
do_pragma (cpp_reader *pfile)
{
const cpp_token *token, *pragma_token = pfile->cur_token;
unsigned int count = 1;
+ /* Save the current position so that defer_pragmas mode can
+ copy the entire current line to a string. It will not work
+ to use _cpp_backup_tokens as that does not reverse buffer->cur. */
+ const uchar *line_start = CPP_BUFFER (pfile)->cur;
+
pfile->state.prevent_expansion++;
token = cpp_get_token (pfile);
}
}
- if (p)
+ if (p && (p->is_internal || !CPP_OPTION (pfile, defer_pragmas)))
{
/* Since the handler below doesn't get the line number, that it
might need for diagnostics, make sure it has the right
(*pfile->cb.line_change) (pfile, pragma_token, false);
(*p->u.handler) (pfile);
}
+ else if (CPP_OPTION (pfile, defer_pragmas))
+ {
+ /* Squirrel away the pragma text. Pragmas are newline-terminated. */
+ const uchar *line_end;
+ uchar *s;
+ cpp_string body;
+ cpp_token *ptok;
+
+ line_end = ustrchr (line_start, '\n');
+
+ body.len = (line_end - line_start) + 1;
+ s = _cpp_unaligned_alloc (pfile, body.len + 1);
+ memcpy (s, line_start, body.len);
+ s[body.len] = '\0';
+ body.text = s;
+
+ /* Create a CPP_PRAGMA token. */
+ ptok = &pfile->directive_result;
+ ptok->src_loc = pragma_token->src_loc;
+ ptok->type = CPP_PRAGMA;
+ ptok->flags = pragma_token->flags | NO_EXPAND;
+ ptok->val.str = body;
+ }
else if (pfile->cb.def_pragma)
{
_cpp_backup_tokens (pfile, count);
cpp_token *saved_cur_token = pfile->cur_token;
tokenrun *saved_cur_run = pfile->cur_run;
- pfile->context = xnew (cpp_context);
+ pfile->context = XNEW (cpp_context);
pfile->context->macro = 0;
pfile->context->prev = 0;
run_directive (pfile, T_PRAGMA, result, dest - result);
- free (pfile->context);
+ XDELETE (pfile->context);
pfile->context = saved_context;
pfile->cur_token = saved_cur_token;
pfile->cur_run = saved_cur_run;
_cpp_do__Pragma (cpp_reader *pfile)
{
const cpp_token *string = get__Pragma_string (pfile);
+ pfile->directive_result.type = CPP_PADDING;
if (string)
destringize_and_run (pfile, &string->val.str);
"_Pragma takes a parenthesized string literal");
}
+/* Handle a pragma that the front end deferred until now. */
+void
+cpp_handle_deferred_pragma (cpp_reader *pfile, const cpp_string *s)
+{
+ cpp_context *saved_context = pfile->context;
+ cpp_token *saved_cur_token = pfile->cur_token;
+ tokenrun *saved_cur_run = pfile->cur_run;
+ bool saved_defer_pragmas = CPP_OPTION (pfile, defer_pragmas);
+ void (*saved_line_change) (cpp_reader *, const cpp_token *, int)
+ = pfile->cb.line_change;
+
+ pfile->context = XNEW (cpp_context);
+ pfile->context->macro = 0;
+ pfile->context->prev = 0;
+ pfile->cb.line_change = NULL;
+ CPP_OPTION (pfile, defer_pragmas) = false;
+
+ run_directive (pfile, T_PRAGMA, s->text, s->len);
+
+ XDELETE (pfile->context);
+ pfile->context = saved_context;
+ pfile->cur_token = saved_cur_token;
+ pfile->cur_run = saved_cur_run;
+ pfile->cb.line_change = saved_line_change;
+ CPP_OPTION (pfile, defer_pragmas) = saved_defer_pragmas;
+}
+
/* Ignore #sccs on all systems. */
static void
do_sccs (cpp_reader *pfile ATTRIBUTE_UNUSED)
struct if_stack *ifs;
cpp_buffer *buffer = pfile->buffer;
- ifs = xobnew (&pfile->buffer_ob, struct if_stack);
+ ifs = XOBNEW (&pfile->buffer_ob, struct if_stack);
ifs->line = pfile->directive_line;
ifs->next = buffer->if_stack;
ifs->skip_elses = pfile->state.skipping || !skip;
node = parse_assertion (pfile, &new_answer, T_ASSERT);
if (node)
{
+ size_t answer_size;
+
/* Place the new answer in the answer list. First check there
is not a duplicate. */
new_answer->next = 0;
new_answer->next = node->value.answers;
}
+ answer_size = sizeof (struct answer) + ((new_answer->count - 1)
+ * sizeof (cpp_token));
+ /* Commit or allocate storage for the object. */
+ if (pfile->hash_table->alloc_subobject)
+ {
+ struct answer *temp_answer = new_answer;
+ new_answer = pfile->hash_table->alloc_subobject (answer_size);
+ memcpy (new_answer, temp_answer, answer_size);
+ }
+ else
+ BUFF_FRONT (pfile->a_buff) += answer_size;
+
node->type = NT_ASSERTION;
node->value.answers = new_answer;
- BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer)
- + (new_answer->count - 1)
- * sizeof (cpp_token));
check_eol (pfile);
}
}
pfile->cb = *cb;
}
+/* The dependencies structure. (Creates one if it hasn't already been.) */
+struct deps *
+cpp_get_deps (cpp_reader *pfile)
+{
+ if (!pfile->deps)
+ pfile->deps = deps_init ();
+ return pfile->deps;
+}
+
/* Push a new buffer on the buffer stack. Returns the new buffer; it
doesn't fail. It does not generate a file change call back; that
is the responsibility of the caller. */
cpp_push_buffer (cpp_reader *pfile, const uchar *buffer, size_t len,
int from_stage3)
{
- cpp_buffer *new = xobnew (&pfile->buffer_ob, cpp_buffer);
+ cpp_buffer *new = XOBNEW (&pfile->buffer_ob, cpp_buffer);
/* Clears, amongst other things, if_stack and mi_cmacro. */
memset (new, 0, sizeof (cpp_buffer));