/* Parse C expressions for cpplib.
- Copyright (C) 1987, 92, 94, 95, 97, 98, 1999, 2000 Free Software Foundation.
+ Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation.
Contributed by Per Bothner, 1994.
This program is free software; you can redistribute it and/or modify it
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Parse a C expression from text in a string */
-
#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
-#endif
-
-#ifndef MAX_CHAR_TYPE_SIZE
-#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
-#endif
-
-#ifndef MAX_INT_TYPE_SIZE
-#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE
-#endif
-
-#ifndef MAX_LONG_TYPE_SIZE
-#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
-#endif
-
-#ifndef MAX_WCHAR_TYPE_SIZE
-#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
-#endif
-
-#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
- ? (~(~(HOST_WIDEST_INT) 0 << MAX_CHAR_TYPE_SIZE)) \
- : ~ (HOST_WIDEST_INT) 0)
-
-#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
- ? ~(~(HOST_WIDEST_INT) 0 << MAX_WCHAR_TYPE_SIZE) \
- : ~ (HOST_WIDEST_INT) 0)
-
/* Yield nonzero if adding two numbers with A's and B's signs can yield a
number with SUM's sign, where A, B, and SUM are all C integers. */
#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
unsigned int,
unsigned HOST_WIDEST_INT));
static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
-static struct op parse_charconst PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op parse_assertion PARAMS ((cpp_reader *));
-static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **,
- const U_CHAR *, HOST_WIDEST_INT));
static struct op lex PARAMS ((cpp_reader *, int));
+static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
struct op
{
#define SYNTAX_ERROR2(msgid, arg) \
do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
-/* Parse and convert an integer for #if. Accepts decimal, hex, or octal
- with or without size suffixes. */
struct suffix
{
- unsigned char s[4];
- unsigned char u;
- unsigned char l;
+ const unsigned char s[4];
+ const unsigned char u;
+ const unsigned char l;
};
-const struct suffix vsuf_1[] = {
+static const struct suffix vsuf_1[] = {
{ "u", 1, 0 }, { "U", 1, 0 },
{ "l", 0, 1 }, { "L", 0, 1 }
};
-const struct suffix vsuf_2[] = {
+static const struct suffix vsuf_2[] = {
{ "ul", 1, 1 }, { "UL", 1, 1 }, { "uL", 1, 1 }, { "Ul", 1, 1 },
{ "lu", 1, 1 }, { "LU", 1, 1 }, { "Lu", 1, 1 }, { "lU", 1, 1 },
{ "ll", 0, 2 }, { "LL", 0, 2 }
};
-const struct suffix vsuf_3[] = {
+static const struct suffix vsuf_3[] = {
{ "ull", 1, 2 }, { "ULL", 1, 2 }, { "uLL", 1, 2 }, { "Ull", 1, 2 },
{ "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 }
};
#define Nsuff(tab) (sizeof tab / sizeof (struct suffix))
+/* Parse and convert an integer for #if. Accepts decimal, hex, or
+ octal with or without size suffixes. Returned op is CPP_ERROR on
+ error, otherwise it is a CPP_NUMBER. */
+
static struct op
parse_number (pfile, tok)
cpp_reader *pfile;
{
c = *p;
- if (c >= '0' && c <= '9')
- digit = c - '0';
- /* We believe that in all live character sets, a-f are
- consecutive, and so are A-F. */
- else if (base == 16 && c >= 'a' && c <= 'f')
- digit = c - 'a' + 10;
- else if (base == 16 && c >= 'A' && c <= 'F')
- digit = c - 'A' + 10;
+ if (ISDIGIT (c)
+ || (base == 16 && ISXDIGIT (c)))
+ digit = hex_value (c);
else
break;
{
/* Check for a floating point constant. Note that float constants
with an exponent or suffix but no decimal point are technically
- illegal (C99 6.4.4.2) but accepted elsewhere. */
+ invalid (C99 6.4.4.2) but accepted elsewhere. */
if ((c == '.' || c == 'F' || c == 'f')
|| (base == 10 && (c == 'E' || c == 'e')
&& p+1 < end && (p[1] == '+' || p[1] == '-'))
goto invalid_suffix;
op.unsignedp = sufftab[i].u;
- if (CPP_OPTION (pfile, c89) && sufftab[i].l == 2)
- SYNTAX_ERROR ("too many 'l' suffixes in integer constant");
+ if (CPP_WTRADITIONAL (pfile)
+ && sufftab[i].u
+ && ! cpp_sys_macro_p (pfile))
+ cpp_warning (pfile, "traditional C rejects the `U' suffix");
+ if (sufftab[i].l == 2 && CPP_OPTION (pfile, pedantic)
+ && ! CPP_OPTION (pfile, c99))
+ cpp_pedwarn (pfile, "too many 'l' suffixes in integer constant");
}
if (base <= largest_digit)
}
op.value = n;
- op.op = CPP_INT;
+ op.op = CPP_NUMBER;
return op;
invalid_suffix:
return op;
}
-/* Parse and convert a character constant for #if. Understands backslash
- escapes (\n, \031) and multibyte characters (if so configured). */
static struct op
-parse_charconst (pfile, tok)
+parse_defined (pfile)
cpp_reader *pfile;
- const cpp_token *tok;
{
+ int paren = 0;
+ cpp_hashnode *node = 0;
+ const cpp_token *token;
struct op op;
- HOST_WIDEST_INT result = 0;
- int num_chars = 0;
- int num_bits;
- unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK;
- int max_chars;
- const U_CHAR *ptr = tok->val.str.text;
- const U_CHAR *end = ptr + tok->val.str.len;
+ cpp_context *initial_context = pfile->context;
- int c = -1;
+ /* Don't expand macros. */
+ pfile->state.prevent_expansion++;
- if (tok->type == CPP_WCHAR)
- width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK;
- max_chars = MAX_LONG_TYPE_SIZE / width;
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ paren = 1;
+ token = cpp_get_token (pfile);
+ }
- while (ptr < end)
+ if (token->type == CPP_NAME)
{
- c = *ptr++;
- if (c == '\'')
- CPP_ICE ("unescaped ' in character constant");
- else if (c == '\\')
+ node = token->val.node;
+ if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
{
- c = parse_escape (pfile, &ptr, end, mask);
- if (width < HOST_BITS_PER_INT
- && (unsigned int) c >= (unsigned int)(1 << width))
- cpp_pedwarn (pfile,
- "escape sequence out of range for character");
+ cpp_error (pfile, "missing ')' after \"defined\"");
+ node = 0;
}
-
- /* Merge character into result; ignore excess chars. */
- if (++num_chars <= max_chars)
+ }
+ else
+ {
+ cpp_error (pfile, "operator \"defined\" requires an identifier");
+ if (token->flags & NAMED_OP)
{
- if (width < HOST_BITS_PER_INT)
- result = (result << width) | (c & ((1 << width) - 1));
- else
- result = c;
+ cpp_token op;
+
+ op.flags = 0;
+ op.type = token->type;
+ cpp_error (pfile,
+ "(\"%s\" is an alternative token for \"%s\" in C++)",
+ cpp_token_as_text (pfile, token),
+ cpp_token_as_text (pfile, &op));
}
}
- if (num_chars == 0)
- SYNTAX_ERROR ("empty character constant");
- else if (num_chars > max_chars)
- SYNTAX_ERROR ("character constant too long");
- else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
- cpp_warning (pfile, "multi-character character constant");
-
- /* If char type is signed, sign-extend the constant. */
- num_bits = num_chars * width;
-
- if (pfile->spec_nodes->n__CHAR_UNSIGNED__->type != T_VOID
- || ((result >> (num_bits - 1)) & 1) == 0)
- op.value = result & ((unsigned HOST_WIDEST_INT) ~0
- >> (HOST_BITS_PER_WIDEST_INT - num_bits));
+ if (!node)
+ op.op = CPP_ERROR;
else
- op.value = result | ~((unsigned HOST_WIDEST_INT) ~0
- >> (HOST_BITS_PER_WIDEST_INT - num_bits));
-
- /* This is always a signed type. */
- op.unsignedp = 0;
- op.op = CPP_INT;
- return op;
-
- syntax_error:
- op.op = CPP_ERROR;
- return op;
-}
-
-static struct op
-parse_defined (pfile)
- cpp_reader *pfile;
-{
- int paren;
- const cpp_token *tok;
- struct op op;
-
- paren = 0;
- tok = _cpp_get_raw_token (pfile);
- if (tok->type == CPP_OPEN_PAREN)
{
- paren = 1;
- tok = _cpp_get_raw_token (pfile);
- }
-
- if (tok->type != CPP_NAME)
- SYNTAX_ERROR ("\"defined\" without an identifier");
-
- if (paren && _cpp_get_raw_token (pfile)->type != CPP_CLOSE_PAREN)
- SYNTAX_ERROR ("missing close paren after \"defined\"");
-
- if (tok->val.node->type == T_POISON)
- SYNTAX_ERROR2 ("attempt to use poisoned \"%s\"", tok->val.node->name);
-
- op.value = tok->val.node->type != T_VOID;
- op.unsignedp = 0;
- op.op = CPP_INT;
- return op;
-
- syntax_error:
- op.op = CPP_ERROR;
- return op;
-}
+ if (pfile->context != initial_context)
+ cpp_warning (pfile, "this use of \"defined\" may not be portable");
-static struct op
-parse_assertion (pfile)
- cpp_reader *pfile;
-{
- struct op op;
- struct answer *answer;
- cpp_hashnode *hp;
-
- op.op = CPP_ERROR;
- hp = _cpp_parse_assertion (pfile, &answer);
- if (hp)
- {
- /* If we get here, the syntax is valid. */
- op.op = CPP_INT;
+ op.value = node->type == NT_MACRO;
op.unsignedp = 0;
- op.value = (hp->type == T_ASSERTION &&
- (answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0));
+ op.op = CPP_NUMBER;
- if (answer)
- FREE_ANSWER (answer);
+ /* A possible controlling macro of the form #if !defined ().
+ _cpp_parse_expr checks there was no other junk on the line. */
+ pfile->mi_ind_cmacro = node;
}
+
+ pfile->state.prevent_expansion--;
return op;
}
-/* Read one token. */
+/* Read a token. The returned type is CPP_NUMBER for a valid number
+ (an interpreted preprocessing number or character constant, or the
+ result of the "defined" or "#" operators), CPP_ERROR on error,
+ CPP_EOF, or the type of an operator token. */
static struct op
lex (pfile, skip_evaluation)
int skip_evaluation;
{
struct op op;
- const cpp_token *tok;
-
- retry:
- tok = _cpp_get_token (pfile);
+ const cpp_token *token = cpp_get_token (pfile);
- switch (tok->type)
+ switch (token->type)
{
- case CPP_PLACEMARKER:
- /* XXX These shouldn't be visible outside cpplex.c. */
- goto retry;
-
- case CPP_INT:
case CPP_NUMBER:
- return parse_number (pfile, tok);
+ return parse_number (pfile, token);
+
case CPP_CHAR:
case CPP_WCHAR:
- return parse_charconst (pfile, tok);
+ {
+ unsigned int chars_seen;
+
+ /* This is always a signed type. */
+ op.unsignedp = 0;
+ op.op = CPP_NUMBER;
+ op.value = cpp_interpret_charconst (pfile, token, 1, 0, &chars_seen);
+ return op;
+ }
case CPP_STRING:
case CPP_WSTRING:
SYNTAX_ERROR ("string constants are not valid in #if");
- case CPP_FLOAT:
- SYNTAX_ERROR ("floating point numbers are not valid in #if");
-
case CPP_OTHER:
- if (ISGRAPH (tok->val.aux))
- SYNTAX_ERROR2 ("invalid character '%c' in #if", tok->val.aux);
+ if (ISGRAPH (token->val.c))
+ SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c);
else
- SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", tok->val.aux);
+ SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
case CPP_NAME:
- if (tok->val.node == pfile->spec_nodes->n_defined)
+ if (token->val.node == pfile->spec_nodes.n_defined)
return parse_defined (pfile);
+ else if (CPP_OPTION (pfile, cplusplus)
+ && (token->val.node == pfile->spec_nodes.n_true
+ || 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);
+
+ /* Warn about use of true or false in #if when pedantic
+ and stdbool.h has not been included. */
+ if (CPP_PEDANTIC (pfile)
+ && ! cpp_defined (pfile, DSC("__bool_true_false_are_defined")))
+ cpp_pedwarn (pfile, "ISO C++ does not permit \"%s\" in #if",
+ NODE_NAME (token->val.node));
+ return op;
+ }
+ else
+ {
+ op.op = CPP_NUMBER;
+ op.unsignedp = 0;
+ op.value = 0;
- op.op = CPP_INT;
- op.unsignedp = 0;
- op.value = 0;
-
- if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
- cpp_warning (pfile, "\"%s\" is not defined", tok->val.node->name);
- return op;
+ if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
+ cpp_warning (pfile, "\"%s\" is not defined",
+ NODE_NAME (token->val.node));
+ return op;
+ }
case CPP_HASH:
- return parse_assertion (pfile);
+ {
+ 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 ((tok->type > CPP_EQ && tok->type < CPP_PLUS_EQ)
- || tok->type == CPP_EOF)
+ if (((int) token->type > (int) CPP_EQ
+ && (int) token->type < (int) CPP_PLUS_EQ)
+ || token->type == CPP_EOF)
{
- op.op = tok->type;
+ op.op = token->type;
return op;
}
- SYNTAX_ERROR2("'%s' is not valid in #if expressions",
- _cpp_spell_operator (tok->type));
- }
+ SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions",
+ cpp_token_as_text (pfile, token));
+ }
syntax_error:
op.op = CPP_ERROR;
return op;
}
-/* Parse a C escape sequence. STRING_PTR points to a variable
- containing a pointer to the string to parse. That pointer
- is updated past the characters we use. The value of the
- escape sequence is returned.
-
- If \ is followed by 000, we return 0 and leave the string pointer
- after the zeros. A value of 0 does not mean end of string. */
-
-static HOST_WIDEST_INT
-parse_escape (pfile, string_ptr, limit, result_mask)
- cpp_reader *pfile;
- const U_CHAR **string_ptr;
- const U_CHAR *limit;
- HOST_WIDEST_INT result_mask;
-{
- const U_CHAR *ptr = *string_ptr;
- /* We know we have at least one following character. */
- int c = *ptr++;
- switch (c)
- {
- case 'a': c = TARGET_BELL; break;
- case 'b': c = TARGET_BS; break;
- case 'f': c = TARGET_FF; break;
- case 'n': c = TARGET_NEWLINE; break;
- case 'r': c = TARGET_CR; break;
- case 't': c = TARGET_TAB; break;
- case 'v': c = TARGET_VT; break;
-
- case 'e': case 'E':
- if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c);
- c = TARGET_ESC;
- break;
-
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- {
- unsigned int i = c - '0';
- int count = 0;
- while (++count < 3)
- {
- if (ptr >= limit)
- break;
-
- c = *ptr;
- if (c < '0' || c > '7')
- break;
- ptr++;
- i = (i << 3) + c - '0';
- }
- if (i != (i & result_mask))
- {
- i &= result_mask;
- cpp_pedwarn (pfile, "octal escape sequence out of range");
- }
- c = i;
- break;
- }
-
- case 'x':
- {
- unsigned int i = 0, overflow = 0;
- int digits_found = 0, digit;
- for (;;)
- {
- if (ptr >= limit)
- break;
- c = *ptr;
- if (c >= '0' && c <= '9')
- digit = c - '0';
- else if (c >= 'a' && c <= 'f')
- digit = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- digit = c - 'A' + 10;
- else
- break;
- ptr++;
- overflow |= i ^ (i << 4 >> 4);
- i = (i << 4) + digit;
- digits_found = 1;
- }
- if (!digits_found)
- cpp_error (pfile, "\\x used with no following hex digits");
- if (overflow | (i != (i & result_mask)))
- {
- i &= result_mask;
- cpp_pedwarn (pfile, "hex escape sequence out of range");
- }
- c = i;
- break;
- }
- }
- *string_ptr = ptr;
- return c;
-}
-
static void
integer_overflow (pfile)
cpp_reader *pfile;
#define FLAG_BITS 8
#define FLAG_MASK ((1 << FLAG_BITS) - 1)
#define PRIO_SHIFT (FLAG_BITS + 1)
-#define EXTRACT_PRIO(cnst) (cnst >> FLAG_BITS)
-#define EXTRACT_FLAGS(cnst) (cnst & FLAG_MASK)
+#define EXTRACT_PRIO(CNST) ((CNST) >> FLAG_BITS)
+#define EXTRACT_FLAGS(CNST) ((CNST) & FLAG_MASK)
/* Flags. */
#define HAVE_VALUE (1 << 0)
#define OR_PRIO (8 << PRIO_SHIFT)
#define XOR_PRIO (9 << PRIO_SHIFT)
#define AND_PRIO (10 << PRIO_SHIFT)
-#define EQUAL_PRIO (11 << PRIO_SHIFT)
-#define LESS_PRIO (12 << PRIO_SHIFT)
-#define SHIFT_PRIO (13 << PRIO_SHIFT)
-#define PLUS_PRIO (14 << PRIO_SHIFT)
-#define MUL_PRIO (15 << PRIO_SHIFT)
-#define UNARY_PRIO ((16 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
+#define MINMAX_PRIO (11 << PRIO_SHIFT)
+#define EQUAL_PRIO (12 << PRIO_SHIFT)
+#define LESS_PRIO (13 << PRIO_SHIFT)
+#define SHIFT_PRIO (14 << PRIO_SHIFT)
+#define PLUS_PRIO (15 << PRIO_SHIFT)
+#define MUL_PRIO (16 << PRIO_SHIFT)
+#define UNARY_PRIO ((17 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
/* Operator to priority map. Must be in the same order as the first
N entries of enum cpp_ttype. */
/* XOR */ XOR_PRIO,
/* RSHIFT */ SHIFT_PRIO,
/* LSHIFT */ SHIFT_PRIO,
+ /* MIN */ MINMAX_PRIO, /* C++ specific */
+ /* MAX */ MINMAX_PRIO, /* extensions */
/* COMPL */ UNARY_PRIO,
/* AND_AND */ ANDAND_PRIO,
#define BITWISE(OP) \
top->value = v1 OP v2; \
top->unsignedp = unsigned1 | unsigned2;
+#define MINMAX(OP) \
+ top->value = (v1 OP v2) ? v1 : v2; \
+ top->unsignedp = unsigned1 | unsigned2;
#define UNARY(OP) \
top->value = OP v2; \
top->unsignedp = unsigned2; \
struct op init_stack[INIT_STACK_SIZE];
struct op *stack = init_stack;
struct op *limit = stack + INIT_STACK_SIZE;
- register struct op *top = stack + 1;
+ struct op *top = stack + 1;
int skip_evaluation = 0;
int result;
+ unsigned int lex_count, saw_leading_not;
- /* Save parser state and set it to something sane. */
- int save_skipping = pfile->skipping;
- pfile->skipping = 0;
+ /* Set up detection of #if ! defined(). */
+ pfile->mi_ind_cmacro = 0;
+ saw_leading_not = 0;
+ lex_count = 0;
/* We've finished when we try to reduce this. */
top->op = CPP_EOF;
/* Read a token */
op = lex (pfile, skip_evaluation);
+ 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
case CPP_ERROR:
goto syntax_error;
push_immediate:
- case CPP_INT:
+ case CPP_NUMBER:
/* Push a value onto the stack. */
if (top->flags & HAVE_VALUE)
SYNTAX_ERROR ("missing binary operator");
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 */
SYNTAX_ERROR ("void expression between '(' and ')'");
else
SYNTAX_ERROR2 ("operator '%s' has no right operand",
- _cpp_spell_operator (top->op));
+ op_as_text (pfile, top->op));
}
unsigned2 = top->unsignedp, v2 = top->value;
switch (top[1].op)
{
default:
- cpp_ice (pfile, "impossible operator type %s",
- _cpp_spell_operator (op.op));
+ cpp_ice (pfile, "impossible operator '%s'",
+ op_as_text (pfile, top[1].op));
goto syntax_error;
case CPP_NOT: UNARY(!); break;
case CPP_OR: BITWISE(|); break;
case CPP_LSHIFT: SHIFT(left_shift, right_shift); break;
case CPP_RSHIFT: SHIFT(right_shift, left_shift); break;
+ case CPP_MIN: MINMAX(<); break;
+ case CPP_MAX: MINMAX(>); break;
case CPP_PLUS:
if (!(top->flags & HAVE_VALUE))
top->value = v2;
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
+
+ if (CPP_WTRADITIONAL (pfile))
+ cpp_warning (pfile,
+ "traditional C rejects the unary plus operator");
}
else
{
{
if (top->flags & HAVE_VALUE)
SYNTAX_ERROR2 ("missing binary operator before '%s'",
- _cpp_spell_operator (op.op));
+ op_as_text (pfile, op.op));
}
else
{
if (!(top->flags & HAVE_VALUE))
SYNTAX_ERROR2 ("operator '%s' has no left operand",
- _cpp_spell_operator (op.op));
+ op_as_text (pfile, op.op));
}
/* Check for and handle stack overflow. */
}
done:
+ /* The controlling macro expression is only valid if we called lex 3
+ times: <!> <defined expression> and <EOF>. push_conditional ()
+ checks that we are at top-of-file. */
+ if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
+ pfile->mi_ind_cmacro = 0;
+
result = (top[1].value != 0);
+
if (top != stack)
CPP_ICE ("unbalanced stack in #if");
else if (!(top[1].flags & HAVE_VALUE))
/* Free dynamic stack if we allocated one. */
if (stack != init_stack)
free (stack);
- pfile->skipping = save_skipping;
return result;
}
+
+static const unsigned char *
+op_as_text (pfile, op)
+ cpp_reader *pfile;
+ enum cpp_ttype op;
+{
+ cpp_token token;
+
+ token.type = op;
+ token.flags = 0;
+ return cpp_token_as_text (pfile, &token);
+}