]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/c-lex.c
[multiple changes]
[gcc.git] / gcc / c-lex.c
index f5f88721ffd190f3b7dc24d111871f07bd517e3e..b6d8295606c21bbb8b1cdecb17f0011d11d3b03f 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-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,33 +15,40 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
-
-#include <stdio.h>
-#include <errno.h>
+#include "config.h"
+#include "system.h"
 #include <setjmp.h>
 
-#include "config.h"
 #include "rtl.h"
 #include "tree.h"
 #include "input.h"
+#include "output.h"
 #include "c-lex.h"
 #include "c-tree.h"
 #include "flags.h"
 #include "c-parse.h"
-
-#include <ctype.h>
+#include "c-pragma.h"
+#include "toplev.h"
 
 #ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
+#include "mbchar.h"
 #include <locale.h>
-#endif
+#endif /* MULTIBYTE_CHARS */
 
-#ifndef errno
-extern int errno;
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader  parse_in;
+extern cpp_options parse_options;
+#else
+/* Stream for reading from the input file.  */
+FILE *finput;
 #endif
 
+extern void yyprint                    PROTO((FILE *, int, YYSTYPE));
+
 /* The elements of `ridpointers' are identifier nodes
    for the reserved type names and storage classes.
    It is indexed by a RID_... value.  */
@@ -50,6 +57,18 @@ tree ridpointers[(int) RID_MAX];
 /* Cause the `yydebug' variable to be defined.  */
 #define YYDEBUG 1
 
+#if USE_CPPLIB
+extern unsigned char *yy_cur, *yy_lim;
+  
+extern int yy_get_token ();
+  
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#define UNGETC(c) ((c), yy_cur--)
+#else
+#define GETC() getc (finput)
+#define UNGETC(c) ungetc (c, finput)
+#endif
+
 /* the declaration found for the last IDENTIFIER token read in.
    yylex must look this up to detect typedefs, which get token type TYPENAME,
    so it is left around in case the identifier is not a typedef but is
@@ -60,8 +79,6 @@ tree lastiddecl;
 
 int doing_objc_thang;
 
-extern tree is_class_name ();
-
 extern int yydebug;
 
 /* File used for outputting assembler code.  */
@@ -83,201 +100,29 @@ char *token_buffer;       /* Pointer to token buffer.
                           Actual allocated length is maxtoken + 2.
                           This is not static because objc-parse.y uses it.  */
 
+static int indent_level = 0;        /* Number of { minus number of }. */
+
 /* Nonzero if end-of-file has been seen on input.  */
 static int end_of_file;
 
+#if !USE_CPPLIB
 /* Buffered-back input character; faster than using ungetc.  */
 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;
-}
+#ifdef HANDLE_GENERIC_PRAGMAS
+static int handle_generic_pragma       PROTO((int));
+#endif /* HANDLE_GENERIC_PRAGMAS */
+static int whitespace_cr               PROTO((int));
+static int skip_white_space            PROTO((int));
+static int skip_white_space_on_line    PROTO((void));
+static char *extend_token_buffer       PROTO((char *));
+static int readescape                  PROTO((int *));
+\f
+/* 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.
@@ -319,10 +164,59 @@ remember_protocol_qualifiers ()
       wordlist[i].name = "inout";
     else if (wordlist[i].rid == RID_BYCOPY)
       wordlist[i].name = "bycopy";
+    else if (wordlist[i].rid == RID_BYREF)
+      wordlist[i].name = "byref";
     else if (wordlist[i].rid == RID_ONEWAY)
       wordlist[i].name = "oneway";   
 }
 \f
+char *
+init_parse (filename)
+     char *filename;
+{
+#if !USE_CPPLIB
+  /* Open input file.  */
+  if (filename == 0 || !strcmp (filename, "-"))
+    {
+      finput = stdin;
+      filename = "stdin";
+    }
+  else
+    finput = fopen (filename, "r");
+  if (finput == 0)
+    pfatal_with_name (filename);
+
+#ifdef IO_BUFFER_SIZE
+  setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+#endif /* !USE_CPPLIB */
+
+  init_lex ();
+
+#if USE_CPPLIB
+  parse_in.show_column = 1;
+  if (! cpp_start_read (&parse_in, filename))
+    abort ();
+
+  /* cpp_start_read always puts at least one line directive into the
+     token buffer.  We must arrange to read it out here. */
+  yy_cur = parse_in.token_buffer;
+  yy_lim = CPP_PWRITTEN (&parse_in);
+#endif
+
+  return filename;
+}
+
+void
+finish_parse ()
+{
+#if USE_CPPLIB
+  cpp_finish (&parse_in);
+#else
+  fclose (finput);
+#endif
+}
+
 void
 init_lex ()
 {
@@ -336,6 +230,7 @@ init_lex ()
 #ifdef MULTIBYTE_CHARS
   /* Change to the native locale for multibyte conversions.  */
   setlocale (LC_CTYPE, "");
+  literal_codeset = getenv ("LANG");
 #endif
 
   maxtoken = 40;
@@ -352,6 +247,7 @@ init_lex ()
   ridpointers[(int) RID_SIGNED] = get_identifier ("signed");
   ridpointers[(int) RID_INLINE] = get_identifier ("inline");
   ridpointers[(int) RID_CONST] = get_identifier ("const");
+  ridpointers[(int) RID_RESTRICT] = get_identifier ("restrict");
   ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile");
   ridpointers[(int) RID_AUTO] = get_identifier ("auto");
   ridpointers[(int) RID_STATIC] = get_identifier ("static");
@@ -365,6 +261,7 @@ init_lex ()
   ridpointers[(int) RID_OUT] = get_identifier ("out");
   ridpointers[(int) RID_INOUT] = get_identifier ("inout");
   ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy");
+  ridpointers[(int) RID_BYREF] = get_identifier ("byref");
   ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway");
   forget_protocol_qualifiers();
 
@@ -380,6 +277,7 @@ init_lex ()
   if (flag_traditional)
     {
       UNSET_RESERVED_WORD ("const");
+      UNSET_RESERVED_WORD ("restrict");
       UNSET_RESERVED_WORD ("volatile");
       UNSET_RESERVED_WORD ("typeof");
       UNSET_RESERVED_WORD ("signed");
@@ -387,6 +285,9 @@ init_lex ()
       UNSET_RESERVED_WORD ("iterator");
       UNSET_RESERVED_WORD ("complex");
     }
+  else if (!flag_isoc9x)
+    UNSET_RESERVED_WORD ("restrict");
+
   if (flag_no_asm)
     {
       UNSET_RESERVED_WORD ("asm");
@@ -426,10 +327,14 @@ yyprint (file, yychar, yylval)
       if (TREE_CODE (t) == INTEGER_CST)
        fprintf (file,
 #if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                " 0x%x%016x",
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
                 " 0x%lx%016lx",
 #else
-                " 0x%x%016x",
+                " 0x%llx%016llx",
+#endif
 #endif
 #else
 #if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
@@ -442,8 +347,30 @@ yyprint (file, yychar, yylval)
       break;
     }
 }
-
 \f
+/* Iff C is a carriage return, warn about it - if appropriate -
+   and return nonzero.  */
+static int
+whitespace_cr (c)
+     int c;
+{
+  static int newline_warning = 0;
+
+  if (c == '\r')
+    {
+      /* ANSI C says the effects of a carriage return in a source file
+        are undefined.  */
+      if (pedantic && !newline_warning)
+       {
+         warning ("carriage return in source file");
+         warning ("(we only warn about the first carriage return)");
+         newline_warning = 1;
+       }
+      return 1;
+    }
+  return 0;
+}
+
 /* If C is not whitespace, return C.
    Otherwise skip whitespace and return first nonwhite char read.  */
 
@@ -451,8 +378,6 @@ static int
 skip_white_space (c)
      register int c;
 {
-  static int newline_warning = 0;
-
   for (;;)
     {
       switch (c)
@@ -470,28 +395,21 @@ skip_white_space (c)
        case '\f':
        case '\v':
        case '\b':
-         c = getc (finput);
+         c = GETC();
          break;
 
        case '\r':
-         /* ANSI C says the effects of a carriage return in a source file
-            are undefined.  */
-         if (pedantic && !newline_warning)
-           {
-             warning ("carriage return in source file");
-             warning ("(we only warn about the first carriage return)");
-             newline_warning = 1;
-           }
-         c = getc (finput);
+         whitespace_cr (c);
+         c = GETC();
          break;
 
        case '\\':
-         c = getc (finput);
+         c = GETC();
          if (c == '\n')
            lineno++;
          else
            error ("stray '\\' in program");
-         c = getc (finput);
+         c = GETC();
          break;
 
        default:
@@ -508,12 +426,46 @@ position_after_white_space ()
 {
   register int c;
 
+#if !USE_CPPLIB
   if (nextchar != -1)
     c = nextchar, nextchar = -1;
   else
-    c = getc (finput);
+#endif
+    c = GETC();
+
+  UNGETC (skip_white_space (c));
+}
+
+/* Like skip_white_space, but don't advance beyond the end of line.
+   Moreover, we don't get passed a character to start with.  */
+static int
+skip_white_space_on_line ()
+{
+  register int c;
+
+  while (1)
+    {
+      c = GETC();
+      switch (c)
+       {
+       case '\n':
+       default:
+         break;
 
-  ungetc (skip_white_space (c), finput);
+       case ' ':
+       case '\t':
+       case '\f':
+       case '\v':
+       case '\b':
+         continue;
+
+       case '\r':
+         whitespace_cr (c);
+         continue;
+       }
+      break;
+    }
+  return c;
 }
 
 /* Make the token buffer longer, preserving the data in it.
@@ -533,6 +485,22 @@ extend_token_buffer (p)
   return token_buffer + offset;
 }
 \f
+#if defined HANDLE_PRAGMA 
+/* Local versions of these macros, that can be passed as function pointers.  */
+static int
+pragma_getc ()
+{
+  return GETC();
+}
+
+static void
+pragma_ungetc (arg)
+     int arg;
+{
+  UNGETC (arg);
+}
+#endif
+
 /* At the beginning of a line, increment the line number
    and process any #-directive on this line.
    If the line is a #-directive, read the entire line and return a newline.
@@ -548,9 +516,9 @@ check_newline ()
 
   /* Read first nonwhite char on the line.  */
 
-  c = getc (finput);
+  c = GETC();
   while (c == ' ' || c == '\t')
-    c = getc (finput);
+    c = GETC();
 
   if (c != '#')
     {
@@ -560,9 +528,9 @@ check_newline ()
 
   /* Read first nonwhite char after the `#'.  */
 
-  c = getc (finput);
+  c = GETC();
   while (c == ' ' || c == '\t')
-    c = getc (finput);
+    c = GETC();
 
   /* If a letter follows, then if the word here is `line', skip
      it and ignore it; otherwise, ignore the line, with an error
@@ -572,85 +540,117 @@ check_newline ()
     {
       if (c == 'p')
        {
-         if (getc (finput) == 'r'
-             && getc (finput) == 'a'
-             && getc (finput) == 'g'
-             && getc (finput) == 'm'
-             && getc (finput) == 'a'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'r'
+             && GETC() == 'a'
+             && GETC() == 'g'
+             && GETC() == 'm'
+             && GETC() == 'a'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'
+                  || whitespace_cr (c) ))
            {
-#ifdef HANDLE_SYSV_PRAGMA
-             return handle_sysv_pragma (finput, c);
-#endif /* HANDLE_SYSV_PRAGMA */
+             while (c == ' ' || c == '\t' || whitespace_cr (c))
+               c = GETC ();
+             if (c == '\n')
+               return c;
+
+#if defined HANDLE_PRAGMA || defined HANDLE_GENERIC_PRAGMAS
+             UNGETC (c);
+             token = yylex ();
+             if (token != IDENTIFIER)
+               goto skipline;
+#endif /* HANDLE_PRAGMA || HANDLE_GENERIC_PRAGMAS */
+             
 #ifdef HANDLE_PRAGMA
-             HANDLE_PRAGMA (finput);
+             /* We invoke HANDLE_PRAGMA before HANDLE_GENERIC_PRAGMAS (if
+                both are defined), in order to give the back end a chance to
+                override the interpretation of generic style pragmas.  */
+#if !USE_CPPLIB
+             if (nextchar >= 0)
+               {
+                 c = nextchar, nextchar = -1;
+                 UNGETC (c);
+               }
+#endif /* !USE_CPPLIB */
+             
+             if (TREE_CODE (yylval.ttype) != IDENTIFIER_NODE)
+               goto skipline;
+
+             if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc,
+                                IDENTIFIER_POINTER (yylval.ttype)))
+               return GETC ();
 #endif /* HANDLE_PRAGMA */
+             
+#ifdef HANDLE_GENERIC_PRAGMAS
+             if (handle_generic_pragma (token))
+               return GETC ();
+#endif /* HANDLE_GENERIC_PRAGMAS */
+             
+             /* Issue a warning message if we have been asked to do so.
+                Ignoring unknown pragmas in system header file unless
+                an explcit -Wunknown-pragmas has been given. */
+             if (warn_unknown_pragmas > 1
+                 || (warn_unknown_pragmas && ! in_system_header))
+               warning ("ignoring pragma: %s", token_buffer);
+             
              goto skipline;
            }
        }
 
       else if (c == 'd')
        {
-         if (getc (finput) == 'e'
-             && getc (finput) == 'f'
-             && getc (finput) == 'i'
-             && getc (finput) == 'n'
-             && getc (finput) == 'e'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'e'
+             && GETC() == 'f'
+             && GETC() == 'i'
+             && GETC() == 'n'
+             && GETC() == 'e'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
            {
-#ifdef DWARF_DEBUGGING_INFO
-             if ((debug_info_level == DINFO_LEVEL_VERBOSE)
-                 && (write_symbols == DWARF_DEBUG))
-               dwarfout_define (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+             if (c != '\n')
+               debug_define (lineno, GET_DIRECTIVE_LINE ());
              goto skipline;
            }
        }
       else if (c == 'u')
        {
-         if (getc (finput) == 'n'
-             && getc (finput) == 'd'
-             && getc (finput) == 'e'
-             && getc (finput) == 'f'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'n'
+             && GETC() == 'd'
+             && GETC() == 'e'
+             && GETC() == 'f'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
            {
-#ifdef DWARF_DEBUGGING_INFO
-             if ((debug_info_level == DINFO_LEVEL_VERBOSE)
-                 && (write_symbols == DWARF_DEBUG))
-               dwarfout_undef (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+             if (c != '\n')
+               debug_undef (lineno, GET_DIRECTIVE_LINE ());
              goto skipline;
            }
        }
       else if (c == 'l')
        {
-         if (getc (finput) == 'i'
-             && getc (finput) == 'n'
-             && getc (finput) == 'e'
-             && ((c = getc (finput)) == ' ' || c == '\t'))
+         if (GETC() == 'i'
+             && GETC() == 'n'
+             && GETC() == 'e'
+             && ((c = GETC()) == ' ' || c == '\t'))
            goto linenum;
        }
       else if (c == 'i')
        {
-         if (getc (finput) == 'd'
-             && getc (finput) == 'e'
-             && getc (finput) == 'n'
-             && getc (finput) == 't'
-             && ((c = getc (finput)) == ' ' || c == '\t'))
+         if (GETC() == 'd'
+             && GETC() == 'e'
+             && GETC() == 'n'
+             && GETC() == 't'
+             && ((c = GETC()) == ' ' || c == '\t'))
            {
              /* #ident.  The pedantic warning is now in cccp.c.  */
 
              /* Here we have just seen `#ident '.
                 A string constant should follow.  */
 
-             while (c == ' ' || c == '\t')
-               c = getc (finput);
+             c = skip_white_space_on_line ();
 
              /* If no argument, ignore the line.  */
              if (c == '\n')
                return c;
 
-             ungetc (c, finput);
+             UNGETC (c);
              token = yylex ();
              if (token != STRING
                  || TREE_CODE (yylval.ttype) != STRING_CST)
@@ -679,8 +679,11 @@ linenum:
   /* Here we have either `#line' or `# <nonletter>'.
      In either case, it should be a line number; a digit should follow.  */
 
-  while (c == ' ' || c == '\t')
-    c = getc (finput);
+  /* Can't use skip_white_space here, but must handle all whitespace
+     that is not '\n', lest we get a recursion for '\r' '\n' when
+     calling yylex.  */
+  UNGETC (c);
+  c = skip_white_space_on_line ();
 
   /* If the # is the only nonwhite char on the line,
      just ignore it.  Check the new newline.  */
@@ -689,7 +692,7 @@ linenum:
 
   /* Something follows the #; read a token.  */
 
-  ungetc (c, finput);
+  UNGETC (c);
   token = yylex ();
 
   if (token == CONSTANT
@@ -703,23 +706,19 @@ linenum:
       int l = TREE_INT_CST_LOW (yylval.ttype) - 1;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
-      while (c == ' ' || c == '\t')
-       c = getc (finput);
+      c = skip_white_space_on_line ();
       if (c == '\n')
        {
          /* No more: store the line number and check following line.  */
          lineno = l;
          return c;
        }
-      ungetc (c, finput);
+      UNGETC (c);
 
       /* 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)
        {
@@ -740,9 +739,7 @@ linenum:
        main_input_filename = input_filename;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
-      while (c == ' ' || c == '\t')
-       c = getc (finput);
+      c = skip_white_space_on_line ();
       if (c == '\n')
        {
          /* Update the name in the top element of input_file_stack.  */
@@ -751,7 +748,7 @@ linenum:
 
          return c;
        }
-      ungetc (c, finput);
+      UNGETC (c);
 
       token = yylex ();
       used_up = 0;
@@ -770,14 +767,10 @@ linenum:
              input_file_stack->line = old_lineno;
              p->next = input_file_stack;
              p->name = input_filename;
+             p->indent_level = indent_level;
              input_file_stack = p;
              input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
-             if (debug_info_level == DINFO_LEVEL_VERBOSE
-                 && write_symbols == DWARF_DEBUG)
-               dwarfout_start_new_source_file (input_filename);
-#endif /* DWARF_DEBUGGING_INFO */
-
+             debug_start_source_file (input_filename);
              used_up = 1;
            }
          else if (TREE_INT_CST_LOW (yylval.ttype) == 2)
@@ -786,14 +779,18 @@ linenum:
              if (input_file_stack->next)
                {
                  struct file_stack *p = input_file_stack;
+                 if (indent_level != p->indent_level)
+                   {
+                     warning_with_file_and_line 
+                       (p->name, old_lineno,
+                        "This file contains more `%c's than `%c's.",
+                        indent_level > p->indent_level ? '{' : '}',
+                        indent_level > p->indent_level ? '}' : '{');
+                   }
                  input_file_stack = p->next;
                  free (p);
                  input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
-                 if (debug_info_level == DINFO_LEVEL_VERBOSE
-                     && write_symbols == DWARF_DEBUG)
-                   dwarfout_resume_previous_source_file (input_file_stack->line);
-#endif /* DWARF_DEBUGGING_INFO */
+                 debug_end_source_file (input_file_stack->line);
                }
              else
                error ("#-lines for entering and leaving files don't match");
@@ -812,12 +809,10 @@ linenum:
       if (used_up)
        {
          /* Is this the last nonwhite stuff on the line?  */
-         c = getc (finput);
-         while (c == ' ' || c == '\t')
-           c = getc (finput);
+         c = skip_white_space_on_line ();
          if (c == '\n')
            return c;
-         ungetc (c, finput);
+         UNGETC (c);
 
          token = yylex ();
          used_up = 0;
@@ -828,44 +823,51 @@ 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 = skip_white_space_on_line ();
+         if (c == '\n')
+           return c;
+         UNGETC (c);
+       }
+
+      warning ("unrecognized text at end of #line");
     }
   else
     error ("invalid #-line");
 
   /* skip the rest of this line.  */
  skipline:
-  if (c == '\n')
-    return c;
-  while ((c = getc (finput)) != EOF && c != '\n');
+#if !USE_CPPLIB
+  if (c != '\n' && c != EOF && nextchar >= 0)
+    c = nextchar, nextchar = -1;
+#endif
+  while (c != '\n' && c != EOF)
+    c = GETC();
   return c;
 }
 \f
-#ifdef HANDLE_SYSV_PRAGMA
+#ifdef HANDLE_GENERIC_PRAGMAS
 
-/* Handle a #pragma directive.  INPUT is the current input stream,
-   and C is a character to reread.  Processes the entire input line
-   and returns a character for the caller to reread: either \n or EOF.  */
+/* Handle a #pragma directive.
+   TOKEN is the token we read after `#pragma'.  Processes the entire input
+   line and return non-zero iff the pragma has been successfully parsed.  */
 
 /* This function has to be in this file, in order to get at
    the token types.  */
 
-int
-handle_sysv_pragma (input, c)
-     FILE *input;
-     int c;
+static int
+handle_generic_pragma (token)
+     register int token;
 {
+  register int c;
+
   for (;;)
     {
-      while (c == ' ' || c == '\t')
-       c = getc (input);
-      if (c == '\n' || c == EOF)
-       {
-         handle_pragma_token (0, 0);
-         return c;
-       }
-      ungetc (c, input);
-      switch (yylex ())
+      switch (token)
        {
        case IDENTIFIER:
        case TYPENAME:
@@ -874,16 +876,27 @@ handle_sysv_pragma (input, c)
          handle_pragma_token (token_buffer, yylval.ttype);
          break;
        default:
-         handle_pragma_token (token_buffer, 0);
+         handle_pragma_token (token_buffer, NULL);
        }
+#if !USE_CPPLIB
       if (nextchar >= 0)
        c = nextchar, nextchar = -1;
       else
-       c = getc (input);
+#endif
+       c = GETC ();
+
+      while (c == ' ' || c == '\t')
+       c = GETC ();
+      UNGETC (c);
+      
+      if (c == '\n' || c == EOF)
+       return handle_pragma_token (NULL, NULL);
+
+      token = yylex ();
     }
 }
 
-#endif /* HANDLE_SYSV_PRAGMA */
+#endif /* HANDLE_GENERIC_PRAGMAS */
 \f
 #define ENDFILE -1  /* token that represents end-of-file */
 
@@ -894,10 +907,10 @@ static int
 readescape (ignore_ptr)
      int *ignore_ptr;
 {
-  register int c = getc (finput);
+  register int c = GETC();
   register int code;
   register unsigned count;
-  unsigned firstdig;
+  unsigned firstdig = 0;
   int nonnull;
 
   switch (c)
@@ -914,12 +927,12 @@ readescape (ignore_ptr)
       nonnull = 0;
       while (1)
        {
-         c = getc (finput);
+         c = GETC();
          if (!(c >= 'a' && c <= 'f')
              && !(c >= 'A' && c <= 'F')
              && !(c >= '0' && c <= '9'))
            {
-             ungetc (c, finput);
+             UNGETC (c);
              break;
            }
          code *= 16;
@@ -944,7 +957,7 @@ readescape (ignore_ptr)
        ;
       else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
               || (count > 1
-                  && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
+                  && (((unsigned)1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
                       <= firstdig)))
        pedwarn ("hex escape out of range");
       return code;
@@ -956,9 +969,9 @@ readescape (ignore_ptr)
       while ((c <= '7') && (c >= '0') && (count++ < 3))
        {
          code = (code * 8) + (c - '0');
-         c = getc (finput);
+         c = GETC();
        }
-      ungetc (c, finput);
+      UNGETC (c);
       return code;
 
     case '\\': case '\'': case '"':
@@ -1082,10 +1095,12 @@ yylex ()
   int wide_flag = 0;
   int objc_flag = 0;
 
+#if !USE_CPPLIB
   if (nextchar >= 0)
     c = nextchar, nextchar = -1;
   else
-    c = getc (finput);
+#endif
+    c = GETC();
 
   /* Effectively do c = skip_white_space (c)
      but do it faster in the usual cases.  */
@@ -1097,7 +1112,7 @@ yylex ()
       case '\f':
       case '\v':
       case '\b':
-       c = getc (finput);
+       c = GETC();
        break;
 
       case '\r':
@@ -1125,15 +1140,10 @@ yylex ()
       value = ENDFILE;
       break;
 
-    case '$':
-      if (dollars_in_ident)
-       goto letter;
-      return '$';
-
     case 'L':
       /* Capital L may start a wide-string or wide-character constant.  */
       {
-       register int c = getc (finput);
+       register int c = GETC();
        if (c == '\'')
          {
            wide_flag = 1;
@@ -1144,7 +1154,7 @@ yylex ()
            wide_flag = 1;
            goto string_constant;
          }
-       ungetc (c, finput);
+       UNGETC (c);
       }
       goto letter;
 
@@ -1157,14 +1167,14 @@ yylex ()
       else
        {
          /* '@' may start a constant string object.  */
-         register int c = getc(finput);
+         register int c = GETC ();
          if (c == '"')
            {
              objc_flag = 1;
              goto string_constant;
            }
-         ungetc(c, finput);
-         /* Fall through to treat '@' as the start of an indentifier.  */
+         UNGETC (c);
+         /* Fall through to treat '@' as the start of an identifier.  */
        }
 
     case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
@@ -1180,25 +1190,35 @@ yylex ()
     case 'u':  case 'v':  case 'w':  case 'x':  case 'y':
     case 'z':
     case '_':
+    case '$':
     letter:
       p = token_buffer;
-      while (isalnum (c) || c == '_' || c == '$' || c == '@')
+      while (ISALNUM (c) || c == '_' || c == '$' || c == '@')
        {
          /* Make sure this char really belongs in an identifier.  */
          if (c == '@' && ! doing_objc_thang)
            break;
-         if (c == '$' && ! dollars_in_ident)
-           break;
+         if (c == '$')
+           {
+             if (! dollars_in_ident)
+               error ("`$' in identifier");
+             else if (pedantic)
+               pedwarn ("`$' in identifier");
+           }
 
          if (p >= token_buffer + maxtoken)
            p = extend_token_buffer (p);
 
          *p++ = c;
-         c = getc (finput);
+         c = GETC();
        }
 
       *p = 0;
+#if USE_CPPLIB
+      UNGETC (c);
+#else
       nextchar = c;
+#endif
 
       value = IDENTIFIER;
       yylval.itype = 0;
@@ -1208,7 +1228,7 @@ yylex ()
       {
        register struct resword *ptr;
 
-       if (ptr = is_reserved_word (token_buffer, p - token_buffer))
+       if ((ptr = is_reserved_word (token_buffer, p - token_buffer)))
          {
            if (ptr->rid)
              yylval.ttype = ridpointers[(int) ptr->rid];
@@ -1278,7 +1298,23 @@ yylex ()
 
       break;
 
-    case '0':  case '1':  case '2':  case '3':  case '4':
+    case '0':  case '1':
+      {
+       int next_c;
+       /* Check first for common special case:  single-digit 0 or 1.  */
+
+       next_c = GETC ();
+       UNGETC (next_c);        /* Always undo this lookahead.  */
+       if (!ISALNUM (next_c) && next_c != '.')
+         {
+           token_buffer[0] = (char)c,  token_buffer[1] = '\0';
+           yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node;
+           value = CONSTANT;
+           break;
+         }
+       /*FALLTHRU*/
+      }
+    case '2':  case '3':  case '4':
     case '5':  case '6':  case '7':  case '8':  case '9':
     case '.':
       {
@@ -1307,11 +1343,11 @@ yylex ()
 
        if (c == '0')
          {
-           *p++ = (c = getc (finput));
+           *p++ = (c = GETC());
            if ((c == 'x') || (c == 'X'))
              {
                base = 16;
-               *p++ = (c = getc (finput));
+               *p++ = (c = GETC());
              }
            /* Leading 0 forces octal unless the 0 is the only digit.  */
            else if (c >= '0' && c <= '9')
@@ -1326,7 +1362,7 @@ yylex ()
        /* Read all the digits-and-decimal-points.  */
 
        while (c == '.'
-              || (isalnum (c) && c != 'l' && c != 'L'
+              || (ISALNUM (c) && c != 'l' && c != 'L'
                   && c != 'u' && c != 'U'
                   && c != 'i' && c != 'I' && c != 'j' && c != 'J'
                   && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F')))))
@@ -1335,25 +1371,31 @@ 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;
 
                base = 10;
-               *p++ = c = getc (finput);
+               *p++ = c = GETC();
                /* Accept '.' as the start of a floating-point number
                   only when it is followed by a digit.
                   Otherwise, unread the following non-digit
                   and use the '.' as a structural token.  */
-               if (p == token_buffer + 2 && !isdigit (c))
+               if (p == token_buffer + 2 && !ISDIGIT (c))
                  {
                    if (c == '.')
                      {
-                       c = getc (finput);
+                       c = GETC();
                        if (c == '.')
                          {
                            *p++ = c;
@@ -1362,7 +1404,7 @@ yylex ()
                          }
                        error ("parse error at `..'");
                      }
-                   ungetc (c, finput);
+                   UNGETC (c);
                    token_buffer[1] = 0;
                    value = '.';
                    goto done;
@@ -1373,7 +1415,7 @@ yylex ()
                /* It is not a decimal point.
                   It should be a digit (perhaps a hex digit).  */
 
-               if (isdigit (c))
+               if (ISDIGIT (c))
                  {
                    c = c - '0';
                  }
@@ -1421,7 +1463,7 @@ yylex ()
 
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
-               *p++ = (c = getc (finput));
+               *p++ = (c = GETC());
              }
          }
 
@@ -1437,8 +1479,8 @@ yylex ()
        if (floatflag != NOT_FLOAT)
          {
            tree type = double_type_node;
-           int garbage_chars = 0, exceeds_double = 0;
            int imag = 0;
+           int conversion_errno = 0;
            REAL_VALUE_TYPE value;
            jmp_buf handler;
 
@@ -1449,25 +1491,24 @@ yylex ()
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
                *p++ = c;
-               c = getc (finput);
+               c = GETC();
                if ((c == '+') || (c == '-'))
                  {
                    *p++ = c;
-                   c = getc (finput);
+                   c = GETC();
                  }
-               if (! isdigit (c))
+               if (! ISDIGIT (c))
                  error ("floating constant exponent has no digits");
-               while (isdigit (c))
+               while (ISDIGIT (c))
                  {
                    if (p >= token_buffer + maxtoken - 3)
                      p = extend_token_buffer (p);
                    *p++ = c;
-                   c = getc (finput);
+                   c = GETC();
                  }
              }
 
            *p = 0;
-           errno = 0;
 
            /* Convert string to a double, checking for overflow.  */
            if (setjmp (handler))
@@ -1477,85 +1518,117 @@ 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 (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                   && 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 (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                   && 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 (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                   && REAL_VALUE_ISINF (value) && pedantic)
-                 pedwarn ("floating point number exceeds range of `double'");
-             }
-           set_float_handler (NULL_PTR);
-           }
-#ifdef ERANGE
-           if (errno == ERANGE && !flag_traditional && pedantic)
-             {
-               /* ERANGE is also reported for underflow,
-                  so test the value to distinguish overflow from that.  */
-               if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                   && (REAL_VALUES_LESS (dconst1, value)
-                       || REAL_VALUES_LESS (value, dconstm1)))
+                   /* 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();
+                 }
+
+               /* The second argument, machine_mode, of REAL_VALUE_ATOF
+                  tells the desired precision of the binary result
+                  of decimal-to-binary conversion.  */
+
+               if (fflag)
                  {
-                   pedwarn ("floating point number exceeds range of `double'");
-                   exceeds_double = 1;
+                   if (lflag)
+                     error ("both `f' and `l' in floating constant");
+
+                   type = float_type_node;
+                   errno = 0;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
+                   /* 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;
+                   errno = 0;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `long double'");
+                 }
+               else
+                 {
+                   errno = 0;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `double'");
+                 }
+
+               set_float_handler (NULL_PTR);
+           }
+#ifdef ERANGE
+           /* ERANGE is also reported for underflow,
+              so test the value to distinguish overflow from that.  */
+           if (conversion_errno == ERANGE && !flag_traditional && pedantic
+               && (REAL_VALUES_LESS (dconst1, value)
+                   || REAL_VALUES_LESS (value, dconstm1)))
+             warning ("floating point number exceeds range of `double'");
 #endif
-           /* Note: garbage_chars is -1 if first char is *not* garbage.  */
-           while (isalnum (c) || c == '.' || c == '_'
-                  || (!flag_traditional && (c == '+' || c == '-')
-                      && (p[-1] == 'e' || p[-1] == 'E')))
-             {
-               if (p >= token_buffer + maxtoken - 3)
-                 p = extend_token_buffer (p);
-               *p++ = c;
-               c = getc (finput);
-               garbage_chars++;
-             }
-           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),
+             yylval.ttype = build_complex (NULL_TREE,
+                                           convert (type, integer_zero_node),
                                            build_real (type, value));
            else
              yylval.ttype = build_real (type, value);
-
-           ungetc (c, finput);
-           *p = 0;
          }
        else
          {
@@ -1567,6 +1640,7 @@ yylex ()
            int spec_imag = 0;
            int bytes, warn, i;
 
+           traditional_type = ansi_type = type = NULL_TREE;
            while (1)
              {
                if (c == 'u' || c == 'U')
@@ -1581,7 +1655,7 @@ yylex ()
                      {
                        if (spec_long_long)
                          error ("three `l's in integer constant");
-                       else if (pedantic)
+                       else if (pedantic && ! in_system_header && warn_long_long)
                          pedwarn ("ANSI C forbids long long integer constants");
                        spec_long_long = 1;
                      }
@@ -1591,49 +1665,27 @@ 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
-                 {
-                   if (isalnum (c) || c == '.' || c == '_'
-                       || (!flag_traditional && (c == '+' || c == '-')
-                           && (p[-1] == 'e' || p[-1] == 'E')))
-                     {
-                       error ("garbage at end of number");
-                       while (isalnum (c) || c == '.' || c == '_'
-                              || (!flag_traditional && (c == '+' || c == '-')
-                                  && (p[-1] == 'e' || p[-1] == 'E')))
-                         {
-                           if (p >= token_buffer + maxtoken - 3)
-                             p = extend_token_buffer (p);
-                           *p++ = c;
-                           c = getc (finput);
-                         }
-                     }
-                   break;
-                 }
+                 break;
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
                *p++ = c;
-               c = getc (finput);
+               c = GETC();
              }
 
-           ungetc (c, finput);
-
-           /* If the constant is not long long and it won't fit in an
-              unsigned long, or if the constant is long long and won't fit
-              in an unsigned long long, then warn that the constant is out
-              of range.  */
+           /* If the constant won't fit in an unsigned long long,
+              then warn that the constant is out of range.  */
 
            /* ??? This assumes that long long and long integer types are
               a multiple of 8 bits.  This better than the original code
               though which assumed that long was exactly 32 bits and long
               long was exactly 64 bits.  */
 
-           if (spec_long_long)
-             bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
-           else
-             bytes = TYPE_PRECISION (long_integer_type_node) / 8;
+           bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
 
            warn = overflow;
            for (i = bytes; i < TOTAL_PARTS; i++)
@@ -1700,11 +1752,11 @@ yylex ()
                else if (! spec_unsigned && !spec_long_long
                         && int_fits_type_p (yylval.ttype, long_integer_type_node))
                  ansi_type = long_integer_type_node;
-               else if (! spec_long_long)
+               else if (! spec_long_long
+                        && int_fits_type_p (yylval.ttype,
+                                            long_unsigned_type_node))
                  ansi_type = long_unsigned_type_node;
                else if (! spec_unsigned
-                        /* Verify value does not overflow into sign bit.  */
-                        && TREE_INT_CST_HIGH (yylval.ttype) >= 0
                         && int_fits_type_p (yylval.ttype,
                                             long_long_integer_type_node))
                  ansi_type = long_long_integer_type_node;
@@ -1726,8 +1778,9 @@ yylex ()
                  warning ("width of integer constant may change on other systems with -traditional");
              }
 
-           if (!flag_traditional && !int_fits_type_p (yylval.ttype, type)
-               && !warn)
+           if (pedantic && !flag_traditional && !spec_long_long && !warn
+               && (TYPE_PRECISION (long_integer_type_node)
+                   < TYPE_PRECISION (type)))
              pedwarn ("integer constant out of range");
 
            if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
@@ -1738,8 +1791,9 @@ yylex ()
                if (TYPE_PRECISION (type)
                    <= TYPE_PRECISION (integer_type_node))
                  yylval.ttype
-                   = build_complex (integer_zero_node,
-                                    convert (integer_type_node, yylval.ttype));
+                   = build_complex (NULL_TREE, integer_zero_node,
+                                    convert (integer_type_node,
+                                             yylval.ttype));
                else
                  error ("complex integer constant is too wide for `complex int'");
              }
@@ -1750,13 +1804,21 @@ 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;
-
-           *p = 0;
          }
 
+       UNGETC (c);
+       *p = 0;
+
+       if (ISALNUM (c) || c == '.' || c == '_' || c == '$'
+           || (!flag_traditional && (c == '-' || c == '+')
+               && (p[-1] == 'e' || p[-1] == 'E')))
+         error ("missing white space after number `%s'", token_buffer);
+
        value = CONSTANT; break;
       }
 
@@ -1765,30 +1827,27 @@ yylex ()
       {
        register int result = 0;
        register int num_chars = 0;
+       int chars_seen = 0;
        unsigned width = TYPE_PRECISION (char_type_node);
        int max_chars;
-
-       if (wide_flag)
-         {
-           width = WCHAR_TYPE_SIZE;
 #ifdef MULTIBYTE_CHARS
-           max_chars = MB_CUR_MAX;
-#else
-           max_chars = 1;
+       int longest_char = local_mb_cur_max ();
+       (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
 #endif
-         }
-       else
-         max_chars = TYPE_PRECISION (integer_type_node) / width;
+
+       max_chars = TYPE_PRECISION (integer_type_node) / width;
+       if (wide_flag)
+         width = WCHAR_TYPE_SIZE;
 
        while (1)
          {
          tryagain:
-
-           c = getc (finput);
+           c = GETC();
 
            if (c == '\'' || c == EOF)
              break;
 
+           ++chars_seen;
            if (c == '\\')
              {
                int ignore = 0;
@@ -1796,10 +1855,10 @@ yylex ()
                if (ignore)
                  goto tryagain;
                if (width < HOST_BITS_PER_INT
-                   && (unsigned) c >= (1 << width))
+                   && (unsigned) c >= ((unsigned)1 << width))
                  pedwarn ("escape sequence out of range for character");
 #ifdef MAP_CHARACTER
-               if (isprint (c))
+               if (ISPRINT (c))
                  c = MAP_CHARACTER (c);
 #endif
              }
@@ -1809,18 +1868,76 @@ yylex ()
                  pedwarn ("ANSI C forbids newline in character constant");
                lineno++;
              }
-#ifdef MAP_CHARACTER
            else
-             c = MAP_CHARACTER (c);
+             {
+#ifdef MULTIBYTE_CHARS
+               wchar_t wc;
+               int i;
+               int char_len = -1;
+               for (i = 1; i <= longest_char; ++i)
+                 {
+                   if (i > maxtoken - 4)
+                     extend_token_buffer (token_buffer);
+
+                   token_buffer[i] = c;
+                   char_len = local_mbtowc (& wc,
+                                            token_buffer + 1,
+                                            i);
+                   if (char_len != -1)
+                     break;
+                   c = GETC ();
+                 }
+               if (char_len > 1)
+                 {
+                   /* mbtowc sometimes needs an extra char before accepting */
+                   if (char_len < i)
+                     UNGETC (c);
+                   if (! wide_flag)
+                     {
+                       /* Merge character into result; ignore excess chars.  */
+                       for (i = 1; i <= char_len; ++i)
+                         {
+                           if (i > max_chars)
+                             break;
+                           if (width < HOST_BITS_PER_INT)
+                             result = (result << width)
+                               | (token_buffer[i]
+                                  & ((1 << width) - 1));
+                           else
+                             result = token_buffer[i];
+                         }
+                       num_chars += char_len;
+                       goto tryagain;
+                     }
+                   c = wc;
+                 }
+               else
+                 {
+                   if (char_len == -1)
+                     warning ("Ignoring invalid multibyte character");
+                   if (wide_flag)
+                     c = wc;
+#ifdef MAP_CHARACTER
+                   else
+                     c = MAP_CHARACTER (c);
 #endif
+                 }
+#else /* ! MULTIBYTE_CHARS */
+#ifdef MAP_CHARACTER
+               c = MAP_CHARACTER (c);
+#endif
+#endif /* ! MULTIBYTE_CHARS */
+             }
 
-           num_chars++;
-           if (num_chars > maxtoken - 4)
-             extend_token_buffer (token_buffer);
-
-           token_buffer[num_chars] = c;
+           if (wide_flag)
+             {
+               if (chars_seen == 1) /* only keep the first one */
+                 result = c;
+               goto tryagain;
+             }
 
            /* Merge character into result; ignore excess chars.  */
+           num_chars += (width / TYPE_PRECISION (char_type_node));
            if (num_chars < max_chars + 1)
              {
                if (width < HOST_BITS_PER_INT)
@@ -1830,19 +1947,16 @@ yylex ()
              }
          }
 
-       token_buffer[num_chars + 1] = '\'';
-       token_buffer[num_chars + 2] = 0;
-
        if (c != '\'')
          error ("malformatted character constant");
-       else if (num_chars == 0)
+       else if (chars_seen == 0)
          error ("empty character constant");
        else if (num_chars > max_chars)
          {
            num_chars = max_chars;
            error ("character constant too long");
          }
-       else if (num_chars != 1 && ! flag_traditional)
+       else if (chars_seen != 1 && ! flag_traditional && warn_multichar)
          warning ("multi-character character constant");
 
        /* If char type is signed, sign-extend the constant.  */
@@ -1855,34 +1969,18 @@ yylex ()
            else if (TREE_UNSIGNED (char_type_node)
                     || ((result >> (num_bits - 1)) & 1) == 0)
              yylval.ttype
-               = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
+               = build_int_2 (result & (~(unsigned HOST_WIDE_INT) 0
                                         >> (HOST_BITS_PER_WIDE_INT - num_bits)),
                               0);
            else
              yylval.ttype
-               = build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
+               = build_int_2 (result | ~(~(unsigned HOST_WIDE_INT) 0
                                          >> (HOST_BITS_PER_WIDE_INT - num_bits)),
                               -1);
            TREE_TYPE (yylval.ttype) = integer_type_node;
          }
        else
          {
-#ifdef MULTIBYTE_CHARS
-           /* Set the initial shift state and convert the next sequence.  */
-           result = 0;
-           /* In all locales L'\0' is zero and mbtowc will return zero,
-              so don't use it.  */
-           if (num_chars > 1
-               || (num_chars == 1 && token_buffer[1] != '\0'))
-             {
-               wchar_t wc;
-               (void) mbtowc (NULL_PTR, NULL_PTR, 0);
-               if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
-                 result = wc;
-               else
-                 warning ("Ignoring invalid multibyte character");
-             }
-#endif
            yylval.ttype = build_int_2 (result, 0);
            TREE_TYPE (yylval.ttype) = wchar_type_node;
          }
@@ -1894,21 +1992,25 @@ yylex ()
     case '"':
     string_constant:
       {
-       c = getc (finput);
+       unsigned width = wide_flag ? WCHAR_TYPE_SIZE
+                                  : TYPE_PRECISION (char_type_node);
+#ifdef MULTIBYTE_CHARS
+       int longest_char = local_mb_cur_max ();
+       (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
+#endif
+       c = GETC ();
        p = token_buffer + 1;
 
        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);
                if (ignore)
                  goto skipnewline;
-               if (!wide_flag
-                   && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
-                   && c >= (1 << TYPE_PRECISION (char_type_node)))
+               if (width < HOST_BITS_PER_INT
+                   && (unsigned) c >= ((unsigned)1 << width))
                  pedwarn ("escape sequence out of range for character");
              }
            else if (c == '\n')
@@ -1917,74 +2019,122 @@ yylex ()
                  pedwarn ("ANSI C forbids newline in string constant");
                lineno++;
              }
+           else
+             {
+#ifdef MULTIBYTE_CHARS
+               wchar_t wc;
+               int i;
+               int char_len = -1;
+               for (i = 0; i < longest_char; ++i)
+                 {
+                   if (p + i >= token_buffer + maxtoken)
+                     p = extend_token_buffer (p);
+                   p[i] = c;
+
+                   char_len = local_mbtowc (& wc, p, i + 1);
+                   if (char_len != -1)
+                     break;
+                   c = GETC ();
+                 }
+               if (char_len == -1)
+                 warning ("Ignoring invalid multibyte character");
+               else
+                 {
+                   /* mbtowc sometimes needs an extra char before accepting */
+                   if (char_len <= i)
+                     UNGETC (c);
+                   if (! wide_flag)
+                     {
+                       p += (i + 1);
+                       c = GETC ();
+                       continue;
+                     }
+                   c = wc;
+                 }
+#endif /* MULTIBYTE_CHARS */
+             }
 
-           if (p == token_buffer + maxtoken)
-             p = extend_token_buffer (p);
-           *p++ = c;
+           /* Add this single character into the buffer either as a wchar_t
+              or as a single byte.  */
+           if (wide_flag)
+             {
+               unsigned width = TYPE_PRECISION (char_type_node);
+               unsigned bytemask = (1 << width) - 1;
+               int byte;
+
+               if (p + WCHAR_BYTES > token_buffer + maxtoken)
+                 p = extend_token_buffer (p);
+
+               for (byte = 0; byte < WCHAR_BYTES; ++byte)
+                 {
+                   int value;
+                   if (byte >= (int) sizeof (c))
+                     value = 0;
+                   else
+                     value = (c >> (byte * width)) & bytemask;
+                   if (BYTES_BIG_ENDIAN)
+                     p[WCHAR_BYTES - byte - 1] = value;
+                   else
+                     p[byte] = value;
+                 }
+               p += WCHAR_BYTES;
+             }
+           else
+             {
+               if (p >= token_buffer + maxtoken)
+                 p = extend_token_buffer (p);
+               *p++ = c;
+             }
 
          skipnewline:
-           c = getc (finput);
+           c = GETC ();
          }
-       *p = 0;
+
+       /* Terminate the string value, either with a single byte zero
+          or with a wide zero.  */
+       if (wide_flag)
+         {
+           if (p + WCHAR_BYTES > token_buffer + maxtoken)
+             p = extend_token_buffer (p);
+           bzero (p, WCHAR_BYTES);
+           p += WCHAR_BYTES;
+         }
+       else
+         {
+           if (p >= token_buffer + maxtoken)
+             p = extend_token_buffer (p);
+           *p++ = 0;
+         }
+
+       if (c < 0)
+         error ("Unterminated string constant");
 
        /* We have read the entire constant.
           Construct a STRING_CST for the result.  */
 
        if (wide_flag)
          {
-           /* If this is a L"..." wide-string, convert the multibyte string
-              to a wide character string.  */
-           char *widep = (char *) alloca ((p - token_buffer) * WCHAR_BYTES);
-           int len;
-
-#ifdef MULTIBYTE_CHARS
-           len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
-           if (len < 0 || len >= (p - token_buffer))
-             {
-               warning ("Ignoring invalid multibyte string");
-               len = 0;
-             }
-           bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
-#else
-           {
-             union { long l; char c[sizeof (long)]; } u;
-             int big_endian;
-             char *wp, *cp;
-
-             /* Determine whether host is little or big endian.  */
-             u.l = 1;
-             big_endian = u.c[sizeof (long) - 1];
-             wp = widep + (big_endian ? WCHAR_BYTES - 1 : 0);
-
-             bzero (widep, (p - token_buffer) * WCHAR_BYTES);
-             for (cp = token_buffer + 1; cp < p; cp++)
-               *wp = *cp, wp += WCHAR_BYTES;
-             len = p - token_buffer - 1;
-           }
-#endif
-           yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
+           yylval.ttype = build_string (p - (token_buffer + 1),
+                                        token_buffer + 1);
            TREE_TYPE (yylval.ttype) = wchar_array_type_node;
            value = STRING;
          }
        else if (objc_flag)
          {
-           extern tree build_objc_string();
            /* Return an Objective-C @"..." constant string object.  */
-           yylval.ttype = build_objc_string (p - token_buffer,
+           yylval.ttype = build_objc_string (p - (token_buffer + 1),
                                              token_buffer + 1);
            TREE_TYPE (yylval.ttype) = char_array_type_node;
            value = OBJC_STRING;
          }
        else
          {
-           yylval.ttype = build_string (p - token_buffer, token_buffer + 1);
+           yylval.ttype = build_string (p - (token_buffer + 1),
+                                        token_buffer + 1);
            TREE_TYPE (yylval.ttype) = char_array_type_node;
            value = STRING;
          }
 
-       *p++ = '"';
-       *p = 0;
-
        break;
       }
 
@@ -1992,6 +2142,7 @@ yylex ()
     case '-':
     case '&':
     case '|':
+    case ':':
     case '<':
     case '>':
     case '*':
@@ -2033,7 +2184,7 @@ yylex ()
            yylval.code = GT_EXPR; break;
          }
 
-       token_buffer[1] = c1 = getc (finput);
+       token_buffer[1] = c1 = GETC();
        token_buffer[2] = 0;
 
        if (c1 == '=')
@@ -2069,9 +2220,29 @@ yylex ()
              c = RSHIFT;
              goto combine;
            }
-       else if ((c == '-') && (c1 == '>'))
-         { value = POINTSAT; goto done; }
-       ungetc (c1, finput);
+       else
+         switch (c)
+           {
+           case '-':
+             if (c1 == '>')
+               { value = POINTSAT; goto done; }
+             break;
+           case ':':
+             if (c1 == '>')
+               { value = ']'; goto done; }
+             break;
+           case '<':
+             if (c1 == '%')
+               { value = '{'; indent_level++; goto done; }
+             if (c1 == ':')
+               { value = '['; goto done; }
+             break;
+           case '%':
+             if (c1 == '>')
+               { value = '}'; indent_level--; goto done; }
+             break;
+           }
+       UNGETC (c1);
        token_buffer[1] = 0;
 
        if ((c == '<') || (c == '>'))
@@ -2085,6 +2256,16 @@ yylex ()
       value = 1;
       break;
 
+    case '{':
+      indent_level++;
+      value = c;
+      break;
+
+    case '}':
+      indent_level--;
+      value = c;
+      break;
+
     default:
       value = c;
     }
This page took 0.083168 seconds and 5 git commands to generate.