#include "keyword.h"
#include "flags.h"
#include "chartables.h"
#ifndef JC1_LITE
#include "timevar.h"
#endif
static char *java_sprint_unicode (int);
static void java_unicode_2_utf8 (unicode_t);
static void java_lex_error (const char *, int);
#ifndef JC1_LITE
static int do_java_lex (YYSTYPE *);
static int java_lex (YYSTYPE *);
static int java_is_eol (FILE *, int);
static tree build_wfl_node (tree);
#endif
static int java_parse_escape_sequence (void);
static int java_start_char_p (unicode_t);
static int java_part_char_p (unicode_t);
static int java_space_char_p (unicode_t);
static void java_parse_doc_section (int);
static void java_parse_end_comment (int);
static int java_read_char (java_lexer *);
static int java_get_unicode (void);
static int java_peek_unicode (void);
static void java_next_unicode (void);
static int java_read_unicode (java_lexer *, int *);
#ifndef JC1_LITE
static int utf8_cmp (const unsigned char *, int, const char *);
#endif
java_lexer *java_new_lexer (FILE *, const char *);
#ifndef JC1_LITE
static void error_if_numeric_overflow (tree);
#endif
#ifdef HAVE_ICONV
static int byteswap_init = 0;
static int need_byteswap = 0;
#endif
void
java_init_lex (FILE *finput, const char *encoding)
{
#ifndef JC1_LITE
int java_lang_imported = 0;
if (!java_lang_id)
java_lang_id = get_identifier ("java.lang");
if (!inst_id)
inst_id = get_identifier ("inst$");
if (!wpv_id)
wpv_id = get_identifier ("write_parm_value$");
if (!java_lang_imported)
{
tree node = build_tree_list (build_unknown_wfl (java_lang_id),
NULL_TREE);
read_import_dir (TREE_PURPOSE (node));
TREE_CHAIN (node) = ctxp->import_demand_list;
ctxp->import_demand_list = node;
java_lang_imported = 1;
}
if (!wfl_operator)
{
#ifndef JC1_LITE
#ifdef USE_MAPPED_LOCATION
wfl_operator = build_expr_wfl (NULL_TREE, input_location);
#else
wfl_operator = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0);
#endif
#endif
}
if (!label_id)
label_id = get_identifier ("$L");
if (!wfl_append)
wfl_append = build_unknown_wfl (get_identifier ("append"));
if (!wfl_string_buffer)
wfl_string_buffer =
build_unknown_wfl (get_identifier (flag_emit_class_files
? "java.lang.StringBuffer"
: "gnu.gcj.runtime.StringBuffer"));
if (!wfl_to_string)
wfl_to_string = build_unknown_wfl (get_identifier ("toString"));
CPC_INITIALIZER_LIST (ctxp) = CPC_STATIC_INITIALIZER_LIST (ctxp) =
CPC_INSTANCE_INITIALIZER_LIST (ctxp) = NULL_TREE;
memset (ctxp->modifier_ctx, 0, sizeof (ctxp->modifier_ctx));
ctxp->current_parsed_class = NULL;
ctxp->package = NULL_TREE;
#endif
#ifndef JC1_LITE
ctxp->save_location = input_location;
#endif
ctxp->java_error_flag = 0;
ctxp->lexer = java_new_lexer (finput, encoding);
}
static char *
java_sprint_unicode (int c)
{
static char buffer [10];
if (c < ' ' || c >= 127)
sprintf (buffer, "\\u%04x", c);
else
{
buffer [0] = c;
buffer [1] = '\0';
}
return buffer;
}
java_lexer *
java_new_lexer (FILE *finput, const char *encoding)
{
java_lexer *lex = xmalloc (sizeof (java_lexer));
int enc_error = 0;
lex->finput = finput;
lex->bs_count = 0;
lex->unget_value = 0;
lex->next_unicode = 0;
lex->avail_unicode = 0;
lex->next_columns = 1;
lex->encoding = encoding;
lex->position.line = 1;
lex->position.col = 1;
#ifndef JC1_LITE
#ifdef USE_MAPPED_LOCATION
input_location
= linemap_line_start (&line_table, 1, 120);
#else
input_line = 1;
#endif
#endif
#ifdef HAVE_ICONV
lex->handle = iconv_open ("UCS-2", encoding);
if (lex->handle != (iconv_t) -1)
{
lex->first = -1;
lex->last = -1;
lex->out_first = -1;
lex->out_last = -1;
lex->read_anything = 0;
lex->use_fallback = 0;
if (! byteswap_init)
{
iconv_t handle;
byteswap_init = 1;
handle = iconv_open ("UCS-2", "UTF-8");
if (handle != (iconv_t) -1)
{
unicode_t result;
unsigned char in[3];
char *inp, *outp;
size_t inc, outc, r;
in[0] = 0xef;
in[1] = 0xbb;
in[2] = 0xbf;
inp = (char *) in;
inc = 3;
outp = (char *) &result;
outc = 2;
r = iconv (handle, (ICONV_CONST char **) &inp, &inc,
&outp, &outc);
iconv_close (handle);
if (r != (size_t) -1 && inc == 0 && outc == 0)
need_byteswap = (result != 0xfeff);
}
}
lex->byte_swap = need_byteswap;
}
else
#endif
{
if (strcmp (encoding, DEFAULT_ENCODING) && strcmp (encoding, "646"))
enc_error = 1;
#ifdef HAVE_ICONV
else
{
lex->use_fallback = 1;
lex->encoding = "UTF-8";
}
#endif
}
if (enc_error)
fatal_error ("unknown encoding: %qs\nThis might mean that your locale's encoding is not supported\nby your system's iconv(3) implementation. If you aren't trying\nto use a particular encoding for your input file, try the\n%<--encoding=UTF-8%> option", encoding);
return lex;
}
void
java_destroy_lexer (java_lexer *lex)
{
#ifdef HAVE_ICONV
if (! lex->use_fallback)
iconv_close (lex->handle);
#endif
free (lex);
}
static int
java_read_char (java_lexer *lex)
{
#ifdef HAVE_ICONV
if (! lex->use_fallback)
{
size_t ir, inbytesleft, in_save, out_count, out_save;
char *inp, *outp;
unicode_t result;
if (lex->out_first == -1 || lex->out_first >= lex->out_last)
{
lex->out_first = 0;
lex->out_last = 0;
while (1)
{
if (lex->first == 0 || lex->first >= lex->last)
{
int r;
if (lex->first >= lex->last)
{
lex->first = 0;
lex->last = 0;
}
if (feof (lex->finput))
return UEOF;
r = fread (&lex->buffer[lex->last], 1,
sizeof (lex->buffer) - lex->last,
lex->finput);
lex->last += r;
}
inbytesleft = lex->last - lex->first;
out_count = sizeof (lex->out_buffer) - lex->out_last;
if (inbytesleft == 0)
{
return UEOF;
}
in_save = inbytesleft;
out_save = out_count;
inp = &lex->buffer[lex->first];
outp = (char *) &lex->out_buffer[lex->out_last];
ir = iconv (lex->handle, (ICONV_CONST char **) &inp,
&inbytesleft, &outp, &out_count);
if (! lex->read_anything && out_save - out_count >= 2)
{
unicode_t uc = * (unicode_t *) &lex->out_buffer[0];
if (uc == 0xfeff)
{
lex->byte_swap = 0;
lex->out_first += 2;
}
else if (uc == 0xfffe)
{
lex->byte_swap = 1;
lex->out_first += 2;
}
lex->read_anything = 1;
}
if (lex->byte_swap)
{
unsigned int i;
for (i = 0; i < out_save - out_count; i += 2)
{
char t = lex->out_buffer[lex->out_last + i];
lex->out_buffer[lex->out_last + i]
= lex->out_buffer[lex->out_last + i + 1];
lex->out_buffer[lex->out_last + i + 1] = t;
}
}
lex->first += in_save - inbytesleft;
lex->out_last += out_save - out_count;
if (out_count != out_save)
break;
if (ir == (size_t) -1)
{
if (errno == EINVAL)
{
memmove (&lex->buffer[0], &lex->buffer[lex->first],
lex->last - lex->first);
lex->last -= lex->first;
lex->first = 0;
}
else
{
char buffer[128];
sprintf (buffer,
"Unrecognized character for encoding '%s'",
lex->encoding);
java_lex_error (buffer, 0);
return UEOF;
}
}
}
}
if (lex->out_first == -1 || lex->out_first >= lex->out_last)
{
return UEOF;
}
result = * ((unicode_t *) &lex->out_buffer[lex->out_first]);
lex->out_first += 2;
return result;
}
else
#endif
{
int c, c1, c2;
c = getc (lex->finput);
if (c == EOF)
return UEOF;
if (c < 128)
return (unicode_t) c;
else
{
if ((c & 0xe0) == 0xc0)
{
c1 = getc (lex->finput);
if ((c1 & 0xc0) == 0x80)
{
unicode_t r = (unicode_t)(((c & 0x1f) << 6) + (c1 & 0x3f));
if (r == 0 || (r >= 0x80 && r <= 0x7ff))
return r;
}
}
else if ((c & 0xf0) == 0xe0)
{
c1 = getc (lex->finput);
if ((c1 & 0xc0) == 0x80)
{
c2 = getc (lex->finput);
if ((c2 & 0xc0) == 0x80)
{
unicode_t r = (unicode_t)(((c & 0xf) << 12) +
(( c1 & 0x3f) << 6)
+ (c2 & 0x3f));
if (IN_RANGE (r, 0x800, 0xffff)
&& ! IN_RANGE (r, 0xd800, 0xdfff)
&& r != 0xfffe && r != 0xffff)
return r;
}
}
}
java_lex_error ("malformed UTF-8 character", 0);
}
}
return UEOF;
}
static int
java_read_unicode (java_lexer *lex, int *unicode_escape_p)
{
int c;
if (lex->unget_value)
{
c = lex->unget_value;
lex->unget_value = 0;
}
else
c = java_read_char (lex);
*unicode_escape_p = 0;
if (c != '\\')
{
lex->bs_count = 0;
return c;
}
++lex->bs_count;
if ((lex->bs_count) % 2 == 1)
{
c = java_read_char (lex);
if (c == 'u')
{
unicode_t unicode = 0;
int shift = 12;
while ((c = java_read_char (lex)) == 'u')
;
shift = 12;
do
{
if (c == UEOF)
{
java_lex_error ("prematurely terminated \\u sequence", 0);
return UEOF;
}
if (hex_p (c))
unicode |= (unicode_t)(hex_value (c) << shift);
else
{
java_lex_error ("non-hex digit in \\u sequence", 0);
break;
}
c = java_read_char (lex);
shift -= 4;
}
while (shift >= 0);
if (c != UEOF)
lex->unget_value = c;
lex->bs_count = 0;
*unicode_escape_p = 1;
return unicode;
}
lex->unget_value = c;
}
return (unicode_t) '\\';
}
static int
java_get_unicode (void)
{
int next = java_peek_unicode ();
java_next_unicode ();
return next;
}
static int
java_peek_unicode (void)
{
int unicode_escape_p;
java_lexer *lex = ctxp->lexer;
int next;
if (lex->avail_unicode)
return lex->next_unicode;
next = java_read_unicode (lex, &unicode_escape_p);
if (next == '\r')
{
int dummy;
next = java_read_unicode (lex, &dummy);
if (next != '\n' && next != UEOF)
lex->unget_value = next;
next = '\n';
}
lex->next_unicode = next;
lex->avail_unicode = 1;
if (next == UEOF)
{
lex->next_columns = 0;
return next;
}
if (next == '\n')
{
lex->next_columns = 1 - lex->position.col;
}
else if (next == '\t')
{
int cur_col = lex->position.col;
lex->next_columns = ((cur_col + 7) & ~7) + 1 - cur_col;
}
else
{
lex->next_columns = 1;
}
if (unicode_escape_p)
lex->next_columns = 6;
return next;
}
static void java_next_unicode (void)
{
struct java_lexer *lex = ctxp->lexer;
lex->position.col += lex->next_columns;
if (lex->next_unicode == '\n')
{
lex->position.line++;
#ifndef JC1_LITE
#ifdef USE_MAPPED_LOCATION
input_location
= linemap_line_start (&line_table, lex->position.line, 120);
#else
input_line = lex->position.line;
#endif
#endif
}
lex->avail_unicode = 0;
}
#if 0
static void java_unget_unicode ()
{
struct java_lexer *lex = ctxp->lexer;
if (lex->avail_unicode)
fatal_error ("internal error - bad unget");
lex->avail_unicode = 1;
lex->position.col -= lex->next_columns;
}
#endif
static void
java_parse_end_comment (int c)
{
for ( ;; c = java_get_unicode ())
{
switch (c)
{
case UEOF:
java_lex_error ("Comment not terminated at end of input", 0);
return;
case '*':
switch (c = java_peek_unicode ())
{
case UEOF:
java_lex_error ("Comment not terminated at end of input", 0);
return;
case '/':
java_next_unicode ();
return;
case '*':
;
}
}
}
}
static void
java_parse_doc_section (int c)
{
int last_was_star;
ctxp->deprecated = 0;
while (1)
{
if (! ctxp->deprecated)
{
while (JAVA_WHITE_SPACE_P (c) || c == '*')
{
last_was_star = (c == '*');
c = java_get_unicode ();
if (last_was_star && c == '/')
{
return;
}
}
if (c == UEOF)
goto eof;
if (c == '@')
{
const char *deprecated = "@deprecated";
int i;
for (i = 0; deprecated[i]; ++i)
{
if (c != deprecated[i])
break;
c = java_get_unicode ();
}
if (c == UEOF)
goto eof;
if (c == ' ' || c == '\n' || c == '*' || java_space_char_p (c))
{
if (! deprecated[i])
ctxp->deprecated = 1;
}
}
}
while (c != '\n' && c != UEOF)
{
last_was_star = (c == '*');
c = java_get_unicode ();
if (last_was_star && c == '/')
return;
}
if (c == UEOF)
goto eof;
c = java_get_unicode ();
if (c == UEOF)
goto eof;
}
eof:
java_lex_error ("Comment not terminated at end of input", 0);
}
static int
java_start_char_p (unicode_t c)
{
unsigned int hi = c / 256;
const char *const page = type_table[hi];
unsigned long val = (unsigned long) page;
int flags;
if ((val & ~ LETTER_MASK) != 0)
flags = page[c & 255];
else
flags = val;
return flags & LETTER_START;
}
static int
java_part_char_p (unicode_t c)
{
unsigned int hi = c / 256;
const char *const page = type_table[hi];
unsigned long val = (unsigned long) page;
int flags;
if ((val & ~ LETTER_MASK) != 0)
flags = page[c & 255];
else
flags = val;
return flags & LETTER_PART;
}
static int
java_space_char_p (unicode_t c)
{
unsigned int hi = c / 256;
const char *const page = type_table[hi];
unsigned long val = (unsigned long) page;
int flags;
if ((val & ~ LETTER_MASK) != 0)
flags = page[c & 255];
else
flags = val;
return flags & LETTER_SPACE;
}
static int
java_parse_escape_sequence (void)
{
int c;
switch (c = java_get_unicode ())
{
case 'b':
return (unicode_t)0x8;
case 't':
return (unicode_t)0x9;
case 'n':
return (unicode_t)0xa;
case 'f':
return (unicode_t)0xc;
case 'r':
return (unicode_t)0xd;
case '"':
return (unicode_t)0x22;
case '\'':
return (unicode_t)0x27;
case '\\':
return (unicode_t)0x5c;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7':
{
int more = 3;
unicode_t char_lit = 0;
if (c > '3')
{
--more;
}
char_lit = 0;
for (;;)
{
char_lit = 8 * char_lit + c - '0';
if (--more == 0)
break;
c = java_peek_unicode ();
if (! RANGE (c, '0', '7'))
break;
java_next_unicode ();
}
return char_lit;
}
default:
java_lex_error ("Invalid character in escape sequence", -1);
return JAVA_CHAR_ERROR;
}
}
#ifndef JC1_LITE
#define IS_ZERO(X) REAL_VALUES_EQUAL (X, dconst0)
static void java_perform_atof (YYSTYPE *, char *, int, int);
static void
java_perform_atof (YYSTYPE *java_lval, char *literal_token, int fflag,
int number_beginning)
{
REAL_VALUE_TYPE value;
tree type = (fflag ? FLOAT_TYPE_NODE : DOUBLE_TYPE_NODE);
SET_REAL_VALUE_ATOF (value,
REAL_VALUE_ATOF (literal_token, TYPE_MODE (type)));
if (REAL_VALUE_ISINF (value) || REAL_VALUE_ISNAN (value))
{
JAVA_FLOAT_RANGE_ERROR (fflag ? "float" : "double");
value = DCONST0;
}
else if (IS_ZERO (value))
{
int really_zero = 1;
char *p = literal_token;
if (*p == '-')
++p;
while (*p && *p != 'e' && *p != 'E')
{
if (*p != '0' && *p != '.')
{
really_zero = 0;
break;
}
++p;
}
if (! really_zero)
{
int save_col = ctxp->lexer->position.col;
ctxp->lexer->position.col = number_beginning;
java_lex_error ("Floating point literal underflow", 0);
ctxp->lexer->position.col = save_col;
}
}
SET_LVAL_NODE (build_real (type, value));
}
#endif
static int yylex (YYSTYPE *);
static int
#ifdef JC1_LITE
yylex (YYSTYPE *java_lval)
#else
do_java_lex (YYSTYPE *java_lval)
#endif
{
int c;
char *string;
step1:
for (;;)
{
c = java_peek_unicode ();
if (c != '\n' && ! JAVA_WHITE_SPACE_P (c))
break;
java_next_unicode ();
}
if (c == UEOF)
return 0;
#ifndef JC1_LITE
#ifdef USE_MAPPED_LOCATION
LINEMAP_POSITION_FOR_COLUMN (input_location, &line_table,
ctxp->lexer->position.col);
#else
ctxp->lexer->token_start = ctxp->lexer->position;
#endif
#endif
if (JAVA_ASCII_DIGIT (c) || (c == '.'))
{
#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
int parts[TOTAL_PARTS];
HOST_WIDE_INT high, low;
char literal_token [256];
int literal_index = 0, radix = 10, long_suffix = 0, overflow = 0, bytes;
int found_hex_digits = 0, found_non_octal_digits = -1;
int i;
#ifndef JC1_LITE
int number_beginning = ctxp->lexer->position.col;
tree value;
#endif
for (i = 0; i < TOTAL_PARTS; i++)
parts [i] = 0;
if (c == '0')
{
java_next_unicode ();
c = java_peek_unicode ();
if (c == 'x' || c == 'X')
{
radix = 16;
java_next_unicode ();
c = java_peek_unicode ();
}
else if (JAVA_ASCII_DIGIT (c))
{
literal_token [literal_index++] = '0';
radix = 8;
}
else if (c == '.' || c == 'e' || c =='E')
{
literal_token [literal_index++] = '0';
}
else
{
switch (c)
{
case 'L': case 'l':
java_next_unicode ();
SET_LVAL_NODE (long_zero_node);
return (INT_LIT_TK);
case 'f': case 'F':
java_next_unicode ();
SET_LVAL_NODE (float_zero_node);
return (FP_LIT_TK);
case 'd': case 'D':
java_next_unicode ();
SET_LVAL_NODE (double_zero_node);
return (FP_LIT_TK);
default:
SET_LVAL_NODE (integer_zero_node);
return (INT_LIT_TK);
}
}
}
while (radix == 16 ? JAVA_ASCII_HEXDIGIT (c) : JAVA_ASCII_DIGIT (c))
{
int numeric = hex_value (c);
int count;
if (radix == 16)
found_hex_digits = 1;
else if (radix == 8 && numeric >= 8 && found_non_octal_digits < 0)
found_non_octal_digits = literal_index;
literal_token [literal_index++] = c;
for (count = 0; count < TOTAL_PARTS; count++)
{
parts[count] *= radix;
if (count)
{
parts[count] += (parts[count-1] >> HOST_BITS_PER_CHAR);
parts[count-1] &= (1 << HOST_BITS_PER_CHAR) - 1;
}
else
parts[0] += numeric;
}
if (parts [TOTAL_PARTS-1] != 0)
overflow = 1;
java_next_unicode ();
c = java_peek_unicode ();
}
if (JAVA_ASCII_FPCHAR (c) && !JAVA_ASCII_DIGIT (c))
{
int stage = 0;
int seen_digit = (literal_index ? 1 : 0);
int seen_exponent = 0;
int fflag = 0;
if (radix == 16)
java_lex_error ("Can't express non-decimal FP literal", 0);
radix = 10;
for (;;)
{
if (c == '.')
{
if (stage < 1)
{
stage = 1;
literal_token [literal_index++ ] = c;
java_next_unicode ();
c = java_peek_unicode ();
if (literal_index == 1 && !JAVA_ASCII_DIGIT (c))
BUILD_OPERATOR (DOT_TK);
}
else
java_lex_error ("Invalid character in FP literal", 0);
}
if (c == 'e' || c == 'E')
{
if (stage < 2)
{
if (!seen_digit)
java_lex_error
("Invalid FP literal, mantissa must have digit", 0);
seen_digit = 0;
seen_exponent = 1;
stage = 2;
literal_token [literal_index++] = c;
java_next_unicode ();
c = java_peek_unicode ();
}
else
java_lex_error ("Invalid character in FP literal", 0);
}
if ( c == 'f' || c == 'F' || c == 'd' || c == 'D')
{
fflag = ((c == 'd') || (c == 'D')) ? 0 : 1;
stage = 4;
}
if ((c=='-' || c =='+') && stage == 2)
{
stage = 3;
literal_token [literal_index++] = c;
java_next_unicode ();
c = java_peek_unicode ();
}
if ((stage == 0 && JAVA_ASCII_FPCHAR (c)) ||
(stage == 1 && JAVA_ASCII_FPCHAR (c) && !(c == '.')) ||
(stage == 2 && (JAVA_ASCII_DIGIT (c) || JAVA_FP_PM (c))) ||
(stage == 3 && JAVA_ASCII_DIGIT (c)))
{
if (JAVA_ASCII_DIGIT (c))
seen_digit = 1;
if (stage == 2)
stage = 3;
literal_token [literal_index++ ] = c;
java_next_unicode ();
c = java_peek_unicode ();
}
else
{
if (stage == 4)
java_next_unicode ();
if (seen_exponent && !seen_digit)
java_lex_error
("Invalid FP literal, exponent must have digit", 0);
literal_token [literal_index] = '\0';
#ifndef JC1_LITE
java_perform_atof (java_lval, literal_token,
fflag, number_beginning);
#endif
return FP_LIT_TK;
}
}
}
if (radix == 16 && ! found_hex_digits)
java_lex_error
("0x must be followed by at least one hexadecimal digit", 0);
else if (radix == 8 && found_non_octal_digits >= 0)
{
int back = literal_index - found_non_octal_digits;
ctxp->lexer->position.col -= back;
java_lex_error ("Octal literal contains digit out of range", 0);
ctxp->lexer->position.col += back;
}
else if (c == 'L' || c == 'l')
{
java_next_unicode ();
long_suffix = 1;
}
if (!overflow)
{
bytes = GET_TYPE_PRECISION (long_type_node);
for (i = bytes; i < TOTAL_PARTS; i++)
if (parts [i])
{
overflow = 1;
break;
}
}
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);
}
#ifndef JC1_LITE
value = build_int_cst_wide (long_suffix
? unsigned_long_type_node
: unsigned_int_type_node, low, high);
SET_LVAL_NODE (value);
if (overflow || (radix == 10
&& tree_int_cst_lt (long_suffix
? decimal_long_max
: decimal_int_max,
value)))
{
if (long_suffix)
JAVA_RANGE_ERROR ("Numeric overflow for 'long' literal");
else
JAVA_RANGE_ERROR ("Numeric overflow for 'int' literal");
}
value = build_int_cst_wide (long_suffix ? long_type_node : int_type_node,
low, high);
value = force_fit_type (value, 0, false, false);
if (radix != 10)
{
value = copy_node (value);
JAVA_NOT_RADIX10_FLAG (value) = 1;
}
SET_LVAL_NODE (value);
#endif
return INT_LIT_TK;
}
if (JAVA_START_CHAR_P (c))
{
int ascii_index = 0, all_ascii = 1;
while (c != UEOF && JAVA_PART_CHAR_P (c))
{
java_unicode_2_utf8 (c);
if (c >= 128)
all_ascii = 0;
java_next_unicode ();
ascii_index++;
c = java_peek_unicode ();
}
obstack_1grow (&temporary_obstack, '\0');
string = obstack_finish (&temporary_obstack);
if (all_ascii)
{
const struct java_keyword *kw;
if ((kw=java_keyword (string, ascii_index)))
{
switch (kw->token)
{
case PUBLIC_TK: case PROTECTED_TK: case STATIC_TK:
case ABSTRACT_TK: case FINAL_TK: case NATIVE_TK:
case SYNCHRONIZED_TK: case TRANSIENT_TK: case VOLATILE_TK:
case PRIVATE_TK: case STRICT_TK:
SET_MODIFIER_CTX (kw->token);
return MODIFIER_TK;
case FLOAT_TK:
SET_LVAL_NODE (float_type_node);
return FP_TK;
case DOUBLE_TK:
SET_LVAL_NODE (double_type_node);
return FP_TK;
case BOOLEAN_TK:
SET_LVAL_NODE (boolean_type_node);
return BOOLEAN_TK;
case BYTE_TK:
SET_LVAL_NODE (byte_type_node);
return INTEGRAL_TK;
case SHORT_TK:
SET_LVAL_NODE (short_type_node);
return INTEGRAL_TK;
case INT_TK:
SET_LVAL_NODE (int_type_node);
return INTEGRAL_TK;
case LONG_TK:
SET_LVAL_NODE (long_type_node);
return INTEGRAL_TK;
case CHAR_TK:
SET_LVAL_NODE (char_type_node);
return INTEGRAL_TK;
case TRUE_TK:
case FALSE_TK:
SET_LVAL_NODE ((kw->token == TRUE_TK ?
boolean_true_node : boolean_false_node));
return BOOL_LIT_TK;
case NULL_TK:
SET_LVAL_NODE (null_pointer_node);
return NULL_TK;
case ASSERT_TK:
if (flag_assert)
{
BUILD_OPERATOR (kw->token);
return kw->token;
}
else
break;
case CASE_TK:
case DEFAULT_TK:
case SUPER_TK:
case THIS_TK:
case RETURN_TK:
case BREAK_TK:
case CONTINUE_TK:
case TRY_TK:
case CATCH_TK:
case THROW_TK:
case INSTANCEOF_TK:
BUILD_OPERATOR (kw->token);
default:
return kw->token;
}
}
}
java_lval->node = BUILD_ID_WFL (GET_IDENTIFIER (string));
return ID_TK;
}
java_next_unicode ();
if (c == '\'')
{
int char_lit;
if ((c = java_get_unicode ()) == '\\')
char_lit = java_parse_escape_sequence ();
else
{
if (c == '\n' || c == '\'')
java_lex_error ("Invalid character literal", 0);
char_lit = c;
}
c = java_get_unicode ();
if ((c == '\n') || (c == UEOF))
java_lex_error ("Character literal not terminated at end of line", 0);
if (c != '\'')
java_lex_error ("Syntax error in character literal", 0);
if (char_lit == JAVA_CHAR_ERROR)
char_lit = 0;
SET_LVAL_NODE (build_int_cst (char_type_node, char_lit));
return CHAR_LIT_TK;
}
if (c == '"')
{
int no_error = 1;
char *string;
for (;;)
{
c = java_peek_unicode ();
if (c == '\n' || c == UEOF)
{
java_lex_error ("String not terminated at end of line", 0);
break;
}
java_next_unicode ();
if (c == '"')
break;
if (c == '\\')
c = java_parse_escape_sequence ();
if (c == JAVA_CHAR_ERROR)
{
no_error = 0;
c = 0;
}
java_unicode_2_utf8 (c);
}
obstack_1grow (&temporary_obstack, '\0');
string = obstack_finish (&temporary_obstack);
#ifndef JC1_LITE
if (!no_error || (c != '"'))
java_lval->node = error_mark_node;
else
java_lval->node = build_string (strlen (string), string);
#endif
obstack_free (&temporary_obstack, string);
return STRING_LIT_TK;
}
switch (c)
{
case '/':
switch (c = java_peek_unicode ())
{
case '/':
java_next_unicode ();
for (;;)
{
c = java_get_unicode ();
if (c == UEOF)
{
if (pedantic)
java_lex_error ("Comment not terminated at end of input",
0);
return 0;
}
if (c == '\n')
goto step1;
}
break;
case '*':
java_next_unicode ();
if ((c = java_get_unicode ()) == '*')
{
c = java_get_unicode ();
if (c == '/')
{
ctxp->deprecated = 0;
}
else
java_parse_doc_section (c);
}
else
java_parse_end_comment ((c = java_get_unicode ()));
goto step1;
break;
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (DIV_ASSIGN_TK);
default:
BUILD_OPERATOR (DIV_TK);
}
case '(':
BUILD_OPERATOR (OP_TK);
case ')':
return CP_TK;
case '{':
#ifndef JC1_LITE
java_lval->operator.token = OCB_TK;
java_lval->operator.location = BUILD_LOCATION();
#ifdef USE_MAPPED_LOCATION
if (ctxp->ccb_indent == 1)
ctxp->first_ccb_indent1 = input_location;
#else
if (ctxp->ccb_indent == 1)
ctxp->first_ccb_indent1 = input_line;
#endif
#endif
ctxp->ccb_indent++;
return OCB_TK;
case '}':
ctxp->ccb_indent--;
#ifndef JC1_LITE
java_lval->operator.token = CCB_TK;
java_lval->operator.location = BUILD_LOCATION();
#ifdef USE_MAPPED_LOCATION
if (ctxp->ccb_indent == 1)
ctxp->last_ccb_indent1 = input_location;
#else
if (ctxp->ccb_indent == 1)
ctxp->last_ccb_indent1 = input_line;
#endif
#endif
return CCB_TK;
case '[':
BUILD_OPERATOR (OSB_TK);
case ']':
return CSB_TK;
case ';':
return SC_TK;
case ',':
return C_TK;
case '.':
BUILD_OPERATOR (DOT_TK);
case '=':
c = java_peek_unicode ();
if (c == '=')
{
java_next_unicode ();
BUILD_OPERATOR (EQ_TK);
}
else
{
BUILD_OPERATOR (ASSIGN_TK);
}
case '>':
switch ((c = java_peek_unicode ()))
{
case '=':
java_next_unicode ();
BUILD_OPERATOR (GTE_TK);
case '>':
java_next_unicode ();
switch ((c = java_peek_unicode ()))
{
case '>':
java_next_unicode ();
c = java_peek_unicode ();
if (c == '=')
{
java_next_unicode ();
BUILD_OPERATOR2 (ZRS_ASSIGN_TK);
}
else
{
BUILD_OPERATOR (ZRS_TK);
}
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (SRS_ASSIGN_TK);
default:
BUILD_OPERATOR (SRS_TK);
}
default:
BUILD_OPERATOR (GT_TK);
}
case '<':
switch ((c = java_peek_unicode ()))
{
case '=':
java_next_unicode ();
BUILD_OPERATOR (LTE_TK);
case '<':
java_next_unicode ();
if ((c = java_peek_unicode ()) == '=')
{
java_next_unicode ();
BUILD_OPERATOR2 (LS_ASSIGN_TK);
}
else
{
BUILD_OPERATOR (LS_TK);
}
default:
BUILD_OPERATOR (LT_TK);
}
case '&':
switch ((c = java_peek_unicode ()))
{
case '&':
java_next_unicode ();
BUILD_OPERATOR (BOOL_AND_TK);
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (AND_ASSIGN_TK);
default:
BUILD_OPERATOR (AND_TK);
}
case '|':
switch ((c = java_peek_unicode ()))
{
case '|':
java_next_unicode ();
BUILD_OPERATOR (BOOL_OR_TK);
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (OR_ASSIGN_TK);
default:
BUILD_OPERATOR (OR_TK);
}
case '+':
switch ((c = java_peek_unicode ()))
{
case '+':
java_next_unicode ();
BUILD_OPERATOR (INCR_TK);
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (PLUS_ASSIGN_TK);
default:
BUILD_OPERATOR (PLUS_TK);
}
case '-':
switch ((c = java_peek_unicode ()))
{
case '-':
java_next_unicode ();
BUILD_OPERATOR (DECR_TK);
case '=':
java_next_unicode ();
BUILD_OPERATOR2 (MINUS_ASSIGN_TK);
default:
BUILD_OPERATOR (MINUS_TK);
}
case '*':
if ((c = java_peek_unicode ()) == '=')
{
java_next_unicode ();
BUILD_OPERATOR2 (MULT_ASSIGN_TK);
}
else
{
BUILD_OPERATOR (MULT_TK);
}
case '^':
if ((c = java_peek_unicode ()) == '=')
{
java_next_unicode ();
BUILD_OPERATOR2 (XOR_ASSIGN_TK);
}
else
{
BUILD_OPERATOR (XOR_TK);
}
case '%':
if ((c = java_peek_unicode ()) == '=')
{
java_next_unicode ();
BUILD_OPERATOR2 (REM_ASSIGN_TK);
}
else
{
BUILD_OPERATOR (REM_TK);
}
case '!':
if ((c = java_peek_unicode()) == '=')
{
java_next_unicode ();
BUILD_OPERATOR (NEQ_TK);
}
else
{
BUILD_OPERATOR (NEG_TK);
}
case '?':
BUILD_OPERATOR (REL_QM_TK);
case ':':
BUILD_OPERATOR (REL_CL_TK);
case '~':
BUILD_OPERATOR (NOT_TK);
}
if (c == 0x1a)
{
if ((c = java_peek_unicode ()) == UEOF)
return 0;
}
{
char lex_error_buffer [128];
sprintf (lex_error_buffer, "Invalid character '%s' in input",
java_sprint_unicode (c));
java_lex_error (lex_error_buffer, -1);
}
return 0;
}
#ifndef JC1_LITE
static int
java_lex (YYSTYPE *java_lval)
{
int r;
timevar_push (TV_LEX);
r = do_java_lex (java_lval);
timevar_pop (TV_LEX);
return r;
}
static void
error_if_numeric_overflow (tree value)
{
if (TREE_CODE (value) == INTEGER_CST
&& !JAVA_NOT_RADIX10_FLAG (value)
&& tree_int_cst_sgn (value) < 0)
{
if (TREE_TYPE (value) == long_type_node)
java_lex_error ("Numeric overflow for 'long' literal", 0);
else
java_lex_error ("Numeric overflow for 'int' literal", 0);
}
}
#endif
static void
java_unicode_2_utf8 (unicode_t unicode)
{
if (RANGE (unicode, 0x01, 0x7f))
obstack_1grow (&temporary_obstack, (char)unicode);
else if (RANGE (unicode, 0x80, 0x7ff) || unicode == 0)
{
obstack_1grow (&temporary_obstack,
(unsigned char)(0xc0 | ((0x7c0 & unicode) >> 6)));
obstack_1grow (&temporary_obstack,
(unsigned char)(0x80 | (unicode & 0x3f)));
}
else
{
obstack_1grow (&temporary_obstack,
(unsigned char)(0xe0 | (unicode & 0xf000) >> 12));
obstack_1grow (&temporary_obstack,
(unsigned char)(0x80 | (unicode & 0x0fc0) >> 6));
obstack_1grow (&temporary_obstack,
(unsigned char)(0x80 | (unicode & 0x003f)));
}
}
#ifndef JC1_LITE
static tree
build_wfl_node (tree node)
{
#ifdef USE_MAPPED_LOCATION
node = build_expr_wfl (node, input_location);
#else
node = build_expr_wfl (node, ctxp->filename,
ctxp->lexer->token_start.line,
ctxp->lexer->token_start.col);
#endif
TREE_TYPE (node) = NULL_TREE;
return node;
}
#endif
static void
java_lex_error (const char *msg ATTRIBUTE_UNUSED, int forward ATTRIBUTE_UNUSED)
{
#ifndef JC1_LITE
int col = (ctxp->lexer->position.col
+ forward * ctxp->lexer->next_columns);
#if USE_MAPPED_LOCATION
source_location save_location = input_location;
LINEMAP_POSITION_FOR_COLUMN (input_location, &line_table, col);
ctxp->java_error_flag = 0;
java_error (NULL);
java_error (msg);
input_location = save_location;
#else
java_lc save = ctxp->lexer->token_start;
ctxp->lexer->token_start.line = ctxp->lexer->position.line;
ctxp->lexer->token_start.col = col;
ctxp->java_error_flag = 0;
java_error (NULL);
java_error (msg);
ctxp->lexer->token_start = save;
#endif
#endif
}
#ifndef JC1_LITE
static int
java_is_eol (FILE *fp, int c)
{
int next;
switch (c)
{
case '\r':
next = getc (fp);
if (next != '\n' && next != EOF)
ungetc (next, fp);
return 1;
case '\n':
return 1;
default:
return 0;
}
}
#endif
char *
java_get_line_col (const char *filename ATTRIBUTE_UNUSED,
int line ATTRIBUTE_UNUSED, int col ATTRIBUTE_UNUSED)
{
#ifdef JC1_LITE
return 0;
#else
FILE *fp;
int c, ccol, cline = 1;
int current_line_col = 0;
int first_non_space = 0;
char *base;
if (!(fp = fopen (filename, "r")))
fatal_error ("can't open %s: %m", filename);
while (cline != line)
{
c = getc (fp);
if (c == EOF)
{
static const char msg[] = "<<file too short - unexpected EOF>>";
obstack_grow (&temporary_obstack, msg, sizeof(msg)-1);
goto have_line;
}
if (java_is_eol (fp, c))
cline++;
}
for (;;)
{
c = getc (fp);
if (c < 0 || java_is_eol (fp, c))
break;
if (!first_non_space && !JAVA_WHITE_SPACE_P (c))
first_non_space = current_line_col;
obstack_1grow (&temporary_obstack, c);
current_line_col++;
}
have_line:
obstack_1grow (&temporary_obstack, '\n');
if (col == -1)
{
col = current_line_col;
first_non_space = 0;
}
else if (col == -2)
col = first_non_space;
else
first_non_space = 0;
base = obstack_base (&temporary_obstack);
for (col += 2, ccol = 0; ccol < col; ccol++)
{
char c = (first_non_space ?
(base [ccol] == '\t' ? '\t' : ' ') : ' ');
obstack_1grow (&temporary_obstack, c);
}
obstack_grow0 (&temporary_obstack, "^", 1);
fclose (fp);
return obstack_finish (&temporary_obstack);
#endif
}
#ifndef JC1_LITE
static int
utf8_cmp (const unsigned char *str, int length, const char *name)
{
const unsigned char *limit = str + length;
int i;
for (i = 0; name[i]; ++i)
{
int ch = UTF8_GET (str, limit);
if (ch != name[i])
return ch - name[i];
}
return str == limit ? 0 : 1;
}
static const char *const cxx_keywords[] =
{
"_Complex",
"__alignof",
"__alignof__",
"__asm",
"__asm__",
"__attribute",
"__attribute__",
"__builtin_va_arg",
"__complex",
"__complex__",
"__const",
"__const__",
"__extension__",
"__imag",
"__imag__",
"__inline",
"__inline__",
"__label__",
"__null",
"__real",
"__real__",
"__restrict",
"__restrict__",
"__signed",
"__signed__",
"__typeof",
"__typeof__",
"__volatile",
"__volatile__",
"and",
"and_eq",
"asm",
"auto",
"bitand",
"bitor",
"bool",
"break",
"case",
"catch",
"char",
"class",
"compl",
"const",
"const_cast",
"continue",
"default",
"delete",
"do",
"double",
"dynamic_cast",
"else",
"enum",
"explicit",
"export",
"extern",
"false",
"float",
"for",
"friend",
"goto",
"if",
"inline",
"int",
"long",
"mutable",
"namespace",
"new",
"not",
"not_eq",
"operator",
"or",
"or_eq",
"private",
"protected",
"public",
"register",
"reinterpret_cast",
"return",
"short",
"signed",
"sizeof",
"static",
"static_cast",
"struct",
"switch",
"template",
"this",
"throw",
"true",
"try",
"typedef",
"typeid",
"typename",
"typeof",
"union",
"unsigned",
"using",
"virtual",
"void",
"volatile",
"wchar_t",
"while",
"xor",
"xor_eq"
};
int
cxx_keyword_p (const char *name, int length)
{
int last = ARRAY_SIZE (cxx_keywords);
int first = 0;
int mid = (last + first) / 2;
int old = -1;
for (mid = (last + first) / 2;
mid != old;
old = mid, mid = (last + first) / 2)
{
int kwl = strlen (cxx_keywords[mid]);
int min_length = kwl > length ? length : kwl;
int r = utf8_cmp ((const unsigned char *) name, min_length, cxx_keywords[mid]);
if (r == 0)
{
int i;
for (i = min_length; i < length && name[i] == '$'; ++i)
;
if (i == length)
return 1;
r = 1;
}
if (r < 0)
last = mid;
else
first = mid;
}
return 0;
}
#endif