Commit 60284a59 by Neil Booth Committed by Neil Booth

cppexp.c (lex): Move some code to _cpp_parse_expr, but keep most cases as function eval_token.

	* cppexp.c (lex): Move some code to _cpp_parse_expr, but
	keep most cases as function eval_token.
	(eval_token): New function.
	(_cpp_parse_expr): Read token here for improved diagnostics.
	Don't use op_as_text.  Detect bad ':' here.
	(reduce): Don't detect bad ':' here.
	(op_as_text): Remove.
	* cpphash.h (_cpp_test_assertion): Change prototype.
	* cpplib.c (_cpp_test_assertion): Change prototype.
testsuite:
	* gcc.dg/cpp/if-cexp.c: Add a test.

From-SVN: r52866
parent 349a4b40
2002-04-29 Neil Booth <neil@daikokuya.demon.co.uk>
* cppexp.c (lex): Move some code to _cpp_parse_expr, but
keep most cases as function eval_token.
(eval_token): New function.
(_cpp_parse_expr): Read token here for improved diagnostics.
Don't use op_as_text. Detect bad ':' here.
(reduce): Don't detect bad ':' here.
(op_as_text): Remove.
* cpphash.h (_cpp_test_assertion): Change prototype.
* cpplib.c (_cpp_test_assertion): Change prototype.
2002-04-28 Richard Henderson <rth@redhat.com> 2002-04-28 Richard Henderson <rth@redhat.com>
PR c/5154 PR c/5154
......
...@@ -36,8 +36,7 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, ...@@ -36,8 +36,7 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
unsigned HOST_WIDEST_INT)); unsigned HOST_WIDEST_INT));
static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *)); static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_defined PARAMS ((cpp_reader *)); static struct op parse_defined PARAMS ((cpp_reader *));
static struct op lex PARAMS ((cpp_reader *)); static struct op eval_token PARAMS ((cpp_reader *, const cpp_token *));
static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype)); static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
struct op struct op
...@@ -275,45 +274,30 @@ parse_defined (pfile) ...@@ -275,45 +274,30 @@ parse_defined (pfile)
return op; return op;
} }
/* Read a token. The returned type is CPP_NUMBER for a valid number /* Convert a token into a CPP_NUMBER (an interpreted preprocessing
(an interpreted preprocessing number or character constant, or the number or character constant, or the result of the "defined" or "#"
result of the "defined" or "#" operators), CPP_ERROR on error, operators), or CPP_ERROR on error. */
CPP_EOF, or the type of an operator token. */
static struct op static struct op
lex (pfile) eval_token (pfile, token)
cpp_reader *pfile; cpp_reader *pfile;
const cpp_token *token;
{ {
unsigned int temp;
struct op op; struct op op;
const cpp_token *token = cpp_get_token (pfile);
op.op = CPP_NUMBER;
op.unsignedp = 0;
switch (token->type) switch (token->type)
{ {
case CPP_NUMBER: case CPP_NUMBER:
return parse_number (pfile, token); return parse_number (pfile, token);
case CPP_CHAR:
case CPP_WCHAR: case CPP_WCHAR:
{ op.unsignedp = WCHAR_UNSIGNED;
unsigned int chars_seen; case CPP_CHAR: /* Always unsigned. */
op.value = cpp_interpret_charconst (pfile, token, 1, &temp);
if (token->type == CPP_CHAR) break;
op.unsignedp = 0;
else
op.unsignedp = WCHAR_UNSIGNED;
op.op = CPP_NUMBER;
op.value = cpp_interpret_charconst (pfile, token, 1, &chars_seen);
return op;
}
case CPP_STRING:
case CPP_WSTRING:
SYNTAX_ERROR ("string constants are not valid in #if");
case CPP_OTHER:
if (ISGRAPH (token->val.c))
SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c);
else
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
case CPP_NAME: case CPP_NAME:
if (token->val.node == pfile->spec_nodes.n_defined) if (token->val.node == pfile->spec_nodes.n_defined)
...@@ -322,8 +306,6 @@ lex (pfile) ...@@ -322,8 +306,6 @@ lex (pfile)
&& (token->val.node == pfile->spec_nodes.n_true && (token->val.node == pfile->spec_nodes.n_true
|| token->val.node == pfile->spec_nodes.n_false)) || token->val.node == pfile->spec_nodes.n_false))
{ {
op.op = CPP_NUMBER;
op.unsignedp = 0;
op.value = (token->val.node == pfile->spec_nodes.n_true); op.value = (token->val.node == pfile->spec_nodes.n_true);
/* Warn about use of true or false in #if when pedantic /* Warn about use of true or false in #if when pedantic
...@@ -333,46 +315,22 @@ lex (pfile) ...@@ -333,46 +315,22 @@ lex (pfile)
cpp_error (pfile, DL_PEDWARN, cpp_error (pfile, DL_PEDWARN,
"ISO C++ does not permit \"%s\" in #if", "ISO C++ does not permit \"%s\" in #if",
NODE_NAME (token->val.node)); NODE_NAME (token->val.node));
return op;
} }
else else
{ {
op.op = CPP_NUMBER;
op.unsignedp = 0;
op.value = 0; op.value = 0;
if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
cpp_error (pfile, DL_WARNING, "\"%s\" is not defined", cpp_error (pfile, DL_WARNING, "\"%s\" is not defined",
NODE_NAME (token->val.node)); NODE_NAME (token->val.node));
return op;
}
case CPP_HASH:
{
int temp;
op.op = CPP_NUMBER;
if (_cpp_test_assertion (pfile, &temp))
op.op = CPP_ERROR;
op.unsignedp = 0;
op.value = temp;
return op;
}
default:
if (((int) token->type > (int) CPP_EQ
&& (int) token->type < (int) CPP_PLUS_EQ))
{
op.op = token->type;
return op;
} }
break;
SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions", default: /* CPP_HASH */
cpp_token_as_text (pfile, token)); if (_cpp_test_assertion (pfile, &temp))
op.op = CPP_ERROR;
op.value = temp;
} }
syntax_error:
op.op = CPP_ERROR;
return op; return op;
} }
...@@ -459,7 +417,7 @@ extra semantics need to be handled with operator-specific code. */ ...@@ -459,7 +417,7 @@ extra semantics need to be handled with operator-specific code. */
N entries of enum cpp_ttype. */ N entries of enum cpp_ttype. */
static const struct operator static const struct operator
{ {
uchar prio; /* Priorities are even. */ uchar prio;
uchar flags; uchar flags;
} optab[] = } optab[] =
{ {
...@@ -539,6 +497,7 @@ _cpp_parse_expr (pfile) ...@@ -539,6 +497,7 @@ _cpp_parse_expr (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct op *top = pfile->op_stack; struct op *top = pfile->op_stack;
const cpp_token *token = NULL, *prev_token;
unsigned int lex_count; unsigned int lex_count;
bool saw_leading_not, want_value = true; bool saw_leading_not, want_value = true;
...@@ -556,19 +515,26 @@ _cpp_parse_expr (pfile) ...@@ -556,19 +515,26 @@ _cpp_parse_expr (pfile)
{ {
struct op op; struct op op;
/* Read a token */ prev_token = token;
op = lex (pfile); token = cpp_get_token (pfile);
lex_count++; lex_count++;
op.op = token->type;
switch (op.op) switch (op.op)
{ {
case CPP_ERROR: /* These tokens convert into values. */
goto syntax_error;
case CPP_NUMBER: case CPP_NUMBER:
/* Push a value onto the stack. */ case CPP_CHAR:
case CPP_WCHAR:
case CPP_NAME:
case CPP_HASH:
if (!want_value) if (!want_value)
SYNTAX_ERROR ("missing binary operator"); SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
cpp_token_as_text (pfile, token));
want_value = false; want_value = false;
op = eval_token (pfile, token);
if (op.op == CPP_ERROR)
goto syntax_error;
top->value = op.value; top->value = op.value;
top->unsignedp = op.unsignedp; top->unsignedp = op.unsignedp;
continue; continue;
...@@ -584,7 +550,16 @@ _cpp_parse_expr (pfile) ...@@ -584,7 +550,16 @@ _cpp_parse_expr (pfile)
if (want_value) if (want_value)
op.op = CPP_UMINUS; op.op = CPP_UMINUS;
break; break;
case CPP_OTHER:
if (ISGRAPH (token->val.c))
SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c);
else
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
default: default:
if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
SYNTAX_ERROR2 ("token \"%s\" is not valid in #if expressions",
cpp_token_as_text (pfile, token));
break; break;
} }
...@@ -592,11 +567,13 @@ _cpp_parse_expr (pfile) ...@@ -592,11 +567,13 @@ _cpp_parse_expr (pfile)
if (optab[op.op].flags & NO_L_OPERAND) if (optab[op.op].flags & NO_L_OPERAND)
{ {
if (!want_value) if (!want_value)
SYNTAX_ERROR2 ("missing binary operator before '%s'", SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
op_as_text (pfile, op.op)); cpp_token_as_text (pfile, token));
} }
else if (want_value) else if (want_value)
{ {
/* Ordering here is subtle and intended to favour the
missing parenthesis diagnostics over alternatives. */
if (op.op == CPP_CLOSE_PAREN) if (op.op == CPP_CLOSE_PAREN)
{ {
if (top->op == CPP_OPEN_PAREN) if (top->op == CPP_OPEN_PAREN)
...@@ -606,19 +583,20 @@ _cpp_parse_expr (pfile) ...@@ -606,19 +583,20 @@ _cpp_parse_expr (pfile)
SYNTAX_ERROR ("#if with no expression"); SYNTAX_ERROR ("#if with no expression");
if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
SYNTAX_ERROR2 ("operator '%s' has no right operand", SYNTAX_ERROR2 ("operator '%s' has no right operand",
op_as_text (pfile, top->op)); cpp_token_as_text (pfile, prev_token));
} }
top = reduce (pfile, top, op.op); top = reduce (pfile, top, op.op);
if (!top) if (!top)
goto syntax_error; goto syntax_error;
if (op.op == CPP_EOF)
break;
switch (op.op) switch (op.op)
{ {
case CPP_CLOSE_PAREN: case CPP_CLOSE_PAREN:
continue; continue;
case CPP_EOF:
goto done;
case CPP_OR_OR: case CPP_OR_OR:
if (top->value) if (top->value)
pfile->state.skip_eval++; pfile->state.skip_eval++;
...@@ -629,6 +607,8 @@ _cpp_parse_expr (pfile) ...@@ -629,6 +607,8 @@ _cpp_parse_expr (pfile)
pfile->state.skip_eval++; pfile->state.skip_eval++;
break; break;
case CPP_COLON: case CPP_COLON:
if (top->op != CPP_QUERY)
SYNTAX_ERROR (" ':' without preceding '?'");
if (top[-1].value) /* Was '?' condition true? */ if (top[-1].value) /* Was '?' condition true? */
pfile->state.skip_eval++; pfile->state.skip_eval++;
else else
...@@ -646,7 +626,6 @@ _cpp_parse_expr (pfile) ...@@ -646,7 +626,6 @@ _cpp_parse_expr (pfile)
top->op = op.op; top->op = op.op;
} }
done:
/* The controlling macro expression is only valid if we called lex 3 /* The controlling macro expression is only valid if we called lex 3
times: <!> <defined expression> and <EOF>. push_conditional () times: <!> <defined expression> and <EOF>. push_conditional ()
checks that we are at top-of-file. */ checks that we are at top-of-file. */
...@@ -693,8 +672,7 @@ reduce (pfile, top, op) ...@@ -693,8 +672,7 @@ reduce (pfile, top, op)
switch (top[1].op) switch (top[1].op)
{ {
default: default:
cpp_error (pfile, DL_ICE, "impossible operator '%s'", cpp_error (pfile, DL_ICE, "impossible operator '%u'", top[1].op);
op_as_text (pfile, top[1].op));
return 0; return 0;
case CPP_NOT: UNARY(!); break; case CPP_NOT: UNARY(!); break;
...@@ -806,11 +784,6 @@ reduce (pfile, top, op) ...@@ -806,11 +784,6 @@ reduce (pfile, top, op)
cpp_error (pfile, DL_ERROR, "'?' without following ':'"); cpp_error (pfile, DL_ERROR, "'?' without following ':'");
return 0; return 0;
case CPP_COLON: case CPP_COLON:
if (top->op != CPP_QUERY)
{
cpp_error (pfile, DL_ERROR, " ':' without preceding '?'");
return 0;
}
top--; top--;
if (top->value) pfile->state.skip_eval--; if (top->value) pfile->state.skip_eval--;
top->value = top->value ? v1 : v2; top->value = top->value ? v1 : v2;
...@@ -849,21 +822,3 @@ _cpp_expand_op_stack (pfile) ...@@ -849,21 +822,3 @@ _cpp_expand_op_stack (pfile)
return pfile->op_stack + n; return pfile->op_stack + n;
} }
/* Output OP as text for diagnostics. */
static const unsigned char *
op_as_text (pfile, op)
cpp_reader *pfile;
enum cpp_ttype op;
{
cpp_token token;
if (op == CPP_UPLUS)
op = CPP_PLUS;
else if (op == CPP_UMINUS)
op = CPP_MINUS;
token.type = op;
token.flags = 0;
return cpp_token_as_text (pfile, &token);
}
...@@ -413,7 +413,7 @@ extern void _cpp_init_tokenrun PARAMS ((tokenrun *, unsigned int)); ...@@ -413,7 +413,7 @@ extern void _cpp_init_tokenrun PARAMS ((tokenrun *, unsigned int));
extern void _cpp_maybe_push_include_file PARAMS ((cpp_reader *)); extern void _cpp_maybe_push_include_file PARAMS ((cpp_reader *));
/* In cpplib.c */ /* In cpplib.c */
extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *)); extern int _cpp_test_assertion PARAMS ((cpp_reader *, unsigned int *));
extern int _cpp_handle_directive PARAMS ((cpp_reader *, int)); extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *)); extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *));
extern void _cpp_do__Pragma PARAMS ((cpp_reader *)); extern void _cpp_do__Pragma PARAMS ((cpp_reader *));
......
...@@ -1652,7 +1652,7 @@ find_answer (node, candidate) ...@@ -1652,7 +1652,7 @@ find_answer (node, candidate)
int int
_cpp_test_assertion (pfile, value) _cpp_test_assertion (pfile, value)
cpp_reader *pfile; cpp_reader *pfile;
int *value; unsigned int *value;
{ {
struct answer *answer; struct answer *answer;
cpp_hashnode *node; cpp_hashnode *node;
......
2002-04-29 Neil Booth <neil@daikokuya.demon.co.uk>
* gcc.dg/cpp/if-cexp.c: Add a test.
2002-04-28 Jakub Jelinek <jakub@redhat.com> 2002-04-28 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/20020426-2.c: New test. * gcc.dg/20020426-2.c: New test.
......
...@@ -10,4 +10,5 @@ ...@@ -10,4 +10,5 @@
#error OK /* { dg-error "OK" "nested ? : with parens" } */ #error OK /* { dg-error "OK" "nested ? : with parens" } */
#endif #endif
#if 2: /* { dg-error "':' without" "immediate :" } */
#endif
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