Commit 45b966db by Zack Weinberg Committed by Zack Weinberg

Makefile.in (LIBCPP_OBJS): Add cpplex.o.

	* Makefile.in (LIBCPP_OBJS): Add cpplex.o.
	(cpplex.o): New target.
	* po/POTFILES.in: Add cpplex.c.

	* cpplex.c (_cpp_grow_token_buffer, null_cleanup,
	cpp_push_buffer, cpp_pop_buffer, cpp_scan_buffer,
	cpp_expand_to_buffer, cpp_buf_line_and_col, cpp_file_buffer,
	skip_block_comment, skip_line_comment, skip_comment,
	copy_comment, _cpp_skip_hspace, _cpp_skip_rest_of_line,
	_cpp_parse_name, skip_string, parse_string,
	_cpp_parse_assertion, cpp_get_token, cpp_get_non_space_token,
	_cpp_get_directive_token, find_position,
	_cpp_read_and_prescan, _cpp_init_input_buffer): Move here.
	(maybe_macroexpand, _cpp_lex_token): New functions.

	* cpplib.c (SKIP_WHITE_SPACE, eval_if_expr, parse_set_mark,
	parse_goto_mark): Delete.
	(_cpp_handle_eof): New function.
	(_cpp_handle_directive): Rename from handle_directive.
	(_cpp_output_line_command): Rename from output_line_command.
	(do_if, do_elif): Call _cpp_parse_expr directly.
	* cppfiles.c (_cpp_read_include_file): Don't call
	init_input_buffer here.
	* cpphash.c (quote_string): Move here, rename _cpp_quote_string.
	* cppexp.c (_cpp_parse_expr): Diddle parsing_if_directive
	here; pop the token_buffer and skip the rest of the line here.
	* cppinit.c (cpp_start_read): Call _cpp_init_input_buffer
	here.

	* cpphash.h (CPP_RESERVE, CPP_IS_MACRO_BUFFER, ACTIVE_MARK_P):
	Define here.
	(CPP_SET_BUF_MARK, CPP_GOTO_BUF_MARK, CPP_SET_MARK,
	CPP_GOTO_MARK): New macros.
	(_cpp_quote_string, _cpp_parse_name, _cpp_skip_rest_of_line,
	_cpp_skip_hspace, _cpp_parse_assertion, _cpp_lex_token,
	_cpp_read_and_prescan, _cpp_init_input_buffer,
	_cpp_grow_token_buffer, _cpp_get_directive_token,
	_cpp_handle_directive, _cpp_handle_eof,
	_cpp_output_line_command): Prototype them here.
	* cpplib.h (enum cpp_token): Add CPP_MACRO.
	(CPP_RESERVE, get_directive_token, cpp_grow_buffer,
	quote_string, output_line_command): Remove.

From-SVN: r32513
parent 46089b86
2000-03-13 Zack Weinberg <zack@wolery.cumb.org>
* Makefile.in (LIBCPP_OBJS): Add cpplex.o.
(cpplex.o): New target.
* po/POTFILES.in: Add cpplex.c.
* cpplex.c (_cpp_grow_token_buffer, null_cleanup,
cpp_push_buffer, cpp_pop_buffer, cpp_scan_buffer,
cpp_expand_to_buffer, cpp_buf_line_and_col, cpp_file_buffer,
skip_block_comment, skip_line_comment, skip_comment,
copy_comment, _cpp_skip_hspace, _cpp_skip_rest_of_line,
_cpp_parse_name, skip_string, parse_string,
_cpp_parse_assertion, cpp_get_token, cpp_get_non_space_token,
_cpp_get_directive_token, find_position,
_cpp_read_and_prescan, _cpp_init_input_buffer): Move here.
(maybe_macroexpand, _cpp_lex_token): New functions.
* cpplib.c (SKIP_WHITE_SPACE, eval_if_expr, parse_set_mark,
parse_goto_mark): Delete.
(_cpp_handle_eof): New function.
(_cpp_handle_directive): Rename from handle_directive.
(_cpp_output_line_command): Rename from output_line_command.
(do_if, do_elif): Call _cpp_parse_expr directly.
* cppfiles.c (_cpp_read_include_file): Don't call
init_input_buffer here.
* cpphash.c (quote_string): Move here, rename _cpp_quote_string.
* cppexp.c (_cpp_parse_expr): Diddle parsing_if_directive
here; pop the token_buffer and skip the rest of the line here.
* cppinit.c (cpp_start_read): Call _cpp_init_input_buffer
here.
* cpphash.h (CPP_RESERVE, CPP_IS_MACRO_BUFFER, ACTIVE_MARK_P):
Define here.
(CPP_SET_BUF_MARK, CPP_GOTO_BUF_MARK, CPP_SET_MARK,
CPP_GOTO_MARK): New macros.
(_cpp_quote_string, _cpp_parse_name, _cpp_skip_rest_of_line,
_cpp_skip_hspace, _cpp_parse_assertion, _cpp_lex_token,
_cpp_read_and_prescan, _cpp_init_input_buffer,
_cpp_grow_token_buffer, _cpp_get_directive_token,
_cpp_handle_directive, _cpp_handle_eof,
_cpp_output_line_command): Prototype them here.
* cpplib.h (enum cpp_token): Add CPP_MACRO.
(CPP_RESERVE, get_directive_token, cpp_grow_buffer,
quote_string, output_line_command): Remove.
2000-03-13 Bernd Schmidt <bernds@cygnus.co.uk> 2000-03-13 Bernd Schmidt <bernds@cygnus.co.uk>
* stmt.c (expand_end_case): RANGE may be signed, and when checking * stmt.c (expand_end_case): RANGE may be signed, and when checking
......
...@@ -2025,7 +2025,7 @@ cccp.o: cccp.c $(CONFIG_H) intl.h pcp.h version.c config.status system.h \ ...@@ -2025,7 +2025,7 @@ cccp.o: cccp.c $(CONFIG_H) intl.h pcp.h version.c config.status system.h \
-c `echo $(srcdir)/cccp.c | sed 's,^\./,,'` -c `echo $(srcdir)/cccp.c | sed 's,^\./,,'`
LIBCPP_OBJS = cpplib.o cpphash.o cpperror.o cppexp.o cppfiles.o \ LIBCPP_OBJS = cpplib.o cpphash.o cpperror.o cppexp.o cppfiles.o \
cppinit.o cppulp.o mkdeps.o \ cppinit.o cppulp.o cpplex.o mkdeps.o \
prefix.o version.o mbchar.o @extra_cpp_objs@ prefix.o version.o mbchar.o @extra_cpp_objs@
LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h
...@@ -2048,6 +2048,7 @@ cppmain.o: cppmain.c $(CONFIG_H) cpplib.h intl.h system.h ...@@ -2048,6 +2048,7 @@ cppmain.o: cppmain.c $(CONFIG_H) cpplib.h intl.h system.h
cppulp.o: cppulp.c $(CONFIG_H) system.h output.h cppulp.o: cppulp.c $(CONFIG_H) system.h output.h
cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS) cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS) cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS)
cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS)
cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H) cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H)
cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H) cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H)
cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H) mkdeps.h cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(HASHTAB_H) mkdeps.h
......
...@@ -352,12 +352,12 @@ parse_defined (pfile) ...@@ -352,12 +352,12 @@ parse_defined (pfile)
op.op = INT; op.op = INT;
pfile->no_macro_expand++; pfile->no_macro_expand++;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_LPAREN) if (token == CPP_LPAREN)
{ {
paren++; paren++;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
} }
if (token != CPP_NAME) if (token != CPP_NAME)
...@@ -369,7 +369,7 @@ parse_defined (pfile) ...@@ -369,7 +369,7 @@ parse_defined (pfile)
if (paren) if (paren)
{ {
if (get_directive_token (pfile) != CPP_RPAREN) if (_cpp_get_directive_token (pfile) != CPP_RPAREN)
goto oops; goto oops;
} }
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
...@@ -419,7 +419,7 @@ lex (pfile, skip_evaluation) ...@@ -419,7 +419,7 @@ lex (pfile, skip_evaluation)
long old_written; long old_written;
old_written = CPP_WRITTEN (pfile); old_written = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
tok_start = pfile->token_buffer + old_written; tok_start = pfile->token_buffer + old_written;
tok_end = CPP_PWRITTEN (pfile); tok_end = CPP_PWRITTEN (pfile);
...@@ -689,7 +689,10 @@ _cpp_parse_expr (pfile) ...@@ -689,7 +689,10 @@ _cpp_parse_expr (pfile)
register struct operation *top = stack; register struct operation *top = stack;
unsigned int lprio, rprio = 0; unsigned int lprio, rprio = 0;
int skip_evaluation = 0; int skip_evaluation = 0;
long old_written = CPP_WRITTEN (pfile);
int result;
pfile->parsing_if_directive++;
top->rprio = 0; top->rprio = 0;
top->flags = 0; top->flags = 0;
for (;;) for (;;)
...@@ -999,9 +1002,8 @@ _cpp_parse_expr (pfile) ...@@ -999,9 +1002,8 @@ _cpp_parse_expr (pfile)
{ {
if (top != stack) if (top != stack)
cpp_ice (pfile, "unbalanced stack in #if expression"); cpp_ice (pfile, "unbalanced stack in #if expression");
if (stack != init_stack) result = (top->value != 0);
free (stack); goto done;
return (top->value != 0);
} }
top++; top++;
...@@ -1041,7 +1043,12 @@ _cpp_parse_expr (pfile) ...@@ -1041,7 +1043,12 @@ _cpp_parse_expr (pfile)
} }
} }
syntax_error: syntax_error:
_cpp_skip_rest_of_line (pfile);
result = 0;
done:
pfile->parsing_if_directive--;
CPP_SET_WRITTEN (pfile, old_written);
if (stack != init_stack) if (stack != init_stack)
free (stack); free (stack);
return 0; return result;
} }
...@@ -38,17 +38,13 @@ static struct file_name_map *read_name_map ...@@ -38,17 +38,13 @@ static struct file_name_map *read_name_map
static char *read_filename_string PARAMS ((int, FILE *)); static char *read_filename_string PARAMS ((int, FILE *));
static char *remap_filename PARAMS ((cpp_reader *, char *, static char *remap_filename PARAMS ((cpp_reader *, char *,
struct file_name_list *)); struct file_name_list *));
static long read_and_prescan PARAMS ((cpp_reader *, cpp_buffer *,
int, size_t));
static struct file_name_list *actual_directory static struct file_name_list *actual_directory
PARAMS ((cpp_reader *, const char *)); PARAMS ((cpp_reader *, const char *));
static unsigned int hash_IHASH PARAMS ((const void *)); static unsigned int hash_IHASH PARAMS ((const void *));
static int eq_IHASH PARAMS ((const void *, const void *)); static int eq_IHASH PARAMS ((const void *, const void *));
static void init_input_buffer PARAMS ((cpp_reader *, int, struct stat *));
static int file_cleanup PARAMS ((cpp_buffer *, cpp_reader *)); static int file_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
static U_CHAR *find_position PARAMS ((U_CHAR *, U_CHAR *, unsigned long *));
#if 0 #if 0
static void hack_vms_include_specification PARAMS ((char *)); static void hack_vms_include_specification PARAMS ((char *));
...@@ -587,14 +583,11 @@ _cpp_read_include_file (pfile, fd, ihash) ...@@ -587,14 +583,11 @@ _cpp_read_include_file (pfile, fd, ihash)
goto fail; goto fail;
} }
if (pfile->input_buffer == NULL)
init_input_buffer (pfile, fd, &st);
/* Read the file, converting end-of-line characters and trigraphs /* Read the file, converting end-of-line characters and trigraphs
(if enabled). */ (if enabled). */
fp->ihash = ihash; fp->ihash = ihash;
fp->nominal_fname = ihash->name; fp->nominal_fname = ihash->name;
length = read_and_prescan (pfile, fp, fd, st_size); length = _cpp_read_and_prescan (pfile, fp, fd, st_size);
if (length < 0) if (length < 0)
goto fail; goto fail;
if (length == 0) if (length == 0)
...@@ -687,402 +680,6 @@ actual_directory (pfile, fname) ...@@ -687,402 +680,6 @@ actual_directory (pfile, fname)
return x; return x;
} }
/* Determine the current line and column. Used only by read_and_prescan. */
static U_CHAR *
find_position (start, limit, linep)
U_CHAR *start;
U_CHAR *limit;
unsigned long *linep;
{
unsigned long line = *linep;
U_CHAR *lbase = start;
while (start < limit)
{
U_CHAR ch = *start++;
if (ch == '\n' || ch == '\r')
{
line++;
lbase = start;
}
}
*linep = line;
return lbase;
}
/* Read the entire contents of file DESC into buffer BUF. LEN is how
much memory to allocate initially; more will be allocated if
necessary. Convert end-of-line markers (\n, \r, \r\n, \n\r) to
canonical form (\n). If enabled, convert and/or warn about
trigraphs. Convert backslash-newline to a one-character escape
(\r) and remove it from "embarrassing" places (i.e. the middle of a
token). If there is no newline at the end of the file, add one and
warn. Returns -1 on failure, or the actual length of the data to
be scanned.
This function does a lot of work, and can be a serious performance
bottleneck. It has been tuned heavily; make sure you understand it
before hacking. The common case - no trigraphs, Unix style line
breaks, backslash-newline set off by whitespace, newline at EOF -
has been optimized at the expense of the others. The performance
penalty for DOS style line breaks (\r\n) is about 15%.
Warnings lose particularly heavily since we have to determine the
line number, which involves scanning from the beginning of the file
or from the last warning. The penalty for the absence of a newline
at the end of reload1.c is about 60%. (reload1.c is 329k.)
If your file has more than one kind of end-of-line marker, you
will get messed-up line numbering. */
/* Table of characters that can't be handled in the inner loop.
Keep these contiguous to optimize the performance of the code generated
for the switch that uses them. */
#define SPECCASE_EMPTY 0
#define SPECCASE_NUL 1
#define SPECCASE_CR 2
#define SPECCASE_BACKSLASH 3
#define SPECCASE_QUESTION 4
static long
read_and_prescan (pfile, fp, desc, len)
cpp_reader *pfile;
cpp_buffer *fp;
int desc;
size_t len;
{
U_CHAR *buf = (U_CHAR *) xmalloc (len);
U_CHAR *ip, *op, *line_base;
U_CHAR *ibase;
U_CHAR *speccase = pfile->input_speccase;
unsigned long line;
unsigned int deferred_newlines;
int count;
size_t offset;
offset = 0;
op = buf;
line_base = buf;
line = 1;
ibase = pfile->input_buffer + 2;
deferred_newlines = 0;
for (;;)
{
read_next:
count = read (desc, pfile->input_buffer + 2, pfile->input_buffer_len);
if (count < 0)
goto error;
else if (count == 0)
break;
offset += count;
ip = ibase;
ibase = pfile->input_buffer + 2;
ibase[count] = ibase[count+1] = '\0';
if (offset > len)
{
size_t delta_op;
size_t delta_line_base;
len *= 2;
if (offset > len)
/* len overflowed.
This could happen if the file is larger than half the
maximum address space of the machine. */
goto too_big;
delta_op = op - buf;
delta_line_base = line_base - buf;
buf = (U_CHAR *) xrealloc (buf, len);
op = buf + delta_op;
line_base = buf + delta_line_base;
}
for (;;)
{
unsigned int span = 0;
/* Deal with \-newline in the middle of a token. */
if (deferred_newlines)
{
while (speccase[ip[span]] == SPECCASE_EMPTY
&& ip[span] != '\n'
&& ip[span] != '\t'
&& ip[span] != ' ')
span++;
memcpy (op, ip, span);
op += span;
ip += span;
/* If ip[0] is SPECCASE_EMPTY, we have hit white space.
Dump out the remaining deferred \-newlines. */
if (speccase[ip[0]] == SPECCASE_EMPTY)
while (deferred_newlines)
deferred_newlines--, *op++ = '\r';
span = 0;
}
/* Copy as much as we can without special treatment. */
while (speccase[ip[span]] == SPECCASE_EMPTY) span++;
memcpy (op, ip, span);
op += span;
ip += span;
switch (speccase[*ip++])
{
case SPECCASE_NUL: /* \0 */
ibase[-1] = op[-1];
goto read_next;
case SPECCASE_CR: /* \r */
if (ip[-2] == '\n')
continue;
else if (*ip == '\n')
ip++;
else if (*ip == '\0')
{
*--ibase = '\r';
goto read_next;
}
*op++ = '\n';
break;
case SPECCASE_BACKSLASH: /* \ */
backslash:
{
/* If we're at the end of the intermediate buffer,
we have to shift the backslash down to the start
and come back next pass. */
if (*ip == '\0')
{
*--ibase = '\\';
goto read_next;
}
else if (*ip == '\n')
{
ip++;
if (*ip == '\r') ip++;
if (*ip == '\n' || *ip == '\t' || *ip == ' ')
*op++ = '\r';
else if (op[-1] == '\t' || op[-1] == ' '
|| op[-1] == '\r' || op[-1] == '\n')
*op++ = '\r';
else
deferred_newlines++;
}
else if (*ip == '\r')
{
ip++;
if (*ip == '\n') ip++;
else if (*ip == '\0')
{
*--ibase = '\r';
*--ibase = '\\';
goto read_next;
}
else if (*ip == '\r' || *ip == '\t' || *ip == ' ')
*op++ = '\r';
else
deferred_newlines++;
}
else
*op++ = '\\';
}
break;
case SPECCASE_QUESTION: /* ? */
{
unsigned int d, t;
/* If we're at the end of the intermediate buffer,
we have to shift the ?'s down to the start and
come back next pass. */
d = ip[0];
if (d == '\0')
{
*--ibase = '?';
goto read_next;
}
if (d != '?')
{
*op++ = '?';
break;
}
d = ip[1];
if (d == '\0')
{
*--ibase = '?';
*--ibase = '?';
goto read_next;
}
/* Trigraph map:
* from to from to from to
* ?? = # ?? ) ] ?? ! |
* ?? ( [ ?? ' ^ ?? > }
* ?? / \ ?? < { ?? - ~
*/
if (d == '=') t = '#';
else if (d == ')') t = ']';
else if (d == '!') t = '|';
else if (d == '(') t = '[';
else if (d == '\'') t = '^';
else if (d == '>') t = '}';
else if (d == '/') t = '\\';
else if (d == '<') t = '{';
else if (d == '-') t = '~';
else
{
*op++ = '?';
break;
}
ip += 2;
if (CPP_OPTIONS (pfile)->warn_trigraphs)
{
unsigned long col;
line_base = find_position (line_base, op, &line);
col = op - line_base + 1;
if (CPP_OPTIONS (pfile)->trigraphs)
cpp_warning_with_line (pfile, line, col,
"trigraph ??%c converted to %c", d, t);
else
cpp_warning_with_line (pfile, line, col,
"trigraph ??%c ignored", d);
}
if (CPP_OPTIONS (pfile)->trigraphs)
{
if (t == '\\')
goto backslash;
else
*op++ = t;
}
else
{
*op++ = '?';
*op++ = '?';
*op++ = d;
}
}
}
}
}
if (offset == 0)
return 0;
/* Deal with pushed-back chars at true EOF.
This may be any of: ?? ? \ \r \n \\r \\n.
\r must become \n, \\r or \\n must become \r.
We know we have space already. */
if (ibase == pfile->input_buffer)
{
if (*ibase == '?')
{
*op++ = '?';
*op++ = '?';
}
else
*op++ = '\r';
}
else if (ibase == pfile->input_buffer + 1)
{
if (*ibase == '\r')
*op++ = '\n';
else
*op++ = *ibase;
}
if (op[-1] != '\n')
{
unsigned long col;
line_base = find_position (line_base, op, &line);
col = op - line_base + 1;
cpp_warning_with_line (pfile, line, col, "no newline at end of file\n");
if (offset + 1 > len)
{
len += 1;
if (offset + 1 > len)
goto too_big;
buf = (U_CHAR *) xrealloc (buf, len);
op = buf + offset;
}
*op++ = '\n';
}
fp->buf = ((len - offset < 20) ? buf : (U_CHAR *)xrealloc (buf, op - buf));
return op - buf;
too_big:
cpp_error (pfile, "file is too large (>%lu bytes)\n", (unsigned long)offset);
free (buf);
return -1;
error:
cpp_error_from_errno (pfile, fp->ihash->name);
free (buf);
return -1;
}
/* Initialize the `input_buffer' and `input_speccase' tables.
These are only used by read_and_prescan, but they're large and
somewhat expensive to set up, so we want them allocated once for
the duration of the cpp run. */
static void
init_input_buffer (pfile, fd, st)
cpp_reader *pfile;
int fd;
struct stat *st;
{
long pipe_buf;
U_CHAR *tmp;
/* Table of characters that cannot be handled by the
read_and_prescan inner loop. The number of non-EMPTY entries
should be as small as humanly possible. */
tmp = (U_CHAR *) xmalloc (1 << CHAR_BIT);
memset (tmp, SPECCASE_EMPTY, 1 << CHAR_BIT);
tmp['\0'] = SPECCASE_NUL;
tmp['\r'] = SPECCASE_CR;
tmp['\\'] = SPECCASE_BACKSLASH;
if (CPP_OPTIONS (pfile)->trigraphs || CPP_OPTIONS (pfile)->warn_trigraphs)
tmp['?'] = SPECCASE_QUESTION;
pfile->input_speccase = tmp;
/* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. If we are reading a pipe,
we want to make sure the input buffer is bigger than the kernel's
pipe buffer. */
pipe_buf = -1;
if (! S_ISREG (st->st_mode))
{
#ifdef _PC_PIPE_BUF
pipe_buf = fpathconf (fd, _PC_PIPE_BUF);
#endif
if (pipe_buf == -1)
{
#ifdef PIPE_BUF
pipe_buf = PIPE_BUF;
#else
pipe_buf = 8192;
#endif
}
}
if (pipe_buf < 8192)
pipe_buf = 8192;
/* PIPE_BUF bytes of buffer proper, 2 to detect running off the end
without address arithmetic all the time, and 2 for pushback in
the case there's a potential trigraph or end-of-line digraph at
the end of a block. */
tmp = (U_CHAR *) xmalloc (pipe_buf + 2 + 2);
pfile->input_buffer = tmp;
pfile->input_buffer_len = pipe_buf;
}
/* Simplify a path name in place, deleting redundant components. This /* Simplify a path name in place, deleting redundant components. This
reduces OS overhead and guarantees that equivalent paths compare reduces OS overhead and guarantees that equivalent paths compare
the same (modulo symlinks). the same (modulo symlinks).
......
...@@ -307,7 +307,7 @@ collect_expansion (pfile, arglist) ...@@ -307,7 +307,7 @@ collect_expansion (pfile, arglist)
last -= 2; /* two extra chars for the leading escape */ last -= 2; /* two extra chars for the leading escape */
for (;;) for (;;)
{ {
/* We use cpp_get_token because get_directive_token would /* We use cpp_get_token because _cpp_get_directive_token would
discard whitespace and we can't cope with that yet. Macro discard whitespace and we can't cope with that yet. Macro
expansion is off, so we are guaranteed not to see POP or EOF. */ expansion is off, so we are guaranteed not to see POP or EOF. */
...@@ -570,7 +570,7 @@ collect_formal_parameters (pfile) ...@@ -570,7 +570,7 @@ collect_formal_parameters (pfile)
long old_written; long old_written;
old_written = CPP_WRITTEN (pfile); old_written = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_LPAREN) if (token != CPP_LPAREN)
{ {
cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters", cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
...@@ -584,7 +584,7 @@ collect_formal_parameters (pfile) ...@@ -584,7 +584,7 @@ collect_formal_parameters (pfile)
for (;;) for (;;)
{ {
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
switch (token) switch (token)
{ {
case CPP_NAME: case CPP_NAME:
...@@ -660,7 +660,7 @@ collect_formal_parameters (pfile) ...@@ -660,7 +660,7 @@ collect_formal_parameters (pfile)
argv[argc].rest_arg = 1; argv[argc].rest_arg = 1;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_RPAREN) if (token != CPP_RPAREN)
{ {
cpp_error (pfile, "another parameter follows `...'"); cpp_error (pfile, "another parameter follows `...'");
...@@ -826,6 +826,43 @@ static const char * const monthnames[] = ...@@ -826,6 +826,43 @@ static const char * const monthnames[] =
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
}; };
/* Place into PFILE a quoted string representing the string SRC.
Caller must reserve enough space in pfile->token_buffer. */
void
_cpp_quote_string (pfile, src)
cpp_reader *pfile;
const char *src;
{
U_CHAR c;
CPP_PUTC_Q (pfile, '\"');
for (;;)
switch ((c = *src++))
{
default:
if (ISPRINT (c))
CPP_PUTC_Q (pfile, c);
else
{
sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
case '\"':
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
CPP_NUL_TERMINATE_Q (pfile);
return;
}
}
/* /*
* expand things like __FILE__. Place the expansion into the output * expand things like __FILE__. Place the expansion into the output
* buffer *without* rescanning. * buffer *without* rescanning.
...@@ -857,7 +894,7 @@ special_symbol (hp, pfile) ...@@ -857,7 +894,7 @@ special_symbol (hp, pfile)
if (!buf) if (!buf)
buf = ""; buf = "";
CPP_RESERVE (pfile, 3 + 4 * strlen (buf)); CPP_RESERVE (pfile, 3 + 4 * strlen (buf));
quote_string (pfile, buf); _cpp_quote_string (pfile, buf);
return; return;
} }
...@@ -1597,7 +1634,7 @@ _cpp_dump_definition (pfile, sym, len, defn) ...@@ -1597,7 +1634,7 @@ _cpp_dump_definition (pfile, sym, len, defn)
DEFINITION *defn; DEFINITION *defn;
{ {
if (pfile->lineno == 0) if (pfile->lineno == 0)
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
CPP_RESERVE (pfile, len + sizeof "#define "); CPP_RESERVE (pfile, len + sizeof "#define ");
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1); CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1);
......
...@@ -217,6 +217,11 @@ extern unsigned char _cpp_IStable[256]; ...@@ -217,6 +217,11 @@ extern unsigned char _cpp_IStable[256];
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF) ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF)
#define CPP_FORWARD(BUFFER, N) ((BUFFER)->cur += (N)) #define CPP_FORWARD(BUFFER, N) ((BUFFER)->cur += (N))
/* Make sure PFILE->token_buffer has space for at least N more characters. */
#define CPP_RESERVE(PFILE, N) \
(CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \
&& (_cpp_grow_token_buffer (PFILE, N), 0))
/* Append string STR (of length N) to PFILE's output buffer. /* Append string STR (of length N) to PFILE's output buffer.
Assume there is enough space. */ Assume there is enough space. */
#define CPP_PUTS_Q(PFILE, STR, N) \ #define CPP_PUTS_Q(PFILE, STR, N) \
...@@ -242,6 +247,29 @@ extern unsigned char _cpp_IStable[256]; ...@@ -242,6 +247,29 @@ extern unsigned char _cpp_IStable[256];
#define CPP_PEDANTIC(PFILE) \ #define CPP_PEDANTIC(PFILE) \
(CPP_OPTIONS (PFILE)->pedantic && !CPP_BUFFER (pfile)->system_header_p) (CPP_OPTIONS (PFILE)->pedantic && !CPP_BUFFER (pfile)->system_header_p)
/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.
(Note that it is false while we're expanding macro *arguments*.) */
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
/* Remember the current position of PFILE so it may be returned to
after looking ahead a bit.
Note that when you set a mark, you _must_ return to that mark. You
may not forget about it and continue parsing. You may not pop a
buffer with an active mark. You may not call CPP_BUMP_LINE while a
mark is active. */
#define CPP_SET_BUF_MARK(IP) ((IP)->mark = (IP)->cur - (IP)->buf)
#define CPP_GOTO_BUF_MARK(IP) ((IP)->cur = (IP)->buf + (IP)->mark, \
(IP)->mark = -1)
#define CPP_SET_MARK(PFILE) CPP_SET_BUF_MARK(CPP_BUFFER(PFILE))
#define CPP_GOTO_MARK(PFILE) CPP_GOTO_BUF_MARK(CPP_BUFFER(PFILE))
/* ACTIVE_MARK_P is true if there's a live mark in the buffer. */
#define ACTIVE_MARK_P(PFILE) (CPP_BUFFER (PFILE)->mark != -1)
/* Last arg to output_line_command. */
enum file_change_code {same_file, rename_file, enter_file, leave_file};
/* In cpphash.c */ /* In cpphash.c */
extern HASHNODE *_cpp_make_hashnode PARAMS ((const U_CHAR *, size_t, extern HASHNODE *_cpp_make_hashnode PARAMS ((const U_CHAR *, size_t,
enum node_type, enum node_type,
...@@ -257,6 +285,7 @@ extern void _cpp_dump_definition PARAMS ((cpp_reader *, const U_CHAR *, ...@@ -257,6 +285,7 @@ extern void _cpp_dump_definition PARAMS ((cpp_reader *, const U_CHAR *,
long, DEFINITION *)); long, DEFINITION *));
extern int _cpp_compare_defs PARAMS ((cpp_reader *, DEFINITION *, extern int _cpp_compare_defs PARAMS ((cpp_reader *, DEFINITION *,
DEFINITION *)); DEFINITION *));
extern void _cpp_quote_string PARAMS ((cpp_reader *, const char *));
extern void _cpp_macroexpand PARAMS ((cpp_reader *, HASHNODE *)); extern void _cpp_macroexpand PARAMS ((cpp_reader *, HASHNODE *));
extern void _cpp_init_macro_hash PARAMS ((cpp_reader *)); extern void _cpp_init_macro_hash PARAMS ((cpp_reader *));
extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *)); extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *));
...@@ -272,4 +301,24 @@ extern void _cpp_init_include_hash PARAMS ((cpp_reader *)); ...@@ -272,4 +301,24 @@ extern void _cpp_init_include_hash PARAMS ((cpp_reader *));
/* In cppexp.c */ /* In cppexp.c */
extern int _cpp_parse_expr PARAMS ((cpp_reader *)); extern int _cpp_parse_expr PARAMS ((cpp_reader *));
/* In cpplex.c */
extern void _cpp_parse_name PARAMS ((cpp_reader *, int));
extern void _cpp_skip_rest_of_line PARAMS ((cpp_reader *));
extern void _cpp_skip_hspace PARAMS ((cpp_reader *));
extern int _cpp_parse_assertion PARAMS ((cpp_reader *));
extern enum cpp_token _cpp_lex_token PARAMS ((cpp_reader *));
extern long _cpp_read_and_prescan PARAMS ((cpp_reader *, cpp_buffer *,
int, size_t));
extern void _cpp_init_input_buffer PARAMS ((cpp_reader *));
extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long));
extern enum cpp_token _cpp_get_directive_token
PARAMS ((cpp_reader *));
/* In cpplib.c */
extern int _cpp_handle_directive PARAMS ((cpp_reader *));
extern void _cpp_handle_eof PARAMS ((cpp_reader *));
extern void _cpp_output_line_command PARAMS ((cpp_reader *,
enum file_change_code));
#endif #endif
...@@ -519,7 +519,7 @@ dump_special_to_buffer (pfile, macro_name) ...@@ -519,7 +519,7 @@ dump_special_to_buffer (pfile, macro_name)
{ {
static const char define_directive[] = "#define "; static const char define_directive[] = "#define ";
int macro_name_length = strlen (macro_name); int macro_name_length = strlen (macro_name);
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length); CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length);
CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1); CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1);
CPP_PUTS_Q (pfile, macro_name, macro_name_length); CPP_PUTS_Q (pfile, macro_name, macro_name_length);
...@@ -872,6 +872,9 @@ cpp_start_read (pfile, fname) ...@@ -872,6 +872,9 @@ cpp_start_read (pfile, fname)
with a compiler that supports C99 designated initializers. */ with a compiler that supports C99 designated initializers. */
init_IStable (); init_IStable ();
/* Set up the tables used by read_and_prescan. */
_cpp_init_input_buffer (pfile);
/* Set up the include search path now. */ /* Set up the include search path now. */
if (! opts->no_standard_includes) if (! opts->no_standard_includes)
initialize_standard_includes (pfile); initialize_standard_includes (pfile);
...@@ -933,7 +936,7 @@ cpp_start_read (pfile, fname) ...@@ -933,7 +936,7 @@ cpp_start_read (pfile, fname)
counter accordingly. */ counter accordingly. */
pfile->lineno = CPP_BUFFER (pfile)->lineno; pfile->lineno = CPP_BUFFER (pfile)->lineno;
else else
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
pfile->only_seen_white = 2; pfile->only_seen_white = 2;
/* The -imacros files can be scanned now, but the -include files /* The -imacros files can be scanned now, but the -include files
...@@ -957,7 +960,7 @@ cpp_start_read (pfile, fname) ...@@ -957,7 +960,7 @@ cpp_start_read (pfile, fname)
while (p) while (p)
{ {
if (cpp_read_file (pfile, p->arg)) if (cpp_read_file (pfile, p->arg))
output_line_command (pfile, enter_file); _cpp_output_line_command (pfile, enter_file);
q = p->next; q = p->next;
free (p); free (p);
......
/* CPP Library - lexical analysis.
Copyright (C) 2000 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
Broken out to separate file, Zack Weinberg, Mar 2000
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "intl.h"
#include "cpplib.h"
#include "cpphash.h"
#define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) \
? CPP_BUFFER (pfile)->cur[N] : EOF)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
#define GETC() CPP_BUF_GET (CPP_BUFFER (pfile))
#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))
static void skip_block_comment PARAMS ((cpp_reader *));
static void skip_line_comment PARAMS ((cpp_reader *));
static int maybe_macroexpand PARAMS ((cpp_reader *, long));
static int skip_comment PARAMS ((cpp_reader *, int));
static int copy_comment PARAMS ((cpp_reader *, int));
static void skip_string PARAMS ((cpp_reader *, int));
static void parse_string PARAMS ((cpp_reader *, int));
static U_CHAR *find_position PARAMS ((U_CHAR *, U_CHAR *, unsigned long *));
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
void
_cpp_grow_token_buffer (pfile, n)
cpp_reader *pfile;
long n;
{
long old_written = CPP_WRITTEN (pfile);
pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;
pfile->token_buffer = (U_CHAR *)
xrealloc(pfile->token_buffer, pfile->token_buffer_size);
CPP_SET_WRITTEN (pfile, old_written);
}
static int
null_cleanup (pbuf, pfile)
cpp_buffer *pbuf ATTRIBUTE_UNUSED;
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
return 0;
}
/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack.
If BUFFER != NULL, then use the LENGTH characters in BUFFER
as the new input buffer.
Return the new buffer, or NULL on failure. */
cpp_buffer *
cpp_push_buffer (pfile, buffer, length)
cpp_reader *pfile;
const U_CHAR *buffer;
long length;
{
cpp_buffer *buf = CPP_BUFFER (pfile);
cpp_buffer *new;
if (++pfile->buffer_stack_depth == CPP_STACK_MAX)
{
cpp_fatal (pfile, "macro or `#include' recursion too deep");
return NULL;
}
new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
new->if_stack = pfile->if_stack;
new->cleanup = null_cleanup;
new->buf = new->cur = buffer;
new->alimit = new->rlimit = buffer + length;
new->prev = buf;
new->mark = -1;
new->line_base = NULL;
CPP_BUFFER (pfile) = new;
return new;
}
cpp_buffer *
cpp_pop_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buf = CPP_BUFFER (pfile);
if (ACTIVE_MARK_P (pfile))
cpp_ice (pfile, "mark active in cpp_pop_buffer");
(*buf->cleanup) (buf, pfile);
CPP_BUFFER (pfile) = CPP_PREV_BUFFER (buf);
free (buf);
pfile->buffer_stack_depth--;
return CPP_BUFFER (pfile);
}
/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer.
Pop the buffer when done. */
void
cpp_scan_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buffer = CPP_BUFFER (pfile);
enum cpp_token token;
if (CPP_OPTIONS (pfile)->no_output)
{
long old_written = CPP_WRITTEN (pfile);
/* In no-output mode, we can ignore everything but directives. */
for (;;)
{
if (! pfile->only_seen_white)
_cpp_skip_rest_of_line (pfile);
token = cpp_get_token (pfile);
if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) != NULL)
cpp_pop_buffer (pfile);
break;
}
}
CPP_SET_WRITTEN (pfile, old_written);
}
else
{
for (;;)
{
token = cpp_get_token (pfile);
if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) != NULL)
cpp_pop_buffer (pfile);
break;
}
}
}
}
/*
* Rescan a string (which may have escape marks) into pfile's buffer.
* Place the result in pfile->token_buffer.
*
* The input is copied before it is scanned, so it is safe to pass
* it something from the token_buffer that will get overwritten
* (because it follows CPP_WRITTEN). This is used by do_include.
*/
void
cpp_expand_to_buffer (pfile, buf, length)
cpp_reader *pfile;
const U_CHAR *buf;
int length;
{
register cpp_buffer *ip;
U_CHAR *buf1;
int save_no_output;
if (length < 0)
{
cpp_ice (pfile, "length < 0 in cpp_expand_to_buffer");
return;
}
/* Set up the input on the input stack. */
buf1 = (U_CHAR *) alloca (length + 1);
memcpy (buf1, buf, length);
buf1[length] = 0;
ip = cpp_push_buffer (pfile, buf1, length);
if (ip == NULL)
return;
ip->has_escapes = 1;
/* Scan the input, create the output. */
save_no_output = CPP_OPTIONS (pfile)->no_output;
CPP_OPTIONS (pfile)->no_output = 0;
CPP_OPTIONS (pfile)->no_line_commands++;
cpp_scan_buffer (pfile);
CPP_OPTIONS (pfile)->no_line_commands--;
CPP_OPTIONS (pfile)->no_output = save_no_output;
CPP_NUL_TERMINATE (pfile);
}
void
cpp_buf_line_and_col (pbuf, linep, colp)
register cpp_buffer *pbuf;
long *linep, *colp;
{
if (pbuf)
{
*linep = pbuf->lineno;
if (colp)
*colp = pbuf->cur - pbuf->line_base;
}
else
{
*linep = 0;
if (colp)
*colp = 0;
}
}
/* Return the topmost cpp_buffer that corresponds to a file (not a macro). */
cpp_buffer *
cpp_file_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip;
for (ip = CPP_BUFFER (pfile); ip; ip = CPP_PREV_BUFFER (ip))
if (ip->ihash != NULL)
return ip;
return NULL;
}
/* Skip a C-style block comment. We know it's a comment, and point is
at the second character of the starter. */
static void
skip_block_comment (pfile)
cpp_reader *pfile;
{
int c, prev_c = -1;
long line, col;
FORWARD(1);
cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
for (;;)
{
c = GETC ();
if (c == EOF)
{
cpp_error_with_line (pfile, line, col, "unterminated comment");
return;
}
else if (c == '\n' || c == '\r')
{
/* \r cannot be a macro escape marker here. */
if (!ACTIVE_MARK_P (pfile))
CPP_BUMP_LINE (pfile);
}
else if (c == '/' && prev_c == '*')
return;
else if (c == '*' && prev_c == '/'
&& CPP_OPTIONS (pfile)->warn_comments)
cpp_warning (pfile, "`/*' within comment");
prev_c = c;
}
}
/* Skip a C++/Chill line comment. We know it's a comment, and point
is at the second character of the initiator. */
static void
skip_line_comment (pfile)
cpp_reader *pfile;
{
FORWARD(1);
for (;;)
{
int c = GETC ();
/* We don't have to worry about EOF in here. */
if (c == '\n')
{
/* Don't consider final '\n' to be part of comment. */
FORWARD(-1);
return;
}
else if (c == '\r')
{
/* \r cannot be a macro escape marker here. */
if (!ACTIVE_MARK_P (pfile))
CPP_BUMP_LINE (pfile);
if (CPP_OPTIONS (pfile)->warn_comments)
cpp_warning (pfile, "backslash-newline within line comment");
}
}
}
/* Skip a comment - C, C++, or Chill style. M is the first character
of the comment marker. If this really is a comment, skip to its
end and return ' '. If this is not a comment, return M (which will
be '/' or '-'). */
static int
skip_comment (pfile, m)
cpp_reader *pfile;
int m;
{
if (m == '/' && PEEKC() == '*')
{
skip_block_comment (pfile);
return ' ';
}
else if (m == '/' && PEEKC() == '/')
{
if (CPP_BUFFER (pfile)->system_header_p)
{
/* We silently allow C++ comments in system headers, irrespective
of conformance mode, because lots of busted systems do that
and trying to clean it up in fixincludes is a nightmare. */
skip_line_comment (pfile);
return ' ';
}
else if (CPP_OPTIONS (pfile)->cplusplus_comments)
{
if (CPP_OPTIONS (pfile)->c89
&& CPP_PEDANTIC (pfile)
&& ! CPP_BUFFER (pfile)->warned_cplusplus_comments)
{
cpp_pedwarn (pfile,
"C++ style comments are not allowed in ISO C89");
cpp_pedwarn (pfile,
"(this will be reported only once per input file)");
CPP_BUFFER (pfile)->warned_cplusplus_comments = 1;
}
skip_line_comment (pfile);
return ' ';
}
else
return m;
}
else if (m == '-' && PEEKC() == '-'
&& CPP_OPTIONS (pfile)->chill)
{
skip_line_comment (pfile);
return ' ';
}
else
return m;
}
/* Identical to skip_comment except that it copies the comment into the
token_buffer. This is used if !discard_comments. */
static int
copy_comment (pfile, m)
cpp_reader *pfile;
int m;
{
const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */
const U_CHAR *limit;
if (skip_comment (pfile, m) == m)
return m;
limit = CPP_BUFFER (pfile)->cur;
CPP_RESERVE (pfile, limit - start + 2);
CPP_PUTC_Q (pfile, m);
for (; start <= limit; start++)
if (*start != '\r')
CPP_PUTC_Q (pfile, *start);
return ' ';
}
/* Skip whitespace \-newline and comments. Does not macro-expand. */
void
_cpp_skip_hspace (pfile)
cpp_reader *pfile;
{
int c;
while (1)
{
c = GETC();
if (c == EOF)
return;
else if (is_hspace(c))
{
if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
}
else if (c == '\r')
{
/* \r is a backslash-newline marker if !has_escapes, and
a deletable-whitespace or no-reexpansion marker otherwise. */
if (CPP_BUFFER (pfile)->has_escapes)
{
if (PEEKC() == ' ')
FORWARD(1);
else
break;
}
else
CPP_BUMP_LINE (pfile);
}
else if (c == '/' || c == '-')
{
c = skip_comment (pfile, c);
if (c != ' ')
break;
}
else
break;
}
FORWARD(-1);
}
/* Read and discard the rest of the current line. */
void
_cpp_skip_rest_of_line (pfile)
cpp_reader *pfile;
{
for (;;)
{
int c = GETC();
switch (c)
{
case '\n':
FORWARD(-1);
case EOF:
return;
case '\r':
if (! CPP_BUFFER (pfile)->has_escapes)
CPP_BUMP_LINE (pfile);
break;
case '\'':
case '\"':
skip_string (pfile, c);
break;
case '/':
case '-':
skip_comment (pfile, c);
break;
case '\f':
case '\v':
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
break;
}
}
}
/* Parse an identifier starting with C. */
void
_cpp_parse_name (pfile, c)
cpp_reader *pfile;
int c;
{
for (;;)
{
if (! is_idchar(c))
{
FORWARD (-1);
break;
}
if (c == '$' && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "`$' in identifier");
CPP_RESERVE(pfile, 2); /* One more for final NUL. */
CPP_PUTC_Q (pfile, c);
c = GETC();
if (c == EOF)
break;
}
CPP_NUL_TERMINATE_Q (pfile);
return;
}
/* Parse and skip over a string starting with C. A single quoted
string is treated like a double -- some programs (e.g., troff) are
perverse this way. (However, a single quoted string is not allowed
to extend over multiple lines.) */
static void
skip_string (pfile, c)
cpp_reader *pfile;
int c;
{
long start_line, start_column;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
while (1)
{
int cc = GETC();
switch (cc)
{
case EOF:
cpp_error_with_line (pfile, start_line, start_column,
"unterminated string or character constant");
if (pfile->multiline_string_line != start_line
&& pfile->multiline_string_line != 0)
cpp_error_with_line (pfile,
pfile->multiline_string_line, -1,
"possible real start of unterminated constant");
pfile->multiline_string_line = 0;
return;
case '\n':
CPP_BUMP_LINE (pfile);
/* In Fortran and assembly language, silently terminate
strings of either variety at end of line. This is a
kludge around not knowing where comments are in these
languages. */
if (CPP_OPTIONS (pfile)->lang_fortran
|| CPP_OPTIONS (pfile)->lang_asm)
{
FORWARD(-1);
return;
}
/* Character constants may not extend over multiple lines.
In Standard C, neither may strings. We accept multiline
strings as an extension. */
if (c == '\'')
{
cpp_error_with_line (pfile, start_line, start_column,
"unterminated character constant");
FORWARD(-1);
return;
}
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
cpp_pedwarn_with_line (pfile, start_line, start_column,
"string constant runs past end of line");
if (pfile->multiline_string_line == 0)
pfile->multiline_string_line = start_line;
break;
case '\r':
if (CPP_BUFFER (pfile)->has_escapes)
{
cpp_ice (pfile, "\\r escape inside string constant");
FORWARD(1);
}
else
/* Backslash newline is replaced by nothing at all. */
CPP_BUMP_LINE (pfile);
break;
case '\\':
FORWARD(1);
break;
case '\"':
case '\'':
if (cc == c)
return;
break;
}
}
}
/* Parse a string and copy it to the output. */
static void
parse_string (pfile, c)
cpp_reader *pfile;
int c;
{
const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */
const U_CHAR *limit;
skip_string (pfile, c);
limit = CPP_BUFFER (pfile)->cur;
CPP_RESERVE (pfile, limit - start + 2);
CPP_PUTC_Q (pfile, c);
for (; start < limit; start++)
if (*start != '\r')
CPP_PUTC_Q (pfile, *start);
}
/* Read an assertion into the token buffer, converting to
canonical form: `#predicate(a n swe r)' The next non-whitespace
character to read should be the first letter of the predicate.
Returns 0 for syntax error, 1 for bare predicate, 2 for predicate
with answer (see callers for why). In case of 0, an error has been
printed. */
int
_cpp_parse_assertion (pfile)
cpp_reader *pfile;
{
int c, dropwhite;
_cpp_skip_hspace (pfile);
c = PEEKC();
if (! is_idstart(c))
{
cpp_error (pfile, "assertion predicate is not an identifier");
return 0;
}
CPP_PUTC(pfile, '#');
FORWARD(1);
_cpp_parse_name (pfile, c);
c = PEEKC();
if (c != '(')
{
if (is_hspace(c) || c == '\r')
_cpp_skip_hspace (pfile);
c = PEEKC();
}
if (c != '(')
return 1;
CPP_PUTC(pfile, '(');
FORWARD(1);
dropwhite = 1;
while ((c = GETC()) != ')')
{
if (is_space(c))
{
if (! dropwhite)
{
CPP_PUTC(pfile, ' ');
dropwhite = 1;
}
}
else if (c == '\n' || c == EOF)
{
if (c == '\n') FORWARD(-1);
cpp_error (pfile, "un-terminated assertion answer");
return 0;
}
else if (c == '\r')
/* \r cannot be a macro escape here. */
CPP_BUMP_LINE (pfile);
else
{
CPP_PUTC (pfile, c);
dropwhite = 0;
}
}
if (pfile->limit[-1] == ' ')
pfile->limit[-1] = ')';
else if (pfile->limit[-1] == '(')
{
cpp_error (pfile, "empty token sequence in assertion");
return 0;
}
else
CPP_PUTC (pfile, ')');
CPP_NUL_TERMINATE (pfile);
return 2;
}
/* Get the next token, and add it to the text in pfile->token_buffer.
Return the kind of token we got. */
enum cpp_token
_cpp_lex_token (pfile)
cpp_reader *pfile;
{
register int c, c2, c3;
enum cpp_token token;
struct cpp_options *opts = CPP_OPTIONS (pfile);
get_next:
c = GETC();
switch (c)
{
case EOF:
return CPP_EOF;
case '/':
if (PEEKC () == '=')
goto op2;
comment:
if (opts->discard_comments)
c = skip_comment (pfile, c);
else
c = copy_comment (pfile, c);
if (c != ' ')
goto randomchar;
/* Comments are equivalent to spaces.
For -traditional, a comment is equivalent to nothing. */
if (opts->traditional || !opts->discard_comments)
return CPP_COMMENT;
else
{
CPP_PUTC (pfile, c);
return CPP_HSPACE;
}
case '#':
if (pfile->parsing_if_directive)
{
_cpp_skip_hspace (pfile);
_cpp_parse_assertion (pfile);
return CPP_ASSERTION;
}
if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
{
CPP_RESERVE (pfile, 3);
CPP_PUTC_Q (pfile, '#');
CPP_NUL_TERMINATE_Q (pfile);
if (PEEKC () != '#')
return CPP_STRINGIZE;
FORWARD (1);
CPP_PUTC_Q (pfile, '#');
CPP_NUL_TERMINATE_Q (pfile);
return CPP_TOKPASTE;
}
if (!pfile->only_seen_white)
goto randomchar;
/* -traditional directives are recognized only with the # in
column 1.
XXX Layering violation. */
if (CPP_TRADITIONAL (pfile)
&& CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base != 1)
goto randomchar;
return CPP_DIRECTIVE;
case '\"':
case '\'':
parse_string (pfile, c);
pfile->only_seen_white = 0;
return c == '\'' ? CPP_CHAR : CPP_STRING;
case '$':
if (!opts->dollars_in_ident)
goto randomchar;
goto letter;
case ':':
if (opts->cplusplus && PEEKC () == ':')
goto op2;
goto randomchar;
case '&':
case '+':
case '|':
c2 = PEEKC ();
if (c2 == c || c2 == '=')
goto op2;
goto randomchar;
case '*':
case '!':
case '%':
case '=':
case '^':
if (PEEKC () == '=')
goto op2;
goto randomchar;
case '-':
c2 = PEEKC ();
if (c2 == '-')
{
if (opts->chill)
goto comment; /* Chill style comment */
else
goto op2;
}
else if (c2 == '=')
goto op2;
else if (c2 == '>')
{
if (opts->cplusplus && PEEKN (1) == '*')
{
/* In C++, there's a ->* operator. */
token = CPP_OTHER;
pfile->only_seen_white = 0;
CPP_RESERVE (pfile, 4);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, GETC ());
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
return token;
}
goto op2;
}
goto randomchar;
case '<':
if (pfile->parsing_include_directive)
{
for (;;)
{
CPP_PUTC (pfile, c);
if (c == '>')
break;
c = GETC ();
if (c == '\n' || c == EOF)
{
cpp_error (pfile,
"missing '>' in `#include <FILENAME>'");
break;
}
else if (c == '\r')
{
if (!CPP_BUFFER (pfile)->has_escapes)
{
/* Backslash newline is replaced by nothing. */
CPP_ADJUST_WRITTEN (pfile, -1);
CPP_BUMP_LINE (pfile);
}
else
{
/* We might conceivably get \r- or \r<space> in
here. Just delete 'em. */
int d = GETC();
if (d != '-' && d != ' ')
cpp_ice (pfile, "unrecognized escape \\r%c", d);
CPP_ADJUST_WRITTEN (pfile, -1);
}
}
}
return CPP_STRING;
}
/* else fall through */
case '>':
c2 = PEEKC ();
if (c2 == '=')
goto op2;
/* GNU C++ supports MIN and MAX operators <? and >?. */
if (c2 != c && (!opts->cplusplus || c2 != '?'))
goto randomchar;
FORWARD(1);
CPP_RESERVE (pfile, 4);
CPP_PUTC (pfile, c);
CPP_PUTC (pfile, c2);
c3 = PEEKC ();
if (c3 == '=')
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_OTHER;
case '.':
c2 = PEEKC ();
if (ISDIGIT(c2))
{
CPP_RESERVE(pfile, 2);
CPP_PUTC_Q (pfile, '.');
c = GETC ();
goto number;
}
/* In C++ there's a .* operator. */
if (opts->cplusplus && c2 == '*')
goto op2;
if (c2 == '.' && PEEKN(1) == '.')
{
CPP_RESERVE(pfile, 4);
CPP_PUTC_Q (pfile, '.');
CPP_PUTC_Q (pfile, '.');
CPP_PUTC_Q (pfile, '.');
FORWARD (2);
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_3DOTS;
}
goto randomchar;
op2:
token = CPP_OTHER;
pfile->only_seen_white = 0;
CPP_RESERVE(pfile, 3);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
return token;
case 'L':
c2 = PEEKC ();
if ((c2 == '\'' || c2 == '\"') && !CPP_TRADITIONAL (pfile))
{
CPP_PUTC (pfile, c);
c = GETC ();
parse_string (pfile, c);
pfile->only_seen_white = 0;
return c == '\'' ? CPP_WCHAR : CPP_WSTRING;
}
goto letter;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
number:
c2 = '.';
for (;;)
{
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
c = PEEKC ();
if (c == EOF)
break;
if (!is_numchar(c) && c != '.'
&& ((c2 != 'e' && c2 != 'E'
&& ((c2 != 'p' && c2 != 'P')
|| CPP_OPTIONS (pfile)->c89))
|| (c != '+' && c != '-')))
break;
FORWARD(1);
c2= c;
}
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_NUMBER;
case 'b': case 'c': case 'd': case 'h': case 'o':
case 'B': case 'C': case 'D': case 'H': case 'O':
if (opts->chill && PEEKC () == '\'')
{
pfile->only_seen_white = 0;
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, '\'');
FORWARD(1);
for (;;)
{
c = GETC();
if (c == EOF)
goto chill_number_eof;
if (!is_numchar(c))
break;
CPP_PUTC (pfile, c);
}
if (c == '\'')
{
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
CPP_NUL_TERMINATE_Q (pfile);
return CPP_STRING;
}
else
{
FORWARD(-1);
chill_number_eof:
CPP_NUL_TERMINATE (pfile);
return CPP_NUMBER;
}
}
else
goto letter;
case '_':
case 'a': case 'e': case 'f': case 'g': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'p': case 'q':
case 'r': case 's': case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z':
case 'A': case 'E': case 'F': case 'G': case 'I': case 'J':
case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
letter:
pfile->only_seen_white = 0;
_cpp_parse_name (pfile, c);
return CPP_MACRO;
case ' ': case '\t': case '\v':
for (;;)
{
CPP_PUTC (pfile, c);
c = PEEKC ();
if (c == EOF || !is_hspace(c))
break;
FORWARD(1);
}
return CPP_HSPACE;
case '\r':
if (CPP_BUFFER (pfile)->has_escapes)
{
c = GETC ();
if (c == '-')
{
if (pfile->output_escapes)
CPP_PUTS (pfile, "\r-", 2);
_cpp_parse_name (pfile, GETC ());
return CPP_NAME;
}
else if (c == ' ')
{
CPP_RESERVE (pfile, 2);
if (pfile->output_escapes)
CPP_PUTC_Q (pfile, '\r');
CPP_PUTC_Q (pfile, c);
return CPP_HSPACE;
}
else
{
cpp_ice (pfile, "unrecognized escape \\r%c", c);
goto get_next;
}
}
else
{
/* Backslash newline is ignored. */
CPP_BUMP_LINE (pfile);
goto get_next;
}
case '\n':
CPP_PUTC (pfile, c);
if (pfile->only_seen_white == 0)
pfile->only_seen_white = 1;
CPP_BUMP_LINE (pfile);
if (! CPP_OPTIONS (pfile)->no_line_commands)
{
pfile->lineno++;
if (CPP_BUFFER (pfile)->lineno != pfile->lineno)
_cpp_output_line_command (pfile, same_file);
}
return CPP_VSPACE;
case '(': token = CPP_LPAREN; goto char1;
case ')': token = CPP_RPAREN; goto char1;
case '{': token = CPP_LBRACE; goto char1;
case '}': token = CPP_RBRACE; goto char1;
case ',': token = CPP_COMMA; goto char1;
case ';': token = CPP_SEMICOLON; goto char1;
randomchar:
default:
token = CPP_OTHER;
char1:
pfile->only_seen_white = 0;
CPP_PUTC (pfile, c);
return token;
}
}
/* Check for and expand a macro, which is from WRITTEN to CPP_WRITTEN (pfile).
Caller is expected to have checked no_macro_expand. */
static int
maybe_macroexpand (pfile, written)
cpp_reader *pfile;
long written;
{
U_CHAR *macro = pfile->token_buffer + written;
size_t len = CPP_WRITTEN (pfile) - written;
HASHNODE *hp = _cpp_lookup (pfile, macro, len);
if (!hp)
return 0;
if (hp->type == T_DISABLED)
{
if (pfile->output_escapes)
{
/* Insert a no-reexpand marker before IDENT. */
CPP_RESERVE (pfile, 2);
CPP_ADJUST_WRITTEN (pfile, 2);
macro = pfile->token_buffer + written;
memmove (macro + 2, macro, len);
macro[0] = '\r';
macro[1] = '-';
}
return 0;
}
/* If macro wants an arglist, verify that a '(' follows. */
if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
{
int macbuf_whitespace = 0;
int c;
while (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
{
const U_CHAR *point = CPP_BUFFER (pfile)->cur;
for (;;)
{
_cpp_skip_hspace (pfile);
c = PEEKC ();
if (c == '\n')
FORWARD(1);
else
break;
}
if (point != CPP_BUFFER (pfile)->cur)
macbuf_whitespace = 1;
if (c == '(')
goto is_macro_call;
else if (c != EOF)
goto not_macro_call;
cpp_pop_buffer (pfile);
}
CPP_SET_MARK (pfile);
for (;;)
{
_cpp_skip_hspace (pfile);
c = PEEKC ();
if (c == '\n')
FORWARD(1);
else
break;
}
CPP_GOTO_MARK (pfile);
if (c != '(')
{
not_macro_call:
if (macbuf_whitespace)
CPP_PUTC (pfile, ' ');
return 0;
}
}
is_macro_call:
/* This is now known to be a macro call.
Expand the macro, reading arguments as needed,
and push the expansion on the input stack. */
_cpp_macroexpand (pfile, hp);
CPP_SET_WRITTEN (pfile, written);
return 1;
}
enum cpp_token
cpp_get_token (pfile)
cpp_reader *pfile;
{
enum cpp_token token;
long written = CPP_WRITTEN (pfile);
get_next:
token = _cpp_lex_token (pfile);
switch (token)
{
default:
return token;
case CPP_DIRECTIVE:
if (_cpp_handle_directive (pfile))
return CPP_DIRECTIVE;
pfile->only_seen_white = 0;
CPP_PUTC (pfile, '#');
return CPP_OTHER;
case CPP_MACRO:
if (! pfile->no_macro_expand
&& maybe_macroexpand (pfile, written))
goto get_next;
return CPP_NAME;
case CPP_EOF:
if (CPP_BUFFER (pfile)->manual_pop)
/* If we've been reading from redirected input, the
frontend will pop the buffer. */
return CPP_EOF;
else if (CPP_BUFFER (pfile)->seen_eof)
{
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) == NULL)
return CPP_EOF;
cpp_pop_buffer (pfile);
goto get_next;
}
else
{
_cpp_handle_eof (pfile);
return CPP_POP;
}
}
}
/* Like cpp_get_token, but skip spaces and comments. */
enum cpp_token
cpp_get_non_space_token (pfile)
cpp_reader *pfile;
{
int old_written = CPP_WRITTEN (pfile);
for (;;)
{
enum cpp_token token = cpp_get_token (pfile);
if (token != CPP_COMMENT && token != CPP_POP
&& token != CPP_HSPACE && token != CPP_VSPACE)
return token;
CPP_SET_WRITTEN (pfile, old_written);
}
}
/* Like cpp_get_token, except that it does not read past end-of-line.
Also, horizontal space is skipped, and macros are popped. */
enum cpp_token
_cpp_get_directive_token (pfile)
cpp_reader *pfile;
{
long old_written = CPP_WRITTEN (pfile);
enum cpp_token token;
for (;;)
{
_cpp_skip_hspace (pfile);
if (PEEKC () == '\n')
return CPP_VSPACE;
token = cpp_get_token (pfile);
/* token could be hspace at the beginning of a macro. */
if (token == CPP_HSPACE || token == CPP_COMMENT)
{
CPP_SET_WRITTEN (pfile, old_written);
continue;
}
/* token cannot be vspace, it would have been caught above. */
if (token == CPP_VSPACE)
{
cpp_ice (pfile, "VSPACE in get_directive_token");
return token;
}
/* token cannot be POP unless the buffer is a macro buffer. */
if (token != CPP_POP)
return token;
if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
{
cpp_ice (pfile, "POP of file buffer in get_directive_token");
return token;
}
/* We must pop the buffer by hand, or else cpp_get_token might
hand us white space or newline on the next invocation. */
cpp_pop_buffer (pfile);
}
}
/* Determine the current line and column. Used only by read_and_prescan. */
static U_CHAR *
find_position (start, limit, linep)
U_CHAR *start;
U_CHAR *limit;
unsigned long *linep;
{
unsigned long line = *linep;
U_CHAR *lbase = start;
while (start < limit)
{
U_CHAR ch = *start++;
if (ch == '\n' || ch == '\r')
{
line++;
lbase = start;
}
}
*linep = line;
return lbase;
}
/* Read the entire contents of file DESC into buffer BUF. LEN is how
much memory to allocate initially; more will be allocated if
necessary. Convert end-of-line markers (\n, \r, \r\n, \n\r) to
canonical form (\n). If enabled, convert and/or warn about
trigraphs. Convert backslash-newline to a one-character escape
(\r) and remove it from "embarrassing" places (i.e. the middle of a
token). If there is no newline at the end of the file, add one and
warn. Returns -1 on failure, or the actual length of the data to
be scanned.
This function does a lot of work, and can be a serious performance
bottleneck. It has been tuned heavily; make sure you understand it
before hacking. The common case - no trigraphs, Unix style line
breaks, backslash-newline set off by whitespace, newline at EOF -
has been optimized at the expense of the others. The performance
penalty for DOS style line breaks (\r\n) is about 15%.
Warnings lose particularly heavily since we have to determine the
line number, which involves scanning from the beginning of the file
or from the last warning. The penalty for the absence of a newline
at the end of reload1.c is about 60%. (reload1.c is 329k.)
If your file has more than one kind of end-of-line marker, you
will get messed-up line numbering. */
/* Table of characters that can't be handled in the inner loop.
Keep these contiguous to optimize the performance of the code generated
for the switch that uses them. */
#define SPECCASE_EMPTY 0
#define SPECCASE_NUL 1
#define SPECCASE_CR 2
#define SPECCASE_BACKSLASH 3
#define SPECCASE_QUESTION 4
long
_cpp_read_and_prescan (pfile, fp, desc, len)
cpp_reader *pfile;
cpp_buffer *fp;
int desc;
size_t len;
{
U_CHAR *buf = (U_CHAR *) xmalloc (len);
U_CHAR *ip, *op, *line_base;
U_CHAR *ibase;
U_CHAR *speccase = pfile->input_speccase;
unsigned long line;
unsigned int deferred_newlines;
int count;
size_t offset;
offset = 0;
op = buf;
line_base = buf;
line = 1;
ibase = pfile->input_buffer + 2;
deferred_newlines = 0;
for (;;)
{
read_next:
count = read (desc, pfile->input_buffer + 2, pfile->input_buffer_len);
if (count < 0)
goto error;
else if (count == 0)
break;
offset += count;
ip = ibase;
ibase = pfile->input_buffer + 2;
ibase[count] = ibase[count+1] = '\0';
if (offset > len)
{
size_t delta_op;
size_t delta_line_base;
len *= 2;
if (offset > len)
/* len overflowed.
This could happen if the file is larger than half the
maximum address space of the machine. */
goto too_big;
delta_op = op - buf;
delta_line_base = line_base - buf;
buf = (U_CHAR *) xrealloc (buf, len);
op = buf + delta_op;
line_base = buf + delta_line_base;
}
for (;;)
{
unsigned int span = 0;
/* Deal with \-newline in the middle of a token. */
if (deferred_newlines)
{
while (speccase[ip[span]] == SPECCASE_EMPTY
&& ip[span] != '\n'
&& ip[span] != '\t'
&& ip[span] != ' ')
span++;
memcpy (op, ip, span);
op += span;
ip += span;
/* If ip[0] is SPECCASE_EMPTY, we have hit white space.
Dump out the remaining deferred \-newlines. */
if (speccase[ip[0]] == SPECCASE_EMPTY)
while (deferred_newlines)
deferred_newlines--, *op++ = '\r';
span = 0;
}
/* Copy as much as we can without special treatment. */
while (speccase[ip[span]] == SPECCASE_EMPTY) span++;
memcpy (op, ip, span);
op += span;
ip += span;
switch (speccase[*ip++])
{
case SPECCASE_NUL: /* \0 */
ibase[-1] = op[-1];
goto read_next;
case SPECCASE_CR: /* \r */
if (ip[-2] == '\n')
continue;
else if (*ip == '\n')
ip++;
else if (*ip == '\0')
{
*--ibase = '\r';
goto read_next;
}
*op++ = '\n';
break;
case SPECCASE_BACKSLASH: /* \ */
backslash:
{
/* If we're at the end of the intermediate buffer,
we have to shift the backslash down to the start
and come back next pass. */
if (*ip == '\0')
{
*--ibase = '\\';
goto read_next;
}
else if (*ip == '\n')
{
ip++;
if (*ip == '\r') ip++;
if (*ip == '\n' || *ip == '\t' || *ip == ' ')
*op++ = '\r';
else if (op[-1] == '\t' || op[-1] == ' '
|| op[-1] == '\r' || op[-1] == '\n')
*op++ = '\r';
else
deferred_newlines++;
}
else if (*ip == '\r')
{
ip++;
if (*ip == '\n') ip++;
else if (*ip == '\0')
{
*--ibase = '\r';
*--ibase = '\\';
goto read_next;
}
else if (*ip == '\r' || *ip == '\t' || *ip == ' ')
*op++ = '\r';
else
deferred_newlines++;
}
else
*op++ = '\\';
}
break;
case SPECCASE_QUESTION: /* ? */
{
unsigned int d, t;
/* If we're at the end of the intermediate buffer,
we have to shift the ?'s down to the start and
come back next pass. */
d = ip[0];
if (d == '\0')
{
*--ibase = '?';
goto read_next;
}
if (d != '?')
{
*op++ = '?';
break;
}
d = ip[1];
if (d == '\0')
{
*--ibase = '?';
*--ibase = '?';
goto read_next;
}
/* Trigraph map:
* from to from to from to
* ?? = # ?? ) ] ?? ! |
* ?? ( [ ?? ' ^ ?? > }
* ?? / \ ?? < { ?? - ~
*/
if (d == '=') t = '#';
else if (d == ')') t = ']';
else if (d == '!') t = '|';
else if (d == '(') t = '[';
else if (d == '\'') t = '^';
else if (d == '>') t = '}';
else if (d == '/') t = '\\';
else if (d == '<') t = '{';
else if (d == '-') t = '~';
else
{
*op++ = '?';
break;
}
ip += 2;
if (CPP_OPTIONS (pfile)->warn_trigraphs)
{
unsigned long col;
line_base = find_position (line_base, op, &line);
col = op - line_base + 1;
if (CPP_OPTIONS (pfile)->trigraphs)
cpp_warning_with_line (pfile, line, col,
"trigraph ??%c converted to %c", d, t);
else
cpp_warning_with_line (pfile, line, col,
"trigraph ??%c ignored", d);
}
if (CPP_OPTIONS (pfile)->trigraphs)
{
if (t == '\\')
goto backslash;
else
*op++ = t;
}
else
{
*op++ = '?';
*op++ = '?';
*op++ = d;
}
}
}
}
}
if (offset == 0)
return 0;
/* Deal with pushed-back chars at true EOF.
This may be any of: ?? ? \ \r \n \\r \\n.
\r must become \n, \\r or \\n must become \r.
We know we have space already. */
if (ibase == pfile->input_buffer)
{
if (*ibase == '?')
{
*op++ = '?';
*op++ = '?';
}
else
*op++ = '\r';
}
else if (ibase == pfile->input_buffer + 1)
{
if (*ibase == '\r')
*op++ = '\n';
else
*op++ = *ibase;
}
if (op[-1] != '\n')
{
unsigned long col;
line_base = find_position (line_base, op, &line);
col = op - line_base + 1;
cpp_warning_with_line (pfile, line, col, "no newline at end of file\n");
if (offset + 1 > len)
{
len += 1;
if (offset + 1 > len)
goto too_big;
buf = (U_CHAR *) xrealloc (buf, len);
op = buf + offset;
}
*op++ = '\n';
}
fp->buf = ((len - offset < 20) ? buf : (U_CHAR *)xrealloc (buf, op - buf));
return op - buf;
too_big:
cpp_error (pfile, "file is too large (>%lu bytes)\n", (unsigned long)offset);
free (buf);
return -1;
error:
cpp_error_from_errno (pfile, fp->ihash->name);
free (buf);
return -1;
}
/* Initialize the `input_buffer' and `input_speccase' tables.
These are only used by read_and_prescan, but they're large and
somewhat expensive to set up, so we want them allocated once for
the duration of the cpp run. */
void
_cpp_init_input_buffer (pfile)
cpp_reader *pfile;
{
U_CHAR *tmp;
/* Table of characters that cannot be handled by the
read_and_prescan inner loop. The number of non-EMPTY entries
should be as small as humanly possible. */
tmp = (U_CHAR *) xmalloc (1 << CHAR_BIT);
memset (tmp, SPECCASE_EMPTY, 1 << CHAR_BIT);
tmp['\0'] = SPECCASE_NUL;
tmp['\r'] = SPECCASE_CR;
tmp['\\'] = SPECCASE_BACKSLASH;
if (CPP_OPTIONS (pfile)->trigraphs || CPP_OPTIONS (pfile)->warn_trigraphs)
tmp['?'] = SPECCASE_QUESTION;
pfile->input_speccase = tmp;
/* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. */
/* 8Kbytes of buffer proper, 2 to detect running off the end without
address arithmetic all the time, and 2 for pushback in the case
there's a potential trigraph or end-of-line digraph at the end of
a block. */
tmp = (U_CHAR *) xmalloc (8192 + 2 + 2);
pfile->input_buffer = tmp;
pfile->input_buffer_len = 8192;
}
...@@ -28,19 +28,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -28,19 +28,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "intl.h" #include "intl.h"
#include "mkdeps.h" #include "mkdeps.h"
#define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0) #define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) \
? CPP_BUFFER (pfile)->cur[N] : EOF)
#define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N)) #define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
#define GETC() CPP_BUF_GET (CPP_BUFFER (pfile)) #define GETC() CPP_BUF_GET (CPP_BUFFER (pfile))
#define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile)) #define PEEKC() CPP_BUF_PEEK (CPP_BUFFER (pfile))
/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.
(Note that it is false while we're expanding macro *arguments*.) */
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
/* ACTIVE_MARK_P is true if there's a live mark in the buffer, in which
case CPP_BUMP_LINE must not be called. */
#define ACTIVE_MARK_P() (CPP_BUFFER (pfile)->mark != -1)
/* `struct directive' defines one #-directive, including how to handle it. */ /* `struct directive' defines one #-directive, including how to handle it. */
...@@ -93,22 +85,9 @@ static int do_warning PARAMS ((cpp_reader *, const struct directive *)); ...@@ -93,22 +85,9 @@ static int do_warning PARAMS ((cpp_reader *, const struct directive *));
/* Forward declarations. */ /* Forward declarations. */
static void validate_else PARAMS ((cpp_reader *, const char *)); static void validate_else PARAMS ((cpp_reader *, const char *));
static int eval_if_expr PARAMS ((cpp_reader *));
static void conditional_skip PARAMS ((cpp_reader *, int, static void conditional_skip PARAMS ((cpp_reader *, int,
enum node_type, U_CHAR *)); enum node_type, U_CHAR *));
static void skip_if_group PARAMS ((cpp_reader *)); static void skip_if_group PARAMS ((cpp_reader *));
static void parse_name PARAMS ((cpp_reader *, int));
static void parse_string PARAMS ((cpp_reader *, int));
static int parse_assertion PARAMS ((cpp_reader *));
static const char *if_directive_name PARAMS ((cpp_reader *,
struct if_stack *));
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
static int skip_comment PARAMS ((cpp_reader *, int));
static int copy_comment PARAMS ((cpp_reader *, int));
static void skip_string PARAMS ((cpp_reader *, int));
static void skip_rest_of_line PARAMS ((cpp_reader *));
static void cpp_skip_hspace PARAMS ((cpp_reader *));
static int handle_directive PARAMS ((cpp_reader *));
static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, static void pass_thru_directive PARAMS ((const U_CHAR *, size_t,
cpp_reader *, cpp_reader *,
const struct directive *)); const struct directive *));
...@@ -116,11 +95,9 @@ static int read_line_number PARAMS ((cpp_reader *, int *)); ...@@ -116,11 +95,9 @@ static int read_line_number PARAMS ((cpp_reader *, int *));
static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *)); static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
static int consider_directive_while_skipping static int consider_directive_while_skipping
PARAMS ((cpp_reader *, IF_STACK *)); PARAMS ((cpp_reader *, IF_STACK *));
static void skip_block_comment PARAMS ((cpp_reader *));
static void skip_line_comment PARAMS ((cpp_reader *));
static void parse_set_mark PARAMS ((cpp_reader *));
static void parse_goto_mark PARAMS ((cpp_reader *));
static int get_macro_name PARAMS ((cpp_reader *)); static int get_macro_name PARAMS ((cpp_reader *));
static const char *if_directive_name PARAMS ((cpp_reader *,
struct if_stack *));
/* Here is the actual list of #-directives. /* Here is the actual list of #-directives.
This table is ordered by frequency of occurrence; the numbers This table is ordered by frequency of occurrence; the numbers
...@@ -156,367 +133,11 @@ static const struct directive directive_table[] = { ...@@ -156,367 +133,11 @@ static const struct directive directive_table[] = {
{ -1, 0, "", T_UNUSED } { -1, 0, "", T_UNUSED }
}; };
/* Place into PFILE a quoted string representing the string SRC.
Caller must reserve enough space in pfile->token_buffer. */
void
quote_string (pfile, src)
cpp_reader *pfile;
const char *src;
{
U_CHAR c;
CPP_PUTC_Q (pfile, '\"');
for (;;)
switch ((c = *src++))
{
default:
if (ISPRINT (c))
CPP_PUTC_Q (pfile, c);
else
{
sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
case '\"':
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
CPP_NUL_TERMINATE_Q (pfile);
return;
}
}
/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
void
cpp_grow_buffer (pfile, n)
cpp_reader *pfile;
long n;
{
long old_written = CPP_WRITTEN (pfile);
pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;
pfile->token_buffer = (U_CHAR *)
xrealloc(pfile->token_buffer, pfile->token_buffer_size);
CPP_SET_WRITTEN (pfile, old_written);
}
/* Process the string STR as if it appeared as the body of a #define.
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;
const char *str;
{
char *buf, *p;
size_t count;
p = strchr (str, '=');
/* Copy the entire option so we can modify it.
Change the first "=" in the string to a space. If there is none,
tack " 1" on the end. Then add a newline and a NUL. */
if (p)
{
count = strlen (str) + 2;
buf = alloca (count);
memcpy (buf, str, count - 2);
buf[p - str] = ' ';
buf[count - 2] = '\n';
buf[count - 1] = '\0';
}
else
{
count = strlen (str) + 4;
buf = alloca (count);
memcpy (buf, str, count - 4);
strcpy (&buf[count-4], " 1\n");
}
if (cpp_push_buffer (pfile, buf, count - 1) != NULL)
{
do_define (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
/* Process the string STR as if it appeared as the body of a #assert. */
void
cpp_assert (pfile, str)
cpp_reader *pfile;
const char *str;
{
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
{
do_assert (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
/* Determine whether the identifier ID, of length LEN, is a defined macro. */
int
cpp_defined (pfile, id, len)
cpp_reader *pfile;
const U_CHAR *id;
int len;
{
HASHNODE *hp = _cpp_lookup (pfile, id, len);
if (hp && hp->type == T_POISON)
{
cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
return 0;
}
return (hp != NULL);
}
static int
null_cleanup (pbuf, pfile)
cpp_buffer *pbuf ATTRIBUTE_UNUSED;
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
return 0;
}
/* Skip a C-style block comment. We know it's a comment, and point is
at the second character of the starter. */
static void
skip_block_comment (pfile)
cpp_reader *pfile;
{
int c, prev_c = -1;
long line, col;
FORWARD(1);
cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
for (;;)
{
c = GETC ();
if (c == EOF)
{
cpp_error_with_line (pfile, line, col, "unterminated comment");
return;
}
else if (c == '\n' || c == '\r')
{
/* \r cannot be a macro escape marker here. */
if (!ACTIVE_MARK_P())
CPP_BUMP_LINE (pfile);
}
else if (c == '/' && prev_c == '*')
return;
else if (c == '*' && prev_c == '/'
&& CPP_OPTIONS (pfile)->warn_comments)
cpp_warning (pfile, "`/*' within comment");
prev_c = c;
}
}
/* Skip a C++/Chill line comment. We know it's a comment, and point
is at the second character of the initiator. */
static void
skip_line_comment (pfile)
cpp_reader *pfile;
{
FORWARD(1);
for (;;)
{
int c = GETC ();
/* We don't have to worry about EOF in here. */
if (c == '\n')
{
/* Don't consider final '\n' to be part of comment. */
FORWARD(-1);
return;
}
else if (c == '\r')
{
/* \r cannot be a macro escape marker here. */
if (!ACTIVE_MARK_P())
CPP_BUMP_LINE (pfile);
if (CPP_OPTIONS (pfile)->warn_comments)
cpp_warning (pfile, "backslash-newline within line comment");
}
}
}
/* Skip a comment - C, C++, or Chill style. M is the first character
of the comment marker. If this really is a comment, skip to its
end and return ' '. If this is not a comment, return M (which will
be '/' or '-'). */
static int
skip_comment (pfile, m)
cpp_reader *pfile;
int m;
{
if (m == '/' && PEEKC() == '*')
{
skip_block_comment (pfile);
return ' ';
}
else if (m == '/' && PEEKC() == '/')
{
if (CPP_BUFFER (pfile)->system_header_p)
{
/* We silently allow C++ comments in system headers, irrespective
of conformance mode, because lots of busted systems do that
and trying to clean it up in fixincludes is a nightmare. */
skip_line_comment (pfile);
return ' ';
}
else if (CPP_OPTIONS (pfile)->cplusplus_comments)
{
if (CPP_OPTIONS (pfile)->c89
&& CPP_PEDANTIC (pfile)
&& ! CPP_BUFFER (pfile)->warned_cplusplus_comments)
{
cpp_pedwarn (pfile,
"C++ style comments are not allowed in ISO C89");
cpp_pedwarn (pfile,
"(this will be reported only once per input file)");
CPP_BUFFER (pfile)->warned_cplusplus_comments = 1;
}
skip_line_comment (pfile);
return ' ';
}
else
return m;
}
else if (m == '-' && PEEKC() == '-'
&& CPP_OPTIONS (pfile)->chill)
{
skip_line_comment (pfile);
return ' ';
}
else
return m;
}
/* Identical to skip_comment except that it copies the comment into the
token_buffer. This is used if !discard_comments. */
static int
copy_comment (pfile, m)
cpp_reader *pfile;
int m;
{
const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */
const U_CHAR *limit;
if (skip_comment (pfile, m) == m)
return m;
limit = CPP_BUFFER (pfile)->cur;
CPP_RESERVE (pfile, limit - start + 2);
CPP_PUTC_Q (pfile, m);
for (; start <= limit; start++)
if (*start != '\r')
CPP_PUTC_Q (pfile, *start);
return ' ';
}
/* Skip whitespace \-newline and comments. Does not macro-expand. */
static void
cpp_skip_hspace (pfile)
cpp_reader *pfile;
{
int c;
while (1)
{
c = GETC();
if (c == EOF)
return;
else if (is_hspace(c))
{
if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
}
else if (c == '\r')
{
/* \r is a backslash-newline marker if !has_escapes, and
a deletable-whitespace or no-reexpansion marker otherwise. */
if (CPP_BUFFER (pfile)->has_escapes)
{
if (PEEKC() == ' ')
FORWARD(1);
else
break;
}
else
CPP_BUMP_LINE (pfile);
}
else if (c == '/' || c == '-')
{
c = skip_comment (pfile, c);
if (c != ' ')
break;
}
else
break;
}
FORWARD(-1);
}
/* Read and discard the rest of the current line. */
static void
skip_rest_of_line (pfile)
cpp_reader *pfile;
{
for (;;)
{
int c = GETC();
switch (c)
{
case '\n':
FORWARD(-1);
case EOF:
return;
case '\r':
if (! CPP_BUFFER (pfile)->has_escapes)
CPP_BUMP_LINE (pfile);
break;
case '\'':
case '\"':
skip_string (pfile, c);
break;
case '/':
case '-':
skip_comment (pfile, c);
break;
case '\f':
case '\v':
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
break;
}
}
}
/* Handle a possible # directive. /* Handle a possible # directive.
'#' has already been read. */ '#' has already been read. */
static int int
handle_directive (pfile) _cpp_handle_directive (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int c; int c;
...@@ -531,7 +152,7 @@ handle_directive (pfile) ...@@ -531,7 +152,7 @@ handle_directive (pfile)
return 0; return 0;
} }
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = PEEKC (); c = PEEKC ();
/* # followed by a number is equivalent to #line. Do not recognize /* # followed by a number is equivalent to #line. Do not recognize
...@@ -558,7 +179,7 @@ handle_directive (pfile) ...@@ -558,7 +179,7 @@ handle_directive (pfile)
/* Now find the directive name. */ /* Now find the directive name. */
CPP_PUTC (pfile, '#'); CPP_PUTC (pfile, '#');
parse_name (pfile, GETC()); _cpp_parse_name (pfile, GETC());
ident = pfile->token_buffer + old_written + 1; ident = pfile->token_buffer + old_written + 1;
ident_length = CPP_PWRITTEN (pfile) - ident; ident_length = CPP_PWRITTEN (pfile) - ident;
if (ident_length == 0) if (ident_length == 0)
...@@ -588,7 +209,7 @@ handle_directive (pfile) ...@@ -588,7 +209,7 @@ handle_directive (pfile)
{ {
cpp_error (pfile, "`#%s' may not be used inside a macro argument", cpp_error (pfile, "`#%s' may not be used inside a macro argument",
kt->name); kt->name);
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
} }
else else
(*kt->func) (pfile, kt); (*kt->func) (pfile, kt);
...@@ -629,7 +250,7 @@ get_macro_name (pfile) ...@@ -629,7 +250,7 @@ get_macro_name (pfile)
here = CPP_WRITTEN (pfile); here = CPP_WRITTEN (pfile);
pfile->no_macro_expand++; pfile->no_macro_expand++;
if (get_directive_token (pfile) != CPP_NAME) if (_cpp_get_directive_token (pfile) != CPP_NAME)
{ {
cpp_error (pfile, "`#define' must be followed by an identifier"); cpp_error (pfile, "`#define' must be followed by an identifier");
goto invalid; goto invalid;
...@@ -646,7 +267,7 @@ get_macro_name (pfile) ...@@ -646,7 +267,7 @@ get_macro_name (pfile)
return len; return len;
invalid: invalid:
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--; pfile->no_macro_expand--;
return 0; return 0;
} }
...@@ -748,222 +369,48 @@ do_define (pfile, keyword) ...@@ -748,222 +369,48 @@ do_define (pfile, keyword)
return 0; return 0;
} }
/*
* write out a #line command, for instance, after an #include file.
* FILE_CHANGE says whether we are entering a file, leaving, or neither.
*/
/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack. void
If BUFFER != NULL, then use the LENGTH characters in BUFFER _cpp_output_line_command (pfile, file_change)
as the new input buffer.
Return the new buffer, or NULL on failure. */
cpp_buffer *
cpp_push_buffer (pfile, buffer, length)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *buffer; enum file_change_code file_change;
long length;
{ {
cpp_buffer *buf = CPP_BUFFER (pfile); long line;
cpp_buffer *new; cpp_buffer *ip;
if (++pfile->buffer_stack_depth == CPP_STACK_MAX)
{
cpp_fatal (pfile, "macro or `#include' recursion too deep");
return NULL;
}
new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
new->if_stack = pfile->if_stack;
new->cleanup = null_cleanup;
new->buf = new->cur = buffer;
new->alimit = new->rlimit = buffer + length;
new->prev = buf;
new->mark = -1;
new->line_base = NULL;
CPP_BUFFER (pfile) = new;
return new;
}
cpp_buffer * if (CPP_OPTIONS (pfile)->no_line_commands
cpp_pop_buffer (pfile) || CPP_OPTIONS (pfile)->no_output)
cpp_reader *pfile; return;
{
cpp_buffer *buf = CPP_BUFFER (pfile);
if (ACTIVE_MARK_P())
cpp_ice (pfile, "mark active in cpp_pop_buffer");
(*buf->cleanup) (buf, pfile);
CPP_BUFFER (pfile) = CPP_PREV_BUFFER (buf);
free (buf);
pfile->buffer_stack_depth--;
return CPP_BUFFER (pfile);
}
/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer. ip = cpp_file_buffer (pfile);
Pop the buffer when done. */ cpp_buf_line_and_col (ip, &line, NULL);
void /* If the current file has not changed, we omit the #line if it would
cpp_scan_buffer (pfile) appear to be a no-op, and we output a few newlines instead
cpp_reader *pfile; if we want to increase the line number by a small amount.
{ We cannot do this if pfile->lineno is zero, because that means we
cpp_buffer *buffer = CPP_BUFFER (pfile); haven't output any line commands yet. (The very first line command
enum cpp_token token; output is a `same_file' command.) */
if (CPP_OPTIONS (pfile)->no_output) if (file_change == same_file && pfile->lineno != 0)
{ {
long old_written = CPP_WRITTEN (pfile); if (line == pfile->lineno)
/* In no-output mode, we can ignore everything but directives. */ return;
for (;;)
/* If the inherited line number is a little too small,
output some newlines instead of a #line command. */
if (line > pfile->lineno && line < pfile->lineno + 8)
{ {
if (! pfile->only_seen_white) CPP_RESERVE (pfile, 20);
skip_rest_of_line (pfile); while (line > pfile->lineno)
token = cpp_get_token (pfile);
if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{ {
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) != NULL) CPP_PUTC_Q (pfile, '\n');
cpp_pop_buffer (pfile); pfile->lineno++;
break;
} }
} return;
CPP_SET_WRITTEN (pfile, old_written);
}
else
{
for (;;)
{
token = cpp_get_token (pfile);
if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) != NULL)
cpp_pop_buffer (pfile);
break;
}
}
}
}
/*
* Rescan a string (which may have escape marks) into pfile's buffer.
* Place the result in pfile->token_buffer.
*
* The input is copied before it is scanned, so it is safe to pass
* it something from the token_buffer that will get overwritten
* (because it follows CPP_WRITTEN). This is used by do_include.
*/
void
cpp_expand_to_buffer (pfile, buf, length)
cpp_reader *pfile;
const U_CHAR *buf;
int length;
{
register cpp_buffer *ip;
U_CHAR *buf1;
int save_no_output;
if (length < 0)
{
cpp_ice (pfile, "length < 0 in cpp_expand_to_buffer");
return;
}
/* Set up the input on the input stack. */
buf1 = (U_CHAR *) alloca (length + 1);
memcpy (buf1, buf, length);
buf1[length] = 0;
ip = cpp_push_buffer (pfile, buf1, length);
if (ip == NULL)
return;
ip->has_escapes = 1;
/* Scan the input, create the output. */
save_no_output = CPP_OPTIONS (pfile)->no_output;
CPP_OPTIONS (pfile)->no_output = 0;
CPP_OPTIONS (pfile)->no_line_commands++;
cpp_scan_buffer (pfile);
CPP_OPTIONS (pfile)->no_line_commands--;
CPP_OPTIONS (pfile)->no_output = save_no_output;
CPP_NUL_TERMINATE (pfile);
}
void
cpp_buf_line_and_col (pbuf, linep, colp)
register cpp_buffer *pbuf;
long *linep, *colp;
{
if (pbuf)
{
*linep = pbuf->lineno;
if (colp)
*colp = pbuf->cur - pbuf->line_base;
}
else
{
*linep = 0;
if (colp)
*colp = 0;
}
}
/* Return the cpp_buffer that corresponds to a file (not a macro). */
cpp_buffer *
cpp_file_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip;
for (ip = CPP_BUFFER (pfile); ip; ip = CPP_PREV_BUFFER (ip))
if (ip->ihash != NULL)
return ip;
return NULL;
}
/*
* write out a #line command, for instance, after an #include file.
* FILE_CHANGE says whether we are entering a file, leaving, or neither.
*/
void
output_line_command (pfile, file_change)
cpp_reader *pfile;
enum file_change_code file_change;
{
long line;
cpp_buffer *ip;
if (CPP_OPTIONS (pfile)->no_line_commands
|| CPP_OPTIONS (pfile)->no_output)
return;
ip = cpp_file_buffer (pfile);
cpp_buf_line_and_col (ip, &line, NULL);
/* If the current file has not changed, we omit the #line if it would
appear to be a no-op, and we output a few newlines instead
if we want to increase the line number by a small amount.
We cannot do this if pfile->lineno is zero, because that means we
haven't output any line commands yet. (The very first line command
output is a `same_file' command.) */
if (file_change == same_file && pfile->lineno != 0)
{
if (line == pfile->lineno)
return;
/* If the inherited line number is a little too small,
output some newlines instead of a #line command. */
if (line > pfile->lineno && line < pfile->lineno + 8)
{
CPP_RESERVE (pfile, 20);
while (line > pfile->lineno)
{
CPP_PUTC_Q (pfile, '\n');
pfile->lineno++;
}
return;
} }
} }
...@@ -973,7 +420,7 @@ output_line_command (pfile, file_change) ...@@ -973,7 +420,7 @@ output_line_command (pfile, file_change)
sprintf ((char *) CPP_PWRITTEN (pfile), "%ld ", line); sprintf ((char *) CPP_PWRITTEN (pfile), "%ld ", line);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile))); CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
quote_string (pfile, ip->nominal_fname); _cpp_quote_string (pfile, ip->nominal_fname);
if (file_change != same_file && file_change != rename_file) if (file_change != same_file && file_change != rename_file)
{ {
CPP_PUTC_Q (pfile, ' '); CPP_PUTC_Q (pfile, ' ');
...@@ -997,61 +444,7 @@ output_line_command (pfile, file_change) ...@@ -997,61 +444,7 @@ output_line_command (pfile, file_change)
pfile->lineno = line; pfile->lineno = line;
} }
/* Handle #include and #import. */
/* Like cpp_get_token, except that it does not read past end-of-line.
Also, horizontal space is skipped, and macros are popped. */
enum cpp_token
get_directive_token (pfile)
cpp_reader *pfile;
{
long old_written = CPP_WRITTEN (pfile);
enum cpp_token token;
for (;;)
{
cpp_skip_hspace (pfile);
if (PEEKC () == '\n')
return CPP_VSPACE;
token = cpp_get_token (pfile);
/* token could be hspace at the beginning of a macro. */
if (token == CPP_HSPACE || token == CPP_COMMENT)
{
CPP_SET_WRITTEN (pfile, old_written);
continue;
}
/* token cannot be vspace, it would have been caught above. */
if (token == CPP_VSPACE)
{
cpp_ice (pfile, "VSPACE in get_directive_token");
return token;
}
/* token cannot be POP unless the buffer is a macro buffer. */
if (token != CPP_POP)
return token;
if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
{
cpp_ice (pfile, "POP of file buffer in get_directive_token");
return token;
}
/* We must pop the buffer by hand, or else cpp_get_token might
hand us white space or newline on the next invocation. */
cpp_pop_buffer (pfile);
}
}
/* Handle #include and #import.
This function expects to see "fname" or <fname> on the input.
The input is normally in part of the output_buffer following
CPP_WRITTEN, and will get overwritten by output_line_command.
I.e. in input file specification has been popped by handle_directive.
This is safe. */
static int static int
do_include (pfile, keyword) do_include (pfile, keyword)
...@@ -1094,7 +487,7 @@ do_include (pfile, keyword) ...@@ -1094,7 +487,7 @@ do_include (pfile, keyword)
} }
pfile->parsing_include_directive++; pfile->parsing_include_directive++;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
pfile->parsing_include_directive--; pfile->parsing_include_directive--;
if (token == CPP_STRING) if (token == CPP_STRING)
...@@ -1120,7 +513,7 @@ do_include (pfile, keyword) ...@@ -1120,7 +513,7 @@ do_include (pfile, keyword)
cpp_error (pfile, cpp_error (pfile,
"`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name); "`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
return 0; return 0;
} }
...@@ -1129,10 +522,10 @@ do_include (pfile, keyword) ...@@ -1129,10 +522,10 @@ do_include (pfile, keyword)
memcpy (ftok, pfile->token_buffer + old_written, flen); memcpy (ftok, pfile->token_buffer + old_written, flen);
ftok[flen] = '\0'; ftok[flen] = '\0';
if (get_directive_token (pfile) != CPP_VSPACE) if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
{ {
cpp_error (pfile, "junk at end of `#include'"); cpp_error (pfile, "junk at end of `#include'");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
} }
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
...@@ -1270,7 +663,7 @@ do_include (pfile, keyword) ...@@ -1270,7 +663,7 @@ do_include (pfile, keyword)
if (_cpp_read_include_file (pfile, fd, ihash)) if (_cpp_read_include_file (pfile, fd, ihash))
{ {
output_line_command (pfile, enter_file); _cpp_output_line_command (pfile, enter_file);
if (angle_brackets) if (angle_brackets)
pfile->system_include_depth++; /* Decremented in file_cleanup. */ pfile->system_include_depth++; /* Decremented in file_cleanup. */
} }
...@@ -1288,9 +681,10 @@ read_line_number (pfile, num) ...@@ -1288,9 +681,10 @@ read_line_number (pfile, num)
int *num; int *num;
{ {
long save_written = CPP_WRITTEN (pfile); long save_written = CPP_WRITTEN (pfile);
U_CHAR *p = pfile->token_buffer + save_written; U_CHAR *p;
enum cpp_token token = get_directive_token (pfile); enum cpp_token token = _cpp_get_directive_token (pfile);
CPP_SET_WRITTEN (pfile, save_written); CPP_SET_WRITTEN (pfile, save_written);
p = pfile->token_buffer + save_written;
if (token == CPP_NUMBER && *p >= '1' && *p <= '4' && p[1] == '\0') if (token == CPP_NUMBER && *p >= '1' && *p <= '4' && p[1] == '\0')
{ {
...@@ -1321,7 +715,7 @@ do_line (pfile, keyword) ...@@ -1321,7 +715,7 @@ do_line (pfile, keyword)
enum cpp_token token; enum cpp_token token;
char *x; char *x;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_NUMBER) if (token != CPP_NUMBER)
{ {
...@@ -1340,7 +734,7 @@ do_line (pfile, keyword) ...@@ -1340,7 +734,7 @@ do_line (pfile, keyword)
if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767)) if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767))
cpp_pedwarn (pfile, "line number out of range in `#line' command"); cpp_pedwarn (pfile, "line number out of range in `#line' command");
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_STRING) if (token == CPP_STRING)
{ {
...@@ -1416,11 +810,11 @@ do_line (pfile, keyword) ...@@ -1416,11 +810,11 @@ do_line (pfile, keyword)
we must store a line number now that is one less. */ we must store a line number now that is one less. */
ip->lineno = new_lineno - 1; ip->lineno = new_lineno - 1;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
output_line_command (pfile, file_change); _cpp_output_line_command (pfile, file_change);
return 0; return 0;
bad_line_directive: bad_line_directive:
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
return 0; return 0;
} }
...@@ -1440,16 +834,16 @@ do_undef (pfile, keyword) ...@@ -1440,16 +834,16 @@ do_undef (pfile, keyword)
long here = CPP_WRITTEN (pfile); long here = CPP_WRITTEN (pfile);
enum cpp_token token; enum cpp_token token;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = GETC(); c = GETC();
if (! is_idstart(c)) if (! is_idstart(c))
{ {
cpp_error (pfile, "token after #undef is not an identifier"); cpp_error (pfile, "token after #undef is not an identifier");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
return 1; return 1;
} }
parse_name (pfile, c); _cpp_parse_name (pfile, c);
buf = pfile->token_buffer + here; buf = pfile->token_buffer + here;
limit = CPP_PWRITTEN(pfile); limit = CPP_PWRITTEN(pfile);
...@@ -1459,11 +853,11 @@ do_undef (pfile, keyword) ...@@ -1459,11 +853,11 @@ do_undef (pfile, keyword)
memcpy (name, buf, len); memcpy (name, buf, len);
name[len] = '\0'; name[len] = '\0';
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_VSPACE) if (token != CPP_VSPACE)
{ {
cpp_pedwarn (pfile, "junk on line after #undef"); cpp_pedwarn (pfile, "junk on line after #undef");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
} }
CPP_SET_WRITTEN (pfile, here); CPP_SET_WRITTEN (pfile, here);
...@@ -1489,25 +883,6 @@ do_undef (pfile, keyword) ...@@ -1489,25 +883,6 @@ do_undef (pfile, keyword)
return 0; return 0;
} }
/* Wrap do_undef for -U processing. */
void
cpp_undef (pfile, macro)
cpp_reader *pfile;
const char *macro;
{
/* Copy the string so we can append a newline. */
size_t len = strlen (macro);
char *buf = alloca (len + 2);
memcpy (buf, macro, len);
buf[len] = '\n';
buf[len + 1] = '\0';
if (cpp_push_buffer (pfile, buf, len + 1))
{
do_undef (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
/* /*
* Report an error detected by the program we are processing. * Report an error detected by the program we are processing.
* Use the text of the line in the error message. * Use the text of the line in the error message.
...@@ -1521,9 +896,9 @@ do_error (pfile, keyword) ...@@ -1521,9 +896,9 @@ do_error (pfile, keyword)
{ {
const U_CHAR *text, *limit; const U_CHAR *text, *limit;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur; text = CPP_BUFFER (pfile)->cur;
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur; limit = CPP_BUFFER (pfile)->cur;
cpp_error (pfile, "#error %.*s", (int)(limit - text), text); cpp_error (pfile, "#error %.*s", (int)(limit - text), text);
...@@ -1542,9 +917,9 @@ do_warning (pfile, keyword) ...@@ -1542,9 +917,9 @@ do_warning (pfile, keyword)
{ {
const U_CHAR *text, *limit; const U_CHAR *text, *limit;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur; text = CPP_BUFFER (pfile)->cur;
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur; limit = CPP_BUFFER (pfile)->cur;
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile))
...@@ -1570,14 +945,14 @@ do_ident (pfile, keyword) ...@@ -1570,14 +945,14 @@ do_ident (pfile, keyword)
CPP_PUTS (pfile, "#ident ", 7); CPP_PUTS (pfile, "#ident ", 7);
/* Next token should be a string constant. */ /* Next token should be a string constant. */
if (get_directive_token (pfile) == CPP_STRING) if (_cpp_get_directive_token (pfile) == CPP_STRING)
/* And then a newline. */ /* And then a newline. */
if (get_directive_token (pfile) == CPP_VSPACE) if (_cpp_get_directive_token (pfile) == CPP_VSPACE)
/* Good - ship it. */ /* Good - ship it. */
return 0; return 0;
cpp_error (pfile, "invalid #ident"); cpp_error (pfile, "invalid #ident");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* discard directive */ CPP_SET_WRITTEN (pfile, old_written); /* discard directive */
return 0; return 0;
...@@ -1616,7 +991,7 @@ do_pragma (pfile, keyword) ...@@ -1616,7 +991,7 @@ do_pragma (pfile, keyword)
key = CPP_WRITTEN (pfile); key = CPP_WRITTEN (pfile);
pfile->no_macro_expand++; pfile->no_macro_expand++;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME) if (token != CPP_NAME)
{ {
if (token == CPP_VSPACE) if (token == CPP_VSPACE)
...@@ -1639,7 +1014,7 @@ do_pragma (pfile, keyword) ...@@ -1639,7 +1014,7 @@ do_pragma (pfile, keyword)
pop = do_pragma_default (pfile); pop = do_pragma_default (pfile);
#undef tokis #undef tokis
if (get_directive_token (pfile) != CPP_VSPACE) if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
goto skip; goto skip;
if (pop) if (pop)
...@@ -1649,7 +1024,7 @@ do_pragma (pfile, keyword) ...@@ -1649,7 +1024,7 @@ do_pragma (pfile, keyword)
skip: skip:
cpp_error (pfile, "malformed #pragma directive"); cpp_error (pfile, "malformed #pragma directive");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
empty: empty:
CPP_SET_WRITTEN (pfile, here); CPP_SET_WRITTEN (pfile, here);
pfile->no_macro_expand--; pfile->no_macro_expand--;
...@@ -1660,7 +1035,7 @@ static int ...@@ -1660,7 +1035,7 @@ static int
do_pragma_default (pfile) do_pragma_default (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
while (get_directive_token (pfile) != CPP_VSPACE) while (_cpp_get_directive_token (pfile) != CPP_VSPACE)
CPP_PUTC (pfile, ' '); CPP_PUTC (pfile, ' ');
return 0; return 0;
} }
...@@ -1696,7 +1071,7 @@ do_pragma_implementation (pfile) ...@@ -1696,7 +1071,7 @@ do_pragma_implementation (pfile)
U_CHAR *copy; U_CHAR *copy;
size_t len; size_t len;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_VSPACE) if (token == CPP_VSPACE)
return 0; return 0;
else if (token != CPP_STRING) else if (token != CPP_STRING)
...@@ -1742,13 +1117,13 @@ do_pragma_poison (pfile) ...@@ -1742,13 +1117,13 @@ do_pragma_poison (pfile)
for (;;) for (;;)
{ {
written = CPP_WRITTEN (pfile); written = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_VSPACE) if (token == CPP_VSPACE)
break; break;
if (token != CPP_NAME) if (token != CPP_NAME)
{ {
cpp_error (pfile, "invalid #pragma poison directive"); cpp_error (pfile, "invalid #pragma poison directive");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
return 1; return 1;
} }
...@@ -1789,7 +1164,7 @@ do_sccs (pfile, keyword) ...@@ -1789,7 +1164,7 @@ do_sccs (pfile, keyword)
{ {
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'"); cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
return 0; return 0;
} }
#endif #endif
...@@ -1817,18 +1192,18 @@ detect_if_not_defined (pfile) ...@@ -1817,18 +1192,18 @@ detect_if_not_defined (pfile)
/* Save state required for restore. */ /* Save state required for restore. */
pfile->no_macro_expand++; pfile->no_macro_expand++;
parse_set_mark (pfile); CPP_SET_MARK (pfile);
base_offset = CPP_WRITTEN (pfile); base_offset = CPP_WRITTEN (pfile);
/* Look for `!', */ /* Look for `!', */
if (get_directive_token (pfile) != CPP_OTHER if (_cpp_get_directive_token (pfile) != CPP_OTHER
|| CPP_WRITTEN (pfile) != (size_t) base_offset + 1 || CPP_WRITTEN (pfile) != (size_t) base_offset + 1
|| CPP_PWRITTEN (pfile)[-1] != '!') || CPP_PWRITTEN (pfile)[-1] != '!')
goto restore; goto restore;
/* ...then `defined', */ /* ...then `defined', */
token_offset = CPP_WRITTEN (pfile); token_offset = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME) if (token != CPP_NAME)
goto restore; goto restore;
ident = pfile->token_buffer + token_offset; ident = pfile->token_buffer + token_offset;
...@@ -1838,11 +1213,11 @@ detect_if_not_defined (pfile) ...@@ -1838,11 +1213,11 @@ detect_if_not_defined (pfile)
/* ...then an optional '(' and the name, */ /* ...then an optional '(' and the name, */
token_offset = CPP_WRITTEN (pfile); token_offset = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_LPAREN) if (token == CPP_LPAREN)
{ {
token_offset = CPP_WRITTEN (pfile); token_offset = CPP_WRITTEN (pfile);
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME) if (token != CPP_NAME)
goto restore; goto restore;
need_rparen = 1; need_rparen = 1;
...@@ -1854,22 +1229,22 @@ detect_if_not_defined (pfile) ...@@ -1854,22 +1229,22 @@ detect_if_not_defined (pfile)
CPP_NUL_TERMINATE (pfile); CPP_NUL_TERMINATE (pfile);
/* ...then the ')', if necessary, */ /* ...then the ')', if necessary, */
if ((!need_rparen || get_directive_token (pfile) == CPP_RPAREN) if ((!need_rparen || _cpp_get_directive_token (pfile) == CPP_RPAREN)
/* ...and make sure there's nothing else on the line. */ /* ...and make sure there's nothing else on the line. */
&& get_directive_token (pfile) == CPP_VSPACE) && _cpp_get_directive_token (pfile) == CPP_VSPACE)
control_macro = (U_CHAR *) xstrdup (ident); control_macro = (U_CHAR *) xstrdup (ident);
restore: restore:
CPP_SET_WRITTEN (pfile, base_offset); CPP_SET_WRITTEN (pfile, base_offset);
pfile->no_macro_expand--; pfile->no_macro_expand--;
parse_goto_mark (pfile); CPP_GOTO_MARK (pfile);
} }
return control_macro; return control_macro;
} }
/* /*
* #if is straightforward; just call eval_if_expr, then conditional_skip. * #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
* Also, check for a reinclude preventer of the form #if !defined (MACRO). * Also, check for a reinclude preventer of the form #if !defined (MACRO).
*/ */
...@@ -1879,7 +1254,7 @@ do_if (pfile, keyword) ...@@ -1879,7 +1254,7 @@ do_if (pfile, keyword)
const struct directive *keyword ATTRIBUTE_UNUSED; const struct directive *keyword ATTRIBUTE_UNUSED;
{ {
U_CHAR *control_macro = detect_if_not_defined (pfile); U_CHAR *control_macro = detect_if_not_defined (pfile);
int value = eval_if_expr (pfile); int value = _cpp_parse_expr (pfile);
conditional_skip (pfile, value == 0, T_IF, control_macro); conditional_skip (pfile, value == 0, T_IF, control_macro);
return 0; return 0;
} }
...@@ -1914,39 +1289,17 @@ do_elif (pfile, keyword) ...@@ -1914,39 +1289,17 @@ do_elif (pfile, keyword)
skip_if_group (pfile); skip_if_group (pfile);
else else
{ {
int value = eval_if_expr (pfile); if (_cpp_parse_expr (pfile) == 0)
if (value == 0)
skip_if_group (pfile); skip_if_group (pfile);
else else
{ {
++pfile->if_stack->if_succeeded; /* continue processing input */ ++pfile->if_stack->if_succeeded; /* continue processing input */
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
} }
} }
return 0; return 0;
} }
/* Thin wrapper around _cpp_parse_expr, which doesn't have access to
* skip_rest_of_line. Also centralizes toggling parsing_if_directive.
*/
static int
eval_if_expr (pfile)
cpp_reader *pfile;
{
int value;
long old_written = CPP_WRITTEN (pfile);
pfile->parsing_if_directive++;
value = _cpp_parse_expr (pfile);
pfile->parsing_if_directive--;
skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
return value;
}
/* /*
* routine to handle ifdef/ifndef. Try to look up the symbol, * routine to handle ifdef/ifndef. Try to look up the symbol,
* then do or don't skip to the #endif/#else/#elif depending * then do or don't skip to the #endif/#else/#elif depending
...@@ -1971,7 +1324,7 @@ do_ifdef (pfile, keyword) ...@@ -1971,7 +1324,7 @@ do_ifdef (pfile, keyword)
start_of_file = pfile->only_seen_white == 2; start_of_file = pfile->only_seen_white == 2;
pfile->no_macro_expand++; pfile->no_macro_expand++;
token = get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
pfile->no_macro_expand--; pfile->no_macro_expand--;
ident = pfile->token_buffer + old_written; ident = pfile->token_buffer + old_written;
...@@ -2005,12 +1358,12 @@ do_ifdef (pfile, keyword) ...@@ -2005,12 +1358,12 @@ do_ifdef (pfile, keyword)
if (!CPP_TRADITIONAL (pfile)) if (!CPP_TRADITIONAL (pfile))
{ int c; { int c;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = PEEKC (); c = PEEKC ();
if (c != EOF && c != '\n') if (c != EOF && c != '\n')
cpp_pedwarn (pfile, "garbage at end of `#%s' argument", keyword->name); cpp_pedwarn (pfile, "garbage at end of `#%s' argument", keyword->name);
} }
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
conditional_skip (pfile, skip, T_IF, control_macro); conditional_skip (pfile, skip, T_IF, control_macro);
return 0; return 0;
...@@ -2043,7 +1396,7 @@ conditional_skip (pfile, skip, type, control_macro) ...@@ -2043,7 +1396,7 @@ conditional_skip (pfile, skip, type, control_macro)
return; return;
} else { } else {
++pfile->if_stack->if_succeeded; ++pfile->if_stack->if_succeeded;
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
} }
} }
...@@ -2061,10 +1414,10 @@ consider_directive_while_skipping (pfile, stack) ...@@ -2061,10 +1414,10 @@ consider_directive_while_skipping (pfile, stack)
const struct directive *kt; const struct directive *kt;
IF_STACK *temp; IF_STACK *temp;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
ident = CPP_WRITTEN (pfile); ident = CPP_WRITTEN (pfile);
parse_name (pfile, GETC()); _cpp_parse_name (pfile, GETC());
ident_len = CPP_WRITTEN (pfile) - ident; ident_len = CPP_WRITTEN (pfile) - ident;
CPP_SET_WRITTEN (pfile, ident); CPP_SET_WRITTEN (pfile, ident);
...@@ -2137,7 +1490,7 @@ skip_if_group (pfile) ...@@ -2137,7 +1490,7 @@ skip_if_group (pfile)
beg_of_line = CPP_BUFFER (pfile)->cur; beg_of_line = CPP_BUFFER (pfile)->cur;
if (! CPP_TRADITIONAL (pfile)) if (! CPP_TRADITIONAL (pfile))
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = GETC(); c = GETC();
if (c == '\n') if (c == '\n')
{ {
...@@ -2153,7 +1506,7 @@ skip_if_group (pfile) ...@@ -2153,7 +1506,7 @@ skip_if_group (pfile)
return; /* Caller will issue error. */ return; /* Caller will issue error. */
FORWARD(-1); FORWARD(-1);
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
c = GETC(); c = GETC();
if (c == EOF) if (c == EOF)
...@@ -2181,7 +1534,7 @@ do_else (pfile, keyword) ...@@ -2181,7 +1534,7 @@ do_else (pfile, keyword)
const struct directive *keyword ATTRIBUTE_UNUSED; const struct directive *keyword ATTRIBUTE_UNUSED;
{ {
validate_else (pfile, "#else"); validate_else (pfile, "#else");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
{ {
...@@ -2208,7 +1561,7 @@ do_else (pfile, keyword) ...@@ -2208,7 +1561,7 @@ do_else (pfile, keyword)
else else
{ {
++pfile->if_stack->if_succeeded; /* continue processing input */ ++pfile->if_stack->if_succeeded; /* continue processing input */
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
} }
return 0; return 0;
} }
...@@ -2223,7 +1576,7 @@ do_endif (pfile, keyword) ...@@ -2223,7 +1576,7 @@ do_endif (pfile, keyword)
const struct directive *keyword ATTRIBUTE_UNUSED; const struct directive *keyword ATTRIBUTE_UNUSED;
{ {
validate_else (pfile, "#endif"); validate_else (pfile, "#endif");
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
cpp_error (pfile, "`#endif' not within a conditional"); cpp_error (pfile, "`#endif' not within a conditional");
...@@ -2237,16 +1590,16 @@ do_endif (pfile, keyword) ...@@ -2237,16 +1590,16 @@ do_endif (pfile, keyword)
See if it is at the end of the file. */ See if it is at the end of the file. */
int c; int c;
parse_set_mark (pfile); CPP_SET_MARK (pfile);
for (;;) for (;;)
{ {
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = GETC (); c = GETC ();
if (c != '\n') if (c != '\n')
break; break;
} }
parse_goto_mark (pfile); CPP_GOTO_MARK (pfile);
if (c == EOF) if (c == EOF)
{ {
...@@ -2258,7 +1611,7 @@ do_endif (pfile, keyword) ...@@ -2258,7 +1611,7 @@ do_endif (pfile, keyword)
} }
} }
free (temp); free (temp);
output_line_command (pfile, same_file); _cpp_output_line_command (pfile, same_file);
} }
return 0; return 0;
} }
...@@ -2275,7 +1628,7 @@ validate_else (pfile, directive) ...@@ -2275,7 +1628,7 @@ validate_else (pfile, directive)
if (! CPP_PEDANTIC (pfile)) if (! CPP_PEDANTIC (pfile))
return; return;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
if (PEEKC () != '\n') if (PEEKC () != '\n')
cpp_pedwarn (pfile, cpp_pedwarn (pfile,
"text following `%s' violates ANSI standard", directive); "text following `%s' violates ANSI standard", directive);
...@@ -2300,734 +1653,40 @@ if_directive_name (pfile, ifs) ...@@ -2300,734 +1653,40 @@ if_directive_name (pfile, ifs)
} }
} }
/* Get the next token, and add it to the text in pfile->token_buffer. void
Return the kind of token we got. */ _cpp_handle_eof (pfile)
enum cpp_token
cpp_get_token (pfile)
cpp_reader *pfile;
{
register int c, c2, c3;
enum cpp_token token;
struct cpp_options *opts = CPP_OPTIONS (pfile);
get_next:
c = GETC();
if (c == EOF)
{
if (CPP_BUFFER (pfile)->manual_pop)
/* If we've been reading from redirected input, the
frontend will pop the buffer. */
return CPP_EOF;
else if (CPP_BUFFER (pfile)->seen_eof)
{
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) == NULL)
return CPP_EOF;
cpp_pop_buffer (pfile);
goto get_next;
}
else
{
cpp_buffer *next_buf = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
struct if_stack *ifs, *nifs;
/* Unwind the conditional stack and generate error messages. */
for (ifs = pfile->if_stack;
ifs != CPP_BUFFER (pfile)->if_stack;
ifs = nifs)
{
cpp_error_with_line (pfile, ifs->lineno, -1,
"unterminated `%s' conditional",
if_directive_name (pfile, ifs));
nifs = ifs->next;
free (ifs);
}
pfile->if_stack = ifs;
if (CPP_BUFFER (pfile)->nominal_fname && next_buf != NULL)
{
/* We're about to return from an #include file.
Emit #line information now (as part of the CPP_POP) result.
But the #line refers to the file we will pop to. */
cpp_buffer *cur_buffer = CPP_BUFFER (pfile);
CPP_BUFFER (pfile) = next_buf;
pfile->input_stack_listing_current = 0;
output_line_command (pfile, leave_file);
CPP_BUFFER (pfile) = cur_buffer;
}
CPP_BUFFER (pfile)->seen_eof = 1;
return CPP_POP;
}
}
else
{
switch (c)
{
case '/':
if (PEEKC () == '=')
goto op2;
comment:
if (opts->discard_comments)
c = skip_comment (pfile, c);
else
c = copy_comment (pfile, c);
if (c != ' ')
goto randomchar;
/* Comments are equivalent to spaces.
For -traditional, a comment is equivalent to nothing. */
if (opts->traditional || !opts->discard_comments)
return CPP_COMMENT;
else
{
CPP_PUTC (pfile, c);
return CPP_HSPACE;
}
case '#':
if (pfile->parsing_if_directive)
{
cpp_skip_hspace (pfile);
parse_assertion (pfile);
return CPP_ASSERTION;
}
if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
{
CPP_RESERVE (pfile, 3);
CPP_PUTC_Q (pfile, '#');
CPP_NUL_TERMINATE_Q (pfile);
if (PEEKC () != '#')
return CPP_STRINGIZE;
FORWARD (1);
CPP_PUTC_Q (pfile, '#');
CPP_NUL_TERMINATE_Q (pfile);
return CPP_TOKPASTE;
}
if (!pfile->only_seen_white)
goto randomchar;
/* -traditional directives are recognized only with the # in
column 1.
XXX Layering violation. */
if (CPP_TRADITIONAL (pfile)
&& CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base != 1)
goto randomchar;
if (handle_directive (pfile))
return CPP_DIRECTIVE;
pfile->only_seen_white = 0;
goto randomchar;
case '\"':
case '\'':
parse_string (pfile, c);
pfile->only_seen_white = 0;
return c == '\'' ? CPP_CHAR : CPP_STRING;
case '$':
if (!opts->dollars_in_ident)
goto randomchar;
goto letter;
case ':':
if (opts->cplusplus && PEEKC () == ':')
goto op2;
goto randomchar;
case '&':
case '+':
case '|':
c2 = PEEKC ();
if (c2 == c || c2 == '=')
goto op2;
goto randomchar;
case '*':
case '!':
case '%':
case '=':
case '^':
if (PEEKC () == '=')
goto op2;
goto randomchar;
case '-':
c2 = PEEKC ();
if (c2 == '-' && opts->chill)
goto comment; /* Chill style comment */
if (c2 == '-' || c2 == '=')
goto op2;
if (c2 == '>')
{
if (opts->cplusplus && PEEKN (1) == '*')
{
/* In C++, there's a ->* operator. */
token = CPP_OTHER;
pfile->only_seen_white = 0;
CPP_RESERVE (pfile, 4);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, GETC ());
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
return token;
}
goto op2;
}
goto randomchar;
case '<':
if (pfile->parsing_include_directive)
{
for (;;)
{
CPP_PUTC (pfile, c);
if (c == '>')
break;
c = GETC ();
if (c == '\n' || c == EOF)
{
cpp_error (pfile,
"missing '>' in `#include <FILENAME>'");
break;
}
else if (c == '\r')
{
if (!CPP_BUFFER (pfile)->has_escapes)
{
/* Backslash newline is replaced by nothing. */
CPP_ADJUST_WRITTEN (pfile, -1);
CPP_BUMP_LINE (pfile);
}
else
{
/* We might conceivably get \r- or \r<space> in
here. Just delete 'em. */
int d = GETC();
if (d != '-' && d != ' ')
cpp_ice (pfile, "unrecognized escape \\r%c", d);
CPP_ADJUST_WRITTEN (pfile, -1);
}
}
}
return CPP_STRING;
}
/* else fall through */
case '>':
c2 = PEEKC ();
if (c2 == '=')
goto op2;
/* GNU C++ supports MIN and MAX operators <? and >?. */
if (c2 != c && (!opts->cplusplus || c2 != '?'))
goto randomchar;
FORWARD(1);
CPP_RESERVE (pfile, 4);
CPP_PUTC (pfile, c);
CPP_PUTC (pfile, c2);
c3 = PEEKC ();
if (c3 == '=')
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_OTHER;
case '.':
c2 = PEEKC ();
if (ISDIGIT(c2))
{
CPP_RESERVE(pfile, 2);
CPP_PUTC_Q (pfile, '.');
c = GETC ();
goto number;
}
/* In C++ there's a .* operator. */
if (opts->cplusplus && c2 == '*')
goto op2;
if (c2 == '.' && PEEKN(1) == '.')
{
CPP_RESERVE(pfile, 4);
CPP_PUTC_Q (pfile, '.');
CPP_PUTC_Q (pfile, '.');
CPP_PUTC_Q (pfile, '.');
FORWARD (2);
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_3DOTS;
}
goto randomchar;
op2:
token = CPP_OTHER;
pfile->only_seen_white = 0;
CPP_RESERVE(pfile, 3);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, GETC ());
CPP_NUL_TERMINATE_Q (pfile);
return token;
case 'L':
c2 = PEEKC ();
if ((c2 == '\'' || c2 == '\"') && !CPP_TRADITIONAL (pfile))
{
CPP_PUTC (pfile, c);
c = GETC ();
parse_string (pfile, c);
pfile->only_seen_white = 0;
return c == '\'' ? CPP_WCHAR : CPP_WSTRING;
}
goto letter;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
number:
c2 = '.';
for (;;)
{
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
c = PEEKC ();
if (c == EOF)
break;
if (!is_numchar(c) && c != '.'
&& ((c2 != 'e' && c2 != 'E'
&& ((c2 != 'p' && c2 != 'P')
|| CPP_OPTIONS (pfile)->c89))
|| (c != '+' && c != '-')))
break;
FORWARD(1);
c2= c;
}
CPP_NUL_TERMINATE_Q (pfile);
pfile->only_seen_white = 0;
return CPP_NUMBER;
case 'b': case 'c': case 'd': case 'h': case 'o':
case 'B': case 'C': case 'D': case 'H': case 'O':
if (opts->chill && PEEKC () == '\'')
{
pfile->only_seen_white = 0;
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
CPP_PUTC_Q (pfile, '\'');
FORWARD(1);
for (;;)
{
c = GETC();
if (c == EOF)
goto chill_number_eof;
if (!is_numchar(c))
break;
CPP_PUTC (pfile, c);
}
if (c == '\'')
{
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c);
CPP_NUL_TERMINATE_Q (pfile);
return CPP_STRING;
}
else
{
FORWARD(-1);
chill_number_eof:
CPP_NUL_TERMINATE (pfile);
return CPP_NUMBER;
}
}
else
goto letter;
case '_':
case 'a': case 'e': case 'f': case 'g': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'p': case 'q':
case 'r': case 's': case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z':
case 'A': case 'E': case 'F': case 'G': case 'I': case 'J':
case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
letter:
{
HASHNODE *hp;
unsigned char *ident;
int before_name_written = CPP_WRITTEN (pfile);
int ident_len;
parse_name (pfile, c);
pfile->only_seen_white = 0;
if (pfile->no_macro_expand)
return CPP_NAME;
ident = pfile->token_buffer + before_name_written;
ident_len = CPP_PWRITTEN (pfile) - ident;
hp = _cpp_lookup (pfile, ident, ident_len);
if (!hp)
return CPP_NAME;
if (hp->type == T_DISABLED)
{
if (pfile->output_escapes)
{ /* Return "\r-IDENT", followed by '\0'. */
int i;
CPP_RESERVE (pfile, 3);
ident = pfile->token_buffer + before_name_written;
CPP_ADJUST_WRITTEN (pfile, 2);
for (i = ident_len; i >= 0; i--) ident[i+2] = ident[i];
ident[0] = '\r';
ident[1] = '-';
}
return CPP_NAME;
}
/* If macro wants an arglist, verify that a '(' follows. */
if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
{
int macbuf_whitespace = 0;
while (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
{
const U_CHAR *point = CPP_BUFFER (pfile)->cur;
for (;;)
{
cpp_skip_hspace (pfile);
c = PEEKC ();
if (c == '\n')
FORWARD(1);
else
break;
}
if (point != CPP_BUFFER (pfile)->cur)
macbuf_whitespace = 1;
if (c == '(')
goto is_macro_call;
else if (c != EOF)
goto not_macro_call;
cpp_pop_buffer (pfile);
}
parse_set_mark (pfile);
for (;;)
{
cpp_skip_hspace (pfile);
c = PEEKC ();
if (c == '\n')
FORWARD(1);
else
break;
}
parse_goto_mark (pfile);
if (c == '(')
goto is_macro_call;
not_macro_call:
if (macbuf_whitespace)
CPP_PUTC (pfile, ' ');
return CPP_NAME;
}
is_macro_call:
/* This is now known to be a macro call.
Expand the macro, reading arguments as needed,
and push the expansion on the input stack. */
_cpp_macroexpand (pfile, hp);
CPP_SET_WRITTEN (pfile, before_name_written);
}
goto get_next;
case ' ': case '\t': case '\v':
for (;;)
{
CPP_PUTC (pfile, c);
c = PEEKC ();
if (c == EOF || !is_hspace(c))
break;
FORWARD(1);
}
return CPP_HSPACE;
case '\r':
if (CPP_BUFFER (pfile)->has_escapes)
{
c = GETC ();
if (c == '-')
{
if (pfile->output_escapes)
CPP_PUTS (pfile, "\r-", 2);
parse_name (pfile, GETC ());
return CPP_NAME;
}
else if (c == ' ')
{
CPP_RESERVE (pfile, 2);
if (pfile->output_escapes)
CPP_PUTC_Q (pfile, '\r');
CPP_PUTC_Q (pfile, c);
return CPP_HSPACE;
}
else
{
cpp_ice (pfile, "unrecognized escape \\r%c", c);
goto get_next;
}
}
else
{
/* Backslash newline is ignored. */
CPP_BUMP_LINE (pfile);
goto get_next;
}
case '\n':
CPP_PUTC (pfile, c);
if (pfile->only_seen_white == 0)
pfile->only_seen_white = 1;
CPP_BUMP_LINE (pfile);
if (! CPP_OPTIONS (pfile)->no_line_commands)
{
pfile->lineno++;
if (CPP_BUFFER (pfile)->lineno != pfile->lineno)
output_line_command (pfile, same_file);
}
return CPP_VSPACE;
case '(': token = CPP_LPAREN; goto char1;
case ')': token = CPP_RPAREN; goto char1;
case '{': token = CPP_LBRACE; goto char1;
case '}': token = CPP_RBRACE; goto char1;
case ',': token = CPP_COMMA; goto char1;
case ';': token = CPP_SEMICOLON; goto char1;
randomchar:
default:
token = CPP_OTHER;
char1:
pfile->only_seen_white = 0;
CPP_PUTC (pfile, c);
return token;
}
}
}
/* Like cpp_get_token, but skip spaces and comments. */
enum cpp_token
cpp_get_non_space_token (pfile)
cpp_reader *pfile;
{
int old_written = CPP_WRITTEN (pfile);
for (;;)
{
enum cpp_token token = cpp_get_token (pfile);
if (token != CPP_COMMENT && token != CPP_POP
&& token != CPP_HSPACE && token != CPP_VSPACE)
return token;
CPP_SET_WRITTEN (pfile, old_written);
}
}
/* Parse an identifier starting with C. */
static void
parse_name (pfile, c)
cpp_reader *pfile;
int c;
{
for (;;)
{
if (! is_idchar(c))
{
FORWARD (-1);
break;
}
if (c == '$' && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "`$' in identifier");
CPP_RESERVE(pfile, 2); /* One more for final NUL. */
CPP_PUTC_Q (pfile, c);
c = GETC();
if (c == EOF)
break;
}
CPP_NUL_TERMINATE_Q (pfile);
return;
}
/* Parse and skip over a string starting with C. A single quoted
string is treated like a double -- some programs (e.g., troff) are
perverse this way. (However, a single quoted string is not allowed
to extend over multiple lines.) */
static void
skip_string (pfile, c)
cpp_reader *pfile;
int c;
{
long start_line, start_column;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
while (1)
{
int cc = GETC();
switch (cc)
{
case EOF:
cpp_error_with_line (pfile, start_line, start_column,
"unterminated string or character constant");
if (pfile->multiline_string_line != start_line
&& pfile->multiline_string_line != 0)
cpp_error_with_line (pfile,
pfile->multiline_string_line, -1,
"possible real start of unterminated constant");
pfile->multiline_string_line = 0;
return;
case '\n':
CPP_BUMP_LINE (pfile);
/* In Fortran and assembly language, silently terminate
strings of either variety at end of line. This is a
kludge around not knowing where comments are in these
languages. */
if (CPP_OPTIONS (pfile)->lang_fortran
|| CPP_OPTIONS (pfile)->lang_asm)
{
FORWARD(-1);
return;
}
/* Character constants may not extend over multiple lines.
In Standard C, neither may strings. We accept multiline
strings as an extension. */
if (c == '\'')
{
cpp_error_with_line (pfile, start_line, start_column,
"unterminated character constant");
FORWARD(-1);
return;
}
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
cpp_pedwarn_with_line (pfile, start_line, start_column,
"string constant runs past end of line");
if (pfile->multiline_string_line == 0)
pfile->multiline_string_line = start_line;
break;
case '\r':
if (CPP_BUFFER (pfile)->has_escapes)
{
cpp_ice (pfile, "\\r escape inside string constant");
FORWARD(1);
}
else
/* Backslash newline is replaced by nothing at all. */
CPP_BUMP_LINE (pfile);
break;
case '\\':
FORWARD(1);
break;
case '\"':
case '\'':
if (cc == c)
return;
break;
}
}
}
/* Parse a string and copy it to the output. */
static void
parse_string (pfile, c)
cpp_reader *pfile; cpp_reader *pfile;
int c;
{ {
const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */ cpp_buffer *next_buf = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
const U_CHAR *limit; struct if_stack *ifs, *nifs;
skip_string (pfile, c); /* Unwind the conditional stack and generate error messages. */
for (ifs = pfile->if_stack;
limit = CPP_BUFFER (pfile)->cur; ifs != CPP_BUFFER (pfile)->if_stack;
CPP_RESERVE (pfile, limit - start + 2); ifs = nifs)
CPP_PUTC_Q (pfile, c);
for (; start < limit; start++)
if (*start != '\r')
CPP_PUTC_Q (pfile, *start);
}
/* Read an assertion into the token buffer, converting to
canonical form: `#predicate(a n swe r)' The next non-whitespace
character to read should be the first letter of the predicate.
Returns 0 for syntax error, 1 for bare predicate, 2 for predicate
with answer (see callers for why). In case of 0, an error has been
printed. */
static int
parse_assertion (pfile)
cpp_reader *pfile;
{
int c, dropwhite;
cpp_skip_hspace (pfile);
c = PEEKC();
if (! is_idstart(c))
{ {
cpp_error (pfile, "assertion predicate is not an identifier"); cpp_error_with_line (pfile, ifs->lineno, -1,
return 0; "unterminated `%s' conditional",
} if_directive_name (pfile, ifs));
CPP_PUTC(pfile, '#');
FORWARD(1);
parse_name(pfile, c);
c = PEEKC(); nifs = ifs->next;
if (c != '(') free (ifs);
{
if (is_hspace(c) || c == '\r')
cpp_skip_hspace (pfile);
c = PEEKC();
} }
if (c != '(') pfile->if_stack = ifs;
return 1;
CPP_PUTC(pfile, '('); if (CPP_BUFFER (pfile)->nominal_fname && next_buf != NULL)
FORWARD(1);
dropwhite = 1;
while ((c = GETC()) != ')')
{ {
if (is_space(c)) /* We're about to return from an #include file.
{ Emit #line information now (as part of the CPP_POP) result.
if (! dropwhite) But the #line refers to the file we will pop to. */
{ cpp_buffer *cur_buffer = CPP_BUFFER (pfile);
CPP_PUTC(pfile, ' '); CPP_BUFFER (pfile) = next_buf;
dropwhite = 1; pfile->input_stack_listing_current = 0;
} _cpp_output_line_command (pfile, leave_file);
} CPP_BUFFER (pfile) = cur_buffer;
else if (c == '\n' || c == EOF)
{
if (c == '\n') FORWARD(-1);
cpp_error (pfile, "un-terminated assertion answer");
return 0;
}
else if (c == '\r')
/* \r cannot be a macro escape here. */
CPP_BUMP_LINE (pfile);
else
{
CPP_PUTC (pfile, c);
dropwhite = 0;
}
} }
if (pfile->limit[-1] == ' ') CPP_BUFFER (pfile)->seen_eof = 1;
pfile->limit[-1] = ')';
else if (pfile->limit[-1] == '(')
{
cpp_error (pfile, "empty token sequence in assertion");
return 0;
}
else
CPP_PUTC (pfile, ')');
CPP_NUL_TERMINATE (pfile);
return 2;
} }
static int static int
...@@ -3045,9 +1704,9 @@ do_assert (pfile, keyword) ...@@ -3045,9 +1704,9 @@ do_assert (pfile, keyword)
if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing) if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing)
cpp_pedwarn (pfile, "ANSI C does not allow `#assert'"); cpp_pedwarn (pfile, "ANSI C does not allow `#assert'");
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
sym = CPP_PWRITTEN (pfile); /* remember where it starts */ sym = CPP_PWRITTEN (pfile); /* remember where it starts */
ret = parse_assertion (pfile); ret = _cpp_parse_assertion (pfile);
if (ret == 0) if (ret == 0)
goto error; goto error;
else if (ret == 1) else if (ret == 1)
...@@ -3056,7 +1715,7 @@ do_assert (pfile, keyword) ...@@ -3056,7 +1715,7 @@ do_assert (pfile, keyword)
goto error; goto error;
} }
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = PEEKC(); c = PEEKC();
if (c != EOF && c != '\n') if (c != EOF && c != '\n')
{ {
...@@ -3094,7 +1753,7 @@ do_assert (pfile, keyword) ...@@ -3094,7 +1753,7 @@ do_assert (pfile, keyword)
return 0; return 0;
error: error:
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
pfile->limit = sym; /* Pop */ pfile->limit = sym; /* Pop */
return 0; return 0;
} }
...@@ -3112,14 +1771,14 @@ do_unassert (pfile, keyword) ...@@ -3112,14 +1771,14 @@ do_unassert (pfile, keyword)
if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing) if (CPP_PEDANTIC (pfile) && CPP_OPTIONS (pfile)->done_initializing)
cpp_pedwarn (pfile, "ANSI C does not allow `#unassert'"); cpp_pedwarn (pfile, "ANSI C does not allow `#unassert'");
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
sym = CPP_PWRITTEN (pfile); /* remember where it starts */ sym = CPP_PWRITTEN (pfile); /* remember where it starts */
ret = parse_assertion (pfile); ret = _cpp_parse_assertion (pfile);
if (ret == 0) if (ret == 0)
goto error; goto error;
cpp_skip_hspace (pfile); _cpp_skip_hspace (pfile);
c = PEEKC (); c = PEEKC ();
if (c != EOF && c != '\n') if (c != EOF && c != '\n')
cpp_error (pfile, "junk at end of `#unassert'"); cpp_error (pfile, "junk at end of `#unassert'");
...@@ -3163,54 +1822,112 @@ do_unassert (pfile, keyword) ...@@ -3163,54 +1822,112 @@ do_unassert (pfile, keyword)
pfile->limit = sym; /* Pop */ pfile->limit = sym; /* Pop */
return 0; return 0;
error: error:
skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
pfile->limit = sym; /* Pop */ pfile->limit = sym; /* Pop */
return 0; return 0;
} }
/* Process STR as if it appeared as the body of an #unassert. */ /* These are for -D, -U, -A. */
/* Process the string STR as if it appeared as the body of a #define.
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 void
cpp_unassert (pfile, str) cpp_define (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; const char *str;
{ {
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL) char *buf, *p;
size_t count;
p = strchr (str, '=');
/* Copy the entire option so we can modify it.
Change the first "=" in the string to a space. If there is none,
tack " 1" on the end. Then add a newline and a NUL. */
if (p)
{ {
do_unassert (pfile, NULL); count = strlen (str) + 2;
cpp_pop_buffer (pfile); buf = alloca (count);
memcpy (buf, str, count - 2);
buf[p - str] = ' ';
buf[count - 2] = '\n';
buf[count - 1] = '\0';
}
else
{
count = strlen (str) + 4;
buf = alloca (count);
memcpy (buf, str, count - 4);
strcpy (&buf[count-4], " 1\n");
} }
}
/* Remember the current position of PFILE so it may be returned to
after looking ahead a bit.
Note that when you set a mark, you _must_ return to that mark. You if (cpp_push_buffer (pfile, buf, count - 1) != NULL)
may not forget about it and continue parsing. You may not pop a {
buffer with an active mark. You may not call CPP_BUMP_LINE while a do_define (pfile, NULL);
mark is active. */ cpp_pop_buffer (pfile);
}
}
static void /* Process MACRO as if it appeared as the body of an #undef. */
parse_set_mark (pfile) void
cpp_undef (pfile, macro)
cpp_reader *pfile; cpp_reader *pfile;
const char *macro;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); /* Copy the string so we can append a newline. */
if (ACTIVE_MARK_P()) size_t len = strlen (macro);
cpp_ice (pfile, "mark active in parse_set_mark"); char *buf = alloca (len + 2);
memcpy (buf, macro, len);
ip->mark = ip->cur - ip->buf; buf[len] = '\n';
buf[len + 1] = '\0';
if (cpp_push_buffer (pfile, buf, len + 1))
{
do_undef (pfile, NULL);
cpp_pop_buffer (pfile);
}
} }
/* Backup the current position of PFILE to that saved in its mark, /* Process the string STR as if it appeared as the body of a #assert. */
and clear the mark. */ void
cpp_assert (pfile, str)
cpp_reader *pfile;
const char *str;
{
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
{
do_assert (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
static void /* Process STR as if it appeared as the body of an #unassert. */
parse_goto_mark (pfile) void
cpp_unassert (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
if (!ACTIVE_MARK_P()) {
cpp_ice (pfile, "mark not active in parse_goto_mark"); do_unassert (pfile, NULL);
cpp_pop_buffer (pfile);
}
}
ip->cur = ip->buf + ip->mark; /* Determine whether the identifier ID, of length LEN, is a defined macro. */
ip->mark = -1; int
cpp_defined (pfile, id, len)
cpp_reader *pfile;
const U_CHAR *id;
int len;
{
HASHNODE *hp = _cpp_lookup (pfile, id, len);
if (hp && hp->type == T_POISON)
{
cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
return 0;
}
return (hp != NULL);
} }
...@@ -40,6 +40,7 @@ enum cpp_token ...@@ -40,6 +40,7 @@ enum cpp_token
CPP_HSPACE, CPP_HSPACE,
CPP_VSPACE, /* newlines and #line directives */ CPP_VSPACE, /* newlines and #line directives */
CPP_NAME, CPP_NAME,
CPP_MACRO,
CPP_NUMBER, CPP_NUMBER,
CPP_CHAR, CPP_CHAR,
CPP_WCHAR, CPP_WCHAR,
...@@ -233,11 +234,6 @@ struct cpp_reader ...@@ -233,11 +234,6 @@ struct cpp_reader
#define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA)) #define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA))
#define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N)) #define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N))
/* Make sure PFILE->token_buffer has space for at least N more characters. */
#define CPP_RESERVE(PFILE, N) \
(CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \
&& (cpp_grow_buffer (PFILE, N), 0))
#define CPP_OPTIONS(PFILE) ((PFILE)->opts) #define CPP_OPTIONS(PFILE) ((PFILE)->opts)
#define CPP_BUFFER(PFILE) ((PFILE)->buffer) #define CPP_BUFFER(PFILE) ((PFILE)->buffer)
...@@ -438,7 +434,6 @@ extern const char *progname; ...@@ -438,7 +434,6 @@ extern const char *progname;
extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **)); extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
extern enum cpp_token cpp_get_token PARAMS ((cpp_reader *)); extern enum cpp_token cpp_get_token PARAMS ((cpp_reader *));
extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *)); extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *));
extern enum cpp_token get_directive_token PARAMS ((cpp_reader *));
extern void cpp_reader_init PARAMS ((cpp_reader *)); extern void cpp_reader_init PARAMS ((cpp_reader *));
extern void cpp_options_init PARAMS ((cpp_options *)); extern void cpp_options_init PARAMS ((cpp_options *));
...@@ -482,22 +477,15 @@ extern void cpp_pedwarn_with_file_and_line PARAMS ((cpp_reader *, const char *, ...@@ -482,22 +477,15 @@ extern void cpp_pedwarn_with_file_and_line PARAMS ((cpp_reader *, const char *,
extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *)); extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *));
extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *)); extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *));
extern void cpp_grow_buffer PARAMS ((cpp_reader *, long));
extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *, extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
const unsigned char *, long)); const unsigned char *, long));
extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *)); extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *));
extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int)); extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int));
extern void quote_string PARAMS ((cpp_reader *, const char *));
extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, extern void cpp_expand_to_buffer PARAMS ((cpp_reader *,
const unsigned char *, int)); const unsigned char *, int));
extern void cpp_scan_buffer PARAMS ((cpp_reader *)); extern void cpp_scan_buffer PARAMS ((cpp_reader *));
/* Last arg to output_line_command. */
enum file_change_code {same_file, rename_file, enter_file, leave_file};
extern void output_line_command PARAMS ((cpp_reader *,
enum file_change_code));
/* In cppfiles.c */ /* In cppfiles.c */
extern int cpp_included PARAMS ((cpp_reader *, const char *)); extern int cpp_included PARAMS ((cpp_reader *, const char *));
extern int cpp_read_file PARAMS ((cpp_reader *, const char *)); extern int cpp_read_file PARAMS ((cpp_reader *, const char *));
......
...@@ -594,6 +594,7 @@ cppfiles.c ...@@ -594,6 +594,7 @@ cppfiles.c
cpphash.c cpphash.c
cpphash.h cpphash.h
cppinit.c cppinit.c
cpplex.c
cpplib.c cpplib.c
cpplib.h cpplib.h
cppmain.c cppmain.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment