/* 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.
#include "c-tree.h"
#include "flags.h"
#include "c-parse.h"
+#include "c-pragma.h"
+
+#include <ctype.h>
#ifdef MULTIBYTE_CHARS
#include <stdlib.h>
int doing_objc_thang;
-extern tree lookup_interface ();
+extern tree is_class_name ();
extern int yydebug;
/* File used for outputting assembler code. */
extern FILE *asm_out_file;
-#ifndef LONG_LONG_TYPE_SIZE
-#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
#ifndef WCHAR_TYPE_SIZE
#ifdef INT_TYPE_SIZE
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
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 -N is_reserved_word -k1,3,$ c-parse.gperf */
-struct resword { char *name; short token; enum rid rid; };
-
-#define TOTAL_KEYWORDS 53
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 13
-#define MIN_HASH_VALUE 7
-#define MAX_HASH_VALUE 102
-/* maximum key range = 96, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#endif
-static unsigned int
-hash (str, len)
- register char *str;
- register int unsigned len;
-{
- static unsigned char asso_values[] =
- {
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
- 103, 103, 103, 103, 103, 1, 103, 2, 1, 24,
- 1, 5, 19, 39, 16, 13, 103, 1, 25, 1,
- 34, 34, 24, 103, 13, 12, 1, 45, 24, 7,
- 103, 103, 2, 103, 103, 103, 103, 103,
- };
- 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]];
-}
-
-#ifdef __GNUC__
-__inline
-#endif
-struct resword *
-is_reserved_word (str, len)
- register char *str;
- register unsigned int len;
-{
- static struct resword wordlist[] =
- {
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"asm", ASM_KEYWORD, NORID},
- {"",},
- {"__asm", ASM_KEYWORD, NORID},
- {"",},
- {"__asm__", ASM_KEYWORD, NORID},
- {"break", BREAK, NORID},
- {"__typeof__", TYPEOF, NORID},
- {"",},
- {"__alignof__", ALIGNOF, NORID},
- {"",},
- {"__attribute__", ATTRIBUTE, NORID},
- {"int", TYPESPEC, RID_INT},
- {"__attribute", ATTRIBUTE, NORID},
- {"__extension__", EXTENSION, NORID},
- {"",},
- {"__signed", TYPESPEC, RID_SIGNED},
- {"",},
- {"__signed__", TYPESPEC, RID_SIGNED},
- {"__inline__", SCSPEC, RID_INLINE},
- {"else", ELSE, NORID},
- {"__inline", SCSPEC, RID_INLINE},
- {"default", DEFAULT, NORID},
- {"__typeof", TYPEOF, NORID},
- {"while", WHILE, NORID},
- {"__alignof", ALIGNOF, NORID},
- {"struct", STRUCT, NORID},
- {"__const", TYPE_QUAL, RID_CONST},
- {"if", IF, NORID},
- {"__const__", TYPE_QUAL, RID_CONST},
- {"__label__", LABEL, NORID},
- {"do", DO, NORID},
- {"__volatile__", TYPE_QUAL, RID_VOLATILE},
- {"sizeof", SIZEOF, NORID},
- {"__volatile", TYPE_QUAL, RID_VOLATILE},
- {"auto", SCSPEC, RID_AUTO},
- {"void", TYPESPEC, RID_VOID},
- {"char", TYPESPEC, RID_CHAR},
- {"static", SCSPEC, RID_STATIC},
- {"case", CASE, NORID},
- {"extern", SCSPEC, RID_EXTERN},
- {"switch", SWITCH, NORID},
- {"for", FOR, NORID},
- {"inline", SCSPEC, RID_INLINE},
- {"typeof", TYPEOF, NORID},
- {"typedef", SCSPEC, RID_TYPEDEF},
- {"short", TYPESPEC, RID_SHORT},
- {"",},
- {"return", RETURN, NORID},
- {"enum", ENUM, NORID},
- {"",},
- {"double", TYPESPEC, RID_DOUBLE},
- {"signed", TYPESPEC, RID_SIGNED},
- {"float", TYPESPEC, RID_FLOAT},
- {"",}, {"",},
- {"volatile", TYPE_QUAL, RID_VOLATILE},
- {"",},
- {"const", TYPE_QUAL, RID_CONST},
- {"",},
- {"unsigned", TYPESPEC, RID_UNSIGNED},
- {"",}, {"",}, {"",}, {"",},
- {"continue", CONTINUE, NORID},
- {"",},
- {"register", SCSPEC, RID_REGISTER},
- {"",}, {"",}, {"",}, {"",},
- {"goto", GOTO, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
-
- {"union", UNION, NORID},
- {"",}, {"",}, {"",}, {"",},
- {"long", TYPESPEC, RID_LONG},
- };
-
- 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.
}
\f
void
+forget_protocol_qualifiers ()
+{
+ int i, n = sizeof wordlist / sizeof (struct resword);
+
+ for (i = 0; i < n; i++)
+ if ((int) wordlist[i].rid >= (int) RID_IN
+ && (int) wordlist[i].rid <= (int) RID_ONEWAY)
+ wordlist[i].name = "";
+}
+
+void
+remember_protocol_qualifiers ()
+{
+ int i, n = sizeof wordlist / sizeof (struct resword);
+
+ for (i = 0; i < n; i++)
+ if (wordlist[i].rid == RID_IN)
+ wordlist[i].name = "in";
+ else if (wordlist[i].rid == RID_OUT)
+ wordlist[i].name = "out";
+ else if (wordlist[i].rid == RID_INOUT)
+ wordlist[i].name = "inout";
+ else if (wordlist[i].rid == RID_BYCOPY)
+ wordlist[i].name = "bycopy";
+ else if (wordlist[i].rid == RID_ONEWAY)
+ wordlist[i].name = "oneway";
+}
+\f
+void
init_lex ()
{
/* Make identifier nodes long enough for the language-specific slots. */
ridpointers[(int) RID_EXTERN] = get_identifier ("extern");
ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef");
ridpointers[(int) RID_REGISTER] = get_identifier ("register");
+ ridpointers[(int) RID_ITERATOR] = get_identifier ("iterator");
+ ridpointers[(int) RID_COMPLEX] = get_identifier ("complex");
+ ridpointers[(int) RID_ID] = get_identifier ("id");
+ ridpointers[(int) RID_IN] = get_identifier ("in");
+ ridpointers[(int) RID_OUT] = get_identifier ("out");
+ ridpointers[(int) RID_INOUT] = get_identifier ("inout");
+ ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy");
+ ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway");
+ forget_protocol_qualifiers();
/* Some options inhibit certain reserved words.
Clear those words out of the hash table so they won't be recognized. */
do { struct resword *s = is_reserved_word (STRING, sizeof (STRING) - 1); \
if (s) s->name = ""; } while (0)
+ if (! doing_objc_thang)
+ UNSET_RESERVED_WORD ("id");
+
if (flag_traditional)
{
UNSET_RESERVED_WORD ("const");
UNSET_RESERVED_WORD ("typeof");
UNSET_RESERVED_WORD ("signed");
UNSET_RESERVED_WORD ("inline");
+ UNSET_RESERVED_WORD ("iterator");
+ UNSET_RESERVED_WORD ("complex");
}
if (flag_no_asm)
{
UNSET_RESERVED_WORD ("asm");
UNSET_RESERVED_WORD ("typeof");
UNSET_RESERVED_WORD ("inline");
+ UNSET_RESERVED_WORD ("iterator");
+ UNSET_RESERVED_WORD ("complex");
}
}
{
case IDENTIFIER:
case TYPENAME:
+ case OBJECTNAME:
t = yylval.ttype;
if (IDENTIFIER_POINTER (t))
fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
case CONSTANT:
t = yylval.ttype;
if (TREE_CODE (t) == INTEGER_CST)
- fprintf (file, " 0x%8x%8x", TREE_INT_CST_HIGH (t),
- TREE_INT_CST_LOW (t));
+ fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+ " 0x%lx%016lx",
+#else
+ " 0x%x%016x",
+#endif
+#else
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+ " 0x%lx%08lx",
+#else
+ " 0x%x%08x",
+#endif
+#endif
+ TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t));
break;
}
}
{
#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 */
}
}
/* 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)
{
while (c == ' ' || c == '\t')
c = getc (finput);
if (c == '\n')
- return c;
+ {
+ /* Update the name in the top element of input_file_stack. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
+
+ return c;
+ }
ungetc (c, finput);
token = yylex ();
}
}
+ /* Now that we've pushed or popped the input stack,
+ update the name in the top element. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
+
/* If we have handled a `1' or a `2',
see if there is another number to read. */
if (used_up)
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");
#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,
- or -1 if it is backslash-newline. */
+ or store 1 in *ignore_ptr if it is backslash-newline. */
static int
-readescape ()
+readescape (ignore_ptr)
+ int *ignore_ptr;
{
register int c = getc (finput);
register int code;
register unsigned count;
- unsigned firstdig;
+ unsigned firstdig = 0;
+ int nonnull;
switch (c)
{
code = 0;
count = 0;
+ nonnull = 0;
while (1)
{
c = getc (finput);
code += c - 'A' + 10;
if (c >= '0' && c <= '9')
code += c - '0';
- if (count == 0)
- firstdig = code;
- count++;
+ if (code != 0 || count != 0)
+ {
+ if (count == 0)
+ firstdig = code;
+ count++;
+ }
+ nonnull = 1;
}
- if (count == 0)
+ if (! nonnull)
error ("\\x used with no following hex digits");
+ else if (count == 0)
+ /* Digits are all 0's. Ok. */
+ ;
else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
|| (count > 1
&& ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
case '\n':
lineno++;
- return -1;
+ *ignore_ptr = 1;
+ return 0;
case 'n':
return TARGET_NEWLINE;
#endif
return TARGET_VT;
+ case 'e':
case 'E':
- pedwarn ("non-ANSI-standard escape sequence, `\\E'");
+ if (pedantic)
+ pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
return 033;
case '?':
case '(':
case '{':
case '[':
+ /* `\%' is used to prevent SCCS from getting confused. */
+ case '%':
if (pedantic)
pedwarn ("non-ANSI escape sequence `\\%c'", c);
return c;
}
- if (c >= 040 && c <= 0177)
+ if (c >= 040 && c < 0177)
pedwarn ("unknown escape sequence `\\%c'", c);
else
pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
register char *p;
register int value;
int wide_flag = 0;
+ int objc_flag = 0;
if (nextchar >= 0)
c = nextchar, nextchar = -1;
value = c;
break;
}
- p = token_buffer;
- *p++ = '@';
- c = getc (finput);
- while (isalnum (c) || c == '_')
+ else
{
- if (p >= token_buffer + maxtoken)
- p = extend_token_buffer (p);
-
- *p++ = c;
- c = getc (finput);
+ /* '@' may start a constant string object. */
+ register int c = getc(finput);
+ if (c == '"')
+ {
+ objc_flag = 1;
+ goto string_constant;
+ }
+ ungetc(c, finput);
+ /* Fall through to treat '@' as the start of an indentifier. */
}
- *p = 0;
- nextchar = c;
- value = recognize_objc_keyword (token_buffer + 1);
- if (value != 0)
- break;
- error ("invalid Objective C keyword `%s'", token_buffer);
- /* Cause a syntax error--1 is not a valid token type. */
- value = 1;
- break;
-
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'M': case 'N': case 'O':
p = token_buffer;
while (isalnum (c) || c == '_' || c == '$' || c == '@')
{
- if (p >= token_buffer + maxtoken)
- p = extend_token_buffer (p);
+ /* Make sure this char really belongs in an identifier. */
+ if (c == '@' && ! doing_objc_thang)
+ break;
if (c == '$' && ! dollars_in_ident)
break;
+ if (p >= token_buffer + maxtoken)
+ p = extend_token_buffer (p);
+
*p++ = c;
c = getc (finput);
}
yylval.ttype = ridpointers[(int) ptr->rid];
value = (int) ptr->token;
+ /* Only return OBJECTNAME if it is a typedef. */
+ if (doing_objc_thang && value == OBJECTNAME)
+ {
+ lastiddecl = lookup_name(yylval.ttype);
+
+ if (lastiddecl == NULL_TREE
+ || TREE_CODE (lastiddecl) != TYPE_DECL)
+ value = IDENTIFIER;
+ }
+
/* Even if we decided to recognize asm, still perhaps warn. */
if (pedantic
&& (value == ASM_KEYWORD || value == TYPEOF
if (value == IDENTIFIER)
{
+ if (token_buffer[0] == '@')
+ error("invalid identifier `%s'", token_buffer);
+
yylval.ttype = get_identifier (token_buffer);
lastiddecl = lookup_name (yylval.ttype);
&& DECL_INITIAL (lastiddecl) != 0
&& TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST)
{
- yylval.ttype = DECL_INITIAL (lastiddecl);
+ tree stringval = DECL_INITIAL (lastiddecl);
+
+ /* Copy the string value so that we won't clobber anything
+ if we put something in the TREE_CHAIN of this one. */
+ yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
+ TREE_STRING_POINTER (stringval));
value = STRING;
}
else if (doing_objc_thang)
{
- tree objc_interface_decl = lookup_interface (yylval.ttype);
+ tree objc_interface_decl = is_class_name (yylval.ttype);
if (objc_interface_decl)
{
/* for multi-precision arithmetic,
we actually store only HOST_BITS_PER_CHAR bits in each part.
The number of parts is chosen so as to be sufficient to hold
- at least as many bits as are in a target `long long' value. */
-#define TOTAL_PARTS (LONG_LONG_TYPE_SIZE / HOST_BITS_PER_CHAR) + 2
+ the enough bits to fit into the two HOST_WIDE_INTs that contain
+ the integer value (this is always at least as many bits as are
+ in a target `long long' value, but may be wider). */
+#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
int parts[TOTAL_PARTS];
int overflow = 0;
/* Read all the digits-and-decimal-points. */
while (c == '.'
- || (isalnum (c) && (c != 'l') && (c != 'L')
- && (c != 'u') && (c != 'U')
+ || (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')))))
{
if (c == '.')
{
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;
}
else if (base <= 10)
{
- if ((c&~040) == 'E')
+ if (c == 'e' || c == 'E')
{
base = 10;
floatflag = AFTER_POINT;
if (floatflag != NOT_FLOAT)
{
tree type = double_type_node;
- char f_seen = 0;
- char l_seen = 0;
+ int garbage_chars = 0, exceeds_double = 0;
+ int imag = 0;
REAL_VALUE_TYPE value;
jmp_buf handler;
}
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);
- value = REAL_VALUE_ATOF (token_buffer);
- set_float_handler (0);
- }
-#ifdef ERANGE
- if (errno == ERANGE && !flag_traditional && pedantic)
- {
- char *p1 = token_buffer;
- /* Check for "0.0" and variants;
- SunOS 4 spuriously returns ERANGE for them. */
- while (*p1 == '0') p1++;
- if (*p1 == '.')
- {
- p1++;
- while (*p1 == '0') p1++;
- }
- if (*p1 == 'e' || *p1 == 'E')
- {
- /* with significand==0, ignore the exponent */
- p1++;
- while (*p1 != 0) p1++;
- }
- /* ERANGE is also reported for underflow,
- so test the value to distinguish overflow from that. */
- if (*p1 != 0 && (value > 1.0 || value < -1.0))
- pedwarn ("floating point number exceeds range of `double'");
- }
-#endif
- /* Read the suffixes to choose a data type. */
- while (1)
- {
- if (c == 'f' || c == 'F')
+ while (1)
{
- if (f_seen)
- error ("two `f's in floating constant");
- else
+ int lose = 0;
+
+ /* Read the suffixes to choose a data type. */
+ switch (c)
{
- f_seen = 1;
- type = float_type_node;
- value = real_value_truncate (TYPE_MODE (type), value);
- if (REAL_VALUE_ISINF (value) && pedantic)
- pedwarn ("floating point number exceeds range of `float'");
+ 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);
}
- else if (c == 'l' || c == 'L')
+
+ /* 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)
{
- if (l_seen)
- error ("two `l's in floating constant");
- l_seen = 1;
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
{
- if (isalnum (c))
- {
- error ("garbage at end of number");
- while (isalnum (c))
- {
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- c = getc (finput);
- }
- }
- break;
+ 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)
+ {
+ /* ERANGE is also reported for underflow,
+ so test the value to distinguish overflow from that. */
+ if (REAL_VALUES_LESS (dconst1, value)
+ || REAL_VALUES_LESS (value, dconstm1))
+ {
+ warning ("floating point number exceeds range of `double'");
+ exceeds_double = 1;
}
+ }
+#endif
+ garbage_chars = 0;
+ 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. */
- yylval.ttype = build_real (type, value);
+ if (imag)
+ yylval.ttype = build_complex (convert (type, integer_zero_node),
+ build_real (type, value));
+ else
+ yylval.ttype = build_real (type, value);
ungetc (c, finput);
*p = 0;
else
{
tree traditional_type, ansi_type, type;
+ HOST_WIDE_INT high, low;
int spec_unsigned = 0;
int spec_long = 0;
int spec_long_long = 0;
+ int spec_imag = 0;
int bytes, warn, i;
while (1)
}
spec_long = 1;
}
+ else if (c == 'i' || c == 'j' || c == 'I' || c == 'J')
+ {
+ 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))
+ if (isalnum (c) || c == '.' || c == '_'
+ || (!flag_traditional && (c == '+' || c == '-')
+ && (p[-1] == 'e' || p[-1] == 'E')))
{
error ("garbage at end of number");
- while (isalnum (c))
+ 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);
/* This is simplified by the fact that our constant
is always positive. */
- /* The casts in the following statement should not be
- needed, but they get around bugs in some C compilers. */
- yylval.ttype
- = (build_int_2
- ((((long)parts[3]<<24) + ((long)parts[2]<<16)
- + ((long)parts[1]<<8) + (long)parts[0]),
- (((long)parts[7]<<24) + ((long)parts[6]<<16)
- + ((long)parts[5]<<8) + (long)parts[4])));
+
+ high = low = 0;
+
+ for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++)
+ {
+ high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT
+ / HOST_BITS_PER_CHAR)]
+ << (i * HOST_BITS_PER_CHAR));
+ low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
+ }
+
+ yylval.ttype = build_int_2 (low, high);
+ TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
/* If warn_traditional, calculate both the ANSI type and the
traditional type, then see if they disagree.
else if (! spec_long_long)
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;
&& !warn)
pedwarn ("integer constant out of range");
- TREE_TYPE (yylval.ttype) = type;
+ if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
+ warning ("decimal constant is so large that it is unsigned");
+
+ if (spec_imag)
+ {
+ if (TYPE_PRECISION (type)
+ <= TYPE_PRECISION (integer_type_node))
+ yylval.ttype
+ = build_complex (integer_zero_node,
+ convert (integer_type_node, yylval.ttype));
+ else
+ error ("complex integer constant is too wide for `complex int'");
+ }
+ else if (flag_traditional && !int_fits_type_p (yylval.ttype, type))
+ /* The traditional constant 0x80000000 is signed
+ but doesn't fit in the range of int.
+ This will change it to -0x80000000, which does fit. */
+ {
+ 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;
}
char_constant:
{
register int result = 0;
- register num_chars = 0;
+ register int num_chars = 0;
unsigned width = TYPE_PRECISION (char_type_node);
int max_chars;
if (c == '\\')
{
- c = readescape ();
- if (c < 0)
+ int ignore = 0;
+ c = readescape (&ignore);
+ if (ignore)
goto tryagain;
if (width < HOST_BITS_PER_INT
&& (unsigned) c >= (1 << width))
pedwarn ("escape sequence out of range for character");
+#ifdef MAP_CHARACTER
+ if (isprint (c))
+ c = MAP_CHARACTER (c);
+#endif
}
else if (c == '\n')
{
pedwarn ("ANSI C forbids newline in character constant");
lineno++;
}
+#ifdef MAP_CHARACTER
+ else
+ c = MAP_CHARACTER (c);
+#endif
num_chars++;
if (num_chars > maxtoken - 4)
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) ~0
- >> (HOST_BITS_PER_INT - num_bits)),
+ = 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) ~0
- >> (HOST_BITS_PER_INT - num_bits)),
+ = 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
{
|| (num_chars == 1 && token_buffer[1] != '\0'))
{
wchar_t wc;
- (void) mbtowc (NULL, NULL, 0);
+ (void) mbtowc (NULL_PTR, NULL_PTR, 0);
if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
result = wc;
else
}
#endif
yylval.ttype = build_int_2 (result, 0);
+ TREE_TYPE (yylval.ttype) = wchar_type_node;
}
- TREE_TYPE (yylval.ttype) = integer_type_node;
value = CONSTANT;
break;
}
while (c != '"' && c >= 0)
{
- /* ignore_escape_flag is set for reading the filename in #line. */
- if (!ignore_escape_flag && c == '\\')
+ if (c == '\\')
{
- c = readescape ();
- if (c < 0)
+ int ignore = 0;
+ c = readescape (&ignore);
+ if (ignore)
goto skipnewline;
if (!wide_flag
&& TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
}
*p = 0;
+ if (c < 0)
+ error ("Unterminated string constant");
+
/* We have read the entire constant.
Construct a STRING_CST for the result. */
#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;
#endif
yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
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,
+ 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);
TREE_TYPE (yylval.ttype) = char_array_type_node;
+ value = STRING;
}
*p++ = '"';
*p = 0;
- value = STRING; break;
+ break;
}
case '+':
case '-':
case '&':
case '|':
+ case ':':
case '<':
case '>':
case '*':
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;