OSDN Git Service

* doc/fragments.texi, doc/trouble.texi: Remove links to old
[pf3gnuchains/gcc-fork.git] / gcc / cppexp.c
index 18f494f..f7fe054 100644 (file)
@@ -1,5 +1,6 @@
 /* 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
@@ -17,53 +18,11 @@ along with this program; if not, write to the Free Software
 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)
@@ -76,12 +35,9 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
                                            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
 {
@@ -105,32 +61,34 @@ 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;
@@ -171,14 +129,9 @@ parse_number (pfile, tok)
     {
       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;
 
@@ -218,8 +171,13 @@ parse_number (pfile, tok)
        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)
@@ -237,7 +195,7 @@ parse_number (pfile, tok)
     }
 
   op.value = n;
-  op.op = CPP_INT;
+  op.op = CPP_NUMBER;
   return op;
 
  invalid_suffix:
@@ -248,140 +206,75 @@ parse_number (pfile, tok)
   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_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 (pfile->context != initial_context)
+       cpp_warning (pfile, "this use of \"defined\" may not be portable");
 
-  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;
-}
-
-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)
@@ -389,163 +282,96 @@ lex (pfile, skip_evaluation)
      int skip_evaluation;
 {
   struct op op;
-  const cpp_token *tok;
+  const cpp_token *token = cpp_get_token (pfile);
 
- retry:
-  tok = _cpp_get_token (pfile);
-
-  switch (tok->type)
+  switch (token->type)
     {
-    case CPP_PLACEMARKER:
-      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);
-
-    case CPP_DEFINED:
-      return parse_defined (pfile);
+       SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
 
     case CPP_NAME:
-      op.op = CPP_INT;
-      op.unsignedp = 0;
-      op.value = 0;
+      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;
 
-      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", TOKEN_NAME (tok));
-  }
+      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;
@@ -626,8 +452,8 @@ be handled with operator-specific code.  */
 #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)
@@ -722,8 +548,6 @@ op_to_prio[] =
 /* Parse and evaluate a C expression, reading from PFILE.
    Returns the truth value of the expression.  */
 
-#define TYPE_NAME(t) _cpp_token_spellings[t].name
-
 int
 _cpp_parse_expr (pfile)
      cpp_reader *pfile;
@@ -742,13 +566,15 @@ _cpp_parse_expr (pfile)
   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;
@@ -765,6 +591,7 @@ _cpp_parse_expr (pfile)
 
       /* 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
@@ -774,7 +601,7 @@ _cpp_parse_expr (pfile)
        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");
@@ -784,6 +611,11 @@ _cpp_parse_expr (pfile)
          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 */
@@ -810,7 +642,7 @@ _cpp_parse_expr (pfile)
                SYNTAX_ERROR ("void expression between '(' and ')'");
              else
                SYNTAX_ERROR2 ("operator '%s' has no right operand",
-                              TYPE_NAME (top->op));
+                              op_as_text (pfile, top->op));
            }
 
          unsigned2 = top->unsignedp, v2 = top->value;
@@ -821,7 +653,8 @@ _cpp_parse_expr (pfile)
          switch (top[1].op)
            {
            default:
-             cpp_ice (pfile, "impossible operator type %s", TYPE_NAME (op.op));
+             cpp_ice (pfile, "impossible operator '%s'",
+                              op_as_text (pfile, top[1].op));
              goto syntax_error;
 
            case CPP_NOT:        UNARY(!);      break;
@@ -980,13 +813,13 @@ _cpp_parse_expr (pfile)
        {
          if (top->flags & HAVE_VALUE)
            SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          TYPE_NAME (op.op));
+                          op_as_text (pfile, op.op));
        }
       else
        {
          if (!(top->flags & HAVE_VALUE))
            SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          TYPE_NAME (op.op));
+                          op_as_text (pfile, op.op));
        }
 
       /* Check for and handle stack overflow.  */
@@ -1014,7 +847,14 @@ _cpp_parse_expr (pfile)
     }
 
  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))
@@ -1027,6 +867,17 @@ _cpp_parse_expr (pfile)
   /* 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);
+}