* cppexp.c (parse_assertion): New.
(lex): Call it for CPP_HASH. Remove CPP_ASSERTION case.
(_cpp_parse_expr): Remove case '#'. Don't set
parsing_if_directive.
* cpphash.c (collect_objlike_expansion,
collect_funlike_expansion, collect_params,
_cpp_create_definition): The list no longer has a trailing
VSPACE token.
* cpphash.h (enum node_type): Add T_ASSERTION.
(struct hashnode): Remove aschain, add pred.
(struct predicate): New.
Update prototypes.
* cpplex.c (expand_token_space): Handle both offset and
nonoffset lists.
(init_token_list, _cpp_free_token_list, _cpp_parse_assertion): Delete.
(_cpp_init_toklist, _cpp_clear_toklist, _cpp_free_toklist,
_cpp_slice_toklist, _cpp_squeeze_toklist, _cpp_equiv_tokens,
_cpp_equiv_toklists): New.
(_cpp_scan_line): Rename to _cpp_scan_until; add ability to
stop at any single-character token, not just newline.
(_cpp_lex_token): Remove special cases for #define and #if.
(cpp_get_token): Expect # as a separate token type. Remove
DIRECTIVE case.
(_cpp_get_directive_token): Remove DIRECTIVE case.
(_cpp_lex_line, _cpp_lex_file, _cpp_init_input_buffer): Update.
* cpplib.c (_cpp_check_directive): Set dirno and
SYNTAX_INCLUDE bit of flags, not dir_handler and dir_flags.
(_cpp_handle_directive): Run # <number> through the same logic
as normal directives.
(do_define): Don't set parsing_define_directive. Use
_cpp_scan_until. The list does not have a VSPACE at the end.
(do_if): Save, clear, and restore only_seen_white around
_cpp_parse_expr.
(skip_if_group): s/CPP_DIRECTIVE/CPP_HASH/
(do_assert, do_unassert): Rewrite.
* cpplib.h (TTYPE_TABLE): Remove CPP_ASSERTION.
(LIST_OFFSET): New flag.
(struct cpp_toklist): Replace dir_handler and dir_flags with
dirno and flags.
(struct cpp_reader): Remove parsing_if_directive and
parsing_define_directive.
From-SVN: r33984
+2000-05-18 Zack Weinberg <zack@wolery.cumb.org>
+
+ * cppexp.c (parse_assertion): New.
+ (lex): Call it for CPP_HASH. Remove CPP_ASSERTION case.
+ (_cpp_parse_expr): Remove case '#'. Don't set
+ parsing_if_directive.
+ * cpphash.c (collect_objlike_expansion,
+ collect_funlike_expansion, collect_params,
+ _cpp_create_definition): The list no longer has a trailing
+ VSPACE token.
+ * cpphash.h (enum node_type): Add T_ASSERTION.
+ (struct hashnode): Remove aschain, add pred.
+ (struct predicate): New.
+ Update prototypes.
+
+ * cpplex.c (expand_token_space): Handle both offset and
+ nonoffset lists.
+ (init_token_list, _cpp_free_token_list, _cpp_parse_assertion): Delete.
+ (_cpp_init_toklist, _cpp_clear_toklist, _cpp_free_toklist,
+ _cpp_slice_toklist, _cpp_squeeze_toklist, _cpp_equiv_tokens,
+ _cpp_equiv_toklists): New.
+ (_cpp_scan_line): Rename to _cpp_scan_until; add ability to
+ stop at any single-character token, not just newline.
+ (_cpp_lex_token): Remove special cases for #define and #if.
+ (cpp_get_token): Expect # as a separate token type. Remove
+ DIRECTIVE case.
+ (_cpp_get_directive_token): Remove DIRECTIVE case.
+ (_cpp_lex_line, _cpp_lex_file, _cpp_init_input_buffer): Update.
+
+ * cpplib.c (_cpp_check_directive): Set dirno and
+ SYNTAX_INCLUDE bit of flags, not dir_handler and dir_flags.
+ (_cpp_handle_directive): Run # <number> through the same logic
+ as normal directives.
+ (do_define): Don't set parsing_define_directive. Use
+ _cpp_scan_until. The list does not have a VSPACE at the end.
+ (do_if): Save, clear, and restore only_seen_white around
+ _cpp_parse_expr.
+ (skip_if_group): s/CPP_DIRECTIVE/CPP_HASH/
+ (do_assert, do_unassert): Rewrite.
+
+ * cpplib.h (TTYPE_TABLE): Remove CPP_ASSERTION.
+ (LIST_OFFSET): New flag.
+ (struct cpp_toklist): Replace dir_handler and dir_flags with
+ dirno and flags.
+ (struct cpp_reader): Remove parsing_if_directive and
+ parsing_define_directive.
+
2000-05-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* fixinc/inclhack.def (broken_cabs): Update fix to handle comments
static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *,
U_CHAR *));
static struct operation parse_defined PARAMS ((cpp_reader *));
+static struct operation parse_assertion PARAMS ((cpp_reader *));
static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **,
HOST_WIDEST_INT));
static struct operation lex PARAMS ((cpp_reader *, int));
HOST_WIDEST_INT value; /* The value logically "right" of op. */
};
+/* With -O2, gcc appears to produce nice code, moving the error
+ message load and subsequent jump completely out of the main path. */
+#define CPP_ICE(msgid) \
+ do { cpp_ice (pfile, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR(msgid) \
+ do { cpp_error (pfile, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR2(msgid, arg) \
+ do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
+
/* Parse and convert an integer for #if. Accepts decimal, hex, or octal
with or without size suffixes. */
return op;
}
+static struct operation
+parse_assertion (pfile)
+ cpp_reader *pfile;
+{
+ struct operation op;
+ HASHNODE *hp;
+ struct predicate *pred;
+ cpp_toklist query;
+ enum cpp_ttype type;
+ U_CHAR *tok;
+ size_t len;
+ unsigned int old_written;
+ int specific = 0;
+
+ old_written = CPP_WRITTEN (pfile);
+ CPP_PUTC (pfile, '#');
+ pfile->no_macro_expand++;
+ type = _cpp_get_directive_token (pfile);
+ if (type == CPP_VSPACE)
+ SYNTAX_ERROR ("assertion without predicate");
+ else if (type != CPP_NAME)
+ SYNTAX_ERROR ("assertion predicate is not an identifier");
+
+ tok = pfile->token_buffer + old_written;
+ len = CPP_WRITTEN (pfile) - old_written;
+ hp = _cpp_lookup (pfile, tok, len);
+
+ /* Look ahead for an open paren. */
+ _cpp_skip_hspace (pfile);
+ if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(')
+ {
+ if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN)
+ CPP_ICE ("impossible token, expecting ( in parse_assertion");
+
+ _cpp_init_toklist (&query);
+ specific = 1;
+ if (_cpp_scan_until (pfile, &query, CPP_CLOSE_PAREN) != CPP_CLOSE_PAREN)
+ SYNTAX_ERROR ("missing close paren on assertion answer");
+
+ if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
+ CPP_ICE ("impossible token, expecting ) in parse_assertion");
+ }
+
+ /* If we get here, the syntax is valid. */
+ op.op = INT;
+ op.value = 0;
+ /* Has this predicate been asserted at all? */
+ if (hp->type == T_ASSERTION)
+ {
+ if (specific)
+ {
+ for (pred = hp->value.pred; pred; pred = pred->next)
+ if (_cpp_equiv_toklists (&query, &pred->answer))
+ {
+ op.value = 1;
+ break;
+ }
+ _cpp_free_toklist (&query);
+ }
+ else
+ op.value = 1;
+ }
+
+ out:
+ pfile->no_macro_expand--;
+ CPP_SET_WRITTEN (pfile, old_written);
+ return op;
+
+ syntax_error:
+ if (specific)
+ _cpp_free_toklist (&query);
+ op.op = ERROR;
+ goto out;
+}
+
struct token
{
const char *operator;
(int) (tok_end - tok_start), tok_start);
return op;
- case CPP_ASSERTION:
- op.op = INT;
- op.unsignedp = 0;
- op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
- return op;
+ case CPP_HASH:
+ return parse_assertion (pfile);
case CPP_OTHER:
/* See if it is a special token of length 2. */
top->value = v1 OP v2; \
top->unsignedp = unsigned1 | unsigned2;
-/* With -O2, gcc appears to produce nice code, moving the error
- message load and subsequent jump completely out of the main path. */
-#define CPP_ICE(msgid) \
- do { cpp_ice (pfile, msgid); goto syntax_error; } while(0)
-#define SYNTAX_ERROR(msgid) \
- do { cpp_error (pfile, msgid); goto syntax_error; } while(0)
-#define SYNTAX_ERROR2(msgid, arg) \
- do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
-
/* Parse and evaluate a C expression, reading from PFILE.
Returns the truth value of the expression. */
int result;
char buff[5];
- pfile->parsing_if_directive++;
/* We've finished when we try to reduce this. */
top->op = FINISHED;
/* Nifty way to catch missing '('. */
CPP_ICE ("lex returns a NAME");
case ERROR:
goto syntax_error;
- case '#':
- /* We get '#' when get_directive_token hits a syntactically
- invalid assertion predicate. _cpp_parse_assertion has
- already issued an error. */
- goto syntax_error;
default:
SYNTAX_ERROR ("invalid character in #if");
/* Free dynamic stack if we allocated one. */
if (stack != init_stack)
free (stack);
- pfile->parsing_if_directive--;
CPP_SET_WRITTEN (pfile, old_written);
return result;
}
{
switch (TOK_TYPE (list, i))
{
- case CPP_EOF:
- cpp_ice (pfile, "EOF in collect_expansion");
- /* fall through */
- case CPP_VSPACE:
- goto done;
-
case CPP_PASTE:
/* ## is not special if it appears right after another ##;
nor is it special if -traditional. */
CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i));
last_was_paste = 0;
}
- done:
if (last_was_paste)
cpp_error (pfile, "`##' at end of macro definition");
len = TOK_LEN (list, i);
switch (token)
{
- case CPP_EOF:
- cpp_ice (pfile, "EOF in collect_expansion");
- /* fall through */
- case CPP_VSPACE:
- goto done;
-
case CPP_HASH:
/* # is special in function-like macros with no args.
(6.10.3.2 para 1.) However, it is not special after
}
last_token = ARG;
}
- done:
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
case CPP_CLOSE_PAREN:
goto scanned;
case CPP_VSPACE:
- cpp_error_with_line (pfile, list->line, TOK_COL (list, i),
- "missing right paren in macro argument list");
+ case CPP_EOF:
+ cpp_ice (pfile, "impossible token in macro argument list");
return 0;
default:
}
goto scanned;
}
-
- cpp_ice (pfile, "collect_params: unreachable - i=%d, ntokens=%d, type=%d",
- i, list->tokens_used, TOK_TYPE (list, i-1));
+ cpp_error_with_line (pfile, list->line, TOK_COL (list, i-1),
+ "missing right paren in macro argument list");
return 0;
scanned:
#define FUNC(a, b, ...) // nothing
#define FUNC(a, b, c) FUNC(a, b, c) */
- if (list->tokens_used == 2)
+ if (list->tokens_used == 1)
ntype = T_EMPTY; /* Empty definition of object-like macro. */
- else if (list->tokens_used == 3 && TOK_TYPE (list, 1) == CPP_NAME
+ else if (list->tokens_used == 2 && TOK_TYPE (list, 1) == CPP_NAME
&& TOK_LEN (list, 0) == TOK_LEN (list, 1)
&& !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1),
TOK_LEN (list, 0)))
T_MACRO, /* object-like macro */
T_FMACRO, /* function-like macro */
T_IDENTITY, /* macro defined to itself */
- T_EMPTY /* macro defined to nothing */
+ T_EMPTY, /* macro defined to nothing */
+ T_ASSERTION /* predicate for #assert */
};
typedef struct hashnode HASHNODE;
const U_CHAR *cpval; /* some predefined macros */
const struct object_defn *odefn; /* #define foo bar */
const struct funct_defn *fdefn; /* #define foo(x) bar(x) */
- struct hashnode *aschain; /* #assert */
+ struct predicate *pred; /* #assert */
} value;
const U_CHAR name[1]; /* name[length] */
};
+/* Structure used for assertion predicates. */
+struct predicate
+{
+ struct predicate *next;
+ struct cpp_toklist answer;
+};
+
/* List of directories to look for include files in. */
struct file_name_list
{
PARAMS ((cpp_reader *));
extern enum cpp_ttype _cpp_get_define_token
PARAMS ((cpp_reader *));
-extern void _cpp_scan_line PARAMS ((cpp_reader *, cpp_toklist *));
+extern enum cpp_ttype _cpp_scan_until PARAMS ((cpp_reader *, cpp_toklist *,
+ enum cpp_ttype));
+extern void _cpp_init_toklist PARAMS ((cpp_toklist *));
+extern void _cpp_clear_toklist PARAMS ((cpp_toklist *));
+extern void _cpp_free_toklist PARAMS ((cpp_toklist *));
+extern void _cpp_slice_toklist PARAMS ((cpp_toklist *,
+ const cpp_token *,
+ const cpp_token *));
+extern void _cpp_squeeze_toklist PARAMS ((cpp_toklist *));
+extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,
+ const cpp_token *));
+extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *,
+ const cpp_toklist *));
+
/* In cpplib.c */
extern int _cpp_handle_directive PARAMS ((cpp_reader *));
unsigned int));
static void expand_name_space PARAMS ((cpp_toklist *, unsigned int));
static void expand_token_space PARAMS ((cpp_toklist *));
-static void init_token_list PARAMS ((cpp_reader *, cpp_toklist *, int));
static void pedantic_whitespace PARAMS ((cpp_reader *, U_CHAR *,
unsigned int));
for (;;)
{
token = cpp_get_token (pfile);
- if (token == CPP_EOF || token == CPP_VSPACE
+ if (token == CPP_VSPACE || token == CPP_EOF
/* XXX Temporary kluge - force flush after #include only */
|| (token == CPP_DIRECTIVE
&& CPP_BUFFER (pfile)->nominal_fname != print->last_fname))
cpp_toklist *list;
{
list->tokens_cap *= 2;
+ if (list->flags & LIST_OFFSET)
+ list->tokens--;
list->tokens = (cpp_token *)
- xrealloc (list->tokens - 1, (list->tokens_cap + 1) * sizeof (cpp_token));
- list->tokens++; /* Skip the dummy. */
+ xrealloc (list->tokens, (list->tokens_cap + 1) * sizeof (cpp_token));
+ if (list->flags & LIST_OFFSET)
+ list->tokens++; /* Skip the dummy. */
}
/* Initialize a token list. We allocate an extra token in front of
the token list, as this allows us to always peek at the previous
token without worrying about underflowing the list. */
-static void
-init_token_list (pfile, list, recycle)
- cpp_reader *pfile;
+void
+_cpp_init_toklist (list)
cpp_toklist *list;
- int recycle;
{
- /* Recycling a used list saves 3 free-malloc pairs. */
- if (!recycle)
- {
- /* Initialize token space. Put a dummy token before the start
- that will fail matches. */
- list->tokens_cap = 256; /* 4K's worth. */
- list->tokens = (cpp_token *)
- xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
- list->tokens[0].type = CPP_EOF;
- list->tokens++;
-
- /* Initialize name space. */
- list->name_cap = 1024;
- list->namebuf = (unsigned char *) xmalloc (list->name_cap);
-
- /* Only create a comment space on demand. */
- list->comments_cap = 0;
- list->comments = 0;
- }
+ /* Initialize token space. Put a dummy token before the start
+ that will fail matches. */
+ list->tokens_cap = 256; /* 4K's worth. */
+ list->tokens = (cpp_token *)
+ xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
+ list->tokens[0].type = CPP_EOF;
+ list->tokens++;
+
+ /* Initialize name space. */
+ list->name_cap = 1024;
+ list->namebuf = (unsigned char *) xmalloc (list->name_cap);
+
+ /* Only create a comment space on demand. */
+ list->comments_cap = 0;
+ list->comments = 0;
+
+ list->flags = LIST_OFFSET;
+ _cpp_clear_toklist (list);
+}
+/* Clear a token list. */
+void
+_cpp_clear_toklist (list)
+ cpp_toklist *list;
+{
list->tokens_used = 0;
list->name_used = 0;
list->comments_used = 0;
- if (pfile->buffer)
- list->line = pfile->buffer->lineno;
- list->dir_handler = 0;
- list->dir_flags = 0;
+ list->dirno = -1;
+ list->flags &= LIST_OFFSET; /* clear all but that one */
+}
+
+/* Free a token list. Does not free the list itself, which may be
+ embedded in a larger structure. */
+void
+_cpp_free_toklist (list)
+ cpp_toklist *list;
+{
+ if (list->comments)
+ free (list->comments);
+ if (list->flags & LIST_OFFSET)
+ free (list->tokens - 1); /* Backup over dummy token. */
+ else
+ free (list->tokens);
+ free (list->namebuf);
}
-/* Scan an entire line and create a token list for it. Does not
- macro-expand or execute directives. */
+/* Slice a token list: copy the sublist [START, FINISH) into COPY.
+ COPY is assumed not to be initialized. The comment space is not
+ copied. */
+void
+_cpp_slice_toklist (copy, start, finish)
+ cpp_toklist *copy;
+ const cpp_token *start, *finish;
+{
+ unsigned int i, n;
+ size_t bytes;
+
+ n = finish - start;
+ copy->tokens_cap = n;
+ copy->tokens = (cpp_token *) xmalloc (n * sizeof (cpp_token));
+ memcpy (copy->tokens, start, n * sizeof (cpp_token));
+
+ bytes = 0;
+ for (i = 0; i < n; i++)
+ if (token_spellings[start[i].type].type > SPELL_NONE)
+ bytes += start[i].val.name.len;
+
+ copy->namebuf = xmalloc (bytes);
+ bytes = 0;
+ for (i = 0; i < n; i++)
+ if (token_spellings[start[i].type].type > SPELL_NONE)
+ {
+ memcpy (copy->namebuf + bytes,
+ start[i].val.name.text, start[i].val.name.len);
+ copy->tokens[i].val.name.text = copy->namebuf + bytes;
+ bytes += start[i].val.name.len;
+ }
+
+ copy->tokens_cap = n;
+ copy->tokens_used = n;
+ copy->name_used = bytes;
+ copy->name_cap = bytes;
+ copy->comments = 0;
+ copy->comments_cap = 0;
+ copy->comments_used = 0;
+
+ copy->flags = 0;
+ copy->dirno = -1;
+}
+/* Shrink a token list down to the minimum size. */
void
-_cpp_scan_line (pfile, list)
+_cpp_squeeze_toklist (list)
+ cpp_toklist *list;
+{
+ long delta;
+ const U_CHAR *old_namebuf;
+
+ if (list->flags & LIST_OFFSET)
+ {
+ list->tokens--;
+ memmove (list->tokens, list->tokens + 1,
+ list->tokens_used * sizeof (cpp_token));
+ list->tokens = xrealloc (list->tokens,
+ list->tokens_used * sizeof (cpp_token));
+ list->flags &= ~LIST_OFFSET;
+ }
+ else
+ list->tokens = xrealloc (list->tokens,
+ list->tokens_used * sizeof (cpp_token));
+ list->tokens_cap = list->tokens_used;
+
+ old_namebuf = list->namebuf;
+ list->namebuf = xrealloc (list->namebuf, list->name_used);
+ list->name_cap = list->name_used;
+
+ /* Fix up token text pointers. */
+ delta = list->namebuf - old_namebuf;
+ if (delta)
+ {
+ unsigned int i;
+
+ for (i = 0; i < list->tokens_used; i++)
+ if (token_spellings[list->tokens[i].type].type > SPELL_NONE)
+ list->tokens[i].val.name.text += delta;
+ }
+
+ if (list->comments_cap)
+ {
+ list->comments = xrealloc (list->comments,
+ list->comments_used * sizeof (cpp_token));
+ list->comments_cap = list->comments_used;
+ }
+}
+
+/* Compare two tokens. */
+int
+_cpp_equiv_tokens (a, b)
+ const cpp_token *a, *b;
+{
+ if (a->type != b->type
+ || a->flags != b->flags
+ || a->aux != b->aux)
+ return 0;
+
+ if (token_spellings[a->type].type > SPELL_NONE)
+ {
+ if (a->val.name.len != b->val.name.len
+ || ustrncmp(a->val.name.text,
+ b->val.name.text,
+ a->val.name.len))
+ return 0;
+ }
+ return 1;
+}
+
+/* Compare two token lists. */
+int
+_cpp_equiv_toklists (a, b)
+ const cpp_toklist *a, *b;
+{
+ unsigned int i;
+
+ if (a->tokens_used != b->tokens_used)
+ return 0;
+
+ for (i = 0; i < a->tokens_used; i++)
+ if (! _cpp_equiv_tokens (&a->tokens[i], &b->tokens[i]))
+ return 0;
+ return 1;
+}
+
+/* Scan until we encounter a token of type STOP or a newline, and
+ create a token list for it. Does not macro-expand or execute
+ directives. The final token is not included in the list or
+ consumed from the input. Returns the type of the token stopped at. */
+
+enum cpp_ttype
+_cpp_scan_until (pfile, list, stop)
cpp_reader *pfile;
cpp_toklist *list;
+ enum cpp_ttype stop;
{
int i, col;
long written, len;
enum cpp_ttype type;
int space_before;
- init_token_list (pfile, list, 1);
+ _cpp_clear_toklist (list);
+ list->line = CPP_BUF_LINE (CPP_BUFFER (pfile));
written = CPP_WRITTEN (pfile);
i = 0;
if (type == CPP_MACRO)
type = CPP_NAME;
+ if (type == CPP_VSPACE || type == stop)
+ break;
+
list->tokens_used++;
TOK_TYPE (list, i) = type;
TOK_COL (list, i) = col;
TOK_FLAGS (list, i) = space_before ? PREV_WHITESPACE : 0;
- if (type == CPP_VSPACE)
- break;
-
TOK_LEN (list, i) = len;
if (token_spellings[type].type > SPELL_NONE)
{
i++;
space_before = 0;
}
- TOK_AUX (list, i) = CPP_BUFFER (pfile)->lineno + 1;
- /* XXX Temporary kluge: put back the newline. */
+ /* XXX Temporary kluge: put back the newline (or whatever). */
FORWARD(-1);
-}
+ /* Don't consider the first token to have white before. */
+ TOK_FLAGS (list, 0) &= ~PREV_WHITESPACE;
+ return type;
+}
/* Skip a C-style block comment. We know it's a comment, and point is
at the second character of the starter. */
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 (c == '\n')
- {
- cpp_error (pfile, "assertion without predicate");
- return 0;
- }
- else 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, ')');
-
- return 2;
-}
-
/* Get the next token, and add it to the text in pfile->token_buffer.
Return the kind of token we got. */
if (!CPP_OPTION (pfile, discard_comments))
return CPP_COMMENT;
else if (CPP_TRADITIONAL (pfile))
- {
- if (pfile->parsing_define_directive)
- return CPP_COMMENT;
- goto get_next;
- }
+ goto get_next;
else
{
CPP_PUTC (pfile, c);
CPP_PUTC (pfile, c);
hash:
- if (pfile->parsing_if_directive)
+ c2 = PEEKC ();
+ if (c2 == '#')
{
- CPP_ADJUST_WRITTEN (pfile, -1);
- if (_cpp_parse_assertion (pfile))
- return CPP_ASSERTION;
- return CPP_OTHER;
+ FORWARD (1);
+ CPP_PUTC (pfile, c2);
+ return CPP_PASTE;
}
-
- if (pfile->parsing_define_directive)
+ else if (c2 == '%' && PEEKN (1) == ':')
{
- c2 = PEEKC ();
- if (c2 == '#')
- {
- FORWARD (1);
- CPP_PUTC (pfile, c2);
- }
- else if (c2 == '%' && PEEKN (1) == ':')
- {
- /* Digraph: "%:" == "#". */
- FORWARD (1);
- CPP_RESERVE (pfile, 2);
- CPP_PUTC_Q (pfile, c2);
- CPP_PUTC_Q (pfile, GETC ());
- }
- else
- return CPP_HASH;
-
+ /* Digraph: "%:" == "#". */
+ FORWARD (1);
+ CPP_RESERVE (pfile, 2);
+ CPP_PUTC_Q (pfile, c2);
+ CPP_PUTC_Q (pfile, GETC ());
return CPP_PASTE;
}
-
- if (!pfile->only_seen_white)
- return CPP_OTHER;
-
- /* Remove the "#" or "%:" from the token buffer. */
- CPP_ADJUST_WRITTEN (pfile, (c == '#' ? -1 : -2));
- return CPP_DIRECTIVE;
+ else
+ return CPP_HASH;
case '\"':
case '\'':
case CPP_COMMENT:
return token;
- case CPP_DIRECTIVE:
+ case CPP_HASH:
pfile->potential_control_macro = 0;
+ if (!pfile->only_seen_white)
+ return CPP_HASH;
+ /* XXX shouldn't have to do this - remove the hash or %: from
+ the token buffer. */
+ if (CPP_PWRITTEN (pfile)[-1] == '#')
+ CPP_ADJUST_WRITTEN (pfile, -1);
+ else
+ CPP_ADJUST_WRITTEN (pfile, -2);
+
if (_cpp_handle_directive (pfile))
- return CPP_DIRECTIVE;
+ return CPP_DIRECTIVE;
pfile->only_seen_white = 0;
CPP_PUTC (pfile, '#');
- return CPP_OTHER;
+ return CPP_HASH;
case CPP_MACRO:
pfile->potential_control_macro = 0;
goto get_next;
return CPP_HSPACE;
- case CPP_DIRECTIVE:
- /* Don't execute the directive, but don't smash it to OTHER either. */
- CPP_PUTC (pfile, '#');
- return CPP_DIRECTIVE;
-
case CPP_MACRO:
if (! pfile->no_macro_expand
&& maybe_macroexpand (pfile, old_written))
U_CHAR *tmp;
init_chartab ();
- init_token_list (pfile, &pfile->directbuf, 0);
+ _cpp_init_toklist (&pfile->directbuf);
/* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. */
}
}
-void
-cpp_free_token_list (list)
- cpp_toklist *list;
-{
- if (list->comments)
- free (list->comments);
- free (list->tokens - 1); /* Backup over dummy token. */
- free (list->namebuf);
- free (list);
-}
-
void
init_trigraph_map ()
{
break;
}
/* Is this the beginning of a header name? */
- if (list->dir_flags & SYNTAX_INCLUDE)
+ if (list->flags & SYNTAX_INCLUDE)
{
c = '>'; /* Terminator. */
cur_token->type = CPP_HEADER_NAME;
invalid directives in assembly source, we don't know where the
comments are, and # may introduce assembler pseudo-ops. */
- if (IS_DIRECTIVE (list) && list->dir_handler == 0
+ if (IS_DIRECTIVE (list) && list->dirno == -1
&& list->tokens[1].type != CPP_VSPACE
&& !CPP_OPTION (pfile, lang_asm))
cpp_error_with_line (pfile, list->line, list->tokens[1].col,
_cpp_lex_file (pfile)
cpp_reader* pfile;
{
- int recycle;
cpp_toklist* list;
init_trigraph_map ();
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
+ _cpp_init_toklist (list);
- for (recycle = 0; ;)
+ for (;;)
{
- init_token_list (pfile, list, recycle);
- recycle = 1;
-
_cpp_lex_line (pfile, list);
if (list->tokens[0].type == CPP_EOF)
break;
- if (list->dir_handler)
- {
- if (list->dir_handler (pfile))
- {
- list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
- recycle = 0;
- }
- }
+#if 0
+ if (list->dirno)
+ _cpp_handle_directive (pfile, list);
else
+#endif
_cpp_output_list (pfile, list);
+ _cpp_clear_toklist (list);
}
}
size_t len = token->val.name.len;
unsigned int i;
- list->dir_handler = 0;
- list->dir_flags = 0;
+ list->dirno = -1;
+ list->flags &= ~SYNTAX_INCLUDE;
for (i = 0; i < N_DIRECTIVES; i++)
if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len))
{
- list->dir_handler = dtable[i].func;
- list->dir_flags = dtable[i].flags;
+ list->dirno = i;
+ if (dtable[i].flags & SYNTAX_INCLUDE)
+ list->flags |= SYNTAX_INCLUDE;
break;
}
}
&& CPP_BUFFER (pfile)->ihash
&& ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer");
- do_line (pfile);
- return 1;
+ i = T_LINE;
+ goto process_directive;
}
/* If we are rescanning preprocessed input, don't obey any directives
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
+ process_directive:
/* Some directives (e.g. #if) may return a request to execute
another directive handler immediately. No directive ever
requests that #define be executed immediately, so it is safe for
cpp_toklist *list = &pfile->directbuf;
pfile->no_macro_expand++;
- pfile->parsing_define_directive++;
CPP_OPTION (pfile, discard_comments)++;
- _cpp_scan_line (pfile, list);
+ _cpp_scan_until (pfile, list, CPP_VSPACE);
- /* First token on the line must be a NAME. There must be at least
- one token (the VSPACE at the end). */
- if (TOK_TYPE (list, 0) != CPP_NAME)
+ /* First token on the line must be a NAME. There may not be any
+ tokens in the list (if we had #define all by itself on a line). */
+ if (list->tokens_used == 0
+ || TOK_TYPE (list, 0) != CPP_NAME)
{
cpp_error_with_line (pfile, list->line, TOK_COL (list, 0),
"#define must be followed by an identifier");
out:
pfile->no_macro_expand--;
- pfile->parsing_define_directive--;
CPP_OPTION (pfile, discard_comments)--;
return 0;
}
do_if (pfile)
cpp_reader *pfile;
{
- U_CHAR *control_macro = detect_if_not_defined (pfile);
- int value = _cpp_parse_expr (pfile);
+ U_CHAR *control_macro;
+ int value;
+ int save_only_seen_white = pfile->only_seen_white;
+
+ control_macro = detect_if_not_defined (pfile);
+
+ pfile->only_seen_white = 0;
+ value = _cpp_parse_expr (pfile);
+ pfile->only_seen_white = save_only_seen_white;
+
return conditional_skip (pfile, value == 0, T_IF, control_macro);
}
token = _cpp_get_directive_token (pfile);
- if (token == CPP_DIRECTIVE)
+ if (token == CPP_HASH)
{
ret = consider_directive_while_skipping (pfile, save_if_stack);
if (ret)
pfile->if_stack = ifs;
}
+#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
+#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0)
+#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0)
static int
do_assert (pfile)
cpp_reader *pfile;
{
long old_written;
U_CHAR *sym;
- int ret;
- HASHNODE *base, *this;
- size_t blen, tlen;
+ size_t len;
+ HASHNODE *hp;
+ struct predicate *pred = 0;
+ enum cpp_ttype type;
- old_written = CPP_WRITTEN (pfile); /* remember where it starts */
- ret = _cpp_parse_assertion (pfile);
- if (ret == 0)
- goto error;
- else if (ret == 1)
- {
- cpp_error (pfile, "missing token-sequence in #assert");
- goto error;
- }
- tlen = CPP_WRITTEN (pfile) - old_written;
+ old_written = CPP_WRITTEN (pfile);
+ pfile->no_macro_expand++;
+
+ CPP_PUTC (pfile, '#'); /* force token out of macro namespace */
+ type = _cpp_get_directive_token (pfile);
+ if (type == CPP_VSPACE)
+ ERROR ("#assert without predicate");
+ else if (type != CPP_NAME)
+ ERROR ("assertion predicate is not an identifier");
- if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
- {
- cpp_error (pfile, "junk at end of #assert");
- goto error;
- }
sym = pfile->token_buffer + old_written;
+ len = CPP_WRITTEN (pfile) - old_written;
+ hp = _cpp_lookup (pfile, sym, len);
+
+ if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN)
+ ERROR ("missing token-sequence in #assert");
+
+ pred = (struct predicate *) xmalloc (sizeof (struct predicate));
+ _cpp_init_toklist (&pred->answer);
+
+ if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN)
+ != CPP_CLOSE_PAREN)
+ ERROR ("missing close paren in #assert");
- this = _cpp_lookup (pfile, sym, tlen);
- if (this->type == T_ASSERT)
+ if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
+ ICE ("impossible token, expecting ) in do_assert");
+
+ if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
+ ERROR ("junk at end of #assert");
+
+ if (hp->type == T_ASSERTION)
{
- cpp_warning (pfile, "%s re-asserted", sym);
- goto error;
+ /* Check for reassertion. */
+ const struct predicate *old;
+
+ for (old = hp->value.pred; old; old = old->next)
+ if (_cpp_equiv_toklists (&pred->answer, &old->answer))
+ /* We used to warn about this, but SVR4 cc doesn't, so let's
+ match that (also consistent with #define). goto error will
+ clean up. */
+ goto error;
+ pred->next = hp->value.pred;
}
-
- blen = ustrchr (sym, '(') - sym;
- base = _cpp_lookup (pfile, sym, blen);
- if (base->type == T_VOID)
+ else
{
- base->type = T_ASSERT;
- base->value.aschain = 0;
+ hp->type = T_ASSERTION;
+ pred->next = 0;
}
-
- this->type = T_ASSERT;
- this->value.aschain = base->value.aschain;
- base->value.aschain = this;
+
+ _cpp_squeeze_toklist (&pred->answer);
+ hp->value.pred = pred;
+ pfile->no_macro_expand--;
+ CPP_SET_WRITTEN (pfile, old_written);
+ return 0;
error:
_cpp_skip_rest_of_line (pfile);
+ pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
+ if (pred)
+ {
+ _cpp_free_toklist (&pred->answer);
+ free (pred);
+ }
return 0;
}
do_unassert (pfile)
cpp_reader *pfile;
{
- int ret;
long old_written;
U_CHAR *sym;
- long baselen, thislen;
- HASHNODE *base, *this, *next;
+ size_t len;
+ HASHNODE *hp;
+ struct predicate *pred = 0;
+ enum cpp_ttype type;
old_written = CPP_WRITTEN (pfile);
- ret = _cpp_parse_assertion (pfile);
- if (ret == 0)
- goto out;
- thislen = CPP_WRITTEN (pfile) - old_written;
+ pfile->no_macro_expand++;
- if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
+ CPP_PUTC (pfile, '#'); /* force token out of macro namespace */
+ if (_cpp_get_directive_token (pfile) != CPP_NAME)
+ ERROR ("#unassert must be followed by an identifier");
+
+ sym = pfile->token_buffer + old_written;
+ len = CPP_WRITTEN (pfile) - old_written;
+ hp = _cpp_lookup (pfile, sym, len);
+
+ type = _cpp_get_directive_token (pfile);
+ if (type == CPP_OPEN_PAREN)
{
- cpp_error (pfile, "junk at end of #unassert");
- goto out;
+ pred = (struct predicate *) xmalloc (sizeof (struct predicate));
+ _cpp_init_toklist (&pred->answer);
+
+ if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN)
+ != CPP_CLOSE_PAREN)
+ ERROR ("missing close paren in #unassert");
+
+ if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
+ ICE ("impossible token, expecting ) in do_unassert");
+
+ type = _cpp_get_directive_token (pfile);
}
- sym = pfile->token_buffer + old_written;
- CPP_SET_WRITTEN (pfile, old_written);
- if (ret == 1)
+ if (type != CPP_VSPACE)
+ ERROR ("junk at end of #unassert");
+
+ if (hp->type != T_ASSERTION)
+ /* Not an error to #unassert something that isn't asserted.
+ goto error to clean up. */
+ goto error;
+
+ if (pred)
{
- base = _cpp_lookup (pfile, sym, thislen);
- if (base->type == T_VOID)
- goto out; /* It isn't an error to #undef what isn't #defined,
- so it isn't an error to #unassert what isn't
- #asserted either. */
-
- for (this = base->value.aschain; this; this = next)
- {
- next = this->value.aschain;
- this->value.aschain = NULL;
- this->type = T_VOID;
- }
- base->value.aschain = NULL;
- base->type = T_VOID;
+ /* Find this specific answer and remove it. */
+ struct predicate *o, *p;
+
+ for (p = NULL, o = hp->value.pred; o; p = o, o = o->next)
+ if (_cpp_equiv_toklists (&pred->answer, &o->answer))
+ {
+ if (p)
+ p->next = o->next;
+ else
+ hp->value.pred = o->next;
+
+ _cpp_free_toklist (&o->answer);
+ free (o);
+ break;
+ }
}
else
{
- baselen = ustrchr (sym, '(') - sym;
- base = _cpp_lookup (pfile, sym, baselen);
- if (base->type == T_VOID) goto out;
- this = _cpp_lookup (pfile, sym, thislen);
- if (this->type == T_VOID) goto out;
-
- next = base;
- while (next->value.aschain != this)
- next = next->value.aschain;
-
- next->value.aschain = this->value.aschain;
- this->value.aschain = NULL;
- this->type = T_VOID;
-
- if (base->value.aschain == NULL)
- /* Last answer for this predicate deleted. */
- base->type = T_VOID;
+ struct predicate *o, *p;
+ for (o = hp->value.pred; o; o = p)
+ {
+ p = o->next;
+ _cpp_free_toklist ((cpp_toklist *) &o->answer);
+ free (o);
+ }
+ hp->value.pred = NULL;
}
- return 0;
- out:
+ if (hp->value.pred == NULL)
+ hp->type = T_VOID; /* Last answer for this predicate deleted. */
+
+ error:
_cpp_skip_rest_of_line (pfile);
+ pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
+ if (pred)
+ {
+ _cpp_free_toklist (&pred->answer);
+ free (pred);
+ }
return 0;
}
T(CPP_VSPACE, "\n") /* End of line. */ \
N(CPP_EOF, 0) /* End of file. */ \
N(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \
- N(CPP_ASSERTION, 0) /* (...) in #assert */ \
\
/* Obsolete - will be removed when no code uses them still. */ \
N(CPP_HSPACE, 0) /* Horizontal white space. */ \
} val;
};
+/* General flags. */
+#define LIST_OFFSET (1 << 0)
+
/* Directive flags. */
#define SYNTAX_INCLUDE (1 << 8)
unsigned int comments_used; /* comment tokens used. */
unsigned int comments_cap; /* comment token capacity. */
- /* Only used if tokens[0].type == CPP_DIRECTIVE. This is the
- handler to call after lexing the rest of this line. The flags
- indicate whether the rest of the line gets special treatment
- during lexing (#include, #if, #assert, #unassert). */
- directive_handler dir_handler;
- unsigned short dir_flags;
+ /* The handler to call after lexing the rest of this line.
+ -1 for none */
+ short dirno;
+
+ /* Per-list flags, see above */
+ unsigned short flags;
};
struct cpp_buffer
/* If true, characters between '<' and '>' are a single (string) token. */
unsigned char parsing_include_directive;
- /* If true, # introduces an assertion (see do_assert) */
- unsigned char parsing_if_directive;
-
- /* If true, # and ## are the STRINGIZE and TOKPASTE operators */
- unsigned char parsing_define_directive;
-
/* True if escape sequences (as described for has_escapes in
parse_buffer) should be emitted. */
unsigned char output_escapes;