OSDN Git Service

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