#include "cpphash.h"
#include "intl.h"
-#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
-#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
+#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 FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
/* Forward declarations. */
-static char *my_strerror PROTO ((int));
-static void validate_else PROTO ((cpp_reader *, char *));
+static const char *my_strerror PROTO ((int));
+static void validate_else PROTO ((cpp_reader *, const char *));
static HOST_WIDEST_INT eval_if_expression PROTO ((cpp_reader *));
static void conditional_skip PROTO ((cpp_reader *, int,
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 *));
/* External declarations. */
struct directive {
int length; /* Length of name */
int (*func) /* Function to handle directive */
- PARAMS ((cpp_reader *, struct directive *));
- char *name; /* Name of directive */
+ PARAMS ((cpp_reader *, const struct directive *));
+ const char *name; /* Name of directive */
enum node_type type; /* Code which describes which directive. */
};
are going to be placed in a table and some old compilers have trouble with
pointers to functions returning void. */
-static int do_define PARAMS ((cpp_reader *, struct directive *));
-static int do_line PARAMS ((cpp_reader *, struct directive *));
-static int do_include PARAMS ((cpp_reader *, struct directive *));
-static int do_undef PARAMS ((cpp_reader *, struct directive *));
-static int do_error PARAMS ((cpp_reader *, struct directive *));
-static int do_pragma PARAMS ((cpp_reader *, struct directive *));
-static int do_ident PARAMS ((cpp_reader *, struct directive *));
-static int do_if PARAMS ((cpp_reader *, struct directive *));
-static int do_xifdef PARAMS ((cpp_reader *, struct directive *));
-static int do_else PARAMS ((cpp_reader *, struct directive *));
-static int do_elif PARAMS ((cpp_reader *, struct directive *));
-static int do_endif PARAMS ((cpp_reader *, struct directive *));
+static int do_define PARAMS ((cpp_reader *, const struct directive *));
+static int do_line PARAMS ((cpp_reader *, const struct directive *));
+static int do_include PARAMS ((cpp_reader *, const struct directive *));
+static int do_undef PARAMS ((cpp_reader *, const struct directive *));
+static int do_error PARAMS ((cpp_reader *, const struct directive *));
+static int do_pragma PARAMS ((cpp_reader *, const struct directive *));
+static int do_ident PARAMS ((cpp_reader *, const struct directive *));
+static int do_if PARAMS ((cpp_reader *, const struct directive *));
+static int do_xifdef PARAMS ((cpp_reader *, const struct directive *));
+static int do_else PARAMS ((cpp_reader *, const struct directive *));
+static int do_elif PARAMS ((cpp_reader *, const struct directive *));
+static int do_endif PARAMS ((cpp_reader *, const struct directive *));
#ifdef SCCS_DIRECTIVE
-static int do_sccs PARAMS ((cpp_reader *, struct directive *));
+static int do_sccs PARAMS ((cpp_reader *, const struct directive *));
#endif
-static int do_assert PARAMS ((cpp_reader *, struct directive *));
-static int do_unassert PARAMS ((cpp_reader *, struct directive *));
-static int do_warning PARAMS ((cpp_reader *, struct directive *));
-
-#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
-((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
-
-/* Here is the actual list of #-directives, most-often-used first.
- The initialize_builtins function assumes #define is the very first. */
-
-static struct directive directive_table[] = {
- { 6, do_define, "define", T_DEFINE },
- { 5, do_xifdef, "ifdef", T_IFDEF },
- { 6, do_xifdef, "ifndef", T_IFNDEF },
- { 7, do_include, "include", T_INCLUDE },
- { 12, do_include, "include_next", T_INCLUDE_NEXT },
- { 6, do_include, "import", T_IMPORT },
- { 5, do_endif, "endif", T_ENDIF },
- { 4, do_else, "else", T_ELSE },
- { 2, do_if, "if", T_IF },
- { 4, do_elif, "elif", T_ELIF },
- { 5, do_undef, "undef", T_UNDEF },
- { 5, do_error, "error", T_ERROR },
- { 7, do_warning, "warning", T_WARNING },
- { 6, do_pragma, "pragma", T_PRAGMA },
- { 4, do_line, "line", T_LINE },
- { 5, do_ident, "ident", T_IDENT },
+static int do_assert PARAMS ((cpp_reader *, const struct directive *));
+static int do_unassert PARAMS ((cpp_reader *, const struct directive *));
+static int do_warning PARAMS ((cpp_reader *, const struct directive *));
+static enum cpp_token null_underflow PARAMS ((cpp_reader *));
+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 copy_rest_of_line PARAMS ((cpp_reader *));
+static int handle_directive PARAMS ((cpp_reader *));
+static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, cpp_reader *,
+ const struct directive *));
+static enum cpp_token get_directive_token PARAMS ((cpp_reader *));
+static int read_line_number PARAMS ((cpp_reader *, int *));
+static void cpp_print_file_and_line PARAMS ((cpp_reader *));
+static void v_cpp_error PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_warning PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_error_with_line PARAMS ((cpp_reader *, int, int,
+ const char *, va_list));
+static void v_cpp_warning_with_line PARAMS ((cpp_reader *, int, int, const char *, va_list));
+static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
+static int consider_directive_while_skipping PARAMS ((cpp_reader *, IF_STACK_FRAME *));
+
+/* Here is the actual list of #-directives.
+ This table is ordered by frequency of occurrence; the numbers
+ at the end are directive counts from all the source code I have
+ lying around (egcs and libc CVS as of 1999-05-18, plus grub-0.5.91,
+ linux-2.2.9, and pcmcia-cs-3.0.9). */
+
+static const struct directive directive_table[] = {
+ /* In C89 */
+ { 6, do_define, "define", T_DEFINE }, /* 270554 */
+ { 7, do_include, "include", T_INCLUDE }, /* 52262 */
+ { 5, do_endif, "endif", T_ENDIF }, /* 45855 */
+ { 5, do_xifdef, "ifdef", T_IFDEF }, /* 22000 */
+ { 2, do_if, "if", T_IF }, /* 18162 */
+ { 4, do_else, "else", T_ELSE }, /* 9863 */
+ { 6, do_xifdef, "ifndef", T_IFNDEF }, /* 9675 */
+ { 5, do_undef, "undef", T_UNDEF }, /* 4837 */
+ { 4, do_line, "line", T_LINE }, /* 2465 */
+ { 4, do_elif, "elif", T_ELIF }, /* 610 */
+ { 5, do_error, "error", T_ERROR }, /* 475 */
+ { 6, do_pragma, "pragma", T_PRAGMA }, /* 195 */
+
+ /* Extensions. All deprecated except #warning and #include_next. */
+ { 7, do_warning, "warning", T_WARNING }, /* 22 - GNU */
+ { 12, do_include, "include_next", T_INCLUDE_NEXT }, /* 19 - GNU */
+ { 5, do_ident, "ident", T_IDENT }, /* 11 - SVR4 */
+ { 6, do_include, "import", T_IMPORT }, /* 0 - ObjC */
+ { 6, do_assert, "assert", T_ASSERT }, /* 0 - SVR4 */
+ { 8, do_unassert, "unassert", T_UNASSERT }, /* 0 - SVR4 */
#ifdef SCCS_DIRECTIVE
- { 4, do_sccs, "sccs", T_SCCS },
+ { 4, do_sccs, "sccs", T_SCCS }, /* 0 - SVR2? */
#endif
- { 6, do_assert, "assert", T_ASSERT },
- { 8, do_unassert, "unassert", T_UNASSERT },
{ -1, 0, "", T_UNUSED }
};
return EOF;
}
else if (c == '\n' || c == '\r')
+ /* \r cannot be a macro escape marker here. */
CPP_BUMP_LINE (pfile);
else if (c == '/' && prev_c == '*')
return ' ';
return ' ';
}
else if (c == '\r')
+ /* \r cannot be a macro escape marker here. */
CPP_BUMP_LINE (pfile);
}
}
}
else if (c == '\r')
{
+ /* \r cannot be a macro escape marker here. */
CPP_BUMP_LINE (pfile);
continue;
}
return ' ';
}
else if (c == '\r')
+ /* \r cannot be a macro escape marker here. */
CPP_BUMP_LINE (pfile);
CPP_PUTC (pfile, c);
c = GETC();
if (c == EOF)
return;
- else if (is_hor_space[c])
+ else if (is_hspace(c))
{
if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
}
else if (c == '\r')
{
- CPP_BUFFER (pfile)->lineno++;
+ /* \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_BUFFER (pfile)->lineno++;
}
else if (c == '/' || c == '-')
{
if (c == EOF)
return;
else if (c != ' ')
- {
- FORWARD(-1);
- return;
- }
- }
- else if (c == '@' && CPP_BUFFER (pfile)->has_escapes
- && PEEKC() == ' ')
- {
- FORWARD(1);
+ break;
}
else
- {
- FORWARD(-1);
- return;
- }
+ break;
}
+ FORWARD(-1);
}
/* Read the rest of the current line.
return;
case '\r':
- CPP_BUFFER (pfile)->lineno++;
- continue;
+ if (CPP_BUFFER (pfile)->has_escapes)
+ break;
+ else
+ {
+ CPP_BUFFER (pfile)->lineno++;
+ continue;
+ }
case '\'':
case '\"':
parse_string (pfile, c);
cpp_reader *pfile;
{
int c;
- register struct directive *kt;
+ register const struct directive *kt;
int ident_length;
U_CHAR *ident;
long old_written = CPP_WRITTEN (pfile);
cpp_skip_hspace (pfile);
c = PEEKC ();
+ /* # followed by a number is equivalent to #line. Do not recognize
+ this form in assembly language source files. Complain about this
+ form if we're being pedantic, but not if this is regurgitated
+ input (preprocessed or fed back in by the C++ frontend). */
if (c >= '0' && c <= '9')
{
- /* Handle # followed by a line number. */
- if (CPP_PEDANTIC (pfile))
+ if (CPP_OPTIONS (pfile)->lang_asm)
+ {
+ skip_rest_of_line (pfile);
+ return 1;
+ }
+
+ if (CPP_PEDANTIC (pfile)
+ && ! CPP_PREPROCESSED (pfile)
+ && ! CPP_BUFFER (pfile)->manual_pop)
cpp_pedwarn (pfile, "`#' followed by integer");
do_line (pfile, NULL);
- goto done_a_directive;
+ return 1;
}
+ /* If we are rescanning preprocessed input, don't obey any directives
+ other than # nnn. */
+ if (CPP_PREPROCESSED (pfile))
+ return 0;
+
/* Now find the directive name. */
CPP_PUTC (pfile, '#');
parse_name (pfile, GETC());
ident = pfile->token_buffer + old_written + 1;
ident_length = CPP_PWRITTEN (pfile) - ident;
- if (ident_length == 0 && PEEKC() == '\n')
+ if (ident_length == 0)
{
/* A line of just `#' becomes blank. */
- goto done_a_directive;
- }
-
-#if 0
- if (ident_length == 0 || !is_idstart[*ident]) {
- U_CHAR *p = ident;
- while (is_idchar[*p]) {
- if (*p < '0' || *p > '9')
- break;
- p++;
- }
- /* Avoid error for `###' and similar cases unless -pedantic. */
- if (p == ident) {
- while (*p == '#' || is_hor_space[*p]) p++;
- if (*p == '\n') {
- if (pedantic && !lang_asm)
- cpp_warning (pfile, "invalid preprocessor directive");
+ if (PEEKC() == '\n')
+ return 1;
+ else
return 0;
- }
}
- if (!lang_asm)
- cpp_error (pfile, "invalid preprocessor directive name");
-
- return 0;
- }
-#endif
/*
* Decode the keyword and call the appropriate expansion
* routine, after moving the input pointer up to the next line.
*/
- for (kt = directive_table; ; kt++) {
- if (kt->length <= 0)
- goto not_a_directive;
- if (kt->length == ident_length
- && !strncmp (kt->name, ident, ident_length))
- break;
- }
-
- /* We may want to pass through #define, #undef, #pragma, and #include.
- Other directives may create output, but we don't want the directive
- itself out, so we pop it now. For example conditionals may emit
- #failed ... #endfailed stuff. */
-
- if (! (kt->type == T_DEFINE
- || kt->type == T_PRAGMA
- || (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)
- && CPP_OPTIONS (pfile)->dump_includes)))
- CPP_SET_WRITTEN (pfile, old_written);
-
- (*kt->func) (pfile, kt);
-
- if (kt->type == T_DEFINE)
+ for (kt = directive_table; ; kt++)
{
- if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
- {
- /* Skip "#define". */
- U_CHAR *p = pfile->token_buffer + old_written + 7;
-
- SKIP_WHITE_SPACE (p);
- while (is_idchar[*p]) p++;
- pfile->limit = p;
- CPP_PUTC (pfile, '\n');
- }
- else if (CPP_OPTIONS (pfile)->dump_macros != dump_definitions)
- CPP_SET_WRITTEN (pfile, old_written);
+ if (kt->length <= 0)
+ return 0;
+ if (kt->length == ident_length
+ && !strncmp (kt->name, ident, ident_length))
+ break;
}
- done_a_directive:
- return 1;
+ CPP_SET_WRITTEN (pfile, old_written);
+ (*kt->func) (pfile, kt);
- not_a_directive:
- return 0;
+ return 1;
}
/* Pass a directive through to the output file.
BUF points to the contents of the directive, as a contiguous string.
-m LIMIT points to the first character past the end of the directive.
+ LEN is the length of the string pointed to by BUF.
KEYWORD is the keyword-table entry for the directive. */
static void
-pass_thru_directive (buf, limit, pfile, keyword)
- U_CHAR *buf, *limit;
+pass_thru_directive (buf, len, pfile, keyword)
+ const U_CHAR *buf;
+ size_t len;
cpp_reader *pfile;
- struct directive *keyword;
+ const struct directive *keyword;
{
register unsigned keyword_length = keyword->length;
- CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf));
+ CPP_RESERVE (pfile, 1 + keyword_length + len);
CPP_PUTC_Q (pfile, '#');
CPP_PUTS_Q (pfile, keyword->name, keyword_length);
- if (limit != buf && buf[0] != ' ')
+ if (len != 0 && buf[0] != ' ')
CPP_PUTC_Q (pfile, ' ');
- CPP_PUTS_Q (pfile, buf, limit - buf);
-#if 0
- CPP_PUTS_Q (pfile, '\n');
- /* Count the line we have just made in the output,
- to get in sync properly. */
- pfile->lineno++;
-#endif
+ CPP_PUTS_Q (pfile, buf, len);
}
-/* Check a purported macro name SYMNAME, and yield its length.
- ASSERTION is nonzero if this is really for an assertion name. */
+/* Check a purported macro name SYMNAME, and yield its length. */
int
-check_macro_name (pfile, symname, assertion)
+check_macro_name (pfile, symname)
cpp_reader *pfile;
- U_CHAR *symname;
- int assertion;
+ const U_CHAR *symname;
{
- U_CHAR *p;
+ const U_CHAR *p;
int sym_length;
- for (p = symname; is_idchar[*p]; p++)
+ for (p = symname; is_idchar(*p); p++)
;
sym_length = p - symname;
if (sym_length == 0
|| (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
- cpp_error (pfile,
- assertion ? "invalid assertion name" : "invalid macro name");
- else if (!is_idstart[*symname]
+ cpp_error (pfile, "invalid macro name");
+ else if (!is_idstart(*symname)
|| (! strncmp (symname, "defined", 7) && sym_length == 7)) {
U_CHAR *msg; /* what pain... */
msg = (U_CHAR *) alloca (sym_length + 1);
bcopy (symname, msg, sym_length);
msg[sym_length] = 0;
- cpp_error (pfile,
- (assertion
- ? "invalid assertion name `%s'"
- : "invalid macro name `%s'"),
- msg);
+ cpp_error (pfile, "invalid macro name `%s'", msg);
}
return sym_length;
}
-
/* Process a #define command.
-KEYWORD is the keyword-table entry for #define,
-or NULL for a "predefined" macro. */
+ KEYWORD is the keyword-table entry for #define,
+ or NULL for a "predefined" macro,
+ or the keyword-table entry for #pragma in the case of a #pragma poison. */
static int
do_define (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword;
+ const struct directive *keyword;
{
int hashcode;
MACRODEF mdef;
HASHNODE *hp;
long here;
U_CHAR *macro, *buf, *end;
+ enum node_type new_type;
here = CPP_WRITTEN (pfile);
copy_rest_of_line (pfile);
+ if (keyword == NULL || keyword->type == T_DEFINE)
+ new_type = T_MACRO;
+ else
+ new_type = T_POISON;
+
/* Copy out the line so we can pop the token buffer. */
buf = pfile->token_buffer + here;
end = CPP_PWRITTEN (pfile);
- macro = alloca (end - buf + 1);
+ macro = (U_CHAR *) alloca (end - buf + 1);
bcopy (buf, macro, end - buf + 1);
end = macro + (end - buf);
CPP_SET_WRITTEN (pfile, here);
-#if 0
- /* If this is a precompiler run (with -pcp) pass thru #define commands. */
- if (pcp_outfile && keyword)
- pass_thru_directive (macro, end, pfile, keyword);
-#endif
-
mdef = create_definition (macro, end, pfile, keyword == NULL);
if (mdef.defn == 0)
- goto nope;
+ return 0;
hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE);
/* Redefining a precompiled key is ok. */
if (hp->type == T_PCSTRING)
ok = 1;
+ /* Redefining a poisoned identifier is even worse than `not ok'. */
+ else if (hp->type == T_POISON)
+ ok = -1;
/* Redefining a macro is ok if the definitions are the same. */
else if (hp->type == T_MACRO)
ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST || hp->type == T_STDC)
ok = ! CPP_OPTIONS (pfile)->done_initializing;
- /* Print the warning if it's not ok. */
- if (!ok)
+ /* Print the warning or error if it's not ok. */
+ if (ok <= 0)
{
- /* If we are passing through #define and #undef directives, do
- that for this re-definition now. */
- if (CPP_OPTIONS (pfile)->debug_output && keyword)
- pass_thru_directive (macro, end, pfile, keyword);
-
- cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
+ if (hp->type == T_POISON)
+ cpp_error (pfile, "redefining poisoned `%.*s'",
+ mdef.symlen, mdef.symnam);
+ else
+ cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
if (hp->type == T_MACRO)
- cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line,
- "this is the location of the previous definition");
+ cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
+ hp->value.defn->line,
+ "this is the location of the previous definition");
+ }
+ if (hp->type != T_POISON)
+ {
+ /* Replace the old definition. */
+ hp->type = new_type;
+ hp->value.defn = mdef.defn;
}
- /* Replace the old definition. */
- hp->type = T_MACRO;
- hp->value.defn = mdef.defn;
}
else
+ cpp_install (pfile, mdef.symnam, mdef.symlen, new_type,
+ (char *) mdef.defn, hashcode);
+
+ if (keyword != NULL && keyword->type == T_DEFINE)
{
- /* If we are passing through #define and #undef directives, do
- that for this new definition now. */
- if (CPP_OPTIONS (pfile)->debug_output && keyword)
- pass_thru_directive (macro, end, pfile, keyword);
- cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO,
- (char *) mdef.defn, hashcode);
+ if (CPP_OPTIONS (pfile)->debug_output
+ || CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
+ dump_definition (pfile, mdef);
+ else if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
+ pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword);
}
return 0;
-
-nope:
-
- return 1;
}
return NULL;
}
- new = (cpp_buffer *) xcalloc (sizeof (cpp_buffer), 1);
+ new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
new->if_stack = pfile->if_stack;
new->cleanup = null_cleanup;
cpp_reader *pfile;
{
cpp_buffer *buffer = CPP_BUFFER (pfile);
- for (;;)
+ enum cpp_token token;
+ if (CPP_OPTIONS (pfile)->no_output)
{
- enum cpp_token token = cpp_get_token (pfile);
- if (token == CPP_EOF) /* Should not happen ... */
- break;
- if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
+ long old_written = CPP_WRITTEN (pfile);
+ /* In no-output mode, we can ignore everything but directives. */
+ for (;;)
{
- cpp_pop_buffer (pfile);
- break;
+ if (! pfile->only_seen_white)
+ 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))
+ != CPP_NULL_BUFFER (pfile))
+ 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))
+ != CPP_NULL_BUFFER (pfile))
+ cpp_pop_buffer (pfile);
+ break;
+ }
}
}
}
void
cpp_expand_to_buffer (pfile, buf, length)
cpp_reader *pfile;
- U_CHAR *buf;
+ const U_CHAR *buf;
int length;
{
register cpp_buffer *ip;
-#if 0
- cpp_buffer obuf;
-#endif
U_CHAR *buf1;
-#if 0
- int odepth = indepth;
-#endif
+ int save_no_output;
if (length < 0)
- abort ();
+ {
+ cpp_fatal (pfile, "internal error: length < 0 in cpp_expand_to_buffer");
+ return;
+ }
/* Set up the input on the input stack. */
if (ip == NULL)
return;
ip->has_escapes = 1;
-#if 0
- ip->lineno = obuf.lineno = 1;
-#endif
/* Scan the input, create the output. */
+ save_no_output = CPP_OPTIONS (pfile)->no_output;
+ CPP_OPTIONS (pfile)->no_output = 0;
cpp_scan_buffer (pfile);
+ CPP_OPTIONS (pfile)->no_output = save_no_output;
CPP_NUL_TERMINATE (pfile);
}
/*
* write out a #line command, for instance, after an #include file.
- * If CONDITIONAL is nonzero, we can omit the #line if it would
- * appear to be a no-op, and we can output a few newlines instead
- * if we want to increase the line number by a small amount.
* FILE_CHANGE says whether we are entering a file, leaving, or neither.
*/
void
-output_line_command (pfile, conditional, file_change)
+output_line_command (pfile, file_change)
cpp_reader *pfile;
- int conditional;
enum file_change_code file_change;
{
- long line, col;
+ long line;
cpp_buffer *ip = CPP_BUFFER (pfile);
if (ip->fname == NULL)
|| CPP_OPTIONS (pfile)->no_output)
return;
- cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
+ cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, NULL);
- if (conditional)
+ /* 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;
static int
do_include (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword;
+ const struct directive *keyword;
{
int importing = (keyword->type == T_IMPORT);
int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
int angle_brackets = 0; /* 0 for "...", 1 for <...> */
int before; /* included before? */
long flen;
- unsigned char *fbeg, *fend;
+ unsigned char *ftok;
cpp_buffer *fp;
enum cpp_token token;
&& !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning)
{
pfile->import_warning = 1;
- cpp_warning (pfile, "`#import' is obsolete, use an #ifndef wrapper in the header file");
+ cpp_warning (pfile,
+ "#import is obsolete, use an #ifndef wrapper in the header file");
}
pfile->parsing_include_directive++;
if (token == CPP_STRING)
{
- fbeg = pfile->token_buffer + old_written + 1;
- fend = CPP_PWRITTEN (pfile) - 1;
- *fend = '\0';
- if (fbeg[-1] == '<')
- angle_brackets = 1;
+ if (pfile->token_buffer[old_written] == '<')
+ angle_brackets = 1;
}
#ifdef VMS
else if (token == CPP_NAME)
{
- /* Support '#include xyz' like VAX-C to allow for easy use of
- * all the decwindow include files. It defaults to '#include
- * <xyz.h>' and generates a warning. */
+ /* Support '#include xyz' like VAX-C. It is taken as
+ '#include <xyz.h>' and generates a warning. */
cpp_warning (pfile,
- "VAX-C-style include specification found, use '#include <filename.h>' !");
+ "`#include filename' is obsolete, use `#include <filename.h>'");
angle_brackets = 1;
/* Append the missing `.h' to the name. */
- CPP_PUTS (pfile, ".h", 3)
- CPP_NUL_TERMINATE_Q (pfile);
-
- fbeg = pfile->token_buffer + old_written;
- fend = CPP_PWRITTEN (pfile);
+ CPP_PUTS (pfile, ".h", 2);
}
#endif
else
return 0;
}
- token = get_directive_token (pfile);
- if (token != CPP_VSPACE)
+ flen = CPP_WRITTEN (pfile) - old_written;
+ ftok = (unsigned char *) alloca (flen + 1);
+ memcpy (ftok, pfile->token_buffer + old_written, flen);
+ ftok[flen] = '\0';
+
+ if (get_directive_token (pfile) != CPP_VSPACE)
{
cpp_error (pfile, "junk at end of `#include'");
skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written);
- flen = fend - fbeg;
-
if (flen == 0)
{
cpp_error (pfile, "empty file name in `#%s'", keyword->name);
return 0;
}
+ if (CPP_OPTIONS (pfile)->dump_includes)
+ pass_thru_directive (ftok,
+ flen
+#ifdef VMS
+ - ((token == CPP_NAME) ? 2 : 0)
+#endif
+ , pfile, keyword);
+
+#ifdef VMS
+ if (token == CPP_STRING)
+#endif
+ {
+ ftok++;
+ flen -= 2;
+ ftok[flen] = '\0';
+ }
+
search_start = 0;
for (fp = CPP_BUFFER (pfile);
if (fp == CPP_NULL_BUFFER (pfile))
{
cpp_fatal (pfile, "cpp internal error: fp == NULL_BUFFER in do_include");
- return 1;
+ return 0;
}
/* For #include_next, skip in the search path past the dir in which the
if (!search_start)
{
- cpp_error (pfile, "No include path in which to find %s", fbeg);
+ cpp_error (pfile, "No include path in which to find %s", ftok);
return 0;
}
- fd = find_include_file (pfile, fbeg, search_start, &ihash, &before);
+ fd = find_include_file (pfile, ftok, search_start, &ihash, &before);
if (fd == -2)
return 0;
(pfile->system_include_depth > 0)))
{
if (!angle_brackets)
- deps_output (pfile, fbeg, ' ');
+ deps_output (pfile, ftok, ' ');
else
{
char *p;
ptr = CPP_OPTIONS (pfile)->quote_include;
p = (char *) alloca (strlen (ptr->name)
- + strlen (fbeg) + 2);
+ + strlen (ftok) + 2);
if (*ptr->name != '\0')
{
strcpy (p, ptr->name);
strcat (p, "/");
}
- strcat (p, fbeg);
+ strcat (p, ftok);
deps_output (pfile, p, ' ');
}
}
else if (CPP_PRINT_DEPS (pfile)
&& (CPP_PRINT_DEPS (pfile)
<= (angle_brackets || (pfile->system_include_depth > 0))))
- cpp_warning (pfile, "No include path in which to find %s", fbeg);
+ cpp_warning (pfile, "No include path in which to find %s", ftok);
else
- cpp_error_from_errno (pfile, fbeg);
+ cpp_error_from_errno (pfile, ftok);
return 0;
}
if (finclude (pfile, fd, ihash))
{
- output_line_command (pfile, 0, enter_file);
+ output_line_command (pfile, enter_file);
pfile->only_seen_white = 2;
}
return 0;
}
+/* Subroutine of do_line. Read next token from PFILE without adding it to
+ the output buffer. If it is a number between 1 and 4, store it in *NUM
+ and return 1; otherwise, return 0 and complain if we aren't at the end
+ of the directive. */
+
+static int
+read_line_number (pfile, num)
+ cpp_reader *pfile;
+ int *num;
+{
+ long save_written = CPP_WRITTEN (pfile);
+ U_CHAR *p = pfile->token_buffer + save_written;
+ enum cpp_token token = get_directive_token (pfile);
+ CPP_SET_WRITTEN (pfile, save_written);
+
+ if (token == CPP_NUMBER && *p >= '1' && *p <= '4' && p[1] == '\0')
+ {
+ *num = p[0] - '0';
+ return 1;
+ }
+ else
+ {
+ if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+ cpp_error (pfile, "invalid format `#line' command");
+ return 0;
+ }
+}
+
/* Interpret #line command.
Note that the filename string (if any) is treated as if it were an
include filename. That means no escape handling. */
static int
do_line (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
int new_lineno;
{
U_CHAR *fname = pfile->token_buffer + old_written + 1;
U_CHAR *end_name = CPP_PWRITTEN (pfile) - 1;
- long num_start = CPP_WRITTEN (pfile);
+ int action_number = 0;
- token = get_directive_token (pfile);
- if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+ if (read_line_number (pfile, &action_number))
{
- U_CHAR *p = pfile->token_buffer + num_start;
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "garbage at end of `#line' command");
- if (token != CPP_NUMBER || *p < '0' || *p > '4' || p[1] != '\0')
+ if (action_number == 1)
{
- cpp_error (pfile, "invalid format `#line' command");
- goto bad_line_directive;
+ file_change = enter_file;
+ read_line_number (pfile, &action_number);
}
- if (*p == '1')
- file_change = enter_file;
- else if (*p == '2')
- file_change = leave_file;
- else if (*p == '3')
- ip->system_header_p = 1;
- else /* if (*p == '4') */
- ip->system_header_p = 2;
-
- CPP_SET_WRITTEN (pfile, num_start);
- token = get_directive_token (pfile);
- p = pfile->token_buffer + num_start;
- if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4'))
+ else if (action_number == 2)
+ {
+ file_change = leave_file;
+ read_line_number (pfile, &action_number);
+ }
+ if (action_number == 3)
{
- ip->system_header_p = *p == '3' ? 1 : 2;
- token = get_directive_token (pfile);
+ ip->system_header_p = 1;
+ read_line_number (pfile, &action_number);
}
- if (token != CPP_VSPACE)
+ if (action_number == 4)
{
- cpp_error (pfile, "invalid format `#line' command");
- goto bad_line_directive;
+ ip->system_header_p = 2;
+ read_line_number (pfile, &action_number);
}
}
if (strcmp (fname, ip->nominal_fname))
{
- char *newname, *oldname;
+ const char *newname, *oldname;
if (!strcmp (fname, ip->fname))
newname = ip->fname;
else if (ip->last_nominal_fname
&& ip->last_nominal_fname != oldname
&& ip->last_nominal_fname != newname
&& ip->last_nominal_fname != ip->fname)
- free (ip->last_nominal_fname);
+ free ((void *) ip->last_nominal_fname);
if (newname == ip->fname)
ip->last_nominal_fname = NULL;
we must store a line number now that is one less. */
ip->lineno = new_lineno - 1;
CPP_SET_WRITTEN (pfile, old_written);
- output_line_command (pfile, 0, file_change);
+ output_line_command (pfile, file_change);
return 0;
bad_line_directive:
static int
do_undef (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword;
+ const struct directive *keyword;
{
int sym_length;
HASHNODE *hp;
cpp_skip_hspace (pfile);
c = GETC();
- if (! is_idstart[c])
+ if (! is_idstart(c))
{
cpp_error (pfile, "token after #undef is not an identifier");
skip_rest_of_line (pfile);
limit = CPP_PWRITTEN(pfile);
/* Copy out the token so we can pop the token buffer. */
- name = alloca (limit - buf + 1);
+ name = (U_CHAR *) alloca (limit - buf + 1);
bcopy(buf, name, limit - buf);
name[limit - buf] = '\0';
CPP_SET_WRITTEN (pfile, here);
-#if 0
- /* If this is a precompiler run (with -pcp) pass thru #undef commands. */
- if (pcp_outfile && keyword)
- pass_thru_directive (buf, limit, pfile, keyword);
-#endif
-
- sym_length = check_macro_name (pfile, buf, 0);
+ sym_length = check_macro_name (pfile, buf);
while ((hp = cpp_lookup (pfile, name, sym_length, -1)) != NULL)
{
/* If we are generating additional info for debugging (with -g) we
need to pass through all effective #undef commands. */
if (CPP_OPTIONS (pfile)->debug_output && keyword)
- pass_thru_directive (name, name+sym_length, pfile, keyword);
- if (hp->type != T_MACRO)
- cpp_warning (pfile, "undefining `%s'", hp->name);
- delete_macro (hp);
+ pass_thru_directive (name, sym_length, pfile, keyword);
+ if (hp->type == T_POISON)
+ cpp_error (pfile, "cannot undefine poisoned `%s'", hp->name);
+ else
+ {
+ if (hp->type != T_MACRO)
+ cpp_warning (pfile, "undefining `%s'", hp->name);
+ delete_macro (hp);
+ }
}
return 0;
static int
do_error (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
long here = CPP_WRITTEN (pfile);
U_CHAR *text;
static int
do_warning (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
U_CHAR *text;
long here = CPP_WRITTEN(pfile);
return 0;
}
-/* Report program identification. */
+/* Report program identification.
+ This is not precisely what cccp does with #ident, however I believe
+ it matches `closely enough' (behavior is identical as long as there
+ are no macros on the #ident line, which is pathological in my opinion). */
static int
do_ident (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
/* Allow #ident in system headers, since that's not user's fault. */
if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
cpp_pedwarn (pfile, "ANSI C does not allow `#ident'");
- skip_rest_of_line (pfile); /* Correct? Appears to match cccp. */
+ CPP_PUTS (pfile, "#ident ", 7);
+ cpp_skip_hspace (pfile);
+ copy_rest_of_line (pfile);
return 0;
}
static int
do_pragma (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
- long here = CPP_WRITTEN (pfile);
+ long here;
U_CHAR *buf;
+
+ CPP_PUTS (pfile, "#pragma ", 8);
+ cpp_skip_hspace (pfile);
+ here = CPP_WRITTEN (pfile);
copy_rest_of_line (pfile);
buf = pfile->token_buffer + here;
- SKIP_WHITE_SPACE (buf);
if (!strncmp (buf, "once", 4))
{
else
ip->ihash->control_macro = ""; /* never repeat */
}
-
- if (!strncmp (buf, "implementation", 14))
+ else if (!strncmp (buf, "implementation", 14))
{
/* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */
fname = p + 1;
p = (U_CHAR *) index (fname, '\"');
- fcopy = alloca (p - fname + 1);
+ fcopy = (U_CHAR *) alloca (p - fname + 1);
bcopy (fname, fcopy, p - fname);
fcopy[p-fname] = '\0';
"`#pragma implementation' for `%s' appears after file is included",
fcopy);
}
+ else if (!strncmp (buf, "poison", 6))
+ {
+ /* Poison these symbols so that all subsequent usage produces an
+ error message. */
+ U_CHAR *p = buf + 6;
+ size_t plen;
+ U_CHAR *syms;
+ int writeit;
+
+ SKIP_WHITE_SPACE (p);
+ plen = strlen(p) + 1;
+
+ syms = (U_CHAR *) alloca (plen);
+ memcpy (syms, p, plen);
+
+ /* As a rule, don't include #pragma poison commands in output,
+ unless the user asks for them. */
+ writeit = (CPP_OPTIONS (pfile)->debug_output
+ || CPP_OPTIONS (pfile)->dump_macros == dump_definitions
+ || CPP_OPTIONS (pfile)->dump_macros == dump_names);
+
+ if (writeit)
+ CPP_SET_WRITTEN (pfile, here);
+ else
+ CPP_SET_WRITTEN (pfile, here-8);
+
+ if (writeit)
+ {
+ CPP_RESERVE (pfile, plen + 7);
+ CPP_PUTS_Q (pfile, "poison", 7);
+ }
+
+ while (*syms != '\0')
+ {
+ U_CHAR *end = syms;
+
+ while (is_idchar(*end))
+ end++;
+
+ if (!is_hspace(*end) && *end != '\0')
+ {
+ cpp_error (pfile, "invalid #pragma poison directive");
+ return 1;
+ }
+
+ if (cpp_push_buffer (pfile, syms, end - syms) != NULL)
+ {
+ do_define (pfile, keyword);
+ cpp_pop_buffer (pfile);
+ }
+ if (writeit)
+ {
+ CPP_PUTC_Q (pfile, ' ');
+ CPP_PUTS_Q (pfile, syms, end - syms);
+ }
+ syms = end;
+ SKIP_WHITE_SPACE (syms);
+ }
+ }
return 0;
}
static int
do_sccs (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'");
}
#endif
\f
+
+/* We've found an `#if' directive. If the only thing before it in
+ this file is white space, and if it is of the form
+ `#if ! defined SYMBOL', then SYMBOL is a possible controlling macro
+ for inclusion of this file. (See redundant_include_p in cppfiles.c
+ for an explanation of controlling macros.) If so, return a
+ malloc'd copy of SYMBOL. Otherwise, return NULL. */
+
+static U_CHAR *
+detect_if_not_defined (pfile)
+ cpp_reader *pfile;
+{
+ U_CHAR *control_macro = 0;
+
+ if (pfile->only_seen_white == 2)
+ {
+ char *ident;
+ enum cpp_token token;
+ int base_offset;
+ int token_offset;
+ int need_rparen = 0;
+
+ /* Save state required for restore. */
+ pfile->no_macro_expand++;
+ parse_set_mark (pfile);
+ base_offset = CPP_WRITTEN (pfile);
+
+ /* Look for `!', */
+ if (get_directive_token (pfile) != CPP_OTHER
+ || CPP_WRITTEN (pfile) != (size_t) base_offset + 1
+ || CPP_PWRITTEN (pfile)[-1] != '!')
+ goto restore;
+
+ /* ...then `defined', */
+ token_offset = CPP_WRITTEN (pfile);
+ token = get_directive_token (pfile);
+ if (token != CPP_NAME)
+ goto restore;
+ ident = pfile->token_buffer + token_offset;
+ CPP_NUL_TERMINATE (pfile);
+ if (strcmp (ident, "defined"))
+ goto restore;
+
+ /* ...then an optional '(' and the name, */
+ token_offset = CPP_WRITTEN (pfile);
+ token = get_directive_token (pfile);
+ if (token == CPP_LPAREN)
+ {
+ token_offset = CPP_WRITTEN (pfile);
+ token = get_directive_token (pfile);
+ if (token != CPP_NAME)
+ goto restore;
+ need_rparen = 1;
+ }
+ else if (token != CPP_NAME)
+ goto restore;
+
+ ident = pfile->token_buffer + token_offset;
+ CPP_NUL_TERMINATE (pfile);
+
+ /* ...then the ')', if necessary, */
+ if ((!need_rparen || get_directive_token (pfile) == CPP_RPAREN)
+ /* ...and make sure there's nothing else on the line. */
+ && get_directive_token (pfile) == CPP_VSPACE)
+ control_macro = xstrdup (ident);
+
+ restore:
+ CPP_SET_WRITTEN (pfile, base_offset);
+ pfile->no_macro_expand--;
+ parse_goto_mark (pfile);
+ }
+
+ return control_macro;
+}
+
/*
* handle #if command by
* 1) inserting special `defined' keyword into the hash table
static int
do_if (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
+ U_CHAR *control_macro = detect_if_not_defined (pfile);
HOST_WIDEST_INT value = eval_if_expression (pfile);
- conditional_skip (pfile, value == 0, T_IF, NULL_PTR);
+ conditional_skip (pfile, value == 0, T_IF, control_macro);
return 0;
}
static int
do_elif (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) {
cpp_error (pfile, "`#elif' not within a conditional");
skip_if_group (pfile);
else {
++pfile->if_stack->if_succeeded; /* continue processing input */
- output_line_command (pfile, 1, same_file);
+ output_line_command (pfile, same_file);
}
}
return 0;
static int
do_xifdef (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword;
+ const struct directive *keyword;
{
int skip;
cpp_buffer *ip = CPP_BUFFER (pfile);
control_macro = (U_CHAR *) xmalloc (ident_length + 1);
bcopy (ident, control_macro, ident_length + 1);
}
+ if (hp != NULL && hp->type == T_POISON)
+ {
+ cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
+ skip = !skip;
+ }
}
else
{
else {
U_CHAR *cp = buf;
fprintf (pcp_outfile, "#undef ");
- while (is_idchar[*cp]) /* Ick! */
+ while (is_idchar(*cp)) /* Ick! */
fputc (*cp++, pcp_outfile);
putc ('\n', pcp_outfile);
}
temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
temp->fname = CPP_BUFFER (pfile)->nominal_fname;
-#if 0
temp->lineno = CPP_BUFFER (pfile)->lineno;
-#endif
temp->next = pfile->if_stack;
temp->control_macro = control_macro;
pfile->if_stack = temp;
return;
} else {
++pfile->if_stack->if_succeeded;
- output_line_command (pfile, 1, same_file);
+ output_line_command (pfile, same_file);
}
}
IF_STACK_FRAME *stack;
{
long ident_len, ident;
- struct directive *kt;
+ const struct directive *kt;
IF_STACK_FRAME *temp;
cpp_skip_hspace (pfile);
{
CPP_PUTS (pfile, "#failed\n", 8);
pfile->lineno++;
- output_line_command (pfile, 1, same_file);
+ output_line_command (pfile, same_file);
}
old_written = CPP_WRITTEN (pfile);
static int
do_else (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
skip_if_group (pfile);
else {
++pfile->if_stack->if_succeeded; /* continue processing input */
- output_line_command (pfile, 1, same_file);
+ output_line_command (pfile, same_file);
}
return 0;
}
static int
do_endif (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
if (CPP_PEDANTIC (pfile))
validate_else (pfile, "#endif");
skip_rest_of_line (pfile);
if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
- cpp_error (pfile, "unbalanced `#endif'");
+ cpp_error (pfile, "`#endif' not within a conditional");
else
{
IF_STACK_FRAME *temp = pfile->if_stack;
}
}
free (temp);
- output_line_command (pfile, 1, same_file);
+ output_line_command (pfile, same_file);
}
return 0;
}
static void
validate_else (pfile, directive)
cpp_reader *pfile;
- char *directive;
+ const char *directive;
{
int c;
cpp_skip_hspace (pfile);
"text following `%s' violates ANSI standard", directive);
}
+/* Convert T_IF, etc. to a string. Used in error messages. */
+static const char *
+if_directive_name (pfile, ifs)
+ cpp_reader *pfile;
+ struct if_stack *ifs;
+{
+ switch (ifs->type)
+ {
+ case T_IF: return "#if";
+ case T_IFDEF: return "#ifdef";
+ case T_IFNDEF: return "#ifndef";
+ case T_ELIF: return "#elif";
+ case T_ELSE: return "#else";
+ default:
+ cpp_fatal (pfile, "impossible if_stack->type value %d", ifs->type);
+ return "unknown";
+ }
+}
+
/* Get the next token, and add it to the text in pfile->token_buffer.
Return the kind of token we got. */
if (c == EOF)
{
handle_eof:
- if (CPP_BUFFER (pfile)->seen_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)) == CPP_NULL_BUFFER (pfile))
return CPP_EOF;
}
else
{
- cpp_buffer *next_buf
- = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
- CPP_BUFFER (pfile)->seen_eof = 1;
+ 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 != CPP_NULL_BUFFER (pfile))
{
cpp_buffer *cur_buffer = CPP_BUFFER (pfile);
CPP_BUFFER (pfile) = next_buf;
pfile->input_stack_listing_current = 0;
- output_line_command (pfile, 0, leave_file);
+ output_line_command (pfile, leave_file);
CPP_BUFFER (pfile) = cur_buffer;
}
+
+ CPP_BUFFER (pfile)->seen_eof = 1;
return CPP_POP;
}
}
/* OK, now bring us back to the state we were in before we entered
this branch. We need #line because the newline for the pragma
could mess things up. */
- output_line_command (pfile, 0, same_file);
+ output_line_command (pfile, same_file);
*(obp++) = ' '; /* just in case, if comments are copied thru */
*(obp++) = '/';
}
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;
c2 = PEEKC ();
if (c2 == '-' && opts->chill)
goto comment; /* Chill style comment */
- if (c2 == '-' || c2 == '=' || c2 == '>')
+ 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 '<':
}
else if (c == '\r')
{
- /* Backslash newline is replaced by nothing. */
- CPP_ADJUST_WRITTEN (pfile, -1);
- CPP_BUMP_LINE (pfile);
+ 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_fatal (pfile,
+ "internal error: unrecognized escape \\r%c",
+ d);
+ CPP_ADJUST_WRITTEN (pfile, -1);
+ }
}
}
return CPP_STRING;
c2 = PEEKC ();
if (c2 == '=')
goto op2;
- if (c2 != c)
+ /* GNU C++ supports MIN and MAX operators <? and >?. */
+ if (c2 != c && (!opts->cplusplus || c2 != '?'))
goto randomchar;
FORWARD(1);
CPP_RESERVE (pfile, 4);
pfile->only_seen_white = 0;
return CPP_OTHER;
- case '@':
- if (CPP_BUFFER (pfile)->has_escapes)
- {
- c = GETC ();
- if (c == '-')
- {
- if (pfile->output_escapes)
- CPP_PUTS (pfile, "@-", 2);
- parse_name (pfile, GETC ());
- return CPP_NAME;
- }
- else if (c == ' ')
- {
- CPP_RESERVE (pfile, 2);
- if (pfile->output_escapes)
- CPP_PUTC_Q (pfile, '@');
- CPP_PUTC_Q (pfile, c);
- return CPP_HSPACE;
- }
- }
- if (pfile->output_escapes)
- {
- CPP_PUTS (pfile, "@@", 2);
- return CPP_OTHER;
- }
- goto randomchar;
-
case '.':
c2 = PEEKC ();
if (ISDIGIT(c2))
c = GETC ();
goto number;
}
+
+ /* In C++ there's a .* operator. */
+ if (opts->cplusplus && c2 == '*')
+ goto op2;
+
if (c2 == '.' && PEEKN(1) == '.')
{
CPP_RESERVE(pfile, 4);
c = PEEKC ();
if (c == EOF)
break;
- if (!is_idchar[c] && c != '.'
+ if (!is_idchar(c) && c != '.'
&& ((c2 != 'e' && c2 != 'E'
&& ((c2 != 'p' && c2 != 'P') || CPP_C89 (pfile)))
|| (c != '+' && c != '-')))
c = GETC();
if (c == EOF)
goto chill_number_eof;
- if (!is_idchar[c])
+ if (!is_idchar(c))
break;
CPP_PUTC (pfile, c);
}
if (hp->type == T_DISABLED)
{
if (pfile->output_escapes)
- { /* Return "@-IDENT", followed by '\0'. */
+ { /* 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] = '@';
+ ident[0] = '\r';
ident[1] = '-';
}
return CPP_NAME;
{
CPP_PUTC (pfile, c);
c = PEEKC ();
- if (c == EOF || !is_hor_space[c])
+ if (c == EOF || !is_hspace(c))
break;
FORWARD(1);
}
return CPP_HSPACE;
- case '\\':
- goto randomchar;
-
case '\r':
- /* Backslash newline is ignored. */
- CPP_BUMP_LINE (pfile);
- goto get_next;
+ 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_fatal (pfile,
+ "internal error: 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);
- pfile->lineno++;
- if (CPP_BUFFER (pfile)->lineno != pfile->lineno)
- output_line_command (pfile, 1, same_file);
+ 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;
{
for (;;)
{
- if (! is_idchar[c])
+ if (! is_idchar(c))
{
FORWARD (-1);
break;
/* Parse 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. */
+ multiple lines.) */
static void
parse_string (pfile, c)
cpp_reader *pfile;
cpp_pop_buffer (pfile);
continue;
}
- if (!CPP_TRADITIONAL (pfile))
- {
- 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;
- }
+
+ 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;
break;
}
CPP_PUTC (pfile, cc);
case '\n':
CPP_BUMP_LINE (pfile);
pfile->lineno++;
- /* Traditionally, end of line ends a string constant with
- no error. */
- if (CPP_TRADITIONAL (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)
return;
- /* Character constants may not extend over multiple lines. */
+ /* 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,
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");
- }
+ 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':
- /* Backslash newline is replaced by nothing at all. */
CPP_ADJUST_WRITTEN (pfile, -1);
- CPP_BUMP_LINE (pfile);
+ if (CPP_BUFFER (pfile)->has_escapes)
+ {
+ cpp_fatal (pfile,
+ "internal error: \\r escape inside string constant");
+ FORWARD(1);
+ }
+ else
+ /* Backslash newline is replaced by nothing at all. */
+ CPP_BUMP_LINE (pfile);
break;
case '\\':
int c, dropwhite;
cpp_skip_hspace (pfile);
c = PEEKC();
- if (! is_idstart[c])
+ if (! is_idstart(c))
{
cpp_error (pfile, "assertion predicate is not an identifier");
return 0;
c = PEEKC();
if (c != '(')
{
- if (is_hor_space[c] || c == '\r')
+ if (is_hspace(c) || c == '\r')
cpp_skip_hspace (pfile);
c = PEEKC();
}
dropwhite = 1;
while ((c = GETC()) != ')')
{
- if (is_hor_space[c])
+ if (is_space(c))
{
if (! dropwhite)
{
return 0;
}
else if (c == '\r')
+ /* \r cannot be a macro escape here. */
CPP_BUMP_LINE (pfile);
else
{
static int
do_assert (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
char *sym;
int ret, c;
return 0;
error:
- pfile->limit = (unsigned char *) sym; /* Pop */
skip_rest_of_line (pfile);
- return 1;
+ pfile->limit = (unsigned char *) sym; /* Pop */
+ return 0;
}
static int
do_unassert (pfile, keyword)
cpp_reader *pfile;
- struct directive *keyword ATTRIBUTE_UNUSED;
+ const struct directive *keyword ATTRIBUTE_UNUSED;
{
int c, ret;
char *sym;
pfile->limit = (unsigned char *) sym; /* Pop */
return 0;
error:
- pfile->limit = (unsigned char *) sym; /* Pop */
skip_rest_of_line (pfile);
- return 1;
+ pfile->limit = (unsigned char *) sym; /* Pop */
+ return 0;
}
/* Process STR as if it appeared as the body of an #unassert. */
ip->mark = -1;
}
-void
+static void
cpp_print_file_and_line (pfile)
cpp_reader *pfile;
{
giving specified file name and line number, not current. */
void
-cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
- const char *msgid, ...))
+cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, const char *file,
+ int line, const char *msgid, ...))
{
#ifndef ANSI_PROTOTYPES
cpp_reader *pfile;
- char *file;
+ const char *file;
int line;
const char *msgid;
#endif
#ifndef ANSI_PROTOTYPES
pfile = va_arg (ap, cpp_reader *);
- file = va_arg (ap, char *);
+ file = va_arg (ap, const char *);
line = va_arg (ap, int);
msgid = va_arg (ap, const char *);
#endif
/* my_strerror - return the descriptive text associated with an
`errno' code. */
-static char *
+static const char *
my_strerror (errnum)
int errnum;
{
- char *result;
+ const char *result;
#ifndef VMS
#ifndef HAVE_STRERROR