/* The replacement text of a function-like macro is stored as a
contiguous sequence of aligned blocks, each representing the text
- between subsequent parameters in that text.
+ between subsequent parameters.
- Each block comprises the length of text contained therein, the
- one-based index of the argument that immediately follows that text,
- and the text itself. The final block in the macro expansion is
- easily recognizable as it has an argument index of zero. */
+ Each block comprises the text between its surrounding parameters,
+ the length of that text, and the one-based index of the following
+ parameter. The final block in the replacement text is easily
+ recognizable as it has an argument index of zero. */
struct block
{
/* The offset of the macro name in the output buffer. */
size_t offset;
+ /* The line the macro name appeared on. */
+ unsigned int line;
+
/* Zero-based index of argument being currently lexed. */
unsigned int argc;
};
return cur + 1;
}
-/* CUR points to any character in the buffer, not necessarily a
- backslash. Advances CUR until all escaped newlines are skipped,
- and returns the new position.
+/* CUR points to any character in the current context, not necessarily
+ a backslash. Advances CUR until all escaped newlines are skipped,
+ and returns the new position without updating the context.
Warns if a file buffer ends in an escaped newline. */
static const uchar *
return cur;
}
-/* CUR points to the asterisk introducing a comment in the input
- buffer. IN_DEFINE is true if we are in the replacement text
- of a macro.
+/* CUR points to the asterisk introducing a comment in the current
+ context. IN_DEFINE is true if we are in the replacement text of a
+ macro.
The asterisk and following comment is copied to the buffer pointed
to by pfile->out.cur, which must be of sufficient size.
out--;
if (c == '\\' && is_vspace (*cur))
{
- cur = skip_escaped_newlines (pfile, cur);
+ cur = skip_escaped_newlines (pfile, cur - 1);
continue;
}
_cpp_read_logical_line_trad (pfile)
cpp_reader *pfile;
{
- cpp_buffer *buffer = pfile->buffer;
-
do
{
- if (buffer->cur == buffer->rlimit)
+ if (pfile->buffer->cur == pfile->buffer->rlimit)
{
bool stop = true;
/* Don't pop the last buffer. */
- if (buffer->prev)
+ if (pfile->buffer->prev)
{
- stop = buffer->return_at_eof;
+ stop = pfile->buffer->return_at_eof;
_cpp_pop_buffer (pfile);
- buffer = pfile->buffer;
}
if (stop)
return false;
}
- CUR (pfile->context) = buffer->cur;
- RLIMIT (pfile->context) = buffer->rlimit;
scan_out_logical_line (pfile, NULL);
- buffer = pfile->buffer;
- buffer->cur = CUR (pfile->context);
}
while (pfile->state.skipping);
macro->args[macro->argc] = offset;
}
-/* Copies the next logical line in the current buffer to the output
- buffer. The output is guaranteed to terminate with a NUL
- character.
+/* Copies the next logical line in the current buffer (starting at
+ buffer->cur) to the output buffer. The output is guaranteed to
+ terminate with a NUL character. buffer->cur is updated.
If MACRO is non-NULL, then we are scanning the replacement list of
MACRO, and we call save_replacement_text() every time we meet an
const uchar *cur;
uchar *out;
struct fun_macro fmacro;
- unsigned int c, paren_depth = 0, quote = 0;
+ unsigned int c, paren_depth = 0, quote;
enum ls lex_state = ls_none;
+ bool header_ok;
fmacro.buff = NULL;
start_logical_line:
+ quote = 0;
+ header_ok = pfile->state.angled_headers;
+ CUR (pfile->context) = pfile->buffer->cur;
+ RLIMIT (pfile->context) = pfile->buffer->rlimit;
pfile->out.cur = pfile->out.base;
pfile->out.first_line = pfile->line;
new_context:
if ((lex_state == ls_fun_open || lex_state == ls_fun_close)
&& !pfile->state.in_directive)
{
- /* Newlines in arguments become a space. */
+ /* Newlines in arguments become a space, but we don't
+ clear any in-progress quote. */
if (lex_state == ls_fun_close)
out[-1] = ' ';
continue;
goto done;
case '<':
- if (pfile->state.angled_headers && !quote)
+ if (header_ok)
quote = '>';
break;
case '>':
- if (pfile->state.angled_headers && c == quote)
- {
- pfile->state.angled_headers = false;
- quote = 0;
- }
+ if (c == quote)
+ quote = 0;
break;
case '"':
if (node->type == NT_MACRO
/* Should we expand for ls_answer? */
&& (lex_state == ls_none || lex_state == ls_fun_open)
- && !pfile->state.prevent_expansion
- && !recursive_macro (pfile, node))
+ && !pfile->state.prevent_expansion)
{
/* Macros invalidate MI optimization. */
pfile->mi_valid = false;
{
maybe_start_funlike (pfile, node, out_start, &fmacro);
lex_state = ls_fun_open;
+ fmacro.line = pfile->line;
continue;
}
- else
+ else if (!recursive_macro (pfile, node))
{
/* Remove the object-like macro's name from the
output, and push its replacement text. */
paren_depth++;
if (lex_state == ls_fun_open)
{
- lex_state = ls_fun_close;
- paren_depth = 1;
- out = pfile->out.base + fmacro.offset;
- fmacro.args[0] = fmacro.offset;
+ if (recursive_macro (pfile, fmacro.node))
+ lex_state = ls_none;
+ else
+ {
+ lex_state = ls_fun_close;
+ paren_depth = 1;
+ out = pfile->out.base + fmacro.offset;
+ fmacro.args[0] = fmacro.offset;
+ }
}
else if (lex_state == ls_predicate)
lex_state = ls_answer;
{
cpp_macro *m = fmacro.node->value.macro;
+ m->used = 1;
lex_state = ls_none;
save_argument (&fmacro, out - pfile->out.base);
break;
case '#':
- /* At start of a line it's a directive. */
if (out - 1 == pfile->out.base && !pfile->state.in_directive)
{
- /* This is a kludge. We want to have the ISO
- preprocessor lex the next token. */
- pfile->buffer->cur = cur;
- if (_cpp_handle_directive (pfile, false /* indented */))
- goto start_logical_line;
+ /* A directive. With the way _cpp_handle_directive
+ currently works, we only want to call it if either we
+ know the directive is OK, or we want it to fail and
+ be removed from the output. If we want it to be
+ passed through (the assembler case) then we must not
+ call _cpp_handle_directive. */
+ pfile->out.cur = out;
+ cur = skip_whitespace (pfile, cur, true /* skip_comments */);
+ out = pfile->out.cur;
+
+ if (is_vspace (*cur))
+ {
+ /* Null directive. Ignore it and don't invalidate
+ the MI optimization. */
+ out = pfile->out.base;
+ continue;
+ }
+ else
+ {
+ bool do_it = false;
+
+ if (is_numstart (*cur))
+ do_it = true;
+ else if (is_idstart (*cur))
+ /* Check whether we know this directive, but don't
+ advance. */
+ do_it = lex_identifier (pfile, cur)->directive_index != 0;
+
+ if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM)
+ {
+ /* This is a kludge. We want to have the ISO
+ preprocessor lex the next token. */
+ pfile->buffer->cur = cur;
+ _cpp_handle_directive (pfile, false /* indented */);
+ /* #include changes pfile->buffer so we need to
+ update the limits of the current context. */
+ goto start_logical_line;
+ }
+ }
}
+
if (pfile->state.in_expression)
{
lex_state = ls_hash;
break;
}
+ /* Non-whitespace disables MI optimization and stops treating
+ '<' as a quote in #include. */
+ header_ok = false;
+ if (!pfile->state.in_directive)
+ pfile->mi_valid = false;
+
if (lex_state == ls_none)
continue;
done:
out[-1] = '\0';
- CUR (context) = cur;
+ pfile->buffer->cur = cur;
pfile->out.cur = out - 1;
if (fmacro.buff)
_cpp_release_buff (pfile, fmacro.buff);
if (lex_state == ls_fun_close)
- cpp_error (pfile, DL_ERROR,
- "unterminated argument list invoking macro \"%s\"",
- NODE_NAME (fmacro.node));
+ cpp_error_with_line (pfile, DL_ERROR, fmacro.line, 0,
+ "unterminated argument list invoking macro \"%s\"",
+ NODE_NAME (fmacro.node));
}
/* Push a context holding the replacement text of the macro NODE on
else
{
cpp_macro *macro = node->value.macro;
+ macro->used = 1;
text = macro->exp.text;
len = macro->count;
}
cpp_reader *pfile;
cpp_hashnode *node;
{
- bool recursing = node->flags & NODE_DISABLED;
+ bool recursing = !!(node->flags & NODE_DISABLED);
/* Object-like macros that are already expanding are necessarily
recursive.
{
const uchar *cur;
uchar *limit;
+ cpp_context *context = pfile->context;
- CUR (pfile->context) = pfile->buffer->cur;
+ /* The context has not been set up for command line defines, and CUR
+ has not been updated for the macro name for in-file defines. */
+ pfile->out.cur = pfile->out.base;
+ CUR (context) = pfile->buffer->cur;
+ RLIMIT (context) = pfile->buffer->rlimit;
+ check_output_buffer (pfile, RLIMIT (context) - CUR (context));
/* Is this a function-like macro? */
- if (* CUR (pfile->context) == '(')
+ if (* CUR (context) == '(')
{
/* Setting macro to NULL indicates an error occurred, and
prevents unnecessary work in scan_out_logical_line. */
}
/* Skip leading whitespace in the replacement text. */
- CUR (pfile->context)
- = skip_whitespace (pfile, CUR (pfile->context),
+ pfile->buffer->cur
+ = skip_whitespace (pfile, CUR (context),
CPP_OPTION (pfile, discard_comments_in_macro_exp));
pfile->state.prevent_expansion++;
free (p1);
return mismatch;
}
-
-/* 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->out.cur = pfile->out.base;
- CUR (context) = buffer->cur;
- RLIMIT (context) = buffer->rlimit;
- check_output_buffer (pfile, RLIMIT (context) - CUR (context));
-}