/* 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>
static int nextchar = -1;
int check_newline ();
-
-/* Nonzero tells yylex to ignore \ in string constants. */
-static int ignore_escape_flag = 0;
\f
-/* C code produced by gperf version 2.5 (GNU C++ version) */
-/* Command-line: gperf -p -j1 -i 1 -g -o -t -G -N is_reserved_word -k1,3,$ c-parse.gperf */
-struct resword { char *name; short token; enum rid rid; };
-
-#define TOTAL_KEYWORDS 79
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 20
-#define MIN_HASH_VALUE 10
-#define MAX_HASH_VALUE 144
-/* maximum key range = 135, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#endif
-static unsigned int
-hash (str, len)
- register char *str;
- register int unsigned len;
-{
- static unsigned char asso_values[] =
- {
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 25, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
- 145, 145, 145, 145, 145, 1, 145, 46, 8, 15,
- 61, 6, 36, 48, 3, 5, 145, 18, 63, 25,
- 29, 76, 1, 145, 13, 2, 1, 51, 37, 9,
- 9, 1, 3, 145, 145, 145, 145, 145,
- };
- register int hval = len;
-
- switch (hval)
- {
- default:
- case 3:
- hval += asso_values[str[2]];
- case 2:
- case 1:
- hval += asso_values[str[0]];
- }
- return hval + asso_values[str[len - 1]];
-}
-
-static struct resword wordlist[] =
-{
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"",},
- {"int", TYPESPEC, RID_INT},
- {"",}, {"",},
- {"__typeof__", TYPEOF, NORID},
- {"__signed__", TYPESPEC, RID_SIGNED},
- {"__imag__", IMAGPART, NORID},
- {"switch", SWITCH, NORID},
- {"__inline__", SCSPEC, RID_INLINE},
- {"else", ELSE, NORID},
- {"__iterator__", SCSPEC, RID_ITERATOR},
- {"__inline", SCSPEC, RID_INLINE},
- {"__extension__", EXTENSION, NORID},
- {"struct", STRUCT, NORID},
- {"__real__", REALPART, NORID},
- {"__const", TYPE_QUAL, RID_CONST},
- {"while", WHILE, NORID},
- {"__const__", TYPE_QUAL, RID_CONST},
- {"case", CASE, NORID},
- {"__complex__", TYPESPEC, RID_COMPLEX},
- {"__iterator", SCSPEC, RID_ITERATOR},
- {"bycopy", TYPE_QUAL, RID_BYCOPY},
- {"",}, {"",}, {"",},
- {"__complex", TYPESPEC, RID_COMPLEX},
- {"",},
- {"in", TYPE_QUAL, RID_IN},
- {"break", BREAK, NORID},
- {"@defs", DEFS, NORID},
- {"",}, {"",}, {"",},
- {"extern", SCSPEC, RID_EXTERN},
- {"if", IF, NORID},
- {"typeof", TYPEOF, NORID},
- {"typedef", SCSPEC, RID_TYPEDEF},
- {"__typeof", TYPEOF, NORID},
- {"sizeof", SIZEOF, NORID},
- {"",},
- {"return", RETURN, NORID},
- {"const", TYPE_QUAL, RID_CONST},
- {"__volatile__", TYPE_QUAL, RID_VOLATILE},
- {"@private", PRIVATE, NORID},
- {"@selector", SELECTOR, NORID},
- {"__volatile", TYPE_QUAL, RID_VOLATILE},
- {"__asm__", ASM_KEYWORD, NORID},
- {"",}, {"",},
- {"continue", CONTINUE, NORID},
- {"__alignof__", ALIGNOF, NORID},
- {"__imag", IMAGPART, NORID},
- {"__attribute__", ATTRIBUTE, NORID},
- {"",}, {"",},
- {"__attribute", ATTRIBUTE, NORID},
- {"for", FOR, NORID},
- {"",},
- {"@encode", ENCODE, NORID},
- {"id", OBJECTNAME, RID_ID},
- {"static", SCSPEC, RID_STATIC},
- {"@interface", INTERFACE, NORID},
- {"",},
- {"__signed", TYPESPEC, RID_SIGNED},
- {"",},
- {"__label__", LABEL, NORID},
- {"",}, {"",},
- {"__asm", ASM_KEYWORD, NORID},
- {"char", TYPESPEC, RID_CHAR},
- {"",},
- {"inline", SCSPEC, RID_INLINE},
- {"out", TYPE_QUAL, RID_OUT},
- {"register", SCSPEC, RID_REGISTER},
- {"__real", REALPART, NORID},
- {"short", TYPESPEC, RID_SHORT},
- {"",},
- {"enum", ENUM, NORID},
- {"inout", TYPE_QUAL, RID_INOUT},
- {"",},
- {"oneway", TYPE_QUAL, RID_ONEWAY},
- {"union", UNION, NORID},
- {"",},
- {"__alignof", ALIGNOF, NORID},
- {"",},
- {"@implementation", IMPLEMENTATION, NORID},
- {"",},
- {"@class", CLASS, NORID},
- {"",},
- {"@public", PUBLIC, NORID},
- {"asm", ASM_KEYWORD, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",},
- {"default", DEFAULT, NORID},
- {"",},
- {"void", TYPESPEC, RID_VOID},
- {"",},
- {"@protected", PROTECTED, NORID},
- {"@protocol", PROTOCOL, NORID},
- {"",}, {"",}, {"",},
- {"volatile", TYPE_QUAL, RID_VOLATILE},
- {"",}, {"",},
- {"signed", TYPESPEC, RID_SIGNED},
- {"float", TYPESPEC, RID_FLOAT},
- {"@end", END, NORID},
- {"",}, {"",},
- {"unsigned", TYPESPEC, RID_UNSIGNED},
- {"@compatibility_alias", ALIAS, NORID},
- {"double", TYPESPEC, RID_DOUBLE},
- {"",}, {"",},
- {"auto", SCSPEC, RID_AUTO},
- {"",},
- {"goto", GOTO, NORID},
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
- {"do", DO, NORID},
- {"",}, {"",}, {"",}, {"",},
- {"long", TYPESPEC, RID_LONG},
-};
-
-#ifdef __GNUC__
-__inline
-#endif
-struct resword *
-is_reserved_word (str, len)
- register char *str;
- register unsigned int len;
-{
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = hash (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register char *s = wordlist[key].name;
-
- if (*s == *str && !strcmp (str + 1, s + 1))
- return &wordlist[key];
- }
- }
- return 0;
-}
+/* Do not insert generated code into the source, instead, include it.
+ This allows us to build gcc automatically even for targets that
+ need to add or modify the reserved keyword lists. */
+#include "c-gperf.h"
\f
/* Return something to represent absolute declarators containing a *.
TARGET is the absolute declarator that the * contains.
{
#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)
{
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,
register int c = getc (finput);
register int code;
register unsigned count;
- unsigned firstdig;
+ unsigned firstdig = 0;
int nonnull;
switch (c)
case '(':
case '{':
case '[':
+ /* `\%' is used to prevent SCCS from getting confused. */
+ case '%':
if (pedantic)
pedwarn ("non-ANSI escape sequence `\\%c'", c);
return 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
{
+ int fflag = 0, lflag = 0;
+ /* Copy token_buffer now, while it has just the number
+ and not the suffixes; once we add `f' or `i',
+ REAL_VALUE_ATOF may not work any more. */
+ char *copy = (char *) alloca (p - token_buffer + 1);
+ bcopy (token_buffer, copy, p - token_buffer + 1);
+
set_float_handler (handler);
-/* The second argument, machine_mode, of REAL_VALUE_ATOF tells the
- desired precision of the binary result of decimal-to-binary conversion. */
+ while (1)
+ {
+ int lose = 0;
- /* Read the suffixes to choose a data type. */
- switch (c)
- {
- case 'f': case 'F':
- type = float_type_node;
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
- if (REAL_VALUE_ISINF (value) && pedantic)
- pedwarn ("floating point number exceeds range of `float'");
- garbage_chars = -1;
- break;
-
- case 'l': case 'L':
- type = long_double_type_node;
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
- if (REAL_VALUE_ISINF (value) && pedantic)
- pedwarn (
- "floating point number exceeds range of `long double'");
- garbage_chars = -1;
- break;
-
- case 'i': case 'I':
- if (imag)
- error ("more than one `i' or `j' in numeric constant");
- imag = 1;
- garbage_chars = -1;
- break;
-
- default:
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
- if (REAL_VALUE_ISINF (value) && pedantic)
- pedwarn ("floating point number exceeds range of `double'");
- }
- set_float_handler (NULL_PTR);
+ /* Read the suffixes to choose a data type. */
+ switch (c)
+ {
+ case 'f': case 'F':
+ if (fflag)
+ error ("more than one `f' in numeric constant");
+ fflag = 1;
+ break;
+
+ case 'l': case 'L':
+ if (lflag)
+ error ("more than one `l' in numeric constant");
+ lflag = 1;
+ break;
+
+ case 'i': case 'I':
+ if (imag)
+ error ("more than one `i' or `j' in numeric constant");
+ else if (pedantic)
+ pedwarn ("ANSI C forbids imaginary numeric constants");
+ imag = 1;
+ break;
+
+ default:
+ lose = 1;
+ }
+
+ if (lose)
+ break;
+
+ if (p >= token_buffer + maxtoken - 3)
+ p = extend_token_buffer (p);
+ *p++ = c;
+ *p = 0;
+ c = getc (finput);
+ }
+
+ /* The second argument, machine_mode, of REAL_VALUE_ATOF
+ tells the desired precision of the binary result
+ of decimal-to-binary conversion. */
+
+ if (fflag)
+ {
+ if (lflag)
+ error ("both `f' and `l' in floating constant");
+
+ type = float_type_node;
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ /* A diagnostic is required here by some ANSI C testsuites.
+ This is not pedwarn, become some people don't want
+ an error for this. */
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `float'");
+ }
+ else if (lflag)
+ {
+ type = long_double_type_node;
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `long double'");
+ }
+ else
+ {
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `double'");
+ }
+
+ set_float_handler (NULL_PTR);
}
#ifdef ERANGE
if (errno == ERANGE && !flag_traditional && pedantic)
if (REAL_VALUES_LESS (dconst1, value)
|| REAL_VALUES_LESS (value, dconstm1))
{
- pedwarn ("floating point number exceeds range of `double'");
+ warning ("floating point number exceeds range of `double'");
exceeds_double = 1;
}
}
#endif
- /* Note: garbage_chars is -1 if first char is *not* garbage. */
+ garbage_chars = 0;
while (isalnum (c) || c == '.' || c == '_'
|| (!flag_traditional && (c == '+' || c == '-')
&& (p[-1] == 'e' || p[-1] == 'E')))
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),
{
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
{
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;
if (! wide_flag)
{
int num_bits = num_chars * width;
- if (TREE_UNSIGNED (char_type_node)
- || ((result >> (num_bits - 1)) & 1) == 0)
+ if (num_bits == 0)
+ /* We already got an error; avoid invalid shift. */
+ yylval.ttype = build_int_2 (0, 0);
+ else if (TREE_UNSIGNED (char_type_node)
+ || ((result >> (num_bits - 1)) & 1) == 0)
yylval.ttype
= build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
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);
}
*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;
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;