OSDN Git Service

Fri Jan 29 18:19:02 1999 Alexandre Petit-Bianco <apbianco@cygnus.com>
[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 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 characters
28 and returns a token for everything found but comments, white spaces
29 and line terminators. When necessary, it also fills the java_lval
30 (yylval) union. It's implemented to be called by a re-entrant parser
31 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 <stdio.h>
38 #include <string.h>
39 #include <strings.h>
40
41 #ifdef JAVA_LEX_DEBUG
42 #include <ctype.h>
43 #endif
44
45 #include "keyword.h"
46
47 #ifndef SEEK_SET
48 #include <unistd.h>
49 #endif
50
51 #ifndef JC1_LITE
52 extern struct obstack *expression_obstack;
53 #endif
54
55 /* Function declaration  */
56 static int java_lineterminator PROTO ((unicode_t));
57 static char *java_sprint_unicode PROTO ((struct java_line *, int));
58 static void java_unicode_2_utf8 PROTO ((unicode_t));
59 static void java_lex_error PROTO ((char *, int));
60 static int java_is_eol PROTO ((FILE *, int));
61 static void java_store_unicode PROTO ((struct java_line *, unicode_t, int));
62 static unicode_t java_parse_escape_sequence PROTO (());
63 static int java_letter_or_digit_p PROTO ((unicode_t));
64 static int java_parse_doc_section PROTO ((unicode_t));
65 static void java_parse_end_comment PROTO (());
66 static unicode_t java_get_unicode PROTO (());
67 static unicode_t java_read_unicode PROTO ((int, int *));
68 static void java_store_unicode PROTO ((struct java_line *, unicode_t, int));
69 static unicode_t java_read_char PROTO (());
70 static void java_allocate_new_line PROTO (());
71 static void java_unget_unicode PROTO (());
72 static unicode_t java_sneak_unicode PROTO (());
73
74 void
75 java_init_lex ()
76 {
77   int java_lang_imported = 0;
78
79 #ifndef JC1_LITE
80   if (!java_lang_id)
81     java_lang_id = get_identifier ("java.lang");
82
83   if (!java_lang_imported)
84     {
85       tree node = build_tree_list 
86         (build_expr_wfl (java_lang_id, NULL, 0, 0), NULL_TREE);
87       read_import_dir (TREE_PURPOSE (node));
88       TREE_CHAIN (node) = ctxp->import_demand_list;
89       ctxp->import_demand_list = node;
90       java_lang_imported = 1;
91     }
92
93   if (!wfl_operator)
94     wfl_operator = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0);
95   if (!label_id)
96     label_id = get_identifier ("$L");
97   if (!wfl_append) 
98     wfl_append = build_expr_wfl (get_identifier ("append"), NULL, 0, 0);
99   if (!wfl_string_buffer)
100     wfl_string_buffer = 
101       build_expr_wfl (get_identifier ("java.lang.StringBuffer"), NULL, 0, 0);
102   if (!wfl_to_string)
103     wfl_to_string = build_expr_wfl (get_identifier ("toString"), NULL, 0, 0);
104
105   ctxp->static_initialized = ctxp->non_static_initialized = 
106     ctxp->incomplete_class = NULL_TREE;
107   
108   bzero (ctxp->modifier_ctx, 11*sizeof (ctxp->modifier_ctx[0]));
109   bzero (current_jcf, sizeof (JCF));
110   ctxp->current_parsed_class = NULL;
111   ctxp->package = NULL_TREE;
112 #endif
113
114   ctxp->filename = input_filename;
115   ctxp->lineno = lineno = 0;
116   ctxp->p_line = NULL;
117   ctxp->c_line = NULL;
118   ctxp->unget_utf8_value = 0;
119   ctxp->minus_seen = 0;
120   ctxp->java_error_flag = 0;
121 }
122
123 static char *
124 java_sprint_unicode (line, i)
125     struct java_line *line;
126     int i;
127 {
128   static char buffer [10];
129   if (line->unicode_escape_p [i] || line->line [i] > 128)
130     sprintf (buffer, "\\u%04x", line->line [i]);
131   else
132     {
133       buffer [0] = line->line [i];
134       buffer [1] = '\0';
135     }
136   return buffer;
137 }
138
139 static unicode_t
140 java_sneak_unicode ()
141 {
142   return (ctxp->c_line->line [ctxp->c_line->current]);
143 }
144
145 static void
146 java_unget_unicode ()
147 {
148   if (!ctxp->c_line->current)
149     fatal ("can't unget unicode - java_unget_unicode");
150   ctxp->c_line->current--;
151   ctxp->c_line->char_col -= JAVA_COLUMN_DELTA (0);
152 }
153
154 void
155 java_allocate_new_line ()
156 {
157   unicode_t ahead = (ctxp->c_line ? ctxp->c_line->ahead[0] : '\0');
158   char ahead_escape_p = (ctxp->c_line ? 
159                          ctxp->c_line->unicode_escape_ahead_p : 0);
160
161   if (ctxp->c_line && !ctxp->c_line->white_space_only)
162     {
163       if (ctxp->p_line)
164         {
165           free (ctxp->p_line->unicode_escape_p);
166           free (ctxp->p_line->line);
167           free (ctxp->p_line);
168         }
169       ctxp->p_line = ctxp->c_line;
170       ctxp->c_line = NULL;              /* Reallocated */
171     }
172
173   if (!ctxp->c_line)
174     {
175       ctxp->c_line = (struct java_line *)xmalloc (sizeof (struct java_line));
176       ctxp->c_line->max = JAVA_LINE_MAX;
177       ctxp->c_line->line = (unicode_t *)xmalloc 
178         (sizeof (unicode_t)*ctxp->c_line->max);
179       ctxp->c_line->unicode_escape_p = 
180           (char *)xmalloc (sizeof (char)*ctxp->c_line->max);
181       ctxp->c_line->white_space_only = 0;
182     }
183
184   ctxp->c_line->line [0] = ctxp->c_line->size = 0;
185   ctxp->c_line->char_col = ctxp->c_line->current = 0;
186   if (ahead)
187     {
188       ctxp->c_line->line [ctxp->c_line->size] = ahead;
189       ctxp->c_line->unicode_escape_p [ctxp->c_line->size] = ahead_escape_p;
190       ctxp->c_line->size++;
191     }
192   ctxp->c_line->ahead [0] = 0;
193   ctxp->c_line->unicode_escape_ahead_p = 0;
194   ctxp->c_line->lineno = ++lineno;
195   ctxp->c_line->white_space_only = 1;
196 }
197
198 static unicode_t
199 java_read_char ()
200 {
201   int c;
202   int c1, c2;
203
204   if (ctxp->unget_utf8_value)
205     {
206       int to_return = ctxp->unget_utf8_value;
207       ctxp->unget_utf8_value = 0;
208       return (to_return);
209     }
210
211   c = GETC ();
212
213   if (c < 128)
214     return (unicode_t)c;
215   if (c == EOF)
216     return UEOF;
217   else
218     {
219       if ((c & 0xe0) == 0xc0)
220         {
221           c1 = GETC ();
222           if ((c1 & 0xc0) == 0x80)
223             return (unicode_t)(((c &0x1f) << 6) + (c1 & 0x3f));
224         }
225       else if ((c & 0xf0) == 0xe0)
226         {
227           c1 = GETC ();
228           if ((c1 & 0xc0) == 0x80)
229             {
230               c2 = GETC ();
231               if ((c2 & 0xc0) == 0x80)
232                 return (unicode_t)(((c & 0xf) << 12) + 
233                                    (( c1 & 0x3f) << 6) + (c2 & 0x3f));
234             }
235         }
236       java_lex_error ("Bad utf8 encoding", 0);
237     }
238   return 0;
239 }
240
241 static void
242 java_store_unicode (l, c, unicode_escape_p)
243     struct java_line *l;
244     unicode_t c;
245     int unicode_escape_p;
246 {
247   if (l->size == l->max)
248     {
249       l->max += JAVA_LINE_MAX;
250       l->line = (unicode_t *)realloc (l->line, sizeof (unicode_t)*l->max);
251       l->unicode_escape_p = (char *)realloc (l->unicode_escape_p, 
252                                              sizeof (char)*l->max);
253     }
254   l->line [l->size] = c;
255   l->unicode_escape_p [l->size++] = unicode_escape_p;
256 }
257
258 static unicode_t
259 java_read_unicode (term_context, unicode_escape_p)
260     int term_context;
261     int *unicode_escape_p;
262 {
263   unicode_t c;
264   long i, base;
265
266   c = java_read_char ();
267   *unicode_escape_p = 0;
268
269   if (c != '\\')
270     return ((term_context ? c : 
271              java_lineterminator (c) ? '\n' : (unicode_t)c));
272
273   /* Count the number of preceeding '\' */
274   for (base = ftell (finput), i = base-2; c == '\\';)
275     { 
276       fseek (finput, i--, SEEK_SET);
277       c = java_read_char ();    /* Will fail if reading utf8 stream. FIXME */
278     }
279   fseek (finput, base, SEEK_SET);
280   if ((base-i-3)%2 == 0)        /* If odd number of \ seen */
281     {
282       c = java_read_char ();
283       if (c == 'u')
284         {
285           unsigned short unicode = 0;
286           int shift = 12;
287           /* Next should be 4 hex digits, otherwise it's an error.
288              The hex value is converted into the unicode, pushed into
289              the Unicode stream.  */
290           for (shift = 12; shift >= 0; shift -= 4)
291             {
292               if ((c = java_read_char ()) == UEOF)
293                 return UEOF;
294               if (c >= '0' && c <= '9')
295                 unicode |= (unicode_t)((c-'0') << shift);
296               else if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
297                 unicode |= (unicode_t)((10+(c | 0x20)-'a') << shift);
298               else
299                   java_lex_error 
300                     ("Non hex digit in Unicode escape sequence", 0);
301             }
302           *unicode_escape_p = 1;
303           return (term_context ? unicode :
304                   (java_lineterminator (c) ? '\n' : unicode));
305         }
306       UNGETC (c);
307     }
308   return (unicode_t)'\\';
309 }
310
311 static unicode_t
312 java_get_unicode ()
313 {
314   /* It's time to read a line when... */
315   if (!ctxp->c_line || ctxp->c_line->current == ctxp->c_line->size)
316     {
317       unicode_t c;
318       java_allocate_new_line ();
319       if (ctxp->c_line->line[0] != '\n')
320         for (;;)
321           {
322             int unicode_escape_p;
323             c = java_read_unicode (0, &unicode_escape_p);
324             java_store_unicode (ctxp->c_line, c, unicode_escape_p);
325             if (ctxp->c_line->white_space_only 
326                 && !JAVA_WHITE_SPACE_P (c) && c!='\n')
327               ctxp->c_line->white_space_only = 0;
328             if ((c == '\n') || (c == UEOF))
329               break;
330           }
331     }
332   ctxp->c_line->char_col += JAVA_COLUMN_DELTA (0);
333   JAVA_LEX_CHAR (ctxp->c_line->line [ctxp->c_line->current]);
334   return ctxp->c_line->line [ctxp->c_line->current++];
335 }
336
337 static int
338 java_lineterminator (c)
339      unicode_t c;
340 {
341   int unicode_escape_p;
342   if (c == '\n')                /* CR */
343     {
344       if ((c = java_read_unicode (1, &unicode_escape_p)) != '\r')
345         {
346           ctxp->c_line->ahead [0] = c;
347           ctxp->c_line->unicode_escape_ahead_p = unicode_escape_p;
348         }
349       return 1;
350     }
351   else if (c == '\r')           /* LF */
352     {
353       if ((c = java_read_unicode (1, &unicode_escape_p)) != '\n')
354         {
355           ctxp->c_line->ahead [0] = c;
356           ctxp->c_line->unicode_escape_ahead_p = unicode_escape_p;
357         }
358       return 1;
359     }
360   else 
361     return 0;
362 }
363
364 /* Parse the end of a C style comment */
365 static void
366 java_parse_end_comment ()
367 {
368   unicode_t c;
369
370   for (c = java_get_unicode ();; c = java_get_unicode ())
371     {
372       switch (c)
373         {
374         case UEOF:
375           java_lex_error ("Comment not terminated at end of input", 0);
376         case '*':
377           switch (c = java_get_unicode ())
378             {
379             case UEOF:
380               java_lex_error ("Comment not terminated at end of input", 0);
381             case '/':
382               return;
383             case '*':   /* reparse only '*' */
384               java_unget_unicode ();
385             }
386         }
387     }
388 }
389
390 /* Parse the documentation section. Keywords must be at the beginning
391    of a documentation comment line (ignoring white space and any `*'
392    character). Parsed keyword(s): @DEPRECATED.  */
393
394 static int
395 java_parse_doc_section (c)
396      unicode_t c;
397 {
398   int valid_tag = 0, seen_star;
399
400   while (JAVA_WHITE_SPACE_P (c) || (c == '*') || c == '\n')
401     {
402       switch (c)
403         {
404         case '*':
405           seen_star = 1;
406           break;
407         case '\n': /* ULT */
408           valid_tag = 1;
409         default:
410           seen_star = 0;
411         }
412       c = java_get_unicode();
413     }
414   
415   if (c == UEOF)
416     java_lex_error ("Comment not terminated at end of input", 0);
417   
418   if (seen_star && (c == '/'))
419     return 1;                   /* Goto step1 in caller */
420
421   /* We're parsing @deprecated */
422   if (valid_tag && (c == '@'))
423     {
424       char tag [10];
425       int  tag_index = 0;
426
427       while (tag_index < 10 && c != UEOF && c != ' ' && c != '\n')
428         {
429           c = java_get_unicode ();
430           tag [tag_index++] = c;
431         }
432       
433       if (c == UEOF)
434         java_lex_error ("Comment not terminated at end of input", 0);
435       
436       java_unget_unicode ();
437       tag [tag_index] = '\0';
438
439       if (!strcmp (tag, "deprecated"))
440         ctxp->deprecated = 1;
441     }
442   return 0;
443 }
444
445 /* This function to be used only by JAVA_ID_CHAR_P (), otherwise it
446    will return a wrong result.  */
447 static int
448 java_letter_or_digit_p (c)
449      unicode_t c;
450 {
451   return _JAVA_LETTER_OR_DIGIT_P (c);
452 }
453
454 static unicode_t
455 java_parse_escape_sequence ()
456 {
457   unicode_t char_lit;
458   unicode_t c;
459
460   switch (c = java_get_unicode ())
461     {
462     case 'b':
463       return (unicode_t)0x8;
464     case 't':
465       return (unicode_t)0x9;
466     case 'n':
467       return (unicode_t)0xa;
468     case 'f':
469       return (unicode_t)0xc;
470     case 'r':
471       return (unicode_t)0xd;
472     case '"':
473       return (unicode_t)0x22;
474     case '\'':
475       return (unicode_t)0x27;
476     case '\\':
477       return (unicode_t)0x5c;
478     case '0': case '1': case '2': case '3': case '4':
479     case '5': case '6': case '7': case '8': case '9':
480       {
481         int octal_escape[3];
482         int octal_escape_index = 0;
483         
484         for (; octal_escape_index < 3 && RANGE (c, '0', '9');
485              c = java_get_unicode ())
486           octal_escape [octal_escape_index++] = c;
487
488         java_unget_unicode ();
489
490         if ((octal_escape_index == 3) && (octal_escape [0] > '3'))
491           {
492             java_lex_error ("Literal octal escape out of range", 0);
493             return JAVA_CHAR_ERROR;
494           }
495         else
496           {
497             int i, shift;
498             for (char_lit=0, i = 0, shift = 3*(octal_escape_index-1);
499                  i < octal_escape_index; i++, shift -= 3)
500               char_lit |= (octal_escape [i] - '0') << shift;
501
502             return (char_lit);
503           }
504         break;
505       }
506     case '\n':
507       return '\n';              /* ULT, caught latter as a specific error */
508     default:
509       java_lex_error ("Illegal character in escape sequence", 0);
510       return JAVA_CHAR_ERROR;
511     }
512 }
513
514 int
515 #ifdef JC1_LITE
516 yylex (java_lval)
517 #else
518 java_lex (java_lval)
519 #endif
520      YYSTYPE *java_lval;
521 {
522   unicode_t c, first_unicode;
523   int ascii_index, all_ascii;
524   char *string;
525
526   /* Translation of the Unicode escape in the raw stream of Unicode
527      characters. Takes care of line terminator.  */
528  step1:
529   /* Skip white spaces: SP, TAB and FF or ULT */ 
530   for (c = java_get_unicode ();
531        c == '\n' || JAVA_WHITE_SPACE_P (c); c = java_get_unicode ())
532     if (c == '\n')
533       {
534         ctxp->elc.line = ctxp->c_line->lineno;
535         ctxp->elc.col  = ctxp->c_line->char_col-2;
536       }
537
538   ctxp->elc.col = (ctxp->elc.col < 0 ? 0 : ctxp->elc.col);
539
540   if (c == 0x1a)                /* CTRL-Z */
541     {
542       if ((c = java_get_unicode ()) == UEOF)
543         return 0;               /* Ok here */
544       else
545         java_unget_unicode ();  /* Caught latter at the end the function */
546     }
547   /* Handle EOF here */
548   if (c == UEOF)        /* Should probably do something here... */
549     return 0;
550
551   /* Take care of eventual comments.  */
552   if (c == '/')
553     {
554       switch (c = java_get_unicode ())
555         {
556         case '/':
557           for (c = java_get_unicode ();;c = java_get_unicode ())
558             {
559               if (c == UEOF)
560                 java_lex_error ("Comment not terminated at end of input", 0);
561               if (c == '\n')    /* ULT */
562                 goto step1;
563             }
564           break;
565
566         case '*':
567           if ((c = java_get_unicode ()) == '*')
568             {
569               if ((c = java_get_unicode ()) == '/')
570                 goto step1;     /* Empy documentation comment  */
571               else if (java_parse_doc_section (c))
572                 goto step1;
573             }
574           else
575             java_unget_unicode ();
576
577           java_parse_end_comment ();
578           goto step1;
579           break;
580         default:
581           java_unget_unicode ();
582           c = '/';
583           break;
584         }
585     }
586
587   ctxp->elc.line = ctxp->c_line->lineno;
588   ctxp->elc.prev_col = ctxp->elc.col;
589   ctxp->elc.col = ctxp->c_line->char_col - JAVA_COLUMN_DELTA (-1);
590   if (ctxp->elc.col < 0)
591     fatal ("ctxp->elc.col < 0 - java_lex");
592
593   /* Numeric literals */
594   if (JAVA_ASCII_DIGIT (c) || (c == '.'))
595     {
596       /* This section of code is borrowed from gcc/c-lex.c  */
597 #define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
598       int parts[TOTAL_PARTS];
599       HOST_WIDE_INT high, low;
600       /* End borrowed section  */
601       char literal_token [256];
602       int  literal_index = 0, radix = 10, long_suffix = 0, overflow = 0, bytes;
603       int  i;
604       int  number_beginning = ctxp->c_line->current;
605       
606       /* We might have a . separator instead of a FP like .[0-9]* */
607       if (c == '.')
608         {
609           unicode_t peep = java_sneak_unicode ();
610
611           if (!JAVA_ASCII_DIGIT (peep))
612             {
613               JAVA_LEX_SEP('.');
614               BUILD_OPERATOR (DOT_TK);
615             }
616         }
617
618       for (i = 0; i < TOTAL_PARTS; i++)
619         parts [i] = 0;
620
621       if (c == '0')
622         {
623           c = java_get_unicode ();
624           if (c == 'x' || c == 'X')
625             {
626               radix = 16;
627               c = java_get_unicode ();
628             }
629           else if (JAVA_ASCII_DIGIT (c))
630             radix = 8;
631           else if (c == '.')
632             {
633               /* Push the '.' back and prepare for a FP parsing... */
634               java_unget_unicode ();
635               c = '0';
636             }
637           else
638             {
639               /* We have a zero literal: 0, 0{f,F}, 0{d,D} */
640               JAVA_LEX_LIT ("0", 10);
641               switch (c)
642                 {               
643                 case 'L': case 'l':
644                   SET_LVAL_NODE (long_zero_node);
645                   return (INT_LIT_TK);
646                 case 'f': case 'F':
647                   SET_LVAL_NODE (float_zero_node);
648                   return (FP_LIT_TK);
649                 case 'd': case 'D':
650                   SET_LVAL_NODE (double_zero_node);
651                   return (FP_LIT_TK);
652                 default:
653                   java_unget_unicode ();
654                   SET_LVAL_NODE (integer_zero_node);
655                   return (INT_LIT_TK);
656                 }
657             }
658         }
659       /* Parse the first part of the literal, until we find something
660          which is not a number.  */
661       while ((radix == 10 && JAVA_ASCII_DIGIT (c)) ||
662              (radix == 16 && JAVA_ASCII_HEXDIGIT (c)) ||
663              (radix == 8  && JAVA_ASCII_OCTDIGIT (c)))
664         {
665           /* We store in a string (in case it turns out to be a FP) and in
666              PARTS if we have to process a integer literal.  */
667           int numeric = (RANGE (c, '0', '9') ? c-'0' : 10 +(c|0x20)-'a');
668           int count;
669
670           literal_token [literal_index++] = c;
671           /* This section of code if borrowed from gcc/c-lex.c  */
672           for (count = 0; count < TOTAL_PARTS; count++)
673             {
674               parts[count] *= radix;
675               if (count)
676                 {
677                   parts[count]   += (parts[count-1] >> HOST_BITS_PER_CHAR);
678                   parts[count-1] &= (1 << HOST_BITS_PER_CHAR) - 1;
679                 }
680               else
681                 parts[0] += numeric;
682             }
683           if (parts [TOTAL_PARTS-1] != 0)
684             overflow = 1;
685           /* End borrowed section.  */
686           c = java_get_unicode ();
687         }
688
689       /* If we have something from the FP char set but not a digit, parse
690          a FP literal.  */
691       if (JAVA_ASCII_FPCHAR (c) && !JAVA_ASCII_DIGIT (c))
692         {
693           int stage = 0;
694           int seen_digit = (literal_index ? 1 : 0);
695           int seen_exponent = 0;
696           int fflag = 0;        /* 1 for {f,F}, 0 for {d,D}. FP literal are
697                                    double unless specified. */
698           if (radix != 10)
699             java_lex_error ("Can't express non-decimal FP literal", 0);
700
701           for (;;)
702             {
703               if (c == '.')
704                 {
705                   if (stage < 1)
706                     {
707                       stage = 1;
708                       literal_token [literal_index++ ] = c;
709                       c = java_get_unicode ();
710                     }
711                   else
712                     java_lex_error ("Invalid character in FP literal", 0);
713                 }
714
715               if (c == 'e' || c == 'E')
716                 {
717                   if (stage < 2)
718                     {
719                       /* {E,e} must have seen at list a digit */
720                       if (!seen_digit)
721                         java_lex_error ("Invalid FP literal", 0);
722                       seen_digit = 0;
723                       seen_exponent = 1;
724                       stage = 2;
725                       literal_token [literal_index++] = c;
726                       c = java_get_unicode ();
727                     }
728                   else
729                     java_lex_error ("Invalid character in FP literal", 0);
730                 }
731               if ( c == 'f' || c == 'F' || c == 'd' || c == 'D')
732                 {
733                   fflag = ((c == 'd') || (c == 'D')) ? 0 : 1;
734                   stage = 4;    /* So we fall through */
735                 }
736
737               if ((c=='-' || c =='+') && stage < 3)
738                 {
739                   stage = 3;
740                   literal_token [literal_index++] = c;
741                   c = java_get_unicode ();
742                 }
743
744               if ((stage == 0 && JAVA_ASCII_FPCHAR (c)) ||
745                   (stage == 1 && JAVA_ASCII_FPCHAR (c) && !(c == '.')) ||
746                   (stage == 2 && (JAVA_ASCII_DIGIT (c) || JAVA_FP_PM (c))) ||
747                   (stage == 3 && JAVA_ASCII_DIGIT (c)))
748                 {
749                   if (JAVA_ASCII_DIGIT (c))
750                     seen_digit = 1;
751                   literal_token [literal_index++ ] = c;
752                   c = java_get_unicode ();
753                 }
754               else
755                 {
756                   jmp_buf handler;
757                   REAL_VALUE_TYPE value;
758 #ifndef JC1_LITE
759                   tree type = (fflag ? FLOAT_TYPE_NODE : DOUBLE_TYPE_NODE);
760 #endif
761
762                   if (stage != 4) /* Don't push back fF/dD */
763                     java_unget_unicode ();
764                   
765                   /* An exponent (if any) must have seen a digit.  */
766                   if (seen_exponent && !seen_digit)
767                     java_lex_error ("Invalid FP literal", 0);
768
769                   literal_token [literal_index] = '\0';
770                   JAVA_LEX_LIT (literal_token, radix);
771
772                   if (setjmp (handler))
773                     {
774                       JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double"));
775                       value = DCONST0;
776                     }
777                   else
778                     {
779                       SET_FLOAT_HANDLER (handler);
780                       SET_REAL_VALUE_ATOF 
781                         (value, REAL_VALUE_ATOF (literal_token, 
782                                                  TYPE_MODE (type)));
783
784                       if (REAL_VALUE_ISINF (value))
785                         JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double"));
786
787                       if (REAL_VALUE_ISNAN (value))
788                         JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double"));
789
790                       SET_LVAL_NODE_TYPE (build_real (type, value), type);
791                       SET_FLOAT_HANDLER (NULL_PTR);
792                       return FP_LIT_TK;
793                     }
794                 }
795             }
796         } /* JAVA_ASCCI_FPCHAR (c) */
797
798       /* Here we get back to converting the integral literal.  */
799       if (c == 'L' || c == 'l')
800         long_suffix = 1;
801       else if (radix == 16 && JAVA_ASCII_LETTER (c))
802         java_lex_error ("Digit out of range in hexadecimal literal", 0);
803       else if (radix == 8  && JAVA_ASCII_DIGIT (c))
804         java_lex_error ("Digit out of range in octal literal", 0);
805       else if (radix == 16 && !literal_index)
806         java_lex_error ("No digit specified for hexadecimal literal", 0);
807       else
808         java_unget_unicode ();
809
810 #ifdef JAVA_LEX_DEBUG
811       literal_token [literal_index] = '\0'; /* So JAVA_LEX_LIT is safe. */
812       JAVA_LEX_LIT (literal_token, radix);
813 #endif
814       /* This section of code is borrowed from gcc/c-lex.c  */
815       if (!overflow)
816         {
817           bytes = GET_TYPE_PRECISION (long_type_node);
818           for (i = bytes; i < TOTAL_PARTS; i++)
819             if (parts [i])
820               {
821                 overflow = 1;
822                 break;
823               }
824         }
825       high = low = 0;
826       for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++)
827         {
828           high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT
829                                               / HOST_BITS_PER_CHAR)]
830                    << (i * HOST_BITS_PER_CHAR));
831           low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
832         }
833       /* End borrowed section.  */
834
835       /* Range checking */
836       if (long_suffix)
837         {
838           /* 9223372036854775808L is valid if operand of a '-'. Otherwise
839              9223372036854775807L is the biggest `long' literal that can be
840              expressed using a 10 radix. For other radixes, everything that
841              fits withing 64 bits is OK. */
842           int hb = (high >> 31);
843           if (overflow || (hb && low && radix == 10) ||  
844               (hb && high & 0x7fffffff && radix == 10) ||
845               (hb && !(high & 0x7fffffff) && !ctxp->minus_seen && radix == 10))
846             JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `long' literal");
847         }
848       else
849         {
850           /* 2147483648 is valid if operand of a '-'. Otherwise,
851              2147483647 is the biggest `int' literal that can be
852              expressed using a 10 radix. For other radixes, everything
853              that fits within 32 bits is OK.  As all literals are
854              signed, we sign extend here. */
855           int hb = (low >> 31) & 0x1;
856           if (overflow || high || (hb && low & 0x7fffffff && radix == 10) ||
857               (hb && !(low & 0x7fffffff) && !ctxp->minus_seen && radix == 10))
858             JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `int' literal");
859           high = -hb;
860         }
861       ctxp->minus_seen = 0;
862       SET_LVAL_NODE_TYPE (build_int_2 (low, high),
863                           (long_suffix ? long_type_node : int_type_node));
864       return INT_LIT_TK;
865     }
866
867   ctxp->minus_seen = 0;
868   /* Character literals */
869   if (c == '\'')
870     {
871       unicode_t char_lit;
872       if ((c = java_get_unicode ()) == '\\')
873         char_lit = java_parse_escape_sequence ();
874       else
875         char_lit = c;
876
877       c = java_get_unicode ();
878       
879       if ((c == '\n') || (c == UEOF))
880         java_lex_error ("Character literal not terminated at end of line", 0);
881       if (c != '\'')
882         java_lex_error ("Syntax error in character literal", 0);
883
884       if (c == JAVA_CHAR_ERROR)
885         char_lit = 0;           /* We silently convert it to zero */
886
887       JAVA_LEX_CHAR_LIT (char_lit);
888       SET_LVAL_NODE_TYPE (build_int_2 (char_lit, 0), char_type_node);
889       return CHAR_LIT_TK;
890     }
891
892   /* String literals */
893   if (c == '"')
894     {
895       int no_error;
896       char *string;
897
898       for (no_error = 1, c = java_get_unicode (); 
899            c != '"' && c != '\n'; c = java_get_unicode ())
900         {
901           if (c == '\\')
902             c = java_parse_escape_sequence ();
903           no_error &= (c != JAVA_CHAR_ERROR ? 1 : 0);
904           if (c)
905             java_unicode_2_utf8 (c);
906         }
907       if (c == '\n' || c == UEOF) /* ULT */
908         {
909           lineno--;             /* Refer to the line the terminator was seen */
910           java_lex_error ("String not terminated at end of line.", 0);
911           lineno++;
912         }
913
914       obstack_1grow (&temporary_obstack, '\0');
915       string = obstack_finish (&temporary_obstack);
916 #ifndef JC1_LITE
917       if (!no_error || (c != '"'))
918         java_lval->node = error_mark_node; /* Requires futher testing FIXME */
919       else
920         {
921           tree s = make_node (STRING_CST);
922           TREE_STRING_LENGTH (s) = strlen (string);
923           TREE_STRING_POINTER (s) = 
924             obstack_alloc (expression_obstack, TREE_STRING_LENGTH (s)+1);
925           strcpy (TREE_STRING_POINTER (s), string);
926           java_lval->node = s;
927         }
928 #endif
929       return STRING_LIT_TK;
930     }
931
932   /* Separator */
933   switch (c)
934     {
935     case '(':
936       JAVA_LEX_SEP (c);
937       BUILD_OPERATOR (OP_TK);
938     case ')':
939       JAVA_LEX_SEP (c);
940       return CP_TK;
941     case '{':
942       JAVA_LEX_SEP (c);
943       if (ctxp->ccb_indent == 1)
944         ctxp->first_ccb_indent1 = lineno;
945       ctxp->ccb_indent++;
946       BUILD_OPERATOR (OCB_TK);
947     case '}':
948       JAVA_LEX_SEP (c);
949       ctxp->ccb_indent--;
950       if (ctxp->ccb_indent == 1)
951         ctxp->last_ccb_indent1 = lineno;
952       return CCB_TK;
953     case '[':
954       JAVA_LEX_SEP (c);
955       BUILD_OPERATOR (OSB_TK);
956     case ']':
957       JAVA_LEX_SEP (c);
958       return CSB_TK;
959     case ';':
960       JAVA_LEX_SEP (c);
961       return SC_TK;
962     case ',':
963       JAVA_LEX_SEP (c);
964       return C_TK;
965     case '.':
966       JAVA_LEX_SEP (c);
967       BUILD_OPERATOR (DOT_TK);
968       /*      return DOT_TK; */
969     }
970
971   /* Operators */
972   switch (c)
973     {
974     case '=':
975       if ((c = java_get_unicode ()) == '=')
976         {
977           BUILD_OPERATOR (EQ_TK);
978         }
979       else
980         {
981           /* Equals is used in two different locations. In the 
982              variable_declarator: rule, it has to be seen as '=' as opposed
983              to being seen as an ordinary assignment operator in
984              assignment_operators: rule.  */
985           java_unget_unicode ();
986           BUILD_OPERATOR (ASSIGN_TK);
987         }
988       
989     case '>':
990       switch ((c = java_get_unicode ()))
991         {
992         case '=':
993           BUILD_OPERATOR (GTE_TK);
994         case '>':
995           switch ((c = java_get_unicode ()))
996             {
997             case '>':
998               if ((c = java_get_unicode ()) == '=')
999                 {
1000                   BUILD_OPERATOR2 (ZRS_ASSIGN_TK);
1001                 }
1002               else
1003                 {
1004                   java_unget_unicode ();
1005                   BUILD_OPERATOR (ZRS_TK);
1006                 }
1007             case '=':
1008               BUILD_OPERATOR2 (SRS_ASSIGN_TK);
1009             default:
1010               java_unget_unicode ();
1011               BUILD_OPERATOR (SRS_TK);
1012             }
1013         default:
1014           java_unget_unicode ();
1015           BUILD_OPERATOR (GT_TK);
1016         }
1017         
1018     case '<':
1019       switch ((c = java_get_unicode ()))
1020         {
1021         case '=':
1022           BUILD_OPERATOR (LTE_TK);
1023         case '<':
1024           if ((c = java_get_unicode ()) == '=')
1025             {
1026               BUILD_OPERATOR2 (LS_ASSIGN_TK);
1027             }
1028           else
1029             {
1030               java_unget_unicode ();
1031               BUILD_OPERATOR (LS_TK);
1032             }
1033         default:
1034           java_unget_unicode ();
1035           BUILD_OPERATOR (LT_TK);
1036         }
1037
1038     case '&':
1039       switch ((c = java_get_unicode ()))
1040         {
1041         case '&':
1042           BUILD_OPERATOR (BOOL_AND_TK);
1043         case '=':
1044           BUILD_OPERATOR2 (AND_ASSIGN_TK);
1045         default:
1046           java_unget_unicode ();
1047           BUILD_OPERATOR (AND_TK);
1048         }
1049
1050     case '|':
1051       switch ((c = java_get_unicode ()))
1052         {
1053         case '|':
1054           BUILD_OPERATOR (BOOL_OR_TK);
1055         case '=':
1056           BUILD_OPERATOR2 (OR_ASSIGN_TK);
1057         default:
1058           java_unget_unicode ();
1059           BUILD_OPERATOR (OR_TK);
1060         }
1061
1062     case '+':
1063       switch ((c = java_get_unicode ()))
1064         {
1065         case '+':
1066           BUILD_OPERATOR (INCR_TK);
1067         case '=':
1068           BUILD_OPERATOR2 (PLUS_ASSIGN_TK);
1069         default:
1070           java_unget_unicode ();
1071           BUILD_OPERATOR (PLUS_TK);
1072         }
1073
1074     case '-':
1075       switch ((c = java_get_unicode ()))
1076         {
1077         case '-':
1078           BUILD_OPERATOR (DECR_TK);
1079         case '=':
1080           BUILD_OPERATOR2 (MINUS_ASSIGN_TK);
1081         default:
1082           java_unget_unicode ();
1083           ctxp->minus_seen = 1;
1084           BUILD_OPERATOR (MINUS_TK);
1085         }
1086
1087     case '*':
1088       if ((c = java_get_unicode ()) == '=')
1089         {
1090           BUILD_OPERATOR2 (MULT_ASSIGN_TK);
1091         }
1092       else
1093         {
1094           java_unget_unicode ();
1095           BUILD_OPERATOR (MULT_TK);
1096         }
1097
1098     case '/':
1099       if ((c = java_get_unicode ()) == '=')
1100         {
1101           BUILD_OPERATOR2 (DIV_ASSIGN_TK);
1102         }
1103       else
1104         {
1105           java_unget_unicode ();
1106           BUILD_OPERATOR (DIV_TK);
1107         }
1108
1109     case '^':
1110       if ((c = java_get_unicode ()) == '=')
1111         {
1112           BUILD_OPERATOR2 (XOR_ASSIGN_TK);
1113         }
1114       else
1115         {
1116           java_unget_unicode ();
1117           BUILD_OPERATOR (XOR_TK);
1118         }
1119
1120     case '%':
1121       if ((c = java_get_unicode ()) == '=')
1122         {
1123           BUILD_OPERATOR2 (REM_ASSIGN_TK);
1124         }
1125       else
1126         {
1127           java_unget_unicode ();
1128           BUILD_OPERATOR (REM_TK);
1129         }
1130
1131     case '!':
1132       if ((c = java_get_unicode()) == '=')
1133         {
1134           BUILD_OPERATOR (NEQ_TK);
1135         }
1136       else
1137         {
1138           java_unget_unicode ();
1139           BUILD_OPERATOR (NEG_TK);
1140         }
1141           
1142     case '?':
1143       JAVA_LEX_OP ("?");
1144       BUILD_OPERATOR (REL_QM_TK);
1145     case ':':
1146       JAVA_LEX_OP (":");
1147       BUILD_OPERATOR (REL_CL_TK);
1148     case '~':
1149       BUILD_OPERATOR (NOT_TK);
1150     }
1151   
1152   /* Keyword, boolean literal or null literal */
1153   for (first_unicode = c, all_ascii = 1, ascii_index = 0; 
1154        JAVA_ID_CHAR_P (c); c = java_get_unicode ())
1155     {
1156       java_unicode_2_utf8 (c);
1157       if (all_ascii && c >= 128)
1158         all_ascii = 0;
1159       ascii_index++;
1160     }
1161
1162   obstack_1grow (&temporary_obstack, '\0');
1163   string = obstack_finish (&temporary_obstack);
1164   java_unget_unicode ();
1165
1166   /* If we have something all ascii, we consider a keyword, a boolean
1167      literal, a null literal or an all ASCII identifier.  Otherwise,
1168      this is an identifier (possibly not respecting formation rule).  */
1169   if (all_ascii)
1170     {
1171       struct java_keyword *kw;
1172       if ((kw=java_keyword (string, ascii_index)))
1173         {
1174           JAVA_LEX_KW (string);
1175           switch (kw->token)
1176             {
1177             case PUBLIC_TK:       case PROTECTED_TK: case STATIC_TK:
1178             case ABSTRACT_TK:     case FINAL_TK:     case NATIVE_TK:
1179             case SYNCHRONIZED_TK: case TRANSIENT_TK: case VOLATILE_TK:
1180             case PRIVATE_TK:
1181               SET_MODIFIER_CTX (kw->token);
1182               return MODIFIER_TK;
1183             case FLOAT_TK:
1184               SET_LVAL_NODE (float_type_node);
1185               return FP_TK;
1186             case DOUBLE_TK:
1187               SET_LVAL_NODE (double_type_node);
1188               return FP_TK;
1189             case BOOLEAN_TK:
1190               SET_LVAL_NODE (boolean_type_node);
1191               return BOOLEAN_TK;
1192             case BYTE_TK:
1193               SET_LVAL_NODE (byte_type_node);
1194               return INTEGRAL_TK;
1195             case SHORT_TK:
1196               SET_LVAL_NODE (short_type_node);
1197               return INTEGRAL_TK;
1198             case INT_TK:
1199               SET_LVAL_NODE (int_type_node);
1200               return INTEGRAL_TK;
1201             case LONG_TK:
1202               SET_LVAL_NODE (long_type_node);
1203               return INTEGRAL_TK;
1204             case CHAR_TK:
1205               SET_LVAL_NODE (char_type_node);
1206               return INTEGRAL_TK;
1207
1208               /* Keyword based literals */
1209             case TRUE_TK:
1210             case FALSE_TK:
1211               SET_LVAL_NODE ((kw->token == TRUE_TK ? 
1212                               boolean_true_node : boolean_false_node));
1213               return BOOL_LIT_TK;
1214             case NULL_TK:
1215               SET_LVAL_NODE (null_pointer_node);
1216               return NULL_TK;
1217
1218               /* Some keyword we want to retain information on the location
1219                  they where found */
1220             case CASE_TK:
1221             case DEFAULT_TK:
1222             case SUPER_TK:
1223             case THIS_TK:
1224             case RETURN_TK:
1225             case BREAK_TK:
1226             case CONTINUE_TK:
1227             case TRY_TK:
1228             case CATCH_TK:
1229             case THROW_TK:
1230             case INSTANCEOF_TK:
1231               BUILD_OPERATOR (kw->token);
1232
1233             default:
1234               return kw->token;
1235             }
1236         }
1237     }
1238   
1239   /* We may have and ID here */
1240   if (JAVA_ID_CHAR_P(first_unicode) && !JAVA_DIGIT_P (first_unicode))
1241     {
1242       JAVA_LEX_ID (string);
1243       java_lval->node = BUILD_ID_WFL (GET_IDENTIFIER (string));
1244       return ID_TK;
1245     }
1246
1247   /* Everything else is an invalid character in the input */
1248   {
1249     char lex_error_buffer [128];
1250     sprintf (lex_error_buffer, "Invalid character '%s' in input", 
1251              java_sprint_unicode (ctxp->c_line, ctxp->c_line->current));
1252     java_lex_error (lex_error_buffer, 1);
1253   }
1254   return 0;
1255 }
1256
1257 static void
1258 java_unicode_2_utf8 (unicode)
1259     unicode_t unicode;
1260 {
1261   if (RANGE (unicode, 0x01, 0x7f))
1262     obstack_1grow (&temporary_obstack, (char)unicode);
1263   else if (RANGE (unicode, 0x80, 0x7ff) || unicode == 0)
1264     {
1265       obstack_1grow (&temporary_obstack,
1266                      (unsigned char)(0xc0 | ((0x7c0 & unicode) >> 6)));
1267       obstack_1grow (&temporary_obstack,
1268                      (unsigned char)(0x80 | (unicode & 0x3f)));
1269     }
1270   else                          /* Range 0x800-0xffff */
1271     {
1272       obstack_1grow (&temporary_obstack,
1273                      (unsigned char)(0xe0 | (unicode & 0xf000) >> 12));
1274       obstack_1grow (&temporary_obstack,
1275                      (unsigned char)(0x80 | (unicode & 0x0fc0) >> 6));
1276       obstack_1grow (&temporary_obstack,
1277                      (unsigned char)(0x80 | (unicode & 0x003f)));
1278     }
1279 }
1280
1281 #ifndef JC1_LITE
1282 static tree
1283 build_wfl_node (node)
1284      tree node;
1285 {
1286   return build_expr_wfl (node, ctxp->filename, ctxp->elc.line, ctxp->elc.col);
1287 }
1288 #endif
1289
1290 static void
1291 java_lex_error (msg, forward)
1292      char *msg;
1293      int forward;
1294 {
1295 #ifndef JC1_LITE
1296   ctxp->elc.line = ctxp->c_line->lineno;
1297   ctxp->elc.col = ctxp->c_line->char_col-1+forward;
1298
1299   /* Might be caught in the middle of some error report */
1300   ctxp->java_error_flag = 0;
1301   java_error (NULL);
1302   java_error (msg);
1303 #endif
1304 }
1305
1306 static int
1307 java_is_eol (fp, c)
1308   FILE *fp;
1309   int c;
1310 {
1311   int next;
1312   switch (c)
1313     {
1314     case '\n':
1315       next = getc (fp);
1316       if (next != '\r' && next != EOF)
1317         ungetc (next, fp);
1318       return 1;
1319     case '\r':
1320       return 1;
1321     default:
1322       return 0;
1323     }  
1324 }
1325
1326 char *
1327 java_get_line_col (filename, line, col)
1328      char *filename;
1329      int line, col;
1330 {
1331 #ifdef JC1_LITE
1332   return 0;
1333 #else
1334   /* Dumb implementation. Doesn't try to cache or optimize things. */
1335   /* First line of the file is line 1, first column is 1 */
1336
1337   /* COL == -1 means, at the CR/LF in LINE */
1338   /* COL == -2 means, at the first non space char in LINE */
1339
1340   FILE *fp;
1341   int c, ccol, cline = 1;
1342   int current_line_col = 0;
1343   int first_non_space = 0;
1344   char *base;
1345
1346   if (!(fp = fopen (filename, "r")))
1347     fatal ("Can't open file - java_display_line_col");
1348
1349   while (cline != line)
1350     {
1351       c = getc (fp);
1352       if (c < 0)
1353         {
1354           static char msg[] = "<<file too short - unexpected EOF>>";
1355           obstack_grow (&temporary_obstack, msg, sizeof(msg)-1);
1356           goto have_line;
1357         }
1358       if (java_is_eol (fp, c))
1359         cline++;
1360     }
1361
1362   /* Gather the chars of the current line in a buffer */
1363   for (;;)
1364     {
1365       c = getc (fp);
1366       if (c < 0 || java_is_eol (fp, c))
1367         break;
1368       if (!first_non_space && !JAVA_WHITE_SPACE_P (c))
1369         first_non_space = current_line_col;
1370       obstack_1grow (&temporary_obstack, c);
1371       current_line_col++;
1372     }
1373  have_line:
1374
1375   obstack_1grow (&temporary_obstack, '\n');
1376
1377   if (col == -1)
1378     {
1379       col = current_line_col;
1380       first_non_space = 0;
1381     }
1382   else if (col == -2)
1383     col = first_non_space;
1384   else
1385     first_non_space = 0;
1386
1387   /* Place the '^' a the right position */
1388   base = obstack_base (&temporary_obstack);
1389   for (ccol = 1; ccol <= col; ccol++)
1390     {
1391       /* Compute \t when reaching first_non_space */
1392       char c = (first_non_space ?
1393                 (base [ccol-1] == '\t' ? '\t' : ' ') : ' ');
1394       obstack_1grow (&temporary_obstack, c);
1395     }
1396   obstack_grow0 (&temporary_obstack, "^", 1);
1397
1398   fclose (fp);
1399   return obstack_finish (&temporary_obstack);
1400 #endif
1401 }