cppexp.c (CPP_UMINUS, CPP_UPLUS): New.

* cppexp.c (CPP_UMINUS, CPP_UPLUS): New.
	(HAVE_NO_R_OPERAND): Remove.
	(HAVE_VALUE): Remove.
	(op_to_prio): Update.
	(UNARY): Don't alter flags.
	(_cpp_parse_expr): want_value used to indicate whether
	a number or unary operator is expected next.  Distinguish
	unary and binary +/-.
	(op_as_text): Update for unary operators.

From-SVN: r52780
This commit is contained in:
Neil Booth 2002-04-26 06:32:50 +00:00 committed by Neil Booth
parent 6052bef039
commit f8b954fcdc
3 changed files with 95 additions and 83 deletions

View file

@ -1,3 +1,15 @@
2002-04-26 Neil Booth <neil@daikokuya.demon.co.uk>
* cppexp.c (CPP_UMINUS, CPP_UPLUS): New.
(HAVE_NO_R_OPERAND): Remove.
(HAVE_VALUE): Remove.
(op_to_prio): Update.
(UNARY): Don't alter flags.
(_cpp_parse_expr): want_value used to indicate whether
a number or unary operator is expected next. Distinguish
unary and binary +/-.
(op_as_text): Update for unary operators.
2002-04-25 Richard Henderson <rth@redhat.com>
PR c/2161

View file

@ -48,9 +48,12 @@ struct op
HOST_WIDEST_INT value; /* The value logically "right" of op. */
};
/* There is no "error" token, but we can't get comments in #if, so we can
abuse that token type. */
/* Token type abuse. There is no "error" token, but we can't get
comments in #if, so we can abuse that token type. Similarly,
create unary plus and minus operators. */
#define CPP_ERROR CPP_COMMENT
#define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
#define CPP_UMINUS (CPP_LAST_CPP_OP + 2)
/* With -O2, gcc appears to produce nice code, moving the error
message load and subsequent jump completely out of the main path. */
@ -454,10 +457,9 @@ same way as the ultra-low priority end-of-expression dummy operator.
The exit code checks to see if the operator that caused it is ')', and
if so outputs an appropriate error message.
The parser assumes all shifted operators require a right operand
unless the flag NO_R_OPERAND is set, and similarly for NO_L_OPERAND.
These semantics are automatically checked, any extra semantics need to
be handled with operator-specific code. */
The parser assumes all shifted operators require a left operand unless
the flag NO_L_OPERAND is set. These semantics are automatic; any
extra semantics need to be handled with operator-specific code. */
#define FLAG_BITS 8
#define FLAG_MASK ((1 << FLAG_BITS) - 1)
@ -466,10 +468,8 @@ be handled with operator-specific code. */
#define EXTRACT_FLAGS(CNST) ((CNST) & FLAG_MASK)
/* Flags. */
#define HAVE_VALUE (1 << 0)
#define NO_L_OPERAND (1 << 1)
#define NO_R_OPERAND (1 << 2)
#define SHORT_CIRCUIT (1 << 3)
#define NO_L_OPERAND (1 << 0)
#define SHORT_CIRCUIT (1 << 1)
/* Priority and flag combinations. */
#define RIGHT_ASSOC (1 << FLAG_BITS)
@ -501,8 +501,8 @@ op_to_prio[] =
/* NOT */ UNARY_PRIO,
/* GREATER */ LESS_PRIO,
/* LESS */ LESS_PRIO,
/* PLUS */ UNARY_PRIO, /* note these two can be unary */
/* MINUS */ UNARY_PRIO, /* or binary */
/* PLUS */ PLUS_PRIO,
/* MINUS */ PLUS_PRIO,
/* MULT */ MUL_PRIO,
/* DIV */ MUL_PRIO,
/* MOD */ MUL_PRIO,
@ -525,7 +525,10 @@ op_to_prio[] =
/* EQ_EQ */ EQUAL_PRIO,
/* NOT_EQ */ EQUAL_PRIO,
/* GREATER_EQ */ LESS_PRIO,
/* LESS_EQ */ LESS_PRIO
/* LESS_EQ */ LESS_PRIO,
/* EOF */ FORCE_REDUCE_PRIO,
/* UPLUS */ UNARY_PRIO,
/* UMINUS */ UNARY_PRIO
};
#define COMPARE(OP) \
@ -544,8 +547,7 @@ op_to_prio[] =
top->unsignedp = unsigned1 | unsigned2;
#define UNARY(OP) \
top->value = OP v2; \
top->unsignedp = unsigned2; \
top->flags |= HAVE_VALUE;
top->unsignedp = unsigned2;
#define SHIFT(PSH, MSH) \
if (skip_evaluation) \
break; \
@ -568,8 +570,7 @@ _cpp_parse_expr (pfile)
There is a stack element for each operator (only),
and the most recently pushed operator is 'top->op'.
An operand (value) is stored in the 'value' field of the stack
element of the operator that precedes it.
In that case the 'flags' field has the HAVE_VALUE flag set. */
element of the operator that precedes it. */
#define INIT_STACK_SIZE 20
struct op init_stack[INIT_STACK_SIZE];
@ -579,6 +580,7 @@ _cpp_parse_expr (pfile)
int skip_evaluation = 0;
int result;
unsigned int lex_count, saw_leading_not;
bool want_value = true;
/* Set up detection of #if ! defined(). */
pfile->mi_ind_cmacro = 0;
@ -589,8 +591,6 @@ _cpp_parse_expr (pfile)
top->op = CPP_EOF;
/* Nifty way to catch missing '('. */
top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
/* Avoid missing right operand checks. */
top->flags = NO_R_OPERAND;
for (;;)
{
@ -603,38 +603,41 @@ _cpp_parse_expr (pfile)
lex_count++;
/* If the token is an operand, push its value and get next
token. If it is an operator, get its priority and flags, and
try to reduce the expression on the stack. */
token. If it is an operator, handle some special cases, get
its priority and flags, and try to reduce the expression on
the stack. */
switch (op.op)
{
case CPP_ERROR:
goto syntax_error;
push_immediate:
case CPP_NUMBER:
/* Push a value onto the stack. */
if (top->flags & HAVE_VALUE)
if (!want_value)
SYNTAX_ERROR ("missing binary operator");
push_immediate:
want_value = false;
top->value = op.value;
top->unsignedp = op.unsignedp;
top->flags |= HAVE_VALUE;
continue;
case CPP_EOF: prio = FORCE_REDUCE_PRIO; break;
case CPP_NOT:
saw_leading_not = lex_count == 1;
prio = op_to_prio[op.op];
break;
case CPP_PLUS:
case CPP_MINUS: prio = PLUS_PRIO; if (top->flags & HAVE_VALUE) break;
/* else unary; fall through */
default: prio = op_to_prio[op.op]; break;
if (want_value)
op.op = CPP_UPLUS;
break;
case CPP_MINUS:
if (want_value)
op.op = CPP_UMINUS;
break;
default:
break;
}
/* Separate the operator's code into priority and flags. */
flags = EXTRACT_FLAGS(prio);
prio = EXTRACT_PRIO(prio);
if (prio == EXTRACT_PRIO(OPEN_PAREN_PRIO))
flags = EXTRACT_FLAGS (op_to_prio[op.op]);
prio = EXTRACT_PRIO (op_to_prio[op.op]);
if (prio == EXTRACT_PRIO (OPEN_PAREN_PRIO))
goto skip_reduction;
/* Check for reductions. Then push the operator. */
@ -645,13 +648,15 @@ _cpp_parse_expr (pfile)
/* Most operators that can appear on the stack require a
right operand. Check this before trying to reduce. */
if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0)
if (want_value)
{
if (top->op == CPP_OPEN_PAREN)
SYNTAX_ERROR ("void expression between '(' and ')'");
else
else if (top->op != CPP_EOF)
SYNTAX_ERROR2 ("operator '%s' has no right operand",
op_as_text (pfile, top->op));
else if (op.op != CPP_CLOSE_PAREN)
SYNTAX_ERROR ("#if with no expression");
}
unsigned2 = top->unsignedp, v2 = top->value;
@ -682,44 +687,35 @@ _cpp_parse_expr (pfile)
case CPP_MIN: MINMAX(<); break;
case CPP_MAX: MINMAX(>); break;
case CPP_PLUS:
if (!(top->flags & HAVE_VALUE))
{
/* Can't use UNARY(+) because K+R C did not have unary
plus. Can't use UNARY() because some compilers object
to the empty argument. */
top->value = v2;
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
case CPP_UPLUS:
/* Can't use UNARY(+) because K+R C did not have unary
plus. Can't use UNARY() because some compilers object
to the empty argument. */
top->value = v2;
top->unsignedp = unsigned2;
if (CPP_WTRADITIONAL (pfile))
cpp_error (pfile, DL_WARNING,
"traditional C rejects the unary plus operator");
break;
case CPP_UMINUS:
UNARY(-);
if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
integer_overflow (pfile);
break;
if (CPP_WTRADITIONAL (pfile))
cpp_error (pfile, DL_WARNING,
"traditional C rejects the unary plus operator");
}
else
{
top->value = v1 + v2;
top->unsignedp = unsigned1 | unsigned2;
if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (v1, v2, top->value))
integer_overflow (pfile);
}
case CPP_PLUS:
top->value = v1 + v2;
top->unsignedp = unsigned1 | unsigned2;
if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (v1, v2, top->value))
integer_overflow (pfile);
break;
case CPP_MINUS:
if (!(top->flags & HAVE_VALUE))
{
UNARY(-);
if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
integer_overflow (pfile);
}
else
{ /* Binary '-' */
top->value = v1 - v2;
top->unsignedp = unsigned1 | unsigned2;
if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (top->value, v2, v1))
integer_overflow (pfile);
}
top->value = v1 - v2;
top->unsignedp = unsigned1 | unsigned2;
if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (top->value, v2, v1))
integer_overflow (pfile);
break;
case CPP_MULT:
top->unsignedp = unsigned1 | unsigned2;
@ -821,16 +817,17 @@ _cpp_parse_expr (pfile)
/* Check we have a left operand iff we need one. */
if (flags & NO_L_OPERAND)
{
if (top->flags & HAVE_VALUE)
if (!want_value)
SYNTAX_ERROR2 ("missing binary operator before '%s'",
op_as_text (pfile, op.op));
}
else
{
if (!(top->flags & HAVE_VALUE))
if (want_value)
SYNTAX_ERROR2 ("operator '%s' has no left operand",
op_as_text (pfile, op.op));
}
want_value = true;
/* Check for and handle stack overflow. */
top++;
@ -868,11 +865,6 @@ _cpp_parse_expr (pfile)
if (top != stack)
{
cpp_error (pfile, DL_ICE, "unbalanced stack in #if");
goto syntax_error;
}
else if (!(top[1].flags & HAVE_VALUE))
{
SYNTAX_ERROR ("#if with no expression");
syntax_error:
result = 0; /* Return 0 on syntax error. */
}
@ -891,6 +883,11 @@ op_as_text (pfile, 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);

View file

@ -46,9 +46,9 @@ typedef struct cpp_callbacks cpp_callbacks;
struct answer;
struct file_name_map_list;
/* The first two groups, apart from '=', can appear in preprocessor
expressions. This allows a lookup table to be implemented in
_cpp_parse_expr.
/* The first three groups, apart from '=', can appear in preprocessor
expressions (+= and -= are used to indicate unary + and - resp.).
This allows a lookup table to be implemented in _cpp_parse_expr.
The first group, to CPP_LAST_EQ, can be immediately followed by an
'='. The lexer needs operators ending in '=', like ">>=", to be in
@ -58,6 +58,7 @@ struct file_name_map_list;
#define CPP_LAST_EQ CPP_MAX
#define CPP_FIRST_DIGRAPH CPP_HASH
#define CPP_LAST_PUNCTUATOR CPP_DOT_STAR
#define CPP_LAST_CPP_OP CPP_EOF
#define TTYPE_TABLE \
OP(CPP_EQ = 0, "=") \
@ -90,8 +91,11 @@ struct file_name_map_list;
OP(CPP_GREATER_EQ, ">=") \
OP(CPP_LESS_EQ, "<=") \
\
/* These 3 are special in preprocessor expressions. */ \
TK(CPP_EOF, SPELL_NONE) \
OP(CPP_PLUS_EQ, "+=") /* math */ \
OP(CPP_MINUS_EQ, "-=") \
\
OP(CPP_MULT_EQ, "*=") \
OP(CPP_DIV_EQ, "/=") \
OP(CPP_MOD_EQ, "%=") \
@ -135,8 +139,7 @@ struct file_name_map_list;
TK(CPP_COMMENT, SPELL_NUMBER) /* Only if output comments. */ \
/* SPELL_NUMBER happens to DTRT. */ \
TK(CPP_MACRO_ARG, SPELL_NONE) /* Macro argument. */ \
TK(CPP_PADDING, SPELL_NONE) /* Whitespace for cpp0. */ \
TK(CPP_EOF, SPELL_NONE) /* End of line or file. */
TK(CPP_PADDING, SPELL_NONE) /* Whitespace for cpp0. */
#define OP(e, s) e,
#define TK(e, s) e,