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 *));
......
...@@ -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