cppexp.c (lex): Update to use state.skip_eval.
authorNeil Booth <neil@daikokuya.demon.co.uk>
Sun, 28 Apr 2002 19:42:54 +0000 (19:42 +0000)
committerNeil Booth <neil@gcc.gnu.org>
Sun, 28 Apr 2002 19:42:54 +0000 (19:42 +0000)
* cppexp.c (lex): Update to use state.skip_eval.
(struct op): Remove prio and flags members.
(FLAG_BITS, FLAG_MASK, PRIO_SHIFT, EXTRACT_PRIO, EXTRACT_FLAGS,
SHORT_CIRCUIT, RIGHT_ASSOC, ..._PRIO, op_to_prio): Remove.
(LEFT_ASSOC): New macro.
(optab): New table of operator priorities and flags.
(SHIFT): Update.
(_cpp_parse_expr): Clean up logic.  Return bool.  Use a
malloc-ed parser stack.
(reduce): New; reduce the operator stack.
(_cpp_expand_op_stack): Expand the operator stack as necessary.
* cpphash.h (struct op): Predeclare.
(struct cpp_reader): New members op_stack, op_limit.
(struct lexer_state): New member skip_eval.
(_cpp_parse_expr): Update.
(_cpp_expand_op_stack): New.
* cpplib.c (do_if): Update.
* cppinit.c (cpp_create_reader): Create op stack.
(cpp_destroy): And destroy it.
* cpplib.h (CPP_LAST_CPP_OP): Correct.
(TTYPE_TABLE): Correct.
testsuite:
* gcc.dg/cpp/if-mop.c: Update.
* gcc.dg/cpp/if-mpar.c: Add test.
* gcc.dg/cpp/if-oppr.c: Update.

From-SVN: r52853

gcc/ChangeLog
gcc/cppexp.c
gcc/cpphash.h
gcc/cppinit.c
gcc/cpplib.c
gcc/cpplib.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/if-mop.c
gcc/testsuite/gcc.dg/cpp/if-mpar.c
gcc/testsuite/gcc.dg/cpp/if-oppr.c

index 4b62c60f3af380d9746f8134a6a6b20bc00e043e..728e9ff7510a958fc7276e1e71d83571176cbed6 100644 (file)
@@ -1,3 +1,27 @@
+2002-04-28  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * cppexp.c (lex): Update to use state.skip_eval.
+       (struct op): Remove prio and flags members.
+       (FLAG_BITS, FLAG_MASK, PRIO_SHIFT, EXTRACT_PRIO, EXTRACT_FLAGS,
+       SHORT_CIRCUIT, RIGHT_ASSOC, ..._PRIO, op_to_prio): Remove.
+       (LEFT_ASSOC): New macro.
+       (optab): New table of operator priorities and flags.
+       (SHIFT): Update.
+       (_cpp_parse_expr): Clean up logic.  Return bool.  Use a
+       malloc-ed parser stack.
+       (reduce): New; reduce the operator stack.
+       (_cpp_expand_op_stack): Expand the operator stack as necessary.
+       * cpphash.h (struct op): Predeclare.
+       (struct cpp_reader): New members op_stack, op_limit.
+       (struct lexer_state): New member skip_eval.
+       (_cpp_parse_expr): Update.
+       (_cpp_expand_op_stack): New.
+       * cpplib.c (do_if): Update.
+       * cppinit.c (cpp_create_reader): Create op stack.
+       (cpp_destroy): And destroy it.
+       * cpplib.h (CPP_LAST_CPP_OP): Correct.
+       (TTYPE_TABLE): Correct.
+
 2002-04-28  Franz Sirl  <Franz.Sirl-kernel@lauterbach.com>
 
        PR c/6343
index e3756d7f23e700bfbe6b52d1e1d87f543022eba6..29a261105e8b6862167d609e631cdf7a7ad10558 100644 (file)
@@ -36,14 +36,13 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
                                            unsigned HOST_WIDEST_INT));
 static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
 static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op lex PARAMS ((cpp_reader *, int));
+static struct op lex PARAMS ((cpp_reader *));
 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));
 
 struct op
 {
   enum cpp_ttype op;
-  uchar prio;         /* Priority of op.  */
-  uchar flags;
   uchar unsignedp;    /* True if value should be treated as unsigned.  */
   HOST_WIDEST_INT value; /* The value logically "right" of op.  */
 };
@@ -281,9 +280,8 @@ parse_defined (pfile)
    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)
+lex (pfile)
      cpp_reader *pfile;
-     int skip_evaluation;
 {
   struct op op;
   const cpp_token *token = cpp_get_token (pfile);
@@ -343,7 +341,7 @@ lex (pfile, skip_evaluation)
          op.unsignedp = 0;
          op.value = 0;
 
-         if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
+         if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
            cpp_error (pfile, DL_WARNING, "\"%s\" is not defined",
                       NODE_NAME (token->val.node));
          return op;
@@ -363,8 +361,7 @@ lex (pfile, skip_evaluation)
 
     default:
       if (((int) token->type > (int) CPP_EQ
-          && (int) token->type < (int) CPP_PLUS_EQ)
-         || token->type == CPP_EOF)
+          && (int) token->type < (int) CPP_PLUS_EQ))
        {
          op.op = token->type;
          return op;
@@ -435,100 +432,69 @@ right_shift (pfile, a, unsignedp, b)
 /* Operator precedence and flags table.
 
 After an operator is returned from the lexer, if it has priority less
-than or equal to the operator on the top of the stack, we reduce the
-stack by one operator and repeat the test.  Since equal priorities
-reduce, this is naturally left-associative.
-
-We handle right-associative operators by clearing the lower bit of all
-left-associative operators, and setting it for right-associative ones.
-After the reduction phase of a new operator, just before it is pushed
-onto the stack, its RIGHT_ASSOC bit is cleared.  The effect is that
-during the reduction phase, the current right-associative operator has
-a priority one greater than any other operator of otherwise equal
-precedence that has been pushed on the top of the stack.  This avoids
-a reduction pass, and effectively makes the logic right-associative.
+than the operator on the top of the stack, we reduce the stack by one
+operator and repeat the test.  Since equal priorities do not reduce,
+this is naturally right-associative.
+
+We handle left-associative operators by decrementing the priority of
+just-lexed operators by one, but retaining the priority of operators
+already on the stack.
 
 The remaining cases are '(' and ')'.  We handle '(' by skipping the
 reduction phase completely.  ')' is given lower priority than
 everything else, including '(', effectively forcing a reduction of the
-parenthesised expression.  If there is no matching '(', the stack will
-be reduced all the way to the beginning, exiting the parser in the
-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.
+parenthesised expression.  If there is a matching '(', the routine
+reduce() exits immediately.  If the normal exit route sees a ')', then
+there cannot have been a matching '(' and an error message is output.
 
 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)
-#define PRIO_SHIFT (FLAG_BITS + 1)
-#define EXTRACT_PRIO(CNST) ((CNST) >> FLAG_BITS)
-#define EXTRACT_FLAGS(CNST) ((CNST) & FLAG_MASK)
-
 /* Flags.  */
-#define NO_L_OPERAND   (1 << 0)
-#define SHORT_CIRCUIT  (1 << 1)
-
-/* Priority and flag combinations.  */
-#define RIGHT_ASSOC         (1 << FLAG_BITS)
-#define FORCE_REDUCE_PRIO   (0 << PRIO_SHIFT)
-#define CLOSE_PAREN_PRIO    (1 << PRIO_SHIFT)
-#define OPEN_PAREN_PRIO    ((2 << PRIO_SHIFT) | NO_L_OPERAND)
-#define COMMA_PRIO          (3 << PRIO_SHIFT)
-#define COND_PRIO          ((4 << PRIO_SHIFT) | RIGHT_ASSOC | SHORT_CIRCUIT)
-#define COLON_PRIO         ((5 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OROR_PRIO          ((6 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define ANDAND_PRIO        ((7 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OR_PRIO             (8 << PRIO_SHIFT)
-#define XOR_PRIO            (9 << PRIO_SHIFT)
-#define AND_PRIO           (10 << PRIO_SHIFT)
-#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)
+#define NO_L_OPERAND   (1 << 0)
+#define LEFT_ASSOC     (1 << 1)
 
 /* Operator to priority map.  Must be in the same order as the first
    N entries of enum cpp_ttype.  */
-static const short
-op_to_prio[] =
+static const struct operator
+{
+  uchar prio;                  /* Priorities are even.  */
+  uchar flags;
+} optab[] =
 {
-  /* EQ */             0,              /* dummy entry - can't happen */
-  /* NOT */            UNARY_PRIO,
-  /* GREATER */                LESS_PRIO,
-  /* LESS */           LESS_PRIO,
-  /* PLUS */           PLUS_PRIO,
-  /* MINUS */          PLUS_PRIO,
-  /* MULT */           MUL_PRIO,
-  /* DIV */            MUL_PRIO,
-  /* MOD */            MUL_PRIO,
-  /* AND */            AND_PRIO,
-  /* OR */             OR_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,
-  /* OR_OR */          OROR_PRIO,
-  /* QUERY */          COND_PRIO,
-  /* COLON */          COLON_PRIO,
-  /* COMMA */          COMMA_PRIO,
-  /* OPEN_PAREN */     OPEN_PAREN_PRIO,
-  /* CLOSE_PAREN */    CLOSE_PAREN_PRIO,
-  /* EQ_EQ */          EQUAL_PRIO,
-  /* NOT_EQ */         EQUAL_PRIO,
-  /* GREATER_EQ */     LESS_PRIO,
-  /* LESS_EQ */                LESS_PRIO,
-  /* EOF */            FORCE_REDUCE_PRIO,
-  /* UPLUS */          UNARY_PRIO,
-  /* UMINUS */         UNARY_PRIO
+  /* EQ */             {0, 0},         /* Shouldn't happen.  */
+  /* NOT */            {16, NO_L_OPERAND},
+  /* GREATER */                {12, LEFT_ASSOC},
+  /* LESS */           {12, LEFT_ASSOC},
+  /* PLUS */           {14, LEFT_ASSOC},
+  /* MINUS */          {14, LEFT_ASSOC},
+  /* MULT */           {15, LEFT_ASSOC},
+  /* DIV */            {15, LEFT_ASSOC},
+  /* MOD */            {15, LEFT_ASSOC},
+  /* AND */            {9, LEFT_ASSOC},
+  /* OR */             {7, LEFT_ASSOC},
+  /* XOR */            {8, LEFT_ASSOC},
+  /* RSHIFT */         {13, LEFT_ASSOC},
+  /* LSHIFT */         {13, LEFT_ASSOC},
+  /* MIN */            {10, LEFT_ASSOC},       /* C++ specific */
+  /* MAX */            {10, LEFT_ASSOC},       /* extensions */
+
+  /* COMPL */          {16, NO_L_OPERAND},
+  /* AND_AND */                {6, LEFT_ASSOC},
+  /* OR_OR */          {5, LEFT_ASSOC},
+  /* QUERY */          {3, 0},
+  /* COLON */          {4, LEFT_ASSOC},
+  /* COMMA */          {2, LEFT_ASSOC},
+  /* OPEN_PAREN */     {1, NO_L_OPERAND},
+  /* CLOSE_PAREN */    {0, 0},
+  /* EOF */            {0, 0},
+  /* EQ_EQ */          {11, LEFT_ASSOC},
+  /* NOT_EQ */         {11, LEFT_ASSOC},
+  /* GREATER_EQ */     {12, LEFT_ASSOC},
+  /* LESS_EQ */                {12, LEFT_ASSOC},
+  /* UPLUS */          {16, NO_L_OPERAND},
+  /* UMINUS */         {16, NO_L_OPERAND}
 };
 
 #define COMPARE(OP) \
@@ -549,7 +515,7 @@ op_to_prio[] =
   top->value = OP v2; \
   top->unsignedp = unsigned2;
 #define SHIFT(PSH, MSH) \
-  if (skip_evaluation)  \
+  if (pfile->state.skip_eval)  \
     break;             \
   top->unsignedp = unsigned1; \
   if (v2 < 0 && ! unsigned2)  \
@@ -558,54 +524,42 @@ op_to_prio[] =
     top->value = PSH (pfile, v1, unsigned1, v2);
 
 /* Parse and evaluate a C expression, reading from PFILE.
-   Returns the truth value of the expression.  */
-int
+   Returns the truth value of the expression.  
+
+   The implementation is an operator precedence parser, i.e. a
+   bottom-up parser, using a stack for not-yet-reduced tokens.
+
+   The stack base is op_stack, and the current stack pointer is 'top'.
+   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.  */
+bool
 _cpp_parse_expr (pfile)
      cpp_reader *pfile;
 {
-  /* The implementation is an operator precedence parser, i.e. a
-     bottom-up parser, using a stack for not-yet-reduced tokens.
-
-     The stack base is 'stack', and the current stack pointer is 'top'.
-     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.  */
-
-#define INIT_STACK_SIZE 20
-  struct op init_stack[INIT_STACK_SIZE];
-  struct op *stack = init_stack;
-  struct op *limit = stack + INIT_STACK_SIZE;
-  struct op *top = stack + 1;
-  int skip_evaluation = 0;
-  int result;
-  unsigned int lex_count, saw_leading_not;
-  bool want_value = true;
+  struct op *top = pfile->op_stack;
+  unsigned int lex_count;
+  bool saw_leading_not, want_value = true;
+
+  pfile->state.skip_eval = 0;
 
   /* Set up detection of #if ! defined().  */
   pfile->mi_ind_cmacro = 0;
-  saw_leading_not = 0;
+  saw_leading_not = false;
   lex_count = 0;
 
-  /* We've finished when we try to reduce this.  */
+  /* Lowest priority operator prevents further reductions.  */
   top->op = CPP_EOF;
-  /* Nifty way to catch missing '('.  */
-  top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
 
   for (;;)
     {
-      unsigned int prio;
-      unsigned int flags;
       struct op op;
 
       /* Read a token */
-      op = lex (pfile, skip_evaluation);
+      op = lex (pfile);
       lex_count++;
 
-      /* If the token is an operand, push its value and get next
-        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:
@@ -614,7 +568,6 @@ _cpp_parse_expr (pfile)
          /* Push a value onto the stack.  */
          if (!want_value)
            SYNTAX_ERROR ("missing binary operator");
-       push_immediate:
          want_value = false;
          top->value = op.value;
          top->unsignedp = op.unsignedp;
@@ -635,244 +588,266 @@ _cpp_parse_expr (pfile)
          break;
        }
 
-      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.  */
-      while (prio <= top->prio)
+      /* Check we have a value or operator as appropriate.  */
+      if (optab[op.op].flags & NO_L_OPERAND)
        {
-         HOST_WIDEST_INT v1, v2;
-         unsigned int unsigned1, unsigned2;
-         
-         /* Most operators that can appear on the stack require a
-            right operand.  Check this before trying to reduce.  */
-         if (want_value)
+         if (!want_value)
+           SYNTAX_ERROR2 ("missing binary operator before '%s'",
+                          op_as_text (pfile, op.op));
+       }
+      else if (want_value)
+       {
+         if (op.op == CPP_CLOSE_PAREN)
            {
              if (top->op == CPP_OPEN_PAREN)
                SYNTAX_ERROR ("void expression between '(' and ')'");
-             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;
-         top--;
-         unsigned1 = top->unsignedp, v1 = top->value;
-
-         /* Now set top->value = (top[1].op)(v1, v2); */
-         switch (top[1].op)
-           {
-           default:
-             cpp_error (pfile, DL_ICE, "impossible operator '%s'",
-                        op_as_text (pfile, top[1].op));
-             goto syntax_error;
-
-           case CPP_NOT:        UNARY(!);      break;
-           case CPP_COMPL:      UNARY(~);      break;
-           case CPP_LESS:       COMPARE(<);    break;
-           case CPP_GREATER:    COMPARE(>);    break;
-           case CPP_LESS_EQ:    COMPARE(<=);   break;
-           case CPP_GREATER_EQ: COMPARE(>=);   break;
-           case CPP_EQ_EQ:      EQUALITY(==);  break;
-           case CPP_NOT_EQ:     EQUALITY(!=);  break;
-           case CPP_AND:        BITWISE(&);    break;
-           case CPP_XOR:        BITWISE(^);    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_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;
-
-           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:
-             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;
-             if (top->unsignedp)
-               top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
-             else if (!skip_evaluation)
-               {
-                 top->value = v1 * v2;
-                 if (v1 && (top->value / v1 != v2
-                            || (top->value & v1 & v2) < 0))
-                   integer_overflow (pfile);
-               }
-             break;
-           case CPP_DIV:
-           case CPP_MOD:
-             if (skip_evaluation)
-               break;
-             if (v2 == 0)
-               SYNTAX_ERROR ("division by zero in #if");
-             top->unsignedp = unsigned1 | unsigned2;
-             if (top[1].op == CPP_DIV)
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
-                 else
-                   {
-                     top->value = v1 / v2;
-                     if ((top->value & v1 & v2) < 0)
-                       integer_overflow (pfile);
-                   }
-               }
-             else
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
-                 else
-                   top->value = v1 % v2;
-               }
-             break;
-
-           case CPP_OR_OR:
-             top->value = v1 || v2;
-             top->unsignedp = 0;
-             if (v1) skip_evaluation--;
-             break;
-           case CPP_AND_AND:
-             top->value = v1 && v2;
-             top->unsignedp = 0;
-             if (!v1) skip_evaluation--;
-             break;
-           case CPP_COMMA:
-             if (CPP_PEDANTIC (pfile))
-               cpp_error (pfile, DL_PEDWARN,
-                          "comma operator in operand of #if");
-             top->value = v2;
-             top->unsignedp = unsigned2;
-             break;
-           case CPP_QUERY:
-             SYNTAX_ERROR ("syntax error '?' without following ':'");
-           case CPP_COLON:
-             if (top[0].op != CPP_QUERY)
-               SYNTAX_ERROR ("syntax error ':' without preceding '?'");
-             top--;
-             if (top->value) skip_evaluation--;
-             top->value = top->value ? v1 : v2;
-             top->unsignedp = unsigned1 | unsigned2;
-             break;
-           case CPP_OPEN_PAREN:
-             if (op.op != CPP_CLOSE_PAREN)
-               SYNTAX_ERROR ("missing ')' in expression");
-             op.value = v2;
-             op.unsignedp = unsigned2;
-             goto push_immediate;
-           case CPP_EOF:
-             /* Reducing this dummy operator indicates we've finished.  */
-             if (op.op == CPP_CLOSE_PAREN)
-               SYNTAX_ERROR ("missing '(' in expression");
-             goto done;
            }
+         else if (top->op == CPP_EOF)
+           SYNTAX_ERROR ("#if with no expression");
+         if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
+           SYNTAX_ERROR2 ("operator '%s' has no right operand",
+                          op_as_text (pfile, top->op));
        }
 
-      /* Handle short-circuit evaluations.  */
-      if (flags & SHORT_CIRCUIT)
-       switch (op.op)
-         {
-         case CPP_OR_OR:    if (top->value) skip_evaluation++; break;
-         case CPP_AND_AND:
-         case CPP_QUERY:    if (!top->value) skip_evaluation++; break;
-         case CPP_COLON:
-           if (top[-1].value) /* Was '?' condition true?  */
-             skip_evaluation++;
-           else
-             skip_evaluation--;
-         default:
-           break;
-         }
+      top = reduce (pfile, top, op.op);
+      if (!top)
+       goto syntax_error;
 
-    skip_reduction:
-      /* Check we have a left operand iff we need one.  */
-      if (flags & NO_L_OPERAND)
-       {
-         if (!want_value)
-           SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          op_as_text (pfile, op.op));
-       }
-      else
+      switch (op.op)
        {
-         if (want_value)
-           SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          op_as_text (pfile, op.op));
+       case CPP_CLOSE_PAREN:
+         continue;
+       case CPP_EOF:
+         goto done;
+       case CPP_OR_OR:
+         if (top->value)
+           pfile->state.skip_eval++;
+         break;
+       case CPP_AND_AND:
+       case CPP_QUERY:
+         if (!top->value)
+           pfile->state.skip_eval++;
+         break;
+       case CPP_COLON:
+         if (top[-1].value) /* Was '?' condition true?  */
+           pfile->state.skip_eval++;
+         else
+           pfile->state.skip_eval--;
+       default:
+         break;
        }
+
       want_value = true;
 
       /* Check for and handle stack overflow.  */
-      top++;
-      if (top == limit)
-       {
-         struct op *new_stack;
-         int old_size = (char *) limit - (char *) stack;
-         int new_size = 2 * old_size;
-         if (stack != init_stack)
-           new_stack = (struct op *) xrealloc (stack, new_size);
-         else
-           {
-             new_stack = (struct op *) xmalloc (new_size);
-             memcpy (new_stack, stack, old_size);
-           }
-         stack = new_stack;
-         top = (struct op *) ((char *) new_stack + old_size);
-         limit = (struct op *) ((char *) new_stack + new_size);
-       }
+      if (++top == pfile->op_limit)
+       top = _cpp_expand_op_stack (pfile);
       
-      top->flags = flags;
-      top->prio = prio & ~EXTRACT_PRIO(RIGHT_ASSOC);
       top->op = op.op;
     }
 
- done:
+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)
+  if (top != pfile->op_stack)
     {
       cpp_error (pfile, DL_ICE, "unbalanced stack in #if");
     syntax_error:
-      result = 0;  /* Return 0 on syntax error.  */
+      return false;  /* Return false on syntax error.  */
     }
 
-  /* Free dynamic stack if we allocated one.  */
-  if (stack != init_stack)
-    free (stack);
-  return result;
+  return top->value != 0;
+}
+
+/* Reduce the operator / value stack if possible, in preparation for
+   pushing operator OP.  Returns NULL on error, otherwise the top of
+   the stack.  */
+static struct op *
+reduce (pfile, top, op)
+     cpp_reader *pfile;
+     struct op *top;
+     enum cpp_ttype op;
+{
+  unsigned int prio;
+
+  if (op == CPP_OPEN_PAREN)
+    return top;
+
+  /* Decrement the priority of left-associative operators to force a
+     reduction with operators of otherwise equal priority.  */
+  prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
+  while (prio < optab[top->op].prio)
+    {
+      HOST_WIDEST_INT v1, v2;
+      unsigned int unsigned1, unsigned2;
+
+      unsigned2 = top->unsignedp, v2 = top->value;
+      top--;
+      unsigned1 = top->unsignedp, v1 = top->value;
+
+      /* Now set top->value = (top[1].op)(v1, v2); */
+      switch (top[1].op)
+       {
+       default:
+         cpp_error (pfile, DL_ICE, "impossible operator '%s'",
+                    op_as_text (pfile, top[1].op));
+         return 0;
+
+       case CPP_NOT:    UNARY(!);      break;
+       case CPP_COMPL:  UNARY(~);      break;
+       case CPP_LESS:   COMPARE(<);    break;
+       case CPP_GREATER: COMPARE(>);   break;
+       case CPP_LESS_EQ: COMPARE(<=);  break;
+       case CPP_GREATER_EQ: COMPARE(>=); break;
+       case CPP_EQ_EQ:  EQUALITY(==);  break;
+       case CPP_NOT_EQ: EQUALITY(!=);  break;
+       case CPP_AND:    BITWISE(&);    break;
+       case CPP_XOR:    BITWISE(^);    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_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 (!pfile->state.skip_eval && (top->value & v2) < 0 && !unsigned2)
+           integer_overflow (pfile);
+         break;
+
+       case CPP_PLUS:
+         top->value = v1 + v2;
+         top->unsignedp = unsigned1 | unsigned2;
+         if (! top->unsignedp && ! pfile->state.skip_eval
+             && ! possible_sum_sign (v1, v2, top->value))
+           integer_overflow (pfile);
+         break;
+       case CPP_MINUS:
+         top->value = v1 - v2;
+         top->unsignedp = unsigned1 | unsigned2;
+         if (! top->unsignedp && ! pfile->state.skip_eval
+             && ! possible_sum_sign (top->value, v2, v1))
+           integer_overflow (pfile);
+         break;
+       case CPP_MULT:
+         top->unsignedp = unsigned1 | unsigned2;
+         if (top->unsignedp)
+           top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
+         else if (!pfile->state.skip_eval)
+           {
+             top->value = v1 * v2;
+             if (v1 && (top->value / v1 != v2
+                        || (top->value & v1 & v2) < 0))
+               integer_overflow (pfile);
+           }
+         break;
+       case CPP_DIV:
+       case CPP_MOD:
+         if (pfile->state.skip_eval)
+           break;
+         if (v2 == 0)
+           {
+             cpp_error (pfile, DL_ERROR, "division by zero in #if");
+             return 0;
+           }
+         top->unsignedp = unsigned1 | unsigned2;
+         if (top[1].op == CPP_DIV)
+           {
+             if (top->unsignedp)
+               top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
+             else
+               {
+                 top->value = v1 / v2;
+                 if ((top->value & v1 & v2) < 0)
+                   integer_overflow (pfile);
+               }
+           }
+         else
+           {
+             if (top->unsignedp)
+               top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
+             else
+               top->value = v1 % v2;
+           }
+         break;
+
+       case CPP_OR_OR:
+         top->value = v1 || v2;
+         top->unsignedp = 0;
+         if (v1) pfile->state.skip_eval--;
+         break;
+       case CPP_AND_AND:
+         top->value = v1 && v2;
+         top->unsignedp = 0;
+         if (!v1) pfile->state.skip_eval--;
+         break;
+       case CPP_COMMA:
+         if (CPP_PEDANTIC (pfile))
+           cpp_error (pfile, DL_PEDWARN,
+                      "comma operator in operand of #if");
+         top->value = v2;
+         top->unsignedp = unsigned2;
+         break;
+       case CPP_QUERY:
+         cpp_error (pfile, DL_ERROR, "'?' without following ':'");
+         return 0;
+       case CPP_COLON:
+         if (top->op != CPP_QUERY)
+           {
+             cpp_error (pfile, DL_ERROR, " ':' without preceding '?'");
+             return 0;
+           }
+         top--;
+         if (top->value) pfile->state.skip_eval--;
+         top->value = top->value ? v1 : v2;
+         top->unsignedp = unsigned1 | unsigned2;
+         break;
+       case CPP_OPEN_PAREN:
+         if (op != CPP_CLOSE_PAREN)
+           {
+             cpp_error (pfile, DL_ERROR, "missing ')' in expression");
+             return 0;
+           }
+         top->value = v2;
+         top->unsignedp = unsigned2;
+         return top;
+       }
+    }
+
+  if (op == CPP_CLOSE_PAREN)
+    {
+      cpp_error (pfile, DL_ERROR, "missing '(' in expression");
+      return 0;
+    }
+
+  return top;
+}
+
+/* Returns the position of the old top of stack after expansion.  */
+struct op *
+_cpp_expand_op_stack (pfile)
+     cpp_reader *pfile;
+{
+  size_t n = (size_t) (pfile->op_limit - pfile->op_stack);
+
+  pfile->op_stack = (struct op *) xrealloc (pfile->op_stack,
+                                           (n * 2 + 20) * sizeof (struct op));
+
+  return pfile->op_stack + n;
 }
 
 /* Output OP as text for diagnostics.  */
index 773c3cc954f70b394bce7873aabd90ab5147901c..743feeae89c9575ac5927dd97ef46f2da5eb8cb7 100644 (file)
@@ -27,6 +27,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 struct directive;              /* Deliberately incomplete.  */
 struct pending_option;
+struct op;
 
 /* Test if a sign is valid within a preprocessing number.  */
 #define VALID_SIGN(c, prevc) \
@@ -153,6 +154,9 @@ struct lexer_state
 
   /* Nonzero when parsing arguments to a function-like macro.  */
   unsigned char parsing_args;
+
+  /* Nonzero to skip evaluating part of an expression.  */
+  unsigned int skip_eval;
 };
 
 /* Special nodes - identifiers with predefined significance.  */
@@ -312,6 +316,9 @@ struct cpp_reader
   /* Identifier hash table.  */ 
   struct ht *hash_table;
 
+  /* Expression parser stack.  */
+  struct op *op_stack, *op_limit;
+
   /* User visible options.  */
   struct cpp_options opts;
 
@@ -391,7 +398,8 @@ extern void _cpp_pop_file_buffer    PARAMS ((cpp_reader *,
                                                 struct include_file *));
 
 /* In cppexp.c */
-extern int _cpp_parse_expr             PARAMS ((cpp_reader *));
+extern bool _cpp_parse_expr            PARAMS ((cpp_reader *));
+extern struct op *_cpp_expand_op_stack PARAMS ((cpp_reader *));
 
 /* In cpplex.c */
 extern cpp_token *_cpp_temp_token      PARAMS ((cpp_reader *));
index c444f832fb325b5d8c5f6ef9ba022b6b50d158f8..c4f594234b51dced1b61f2f25ab2e8f7016b8243 100644 (file)
@@ -535,6 +535,9 @@ cpp_create_reader (lang)
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* The expression parser stack.  */
+  _cpp_expand_op_stack (pfile);
+
   /* Initialise the buffer obstack.  */
   gcc_obstack_init (&pfile->buffer_ob);
 
@@ -556,6 +559,7 @@ cpp_destroy (pfile)
 
   free_chain (CPP_OPTION (pfile, pending)->include_head);
   free (CPP_OPTION (pfile, pending));
+  free (pfile->op_stack);
 
   while (CPP_BUFFER (pfile) != NULL)
     _cpp_pop_buffer (pfile);
index 712b9dfe478bf5e0bd11d2643262a75f1a750af5..a579873c701bdba79ceb32406fd6afe61fe87529 100644 (file)
@@ -1366,7 +1366,7 @@ do_if (pfile)
   int skip = 1;
 
   if (! pfile->state.skipping)
-    skip = _cpp_parse_expr (pfile) == 0;
+    skip = _cpp_parse_expr (pfile) == false;
 
   push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
 }
index 164c4c8b5b5d3b49b12e45b81583cad6f040bb4a..bbf272be2027affb4449826f1efd76be600d80ab 100644 (file)
@@ -58,7 +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 CPP_LAST_CPP_OP CPP_LESS_EQ
 
 #define TTYPE_TABLE                            \
   OP(CPP_EQ = 0,       "=")                    \
@@ -86,13 +86,13 @@ struct file_name_map_list;
   OP(CPP_COMMA,                ",")    /* grouping */  \
   OP(CPP_OPEN_PAREN,   "(")                    \
   OP(CPP_CLOSE_PAREN,  ")")                    \
+  TK(CPP_EOF,          SPELL_NONE)             \
   OP(CPP_EQ_EQ,                "==")   /* compare */   \
   OP(CPP_NOT_EQ,       "!=")                   \
   OP(CPP_GREATER_EQ,   ">=")                   \
   OP(CPP_LESS_EQ,      "<=")                   \
 \
-  /* These 3 are special in preprocessor expressions.  */ \
-  TK(CPP_EOF,          SPELL_NONE)             \
+  /* These two are unary + / - in preprocessor expressions.  */ \
   OP(CPP_PLUS_EQ,      "+=")   /* math */      \
   OP(CPP_MINUS_EQ,     "-=")                   \
 \
index ab1c3422ecf15d478b699f0d0e86e793c1750b53..1ae710f08c3bfb741b1d154fed71c6b2765fa8a9 100644 (file)
@@ -1,3 +1,9 @@
+2002-04-28  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * gcc.dg/cpp/if-mop.c: Update.
+       * gcc.dg/cpp/if-mpar.c: Add test.
+       * gcc.dg/cpp/if-oppr.c: Update.
+
 2002-04-28  Franz Sirl  <Franz.Sirl-kernel@lauterbach.com>
 
        PR c/6343
index a6a36f150889a04a5d1b74c2b31d14954d55e92b..9202740e6b1246992ecbfa743bc8e5cdb2ca3c6a 100644 (file)
@@ -12,7 +12,7 @@
 #if ~          /* { dg-error "no right op" "no unary operand" } */
 #endif
 
-#if 3 + * 6 + 4  /* { dg-error "no left op" "no left operand" } */
+#if 3 + * 6 + 4  /* { dg-error "no right op" "no right operand" } */
 #endif
 
 #if 2 ~2       /* { dg-error "missing bin" "no binary operator" } */
index b57b5d189ab2837a4da77a9bd705abeaf53dd70f..df200bbbab4615b31d6caca258f9a874d59a8edd 100644 (file)
@@ -19,3 +19,6 @@
 
 #if 4)         /* { dg-error "missing '\\('" "missing '(' no. 3" } */
 #endif
+
+#if (          /* { dg-error "missing '\\)'" "missing ')' no. 3" } */
+#endif
index 3f06cd67ba97ae21c9a0a636613e3b03999aabc3..9c4910f6a20759d132fe3217962a68113860576f 100644 (file)
@@ -20,7 +20,7 @@
 #endif
 
 /* , not higher than ?.  This is not a syntax error if it is.  */
-#if 1 ? 0, 1: 1        /* { dg-error "syntax" "? higher precedence than ," } */
+#if 1 ? 0, 1: 1        /* { dg-error "without" "? higher precedence than ," } */
 #error
 #endif