Disentangling control flow inside the macro expander
Zack Weinberg
zack@wolery.cumb.org
Tue Jul 11 16:16:00 GMT 2000
This patch shuffles the control flow around a bit inside the macro
expander. Formerly we had six core routines engaged in mutual
recursion, plus all the directive handlers and their subroutines. So
you would get this huge cycle in profiling output:
[4] 91.5 0.94 14.47 1094600+8143500 <cycle 1 as a whole> [4]
0.25 8.51 3120900 cpp_get_token <cycle 1> [5]
0.01 0.42 126000 push_macro_context <cycle 1> [36]
0.19 0.02 3087800 maybe_paste_with_next <cycle 1> [55]
0.01 0.22 78500 parse_arg <cycle 1> [51]
0.01 0.00 129900 is_macro_disabled <cycle 1> [125]
0.01 0.00 46600 parse_args <cycle 1> [133]
0.15 0.11 563100 process_directive <cycle 1> [46]
0.00 1.57 9700 do_include <cycle 1> [18]
0.03 0.02 81400 do_ifndef <cycle 1> [81]
0.02 0.01 55900 do_if <cycle 1> [91]
0.03 0.00 149700 do_define <cycle 1> [95]
0.00 0.01 22100 do_undef <cycle 1> [121]
0.00 0.01 46700 do_ifdef <cycle 1> [127]
0.00 0.00 300 do_elif <cycle 1> [198]
0.03 0.04 780400 _cpp_get_raw_token <cycle 1> [72]
0.01 3.49 149700 parse_define <cycle 1> [12]
0.06 0.00 37900 _cpp_parse_expr <cycle 1> [77]
0.04 0.00 89700 parse_defined <cycle 1> [85]
0.03 0.00 171800 get_define_node <cycle 1> [94]
0.02 0.00 149700 _cpp_create_definition <cycle 1> [99]
0.02 0.00 273800 lex <cycle 1> [105]
0.02 0.00 56400 parse_ifdef <cycle 1> [107]
0.00 0.00 9900 parse_include <cycle 1> [192]
I've shuffled this around - the top block is the lexer proper, the
second block is the directives, and the third their subroutines. You
can imagine how confusing it was when it was all one big thing sorted
by time in "children".
With this patch, the cycle is limited to the code that actually needs
mutual recursion. Hopefully we can get rid of a bit more in the
future.
[6] 56.6 0.37 4.08 1483184+3901043 <cycle 1 as a whole> [6]
0.13 3.74 2019716 get_raw_token <cycle 1> [7]
0.02 0.21 56363 push_macro_context <cycle 1> [43]
0.13 0.01 1707945 _cpp_get_token <cycle 1> [54]
0.01 0.10 35304 parse_arg <cycle 1> [60]
0.07 0.01 1485258 maybe_paste_with_next <cycle 1> [71]
0.01 0.00 21543 parse_args <cycle 1> [115]
0.00 0.00 58081 is_macro_disabled <cycle 1> [164]
Profiling is easier, reading the code in cpplex.c is easier,
and as a convenient side effect PLACEMARKER tokens are no longer
returned by the public interface.
This patch also includes a modified version of Donn Terry's patch to
initialize the base context properly.
zw
2000-07-11 Zack Weinberg <zack@wolery.cumb.org>
* cpplex.c (parse_name): No longer inline (premature optimization).
(do_pop_context): Fold into pop_context.
(pop_context): Returns int.
(lex_next): Hoist test for end of directive into pop_context.
(push_macro_context): Returns int; takes just reader and token.
Hoist test for excessive nesting to caller.
(push_arg_context): Returns void; takes just reader and token.
Do not call stringify_arg or get_raw_token.
(get_raw_token): Convert tail recursion through push_arg_context
to a loop at this level. Call stringify_arg here if appropriate.
(maybe_paste_with_next): Convert tail recursion to a while loop.
Hoist test of paste_level to caller.
(stringify_arg): Push arg context at beginning.
(cpp_get_token): Split out core into _cpp_get_token. Call
process_directive here. Throw away CPP_PLACEMARKER tokens.
(_cpp_get_token): Convert tail recursion through
push_macro_context to a loop at this level.
(_cpp_glue_header_name, is_macro_disabled, stringify_arg,
_cpp_get_raw_token): Use _cpp_get_token.
(_cpp_skip_rest_of_line): Drop the context stack directly; do
not call pop_context.
(_cpp_run_directive): Call lex_next directly.
* cpphash.h: Prototype _cpp_get_token.
* cppexp.c (lex): Use it.
* cpphash.c (parse_define): Use it.
* cpplex.c
* cpplib.c (get_define_node, do_undef, parse_include,
read_line_number, do_line, do_ident, do_pragma, do_pragma_gcc,
do_pragma_implementation, do_pragma_poison, do_pragma_dependency,
parse_ifdef, validate_else): Use it.
(cpp_push_buffer): Tweak error message; abort if anyone tries
to push a buffer while macro expansions are stacked.
2000-07-11 Donn Terry <donnte@microsoft.com>
* cpplex.c (free_macro_args, save_token): Cast arg of free
and/or xrealloc to PTR.
(_cpp_init_input_buffer): Clear all fields of the base context.
===================================================================
Index: cppexp.c
--- cppexp.c 2000/07/09 20:44:51 1.65
+++ cppexp.c 2000/07/11 22:42:26
@@ -392,7 +392,7 @@ lex (pfile, skip_evaluation)
const cpp_token *tok;
retry:
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
switch (tok->type)
{
===================================================================
Index: cpphash.c
--- cpphash.c 2000/07/08 19:00:38 1.97
+++ cpphash.c 2000/07/11 22:42:26
@@ -354,7 +354,7 @@ parse_define (pfile)
int prev_white = 0;
/* The first token after the macro's name. */
- token = cpp_get_token (pfile);
+ token = _cpp_get_token (pfile);
/* Constraint 6.10.3.5 */
if (is__va_args__ (pfile, token - 1))
===================================================================
Index: cpphash.h
--- cpphash.h 2000/07/09 09:19:44 1.61
+++ cpphash.h 2000/07/11 22:42:26
@@ -256,6 +256,7 @@ extern void _cpp_run_directive PARAMS (
const char *, size_t));
extern unsigned int _cpp_get_line PARAMS ((cpp_reader *,
unsigned int *));
+extern const cpp_token *_cpp_get_token PARAMS ((cpp_reader *));
extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *));
extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*));
extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *));
===================================================================
Index: cpplex.c
--- cpplex.c 2000/07/11 14:28:09 1.68
+++ cpplex.c 2000/07/11 22:42:27
@@ -417,7 +417,7 @@ _cpp_glue_header_name (pfile)
for (;;)
{
- t = cpp_get_token (pfile);
+ t = _cpp_get_token (pfile);
if (t->type == CPP_GREATER || t->type == CPP_EOF)
break;
@@ -947,7 +947,7 @@ skip_whitespace (pfile, in_directive)
}
/* Parse (append) an identifier. */
-static inline const U_CHAR *
+static const U_CHAR *
parse_name (pfile, tok, cur, rlimit)
cpp_reader *pfile;
cpp_token *tok;
@@ -1960,7 +1960,7 @@ struct cpp_context
const cpp_token **arg; /* Used for arg contexts only. */
} u;
- /* Pushed token to be returned by next call to cpp_get_token. */
+ /* Pushed token to be returned by next call to get_raw_token. */
const cpp_token *pushed_token;
struct macro_args *args; /* 0 for arguments and object-like macros. */
@@ -1985,13 +1985,9 @@ static const cpp_token *parse_arg PARAMS
macro_args *, unsigned int *));
static int parse_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_args *));
static void save_token PARAMS ((macro_args *, const cpp_token *));
-static const cpp_token *push_arg_context PARAMS ((cpp_reader *,
- const cpp_token *));
-static int do_pop_context PARAMS ((cpp_reader *));
-static const cpp_token *pop_context PARAMS ((cpp_reader *));
-static const cpp_token *push_macro_context PARAMS ((cpp_reader *,
- cpp_hashnode *,
- const cpp_token *));
+static int pop_context PARAMS ((cpp_reader *));
+static int push_macro_context PARAMS ((cpp_reader *, const cpp_token *));
+static void push_arg_context PARAMS ((cpp_reader *, const cpp_token *));
static void free_macro_args PARAMS ((macro_args *));
/* Free the storage allocated for macro arguments. */
@@ -2000,7 +1996,7 @@ free_macro_args (args)
macro_args *args;
{
if (args->tokens)
- free (args->tokens);
+ free ((PTR) args->tokens);
free (args->ends);
free (args);
}
@@ -2069,7 +2065,7 @@ is_macro_disabled (pfile, expansion, tok
prev_nme = pfile->no_expand_level;
pfile->no_expand_level = context - pfile->contexts;
- next = cpp_get_token (pfile);
+ next = _cpp_get_token (pfile);
restore_macro_expansion (pfile, prev_nme);
if (next->type != CPP_OPEN_PAREN)
{
@@ -2096,7 +2092,8 @@ save_token (args, token)
{
args->capacity += args->capacity + 100;
args->tokens = (const cpp_token **)
- xrealloc (args->tokens, args->capacity * sizeof (const cpp_token *));
+ xrealloc ((PTR) args->tokens,
+ args->capacity * sizeof (const cpp_token *));
}
args->tokens[args->used++] = token;
}
@@ -2117,7 +2114,7 @@ parse_arg (pfile, var_args, paren_contex
for (count = 0;; count++)
{
- token = cpp_get_token (pfile);
+ token = _cpp_get_token (pfile);
switch (token->type)
{
@@ -2511,97 +2508,100 @@ maybe_paste_with_next (pfile, token)
cpp_context *context = CURRENT_CONTEXT (pfile);
/* Is this token on the LHS of ## ? */
- if (!((context->flags & CONTEXT_PASTEL) && context->posn == context->count)
- && !(token->flags & PASTE_LEFT))
- return token;
- /* Prevent recursion, and possibly pushing back more than one token. */
- if (pfile->paste_level)
- return token;
-
- /* Suppress macro expansion for next token, but don't conflict with
- the other method of suppression. If it is an argument, macro
- expansion within the argument will still occur. */
- pfile->paste_level = pfile->cur_context;
- second = cpp_get_token (pfile);
- pfile->paste_level = 0;
-
- /* Ignore placemarker argument tokens (cannot be from an empty macro
- since macros are not expanded). */
- if (token->type == CPP_PLACEMARKER)
- pasted = duplicate_token (pfile, second);
- else if (second->type == CPP_PLACEMARKER)
- {
- cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
- /* GCC has special extended semantics for a ## b where b is a
- varargs parameter: a disappears if b consists of no tokens.
- This extension is deprecated. */
- if ((mac_context->u.list->flags & GNU_REST_ARGS)
- && (mac_context->u.list->tokens[mac_context->posn - 1].val.aux + 1
- == (unsigned) mac_context->u.list->paramc))
+ while ((token->flags & PASTE_LEFT)
+ || ((context->flags & CONTEXT_PASTEL)
+ && context->posn == context->count))
+ {
+ /* Suppress macro expansion for next token, but don't conflict
+ with the other method of suppression. If it is an argument,
+ macro expansion within the argument will still occur. */
+ pfile->paste_level = pfile->cur_context;
+ second = _cpp_get_token (pfile);
+ pfile->paste_level = 0;
+
+ /* Ignore placemarker argument tokens (cannot be from an empty
+ macro since macros are not expanded). */
+ if (token->type == CPP_PLACEMARKER)
+ pasted = duplicate_token (pfile, second);
+ else if (second->type == CPP_PLACEMARKER)
{
- cpp_warning (pfile, "deprecated GNU ## extension used");
- pasted = duplicate_token (pfile, second);
+ cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
+ /* GCC has special extended semantics for a ## b where b is
+ a varargs parameter: a disappears if b consists of no
+ tokens. This extension is deprecated. */
+ if ((mac_context->u.list->flags & GNU_REST_ARGS)
+ && (mac_context->u.list->tokens[mac_context->posn-1].val.aux + 1
+ == (unsigned) mac_context->u.list->paramc))
+ {
+ cpp_warning (pfile, "deprecated GNU ## extension used");
+ pasted = duplicate_token (pfile, second);
+ }
+ else
+ pasted = duplicate_token (pfile, token);
}
else
- pasted = duplicate_token (pfile, token);
- }
- else
- {
- int digraph = 0;
- enum cpp_ttype type = can_paste (pfile, token, second, &digraph);
-
- if (type == CPP_EOF)
{
- if (CPP_OPTION (pfile, warn_paste))
- cpp_warning (pfile,
- "pasting would not give a valid preprocessing token");
- _cpp_push_token (pfile, second);
- return token;
- }
+ int digraph = 0;
+ enum cpp_ttype type = can_paste (pfile, token, second, &digraph);
- if (type == CPP_NAME || type == CPP_NUMBER)
- {
- /* Join spellings. */
- U_CHAR *buf, *end;
+ if (type == CPP_EOF)
+ {
+ if (CPP_OPTION (pfile, warn_paste))
+ cpp_warning (pfile,
+ "pasting would not give a valid preprocessing token");
+ _cpp_push_token (pfile, second);
+ return token;
+ }
+
+ if (type == CPP_NAME || type == CPP_NUMBER)
+ {
+ /* Join spellings. */
+ U_CHAR *buf, *end;
- pasted = get_temp_token (pfile);
- buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
- end = spell_token (pfile, token, buf);
- end = spell_token (pfile, second, end);
- *end = '\0';
+ pasted = get_temp_token (pfile);
+ buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
+ end = spell_token (pfile, token, buf);
+ end = spell_token (pfile, second, end);
+ *end = '\0';
- if (type == CPP_NAME)
- pasted->val.node = cpp_lookup (pfile, buf, end - buf);
+ if (type == CPP_NAME)
+ pasted->val.node = cpp_lookup (pfile, buf, end - buf);
+ else
+ {
+ pasted->val.str.text = uxstrdup (buf);
+ pasted->val.str.len = end - buf;
+ }
+ }
+ else if (type == CPP_WCHAR || type == CPP_WSTRING)
+ pasted = duplicate_token (pfile, second);
else
{
- pasted->val.str.text = uxstrdup (buf);
- pasted->val.str.len = end - buf;
+ pasted = get_temp_token (pfile);
+ pasted->val.integer = 0;
}
- }
- else if (type == CPP_WCHAR || type == CPP_WSTRING)
- pasted = duplicate_token (pfile, second);
- else
- {
- pasted = get_temp_token (pfile);
- pasted->val.integer = 0;
+
+ pasted->type = type;
+ pasted->flags = digraph ? DIGRAPH : 0;
}
- pasted->type = type;
- pasted->flags = digraph ? DIGRAPH : 0;
+ /* The pasted token gets the whitespace flags and position of the
+ first token, the PASTE_LEFT flag of the second token, plus the
+ PASTED flag to indicate it is the result of a paste. However, we
+ want to preserve the DIGRAPH flag. */
+ pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT);
+ pasted->flags |= ((token->flags & (PREV_WHITE | BOL))
+ | (second->flags & PASTE_LEFT) | PASTED);
+ pasted->col = token->col;
+ pasted->line = token->line;
+
+ /* See if there is another token to be pasted onto the one we just
+ constructed. */
+ token = pasted;
+ context = CURRENT_CONTEXT (pfile);
+ /* and loop */
}
-
- /* The pasted token gets the whitespace flags and position of the
- first token, the PASTE_LEFT flag of the second token, plus the
- PASTED flag to indicate it is the result of a paste. However, we
- want to preserve the DIGRAPH flag. */
- pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT);
- pasted->flags |= ((token->flags & (PREV_WHITE | BOL))
- | (second->flags & PASTE_LEFT) | PASTED);
- pasted->col = token->col;
- pasted->line = token->line;
-
- return maybe_paste_with_next (pfile, pasted);
+ return token;
}
/* Convert a token sequence to a single string token according to the
@@ -2617,13 +2617,14 @@ stringify_arg (pfile, token)
unsigned int prev_value, backslash_count = 0;
unsigned int buf_used = 0, whitespace = 0, buf_cap = INIT_SIZE;
+ push_arg_context (pfile, token);
prev_value = prevent_macro_expansion (pfile);
main_buf = (unsigned char *) xmalloc (buf_cap);
result = get_temp_token (pfile);
ASSIGN_FLAGS_AND_POS (result, token);
- for (; (token = cpp_get_token (pfile))->type != CPP_EOF; )
+ for (; (token = _cpp_get_token (pfile))->type != CPP_EOF; )
{
int escape;
unsigned char *buf;
@@ -2690,22 +2691,16 @@ expand_context_stack (pfile)
/* Push the context of macro NODE onto the context stack. TOKEN is
the CPP_NAME token invoking the macro. */
-static const cpp_token *
-push_macro_context (pfile, node, token)
+static int
+push_macro_context (pfile, token)
cpp_reader *pfile;
- cpp_hashnode *node;
const cpp_token *token;
{
unsigned char orig_flags;
macro_args *args;
cpp_context *context;
+ cpp_hashnode *node = token->val.node;
- if (pfile->cur_context > CPP_STACK_MAX)
- {
- cpp_error (pfile, "infinite macro recursion invoking '%s'", node->name);
- return token;
- }
-
/* Token's flags may change when parsing args containing a nested
invocation of this macro. */
orig_flags = token->flags & (PREV_WHITE | BOL);
@@ -2731,7 +2726,7 @@ push_macro_context (pfile, node, token)
if (error)
{
free_macro_args (args);
- return token;
+ return 1;
}
}
@@ -2753,12 +2748,12 @@ push_macro_context (pfile, node, token)
be one, empty macros are a single placemarker token. */
MODIFY_FLAGS_AND_POS (&context->u.list->tokens[0], token, orig_flags);
- return cpp_get_token (pfile);
+ return 0;
}
/* Push an argument to the current macro onto the context stack.
TOKEN is the MACRO_ARG token representing the argument expansion. */
-static const cpp_token *
+static void
push_arg_context (pfile, token)
cpp_reader *pfile;
const cpp_token *token;
@@ -2792,15 +2787,10 @@ push_arg_context (pfile, token)
token->flags & (PREV_WHITE | BOL));
}
- if (token->flags & STRINGIFY_ARG)
- return stringify_arg (pfile, token);
-
if (token->flags & PASTE_LEFT)
context->flags |= CONTEXT_PASTEL;
if (pfile->paste_level)
context->flags |= CONTEXT_PASTER;
-
- return get_raw_token (pfile);
}
/* "Unget" a token. It is effectively inserted in the token queue and
@@ -2859,58 +2849,92 @@ cpp_get_token (pfile)
cpp_reader *pfile;
{
const cpp_token *token;
- cpp_hashnode *node;
-
- /* Loop till we hit a non-directive, non-skipped, non-placemarker token. */
+ /* Loop till we hit a non-directive, non-placemarker token. */
for (;;)
{
- token = get_raw_token (pfile);
- if (token->flags & BOL && token->type == CPP_HASH
+ token = _cpp_get_token (pfile);
+
+ if (token->type == CPP_PLACEMARKER)
+ continue;
+
+ if (token->type == CPP_HASH && token->flags & BOL
&& pfile->token_list.directive)
{
process_directive (pfile, token);
continue;
}
+ return token;
+ }
+}
+
+/* The internal interface to return the next token. There are two
+ differences between the internal and external interfaces: the
+ internal interface may return a PLACEMARKER token, and it does not
+ process directives. */
+const cpp_token *
+_cpp_get_token (pfile)
+ cpp_reader *pfile;
+{
+ const cpp_token *token;
+ cpp_hashnode *node;
+
+ /* Loop until we hit a non-macro token. */
+ for (;;)
+ {
+ token = get_raw_token (pfile);
+
/* Short circuit EOF. */
if (token->type == CPP_EOF)
return token;
-
- if (pfile->skipping && ! pfile->token_list.directive)
+
+ /* If we are skipping... */
+ if (pfile->skipping)
{
+ /* we still have to process directives, */
+ if (pfile->token_list.directive)
+ return token;
+
+ /* but everything else is ignored. */
_cpp_skip_rest_of_line (pfile);
continue;
}
- break;
- }
-
- /* If there's a potential control macro and we get here, then that
- #ifndef didn't cover the entire file and its argument shouldn't
- be taken as a control macro. */
- pfile->potential_control_macro = 0;
-
- token = maybe_paste_with_next (pfile, token);
- if (token->type != CPP_NAME)
- return token;
+ /* If there's a potential control macro and we get here, then that
+ #ifndef didn't cover the entire file and its argument shouldn't
+ be taken as a control macro. */
+ pfile->potential_control_macro = 0;
+
+ /* See if there's a token to paste with this one. */
+ if (!pfile->paste_level)
+ token = maybe_paste_with_next (pfile, token);
+
+ /* If it isn't a macro, return it now. */
+ if (token->type != CPP_NAME
+ || token->val.node->type == T_VOID)
+ return token;
- /* Is macro expansion disabled in general? */
- if (pfile->no_expand_level == pfile->cur_context || pfile->paste_level)
- return token;
+ /* Is macro expansion disabled in general? */
+ if (pfile->no_expand_level == pfile->cur_context || pfile->paste_level)
+ return token;
- node = token->val.node;
- if (node->type == T_VOID)
- return token;
+ node = token->val.node;
+ if (node->type != T_MACRO)
+ return special_symbol (pfile, node, token);
- if (node->type == T_MACRO)
- {
if (is_macro_disabled (pfile, node->value.expansion, token))
return token;
- return push_macro_context (pfile, node, token);
+ if (pfile->cur_context > CPP_STACK_MAX)
+ {
+ cpp_error (pfile, "macros nested too deep invoking '%s'", node->name);
+ return token;
+ }
+
+ if (push_macro_context (pfile, token))
+ return token;
+ /* else loop */
}
- else
- return special_symbol (pfile, node, token);
}
/* Returns the next raw token, i.e. without performing macro
@@ -2920,33 +2944,45 @@ get_raw_token (pfile)
cpp_reader *pfile;
{
const cpp_token *result;
- cpp_context *context = CURRENT_CONTEXT (pfile);
+ cpp_context *context;
- if (context->pushed_token)
- {
- result = context->pushed_token;
- context->pushed_token = 0;
- }
- else if (context->posn == context->count)
- result = pop_context (pfile);
- else
+ for (;;)
{
- if (IS_ARG_CONTEXT (context))
+ context = CURRENT_CONTEXT (pfile);
+ if (context->pushed_token)
{
- result = context->u.arg[context->posn++];
- if (result == 0)
+ result = context->pushed_token;
+ context->pushed_token = 0;
+ }
+ else if (context->posn == context->count)
+ {
+ if (pop_context (pfile))
+ return &eof_token;
+ continue;
+ }
+ else
+ {
+ if (IS_ARG_CONTEXT (context))
{
- context->flags ^= CONTEXT_RAW;
result = context->u.arg[context->posn++];
+ if (result == 0)
+ {
+ context->flags ^= CONTEXT_RAW;
+ result = context->u.arg[context->posn++];
+ }
+ return result; /* Cannot be a CPP_MACRO_ARG */
}
- return result; /* Cannot be a CPP_MACRO_ARG */
+ result = &context->u.list->tokens[context->posn++];
}
- result = &context->u.list->tokens[context->posn++];
- }
- if (result->type == CPP_MACRO_ARG)
- result = push_arg_context (pfile, result);
- return result;
+ if (result->type != CPP_MACRO_ARG)
+ return result;
+
+ if (result->flags & STRINGIFY_ARG)
+ return stringify_arg (pfile, result);
+
+ push_arg_context (pfile, result);
+ }
}
/* Internal interface to get the token without macro expanding. */
@@ -2955,7 +2991,7 @@ _cpp_get_raw_token (pfile)
cpp_reader *pfile;
{
int prev_nme = prevent_macro_expansion (pfile);
- const cpp_token *result = cpp_get_token (pfile);
+ const cpp_token *result = _cpp_get_token (pfile);
restore_macro_expansion (pfile, prev_nme);
return result;
}
@@ -2973,16 +3009,6 @@ lex_next (pfile, clear)
const cpp_token *old_list = list->tokens;
unsigned int old_used = list->tokens_used;
- /* If we are currently processing a directive, do not advance. 6.10
- paragraph 2: A new-line character ends the directive even if it
- occurs within what would otherwise be an invocation of a
- function-like macro.
-
- It is possible that clear == 1 too; e.g. "#if funlike_macro ("
- since parse_args swallowed the directive's EOF. */
- if (list->directive)
- return 1;
-
if (clear)
{
/* Release all temporary tokens. */
@@ -3034,18 +3060,27 @@ lex_next (pfile, clear)
return 0;
}
-/* Pops a context of the context stack. If we're at the bottom, lexes
- the next logical line. Returns 1 if we're at the end of the
+/* Pops a context off the context stack. If we're at the bottom, lexes
+ the next logical line. Returns EOF if we're at the end of the
argument list to the # operator, or if it is illegal to "overflow"
into the rest of the file (e.g. 6.10.3.1.1). */
static int
-do_pop_context (pfile)
+pop_context (pfile)
cpp_reader *pfile;
{
cpp_context *context;
if (pfile->cur_context == 0)
- return lex_next (pfile, pfile->no_expand_level == UINT_MAX);
+ {
+ /* If we are currently processing a directive, do not advance. 6.10
+ paragraph 2: A new-line character ends the directive even if it
+ occurs within what would otherwise be an invocation of a
+ function-like macro. */
+ if (pfile->token_list.directive)
+ return 1;
+
+ return lex_next (pfile, pfile->no_expand_level == UINT_MAX);
+ }
/* Argument contexts, when parsing args or handling # operator
return CPP_EOF at the end. */
@@ -3064,16 +3099,6 @@ do_pop_context (pfile)
return 0;
}
-/* Move down the context stack, and return the next raw token. */
-static const cpp_token *
-pop_context (pfile)
- cpp_reader *pfile;
-{
- if (do_pop_context (pfile))
- return &eof_token;
- return get_raw_token (pfile);
-}
-
/* Turn off macro expansion at the current context level. */
static unsigned int
prevent_macro_expansion (pfile)
@@ -3286,18 +3311,26 @@ void
_cpp_init_input_buffer (pfile)
cpp_reader *pfile;
{
+ cpp_context *base;
+
init_trigraph_map ();
+ _cpp_init_toklist (&pfile->token_list, DUMMY_TOKEN);
+ pfile->no_expand_level = UINT_MAX;
pfile->context_cap = 20;
- pfile->contexts = (cpp_context *)
- xmalloc (pfile->context_cap * sizeof (cpp_context));
pfile->cur_context = 0;
- pfile->contexts[0].u.list = &pfile->token_list;
- pfile->contexts[0].posn = 0;
- pfile->contexts[0].count = 0;
- pfile->no_expand_level = UINT_MAX;
+ pfile->contexts = (cpp_context *)
+ xmalloc (pfile->context_cap * sizeof (cpp_context));
- _cpp_init_toklist (&pfile->token_list, DUMMY_TOKEN);
+ /* Clear the base context. */
+ base = &pfile->contexts[0];
+ base->u.list = &pfile->token_list;
+ base->posn = 0;
+ base->count = 0;
+ base->args = 0;
+ base->level = 0;
+ base->flags = 0;
+ base->pushed_token = 0;
}
/* Moves to the end of the directive line, popping contexts as
@@ -3306,17 +3339,20 @@ void
_cpp_skip_rest_of_line (pfile)
cpp_reader *pfile;
{
- /* Get to base context. Clear parsing args and each contexts flags,
- since these can cause pop_context to return without popping. */
- pfile->no_expand_level = UINT_MAX;
- while (pfile->cur_context != 0)
- {
- pfile->contexts[pfile->cur_context].flags = 0;
- do_pop_context (pfile);
- }
+ /* Discard all stacked contexts. */
+ int i;
+ for (i = pfile->cur_context; i > 0; i--)
+ if (pfile->contexts[i].args)
+ free_macro_args (pfile->contexts[i].args);
+
+ if (pfile->no_expand_level <= pfile->cur_context)
+ pfile->no_expand_level = 0;
+ pfile->cur_context = 0;
- pfile->contexts[pfile->cur_context].count = 0;
- pfile->contexts[pfile->cur_context].posn = 0;
+ /* Clear the base context, and clear the directive pointer so that
+ get_raw_token will advance to the next line. */
+ pfile->contexts[0].count = 0;
+ pfile->contexts[0].posn = 0;
pfile->token_list.directive = 0;
}
@@ -3332,8 +3368,9 @@ _cpp_run_directive (pfile, dir, buf, cou
if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
{
unsigned int prev_lvl = 0;
- /* scan the line now, else prevent_macro_expansion won't work */
- do_pop_context (pfile);
+
+ /* Scan the line now, else prevent_macro_expansion won't work. */
+ lex_next (pfile, 1);
if (! (dir->flags & EXPAND))
prev_lvl = prevent_macro_expansion (pfile);
===================================================================
Index: cpplib.c
--- cpplib.c 2000/07/08 19:00:39 1.185
+++ cpplib.c 2000/07/11 22:42:27
@@ -250,7 +250,7 @@ get_define_node (pfile)
const cpp_token *token;
/* Skip any -C comments. */
- while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
+ while ((token = _cpp_get_token (pfile))->type == CPP_COMMENT)
;
if (token->type != CPP_NAME)
@@ -307,7 +307,7 @@ do_undef (pfile)
{
cpp_hashnode *node = get_define_node (pfile);
- if (cpp_get_token (pfile)->type != CPP_EOF)
+ if (_cpp_get_token (pfile)->type != CPP_EOF)
cpp_pedwarn (pfile, "junk on line after #undef");
/* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
@@ -343,7 +343,7 @@ parse_include (pfile, dir, trail, strp,
unsigned int *lenp;
int *abp;
{
- const cpp_token *name = cpp_get_token (pfile);
+ const cpp_token *name = _cpp_get_token (pfile);
if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
{
@@ -361,7 +361,7 @@ parse_include (pfile, dir, trail, strp,
return 1;
}
- if (!trail && cpp_get_token (pfile)->type != CPP_EOF)
+ if (!trail && _cpp_get_token (pfile)->type != CPP_EOF)
cpp_error (pfile, "junk at end of #%s", dir);
*lenp = name->val.str.len;
@@ -459,7 +459,7 @@ read_line_number (pfile, num)
cpp_reader *pfile;
int *num;
{
- const cpp_token *tok = cpp_get_token (pfile);
+ const cpp_token *tok = _cpp_get_token (pfile);
enum cpp_ttype type = tok->type;
const U_CHAR *p = tok->val.str.text;
unsigned int len = tok->val.str.len;
@@ -519,7 +519,7 @@ do_line (pfile)
unsigned int len;
const cpp_token *tok;
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
type = tok->type;
str = tok->val.str.text;
len = tok->val.str.len;
@@ -535,7 +535,7 @@ do_line (pfile)
old_lineno = ip->lineno;
ip->lineno = new_lineno;
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
type = tok->type;
str = tok->val.str.text;
len = tok->val.str.len;
@@ -645,9 +645,9 @@ do_ident (pfile)
cpp_reader *pfile;
{
/* Next token should be a string constant. */
- if (cpp_get_token (pfile)->type == CPP_STRING)
+ if (_cpp_get_token (pfile)->type == CPP_STRING)
/* And then a newline. */
- if (cpp_get_token (pfile)->type == CPP_EOF)
+ if (_cpp_get_token (pfile)->type == CPP_EOF)
{
/* Good - ship it. */
pass_thru_directive (pfile);
@@ -725,7 +725,7 @@ do_pragma (pfile)
const cpp_token *tok;
int pop;
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
if (tok->type == CPP_EOF)
return 0;
else if (tok->type != CPP_NAME)
@@ -746,7 +746,7 @@ do_pragma_gcc (pfile)
{
const cpp_token *tok;
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
if (tok->type == CPP_EOF)
return 1;
else if (tok->type != CPP_NAME)
@@ -780,13 +780,13 @@ do_pragma_implementation (pfile)
{
/* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */
- const cpp_token *tok = cpp_get_token (pfile);
+ const cpp_token *tok = _cpp_get_token (pfile);
char *copy;
if (tok->type == CPP_EOF)
return 0;
else if (tok->type != CPP_STRING
- || cpp_get_token (pfile)->type != CPP_EOF)
+ || _cpp_get_token (pfile)->type != CPP_EOF)
{
cpp_error (pfile, "malformed #pragma implementation");
return 1;
@@ -822,7 +822,7 @@ do_pragma_poison (pfile)
for (;;)
{
- tok = cpp_get_token (pfile);
+ tok = _cpp_get_token (pfile);
if (tok->type == CPP_EOF)
break;
if (tok->type != CPP_NAME)
@@ -887,7 +887,7 @@ do_pragma_dependency (pfile)
cpp_warning (pfile, "cannot find source %c%s%c", left, name, right);
else if (ordering > 0)
{
- const cpp_token *msg = cpp_get_token (pfile);
+ const cpp_token *msg = _cpp_get_token (pfile);
cpp_warning (pfile, "current file is older than %c%s%c",
left, name, right);
@@ -974,7 +974,7 @@ parse_ifdef (pfile, name)
enum cpp_ttype type;
const cpp_hashnode *node = 0;
- const cpp_token *token = cpp_get_token (pfile);
+ const cpp_token *token = _cpp_get_token (pfile);
type = token->type;
if (!CPP_TRADITIONAL (pfile))
@@ -983,7 +983,7 @@ parse_ifdef (pfile, name)
cpp_pedwarn (pfile, "#%s with no argument", name);
else if (type != CPP_NAME)
cpp_pedwarn (pfile, "#%s with invalid argument", name);
- else if (cpp_get_token (pfile)->type != CPP_EOF)
+ else if (_cpp_get_token (pfile)->type != CPP_EOF)
cpp_pedwarn (pfile, "garbage at end of #%s", name);
}
@@ -1186,7 +1186,7 @@ validate_else (pfile, directive)
cpp_reader *pfile;
const U_CHAR *directive;
{
- if (CPP_PEDANTIC (pfile) && cpp_get_token (pfile)->type != CPP_EOF)
+ if (CPP_PEDANTIC (pfile) && _cpp_get_token (pfile)->type != CPP_EOF)
cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
}
@@ -1515,8 +1515,13 @@ cpp_push_buffer (pfile, buffer, length)
cpp_buffer *new;
if (++pfile->buffer_stack_depth == CPP_STACK_MAX)
{
- cpp_fatal (pfile, "#include recursion too deep");
+ cpp_fatal (pfile, "#include nested too deep");
return NULL;
+ }
+ if (pfile->cur_context > 0)
+ {
+ cpp_ice (pfile, "buffer pushed with contexts stacked");
+ _cpp_skip_rest_of_line (pfile);
}
new = xobnew (pfile->buffer_ob, cpp_buffer);
More information about the Gcc-patches
mailing list