OSDN Git Service

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