OSDN Git Service

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