* cpphash.h (_cpp_create_definition): Update prototype.
(_cpp_push_text_context, _cpp_create_trad_definition): New.
( cpp_lex_identifier_trad): New.
(_cpp_set_trad_context): New.
* cppinit.c (cpp_finish_options): Don't conditionalize builtins.
* cpplib.c (SEEN_EOL): Update.
(lex_macro_node): Update for -traditional.
(cpp_push_buffer, _cpp_pop_buffer): Similarly.
* cppmacro.c (_cpp_create_definition): Split into
create_iso_definition() and _cpp_create_trad_definition().
(warn_of_redefinition): Update prototype; handle traditional
macros.
(_cpp_push_text_context): New.
* cpptrad.c (skip_whitespace, push_replacement_text): New.
(lex_identifier): Call ht_lookup with correct start.
(_cpp_lex_identifier_tradm _cpp_create_trad_definition,
_cpp_set_trad_context): New.
(scan_out_logical_line): Update to handle changing contexts.
From-SVN: r54293
+2002-06-05 Neil Booth <neil@daikokuya.demon.co.uk>
+
+ * cpphash.h (_cpp_create_definition): Update prototype.
+ (_cpp_push_text_context, _cpp_create_trad_definition): New.
+ ( cpp_lex_identifier_trad): New.
+ (_cpp_set_trad_context): New.
+ * cppinit.c (cpp_finish_options): Don't conditionalize builtins.
+ * cpplib.c (SEEN_EOL): Update.
+ (lex_macro_node): Update for -traditional.
+ (cpp_push_buffer, _cpp_pop_buffer): Similarly.
+ * cppmacro.c (_cpp_create_definition): Split into
+ create_iso_definition() and _cpp_create_trad_definition().
+ (warn_of_redefinition): Update prototype; handle traditional
+ macros.
+ (_cpp_push_text_context): New.
+ * cpptrad.c (skip_whitespace, push_replacement_text): New.
+ (lex_identifier): Call ht_lookup with correct start.
+ (_cpp_lex_identifier_tradm _cpp_create_trad_definition,
+ _cpp_set_trad_context): New.
+ (scan_out_logical_line): Update to handle changing contexts.
+
Wed Jun 5 20:42:31 2002 J"orn Rennecke <joern.rennecke@superh.com>
* config.gcc (sh-*-elf*, sh64*-*-elf*): Unify.
/* In cppmacro.c */
extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
-extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
+extern bool _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
extern void _cpp_pop_context PARAMS ((cpp_reader *));
+extern void _cpp_push_text_context PARAMS ((cpp_reader *, cpp_hashnode *,
+ const uchar *, const uchar*));
+extern bool _cpp_create_trad_definition PARAMS ((cpp_reader *, cpp_macro *));
/* In cpphash.c */
extern void _cpp_init_hashtable PARAMS ((cpp_reader *, hash_table *));
extern bool _cpp_read_logical_line_trad PARAMS ((cpp_reader *));
extern void _cpp_overlay_buffer PARAMS ((cpp_reader *pfile, const uchar *,
size_t));
+extern cpp_hashnode *_cpp_lex_identifier_trad PARAMS ((cpp_reader *));
+extern void _cpp_set_trad_context PARAMS ((cpp_reader *));
/* Utility routines and macros. */
#define DSC(str) (const uchar *)str, sizeof str - 1
struct pending_option *p;
_cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
- if (!CPP_OPTION (pfile, traditional) /* REMOVEME */)
- init_builtins (pfile);
+ init_builtins (pfile);
_cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
- if (!CPP_OPTION (pfile, traditional) /* REMOVEME */)
- for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
- (*p->handler) (pfile, p->arg);
+ for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
+ (*p->handler) (pfile, p->arg);
/* Scan -imacros files after -D, -U, but before -include.
pfile->next_include_file is NULL, so _cpp_pop_buffer does not
do_linemarker, U"#", 1, KANDR, IN_I
};
-#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF)
+#define SEEN_EOL() (CPP_OPTION (pfile, traditional) \
+ || pfile->cur_token[-1].type == CPP_EOF)
/* Skip any remaining tokens in a directive. */
static void
cpp_reader *pfile;
{
cpp_hashnode *node;
- const cpp_token *token = _cpp_lex_token (pfile);
/* The token immediately after #define must be an identifier. That
identifier may not be "defined", per C99 6.10.8p4.
Note that if we're copying comments into macro expansions, we
could encounter comment tokens here, so eat them all up first. */
- if (! CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ if (CPP_OPTION (pfile, traditional))
+ node = _cpp_lex_identifier_trad (pfile);
+ else
{
- while (token->type == CPP_COMMENT)
- token = _cpp_lex_token (pfile);
- }
+ const cpp_token *token = _cpp_lex_token (pfile);
+
+ if (! CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ {
+ while (token->type == CPP_COMMENT)
+ token = _cpp_lex_token (pfile);
+ }
- if (token->type != CPP_NAME)
- {
if (token->type == CPP_EOF)
- cpp_error (pfile, DL_ERROR, "no macro name given in #%s directive",
- pfile->directive->name);
- else if (token->flags & NAMED_OP)
- cpp_error (pfile, DL_ERROR,
- "\"%s\" cannot be used as a macro name as it is an operator in C++",
- NODE_NAME (token->val.node));
+ {
+ cpp_error (pfile, DL_ERROR, "no macro name given in #%s directive",
+ pfile->directive->name);
+ return NULL;
+ }
+
+ if (token->type == CPP_NAME || (token->flags & NAMED_OP))
+ node = token->val.node;
else
- cpp_error (pfile, DL_ERROR, "macro names must be identifiers");
-
- return 0;
+ node = NULL;
}
- node = token->val.node;
- if (node->flags & NODE_POISONED)
- return 0;
-
- if (node == pfile->spec_nodes.n_defined)
- {
- cpp_error (pfile, DL_ERROR, "\"%s\" cannot be used as a macro name",
- NODE_NAME (node));
- return 0;
- }
+ if (!node)
+ cpp_error (pfile, DL_ERROR, "macro names must be identifiers");
+ else if (node->flags & NODE_OPERATOR)
+ cpp_error (pfile, DL_ERROR,
+ "\"%s\" cannot be used as a macro name as it is an operator in C++",
+ NODE_NAME (node));
+ else if (node == pfile->spec_nodes.n_defined)
+ cpp_error (pfile, DL_ERROR, "\"defined\" cannot be used as a macro name");
+ else if (! (node->flags & NODE_POISONED))
+ return node;
- return node;
+ return NULL;
}
/* Process a #define directive. Most work is done in cppmacro.c. */
pfile->buffer = new;
+ if (CPP_OPTION (pfile, traditional))
+ _cpp_set_trad_context (pfile);
+
return new;
}
_cpp_maybe_push_include_file (pfile);
}
}
+
+ if (pfile->buffer && CPP_OPTION (pfile, traditional))
+ _cpp_set_trad_context (pfile);
}
/* Enter all recognised directives in the hash table. */
static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, cpp_macro *,
macro_arg *));
static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
+static bool create_iso_definition PARAMS ((cpp_reader *, cpp_macro *));
/* #define directive parsing and handling. */
static cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
-static int warn_of_redefinition PARAMS ((const cpp_hashnode *,
- const cpp_macro *));
+static bool warn_of_redefinition PARAMS ((cpp_reader *, const cpp_hashnode *,
+ const cpp_macro *));
static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *));
static int parse_params PARAMS ((cpp_reader *, cpp_macro *));
static void check_trad_stringification PARAMS ((cpp_reader *,
LAST (context).token = first + count;
}
+/* Push a traditional macro's replacement text. */
+void
+_cpp_push_text_context (pfile, macro, start, end)
+ cpp_reader *pfile;
+ cpp_hashnode *macro;
+ const uchar *start, *end;
+{
+ cpp_context *context = next_context (pfile);
+
+ context->direct_p = true;
+ context->macro = macro;
+ context->buff = NULL;
+ CUR (context) = start;
+ RLIMIT (context) = end;
+}
+
/* Expand an argument ARG before replacing parameters in a
function-like macro. This works by pushing a context with the
argument's tokens, and then expanding that into a temporary buffer
/* #define directive parsing and handling. */
/* Returns non-zero if a macro redefinition warning is required. */
-static int
-warn_of_redefinition (node, macro2)
+static bool
+warn_of_redefinition (pfile, node, macro2)
+ cpp_reader *pfile;
const cpp_hashnode *node;
const cpp_macro *macro2;
{
/* Some redefinitions need to be warned about regardless. */
if (node->flags & NODE_WARN)
- return 1;
+ return true;
/* Redefinition of a macro is allowed if and only if the old and new
definitions are the same. (6.10.3 paragraph 2). */
|| macro1->paramc != macro2->paramc
|| macro1->fun_like != macro2->fun_like
|| macro1->variadic != macro2->variadic)
- return 1;
-
- /* Check each token. */
- for (i = 0; i < macro1->count; i++)
- if (! _cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i]))
- return 1;
+ return true;
/* Check parameter spellings. */
for (i = 0; i < macro1->paramc; i++)
if (macro1->params[i] != macro2->params[i])
- return 1;
+ return true;
- return 0;
+ /* Check the replacement text or tokens. */
+ if (CPP_OPTION (pfile, traditional))
+ return memcmp (macro1->exp.text, macro2->exp.text, macro1->count);
+
+ for (i = 0; i < macro1->count; i++)
+ if (!_cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i]))
+ return true;
+
+ return false;
}
/* Free the definition of hashnode H. */
return token;
}
-/* Parse a macro and save its expansion. Returns non-zero on success. */
-int
-_cpp_create_definition (pfile, node)
+static bool
+create_iso_definition (pfile, macro)
cpp_reader *pfile;
- cpp_hashnode *node;
+ cpp_macro *macro;
{
- cpp_macro *macro;
- cpp_token *token, *saved_cur_token;
+ cpp_token *token;
const cpp_token *ctoken;
- unsigned int i, ok = 1;
-
- macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
- macro->line = pfile->directive_line;
- macro->params = 0;
- macro->paramc = 0;
- macro->variadic = 0;
- macro->count = 0;
- macro->fun_like = 0;
/* Get the first token of the expansion (or the '(' of a
function-like macro). */
if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
{
- ok = parse_params (pfile, macro);
+ bool ok = parse_params (pfile, macro);
macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
if (!ok)
- goto cleanup2;
+ return false;
/* Success. Commit the parameter array. */
BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
cpp_error (pfile, DL_PEDWARN,
"ISO C requires whitespace after the macro name");
- saved_cur_token = pfile->cur_token;
-
if (macro->fun_like)
token = lex_expansion_token (pfile, macro);
else
/* Let assembler get away with murder. */
else if (CPP_OPTION (pfile, lang) != CLK_ASM)
{
- ok = 0;
cpp_error (pfile, DL_ERROR,
"'#' is not followed by a macro parameter");
- goto cleanup1;
+ return false;
}
}
if (macro->count == 0 || token->type == CPP_EOF)
{
- ok = 0;
cpp_error (pfile, DL_ERROR,
"'##' cannot appear at either end of a macro expansion");
- goto cleanup1;
+ return false;
}
token[-1].flags |= PASTE_LEFT;
/* Commit the memory. */
BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->exp.tokens[macro->count];
- /* Implement the macro-defined-to-itself optimisation. */
- if (macro->count == 1 && !macro->fun_like
- && macro->exp.tokens[0].type == CPP_NAME
- && macro->exp.tokens[0].val.node == node)
- node->flags |= NODE_DISABLED;
+ return true;
+}
+
+/* Parse a macro and save its expansion. Returns non-zero on success. */
+bool
+_cpp_create_definition (pfile, node)
+ cpp_reader *pfile;
+ cpp_hashnode *node;
+{
+ cpp_macro *macro;
+ unsigned int i;
+ bool ok;
+ macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
+ macro->line = pfile->directive_line;
+ macro->params = 0;
+ macro->paramc = 0;
+ macro->variadic = 0;
+ macro->count = 0;
+ macro->fun_like = 0;
/* To suppress some diagnostics. */
macro->syshdr = pfile->map->sysp != 0;
+ if (CPP_OPTION (pfile, traditional))
+ ok = _cpp_create_trad_definition (pfile, macro);
+ else
+ {
+ cpp_token *saved_cur_token = pfile->cur_token;
+
+ ok = create_iso_definition (pfile, macro);
+
+ /* Restore lexer position because of games lex_expansion_token()
+ plays lexing the macro. We set the type for SEEN_EOL() in
+ cpplib.c.
+
+ Longer term we should lex the whole line before coming here,
+ and just copy the expansion. */
+ saved_cur_token[-1].type = pfile->cur_token[-1].type;
+ pfile->cur_token = saved_cur_token;
+
+ /* Stop the lexer accepting __VA_ARGS__. */
+ pfile->state.va_args_ok = 0;
+ }
+
+ /* Clear the fast argument lookup indices. */
+ for (i = macro->paramc; i-- > 0; )
+ macro->params[i]->arg_index = 0;
+
+ if (!ok)
+ return ok;
+
if (node->type != NT_VOID)
{
- if (warn_of_redefinition (node, macro))
+ if (warn_of_redefinition (pfile, node, macro))
{
cpp_error_with_line (pfile, DL_PEDWARN, pfile->directive_line, 0,
"\"%s\" redefined", NODE_NAME (node));
if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
- cpp_error_with_line (pfile, DL_PEDWARN, node->value.macro->line, 0,
- "this is the location of the previous definition");
+ cpp_error_with_line (pfile, DL_PEDWARN,
+ node->value.macro->line, 0,
+ "this is the location of the previous definition");
}
_cpp_free_definition (node);
}
if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
node->flags |= NODE_WARN;
- cleanup1:
-
- /* Set type for SEEN_EOL() in cpplib.c, restore the lexer position. */
- saved_cur_token[-1].type = pfile->cur_token[-1].type;
- pfile->cur_token = saved_cur_token;
-
- cleanup2:
-
- /* Stop the lexer accepting __VA_ARGS__. */
- pfile->state.va_args_ok = 0;
-
- /* Clear the fast argument lookup indices. */
- for (i = macro->paramc; i-- > 0; )
- macro->params[i]->arg_index = 0;
-
return ok;
}
/* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines.
Stop cpplex.c from recognizing comments and directives during its
- lexing pass. Get rid of line_base usage - seems pointless? */
+ lexing pass. Get rid of line_base usage - seems pointless? Do we
+ get escaped newline at EOF correct? */
static const uchar *handle_newline PARAMS ((cpp_reader *, const uchar *));
static const uchar *skip_escaped_newlines PARAMS ((cpp_reader *,
const uchar *));
+static const uchar *skip_whitespace PARAMS ((cpp_reader *, const uchar *));
static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *));
static const uchar *skip_comment PARAMS ((cpp_reader *, const uchar *));
static void scan_out_logical_line PARAMS ((cpp_reader *pfile));
static void check_output_buffer PARAMS ((cpp_reader *, size_t));
static void restore_buff PARAMS ((cpp_reader *));
+static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *));
/* Ensures we have N bytes' space in the output buffer, and
reallocates it if not. */
return cur;
}
+/* Skip any horizontal whitespace and comments beginning at CUR,
+ returning the following character. */
+static const uchar *
+skip_whitespace (pfile, cur)
+ cpp_reader *pfile;
+ const uchar *cur;
+{
+ const uchar *tmp;
+
+ for (;;)
+ {
+ while (is_nvspace (*cur) && *cur != 0)
+ cur++;
+
+ if (*cur == '\0' && cur != RLIMIT (pfile->context))
+ continue;
+
+ if (*cur == '\\')
+ {
+ tmp = cur;
+ cur = skip_escaped_newlines (pfile, cur);
+ if (tmp != cur)
+ continue;
+ }
+
+ if (*cur == '/')
+ {
+ tmp = skip_escaped_newlines (pfile, cur + 1);
+ if (*tmp == '*')
+ {
+ cur = skip_comment (pfile, tmp + 1);
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ return cur;
+}
+
/* Lexes and outputs an identifier starting at CUR, which is assumed
to point to a valid first character of an identifier. Returns
the hashnode, and updates trad_out_cur. */
{
size_t len;
uchar *out = pfile->trad_out_cur;
+ cpp_hashnode *result;
do
{
CUR (pfile->context) = cur;
len = out - pfile->trad_out_cur;
+ result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->trad_out_cur,
+ len, HT_ALLOC);
pfile->trad_out_cur = out;
- return (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->trad_out_cur,
- len, HT_ALLOC);
+ return result;
+}
+
+/* Reads an identifier, returning its hashnode. If the next token is
+ not an identifier, returns NULL. */
+cpp_hashnode *
+_cpp_lex_identifier_trad (pfile)
+ cpp_reader *pfile;
+{
+ const uchar *cur = skip_whitespace (pfile, CUR (pfile->context));
+
+ if (!ISIDST (*cur))
+ {
+ CUR (pfile->context) = cur;
+ return NULL;
+ }
+
+ return lex_identifier (pfile, cur);
}
/* Overlays the true file buffer temporarily with text of length LEN
scan_out_logical_line (pfile)
cpp_reader *pfile;
{
- cpp_context *context = pfile->context;
- const uchar *cur = CUR (context);
+ cpp_context *context;
+ const uchar *cur;
unsigned int c, quote = 0;
uchar *out;
+ new_context:
+ context = pfile->context;
+ cur = CUR (context);
check_output_buffer (pfile, RLIMIT (context) - cur);
out = pfile->trad_out_cur;
case '\0':
if (cur - 1 != RLIMIT (context))
break;
+
+ /* If this is a macro's expansion, pop it. */
+ if (context->prev)
+ {
+ pfile->trad_out_cur = out - 1;
+ _cpp_pop_context (pfile);
+ goto new_context;
+ }
+
+ /* Premature end of file. Fake a new line. */
cur--;
if (!pfile->buffer->from_stage3)
cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
case '\r': case '\n':
cur = handle_newline (pfile, cur - 1);
+ out[-1] = '\0';
finish_output:
- out[-1] = '\n';
- out[0] = '\0';
CUR (context) = cur;
- pfile->trad_out_cur = out;
+ pfile->trad_out_cur = out - 1;
return;
case '"':
pfile->trad_out_cur = --out;
node = lex_identifier (pfile, cur - 1);
+ if (node->type == NT_MACRO)
+ {
+ /* Remove the macro name from the output. */
+ pfile->trad_out_cur = out;
+ push_replacement_text (pfile, node);
+ goto new_context;
+ }
out = pfile->trad_out_cur;
cur = CUR (context);
}
}
}
}
+
+/* Push a context holding the replacement text of the macro NODE on
+ the context stack. Doesn't yet handle special built-ins or
+ function-like macros. */
+static void
+push_replacement_text (pfile, node)
+ cpp_reader *pfile;
+ cpp_hashnode *node;
+{
+ cpp_macro *macro = node->value.macro;
+
+ _cpp_push_text_context (pfile, node,
+ macro->exp.text,
+ macro->exp.text + macro->count);
+}
+
+/* Analyze and save the replacement text of a macro. */
+bool
+_cpp_create_trad_definition (pfile, macro)
+ cpp_reader *pfile;
+ cpp_macro *macro;
+{
+ const uchar *cur, *limit;
+ uchar *exp;
+ size_t len;
+
+ /* Skip leading whitespace now. */
+ CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context));
+
+ pfile->trad_out_cur = pfile->trad_out_base;
+ scan_out_logical_line (pfile);
+
+ /* Skip trailing white space. */
+ cur = pfile->trad_out_base;
+ limit = pfile->trad_out_cur;
+ while (limit > cur && is_space (limit[-1]))
+ limit--;
+
+ len = (size_t) (limit - cur);
+ exp = _cpp_unaligned_alloc (pfile, len + 1);
+ memcpy (exp, cur, len);
+ exp[len] = '\0';
+
+ macro->exp.text = exp;
+ /* Include NUL. */
+ macro->count = len;
+
+ return true;
+}
+
+/* Prepare to be able to scan the current buffer. */
+void
+_cpp_set_trad_context (pfile)
+ cpp_reader *pfile;
+{
+ cpp_buffer *buffer = pfile->buffer;
+ cpp_context *context = pfile->context;
+
+ if (pfile->context->prev)
+ abort ();
+
+ pfile->trad_out_cur = pfile->trad_out_base;
+ CUR (context) = buffer->cur;
+ RLIMIT (context) = buffer->rlimit;
+ check_output_buffer (pfile, RLIMIT (context) - CUR (context));
+}