cppexp.c (parse_assertion): New.

* 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
This commit is contained in:
Zack Weinberg 2000-05-18 15:55:46 +00:00 committed by Zack Weinberg
parent 7021bb50d4
commit 15dad1d908
7 changed files with 555 additions and 345 deletions

View File

@ -1,3 +1,50 @@
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

View File

@ -82,6 +82,7 @@ static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *,
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));
@ -110,6 +111,15 @@ struct operation
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. */
@ -379,6 +389,81 @@ parse_defined (pfile)
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;
@ -451,11 +536,8 @@ lex (pfile, skip_evaluation)
(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. */
@ -734,15 +816,6 @@ be handled with operator-specific code. */
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. */
@ -770,7 +843,6 @@ _cpp_parse_expr (pfile)
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 '('. */
@ -796,11 +868,6 @@ _cpp_parse_expr (pfile)
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");
@ -1094,7 +1161,6 @@ _cpp_parse_expr (pfile)
/* 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;
}

View File

@ -480,12 +480,6 @@ collect_objlike_expansion (pfile, list)
{
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. */
@ -506,7 +500,6 @@ collect_objlike_expansion (pfile, list)
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");
@ -568,12 +561,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement)
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
@ -677,7 +664,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement)
}
last_token = ARG;
}
done:
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
@ -759,8 +745,8 @@ collect_params (pfile, list, arglist)
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:
@ -783,9 +769,8 @@ collect_params (pfile, list, arglist)
}
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:
@ -892,9 +877,9 @@ _cpp_create_definition (pfile, list, hp)
#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)))

View File

@ -49,7 +49,8 @@ enum node_type
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;
@ -64,12 +65,19 @@ struct 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
{
@ -250,7 +258,20 @@ extern enum cpp_ttype _cpp_get_directive_token
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 *));

View File

@ -55,7 +55,6 @@ static void bump_column PARAMS ((cpp_printer *, unsigned int,
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));
@ -491,7 +490,7 @@ cpp_scan_buffer (pfile, print)
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))
@ -548,63 +547,212 @@ expand_token_space (list)
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 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);
/* 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;
}
/* 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 */
}
/* Scan an entire line and create a token list for it. Does not
macro-expand or execute directives. */
/* Free a token list. Does not free the list itself, which may be
embedded in a larger structure. */
void
_cpp_scan_line (pfile, list)
_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);
}
/* 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_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;
@ -636,14 +784,14 @@ _cpp_scan_line (pfile, list)
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)
{
@ -656,12 +804,14 @@ _cpp_scan_line (pfile, list)
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. */
@ -1060,85 +1210,6 @@ parse_string (pfile, c)
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. */
@ -1176,11 +1247,7 @@ _cpp_lex_token (pfile)
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);
@ -1191,42 +1258,24 @@ _cpp_lex_token (pfile)
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;
}
if (pfile->parsing_define_directive)
{
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;
FORWARD (1);
CPP_PUTC (pfile, c2);
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 if (c2 == '%' && PEEKN (1) == ':')
{
/* Digraph: "%:" == "#". */
FORWARD (1);
CPP_RESERVE (pfile, 2);
CPP_PUTC_Q (pfile, c2);
CPP_PUTC_Q (pfile, GETC ());
return CPP_PASTE;
}
else
return CPP_HASH;
case '\"':
case '\'':
@ -1697,13 +1746,22 @@ cpp_get_token (pfile)
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;
@ -1777,11 +1835,6 @@ _cpp_get_directive_token (pfile)
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))
@ -2134,7 +2187,7 @@ _cpp_init_input_buffer (pfile)
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. */
@ -2294,17 +2347,6 @@ expand_comment_space (list)
}
}
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 ()
{
@ -3175,7 +3217,7 @@ _cpp_lex_line (pfile, list)
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;
@ -3304,7 +3346,7 @@ _cpp_lex_line (pfile, list)
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,
@ -3385,31 +3427,25 @@ void
_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);
}
}

View File

@ -160,14 +160,15 @@ _cpp_check_directive (list, token)
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;
}
}
@ -219,8 +220,8 @@ _cpp_handle_directive (pfile)
&& 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
@ -300,6 +301,7 @@ _cpp_handle_directive (pfile)
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
@ -343,14 +345,14 @@ do_define (pfile)
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");
@ -389,7 +391,6 @@ do_define (pfile)
out:
pfile->no_macro_expand--;
pfile->parsing_define_directive--;
CPP_OPTION (pfile, discard_comments)--;
return 0;
}
@ -1097,8 +1098,16 @@ static int
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);
}
@ -1383,7 +1392,7 @@ skip_if_group (pfile)
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)
@ -1509,56 +1518,84 @@ _cpp_unwind_if_stack (pfile, pbuf)
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");
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");
if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
ICE ("impossible token, expecting ) in do_assert");
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
{
cpp_error (pfile, "junk at end of #assert");
goto error;
}
sym = pfile->token_buffer + old_written;
ERROR ("junk at end of #assert");
this = _cpp_lookup (pfile, sym, tlen);
if (this->type == T_ASSERT)
if (hp->type == T_ASSERTION)
{
cpp_warning (pfile, "%s re-asserted", sym);
goto error;
}
blen = ustrchr (sym, '(') - sym;
base = _cpp_lookup (pfile, sym, blen);
if (base->type == T_VOID)
{
base->type = T_ASSERT;
base->value.aschain = 0;
}
/* Check for reassertion. */
const struct predicate *old;
this->type = T_ASSERT;
this->value.aschain = base->value.aschain;
base->value.aschain = this;
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;
}
else
{
hp->type = T_ASSERTION;
pred->next = 0;
}
_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;
}
@ -1566,68 +1603,90 @@ static int
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++;
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");
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
{
cpp_error (pfile, "junk at end of #unassert");
goto out;
}
sym = pfile->token_buffer + old_written;
CPP_SET_WRITTEN (pfile, old_written);
len = CPP_WRITTEN (pfile) - old_written;
hp = _cpp_lookup (pfile, sym, len);
if (ret == 1)
type = _cpp_get_directive_token (pfile);
if (type == CPP_OPEN_PAREN)
{
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. */
pred = (struct predicate *) xmalloc (sizeof (struct predicate));
_cpp_init_toklist (&pred->answer);
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;
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);
}
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)
{
/* 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;
}

View File

@ -124,7 +124,6 @@ typedef struct cpp_name cpp_name;
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. */ \
@ -189,6 +188,9 @@ struct cpp_token
} val;
};
/* General flags. */
#define LIST_OFFSET (1 << 0)
/* Directive flags. */
#define SYNTAX_INCLUDE (1 << 8)
@ -211,12 +213,12 @@ struct cpp_toklist
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
@ -544,12 +546,6 @@ struct cpp_reader
/* 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;