OSDN Git Service

* c-format.c (maybe_read_dollar_number): Use safe-ctype macros
[pf3gnuchains/gcc-fork.git] / gcc / java / lex.c
1 /* Language lexer for the GNU compiler for the Java(TM) language.
2    Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3    Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. 
21
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
25
26 /* It defines java_lex (yylex) that reads a Java ASCII source file
27    possibly containing Unicode escape sequence or utf8 encoded
28    characters and returns a token for everything found but comments,
29    white spaces and line terminators. When necessary, it also fills
30    the java_lval (yylval) union. It's implemented to be called by a
31    re-entrant parser generated by Bison.
32
33    The lexical analysis conforms to the Java grammar described in "The
34    Java(TM) Language Specification. J. Gosling, B. Joy, G. Steele.
35    Addison Wesley 1996" (http://java.sun.com/docs/books/jls/html/3.doc.html) */
36
37 #include "keyword.h"
38 #include "flags.h"
39 #include "chartables.h"
40
41 /* Function declaration  */
42 static char *java_sprint_unicode PARAMS ((struct java_line *, int));
43 static void java_unicode_2_utf8 PARAMS ((unicode_t));
44 static void java_lex_error PARAMS ((const char *, int));
45 #ifndef JC1_LITE
46 static int java_is_eol PARAMS ((FILE *, int));
47 static tree build_wfl_node PARAMS ((tree));
48 #endif
49 static void java_store_unicode PARAMS ((struct java_line *, unicode_t, int));
50 static int java_parse_escape_sequence PARAMS ((void));
51 static int java_start_char_p PARAMS ((unicode_t));
52 static int java_part_char_p PARAMS ((unicode_t));
53 static int java_parse_doc_section PARAMS ((int));
54 static void java_parse_end_comment PARAMS ((int));
55 static int java_get_unicode PARAMS ((void));
56 static int java_read_unicode PARAMS ((java_lexer *, int *));
57 static int java_read_unicode_collapsing_terminators PARAMS ((java_lexer *,
58                                                              int *));
59 static void java_store_unicode PARAMS ((struct java_line *, unicode_t, int));
60 static int java_read_char PARAMS ((java_lexer *));
61 static void java_allocate_new_line PARAMS ((void));
62 static void java_unget_unicode PARAMS ((void));
63 static unicode_t java_sneak_unicode PARAMS ((void));
64 #ifndef JC1_LITE
65 static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
66 #endif
67
68 java_lexer *java_new_lexer PARAMS ((FILE *, const char *));
69
70 #ifdef HAVE_ICONV
71 /* This is nonzero if we have initialized `need_byteswap'.  */
72 static int byteswap_init = 0;
73
74 /* Some versions of iconv() (e.g., glibc 2.1.3) will return UCS-2 in
75    big-endian order -- not native endian order.  We handle this by
76    doing a conversion once at startup and seeing what happens.  This
77    flag holds the results of this determination.  */
78 static int need_byteswap = 0;
79 #endif
80
81 void
82 java_init_lex (finput, encoding)
83      FILE *finput;
84      const char *encoding;
85 {
86 #ifndef JC1_LITE
87   int java_lang_imported = 0;
88
89   if (!java_lang_id)
90     java_lang_id = get_identifier ("java.lang");
91   if (!java_lang_cloneable)
92     java_lang_cloneable = get_identifier ("java.lang.Cloneable");
93   if (!java_io_serializable)
94     java_io_serializable = get_identifier ("java.io.Serializable");
95   if (!inst_id)
96     inst_id = get_identifier ("inst$");
97   if (!wpv_id)
98     wpv_id = get_identifier ("write_parm_value$");
99
100   if (!java_lang_imported)
101     {
102       tree node = build_tree_list 
103         (build_expr_wfl (java_lang_id, NULL, 0, 0), NULL_TREE);
104       read_import_dir (TREE_PURPOSE (node));
105       TREE_CHAIN (node) = ctxp->import_demand_list;
106       ctxp->import_demand_list = node;
107       java_lang_imported = 1;
108     }
109
110   if (!wfl_operator)
111     wfl_operator = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0);
112   if (!label_id)
113     label_id = get_identifier ("$L");
114   if (!wfl_append) 
115     wfl_append = build_expr_wfl (get_identifier ("append"), NULL, 0, 0);
116   if (!wfl_string_buffer)
117     wfl_string_buffer = 
118       build_expr_wfl (get_identifier ("java.lang.StringBuffer"), NULL, 0, 0);
119   if (!wfl_to_string)
120     wfl_to_string = build_expr_wfl (get_identifier ("toString"), NULL, 0, 0);
121
122   CPC_INITIALIZER_LIST (ctxp) = CPC_STATIC_INITIALIZER_LIST (ctxp) =
123     CPC_INSTANCE_INITIALIZER_LIST (ctxp) = NULL_TREE;
124
125   memset ((PTR) ctxp->modifier_ctx, 0, 11*sizeof (ctxp->modifier_ctx[0]));
126   memset ((PTR) current_jcf, 0, sizeof (JCF));
127   ctxp->current_parsed_class = NULL;
128   ctxp->package = NULL_TREE;
129 #endif
130
131   ctxp->filename = input_filename;
132   ctxp->lineno = lineno = 0;
133   ctxp->p_line = NULL;
134   ctxp->c_line = NULL;
135   ctxp->minus_seen = 0;
136   ctxp->java_error_flag = 0;
137   ctxp->lexer = java_new_lexer (finput, encoding);
138 }
139
140 static char *
141 java_sprint_unicode (line, i)
142     struct java_line *line;
143     int i;
144 {
145   static char buffer [10];
146   if (line->unicode_escape_p [i] || line->line [i] > 128)
147     sprintf (buffer, "\\u%04x", line->line [i]);
148   else
149     {
150       buffer [0] = line->line [i];
151       buffer [1] = '\0';
152     }
153   return buffer;
154 }
155
156 static unicode_t
157 java_sneak_unicode ()
158 {
159   return (ctxp->c_line->line [ctxp->c_line->current]);
160 }
161
162 static void
163 java_unget_unicode ()
164 {
165   if (!ctxp->c_line->current)
166     /* Can't unget unicode.  */
167     abort ();
168
169   ctxp->c_line->current--;
170   ctxp->c_line->char_col -= JAVA_COLUMN_DELTA (0);
171 }
172
173 static void
174 java_allocate_new_line ()
175 {
176   unicode_t ahead = (ctxp->c_line ? ctxp->c_line->ahead[0] : '\0');
177   char ahead_escape_p = (ctxp->c_line ? 
178                          ctxp->c_line->unicode_escape_ahead_p : 0);
179
180   if (ctxp->c_line && !ctxp->c_line->white_space_only)
181     {
182       if (ctxp->p_line)
183         {
184           free (ctxp->p_line->unicode_escape_p);
185           free (ctxp->p_line->line);
186           free (ctxp->p_line);
187         }
188       ctxp->p_line = ctxp->c_line;
189       ctxp->c_line = NULL;              /* Reallocated */
190     }
191
192   if (!ctxp->c_line)
193     {
194       ctxp->c_line = (struct java_line *)xmalloc (sizeof (struct java_line));
195       ctxp->c_line->max = JAVA_LINE_MAX;
196       ctxp->c_line->line = (unicode_t *)xmalloc 
197         (sizeof (unicode_t)*ctxp->c_line->max);
198       ctxp->c_line->unicode_escape_p = 
199           (char *)xmalloc (sizeof (char)*ctxp->c_line->max);
200       ctxp->c_line->white_space_only = 0;
201     }
202
203   ctxp->c_line->line [0] = ctxp->c_line->size = 0;
204   ctxp->c_line->char_col = ctxp->c_line->current = 0;
205   if (ahead)
206     {
207       ctxp->c_line->line [ctxp->c_line->size] = ahead;
208       ctxp->c_line->unicode_escape_p [ctxp->c_line->size] = ahead_escape_p;
209       ctxp->c_line->size++;
210     }
211   ctxp->c_line->ahead [0] = 0;
212   ctxp->c_line->unicode_escape_ahead_p = 0;
213   ctxp->c_line->lineno = ++lineno;
214   ctxp->c_line->white_space_only = 1;
215 }
216
217 /* Create a new lexer object.  */
218
219 java_lexer *
220 java_new_lexer (finput, encoding)
221      FILE *finput;
222      const char *encoding;
223 {
224   java_lexer *lex = (java_lexer *) xmalloc (sizeof (java_lexer));
225   int enc_error = 0;
226
227   lex->finput = finput;
228   lex->bs_count = 0;
229   lex->unget_value = 0;
230   lex->hit_eof = 0;
231
232 #ifdef HAVE_ICONV
233   lex->handle = iconv_open ("UCS-2", encoding);
234   if (lex->handle != (iconv_t) -1)
235     {
236       lex->first = -1;
237       lex->last = -1;
238       lex->out_first = -1;
239       lex->out_last = -1;
240       lex->read_anything = 0;
241       lex->use_fallback = 0;
242
243       /* Work around broken iconv() implementations by doing checking at
244          runtime.  We assume that if the UTF-8 => UCS-2 encoder is broken,
245          then all UCS-2 encoders will be broken.  Perhaps not a valid
246          assumption.  */
247       if (! byteswap_init)
248         {
249           iconv_t handle;
250
251           byteswap_init = 1;
252
253           handle = iconv_open ("UCS-2", "UTF-8");
254           if (handle != (iconv_t) -1)
255             {
256               unicode_t result;
257               unsigned char in[3];
258               char *inp, *outp;
259               size_t inc, outc, r;
260
261               /* This is the UTF-8 encoding of \ufeff.  */
262               in[0] = 0xef;
263               in[1] = 0xbb;
264               in[2] = 0xbf;
265
266               inp = in;
267               inc = 3;
268               outp = (char *) &result;
269               outc = 2;
270
271               r = iconv (handle, (ICONV_CONST char **) &inp, &inc,
272                          &outp, &outc);
273               iconv_close (handle);
274               /* Conversion must be complete for us to use the result.  */
275               if (r != (size_t) -1 && inc == 0 && outc == 0)
276                 need_byteswap = (result != 0xfeff);
277             }
278         }
279
280       lex->byte_swap = need_byteswap;
281     }
282   else
283 #endif /* HAVE_ICONV */
284     {
285       /* If iconv failed, use the internal decoder if the default
286          encoding was requested.  This code is used on platforms where
287          iconv exists but is insufficient for our needs.  For
288          instance, on Solaris 2.5 iconv cannot handle UTF-8 or UCS-2.  */
289       if (strcmp (encoding, DEFAULT_ENCODING))
290         enc_error = 1;
291 #ifdef HAVE_ICONV
292       else
293         lex->use_fallback = 1;
294 #endif /* HAVE_ICONV */
295     }
296
297   if (enc_error)
298     fatal_error ("unknown encoding: `%s'\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);
299
300   return lex;
301 }
302
303 void
304 java_destroy_lexer (lex)
305      java_lexer *lex;
306 {
307 #ifdef HAVE_ICONV
308   if (! lex->use_fallback)
309     iconv_close (lex->handle);
310 #endif
311   free (lex);
312 }
313
314 static int
315 java_read_char (lex)
316      java_lexer *lex;
317 {
318   if (lex->unget_value)
319     {
320       unicode_t r = lex->unget_value;
321       lex->unget_value = 0;
322       return r;
323     }
324
325 #ifdef HAVE_ICONV
326   if (! lex->use_fallback)
327     {
328       size_t ir, inbytesleft, in_save, out_count, out_save;
329       char *inp, *outp;
330       unicode_t result;
331
332       /* If there is data which has already been converted, use it.  */
333       if (lex->out_first == -1 || lex->out_first >= lex->out_last)
334         {
335           lex->out_first = 0;
336           lex->out_last = 0;
337
338           while (1)
339             {
340               /* See if we need to read more data.  If FIRST == 0 then
341                  the previous conversion attempt ended in the middle of
342                  a character at the end of the buffer.  Otherwise we
343                  only have to read if the buffer is empty.  */
344               if (lex->first == 0 || lex->first >= lex->last)
345                 {
346                   int r;
347
348                   if (lex->first >= lex->last)
349                     {
350                       lex->first = 0;
351                       lex->last = 0;
352                     }
353                   if (feof (lex->finput))
354                     return UEOF;
355                   r = fread (&lex->buffer[lex->last], 1,
356                              sizeof (lex->buffer) - lex->last,
357                              lex->finput);
358                   lex->last += r;
359                 }
360
361               inbytesleft = lex->last - lex->first;
362               out_count = sizeof (lex->out_buffer) - lex->out_last;
363
364               if (inbytesleft == 0)
365                 {
366                   /* We've tried to read and there is nothing left.  */
367                   return UEOF;
368                 }
369
370               in_save = inbytesleft;
371               out_save = out_count;
372               inp = &lex->buffer[lex->first];
373               outp = &lex->out_buffer[lex->out_last];
374               ir = iconv (lex->handle, (ICONV_CONST char **) &inp,
375                           &inbytesleft, &outp, &out_count);
376
377               /* If we haven't read any bytes, then look to see if we
378                  have read a BOM.  */
379               if (! lex->read_anything && out_save - out_count >= 2)
380                 {
381                   unicode_t uc = * (unicode_t *) &lex->out_buffer[0];
382                   if (uc == 0xfeff)
383                     {
384                       lex->byte_swap = 0;
385                       lex->out_first += 2;
386                     }
387                   else if (uc == 0xfffe)
388                     {
389                       lex->byte_swap = 1;
390                       lex->out_first += 2;
391                     }
392                   lex->read_anything = 1;
393                 }
394
395               if (lex->byte_swap)
396                 {
397                   unsigned int i;
398                   for (i = 0; i < out_save - out_count; i += 2)
399                     {
400                       char t = lex->out_buffer[lex->out_last + i];
401                       lex->out_buffer[lex->out_last + i]
402                         = lex->out_buffer[lex->out_last + i + 1];
403                       lex->out_buffer[lex->out_last + i + 1] = t;
404                     }
405                 }
406
407               lex->first += in_save - inbytesleft;
408               lex->out_last += out_save - out_count;
409
410               /* If we converted anything at all, move along.  */
411               if (out_count != out_save)
412                 break;
413
414               if (ir == (size_t) -1)
415                 {
416                   if (errno == EINVAL)
417                     {
418                       /* This is ok.  This means that the end of our buffer
419                          is in the middle of a character sequence.  We just
420                          move the valid part of the buffer to the beginning
421                          to force a read.  */
422                       memmove (&lex->buffer[0], &lex->buffer[lex->first],
423                                lex->last - lex->first);
424                       lex->last -= lex->first;
425                       lex->first = 0;
426                     }
427                   else
428                     {
429                       /* A more serious error.  */
430                       java_lex_error ("unrecognized character in input stream",
431                                       0);
432                       return UEOF;
433                     }
434                 }
435             }
436         }
437
438       if (lex->out_first == -1 || lex->out_first >= lex->out_last)
439         {
440           /* Don't have any data.  */
441           return UEOF;
442         }
443
444       /* Success.  */
445       result = * ((unicode_t *) &lex->out_buffer[lex->out_first]);
446       lex->out_first += 2;
447       return result;
448     }
449   else
450 #endif /* HAVE_ICONV */
451     {
452       int c, c1, c2;
453       c = getc (lex->finput);
454
455       if (c == EOF)
456         return UEOF;
457       if (c < 128)
458         return (unicode_t) c;
459       else
460         {
461           if ((c & 0xe0) == 0xc0)
462             {
463               c1 = getc (lex->finput);
464               if ((c1 & 0xc0) == 0x80)
465                 {
466                   unicode_t r = (unicode_t)(((c & 0x1f) << 6) + (c1 & 0x3f));
467                   /* Check for valid 2-byte characters.  We explicitly
468                      allow \0 because this encoding is common in the
469                      Java world.  */
470                   if (r == 0 || (r >= 0x80 && r <= 0x7ff))
471                     return r;
472                 }
473             }
474           else if ((c & 0xf0) == 0xe0)
475             {
476               c1 = getc (lex->finput);
477               if ((c1 & 0xc0) == 0x80)
478                 {
479                   c2 = getc (lex->finput);
480                   if ((c2 & 0xc0) == 0x80)
481                     {
482                       unicode_t r =  (unicode_t)(((c & 0xf) << 12) + 
483                                                  (( c1 & 0x3f) << 6)
484                                                  + (c2 & 0x3f));
485                       /* Check for valid 3-byte characters.
486                          Don't allow surrogate, \ufffe or \uffff.  */
487                       if (r >= 0x800 && r <= 0xffff
488                           && ! (r >= 0xd800 && r <= 0xdfff)
489                           && r != 0xfffe && r != 0xffff)
490                         return r;
491                     }
492                 }
493             }
494
495           /* We simply don't support invalid characters.  We also
496              don't support 4-, 5-, or 6-byte UTF-8 sequences, as these
497              cannot be valid Java characters.  */
498           java_lex_error ("malformed UTF-8 character", 0);
499         }
500     }
501
502   /* We only get here on error.  */
503   return UEOF;
504 }
505
506 static void
507 java_store_unicode (l, c, unicode_escape_p)
508     struct java_line *l;
509     unicode_t c;
510     int unicode_escape_p;
511 {
512   if (l->size == l->max)
513     {
514       l->max += JAVA_LINE_MAX;
515       l->line = (unicode_t *) xrealloc (l->line, sizeof (unicode_t)*l->max);
516       l->unicode_escape_p = (char *) xrealloc (l->unicode_escape_p, 
517                                                sizeof (char)*l->max);
518     }
519   l->line [l->size] = c;
520   l->unicode_escape_p [l->size++] = unicode_escape_p;
521 }
522
523 static int
524 java_read_unicode (lex, unicode_escape_p)
525      java_lexer *lex;
526      int *unicode_escape_p;
527 {
528   int c;
529
530   c = java_read_char (lex);
531   *unicode_escape_p = 0;
532
533   if (c != '\\')
534     {
535       lex->bs_count = 0;
536       return c;
537     }
538
539   ++lex->bs_count;
540   if ((lex->bs_count) % 2 == 1)
541     {
542       /* Odd number of \ seen.  */
543       c = java_read_char (lex);
544       if (c == 'u')
545         {
546           unicode_t unicode = 0;
547           int shift = 12;
548
549           /* Recognize any number of `u's in \u.  */
550           while ((c = java_read_char (lex)) == 'u')
551             ;
552
553           /* Unget the most recent character as it is not a `u'.  */
554           if (c == UEOF)
555             return UEOF;
556           lex->unget_value = c;
557
558           /* Next should be 4 hex digits, otherwise it's an error.
559              The hex value is converted into the unicode, pushed into
560              the Unicode stream.  */
561           for (shift = 12; shift >= 0; shift -= 4)
562             {
563               if ((c = java_read_char (lex)) == UEOF)
564                 return UEOF;
565               if (ISDIGIT (c))
566                 unicode |= (unicode_t)((c-'0') << shift);
567               else if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
568                 unicode |= (unicode_t)((10+(c | 0x20)-'a') << shift);
569               else
570                 java_lex_error ("Non hex digit in Unicode escape sequence", 0);
571             }
572           lex->bs_count = 0;
573           *unicode_escape_p = 1;
574           return unicode;
575         }
576       lex->unget_value = c;
577     }
578   return (unicode_t) '\\';
579 }
580
581 static int
582 java_read_unicode_collapsing_terminators (lex, unicode_escape_p)
583      java_lexer *lex;
584      int *unicode_escape_p;
585 {
586   int c = java_read_unicode (lex, unicode_escape_p);
587
588   if (c == '\r')
589     {
590       /* We have to read ahead to see if we got \r\n.  In that case we
591          return a single line terminator.  */
592       int dummy;
593       c = java_read_unicode (lex, &dummy);
594       if (c != '\n')
595         lex->unget_value = c;
596       /* In either case we must return a newline.  */
597       c = '\n';
598     }
599
600   return c;
601 }
602
603 static int
604 java_get_unicode ()
605 {
606   /* It's time to read a line when... */
607   if (!ctxp->c_line || ctxp->c_line->current == ctxp->c_line->size)
608     {
609       int c;
610       int found_chars = 0;
611
612       if (ctxp->lexer->hit_eof)
613         return UEOF;
614
615       java_allocate_new_line ();
616       if (ctxp->c_line->line[0] != '\n')
617         {
618           for (;;)
619             {
620               int unicode_escape_p;
621               c = java_read_unicode_collapsing_terminators (ctxp->lexer,
622                                                             &unicode_escape_p);
623               if (c != UEOF)
624                 {
625                   found_chars = 1;
626                   java_store_unicode (ctxp->c_line, c, unicode_escape_p);
627                   if (ctxp->c_line->white_space_only 
628                       && !JAVA_WHITE_SPACE_P (c)
629                       && c != '\n')
630                     ctxp->c_line->white_space_only = 0;
631                 }
632               if ((c == '\n') || (c == UEOF))
633                 break;
634             }
635
636           if (c == UEOF && ! found_chars)
637             {
638               ctxp->lexer->hit_eof = 1;
639               return UEOF;
640             }
641         }
642     }
643   ctxp->c_line->char_col += JAVA_COLUMN_DELTA (0);
644   JAVA_LEX_CHAR (ctxp->c_line->line [ctxp->c_line->current]);
645   return ctxp->c_line->line [ctxp->c_line->current++];
646 }
647
648 /* Parse the end of a C style comment.
649  * C is the first character following the '/' and '*'. */
650 static void
651 java_parse_end_comment (c)
652      int c;
653 {
654   for ( ;; c = java_get_unicode ())
655     {
656       switch (c)
657         {
658         case UEOF:
659           java_lex_error ("Comment not terminated at end of input", 0);
660           return;
661         case '*':
662           switch (c = java_get_unicode ())
663             {
664             case UEOF:
665               java_lex_error ("Comment not terminated at end of input", 0);
666               return;
667             case '/':
668               return;
669             case '*':   /* reparse only '*' */
670               java_unget_unicode ();
671             }
672         }
673     }
674 }
675
676 /* Parse the documentation section. Keywords must be at the beginning
677    of a documentation comment line (ignoring white space and any `*'
678    character). Parsed keyword(s): @DEPRECATED.  */
679
680 static int
681 java_parse_doc_section (c)
682      int c;
683 {
684   int valid_tag = 0, seen_star = 0;
685
686   while (JAVA_WHITE_SPACE_P (c) || (c == '*') || c == '\n')
687     {
688       switch (c)
689         {
690         case '*':
691           seen_star = 1;
692           break;
693         case '\n': /* ULT */
694           valid_tag = 1;
695         default:
696           seen_star = 0;
697         }
698       c = java_get_unicode();
699     }
700
701   if (c == UEOF)
702     java_lex_error ("Comment not terminated at end of input", 0);
703
704   if (seen_star && (c == '/'))
705     return 1;                   /* Goto step1 in caller */
706
707   /* We're parsing @deprecated */
708   if (valid_tag && (c == '@'))
709     {
710       char tag [11];
711       int  tag_index = 0;
712
713       while (tag_index < 10 && c != UEOF && c != ' ' && c != '\n')
714         {
715           c = java_get_unicode ();
716           tag [tag_index++] = c;
717         }
718
719       if (c == UEOF)
720         java_lex_error ("Comment not terminated at end of input", 0);
721       tag [tag_index] = '\0';
722
723       if (!strcmp (tag, "deprecated"))
724         ctxp->deprecated = 1;
725     }
726   java_unget_unicode ();
727   return 0;
728 }
729
730 /* Return true if C is a valid start character for a Java identifier.
731    This is only called if C >= 128 -- smaller values are handled
732    inline.  However, this function handles all values anyway.  */
733 static int
734 java_start_char_p (c)
735      unicode_t c;
736 {
737   unsigned int hi = c / 256;
738   char *page = type_table[hi];
739   unsigned long val = (unsigned long) page;
740   int flags;
741
742   if ((val & ~ (LETTER_PART | LETTER_START)) != 0)
743     flags = page[c & 255];
744   else
745     flags = val;
746
747   return flags & LETTER_START;
748 }
749
750 /* Return true if C is a valid part character for a Java identifier.
751    This is only called if C >= 128 -- smaller values are handled
752    inline.  However, this function handles all values anyway.  */
753 static int
754 java_part_char_p (c)
755      unicode_t c;
756 {
757   unsigned int hi = c / 256;
758   char *page = type_table[hi];
759   unsigned long val = (unsigned long) page;
760   int flags;
761
762   if ((val & ~ (LETTER_PART | LETTER_START)) != 0)
763     flags = page[c & 255];
764   else
765     flags = val;
766
767   return flags & LETTER_PART;
768 }
769
770 static int
771 java_parse_escape_sequence ()
772 {
773   unicode_t char_lit;
774   int c;
775
776   switch (c = java_get_unicode ())
777     {
778     case 'b':
779       return (unicode_t)0x8;
780     case 't':
781       return (unicode_t)0x9;
782     case 'n':
783       return (unicode_t)0xa;
784     case 'f':
785       return (unicode_t)0xc;
786     case 'r':
787       return (unicode_t)0xd;
788     case '"':
789       return (unicode_t)0x22;
790     case '\'':
791       return (unicode_t)0x27;
792     case '\\':
793       return (unicode_t)0x5c;
794     case '0': case '1': case '2': case '3': case '4':
795     case '5': case '6': case '7':
796       {
797         int octal_escape[3];
798         int octal_escape_index = 0;
799         int max = 3;
800         int i, shift;
801
802         for (; octal_escape_index < max && RANGE (c, '0', '7');
803              c = java_get_unicode ())
804           {
805             if (octal_escape_index == 0 && c > '3')
806               {
807                 /* According to the grammar, `\477' has a well-defined
808                    meaning -- it is `\47' followed by `7'.  */
809                 --max;
810               }
811             octal_escape [octal_escape_index++] = c;
812           }
813
814         java_unget_unicode ();
815
816         for (char_lit=0, i = 0, shift = 3*(octal_escape_index-1);
817              i < octal_escape_index; i++, shift -= 3)
818           char_lit |= (octal_escape [i] - '0') << shift;
819
820         return char_lit;
821       }
822     default:
823       java_lex_error ("Invalid character in escape sequence", 0);
824       return JAVA_CHAR_ERROR;
825     }
826 }
827
828 /* Isolate the code which may raise an arithmetic exception in its
829    own function.  */
830
831 #ifndef JC1_LITE
832 struct jpa_args
833 {
834   YYSTYPE *java_lval;
835   char *literal_token;
836   int fflag;
837   int number_beginning;
838 };
839
840 #ifdef REAL_ARITHMETIC
841 #define IS_ZERO(X) (ereal_cmp (X, dconst0) == 0)
842 #else
843 #define IS_ZERO(X) ((X) == 0)
844 #endif
845
846 static void java_perform_atof   PARAMS ((PTR));
847
848 static void
849 java_perform_atof (av)
850      PTR av;
851 {
852   struct jpa_args *a = (struct jpa_args *)av;
853   YYSTYPE *java_lval = a->java_lval;
854   int number_beginning = a->number_beginning;
855   REAL_VALUE_TYPE value;
856   tree type = (a->fflag ? FLOAT_TYPE_NODE : DOUBLE_TYPE_NODE);
857
858   SET_REAL_VALUE_ATOF (value,
859                        REAL_VALUE_ATOF (a->literal_token, TYPE_MODE (type)));
860
861   if (REAL_VALUE_ISINF (value) || REAL_VALUE_ISNAN (value))
862     {
863       JAVA_FLOAT_RANGE_ERROR ((a->fflag ? "float" : "double"));
864       value = DCONST0;
865     }
866   else if (IS_ZERO (value))
867     {
868       /* We check to see if the value is really 0 or if we've found an
869          underflow.  We do this in the most primitive imaginable way.  */
870       int really_zero = 1;
871       char *p = a->literal_token;
872       if (*p == '-')
873         ++p;
874       while (*p && *p != 'e' && *p != 'E')
875         {
876           if (*p != '0' && *p != '.')
877             {
878               really_zero = 0;
879               break;
880             }
881           ++p;
882         }
883       if (! really_zero)
884         {
885           int i = ctxp->c_line->current;
886           ctxp->c_line->current = number_beginning;
887           java_lex_error ("Floating point literal underflow", 0);
888           ctxp->c_line->current = i;
889         }
890     }
891
892   SET_LVAL_NODE_TYPE (build_real (type, value), type);
893 }
894 #endif
895
896 static int yylex                PARAMS ((YYSTYPE *));
897
898 static int
899 #ifdef JC1_LITE
900 yylex (java_lval)
901 #else
902 java_lex (java_lval)
903 #endif
904      YYSTYPE *java_lval;
905 {
906   int c;
907   unicode_t first_unicode;
908   int ascii_index, all_ascii;
909   char *string;
910
911   /* Translation of the Unicode escape in the raw stream of Unicode
912      characters. Takes care of line terminator.  */
913  step1:
914   /* Skip white spaces: SP, TAB and FF or ULT */ 
915   for (c = java_get_unicode ();
916        c == '\n' || JAVA_WHITE_SPACE_P (c); c = java_get_unicode ())
917     if (c == '\n')
918       {
919         ctxp->elc.line = ctxp->c_line->lineno;
920         ctxp->elc.col  = ctxp->c_line->char_col-2;
921       }
922
923   ctxp->elc.col = (ctxp->elc.col < 0 ? 0 : ctxp->elc.col);
924
925   if (c == 0x1a)                /* CTRL-Z */
926     {
927       if ((c = java_get_unicode ()) == UEOF)
928         return 0;               /* Ok here */
929       else
930         java_unget_unicode ();  /* Caught later, at the end of the function */
931     }
932   /* Handle EOF here */
933   if (c == UEOF)        /* Should probably do something here... */
934     return 0;
935
936   /* Take care of eventual comments.  */
937   if (c == '/')
938     {
939       switch (c = java_get_unicode ())
940         {
941         case '/':
942           for (;;)
943             {
944               c = java_get_unicode ();
945               if (c == UEOF)
946                 {
947                   /* It is ok to end a `//' comment with EOF, unless
948                      we're being pedantic.  */
949                   if (pedantic)
950                     java_lex_error ("Comment not terminated at end of input",
951                                     0);
952                   return 0;
953                 }
954               if (c == '\n')    /* ULT */
955                 goto step1;
956             }
957           break;
958
959         case '*':
960           if ((c = java_get_unicode ()) == '*')
961             {
962               if ((c = java_get_unicode ()) == '/')
963                 goto step1;     /* Empy documentation comment  */
964               else if (java_parse_doc_section (c))
965                 goto step1;
966             }
967
968           java_parse_end_comment ((c = java_get_unicode ()));
969           goto step1;
970           break;
971         default:
972           java_unget_unicode ();
973           c = '/';
974           break;
975         }
976     }
977
978   ctxp->elc.line = ctxp->c_line->lineno;
979   ctxp->elc.prev_col = ctxp->elc.col;
980   ctxp->elc.col = ctxp->c_line->char_col - JAVA_COLUMN_DELTA (-1);
981   if (ctxp->elc.col < 0)
982     abort ();
983
984   /* Numeric literals */
985   if (JAVA_ASCII_DIGIT (c) || (c == '.'))
986     {
987       /* This section of code is borrowed from gcc/c-lex.c  */
988 #define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
989       int parts[TOTAL_PARTS];
990       HOST_WIDE_INT high, low;
991       /* End borrowed section  */
992       char literal_token [256];
993       int  literal_index = 0, radix = 10, long_suffix = 0, overflow = 0, bytes;
994       int  found_hex_digits = 0;
995       int  i;
996 #ifndef JC1_LITE
997       int  number_beginning = ctxp->c_line->current;
998 #endif
999       
1000       /* We might have a . separator instead of a FP like .[0-9]* */
1001       if (c == '.')
1002         {
1003           unicode_t peep = java_sneak_unicode ();
1004
1005           if (!JAVA_ASCII_DIGIT (peep))
1006             {
1007               JAVA_LEX_SEP('.');
1008               BUILD_OPERATOR (DOT_TK);
1009             }
1010         }
1011
1012       for (i = 0; i < TOTAL_PARTS; i++)
1013         parts [i] = 0;
1014
1015       if (c == '0')
1016         {
1017           c = java_get_unicode ();
1018           if (c == 'x' || c == 'X')
1019             {
1020               radix = 16;
1021               c = java_get_unicode ();
1022             }
1023           else if (JAVA_ASCII_DIGIT (c))
1024             radix = 8;
1025           else if (c == '.')
1026             {
1027               /* Push the '.' back and prepare for a FP parsing... */
1028               java_unget_unicode ();
1029               c = '0';
1030             }
1031           else
1032             {
1033               /* We have a zero literal: 0, 0{f,F}, 0{d,D} */
1034               JAVA_LEX_LIT ("0", 10);
1035               switch (c)
1036                 {               
1037                 case 'L': case 'l':
1038                   SET_LVAL_NODE (long_zero_node);
1039                   return (INT_LIT_TK);
1040                 case 'f': case 'F':
1041                   SET_LVAL_NODE (float_zero_node);
1042                   return (FP_LIT_TK);
1043                 case 'd': case 'D':
1044                   SET_LVAL_NODE (double_zero_node);
1045                   return (FP_LIT_TK);
1046                 default:
1047                   java_unget_unicode ();
1048                   SET_LVAL_NODE (integer_zero_node);
1049                   return (INT_LIT_TK);
1050                 }
1051             }
1052         }
1053       /* Parse the first part of the literal, until we find something
1054          which is not a number.  */
1055       while ((radix == 10 && JAVA_ASCII_DIGIT (c)) ||
1056              (radix == 16 && JAVA_ASCII_HEXDIGIT (c)) ||
1057              (radix == 8  && JAVA_ASCII_OCTDIGIT (c)))
1058         {
1059           /* We store in a string (in case it turns out to be a FP) and in
1060              PARTS if we have to process a integer literal.  */
1061           int numeric = (ISDIGIT (c) ? c-'0' : 10 +(c|0x20)-'a');
1062           int count;
1063
1064           /* Remember when we find a valid hexadecimal digit */
1065           if (radix == 16)
1066             found_hex_digits = 1;
1067
1068           literal_token [literal_index++] = c;
1069           /* This section of code if borrowed from gcc/c-lex.c  */
1070           for (count = 0; count < TOTAL_PARTS; count++)
1071             {
1072               parts[count] *= radix;
1073               if (count)
1074                 {
1075                   parts[count]   += (parts[count-1] >> HOST_BITS_PER_CHAR);
1076                   parts[count-1] &= (1 << HOST_BITS_PER_CHAR) - 1;
1077                 }
1078               else
1079                 parts[0] += numeric;
1080             }
1081           if (parts [TOTAL_PARTS-1] != 0)
1082             overflow = 1;
1083           /* End borrowed section.  */
1084           c = java_get_unicode ();
1085         }
1086
1087       /* If we have something from the FP char set but not a digit, parse
1088          a FP literal.  */
1089       if (JAVA_ASCII_FPCHAR (c) && !JAVA_ASCII_DIGIT (c))
1090         {
1091           int stage = 0;
1092           int seen_digit = (literal_index ? 1 : 0);
1093           int seen_exponent = 0;
1094           int fflag = 0;        /* 1 for {f,F}, 0 for {d,D}. FP literal are
1095                                    double unless specified. */
1096
1097           /* It is ok if the radix is 8 because this just means we've
1098              seen a leading `0'.  However, radix==16 is invalid.  */
1099           if (radix == 16)
1100             java_lex_error ("Can't express non-decimal FP literal", 0);
1101           radix = 10;
1102
1103           for (;;)
1104             {
1105               if (c == '.')
1106                 {
1107                   if (stage < 1)
1108                     {
1109                       stage = 1;
1110                       literal_token [literal_index++ ] = c;
1111                       c = java_get_unicode ();
1112                     }
1113                   else
1114                     java_lex_error ("Invalid character in FP literal", 0);
1115                 }
1116
1117               if (c == 'e' || c == 'E')
1118                 {
1119                   if (stage < 2)
1120                     {
1121                       /* {E,e} must have seen at list a digit */
1122                       if (!seen_digit)
1123                         java_lex_error ("Invalid FP literal", 0);
1124                       seen_digit = 0;
1125                       seen_exponent = 1;
1126                       stage = 2;
1127                       literal_token [literal_index++] = c;
1128                       c = java_get_unicode ();
1129                     }
1130                   else
1131                     java_lex_error ("Invalid character in FP literal", 0);
1132                 }
1133               if ( c == 'f' || c == 'F' || c == 'd' || c == 'D')
1134                 {
1135                   fflag = ((c == 'd') || (c == 'D')) ? 0 : 1;
1136                   stage = 4;    /* So we fall through */
1137                 }
1138
1139               if ((c=='-' || c =='+') && stage == 2)
1140                 {
1141                   stage = 3;
1142                   literal_token [literal_index++] = c;
1143                   c = java_get_unicode ();
1144                 }
1145
1146               if ((stage == 0 && JAVA_ASCII_FPCHAR (c)) ||
1147                   (stage == 1 && JAVA_ASCII_FPCHAR (c) && !(c == '.')) ||
1148                   (stage == 2 && (JAVA_ASCII_DIGIT (c) || JAVA_FP_PM (c))) ||
1149                   (stage == 3 && JAVA_ASCII_DIGIT (c)))
1150                 {
1151                   if (JAVA_ASCII_DIGIT (c))
1152                     seen_digit = 1;
1153                   literal_token [literal_index++ ] = c;
1154                   c = java_get_unicode ();
1155                 }
1156               else
1157                 {
1158 #ifndef JC1_LITE
1159                   struct jpa_args a;
1160 #endif
1161                   if (stage != 4) /* Don't push back fF/dD */
1162                     java_unget_unicode ();
1163                   
1164                   /* An exponent (if any) must have seen a digit.  */
1165                   if (seen_exponent && !seen_digit)
1166                     java_lex_error ("Invalid FP literal", 0);
1167
1168                   literal_token [literal_index] = '\0';
1169                   JAVA_LEX_LIT (literal_token, radix);
1170
1171 #ifndef JC1_LITE
1172                   a.literal_token = literal_token;
1173                   a.fflag = fflag;
1174                   a.java_lval = java_lval;
1175                   a.number_beginning = number_beginning;
1176                   if (do_float_handler (java_perform_atof, (PTR) &a))
1177                     return FP_LIT_TK;
1178
1179                   JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double"));
1180 #else
1181                   return FP_LIT_TK;
1182 #endif
1183                 }
1184             }
1185         } /* JAVA_ASCCI_FPCHAR (c) */
1186
1187       if (radix == 16 && ! found_hex_digits)
1188         java_lex_error
1189           ("0x must be followed by at least one hexadecimal digit", 0);
1190
1191       /* Here we get back to converting the integral literal.  */
1192       if (c == 'L' || c == 'l')
1193         long_suffix = 1;
1194       else if (radix == 16 && JAVA_ASCII_LETTER (c))
1195         java_lex_error ("Digit out of range in hexadecimal literal", 0);
1196       else if (radix == 8  && JAVA_ASCII_DIGIT (c))
1197         java_lex_error ("Digit out of range in octal literal", 0);
1198       else if (radix == 16 && !literal_index)
1199         java_lex_error ("No digit specified for hexadecimal literal", 0);
1200       else
1201         java_unget_unicode ();
1202
1203 #ifdef JAVA_LEX_DEBUG
1204       literal_token [literal_index] = '\0'; /* So JAVA_LEX_LIT is safe. */
1205       JAVA_LEX_LIT (literal_token, radix);
1206 #endif
1207       /* This section of code is borrowed from gcc/c-lex.c  */
1208       if (!overflow)
1209         {
1210           bytes = GET_TYPE_PRECISION (long_type_node);
1211           for (i = bytes; i < TOTAL_PARTS; i++)
1212             if (parts [i])
1213               {
1214                 overflow = 1;
1215                 break;
1216               }
1217         }
1218       high = low = 0;
1219       for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++)
1220         {
1221           high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT
1222                                               / HOST_BITS_PER_CHAR)]
1223                    << (i * HOST_BITS_PER_CHAR));
1224           low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
1225         }
1226       /* End borrowed section.  */
1227
1228       /* Range checking */
1229       if (long_suffix)
1230         {
1231           /* 9223372036854775808L is valid if operand of a '-'. Otherwise
1232              9223372036854775807L is the biggest `long' literal that can be
1233              expressed using a 10 radix. For other radixes, everything that
1234              fits withing 64 bits is OK. */
1235           int hb = (high >> 31);
1236           if (overflow || (hb && low && radix == 10) ||  
1237               (hb && high & 0x7fffffff && radix == 10) ||
1238               (hb && !(high & 0x7fffffff) && !ctxp->minus_seen && radix == 10))
1239             JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `long' literal");
1240         }
1241       else
1242         {
1243           /* 2147483648 is valid if operand of a '-'. Otherwise,
1244              2147483647 is the biggest `int' literal that can be
1245              expressed using a 10 radix. For other radixes, everything
1246              that fits within 32 bits is OK.  As all literals are
1247              signed, we sign extend here. */
1248           int hb = (low >> 31) & 0x1;
1249           if (overflow || high || (hb && low & 0x7fffffff && radix == 10) ||
1250               (hb && !(low & 0x7fffffff) && !ctxp->minus_seen && radix == 10))
1251             JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `int' literal");
1252           high = -hb;
1253         }
1254       ctxp->minus_seen = 0;
1255       SET_LVAL_NODE_TYPE (build_int_2 (low, high),
1256                           (long_suffix ? long_type_node : int_type_node));
1257       return INT_LIT_TK;
1258     }
1259
1260   ctxp->minus_seen = 0;
1261
1262   /* Character literals */
1263   if (c == '\'')
1264     {
1265       int char_lit;
1266       if ((c = java_get_unicode ()) == '\\')
1267         char_lit = java_parse_escape_sequence ();
1268       else
1269         {
1270           if (c == '\n' || c == '\'')
1271             java_lex_error ("Invalid character literal", 0);
1272           char_lit = c;
1273         }
1274
1275       c = java_get_unicode ();
1276
1277       if ((c == '\n') || (c == UEOF))
1278         java_lex_error ("Character literal not terminated at end of line", 0);
1279       if (c != '\'')
1280         java_lex_error ("Syntax error in character literal", 0);
1281
1282       if (char_lit == JAVA_CHAR_ERROR)
1283         char_lit = 0;           /* We silently convert it to zero */
1284
1285       JAVA_LEX_CHAR_LIT (char_lit);
1286       SET_LVAL_NODE_TYPE (build_int_2 (char_lit, 0), char_type_node);
1287       return CHAR_LIT_TK;
1288     }
1289
1290   /* String literals */
1291   if (c == '"')
1292     {
1293       int no_error;
1294       char *string;
1295
1296       for (no_error = 1, c = java_get_unicode (); 
1297            c != UEOF && c != '"' && c != '\n'; c = java_get_unicode ())
1298         {
1299           if (c == '\\')
1300             c = java_parse_escape_sequence ();
1301           if (c == JAVA_CHAR_ERROR)
1302             {
1303               no_error = 0;
1304               c = 0;            /* We silently convert it to zero.  */
1305             }
1306           java_unicode_2_utf8 (c);
1307         }
1308       if (c == '\n' || c == UEOF) /* ULT */
1309         {
1310           lineno--;             /* Refer to the line the terminator was seen */
1311           java_lex_error ("String not terminated at end of line.", 0);
1312           lineno++;
1313         }
1314
1315       obstack_1grow (&temporary_obstack, '\0');
1316       string = obstack_finish (&temporary_obstack);
1317 #ifndef JC1_LITE
1318       if (!no_error || (c != '"'))
1319         java_lval->node = error_mark_node; /* Requires futher testing FIXME */
1320       else
1321         java_lval->node = build_string (strlen (string), string);
1322 #endif
1323       obstack_free (&temporary_obstack, string);
1324       return STRING_LIT_TK;
1325     }
1326
1327   /* Separator */
1328   switch (c)
1329     {
1330     case '(':
1331       JAVA_LEX_SEP (c);
1332       BUILD_OPERATOR (OP_TK);
1333     case ')':
1334       JAVA_LEX_SEP (c);
1335       return CP_TK;
1336     case '{':
1337       JAVA_LEX_SEP (c);
1338       if (ctxp->ccb_indent == 1)
1339         ctxp->first_ccb_indent1 = lineno;
1340       ctxp->ccb_indent++;
1341       BUILD_OPERATOR (OCB_TK);
1342     case '}':
1343       JAVA_LEX_SEP (c);
1344       ctxp->ccb_indent--;
1345       if (ctxp->ccb_indent == 1)
1346         ctxp->last_ccb_indent1 = lineno;
1347       BUILD_OPERATOR (CCB_TK);
1348     case '[':
1349       JAVA_LEX_SEP (c);
1350       BUILD_OPERATOR (OSB_TK);
1351     case ']':
1352       JAVA_LEX_SEP (c);
1353       return CSB_TK;
1354     case ';':
1355       JAVA_LEX_SEP (c);
1356       return SC_TK;
1357     case ',':
1358       JAVA_LEX_SEP (c);
1359       return C_TK;
1360     case '.':
1361       JAVA_LEX_SEP (c);
1362       BUILD_OPERATOR (DOT_TK);
1363       /*      return DOT_TK; */
1364     }
1365
1366   /* Operators */
1367   switch (c)
1368     {
1369     case '=':
1370       if ((c = java_get_unicode ()) == '=')
1371         {
1372           BUILD_OPERATOR (EQ_TK);
1373         }
1374       else
1375         {
1376           /* Equals is used in two different locations. In the 
1377              variable_declarator: rule, it has to be seen as '=' as opposed
1378              to being seen as an ordinary assignment operator in
1379              assignment_operators: rule.  */
1380           java_unget_unicode ();
1381           BUILD_OPERATOR (ASSIGN_TK);
1382         }
1383       
1384     case '>':
1385       switch ((c = java_get_unicode ()))
1386         {
1387         case '=':
1388           BUILD_OPERATOR (GTE_TK);
1389         case '>':
1390           switch ((c = java_get_unicode ()))
1391             {
1392             case '>':
1393               if ((c = java_get_unicode ()) == '=')
1394                 {
1395                   BUILD_OPERATOR2 (ZRS_ASSIGN_TK);
1396                 }
1397               else
1398                 {
1399                   java_unget_unicode ();
1400                   BUILD_OPERATOR (ZRS_TK);
1401                 }
1402             case '=':
1403               BUILD_OPERATOR2 (SRS_ASSIGN_TK);
1404             default:
1405               java_unget_unicode ();
1406               BUILD_OPERATOR (SRS_TK);
1407             }
1408         default:
1409           java_unget_unicode ();
1410           BUILD_OPERATOR (GT_TK);
1411         }
1412         
1413     case '<':
1414       switch ((c = java_get_unicode ()))
1415         {
1416         case '=':
1417           BUILD_OPERATOR (LTE_TK);
1418         case '<':
1419           if ((c = java_get_unicode ()) == '=')
1420             {
1421               BUILD_OPERATOR2 (LS_ASSIGN_TK);
1422             }
1423           else
1424             {
1425               java_unget_unicode ();
1426               BUILD_OPERATOR (LS_TK);
1427             }
1428         default:
1429           java_unget_unicode ();
1430           BUILD_OPERATOR (LT_TK);
1431         }
1432
1433     case '&':
1434       switch ((c = java_get_unicode ()))
1435         {
1436         case '&':
1437           BUILD_OPERATOR (BOOL_AND_TK);
1438         case '=':
1439           BUILD_OPERATOR2 (AND_ASSIGN_TK);
1440         default:
1441           java_unget_unicode ();
1442           BUILD_OPERATOR (AND_TK);
1443         }
1444
1445     case '|':
1446       switch ((c = java_get_unicode ()))
1447         {
1448         case '|':
1449           BUILD_OPERATOR (BOOL_OR_TK);
1450         case '=':
1451           BUILD_OPERATOR2 (OR_ASSIGN_TK);
1452         default:
1453           java_unget_unicode ();
1454           BUILD_OPERATOR (OR_TK);
1455         }
1456
1457     case '+':
1458       switch ((c = java_get_unicode ()))
1459         {
1460         case '+':
1461           BUILD_OPERATOR (INCR_TK);
1462         case '=':
1463           BUILD_OPERATOR2 (PLUS_ASSIGN_TK);
1464         default:
1465           java_unget_unicode ();
1466           BUILD_OPERATOR (PLUS_TK);
1467         }
1468
1469     case '-':
1470       switch ((c = java_get_unicode ()))
1471         {
1472         case '-':
1473           BUILD_OPERATOR (DECR_TK);
1474         case '=':
1475           BUILD_OPERATOR2 (MINUS_ASSIGN_TK);
1476         default:
1477           java_unget_unicode ();
1478           ctxp->minus_seen = 1;
1479           BUILD_OPERATOR (MINUS_TK);
1480         }
1481
1482     case '*':
1483       if ((c = java_get_unicode ()) == '=')
1484         {
1485           BUILD_OPERATOR2 (MULT_ASSIGN_TK);
1486         }
1487       else
1488         {
1489           java_unget_unicode ();
1490           BUILD_OPERATOR (MULT_TK);
1491         }
1492
1493     case '/':
1494       if ((c = java_get_unicode ()) == '=')
1495         {
1496           BUILD_OPERATOR2 (DIV_ASSIGN_TK);
1497         }
1498       else
1499         {
1500           java_unget_unicode ();
1501           BUILD_OPERATOR (DIV_TK);
1502         }
1503
1504     case '^':
1505       if ((c = java_get_unicode ()) == '=')
1506         {
1507           BUILD_OPERATOR2 (XOR_ASSIGN_TK);
1508         }
1509       else
1510         {
1511           java_unget_unicode ();
1512           BUILD_OPERATOR (XOR_TK);
1513         }
1514
1515     case '%':
1516       if ((c = java_get_unicode ()) == '=')
1517         {
1518           BUILD_OPERATOR2 (REM_ASSIGN_TK);
1519         }
1520       else
1521         {
1522           java_unget_unicode ();
1523           BUILD_OPERATOR (REM_TK);
1524         }
1525
1526     case '!':
1527       if ((c = java_get_unicode()) == '=')
1528         {
1529           BUILD_OPERATOR (NEQ_TK);
1530         }
1531       else
1532         {
1533           java_unget_unicode ();
1534           BUILD_OPERATOR (NEG_TK);
1535         }
1536           
1537     case '?':
1538       JAVA_LEX_OP ("?");
1539       BUILD_OPERATOR (REL_QM_TK);
1540     case ':':
1541       JAVA_LEX_OP (":");
1542       BUILD_OPERATOR (REL_CL_TK);
1543     case '~':
1544       BUILD_OPERATOR (NOT_TK);
1545     }
1546   
1547   /* Keyword, boolean literal or null literal */
1548   for (first_unicode = c, all_ascii = 1, ascii_index = 0; 
1549        JAVA_PART_CHAR_P (c); c = java_get_unicode ())
1550     {
1551       java_unicode_2_utf8 (c);
1552       if (all_ascii && c >= 128)
1553         all_ascii = 0;
1554       ascii_index++;
1555     }
1556
1557   obstack_1grow (&temporary_obstack, '\0');
1558   string = obstack_finish (&temporary_obstack);
1559   java_unget_unicode ();
1560
1561   /* If we have something all ascii, we consider a keyword, a boolean
1562      literal, a null literal or an all ASCII identifier.  Otherwise,
1563      this is an identifier (possibly not respecting formation rule).  */
1564   if (all_ascii)
1565     {
1566       struct java_keyword *kw;
1567       if ((kw=java_keyword (string, ascii_index)))
1568         {
1569           JAVA_LEX_KW (string);
1570           switch (kw->token)
1571             {
1572             case PUBLIC_TK:       case PROTECTED_TK: case STATIC_TK:
1573             case ABSTRACT_TK:     case FINAL_TK:     case NATIVE_TK:
1574             case SYNCHRONIZED_TK: case TRANSIENT_TK: case VOLATILE_TK:
1575             case PRIVATE_TK:      case STRICT_TK:
1576               SET_MODIFIER_CTX (kw->token);
1577               return MODIFIER_TK;
1578             case FLOAT_TK:
1579               SET_LVAL_NODE (float_type_node);
1580               return FP_TK;
1581             case DOUBLE_TK:
1582               SET_LVAL_NODE (double_type_node);
1583               return FP_TK;
1584             case BOOLEAN_TK:
1585               SET_LVAL_NODE (boolean_type_node);
1586               return BOOLEAN_TK;
1587             case BYTE_TK:
1588               SET_LVAL_NODE (byte_type_node);
1589               return INTEGRAL_TK;
1590             case SHORT_TK:
1591               SET_LVAL_NODE (short_type_node);
1592               return INTEGRAL_TK;
1593             case INT_TK:
1594               SET_LVAL_NODE (int_type_node);
1595               return INTEGRAL_TK;
1596             case LONG_TK:
1597               SET_LVAL_NODE (long_type_node);
1598               return INTEGRAL_TK;
1599             case CHAR_TK:
1600               SET_LVAL_NODE (char_type_node);
1601               return INTEGRAL_TK;
1602
1603               /* Keyword based literals */
1604             case TRUE_TK:
1605             case FALSE_TK:
1606               SET_LVAL_NODE ((kw->token == TRUE_TK ? 
1607                               boolean_true_node : boolean_false_node));
1608               return BOOL_LIT_TK;
1609             case NULL_TK:
1610               SET_LVAL_NODE (null_pointer_node);
1611               return NULL_TK;
1612
1613               /* Some keyword we want to retain information on the location
1614                  they where found */
1615             case CASE_TK:
1616             case DEFAULT_TK:
1617             case SUPER_TK:
1618             case THIS_TK:
1619             case RETURN_TK:
1620             case BREAK_TK:
1621             case CONTINUE_TK:
1622             case TRY_TK:
1623             case CATCH_TK:
1624             case THROW_TK:
1625             case INSTANCEOF_TK:
1626               BUILD_OPERATOR (kw->token);
1627
1628             default:
1629               return kw->token;
1630             }
1631         }
1632     }
1633   
1634   /* We may have an ID here */
1635   if (JAVA_START_CHAR_P (first_unicode))
1636     {
1637       JAVA_LEX_ID (string);
1638       java_lval->node = BUILD_ID_WFL (GET_IDENTIFIER (string));
1639       return ID_TK;
1640     }
1641
1642   /* Everything else is an invalid character in the input */
1643   {
1644     char lex_error_buffer [128];
1645     sprintf (lex_error_buffer, "Invalid character `%s' in input", 
1646              java_sprint_unicode (ctxp->c_line, ctxp->c_line->current));
1647     java_lex_error (lex_error_buffer, 1);
1648   }
1649   return 0;
1650 }
1651
1652 static void
1653 java_unicode_2_utf8 (unicode)
1654     unicode_t unicode;
1655 {
1656   if (RANGE (unicode, 0x01, 0x7f))
1657     obstack_1grow (&temporary_obstack, (char)unicode);
1658   else if (RANGE (unicode, 0x80, 0x7ff) || unicode == 0)
1659     {
1660       obstack_1grow (&temporary_obstack,
1661                      (unsigned char)(0xc0 | ((0x7c0 & unicode) >> 6)));
1662       obstack_1grow (&temporary_obstack,
1663                      (unsigned char)(0x80 | (unicode & 0x3f)));
1664     }
1665   else                          /* Range 0x800-0xffff */
1666     {
1667       obstack_1grow (&temporary_obstack,
1668                      (unsigned char)(0xe0 | (unicode & 0xf000) >> 12));
1669       obstack_1grow (&temporary_obstack,
1670                      (unsigned char)(0x80 | (unicode & 0x0fc0) >> 6));
1671       obstack_1grow (&temporary_obstack,
1672                      (unsigned char)(0x80 | (unicode & 0x003f)));
1673     }
1674 }
1675
1676 #ifndef JC1_LITE
1677 static tree
1678 build_wfl_node (node)
1679      tree node;
1680 {
1681   node = build_expr_wfl (node, ctxp->filename, ctxp->elc.line, ctxp->elc.col);
1682   /* Prevent java_complete_lhs from short-circuiting node (if constant). */
1683   TREE_TYPE (node) = NULL_TREE;
1684   return node;
1685 }
1686 #endif
1687
1688 static void
1689 java_lex_error (msg, forward)
1690      const char *msg ATTRIBUTE_UNUSED;
1691      int forward ATTRIBUTE_UNUSED;
1692 {
1693 #ifndef JC1_LITE
1694   ctxp->elc.line = ctxp->c_line->lineno;
1695   ctxp->elc.col = ctxp->c_line->char_col-1+forward;
1696
1697   /* Might be caught in the middle of some error report */
1698   ctxp->java_error_flag = 0;
1699   java_error (NULL);
1700   java_error (msg);
1701 #endif
1702 }
1703
1704 #ifndef JC1_LITE
1705 static int
1706 java_is_eol (fp, c)
1707   FILE *fp;
1708   int c;
1709 {
1710   int next;
1711   switch (c)
1712     {
1713     case '\r':
1714       next = getc (fp);
1715       if (next != '\n' && next != EOF)
1716         ungetc (next, fp);
1717       return 1;
1718     case '\n':
1719       return 1;
1720     default:
1721       return 0;
1722     }  
1723 }
1724 #endif
1725
1726 char *
1727 java_get_line_col (filename, line, col)
1728      const char *filename ATTRIBUTE_UNUSED;
1729      int line ATTRIBUTE_UNUSED, col ATTRIBUTE_UNUSED;
1730 {
1731 #ifdef JC1_LITE
1732   return 0;
1733 #else
1734   /* Dumb implementation. Doesn't try to cache or optimize things. */
1735   /* First line of the file is line 1, first column is 1 */
1736
1737   /* COL == -1 means, at the CR/LF in LINE */
1738   /* COL == -2 means, at the first non space char in LINE */
1739
1740   FILE *fp;
1741   int c, ccol, cline = 1;
1742   int current_line_col = 0;
1743   int first_non_space = 0;
1744   char *base;
1745
1746   if (!(fp = fopen (filename, "r")))
1747     fatal_io_error ("can't open %s", filename);
1748
1749   while (cline != line)
1750     {
1751       c = getc (fp);
1752       if (c == EOF)
1753         {
1754           static const char msg[] = "<<file too short - unexpected EOF>>";
1755           obstack_grow (&temporary_obstack, msg, sizeof(msg)-1);
1756           goto have_line;
1757         }
1758       if (java_is_eol (fp, c))
1759         cline++;
1760     }
1761
1762   /* Gather the chars of the current line in a buffer */
1763   for (;;)
1764     {
1765       c = getc (fp);
1766       if (c < 0 || java_is_eol (fp, c))
1767         break;
1768       if (!first_non_space && !JAVA_WHITE_SPACE_P (c))
1769         first_non_space = current_line_col;
1770       obstack_1grow (&temporary_obstack, c);
1771       current_line_col++;
1772     }
1773  have_line:
1774
1775   obstack_1grow (&temporary_obstack, '\n');
1776
1777   if (col == -1)
1778     {
1779       col = current_line_col;
1780       first_non_space = 0;
1781     }
1782   else if (col == -2)
1783     col = first_non_space;
1784   else
1785     first_non_space = 0;
1786
1787   /* Place the '^' a the right position */
1788   base = obstack_base (&temporary_obstack);
1789   for (ccol = 1; ccol <= col+3; ccol++)
1790     {
1791       /* Compute \t when reaching first_non_space */
1792       char c = (first_non_space ?
1793                 (base [ccol-1] == '\t' ? '\t' : ' ') : ' ');
1794       obstack_1grow (&temporary_obstack, c);
1795     }
1796   obstack_grow0 (&temporary_obstack, "^", 1);
1797
1798   fclose (fp);
1799   return obstack_finish (&temporary_obstack);
1800 #endif
1801 }
1802
1803 #ifndef JC1_LITE
1804 static int
1805 utf8_cmp (str, length, name)
1806      const unsigned char *str;
1807      int length;
1808      const char *name;
1809 {
1810   const unsigned char *limit = str + length;
1811   int i;
1812
1813   for (i = 0; name[i]; ++i)
1814     {
1815       int ch = UTF8_GET (str, limit);
1816       if (ch != name[i])
1817         return ch - name[i];
1818     }
1819
1820   return str == limit ? 0 : 1;
1821 }
1822
1823 /* A sorted list of all C++ keywords.  */
1824
1825 static const char *const cxx_keywords[] =
1826 {
1827   "_Complex",
1828   "__alignof",
1829   "__alignof__",
1830   "__asm",
1831   "__asm__",
1832   "__attribute",
1833   "__attribute__",
1834   "__builtin_va_arg",
1835   "__complex",
1836   "__complex__",
1837   "__const",
1838   "__const__",
1839   "__extension__",
1840   "__imag",
1841   "__imag__",
1842   "__inline",
1843   "__inline__",
1844   "__label__",
1845   "__null",
1846   "__real",
1847   "__real__",
1848   "__restrict",
1849   "__restrict__",
1850   "__signed",
1851   "__signed__",
1852   "__typeof",
1853   "__typeof__",
1854   "__volatile",
1855   "__volatile__",
1856   "asm",
1857   "and",
1858   "and_eq",
1859   "auto",
1860   "bitand",
1861   "bitor",
1862   "bool",
1863   "break",
1864   "case",
1865   "catch",
1866   "char",
1867   "class",
1868   "compl",
1869   "const",
1870   "const_cast",
1871   "continue",
1872   "default",
1873   "delete",
1874   "do",
1875   "double",
1876   "dynamic_cast",
1877   "else",
1878   "enum",
1879   "explicit",
1880   "export",
1881   "extern",
1882   "false",
1883   "float",
1884   "for",
1885   "friend",
1886   "goto",
1887   "if",
1888   "inline",
1889   "int",
1890   "long",
1891   "mutable",
1892   "namespace",
1893   "new",
1894   "not",
1895   "not_eq",
1896   "operator",
1897   "or",
1898   "or_eq",
1899   "private",
1900   "protected",
1901   "public",
1902   "register",
1903   "reinterpret_cast",
1904   "return",
1905   "short",
1906   "signed",
1907   "sizeof",
1908   "static",
1909   "static_cast",
1910   "struct",
1911   "switch",
1912   "template",
1913   "this",      
1914   "throw",
1915   "true",
1916   "try",
1917   "typedef",
1918   "typename",
1919   "typeid",
1920   "typeof",
1921   "union",
1922   "unsigned",
1923   "using",
1924   "virtual",
1925   "void",
1926   "volatile",
1927   "wchar_t",
1928   "while",
1929   "xor",
1930   "xor_eq"
1931 };
1932
1933 /* Return true if NAME is a C++ keyword.  */
1934
1935 int
1936 cxx_keyword_p (name, length)
1937      const char *name;
1938      int length;
1939 {
1940   int last = ARRAY_SIZE (cxx_keywords);
1941   int first = 0;
1942   int mid = (last + first) / 2;
1943   int old = -1;
1944
1945   for (mid = (last + first) / 2;
1946        mid != old;
1947        old = mid, mid = (last + first) / 2)
1948     {
1949       int kwl = strlen (cxx_keywords[mid]);
1950       int min_length = kwl > length ? length : kwl;
1951       int r = utf8_cmp (name, min_length, cxx_keywords[mid]);
1952
1953       if (r == 0)
1954         {
1955           int i;
1956           /* We've found a match if all the remaining characters are
1957              `$'.  */
1958           for (i = min_length; i < length && name[i] == '$'; ++i)
1959             ;
1960           if (i == length)
1961             return 1;
1962           r = 1;
1963         }
1964
1965       if (r < 0)
1966         last = mid;
1967       else
1968         first = mid;
1969     }
1970   return 0;
1971 }
1972 #endif /* JC1_LITE */