OSDN Git Service

* Rework fields used to describe positions of bitfields and
[pf3gnuchains/gcc-fork.git] / gcc / cppexp.c
index 36e134b..4d1cf10 100644 (file)
@@ -1,5 +1,5 @@
-/* Parse C expressions for CCCP.
-   Copyright (C) 1987, 92, 94, 95, 97, 98, 1999 Free Software Foundation.
+/* Parse C expressions for cpplib.
+   Copyright (C) 1987, 92, 94, 95, 97, 98, 1999, 2000 Free Software Foundation.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -27,10 +27,7 @@ Written by Per Bothner 1994.  */
 #include "config.h"
 #include "system.h"
 #include "cpplib.h"
-
-#ifdef MULTIBYTE_CHARS
-#include <locale.h>
-#endif
+#include "cpphash.h"
 
 #ifndef CHAR_TYPE_SIZE
 #define CHAR_TYPE_SIZE BITS_PER_UNIT
@@ -65,11 +62,11 @@ Written by Per Bothner 1994.  */
 #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 << 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 << MAX_WCHAR_TYPE_SIZE) \
                             : ~ (HOST_WIDEST_INT) 0)
 
 /* Yield nonzero if adding two numbers with A's and B's signs can yield a
@@ -77,8 +74,21 @@ Written by Per Bothner 1994.  */
 #define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
 
 static void integer_overflow PARAMS ((cpp_reader *));
-static long left_shift PARAMS ((cpp_reader *, long, int, unsigned long));
-static long right_shift PARAMS ((cpp_reader *, long, int, unsigned long));
+static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
+                                          unsigned int,
+                                          unsigned HOST_WIDEST_INT));
+static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
+                                           unsigned int,
+                                           unsigned HOST_WIDEST_INT));
+static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *,
+                                             U_CHAR *));
+static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *,
+                                                U_CHAR *));
+static struct operation parse_defined PARAMS ((cpp_reader *));
+static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **,
+                                            HOST_WIDEST_INT));
+static struct operation lex PARAMS ((cpp_reader *, int));
+
 
 #define ERROR 299
 #define OROR 300
@@ -99,16 +109,14 @@ static long right_shift PARAMS ((cpp_reader *, long, int, unsigned long));
 /* SKIP_OPERAND is set for '&&' '||' '?' and ':' when the
    following operand should be short-circuited instead of evaluated.  */
 #define SKIP_OPERAND 8
-/*#define UNSIGNEDP 16*/
 
-#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
-
-struct operation {
-    short op;
-    char rprio; /* Priority of op (relative to it right operand).  */
-    char flags;
-    char unsignedp;    /* true if value should be treated as unsigned */
-    HOST_WIDEST_INT value;        /* The value logically "right" of op.  */
+struct operation
+{
+  short op;
+  U_CHAR rprio; /* Priority of op (relative to it right operand).  */
+  U_CHAR flags;
+  U_CHAR unsignedp;    /* true if value should be treated as unsigned */
+  HOST_WIDEST_INT value;        /* The value logically "right" of op.  */
 };
 
 /* Parse and convert an integer for #if.  Accepts decimal, hex, or octal
@@ -254,13 +262,7 @@ parse_charconst (pfile, start, end)
   int max_chars;
   U_CHAR *ptr = start;
 
-  /* FIXME: Should use reentrant multibyte functions.  */
-#ifdef MULTIBYTE_CHARS
-  wchar_t c;
-  (void) mbtowc (NULL_PTR, NULL_PTR, 0);
-#else
-  int c;
-#endif
+  int c = -1;
 
   if (*ptr == 'L')
     {
@@ -273,22 +275,12 @@ parse_charconst (pfile, start, end)
 
   while (ptr < end)
     {
-#ifndef MULTIBYTE_CHARS
       c = *ptr++;
-#else
-      ptr += mbtowc (&c, ptr, end - ptr);
-#endif
       if (c == '\'' || c == '\0')
        break;
       else if (c == '\\')
        {
-         /* Hopefully valid assumption: if mbtowc returns a backslash,
-            we are in initial shift state.  No valid escape-sequence
-            character can take us out of initial shift state or begin
-            an unshifted multibyte char, so cpp_parse_escape doesn't
-            need to know about multibyte chars.  */
-
-         c = cpp_parse_escape (pfile, (char **) &ptr, mask);
+         c = parse_escape (pfile, &ptr, mask);
          if (width < HOST_BITS_PER_INT
              && (unsigned int) c >= (unsigned int)(1 << width))
            cpp_pedwarn (pfile, "escape sequence out of range for character");
@@ -327,14 +319,14 @@ parse_charconst (pfile, start, end)
   /* If char type is signed, sign-extend the constant.  */
   num_bits = num_chars * width;
       
-  if (cpp_lookup (pfile, (U_CHAR *)"__CHAR_UNSIGNED__",
-                 sizeof ("__CHAR_UNSIGNED__")-1, -1)
+  if (cpp_defined (pfile, (const U_CHAR *)"__CHAR_UNSIGNED__",
+                  sizeof ("__CHAR_UNSIGNED__")-1)
       || ((result >> (num_bits - 1)) & 1) == 0)
-    op.value = result & ((unsigned long) ~0
-                        >> (HOST_BITS_PER_LONG - num_bits));
+    op.value = result & ((unsigned HOST_WIDEST_INT) ~0
+                        >> (HOST_BITS_PER_WIDEST_INT - num_bits));
   else
-    op.value = result | ~((unsigned long) ~0
-                         >> (HOST_BITS_PER_LONG - num_bits));
+    op.value = result | ~((unsigned HOST_WIDEST_INT) ~0
+                         >> (HOST_BITS_PER_WIDEST_INT - num_bits));
 
   /* This is always a signed type.  */
   op.unsignedp = 0;
@@ -346,13 +338,60 @@ parse_charconst (pfile, start, end)
   return op;
 }
 
+static struct operation
+parse_defined (pfile)
+     cpp_reader *pfile;
+{
+  int paren = 0, len;
+  U_CHAR *tok;
+  enum cpp_token token;
+  struct operation op;
+  long old_written = CPP_WRITTEN (pfile);
+
+  op.unsignedp = 0;
+  op.op = INT;
+
+  pfile->no_macro_expand++;
+  token = _cpp_get_directive_token (pfile);
+  if (token == CPP_LPAREN)
+    {
+      paren++;
+      CPP_SET_WRITTEN (pfile, old_written);
+      token = _cpp_get_directive_token (pfile);
+    }
+
+  if (token != CPP_NAME)
+    goto oops;
+
+  tok = pfile->token_buffer + old_written;
+  len = CPP_PWRITTEN (pfile) - tok;
+  op.value = cpp_defined (pfile, tok, len);
+
+  if (paren)
+    {
+      if (_cpp_get_directive_token (pfile) != CPP_RPAREN)
+       goto oops;
+    }
+  CPP_SET_WRITTEN (pfile, old_written);
+  pfile->no_macro_expand--;
+  return op;
+
+ oops:
+  CPP_SET_WRITTEN (pfile, old_written);
+  pfile->no_macro_expand--;
+  cpp_error (pfile, "`defined' without an identifier");
+
+  op.op = ERROR;
+  return op;
+}
+
 
 struct token {
-  char *operator;
+  const char *operator;
   int token;
 };
 
-static struct token tokentab2[] = {
+static const struct token tokentab2[] = {
   {"&&", ANDAND},
   {"||", OROR},
   {"<<", LSH},
@@ -369,112 +408,57 @@ static struct token tokentab2[] = {
 /* Read one token.  */
 
 static struct operation
-cpp_lex (pfile, skip_evaluation)
+lex (pfile, skip_evaluation)
      cpp_reader *pfile;
      int skip_evaluation;
 {
-  U_CHAR c;
-  struct token *toktab;
+  const struct token *toktab;
   enum cpp_token token;
   struct operation op;
   U_CHAR *tok_start, *tok_end;
-  int old_written;
-
- retry:
+  long old_written;
 
   old_written = CPP_WRITTEN (pfile);
-  cpp_skip_hspace (pfile);
-  c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
-  if (c == '#')
-    {
-      op.op = INT;
-      op.value = cpp_read_check_assertion (pfile);
-      return op;
-    }
+  token = _cpp_get_directive_token (pfile);
 
-  if (c == '\n')
-    {
-      op.op = 0;
-      return op;
-    }
-
-  token = cpp_get_token (pfile);
   tok_start = pfile->token_buffer + old_written;
   tok_end = CPP_PWRITTEN (pfile);
-  pfile->limit = tok_start;
+  CPP_SET_WRITTEN (pfile, old_written);
   switch (token)
-  {
+    {
     case CPP_EOF: /* Should not happen ...  */
     case CPP_VSPACE:
       op.op = 0;
       return op;
-    case CPP_POP:
-      if (CPP_BUFFER (pfile)->fname != NULL)
-       {
-         op.op = 0;
-         return op;
-       }
-      cpp_pop_buffer (pfile);
-      goto retry;
-    case CPP_HSPACE:
-    case CPP_COMMENT: 
-      goto retry;
     case CPP_NUMBER:
       return parse_number (pfile, tok_start, tok_end);
     case CPP_STRING:
-      cpp_error (pfile, "string constants not allowed in #if expressions");
+    case CPP_WSTRING:
+      cpp_error (pfile, "string constants are not allowed in #if expressions");
       op.op = ERROR;
       return op;
+
     case CPP_CHAR:
+    case CPP_WCHAR:
       return parse_charconst (pfile, tok_start, tok_end);
 
     case CPP_NAME:
+      if (!strcmp (tok_start, "defined"))
+       return parse_defined (pfile);
+
       op.op = INT;
       op.unsignedp = 0;
       op.value = 0;
-      if (strcmp (tok_start, "defined"))
-       {
-         if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
-           cpp_warning (pfile, "`%.*s' is not defined",
-                        (int) (tok_end - tok_start), tok_start);
-       }
-      else
-       {
-         int paren = 0, len;
-         cpp_buffer *ip = CPP_BUFFER (pfile);
-         U_CHAR *tok;
 
-         SKIP_WHITE_SPACE (ip->cur);
-         if (*ip->cur == '(')
-           {
-             paren++;
-             ip->cur++;                        /* Skip over the paren */
-             SKIP_WHITE_SPACE (ip->cur);
-           }
-
-         if (!is_idstart[*ip->cur])
-           goto oops;
-         if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"'))
-           goto oops;
-         tok = ip->cur;
-         while (is_idchar[*ip->cur])
-           ++ip->cur;
-         len = ip->cur - tok;
-         SKIP_WHITE_SPACE (ip->cur);
-         if (paren)
-           {
-             if (*ip->cur != ')')
-               goto oops;
-             ++ip->cur;
-           }
-         if (cpp_lookup (pfile, tok, len, -1))
-           op.value = 1;
-
-       }
+      if (CPP_OPTIONS (pfile)->warn_undef && !skip_evaluation)
+       cpp_warning (pfile, "`%.*s' is not defined",
+                    (int) (tok_end - tok_start), tok_start);
       return op;
 
-    oops:
-      cpp_error (pfile, "`defined' without an identifier");
+    case CPP_ASSERTION:
+      op.op = INT;
+      op.unsignedp = 0;
+      op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
       return op;
 
     case CPP_OTHER:
@@ -513,10 +497,10 @@ cpp_lex (pfile, skip_evaluation)
    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.  */
 
-HOST_WIDEST_INT
-cpp_parse_escape (pfile, string_ptr, result_mask)
+static HOST_WIDEST_INT
+parse_escape (pfile, string_ptr, result_mask)
      cpp_reader *pfile;
-     char **string_ptr;
+     U_CHAR **string_ptr;
      HOST_WIDEST_INT result_mask;
 {
   register int c = *(*string_ptr)++;
@@ -530,7 +514,7 @@ cpp_parse_escape (pfile, string_ptr, result_mask)
     case 'E':
       if (CPP_OPTIONS (pfile)->pedantic)
        cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, `\\%c'", c);
-      return 033;
+      return TARGET_ESC;
     case 'f':
       return TARGET_FF;
     case 'n':
@@ -620,41 +604,41 @@ integer_overflow (pfile)
     cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
 }
 
-static long
+static HOST_WIDEST_INT
 left_shift (pfile, a, unsignedp, b)
      cpp_reader *pfile;
-     long a;
-     int unsignedp;
-     unsigned long b;
+     HOST_WIDEST_INT a;
+     unsigned int unsignedp;
+     unsigned HOST_WIDEST_INT b;
 {
-  if (b >= HOST_BITS_PER_LONG)
+  if (b >= HOST_BITS_PER_WIDEST_INT)
     {
       if (! unsignedp && a != 0)
        integer_overflow (pfile);
       return 0;
     }
   else if (unsignedp)
-    return (unsigned long) a << b;
+    return (unsigned HOST_WIDEST_INT) a << b;
   else
     {
-      long l = a << b;
+      HOST_WIDEST_INT l = a << b;
       if (l >> b != a)
        integer_overflow (pfile);
       return l;
     }
 }
 
-static long
+static HOST_WIDEST_INT
 right_shift (pfile, a, unsignedp, b)
      cpp_reader *pfile ATTRIBUTE_UNUSED;
-     long a;
-     int unsignedp;
-     unsigned long b;
+     HOST_WIDEST_INT a;
+     unsigned int unsignedp;
+     unsigned HOST_WIDEST_INT b;
 {
-  if (b >= HOST_BITS_PER_LONG)
-    return unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1);
+  if (b >= HOST_BITS_PER_WIDEST_INT)
+    return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1);
   else if (unsignedp)
-    return (unsigned long) a >> b;
+    return (unsigned HOST_WIDEST_INT) a >> b;
   else
     return a >> b;
 }
@@ -679,13 +663,13 @@ right_shift (pfile, a, unsignedp, b)
 #define COMPARE(OP) \
   top->unsignedp = 0;\
   top->value = (unsigned1 || unsigned2) \
-  ? (unsigned long) v1 OP (unsigned long) v2 : (v1 OP v2)
+  ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 : (v1 OP v2)
 
 /* Parse and evaluate a C expression, reading from PFILE.
-   Returns the value of the expression.  */
+   Returns the truth value of the expression.  */
 
-HOST_WIDEST_INT
-cpp_parse_expr (pfile)
+int
+_cpp_parse_expr (pfile)
      cpp_reader *pfile;
 {
   /* The implementation is an operator precedence parser,
@@ -703,18 +687,21 @@ cpp_parse_expr (pfile)
   struct operation *stack = init_stack;
   struct operation *limit = stack + INIT_STACK_SIZE;
   register struct operation *top = stack;
-  int lprio, rprio;
+  unsigned int lprio, rprio = 0;
   int skip_evaluation = 0;
+  long old_written = CPP_WRITTEN (pfile);
+  int result;
 
+  pfile->parsing_if_directive++;
   top->rprio = 0;
   top->flags = 0;
   for (;;)
     {
       struct operation op;
-      char flags = 0;
+      U_CHAR flags = 0;
 
       /* Read a token */
-      op =  cpp_lex (pfile, skip_evaluation);
+      op =  lex (pfile, skip_evaluation);
 
       /* See if the token is an operand, in which case go to set_value.
         If the token is an operator, figure out its left and right
@@ -723,17 +710,19 @@ cpp_parse_expr (pfile)
       switch (op.op)
        {
        case NAME:
-         abort ();
+         cpp_ice (pfile, "lex returns a NAME");
+         goto syntax_error;
        case INT:  case CHAR:
-         top->value = op.value;
-         top->unsignedp = op.unsignedp;
          goto set_value;
        case 0:
          lprio = 0;  goto maybe_reduce;
        case '+':  case '-':
-         /* Is this correct if unary ? FIXME */
-         flags = RIGHT_OPERAND_REQUIRED;
-         lprio = PLUS_PRIO;  rprio = lprio + 1;  goto maybe_reduce;
+         if (top->flags & HAVE_VALUE)
+           {
+             lprio = PLUS_PRIO;
+             goto binop;
+           }
+         /* else fall through */
        case '!':  case '~':
          flags = RIGHT_OPERAND_REQUIRED;
          rprio = UNARY_PRIO;  lprio = rprio + 1;  goto maybe_reduce;
@@ -766,10 +755,6 @@ cpp_parse_expr (pfile)
          goto maybe_reduce;
        case ERROR:
          goto syntax_error;
-       binop:
-         flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED;
-         rprio = lprio + 1;
-         goto maybe_reduce;
        default:
          cpp_error (pfile, "invalid character in #if");
          goto syntax_error;
@@ -782,15 +767,22 @@ cpp_parse_expr (pfile)
          cpp_error (pfile, "syntax error in #if");
          goto syntax_error;
        }
+      top->value = op.value;
+      top->unsignedp = op.unsignedp;
       top->flags |= HAVE_VALUE;
       continue;
 
+    binop:
+      flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED;
+      rprio = lprio + 1;
+
     maybe_reduce:
       /* Push an operator, and check if we can reduce now.  */
       while (top->rprio > lprio)
        {
-         long v1 = top[-1].value, v2 = top[0].value;
-         int unsigned1 = top[-1].unsignedp, unsigned2 = top[0].unsignedp;
+         HOST_WIDEST_INT v1 = top[-1].value, v2 = top[0].value;
+         unsigned int unsigned1 = top[-1].unsignedp;
+         unsigned int unsigned2 = top[0].unsignedp;
          top--;
          if ((top[1].flags & LEFT_OPERAND_REQUIRED)
              && ! (top[0].flags & HAVE_VALUE))
@@ -844,7 +836,7 @@ cpp_parse_expr (pfile)
            case '*':
              top->unsignedp = unsigned1 || unsigned2;
              if (top->unsignedp)
-               top->value = (unsigned long) v1 * v2;
+               top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
              else if (!skip_evaluation)
                {
                  top->value = v1 * v2;
@@ -864,7 +856,7 @@ cpp_parse_expr (pfile)
                }
              top->unsignedp = unsigned1 || unsigned2;
              if (top->unsignedp)
-               top->value = (unsigned long) v1 / v2;
+               top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
              else
                {
                  top->value = v1 / v2;
@@ -882,7 +874,7 @@ cpp_parse_expr (pfile)
                }
              top->unsignedp = unsigned1 || unsigned2;
              if (top->unsignedp)
-               top->value = (unsigned long) v1 % v2;
+               top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
              else
                top->value = v1 % v2;
              break;
@@ -999,20 +991,19 @@ cpp_parse_expr (pfile)
                }
              break;
            default:
-             cpp_error (pfile,
-                        (top[1].op >= ' ' && top[1].op <= '~'
-                         ? "unimplemented operator '%c'\n"
-                         : "unimplemented operator '\\%03o'\n"),
-                        top[1].op);
+             if (ISGRAPH (top[1].op))
+               cpp_error (pfile, "unimplemented operator '%c'\n", top[1].op);
+             else
+               cpp_error (pfile, "unimplemented operator '\\%03o'\n",
+                          top[1].op);
            }
        }
       if (op.op == 0)
        {
          if (top != stack)
-           cpp_error (pfile, "internal error in #if expression");
-         if (stack != init_stack)
-           free (stack);
-         return top->value;
+           cpp_ice (pfile, "unbalanced stack in #if expression");
+         result = (top->value != 0);
+         goto done;
        }
       top++;
       
@@ -1027,7 +1018,7 @@ cpp_parse_expr (pfile)
          else
            {
              new_stack = (struct operation *) xmalloc (new_size);
-             bcopy ((char *) stack, (char *) new_stack, old_size);
+             memcpy (new_stack, stack, old_size);
            }
          stack = new_stack;
          top = (struct operation *) ((char *) new_stack + old_size);
@@ -1052,8 +1043,12 @@ cpp_parse_expr (pfile)
        }
     }
  syntax_error:
+  _cpp_skip_rest_of_line (pfile);
+  result = 0;
+ done:
+  pfile->parsing_if_directive--;
+  CPP_SET_WRITTEN (pfile, old_written);
   if (stack != init_stack)
     free (stack);
-  skip_rest_of_line (pfile);
-  return 0;
+  return result;
 }