OSDN Git Service

2001-05-03 David O'Brien <obrien@FreeBSD.org>
[pf3gnuchains/gcc-fork.git] / gcc / cppexp.c
index 5f141e2..1231a7e 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
@@ -24,22 +25,6 @@ Boston, MA 02111-1307, USA.  */
 #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
@@ -78,10 +63,10 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, 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 struct op lex PARAMS ((cpp_reader *, int, cpp_token *));
+static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
 
 struct op
 {
@@ -193,7 +178,7 @@ parse_number (pfile, tok)
     {
       /* 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] == '-'))
@@ -218,8 +203,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)
@@ -259,7 +249,8 @@ parse_charconst (pfile, tok)
   HOST_WIDEST_INT result = 0;
   int num_chars = 0;
   int num_bits;
-  unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK;
+  unsigned int width = MAX_CHAR_TYPE_SIZE;
+  HOST_WIDEST_INT 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;
@@ -298,13 +289,13 @@ parse_charconst (pfile, tok)
     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))
+  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
+  if (pfile->spec_nodes.n__CHAR_UNSIGNED__->type == NT_MACRO
       || ((result >> (num_bits - 1)) & 1) == 0)
     op.value = result & ((unsigned HOST_WIDEST_INT) ~0
                         >> (HOST_BITS_PER_WIDEST_INT - num_bits));
@@ -326,86 +317,95 @@ static struct op
 parse_defined (pfile)
      cpp_reader *pfile;
 {
-  int paren;
-  const cpp_token *tok;
+  int paren = 0;
+  cpp_hashnode *node = 0;
+  cpp_token token;
   struct op op;
 
-  paren = 0;
-  tok = _cpp_get_raw_token (pfile);
-  if (tok->type == CPP_OPEN_PAREN)
+  /* Don't expand macros.  */
+  pfile->state.prevent_expansion++;
+
+  cpp_get_token (pfile, &token);
+  if (token.type == CPP_OPEN_PAREN)
     {
       paren = 1;
-      tok = _cpp_get_raw_token (pfile);
+      cpp_get_token (pfile, &token);
     }
 
-  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;
-}
-
-static struct op
-parse_assertion (pfile)
-     cpp_reader *pfile;
-{
-  struct op op;
-  struct answer *answer;
-  cpp_hashnode *hp;
+  if (token.type == CPP_NAME)
+    {
+      node = token.val.node;
+      if (paren)
+       {
+         cpp_get_token (pfile, &token);
+         if (token.type != CPP_CLOSE_PAREN)
+           {
+             cpp_error (pfile, "missing ')' after \"defined\"");
+             node = 0;
+           }
+       }
+    }
+  else
+    {
+      cpp_error (pfile, "operator \"defined\" requires an identifier");
+      if (token.flags & NAMED_OP)
+       {
+         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));
+       }
+    }
 
-  op.op = CPP_ERROR;
-  hp = _cpp_parse_assertion (pfile, &answer);
-  if (hp)
+  if (!node)
+    op.op = CPP_ERROR;
+  else
     {
-      /* 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_INT;
 
-      if (answer)
-       FREE_ANSWER (answer);
+      /* No macros?  At top of file?  */
+      if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0
+         && pfile->mi_if_not_defined == MI_IND_NOT && pfile->mi_lexed == 1)
+       {
+         cpp_start_lookahead (pfile);
+         cpp_get_token (pfile, &token);
+         if (token.type == CPP_EOF)
+           pfile->mi_ind_cmacro = node;
+         cpp_stop_lookahead (pfile, 0);
+       }
     }
+
+  pfile->state.prevent_expansion--;
   return op;
 }
 
 /* Read one token.  */
 
 static struct op
-lex (pfile, skip_evaluation)
+lex (pfile, skip_evaluation, token)
      cpp_reader *pfile;
      int skip_evaluation;
+     cpp_token *token;
 {
   struct op op;
-  const cpp_token *tok;
 
- retry:
-  tok = _cpp_get_token (pfile);
+  cpp_get_token (pfile, token);
 
-  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);
+      return parse_charconst (pfile, token);
 
     case CPP_STRING:
     case CPP_WSTRING:
@@ -415,37 +415,79 @@ lex (pfile, skip_evaluation)
       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)
-       return parse_defined (pfile);
+      if (token->val.node == pfile->spec_nodes.n_defined)
+       {
+         if (pfile->context->prev && CPP_PEDANTIC (pfile))
+           cpp_pedwarn (pfile, "\"defined\" operator appears during macro expansion");
 
-      op.op = CPP_INT;
-      op.unsignedp = 0;
-      op.value = 0;
+         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_INT;
+         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",
+                        token->val.node->name);
+         return op;
+       }
+      else
+       {
+         /* Controlling #if expressions cannot contain identifiers (they
+            could become macros in the future).  */
+         pfile->mi_state = MI_FAILED;
 
-      if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
-       cpp_warning (pfile, "\"%s\" is not defined", tok->val.node->name);
-      return op;
+         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", token->val.node->name);
+         return op;
+       }
 
     case CPP_HASH:
-      return parse_assertion (pfile);
+      {
+       int temp;
+
+       op.op = CPP_INT;
+       if (_cpp_test_assertion (pfile, &temp))
+         op.op = CPP_ERROR;
+       op.unsignedp = 0;
+       op.value = temp;
+       return op;
+      }
+
+    case CPP_NOT:
+      /* We don't worry about its position here.  */
+      pfile->mi_if_not_defined = MI_IND_NOT;
+      /* Fall through.  */
 
     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;
@@ -650,12 +692,13 @@ be handled with operator-specific code.  */
 #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.  */
@@ -676,6 +719,8 @@ op_to_prio[] =
   /* 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,
@@ -702,6 +747,9 @@ op_to_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; \
@@ -736,13 +784,14 @@ _cpp_parse_expr (pfile)
   struct op init_stack[INIT_STACK_SIZE];
   struct op *stack = init_stack;
   struct op *limit = stack + INIT_STACK_SIZE;
+  cpp_token token;
   register struct op *top = stack + 1;
   int skip_evaluation = 0;
   int result;
 
-  /* 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_lexed = 0;
+  pfile->mi_if_not_defined = MI_IND_NONE;
 
   /* We've finished when we try to reduce this.  */
   top->op = CPP_EOF;
@@ -758,7 +807,8 @@ _cpp_parse_expr (pfile)
       struct op op;
 
       /* Read a token */
-      op = lex (pfile, skip_evaluation);
+      op = lex (pfile, skip_evaluation, &token);
+      pfile->mi_lexed++;
 
       /* If the token is an operand, push its value and get next
         token.  If it is an operator, get its priority and flags, and
@@ -804,7 +854,7 @@ _cpp_parse_expr (pfile)
                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;
@@ -815,8 +865,8 @@ _cpp_parse_expr (pfile)
          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;
@@ -832,6 +882,8 @@ _cpp_parse_expr (pfile)
            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))
@@ -842,6 +894,10 @@ _cpp_parse_expr (pfile)
                  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
                {
@@ -969,13 +1025,13 @@ _cpp_parse_expr (pfile)
        {
          if (top->flags & HAVE_VALUE)
            SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          _cpp_spell_operator (op.op));
+                          op_as_text (pfile, top->op));
        }
       else
        {
          if (!(top->flags & HAVE_VALUE))
            SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          _cpp_spell_operator (op.op));
+                          op_as_text (pfile, top->op));
        }
 
       /* Check for and handle stack overflow.  */
@@ -1016,6 +1072,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);
+}