Commit 15dad1d9 by Zack Weinberg Committed by Zack Weinberg

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
parent 7021bb50
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> 2000-05-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* fixinc/inclhack.def (broken_cabs): Update fix to handle comments * fixinc/inclhack.def (broken_cabs): Update fix to handle comments
......
...@@ -82,6 +82,7 @@ static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, ...@@ -82,6 +82,7 @@ static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *,
static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *,
U_CHAR *)); U_CHAR *));
static struct operation parse_defined PARAMS ((cpp_reader *)); 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 **, static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **,
HOST_WIDEST_INT)); HOST_WIDEST_INT));
static struct operation lex PARAMS ((cpp_reader *, int)); static struct operation lex PARAMS ((cpp_reader *, int));
...@@ -110,6 +111,15 @@ struct operation ...@@ -110,6 +111,15 @@ struct operation
HOST_WIDEST_INT value; /* The value logically "right" of op. */ 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 /* Parse and convert an integer for #if. Accepts decimal, hex, or octal
with or without size suffixes. */ with or without size suffixes. */
...@@ -379,6 +389,81 @@ parse_defined (pfile) ...@@ -379,6 +389,81 @@ parse_defined (pfile)
return op; 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 struct token
{ {
const char *operator; const char *operator;
...@@ -451,11 +536,8 @@ lex (pfile, skip_evaluation) ...@@ -451,11 +536,8 @@ lex (pfile, skip_evaluation)
(int) (tok_end - tok_start), tok_start); (int) (tok_end - tok_start), tok_start);
return op; return op;
case CPP_ASSERTION: case CPP_HASH:
op.op = INT; return parse_assertion (pfile);
op.unsignedp = 0;
op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
return op;
case CPP_OTHER: case CPP_OTHER:
/* See if it is a special token of length 2. */ /* See if it is a special token of length 2. */
...@@ -734,15 +816,6 @@ be handled with operator-specific code. */ ...@@ -734,15 +816,6 @@ be handled with operator-specific code. */
top->value = v1 OP v2; \ top->value = v1 OP v2; \
top->unsignedp = unsigned1 | unsigned2; 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. /* Parse and evaluate a C expression, reading from PFILE.
Returns the truth value of the expression. */ Returns the truth value of the expression. */
...@@ -770,7 +843,6 @@ _cpp_parse_expr (pfile) ...@@ -770,7 +843,6 @@ _cpp_parse_expr (pfile)
int result; int result;
char buff[5]; char buff[5];
pfile->parsing_if_directive++;
/* We've finished when we try to reduce this. */ /* We've finished when we try to reduce this. */
top->op = FINISHED; top->op = FINISHED;
/* Nifty way to catch missing '('. */ /* Nifty way to catch missing '('. */
...@@ -796,11 +868,6 @@ _cpp_parse_expr (pfile) ...@@ -796,11 +868,6 @@ _cpp_parse_expr (pfile)
CPP_ICE ("lex returns a NAME"); CPP_ICE ("lex returns a NAME");
case ERROR: case ERROR:
goto syntax_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: default:
SYNTAX_ERROR ("invalid character in #if"); SYNTAX_ERROR ("invalid character in #if");
...@@ -1094,7 +1161,6 @@ _cpp_parse_expr (pfile) ...@@ -1094,7 +1161,6 @@ _cpp_parse_expr (pfile)
/* Free dynamic stack if we allocated one. */ /* Free dynamic stack if we allocated one. */
if (stack != init_stack) if (stack != init_stack)
free (stack); free (stack);
pfile->parsing_if_directive--;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
return result; return result;
} }
...@@ -480,12 +480,6 @@ collect_objlike_expansion (pfile, list) ...@@ -480,12 +480,6 @@ collect_objlike_expansion (pfile, list)
{ {
switch (TOK_TYPE (list, i)) 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: case CPP_PASTE:
/* ## is not special if it appears right after another ##; /* ## is not special if it appears right after another ##;
nor is it special if -traditional. */ nor is it special if -traditional. */
...@@ -506,7 +500,6 @@ collect_objlike_expansion (pfile, list) ...@@ -506,7 +500,6 @@ collect_objlike_expansion (pfile, list)
CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i)); CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i));
last_was_paste = 0; last_was_paste = 0;
} }
done:
if (last_was_paste) if (last_was_paste)
cpp_error (pfile, "`##' at end of macro definition"); cpp_error (pfile, "`##' at end of macro definition");
...@@ -568,12 +561,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement) ...@@ -568,12 +561,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement)
len = TOK_LEN (list, i); len = TOK_LEN (list, i);
switch (token) switch (token)
{ {
case CPP_EOF:
cpp_ice (pfile, "EOF in collect_expansion");
/* fall through */
case CPP_VSPACE:
goto done;
case CPP_HASH: case CPP_HASH:
/* # is special in function-like macros with no args. /* # is special in function-like macros with no args.
(6.10.3.2 para 1.) However, it is not special after (6.10.3.2 para 1.) However, it is not special after
...@@ -677,7 +664,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement) ...@@ -677,7 +664,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement)
} }
last_token = ARG; last_token = ARG;
} }
done:
if (last_token == STRIZE) if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name"); cpp_error (pfile, "`#' is not followed by a macro argument name");
...@@ -759,8 +745,8 @@ collect_params (pfile, list, arglist) ...@@ -759,8 +745,8 @@ collect_params (pfile, list, arglist)
case CPP_CLOSE_PAREN: case CPP_CLOSE_PAREN:
goto scanned; goto scanned;
case CPP_VSPACE: case CPP_VSPACE:
cpp_error_with_line (pfile, list->line, TOK_COL (list, i), case CPP_EOF:
"missing right paren in macro argument list"); cpp_ice (pfile, "impossible token in macro argument list");
return 0; return 0;
default: default:
...@@ -783,9 +769,8 @@ collect_params (pfile, list, arglist) ...@@ -783,9 +769,8 @@ collect_params (pfile, list, arglist)
} }
goto scanned; goto scanned;
} }
cpp_error_with_line (pfile, list->line, TOK_COL (list, i-1),
cpp_ice (pfile, "collect_params: unreachable - i=%d, ntokens=%d, type=%d", "missing right paren in macro argument list");
i, list->tokens_used, TOK_TYPE (list, i-1));
return 0; return 0;
scanned: scanned:
...@@ -892,9 +877,9 @@ _cpp_create_definition (pfile, list, hp) ...@@ -892,9 +877,9 @@ _cpp_create_definition (pfile, list, hp)
#define FUNC(a, b, ...) // nothing #define FUNC(a, b, ...) // nothing
#define FUNC(a, b, c) FUNC(a, b, c) */ #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. */ 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) && TOK_LEN (list, 0) == TOK_LEN (list, 1)
&& !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1), && !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1),
TOK_LEN (list, 0))) TOK_LEN (list, 0)))
......
...@@ -49,7 +49,8 @@ enum node_type ...@@ -49,7 +49,8 @@ enum node_type
T_MACRO, /* object-like macro */ T_MACRO, /* object-like macro */
T_FMACRO, /* function-like macro */ T_FMACRO, /* function-like macro */
T_IDENTITY, /* macro defined to itself */ 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; typedef struct hashnode HASHNODE;
...@@ -64,12 +65,19 @@ struct hashnode ...@@ -64,12 +65,19 @@ struct hashnode
const U_CHAR *cpval; /* some predefined macros */ const U_CHAR *cpval; /* some predefined macros */
const struct object_defn *odefn; /* #define foo bar */ const struct object_defn *odefn; /* #define foo bar */
const struct funct_defn *fdefn; /* #define foo(x) bar(x) */ const struct funct_defn *fdefn; /* #define foo(x) bar(x) */
struct hashnode *aschain; /* #assert */ struct predicate *pred; /* #assert */
} value; } value;
const U_CHAR name[1]; /* name[length] */ 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. */ /* List of directories to look for include files in. */
struct file_name_list struct file_name_list
{ {
...@@ -250,7 +258,20 @@ extern enum cpp_ttype _cpp_get_directive_token ...@@ -250,7 +258,20 @@ extern enum cpp_ttype _cpp_get_directive_token
PARAMS ((cpp_reader *)); PARAMS ((cpp_reader *));
extern enum cpp_ttype _cpp_get_define_token extern enum cpp_ttype _cpp_get_define_token
PARAMS ((cpp_reader *)); 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 */ /* In cpplib.c */
extern int _cpp_handle_directive PARAMS ((cpp_reader *)); extern int _cpp_handle_directive PARAMS ((cpp_reader *));
......
...@@ -55,7 +55,6 @@ static void bump_column PARAMS ((cpp_printer *, unsigned int, ...@@ -55,7 +55,6 @@ static void bump_column PARAMS ((cpp_printer *, unsigned int,
unsigned int)); unsigned int));
static void expand_name_space PARAMS ((cpp_toklist *, unsigned int)); static void expand_name_space PARAMS ((cpp_toklist *, unsigned int));
static void expand_token_space PARAMS ((cpp_toklist *)); 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 *, static void pedantic_whitespace PARAMS ((cpp_reader *, U_CHAR *,
unsigned int)); unsigned int));
...@@ -491,7 +490,7 @@ cpp_scan_buffer (pfile, print) ...@@ -491,7 +490,7 @@ cpp_scan_buffer (pfile, print)
for (;;) for (;;)
{ {
token = cpp_get_token (pfile); 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 */ /* XXX Temporary kluge - force flush after #include only */
|| (token == CPP_DIRECTIVE || (token == CPP_DIRECTIVE
&& CPP_BUFFER (pfile)->nominal_fname != print->last_fname)) && CPP_BUFFER (pfile)->nominal_fname != print->last_fname))
...@@ -548,63 +547,212 @@ expand_token_space (list) ...@@ -548,63 +547,212 @@ expand_token_space (list)
cpp_toklist *list; cpp_toklist *list;
{ {
list->tokens_cap *= 2; list->tokens_cap *= 2;
if (list->flags & LIST_OFFSET)
list->tokens--;
list->tokens = (cpp_token *) list->tokens = (cpp_token *)
xrealloc (list->tokens - 1, (list->tokens_cap + 1) * sizeof (cpp_token)); xrealloc (list->tokens, (list->tokens_cap + 1) * sizeof (cpp_token));
list->tokens++; /* Skip the dummy. */ if (list->flags & LIST_OFFSET)
list->tokens++; /* Skip the dummy. */
} }
/* Initialize a token list. We allocate an extra token in front of /* 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 the token list, as this allows us to always peek at the previous
token without worrying about underflowing the list. */ token without worrying about underflowing the list. */
static void void
init_token_list (pfile, list, recycle) _cpp_init_toklist (list)
cpp_reader *pfile;
cpp_toklist *list; cpp_toklist *list;
int recycle;
{ {
/* Recycling a used list saves 3 free-malloc pairs. */ /* Initialize token space. Put a dummy token before the start
if (!recycle) that will fail matches. */
{ list->tokens_cap = 256; /* 4K's worth. */
/* Initialize token space. Put a dummy token before the start list->tokens = (cpp_token *)
that will fail matches. */ xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
list->tokens_cap = 256; /* 4K's worth. */ list->tokens[0].type = CPP_EOF;
list->tokens = (cpp_token *) list->tokens++;
xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
list->tokens[0].type = CPP_EOF; /* Initialize name space. */
list->tokens++; list->name_cap = 1024;
list->namebuf = (unsigned char *) xmalloc (list->name_cap);
/* Initialize name space. */
list->name_cap = 1024; /* Only create a comment space on demand. */
list->namebuf = (unsigned char *) xmalloc (list->name_cap); list->comments_cap = 0;
list->comments = 0;
/* Only create a comment space on demand. */
list->comments_cap = 0; list->flags = LIST_OFFSET;
list->comments = 0; _cpp_clear_toklist (list);
} }
/* Clear a token list. */
void
_cpp_clear_toklist (list)
cpp_toklist *list;
{
list->tokens_used = 0; list->tokens_used = 0;
list->name_used = 0; list->name_used = 0;
list->comments_used = 0; list->comments_used = 0;
if (pfile->buffer) list->dirno = -1;
list->line = pfile->buffer->lineno; list->flags &= LIST_OFFSET; /* clear all but that one */
list->dir_handler = 0; }
list->dir_flags = 0;
/* 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 /* Slice a token list: copy the sublist [START, FINISH) into COPY.
macro-expand or execute directives. */ 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 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_reader *pfile;
cpp_toklist *list; cpp_toklist *list;
enum cpp_ttype stop;
{ {
int i, col; int i, col;
long written, len; long written, len;
enum cpp_ttype type; enum cpp_ttype type;
int space_before; 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); written = CPP_WRITTEN (pfile);
i = 0; i = 0;
...@@ -636,14 +784,14 @@ _cpp_scan_line (pfile, list) ...@@ -636,14 +784,14 @@ _cpp_scan_line (pfile, list)
if (type == CPP_MACRO) if (type == CPP_MACRO)
type = CPP_NAME; type = CPP_NAME;
if (type == CPP_VSPACE || type == stop)
break;
list->tokens_used++; list->tokens_used++;
TOK_TYPE (list, i) = type; TOK_TYPE (list, i) = type;
TOK_COL (list, i) = col; TOK_COL (list, i) = col;
TOK_FLAGS (list, i) = space_before ? PREV_WHITESPACE : 0; TOK_FLAGS (list, i) = space_before ? PREV_WHITESPACE : 0;
if (type == CPP_VSPACE)
break;
TOK_LEN (list, i) = len; TOK_LEN (list, i) = len;
if (token_spellings[type].type > SPELL_NONE) if (token_spellings[type].type > SPELL_NONE)
{ {
...@@ -656,12 +804,14 @@ _cpp_scan_line (pfile, list) ...@@ -656,12 +804,14 @@ _cpp_scan_line (pfile, list)
i++; i++;
space_before = 0; 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); 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 /* Skip a C-style block comment. We know it's a comment, and point is
at the second character of the starter. */ at the second character of the starter. */
...@@ -1060,85 +1210,6 @@ parse_string (pfile, c) ...@@ -1060,85 +1210,6 @@ parse_string (pfile, c)
CPP_PUTC_Q (pfile, *start); 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. /* Get the next token, and add it to the text in pfile->token_buffer.
Return the kind of token we got. */ Return the kind of token we got. */
...@@ -1176,11 +1247,7 @@ _cpp_lex_token (pfile) ...@@ -1176,11 +1247,7 @@ _cpp_lex_token (pfile)
if (!CPP_OPTION (pfile, discard_comments)) if (!CPP_OPTION (pfile, discard_comments))
return CPP_COMMENT; return CPP_COMMENT;
else if (CPP_TRADITIONAL (pfile)) else if (CPP_TRADITIONAL (pfile))
{ goto get_next;
if (pfile->parsing_define_directive)
return CPP_COMMENT;
goto get_next;
}
else else
{ {
CPP_PUTC (pfile, c); CPP_PUTC (pfile, c);
...@@ -1191,42 +1258,24 @@ _cpp_lex_token (pfile) ...@@ -1191,42 +1258,24 @@ _cpp_lex_token (pfile)
CPP_PUTC (pfile, c); CPP_PUTC (pfile, c);
hash: hash:
if (pfile->parsing_if_directive) c2 = PEEKC ();
if (c2 == '#')
{ {
CPP_ADJUST_WRITTEN (pfile, -1); FORWARD (1);
if (_cpp_parse_assertion (pfile)) CPP_PUTC (pfile, c2);
return CPP_ASSERTION; return CPP_PASTE;
return CPP_OTHER;
} }
else if (c2 == '%' && PEEKN (1) == ':')
if (pfile->parsing_define_directive)
{ {
c2 = PEEKC (); /* Digraph: "%:" == "#". */
if (c2 == '#') FORWARD (1);
{ CPP_RESERVE (pfile, 2);
FORWARD (1); CPP_PUTC_Q (pfile, c2);
CPP_PUTC (pfile, c2); CPP_PUTC_Q (pfile, GETC ());
}
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;
return CPP_PASTE; return CPP_PASTE;
} }
else
if (!pfile->only_seen_white) return CPP_HASH;
return CPP_OTHER;
/* Remove the "#" or "%:" from the token buffer. */
CPP_ADJUST_WRITTEN (pfile, (c == '#' ? -1 : -2));
return CPP_DIRECTIVE;
case '\"': case '\"':
case '\'': case '\'':
...@@ -1697,13 +1746,22 @@ cpp_get_token (pfile) ...@@ -1697,13 +1746,22 @@ cpp_get_token (pfile)
case CPP_COMMENT: case CPP_COMMENT:
return token; return token;
case CPP_DIRECTIVE: case CPP_HASH:
pfile->potential_control_macro = 0; 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)) if (_cpp_handle_directive (pfile))
return CPP_DIRECTIVE; return CPP_DIRECTIVE;
pfile->only_seen_white = 0; pfile->only_seen_white = 0;
CPP_PUTC (pfile, '#'); CPP_PUTC (pfile, '#');
return CPP_OTHER; return CPP_HASH;
case CPP_MACRO: case CPP_MACRO:
pfile->potential_control_macro = 0; pfile->potential_control_macro = 0;
...@@ -1777,11 +1835,6 @@ _cpp_get_directive_token (pfile) ...@@ -1777,11 +1835,6 @@ _cpp_get_directive_token (pfile)
goto get_next; goto get_next;
return CPP_HSPACE; 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: case CPP_MACRO:
if (! pfile->no_macro_expand if (! pfile->no_macro_expand
&& maybe_macroexpand (pfile, old_written)) && maybe_macroexpand (pfile, old_written))
...@@ -2134,7 +2187,7 @@ _cpp_init_input_buffer (pfile) ...@@ -2134,7 +2187,7 @@ _cpp_init_input_buffer (pfile)
U_CHAR *tmp; U_CHAR *tmp;
init_chartab (); init_chartab ();
init_token_list (pfile, &pfile->directbuf, 0); _cpp_init_toklist (&pfile->directbuf);
/* Determine the appropriate size for the input buffer. Normal C /* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. */ source files are smaller than eight K. */
...@@ -2295,17 +2348,6 @@ expand_comment_space (list) ...@@ -2295,17 +2348,6 @@ expand_comment_space (list)
} }
void 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 () init_trigraph_map ()
{ {
trigraph_map['='] = '#'; trigraph_map['='] = '#';
...@@ -3175,7 +3217,7 @@ _cpp_lex_line (pfile, list) ...@@ -3175,7 +3217,7 @@ _cpp_lex_line (pfile, list)
break; break;
} }
/* Is this the beginning of a header name? */ /* Is this the beginning of a header name? */
if (list->dir_flags & SYNTAX_INCLUDE) if (list->flags & SYNTAX_INCLUDE)
{ {
c = '>'; /* Terminator. */ c = '>'; /* Terminator. */
cur_token->type = CPP_HEADER_NAME; cur_token->type = CPP_HEADER_NAME;
...@@ -3304,7 +3346,7 @@ _cpp_lex_line (pfile, list) ...@@ -3304,7 +3346,7 @@ _cpp_lex_line (pfile, list)
invalid directives in assembly source, we don't know where the invalid directives in assembly source, we don't know where the
comments are, and # may introduce assembler pseudo-ops. */ 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 && list->tokens[1].type != CPP_VSPACE
&& !CPP_OPTION (pfile, lang_asm)) && !CPP_OPTION (pfile, lang_asm))
cpp_error_with_line (pfile, list->line, list->tokens[1].col, cpp_error_with_line (pfile, list->line, list->tokens[1].col,
...@@ -3385,31 +3427,25 @@ void ...@@ -3385,31 +3427,25 @@ void
_cpp_lex_file (pfile) _cpp_lex_file (pfile)
cpp_reader* pfile; cpp_reader* pfile;
{ {
int recycle;
cpp_toklist* list; cpp_toklist* list;
init_trigraph_map (); init_trigraph_map ();
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); 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); _cpp_lex_line (pfile, list);
if (list->tokens[0].type == CPP_EOF) if (list->tokens[0].type == CPP_EOF)
break; break;
if (list->dir_handler) #if 0
{ if (list->dirno)
if (list->dir_handler (pfile)) _cpp_handle_directive (pfile, list);
{
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
recycle = 0;
}
}
else else
#endif
_cpp_output_list (pfile, list); _cpp_output_list (pfile, list);
_cpp_clear_toklist (list);
} }
} }
......
...@@ -160,14 +160,15 @@ _cpp_check_directive (list, token) ...@@ -160,14 +160,15 @@ _cpp_check_directive (list, token)
size_t len = token->val.name.len; size_t len = token->val.name.len;
unsigned int i; unsigned int i;
list->dir_handler = 0; list->dirno = -1;
list->dir_flags = 0; list->flags &= ~SYNTAX_INCLUDE;
for (i = 0; i < N_DIRECTIVES; i++) for (i = 0; i < N_DIRECTIVES; i++)
if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len)) if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len))
{ {
list->dir_handler = dtable[i].func; list->dirno = i;
list->dir_flags = dtable[i].flags; if (dtable[i].flags & SYNTAX_INCLUDE)
list->flags |= SYNTAX_INCLUDE;
break; break;
} }
} }
...@@ -219,8 +220,8 @@ _cpp_handle_directive (pfile) ...@@ -219,8 +220,8 @@ _cpp_handle_directive (pfile)
&& CPP_BUFFER (pfile)->ihash && CPP_BUFFER (pfile)->ihash
&& ! CPP_OPTION (pfile, preprocessed)) && ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer"); cpp_pedwarn (pfile, "# followed by integer");
do_line (pfile); i = T_LINE;
return 1; goto process_directive;
} }
/* If we are rescanning preprocessed input, don't obey any directives /* If we are rescanning preprocessed input, don't obey any directives
...@@ -300,6 +301,7 @@ _cpp_handle_directive (pfile) ...@@ -300,6 +301,7 @@ _cpp_handle_directive (pfile)
pfile->no_macro_expand--; pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
process_directive:
/* Some directives (e.g. #if) may return a request to execute /* Some directives (e.g. #if) may return a request to execute
another directive handler immediately. No directive ever another directive handler immediately. No directive ever
requests that #define be executed immediately, so it is safe for requests that #define be executed immediately, so it is safe for
...@@ -343,14 +345,14 @@ do_define (pfile) ...@@ -343,14 +345,14 @@ do_define (pfile)
cpp_toklist *list = &pfile->directbuf; cpp_toklist *list = &pfile->directbuf;
pfile->no_macro_expand++; pfile->no_macro_expand++;
pfile->parsing_define_directive++;
CPP_OPTION (pfile, discard_comments)++; 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 /* First token on the line must be a NAME. There may not be any
one token (the VSPACE at the end). */ tokens in the list (if we had #define all by itself on a line). */
if (TOK_TYPE (list, 0) != CPP_NAME) if (list->tokens_used == 0
|| TOK_TYPE (list, 0) != CPP_NAME)
{ {
cpp_error_with_line (pfile, list->line, TOK_COL (list, 0), cpp_error_with_line (pfile, list->line, TOK_COL (list, 0),
"#define must be followed by an identifier"); "#define must be followed by an identifier");
...@@ -389,7 +391,6 @@ do_define (pfile) ...@@ -389,7 +391,6 @@ do_define (pfile)
out: out:
pfile->no_macro_expand--; pfile->no_macro_expand--;
pfile->parsing_define_directive--;
CPP_OPTION (pfile, discard_comments)--; CPP_OPTION (pfile, discard_comments)--;
return 0; return 0;
} }
...@@ -1097,8 +1098,16 @@ static int ...@@ -1097,8 +1098,16 @@ static int
do_if (pfile) do_if (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
U_CHAR *control_macro = detect_if_not_defined (pfile); U_CHAR *control_macro;
int value = _cpp_parse_expr (pfile); 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); return conditional_skip (pfile, value == 0, T_IF, control_macro);
} }
...@@ -1383,7 +1392,7 @@ skip_if_group (pfile) ...@@ -1383,7 +1392,7 @@ skip_if_group (pfile)
token = _cpp_get_directive_token (pfile); token = _cpp_get_directive_token (pfile);
if (token == CPP_DIRECTIVE) if (token == CPP_HASH)
{ {
ret = consider_directive_while_skipping (pfile, save_if_stack); ret = consider_directive_while_skipping (pfile, save_if_stack);
if (ret) if (ret)
...@@ -1509,56 +1518,84 @@ _cpp_unwind_if_stack (pfile, pbuf) ...@@ -1509,56 +1518,84 @@ _cpp_unwind_if_stack (pfile, pbuf)
pfile->if_stack = ifs; 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 static int
do_assert (pfile) do_assert (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
long old_written; long old_written;
U_CHAR *sym; U_CHAR *sym;
int ret; size_t len;
HASHNODE *base, *this; HASHNODE *hp;
size_t blen, tlen; struct predicate *pred = 0;
enum cpp_ttype type;
old_written = CPP_WRITTEN (pfile); /* remember where it starts */ old_written = CPP_WRITTEN (pfile);
ret = _cpp_parse_assertion (pfile); pfile->no_macro_expand++;
if (ret == 0)
goto error; CPP_PUTC (pfile, '#'); /* force token out of macro namespace */
else if (ret == 1) type = _cpp_get_directive_token (pfile);
{ if (type == CPP_VSPACE)
cpp_error (pfile, "missing token-sequence in #assert"); ERROR ("#assert without predicate");
goto error; else if (type != CPP_NAME)
} ERROR ("assertion predicate is not an identifier");
tlen = CPP_WRITTEN (pfile) - old_written;
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
{
cpp_error (pfile, "junk at end of #assert");
goto error;
}
sym = pfile->token_buffer + old_written; 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 (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
if (this->type == T_ASSERT) 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); /* Check for reassertion. */
goto error; 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;
} }
else
blen = ustrchr (sym, '(') - sym;
base = _cpp_lookup (pfile, sym, blen);
if (base->type == T_VOID)
{ {
base->type = T_ASSERT; hp->type = T_ASSERTION;
base->value.aschain = 0; pred->next = 0;
} }
this->type = T_ASSERT; _cpp_squeeze_toklist (&pred->answer);
this->value.aschain = base->value.aschain; hp->value.pred = pred;
base->value.aschain = this; pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
return 0;
error: error:
_cpp_skip_rest_of_line (pfile); _cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
if (pred)
{
_cpp_free_toklist (&pred->answer);
free (pred);
}
return 0; return 0;
} }
...@@ -1566,68 +1603,90 @@ static int ...@@ -1566,68 +1603,90 @@ static int
do_unassert (pfile) do_unassert (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int ret;
long old_written; long old_written;
U_CHAR *sym; U_CHAR *sym;
long baselen, thislen; size_t len;
HASHNODE *base, *this, *next; HASHNODE *hp;
struct predicate *pred = 0;
enum cpp_ttype type;
old_written = CPP_WRITTEN (pfile); old_written = CPP_WRITTEN (pfile);
ret = _cpp_parse_assertion (pfile); pfile->no_macro_expand++;
if (ret == 0)
goto out;
thislen = CPP_WRITTEN (pfile) - old_written;
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"); pred = (struct predicate *) xmalloc (sizeof (struct predicate));
goto out; _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); /* Find this specific answer and remove it. */
if (base->type == T_VOID) struct predicate *o, *p;
goto out; /* It isn't an error to #undef what isn't #defined,
so it isn't an error to #unassert what isn't for (p = NULL, o = hp->value.pred; o; p = o, o = o->next)
#asserted either. */ if (_cpp_equiv_toklists (&pred->answer, &o->answer))
{
for (this = base->value.aschain; this; this = next) if (p)
{ p->next = o->next;
next = this->value.aschain; else
this->value.aschain = NULL; hp->value.pred = o->next;
this->type = T_VOID;
} _cpp_free_toklist (&o->answer);
base->value.aschain = NULL; free (o);
base->type = T_VOID; break;
}
} }
else else
{ {
baselen = ustrchr (sym, '(') - sym; struct predicate *o, *p;
base = _cpp_lookup (pfile, sym, baselen); for (o = hp->value.pred; o; o = p)
if (base->type == T_VOID) goto out; {
this = _cpp_lookup (pfile, sym, thislen); p = o->next;
if (this->type == T_VOID) goto out; _cpp_free_toklist ((cpp_toklist *) &o->answer);
free (o);
next = base; }
while (next->value.aschain != this) hp->value.pred = NULL;
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;
} }
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); _cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
if (pred)
{
_cpp_free_toklist (&pred->answer);
free (pred);
}
return 0; return 0;
} }
......
...@@ -124,7 +124,6 @@ typedef struct cpp_name cpp_name; ...@@ -124,7 +124,6 @@ typedef struct cpp_name cpp_name;
T(CPP_VSPACE, "\n") /* End of line. */ \ T(CPP_VSPACE, "\n") /* End of line. */ \
N(CPP_EOF, 0) /* End of file. */ \ N(CPP_EOF, 0) /* End of file. */ \
N(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \ 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. */ \ /* Obsolete - will be removed when no code uses them still. */ \
N(CPP_HSPACE, 0) /* Horizontal white space. */ \ N(CPP_HSPACE, 0) /* Horizontal white space. */ \
...@@ -189,6 +188,9 @@ struct cpp_token ...@@ -189,6 +188,9 @@ struct cpp_token
} val; } val;
}; };
/* General flags. */
#define LIST_OFFSET (1 << 0)
/* Directive flags. */ /* Directive flags. */
#define SYNTAX_INCLUDE (1 << 8) #define SYNTAX_INCLUDE (1 << 8)
...@@ -211,12 +213,12 @@ struct cpp_toklist ...@@ -211,12 +213,12 @@ struct cpp_toklist
unsigned int comments_used; /* comment tokens used. */ unsigned int comments_used; /* comment tokens used. */
unsigned int comments_cap; /* comment token capacity. */ unsigned int comments_cap; /* comment token capacity. */
/* Only used if tokens[0].type == CPP_DIRECTIVE. This is the /* The handler to call after lexing the rest of this line.
handler to call after lexing the rest of this line. The flags -1 for none */
indicate whether the rest of the line gets special treatment short dirno;
during lexing (#include, #if, #assert, #unassert). */
directive_handler dir_handler; /* Per-list flags, see above */
unsigned short dir_flags; unsigned short flags;
}; };
struct cpp_buffer struct cpp_buffer
...@@ -544,12 +546,6 @@ struct cpp_reader ...@@ -544,12 +546,6 @@ struct cpp_reader
/* If true, characters between '<' and '>' are a single (string) token. */ /* If true, characters between '<' and '>' are a single (string) token. */
unsigned char parsing_include_directive; 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 /* True if escape sequences (as described for has_escapes in
parse_buffer) should be emitted. */ parse_buffer) should be emitted. */
unsigned char output_escapes; unsigned char output_escapes;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment