OSDN Git Service

(const_binop): Don't pass OVERFLOW to force_fit_type if type is
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index f4ab73c..2c10890 100644 (file)
@@ -1,5 +1,5 @@
 /* Lexical analyzer for C and Objective C.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -30,6 +30,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "c-tree.h"
 #include "flags.h"
 #include "c-parse.h"
+#include "c-pragma.h"
+
+#include <ctype.h>
 
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
@@ -88,194 +91,11 @@ static int end_of_file;
 static int nextchar = -1;
 
 int check_newline ();
-
-/* Nonzero tells yylex to ignore \ in string constants.  */
-static int ignore_escape_flag = 0;
 \f
-/* C code produced by gperf version 2.5 (GNU C++ version) */
-/* Command-line: gperf -p -j1 -i 1 -g -o -t -G -N is_reserved_word -k1,3,$ c-parse.gperf  */
-struct resword { char *name; short token; enum rid rid; };
-
-#define TOTAL_KEYWORDS 79
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 20
-#define MIN_HASH_VALUE 10
-#define MAX_HASH_VALUE 144
-/* maximum key range = 135, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#endif
-static unsigned int
-hash (str, len)
-     register char *str;
-     register int unsigned len;
-{
-  static unsigned char asso_values[] =
-    {
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145,  25, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
-     145, 145, 145, 145, 145,   1, 145,  46,   8,  15,
-      61,   6,  36,  48,   3,   5, 145,  18,  63,  25,
-      29,  76,   1, 145,  13,   2,   1,  51,  37,   9,
-       9,   1,   3, 145, 145, 145, 145, 145,
-    };
-  register int hval = len;
-
-  switch (hval)
-    {
-      default:
-      case 3:
-        hval += asso_values[str[2]];
-      case 2:
-      case 1:
-        hval += asso_values[str[0]];
-    }
-  return hval + asso_values[str[len - 1]];
-}
-
-static struct resword wordlist[] =
-{
-  {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-  {"",}, 
-  {"int",  TYPESPEC, RID_INT},
-  {"",}, {"",}, 
-  {"__typeof__",  TYPEOF, NORID},
-  {"__signed__",  TYPESPEC, RID_SIGNED},
-  {"__imag__",  IMAGPART, NORID},
-  {"switch",  SWITCH, NORID},
-  {"__inline__",  SCSPEC, RID_INLINE},
-  {"else",  ELSE, NORID},
-  {"__iterator__",  SCSPEC, RID_ITERATOR},
-  {"__inline",  SCSPEC, RID_INLINE},
-  {"__extension__",  EXTENSION, NORID},
-  {"struct",  STRUCT, NORID},
-  {"__real__",  REALPART, NORID},
-  {"__const",  TYPE_QUAL, RID_CONST},
-  {"while",  WHILE, NORID},
-  {"__const__",  TYPE_QUAL, RID_CONST},
-  {"case",  CASE, NORID},
-  {"__complex__",  TYPESPEC, RID_COMPLEX},
-  {"__iterator",  SCSPEC, RID_ITERATOR},
-  {"bycopy",  TYPE_QUAL, RID_BYCOPY},
-  {"",}, {"",}, {"",}, 
-  {"__complex",  TYPESPEC, RID_COMPLEX},
-  {"",}, 
-  {"in",  TYPE_QUAL, RID_IN},
-  {"break",  BREAK, NORID},
-  {"@defs",  DEFS, NORID},
-  {"",}, {"",}, {"",}, 
-  {"extern",  SCSPEC, RID_EXTERN},
-  {"if",  IF, NORID},
-  {"typeof",  TYPEOF, NORID},
-  {"typedef",  SCSPEC, RID_TYPEDEF},
-  {"__typeof",  TYPEOF, NORID},
-  {"sizeof",  SIZEOF, NORID},
-  {"",}, 
-  {"return",  RETURN, NORID},
-  {"const",  TYPE_QUAL, RID_CONST},
-  {"__volatile__",  TYPE_QUAL, RID_VOLATILE},
-  {"@private",  PRIVATE, NORID},
-  {"@selector",  SELECTOR, NORID},
-  {"__volatile",  TYPE_QUAL, RID_VOLATILE},
-  {"__asm__",  ASM_KEYWORD, NORID},
-  {"",}, {"",}, 
-  {"continue",  CONTINUE, NORID},
-  {"__alignof__",  ALIGNOF, NORID},
-  {"__imag",  IMAGPART, NORID},
-  {"__attribute__",  ATTRIBUTE, NORID},
-  {"",}, {"",}, 
-  {"__attribute",  ATTRIBUTE, NORID},
-  {"for",  FOR, NORID},
-  {"",}, 
-  {"@encode",  ENCODE, NORID},
-  {"id",  OBJECTNAME, RID_ID},
-  {"static",  SCSPEC, RID_STATIC},
-  {"@interface",  INTERFACE, NORID},
-  {"",}, 
-  {"__signed",  TYPESPEC, RID_SIGNED},
-  {"",}, 
-  {"__label__",  LABEL, NORID},
-  {"",}, {"",}, 
-  {"__asm",  ASM_KEYWORD, NORID},
-  {"char",  TYPESPEC, RID_CHAR},
-  {"",}, 
-  {"inline",  SCSPEC, RID_INLINE},
-  {"out",  TYPE_QUAL, RID_OUT},
-  {"register",  SCSPEC, RID_REGISTER},
-  {"__real",  REALPART, NORID},
-  {"short",  TYPESPEC, RID_SHORT},
-  {"",}, 
-  {"enum",  ENUM, NORID},
-  {"inout",  TYPE_QUAL, RID_INOUT},
-  {"",}, 
-  {"oneway",  TYPE_QUAL, RID_ONEWAY},
-  {"union",  UNION, NORID},
-  {"",}, 
-  {"__alignof",  ALIGNOF, NORID},
-  {"",}, 
-  {"@implementation",  IMPLEMENTATION, NORID},
-  {"",}, 
-  {"@class",  CLASS, NORID},
-  {"",}, 
-  {"@public",  PUBLIC, NORID},
-  {"asm",  ASM_KEYWORD, NORID},
-  {"",}, {"",}, {"",}, {"",}, {"",}, 
-  {"default",  DEFAULT, NORID},
-  {"",}, 
-  {"void",  TYPESPEC, RID_VOID},
-  {"",}, 
-  {"@protected",  PROTECTED, NORID},
-  {"@protocol",  PROTOCOL, NORID},
-  {"",}, {"",}, {"",}, 
-  {"volatile",  TYPE_QUAL, RID_VOLATILE},
-  {"",}, {"",}, 
-  {"signed",  TYPESPEC, RID_SIGNED},
-  {"float",  TYPESPEC, RID_FLOAT},
-  {"@end",  END, NORID},
-  {"",}, {"",}, 
-  {"unsigned",  TYPESPEC, RID_UNSIGNED},
-  {"@compatibility_alias",  ALIAS, NORID},
-  {"double",  TYPESPEC, RID_DOUBLE},
-  {"",}, {"",}, 
-  {"auto",  SCSPEC, RID_AUTO},
-  {"",}, 
-  {"goto",  GOTO, NORID},
-  {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-  {"do",  DO, NORID},
-  {"",}, {"",}, {"",}, {"",}, 
-  {"long",  TYPESPEC, RID_LONG},
-};
-
-#ifdef __GNUC__
-__inline
-#endif
-struct resword *
-is_reserved_word (str, len)
-     register char *str;
-     register unsigned int len;
-{
-  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
-    {
-      register int key = hash (str, len);
-
-      if (key <= MAX_HASH_VALUE && key >= 0)
-        {
-          register char *s = wordlist[key].name;
-
-          if (*s == *str && !strcmp (str + 1, s + 1))
-            return &wordlist[key];
-        }
-    }
-  return 0;
-}
+/* Do not insert generated code into the source, instead, include it.
+   This allows us to build gcc automatically even for targets that
+   need to add or modify the reserved keyword lists.  */
+#include "c-gperf.h"
 \f
 /* Return something to represent absolute declarators containing a *.
    TARGET is the absolute declarator that the * contains.
@@ -579,11 +399,12 @@ check_newline ()
            {
 #ifdef HANDLE_SYSV_PRAGMA
              return handle_sysv_pragma (finput, c);
-#endif /* HANDLE_SYSV_PRAGMA */
+#else /* !HANDLE_SYSV_PRAGMA */
 #ifdef HANDLE_PRAGMA
              HANDLE_PRAGMA (finput);
 #endif /* HANDLE_PRAGMA */
              goto skipline;
+#endif /* !HANDLE_SYSV_PRAGMA */
            }
        }
 
@@ -714,10 +535,8 @@ linenum:
 
       /* More follows: it must be a string constant (filename).  */
 
-      /* Read the string constant, but don't treat \ as special.  */
-      ignore_escape_flag = 1;
+      /* Read the string constant.  */
       token = yylex ();
-      ignore_escape_flag = 0;
 
       if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
        {
@@ -826,7 +645,20 @@ linenum:
       if (token == CONSTANT
          && TREE_CODE (yylval.ttype) == INTEGER_CST
          && TREE_INT_CST_LOW (yylval.ttype) == 3)
-       in_system_header = 1;
+       in_system_header = 1, used_up = 1;
+
+      if (used_up)
+       {
+         /* Is this the last nonwhite stuff on the line?  */
+         c = getc (finput);
+         while (c == ' ' || c == '\t')
+           c = getc (finput);
+         if (c == '\n')
+           return c;
+         ungetc (c, finput);
+       }
+
+      warning ("unrecognized text at end of #line");
     }
   else
     error ("invalid #-line");
@@ -883,8 +715,6 @@ handle_sysv_pragma (input, c)
 
 #endif /* HANDLE_SYSV_PRAGMA */
 \f
-#define isalnum(char) ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9'))
-#define isdigit(char) (char >= '0' && char <= '9')
 #define ENDFILE -1  /* token that represents end-of-file */
 
 /* Read an escape sequence, returning its equivalent as a character,
@@ -897,7 +727,7 @@ readescape (ignore_ptr)
   register int c = getc (finput);
   register int code;
   register unsigned count;
-  unsigned firstdig;
+  unsigned firstdig = 0;
   int nonnull;
 
   switch (c)
@@ -1012,6 +842,8 @@ readescape (ignore_ptr)
     case '(':
     case '{':
     case '[':
+      /* `\%' is used to prevent SCCS from getting confused.  */
+    case '%':
       if (pedantic)
        pedwarn ("non-ANSI escape sequence `\\%c'", c);
       return c;
@@ -1333,10 +1165,16 @@ yylex ()
              {
                if (base == 16)
                  error ("floating constant may not be in radix 16");
-               if (floatflag == AFTER_POINT)
+               if (floatflag == TOO_MANY_POINTS)
+                 /* We have already emitted an error.  Don't need another.  */
+                 ;
+               else if (floatflag == AFTER_POINT)
                  {
                    error ("malformed floating constant");
                    floatflag = TOO_MANY_POINTS;
+                   /* Avoid another error from atof by forcing all characters
+                      from here on to be ignored.  */
+                   p[-1] = '\0';
                  }
                else
                  floatflag = AFTER_POINT;
@@ -1475,44 +1313,88 @@ yylex ()
              }
            else
              {
+               int fflag = 0, lflag = 0;
+               /* Copy token_buffer now, while it has just the number
+                  and not the suffixes; once we add `f' or `i',
+                  REAL_VALUE_ATOF may not work any more.  */
+               char *copy = (char *) alloca (p - token_buffer + 1);
+               bcopy (token_buffer, copy, p - token_buffer + 1);
+
                set_float_handler (handler);
 
-/* The second argument, machine_mode, of REAL_VALUE_ATOF tells the
-   desired precision of the binary result of decimal-to-binary conversion.  */
+               while (1)
+                 {
+                   int lose = 0;
 
-           /* Read the suffixes to choose a data type.  */
-           switch (c)
-             {
-             case 'f': case 'F':
-               type = float_type_node;
-               value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
-               if (REAL_VALUE_ISINF (value) && pedantic)
-                 pedwarn ("floating point number exceeds range of `float'");
-               garbage_chars = -1;
-               break;
-
-             case 'l': case 'L':
-               type = long_double_type_node;
-               value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
-               if (REAL_VALUE_ISINF (value) && pedantic)
-                 pedwarn (
-                     "floating point number exceeds range of `long double'");
-               garbage_chars = -1;
-               break;
-
-             case 'i': case 'I':
-               if (imag)
-                 error ("more than one `i' or `j' in numeric constant");
-               imag = 1;
-               garbage_chars = -1;
-               break;
-
-              default:
-               value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
-               if (REAL_VALUE_ISINF (value) && pedantic)
-                 pedwarn ("floating point number exceeds range of `double'");
-             }
-           set_float_handler (NULL_PTR);
+                   /* Read the suffixes to choose a data type.  */
+                   switch (c)
+                     {
+                     case 'f': case 'F':
+                       if (fflag)
+                         error ("more than one `f' in numeric constant");
+                       fflag = 1;
+                       break;
+
+                     case 'l': case 'L':
+                       if (lflag)
+                         error ("more than one `l' in numeric constant");
+                       lflag = 1;
+                       break;
+
+                     case 'i': case 'I':
+                       if (imag)
+                         error ("more than one `i' or `j' in numeric constant");
+                       else if (pedantic)
+                         pedwarn ("ANSI C forbids imaginary numeric constants");
+                       imag = 1;
+                       break;
+
+                     default:
+                       lose = 1;
+                     }
+
+                   if (lose)
+                     break;
+
+                   if (p >= token_buffer + maxtoken - 3)
+                     p = extend_token_buffer (p);
+                   *p++ = c;
+                   *p = 0;
+                   c = getc (finput);
+                 }
+
+               /* The second argument, machine_mode, of REAL_VALUE_ATOF
+                  tells the desired precision of the binary result
+                  of decimal-to-binary conversion.  */
+
+               if (fflag)
+                 {
+                   if (lflag)
+                     error ("both `f' and `l' in floating constant");
+
+                   type = float_type_node;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   /* A diagnostic is required here by some ANSI C testsuites.
+                      This is not pedwarn, become some people don't want
+                      an error for this.  */
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `float'");
+                 }
+               else if (lflag)
+                 {
+                   type = long_double_type_node;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `long double'");
+                 }
+               else
+                 {
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `double'");
+                 }
+
+               set_float_handler (NULL_PTR);
            }
 #ifdef ERANGE
            if (errno == ERANGE && !flag_traditional && pedantic)
@@ -1522,12 +1404,12 @@ yylex ()
                if (REAL_VALUES_LESS (dconst1, value)
                    || REAL_VALUES_LESS (value, dconstm1))
                  {
-                   pedwarn ("floating point number exceeds range of `double'");
+                   warning ("floating point number exceeds range of `double'");
                    exceeds_double = 1;
                  }
              }
 #endif
-           /* Note: garbage_chars is -1 if first char is *not* garbage.  */
+           garbage_chars = 0;
            while (isalnum (c) || c == '.' || c == '_'
                   || (!flag_traditional && (c == '+' || c == '-')
                       && (p[-1] == 'e' || p[-1] == 'E')))
@@ -1541,6 +1423,12 @@ yylex ()
            if (garbage_chars > 0)
              error ("garbage at end of number");
 
+           /* If the result is not a number, assume it must have been
+              due to some error message above, so silently convert
+              it to a zero.  */
+           if (REAL_VALUE_ISNAN (value))
+             value = dconst0;
+
            /* Create a node with determined type and value.  */
            if (imag)
              yylval.ttype = build_complex (convert (type, integer_zero_node),
@@ -1585,6 +1473,8 @@ yylex ()
                  {
                    if (spec_imag)
                      error ("more than one `i' or `j' in numeric constant");
+                   else if (pedantic)
+                     pedwarn ("ANSI C forbids imaginary numeric constants");
                    spec_imag = 1;
                  }
                else
@@ -1744,6 +1634,8 @@ yylex ()
              {
                TREE_TYPE (yylval.ttype) = unsigned_type (type);
                yylval.ttype = convert (type, yylval.ttype);
+               TREE_OVERFLOW (yylval.ttype)
+                 = TREE_CONSTANT_OVERFLOW (yylval.ttype) = 0;
              }
            else
              TREE_TYPE (yylval.ttype) = type;
@@ -1843,8 +1735,11 @@ yylex ()
        if (! wide_flag)
          {
            int num_bits = num_chars * width;
-           if (TREE_UNSIGNED (char_type_node)
-               || ((result >> (num_bits - 1)) & 1) == 0)
+           if (num_bits == 0)
+             /* We already got an error; avoid invalid shift.  */
+             yylval.ttype = build_int_2 (0, 0);
+           else if (TREE_UNSIGNED (char_type_node)
+                    || ((result >> (num_bits - 1)) & 1) == 0)
              yylval.ttype
                = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
                                         >> (HOST_BITS_PER_WIDE_INT - num_bits)),
@@ -1890,8 +1785,7 @@ yylex ()
 
        while (c != '"' && c >= 0)
          {
-           /* ignore_escape_flag is set for reading the filename in #line.  */
-           if (!ignore_escape_flag && c == '\\')
+           if (c == '\\')
              {
                int ignore = 0;
                c = readescape (&ignore);
@@ -1918,6 +1812,9 @@ yylex ()
          }
        *p = 0;
 
+       if (c < 0)
+         error ("Unterminated string constant");
+
        /* We have read the entire constant.
           Construct a STRING_CST for the result.  */
 
@@ -1930,7 +1827,7 @@ yylex ()
 
 #ifdef MULTIBYTE_CHARS
            len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
-           if ((unsigned) len >= (p - token_buffer))
+           if (len < 0 || len >= (p - token_buffer))
              {
                warning ("Ignoring invalid multibyte string");
                len = 0;
@@ -1983,6 +1880,7 @@ yylex ()
     case '-':
     case '&':
     case '|':
+    case ':':
     case '<':
     case '>':
     case '*':
@@ -2060,8 +1958,28 @@ yylex ()
              c = RSHIFT;
              goto combine;
            }
-       else if ((c == '-') && (c1 == '>'))
-         { value = POINTSAT; goto done; }
+       else
+         switch (c)
+           {
+           case '-':
+             if (c1 == '>')
+               { value = POINTSAT; goto done; }
+             break;
+           case ':':
+             if (c1 == '>')
+               { value = ']'; goto done; }
+             break;
+           case '<':
+             if (c1 == '%')
+               { value = '{'; goto done; }
+             if (c1 == ':')
+               { value = '['; goto done; }
+             break;
+           case '%':
+             if (c1 == '>')
+               { value = '}'; goto done; }
+             break;
+           }
        ungetc (c1, finput);
        token_buffer[1] = 0;