* c-decl.c (grokdeclarator): Use ISO word.
[official-gcc.git] / gcc / f / lex.c
blobd0aa829dc775b5a87442a97cf463aba5ba997baa
1 /* Implementation of Fortran lexer
2 Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
3 Contributed by James Craig Burley.
5 This file is part of GNU Fortran.
7 GNU Fortran 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.
12 GNU Fortran 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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Fortran; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
22 #include "proj.h"
23 #include "top.h"
24 #include "bad.h"
25 #include "com.h"
26 #include "lex.h"
27 #include "malloc.h"
28 #include "src.h"
29 #include "debug.h"
30 #include "flags.h"
31 #include "input.h"
32 #include "toplev.h"
33 #include "output.h"
34 #include "ggc.h"
36 static void ffelex_append_to_token_ (char c);
37 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
38 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
39 ffewhereColumnNumber cn0);
40 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
41 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
42 ffewhereColumnNumber cn1);
43 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
44 ffewhereColumnNumber cn0);
45 static void ffelex_finish_statement_ (void);
46 static int ffelex_get_directive_line_ (char **text, FILE *finput);
47 static int ffelex_hash_ (FILE *f);
48 static ffewhereColumnNumber ffelex_image_char_ (int c,
49 ffewhereColumnNumber col);
50 static void ffelex_include_ (void);
51 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
52 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
53 static void ffelex_next_line_ (void);
54 static void ffelex_prepare_eos_ (void);
55 static void ffelex_send_token_ (void);
56 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
57 static ffelexToken ffelex_token_new_ (void);
59 /* Pertaining to the geometry of the input file. */
61 /* Initial size for card image to be allocated. */
62 #define FFELEX_columnINITIAL_SIZE_ 255
64 /* The card image itself, which grows as source lines get longer. It
65 has room for ffelex_card_size_ + 8 characters, and the length of the
66 current image is ffelex_card_length_. (The + 8 characters are made
67 available for easy handling of tabs and such.) */
68 static char *ffelex_card_image_;
69 static ffewhereColumnNumber ffelex_card_size_;
70 static ffewhereColumnNumber ffelex_card_length_;
72 /* Max width for free-form lines (ISO F90). */
73 #define FFELEX_FREE_MAX_COLUMNS_ 132
75 /* True if we saw a tab on the current line, as this (currently) means
76 the line is therefore treated as though final_nontab_column_ were
77 infinite. */
78 static bool ffelex_saw_tab_;
80 /* TRUE if current line is known to be erroneous, so don't bother
81 expanding room for it just to display it. */
82 static bool ffelex_bad_line_ = FALSE;
84 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
85 static ffewhereColumnNumber ffelex_final_nontab_column_;
87 /* Array for quickly deciding what kind of line the current card has,
88 based on its first character. */
89 static ffelexType ffelex_first_char_[256];
91 /* Pertaining to file management. */
93 /* The wf argument of the most recent active ffelex_file_(fixed,free)
94 function. */
95 static ffewhereFile ffelex_current_wf_;
97 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
98 can be called). */
99 static bool ffelex_permit_include_;
101 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
102 called). */
103 static bool ffelex_set_include_;
105 /* Information on the pending INCLUDE file. */
106 static FILE *ffelex_include_file_;
107 static bool ffelex_include_free_form_;
108 static ffewhereFile ffelex_include_wherefile_;
110 /* Current master line count. */
111 static ffewhereLineNumber ffelex_linecount_current_;
112 /* Next master line count. */
113 static ffewhereLineNumber ffelex_linecount_next_;
115 /* ffewhere info on the latest (currently active) line read from the
116 active source file. */
117 static ffewhereLine ffelex_current_wl_;
118 static ffewhereColumn ffelex_current_wc_;
120 /* Pertaining to tokens in general. */
122 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
123 token. */
124 #define FFELEX_columnTOKEN_SIZE_ 63
125 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
126 #error "token size too small!"
127 #endif
129 /* Current token being lexed. */
130 static ffelexToken ffelex_token_;
132 /* Handler for current token. */
133 static ffelexHandler ffelex_handler_;
135 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
136 static bool ffelex_names_;
138 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
139 static bool ffelex_names_pure_;
141 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
142 numbers. */
143 static bool ffelex_hexnum_;
145 /* For ffelex_swallow_tokens(). */
146 static ffelexHandler ffelex_eos_handler_;
148 /* Number of tokens sent since last EOS or beginning of input file
149 (include INCLUDEd files). */
150 static unsigned long int ffelex_number_of_tokens_;
152 /* Number of labels sent (as NUMBER tokens) since last reset of
153 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
154 (Fixed-form source only.) */
155 static unsigned long int ffelex_label_tokens_;
157 /* Metering for token management, to catch token-memory leaks. */
158 static long int ffelex_total_tokens_ = 0;
159 static long int ffelex_old_total_tokens_ = 1;
160 static long int ffelex_token_nextid_ = 0;
162 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
164 /* >0 if a Hollerith constant of that length might be in mid-lex, used
165 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
166 mode (see ffelex_raw_mode_). */
167 static long int ffelex_expecting_hollerith_;
169 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
170 -2: Possible closing apostrophe/quote seen in CHARACTER.
171 -1: Lexing CHARACTER.
172 0: Not lexing CHARACTER or HOLLERITH.
173 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
174 static long int ffelex_raw_mode_;
176 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
177 static char ffelex_raw_char_;
179 /* TRUE when backslash processing had to use most recent character
180 to finish its state engine, but that character is not part of
181 the backslash sequence, so must be reconsidered as a "normal"
182 character in CHARACTER/HOLLERITH lexing. */
183 static bool ffelex_backslash_reconsider_ = FALSE;
185 /* Characters preread before lexing happened (might include EOF). */
186 static int *ffelex_kludge_chars_ = NULL;
188 /* Doing the kludge processing, so not initialized yet. */
189 static bool ffelex_kludge_flag_ = FALSE;
191 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
192 static ffewhereLine ffelex_raw_where_line_;
193 static ffewhereColumn ffelex_raw_where_col_;
196 /* Call this to append another character to the current token. If it isn't
197 currently big enough for it, it will be enlarged. The current token
198 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
200 static void
201 ffelex_append_to_token_ (char c)
203 if (ffelex_token_->text == NULL)
205 ffelex_token_->text
206 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
207 FFELEX_columnTOKEN_SIZE_ + 1);
208 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
209 ffelex_token_->length = 0;
211 else if (ffelex_token_->length >= ffelex_token_->size)
213 ffelex_token_->text
214 = malloc_resize_ksr (malloc_pool_image (),
215 ffelex_token_->text,
216 (ffelex_token_->size << 1) + 1,
217 ffelex_token_->size + 1);
218 ffelex_token_->size <<= 1;
219 assert (ffelex_token_->length < ffelex_token_->size);
221 #ifdef MAP_CHARACTER
222 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
223 please contact fortran@gnu.org if you wish to fund work to
224 port g77 to non-ASCII machines.
225 #endif
226 ffelex_token_->text[ffelex_token_->length++] = c;
229 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
230 being lexed. */
232 static int
233 ffelex_backslash_ (int c, ffewhereColumnNumber col)
235 static int state = 0;
236 static unsigned int count;
237 static int code;
238 static unsigned int firstdig = 0;
239 static int nonnull;
240 static ffewhereLineNumber line;
241 static ffewhereColumnNumber column;
243 /* See gcc/c-lex.c readescape() for a straightforward version
244 of this state engine for handling backslashes in character/
245 hollerith constants. */
247 #define wide_flag 0
248 #define warn_traditional 0
249 #define flag_traditional 0
251 switch (state)
253 case 0:
254 if ((c == '\\')
255 && (ffelex_raw_mode_ != 0)
256 && ffe_is_backslash ())
258 state = 1;
259 column = col + 1;
260 line = ffelex_linecount_current_;
261 return EOF;
263 return c;
265 case 1:
266 state = 0; /* Assume simple case. */
267 switch (c)
269 case 'x':
270 if (warn_traditional)
272 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
273 FFEBAD_severityWARNING);
274 ffelex_bad_here_ (0, line, column);
275 ffebad_finish ();
278 if (flag_traditional)
279 return c;
281 code = 0;
282 count = 0;
283 nonnull = 0;
284 state = 2;
285 return EOF;
287 case '0': case '1': case '2': case '3': case '4':
288 case '5': case '6': case '7':
289 code = c - '0';
290 count = 1;
291 state = 3;
292 return EOF;
294 case '\\': case '\'': case '"':
295 return c;
297 #if 0 /* Inappropriate for Fortran. */
298 case '\n':
299 ffelex_next_line_ ();
300 *ignore_ptr = 1;
301 return 0;
302 #endif
304 case 'n':
305 return TARGET_NEWLINE;
307 case 't':
308 return TARGET_TAB;
310 case 'r':
311 return TARGET_CR;
313 case 'f':
314 return TARGET_FF;
316 case 'b':
317 return TARGET_BS;
319 case 'a':
320 if (warn_traditional)
322 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
323 FFEBAD_severityWARNING);
324 ffelex_bad_here_ (0, line, column);
325 ffebad_finish ();
328 if (flag_traditional)
329 return c;
330 return TARGET_BELL;
332 case 'v':
333 #if 0 /* Vertical tab is present in common usage compilers. */
334 if (flag_traditional)
335 return c;
336 #endif
337 return TARGET_VT;
339 case 'e':
340 case 'E':
341 case '(':
342 case '{':
343 case '[':
344 case '%':
345 if (pedantic)
347 char m[2];
349 m[0] = c;
350 m[1] = '\0';
351 ffebad_start_msg_lex ("Non-ISO-C-standard escape sequence `\\%A' at %0",
352 FFEBAD_severityPEDANTIC);
353 ffelex_bad_here_ (0, line, column);
354 ffebad_string (m);
355 ffebad_finish ();
357 return (c == 'E' || c == 'e') ? 033 : c;
359 case '?':
360 return c;
362 default:
363 if (c >= 040 && c < 0177)
365 char m[2];
367 m[0] = c;
368 m[1] = '\0';
369 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
370 FFEBAD_severityPEDANTIC);
371 ffelex_bad_here_ (0, line, column);
372 ffebad_string (m);
373 ffebad_finish ();
375 else if (c == EOF)
377 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
378 FFEBAD_severityPEDANTIC);
379 ffelex_bad_here_ (0, line, column);
380 ffebad_finish ();
382 else
384 char m[20];
386 sprintf (&m[0], "%x", c);
387 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
388 FFEBAD_severityPEDANTIC);
389 ffelex_bad_here_ (0, line, column);
390 ffebad_string (m);
391 ffebad_finish ();
394 return c;
396 case 2:
397 if (ISXDIGIT (c))
399 code *= 16;
400 if (c >= 'a' && c <= 'f')
401 code += c - 'a' + 10;
402 if (c >= 'A' && c <= 'F')
403 code += c - 'A' + 10;
404 if (ISDIGIT (c))
405 code += c - '0';
406 if (code != 0 || count != 0)
408 if (count == 0)
409 firstdig = code;
410 count++;
412 nonnull = 1;
413 return EOF;
416 state = 0;
418 if (! nonnull)
420 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
421 FFEBAD_severityFATAL);
422 ffelex_bad_here_ (0, line, column);
423 ffebad_finish ();
425 else if (count == 0)
426 /* Digits are all 0's. Ok. */
428 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
429 || (count > 1
430 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
431 <= (int) firstdig)))
433 ffebad_start_msg_lex ("Hex escape at %0 out of range",
434 FFEBAD_severityPEDANTIC);
435 ffelex_bad_here_ (0, line, column);
436 ffebad_finish ();
438 break;
440 case 3:
441 if ((c <= '7') && (c >= '0') && (count++ < 3))
443 code = (code * 8) + (c - '0');
444 return EOF;
446 state = 0;
447 break;
449 default:
450 assert ("bad backslash state" == NULL);
451 abort ();
454 /* Come here when code has a built character, and c is the next
455 character that might (or might not) be the next one in the constant. */
457 /* Don't bother doing this check for each character going into
458 CHARACTER or HOLLERITH constants, just the escaped-value ones.
459 gcc apparently checks every single character, which seems
460 like it'd be kinda slow and not worth doing anyway. */
462 if (!wide_flag
463 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
464 && code >= (1 << TYPE_PRECISION (char_type_node)))
466 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
467 FFEBAD_severityFATAL);
468 ffelex_bad_here_ (0, line, column);
469 ffebad_finish ();
472 if (c == EOF)
474 /* Known end of constant, just append this character. */
475 ffelex_append_to_token_ (code);
476 if (ffelex_raw_mode_ > 0)
477 --ffelex_raw_mode_;
478 return EOF;
481 /* Have two characters to handle. Do the first, then leave it to the
482 caller to detect anything special about the second. */
484 ffelex_append_to_token_ (code);
485 if (ffelex_raw_mode_ > 0)
486 --ffelex_raw_mode_;
487 ffelex_backslash_reconsider_ = TRUE;
488 return c;
491 /* ffelex_bad_1_ -- Issue diagnostic with one source point
493 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
495 Creates ffewhere line and column objects for the source point, sends them
496 along with the error code to ffebad, then kills the line and column
497 objects before returning. */
499 static void
500 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
502 ffewhereLine wl0;
503 ffewhereColumn wc0;
505 wl0 = ffewhere_line_new (ln0);
506 wc0 = ffewhere_column_new (cn0);
507 ffebad_start_lex (errnum);
508 ffebad_here (0, wl0, wc0);
509 ffebad_finish ();
510 ffewhere_line_kill (wl0);
511 ffewhere_column_kill (wc0);
514 /* ffelex_bad_2_ -- Issue diagnostic with two source points
516 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
517 otherline,othercolumn);
519 Creates ffewhere line and column objects for the source points, sends them
520 along with the error code to ffebad, then kills the line and column
521 objects before returning. */
523 static void
524 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
525 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
527 ffewhereLine wl0, wl1;
528 ffewhereColumn wc0, wc1;
530 wl0 = ffewhere_line_new (ln0);
531 wc0 = ffewhere_column_new (cn0);
532 wl1 = ffewhere_line_new (ln1);
533 wc1 = ffewhere_column_new (cn1);
534 ffebad_start_lex (errnum);
535 ffebad_here (0, wl0, wc0);
536 ffebad_here (1, wl1, wc1);
537 ffebad_finish ();
538 ffewhere_line_kill (wl0);
539 ffewhere_column_kill (wc0);
540 ffewhere_line_kill (wl1);
541 ffewhere_column_kill (wc1);
544 static void
545 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
546 ffewhereColumnNumber cn0)
548 ffewhereLine wl0;
549 ffewhereColumn wc0;
551 wl0 = ffewhere_line_new (ln0);
552 wc0 = ffewhere_column_new (cn0);
553 ffebad_here (n, wl0, wc0);
554 ffewhere_line_kill (wl0);
555 ffewhere_column_kill (wc0);
558 static int
559 ffelex_getc_ (FILE *finput)
561 int c;
563 if (ffelex_kludge_chars_ == NULL)
564 return getc (finput);
566 c = *ffelex_kludge_chars_++;
567 if (c != 0)
568 return c;
570 ffelex_kludge_chars_ = NULL;
571 return getc (finput);
574 static int
575 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
577 register int c = getc (finput);
578 register int code;
579 register unsigned count;
580 unsigned firstdig = 0;
581 int nonnull;
583 *use_d = 0;
585 switch (c)
587 case 'x':
588 if (warn_traditional)
589 warning ("the meaning of `\\x' varies with -traditional");
591 if (flag_traditional)
592 return c;
594 code = 0;
595 count = 0;
596 nonnull = 0;
597 while (1)
599 c = getc (finput);
600 if (! ISXDIGIT (c))
602 *use_d = 1;
603 *d = c;
604 break;
606 code *= 16;
607 if (c >= 'a' && c <= 'f')
608 code += c - 'a' + 10;
609 if (c >= 'A' && c <= 'F')
610 code += c - 'A' + 10;
611 if (ISDIGIT (c))
612 code += c - '0';
613 if (code != 0 || count != 0)
615 if (count == 0)
616 firstdig = code;
617 count++;
619 nonnull = 1;
621 if (! nonnull)
622 error ("\\x used with no following hex digits");
623 else if (count == 0)
624 /* Digits are all 0's. Ok. */
626 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
627 || (count > 1
628 && (((unsigned) 1
629 << (TYPE_PRECISION (integer_type_node) - (count - 1)
630 * 4))
631 <= firstdig)))
632 pedwarn ("hex escape out of range");
633 return code;
635 case '0': case '1': case '2': case '3': case '4':
636 case '5': case '6': case '7':
637 code = 0;
638 count = 0;
639 while ((c <= '7') && (c >= '0') && (count++ < 3))
641 code = (code * 8) + (c - '0');
642 c = getc (finput);
644 *use_d = 1;
645 *d = c;
646 return code;
648 case '\\': case '\'': case '"':
649 return c;
651 case '\n':
652 ffelex_next_line_ ();
653 *use_d = 2;
654 return 0;
656 case EOF:
657 *use_d = 1;
658 *d = EOF;
659 return EOF;
661 case 'n':
662 return TARGET_NEWLINE;
664 case 't':
665 return TARGET_TAB;
667 case 'r':
668 return TARGET_CR;
670 case 'f':
671 return TARGET_FF;
673 case 'b':
674 return TARGET_BS;
676 case 'a':
677 if (warn_traditional)
678 warning ("the meaning of `\\a' varies with -traditional");
680 if (flag_traditional)
681 return c;
682 return TARGET_BELL;
684 case 'v':
685 #if 0 /* Vertical tab is present in common usage compilers. */
686 if (flag_traditional)
687 return c;
688 #endif
689 return TARGET_VT;
691 case 'e':
692 case 'E':
693 if (pedantic)
694 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
695 return 033;
697 case '?':
698 return c;
700 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
701 case '(':
702 case '{':
703 case '[':
704 /* `\%' is used to prevent SCCS from getting confused. */
705 case '%':
706 if (pedantic)
707 pedwarn ("non-ISO escape sequence `\\%c'", c);
708 return c;
710 if (c >= 040 && c < 0177)
711 pedwarn ("unknown escape sequence `\\%c'", c);
712 else
713 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
714 return c;
717 /* A miniature version of the C front-end lexer. */
719 static int
720 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
722 ffelexToken token;
723 char buff[129];
724 char *p;
725 char *q;
726 char *r;
727 register unsigned buffer_length;
729 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
730 ffelex_token_kill (*xtoken);
732 switch (c)
734 case '0': case '1': case '2': case '3': case '4':
735 case '5': case '6': case '7': case '8': case '9':
736 buffer_length = ARRAY_SIZE (buff);
737 p = &buff[0];
738 q = p;
739 r = &buff[buffer_length];
740 for (;;)
742 *p++ = c;
743 if (p >= r)
745 register unsigned bytes_used = (p - q);
747 buffer_length *= 2;
748 q = (char *)xrealloc (q, buffer_length);
749 p = &q[bytes_used];
750 r = &q[buffer_length];
752 c = ffelex_getc_ (finput);
753 if (! ISDIGIT (c))
754 break;
756 *p = '\0';
757 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
758 ffewhere_column_unknown ());
760 if (q != &buff[0])
761 free (q);
763 break;
765 case '\"':
766 buffer_length = ARRAY_SIZE (buff);
767 p = &buff[0];
768 q = p;
769 r = &buff[buffer_length];
770 c = ffelex_getc_ (finput);
771 for (;;)
773 bool done = FALSE;
774 int use_d = 0;
775 int d;
777 switch (c)
779 case '\"':
780 c = getc (finput);
781 done = TRUE;
782 break;
784 case '\\': /* ~~~~~ */
785 c = ffelex_cfebackslash_ (&use_d, &d, finput);
786 break;
788 case EOF:
789 case '\n':
790 error ("badly formed directive -- no closing quote");
791 done = TRUE;
792 break;
794 default:
795 break;
797 if (done)
798 break;
800 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
802 *p++ = c;
803 if (p >= r)
805 register unsigned bytes_used = (p - q);
807 buffer_length = bytes_used * 2;
808 q = (char *)xrealloc (q, buffer_length);
809 p = &q[bytes_used];
810 r = &q[buffer_length];
813 if (use_d == 1)
814 c = d;
815 else
816 c = getc (finput);
818 *p = '\0';
819 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
820 ffewhere_column_unknown ());
822 if (q != &buff[0])
823 free (q);
825 break;
827 default:
828 token = NULL;
829 break;
832 *xtoken = token;
833 return c;
836 static void
837 ffelex_file_pop_ (const char *input_filename)
839 if (input_file_stack->next)
841 struct file_stack *p = input_file_stack;
842 input_file_stack = p->next;
843 free (p);
844 input_file_stack_tick++;
845 (*debug_hooks->end_source_file) (input_file_stack->line);
847 else
848 error ("#-lines for entering and leaving files don't match");
850 /* Now that we've pushed or popped the input stack,
851 update the name in the top element. */
852 if (input_file_stack)
853 input_file_stack->name = input_filename;
856 static void
857 ffelex_file_push_ (int old_lineno, const char *input_filename)
859 struct file_stack *p
860 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
862 input_file_stack->line = old_lineno;
863 p->next = input_file_stack;
864 p->name = input_filename;
865 input_file_stack = p;
866 input_file_stack_tick++;
868 (*debug_hooks->start_source_file) (0, input_filename);
870 /* Now that we've pushed or popped the input stack,
871 update the name in the top element. */
872 if (input_file_stack)
873 input_file_stack->name = input_filename;
876 /* Prepare to finish a statement-in-progress by sending the current
877 token, if any, then setting up EOS as the current token with the
878 appropriate current pointer. The caller can then move the current
879 pointer before actually sending EOS, if desired, as it is in
880 typical fixed-form cases. */
882 static void
883 ffelex_prepare_eos_ ()
885 if (ffelex_token_->type != FFELEX_typeNONE)
887 ffelex_backslash_ (EOF, 0);
889 switch (ffelex_raw_mode_)
891 case -2:
892 break;
894 case -1:
895 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
896 : FFEBAD_NO_CLOSING_QUOTE);
897 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
898 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
899 ffebad_finish ();
900 break;
902 case 0:
903 break;
905 default:
907 char num[20];
909 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
910 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
911 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
912 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
913 ffebad_string (num);
914 ffebad_finish ();
915 /* Make sure the token has some text, might as well fill up with spaces. */
918 ffelex_append_to_token_ (' ');
919 } while (--ffelex_raw_mode_ > 0);
920 break;
923 ffelex_raw_mode_ = 0;
924 ffelex_send_token_ ();
926 ffelex_token_->type = FFELEX_typeEOS;
927 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
928 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
931 static void
932 ffelex_finish_statement_ ()
934 if ((ffelex_number_of_tokens_ == 0)
935 && (ffelex_token_->type == FFELEX_typeNONE))
936 return; /* Don't have a statement pending. */
938 if (ffelex_token_->type != FFELEX_typeEOS)
939 ffelex_prepare_eos_ ();
941 ffelex_permit_include_ = TRUE;
942 ffelex_send_token_ ();
943 ffelex_permit_include_ = FALSE;
944 ffelex_number_of_tokens_ = 0;
945 ffelex_label_tokens_ = 0;
946 ffelex_names_ = TRUE;
947 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
948 ffelex_hexnum_ = FALSE;
950 if (!ffe_is_ffedebug ())
951 return;
953 /* For debugging purposes only. */
955 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
957 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
958 ffelex_old_total_tokens_, ffelex_total_tokens_);
959 ffelex_old_total_tokens_ = ffelex_total_tokens_;
963 /* Copied from gcc/c-common.c get_directive_line. */
965 static int
966 ffelex_get_directive_line_ (char **text, FILE *finput)
968 static char *directive_buffer = NULL;
969 static unsigned buffer_length = 0;
970 register char *p;
971 register char *buffer_limit;
972 register int looking_for = 0;
973 register int char_escaped = 0;
975 if (buffer_length == 0)
977 directive_buffer = (char *)xmalloc (128);
978 buffer_length = 128;
981 buffer_limit = &directive_buffer[buffer_length];
983 for (p = directive_buffer; ; )
985 int c;
987 /* Make buffer bigger if it is full. */
988 if (p >= buffer_limit)
990 register unsigned bytes_used = (p - directive_buffer);
992 buffer_length *= 2;
993 directive_buffer
994 = (char *)xrealloc (directive_buffer, buffer_length);
995 p = &directive_buffer[bytes_used];
996 buffer_limit = &directive_buffer[buffer_length];
999 c = getc (finput);
1001 /* Discard initial whitespace. */
1002 if ((c == ' ' || c == '\t') && p == directive_buffer)
1003 continue;
1005 /* Detect the end of the directive. */
1006 if ((c == '\n' && looking_for == 0)
1007 || c == EOF)
1009 if (looking_for != 0)
1010 error ("bad directive -- missing close-quote");
1012 *p++ = '\0';
1013 *text = directive_buffer;
1014 return c;
1017 *p++ = c;
1018 if (c == '\n')
1019 ffelex_next_line_ ();
1021 /* Handle string and character constant syntax. */
1022 if (looking_for)
1024 if (looking_for == c && !char_escaped)
1025 looking_for = 0; /* Found terminator... stop looking. */
1027 else
1028 if (c == '\'' || c == '"')
1029 looking_for = c; /* Don't stop buffering until we see another
1030 one of these (or an EOF). */
1032 /* Handle backslash. */
1033 char_escaped = (c == '\\' && ! char_escaped);
1037 /* Handle # directives that make it through (or are generated by) the
1038 preprocessor. As much as reasonably possible, emulate the behavior
1039 of the gcc compiler phase cc1, though interactions between #include
1040 and INCLUDE might possibly produce bizarre results in terms of
1041 error reporting and the generation of debugging info vis-a-vis the
1042 locations of some things.
1044 Returns the next character unhandled, which is always newline or EOF. */
1046 #if defined HANDLE_PRAGMA
1047 /* Local versions of these macros, that can be passed as function pointers. */
1048 static int
1049 pragma_getc ()
1051 return getc (finput);
1054 static void
1055 pragma_ungetc (arg)
1056 int arg;
1058 ungetc (arg, finput);
1060 #endif /* HANDLE_PRAGMA */
1062 static int
1063 ffelex_hash_ (FILE *finput)
1065 register int c;
1066 ffelexToken token = NULL;
1068 /* Read first nonwhite char after the `#'. */
1070 c = ffelex_getc_ (finput);
1071 while (c == ' ' || c == '\t')
1072 c = ffelex_getc_ (finput);
1074 /* If a letter follows, then if the word here is `line', skip
1075 it and ignore it; otherwise, ignore the line, with an error
1076 if the word isn't `pragma', `ident', `define', or `undef'. */
1078 if (ISALPHA(c))
1080 if (c == 'p')
1082 if (getc (finput) == 'r'
1083 && getc (finput) == 'a'
1084 && getc (finput) == 'g'
1085 && getc (finput) == 'm'
1086 && getc (finput) == 'a'
1087 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1088 || c == EOF))
1090 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1091 static char buffer [128];
1092 char * buff = buffer;
1094 /* Read the pragma name into a buffer.
1095 ISSPACE() may evaluate its argument more than once! */
1096 while (((c = getc (finput)), ISSPACE(c)))
1097 continue;
1101 * buff ++ = c;
1102 c = getc (finput);
1104 while (c != EOF && ! ISSPACE (c) && c != '\n'
1105 && buff < buffer + 128);
1107 pragma_ungetc (c);
1109 * -- buff = 0;
1110 #ifdef HANDLE_PRAGMA
1111 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1112 goto skipline;
1113 #endif /* HANDLE_PRAGMA */
1114 #ifdef HANDLE_GENERIC_PRAGMAS
1115 if (handle_generic_pragma (buffer))
1116 goto skipline;
1117 #endif /* !HANDLE_GENERIC_PRAGMAS */
1119 /* Issue a warning message if we have been asked to do so.
1120 Ignoring unknown pragmas in system header file unless
1121 an explcit -Wunknown-pragmas has been given. */
1122 if (warn_unknown_pragmas > 1
1123 || (warn_unknown_pragmas && ! in_system_header))
1124 warning ("ignoring pragma: %s", token_buffer);
1125 #endif /* 0 */
1126 goto skipline;
1130 else if (c == 'd')
1132 if (getc (finput) == 'e'
1133 && getc (finput) == 'f'
1134 && getc (finput) == 'i'
1135 && getc (finput) == 'n'
1136 && getc (finput) == 'e'
1137 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1138 || c == EOF))
1140 char *text;
1142 c = ffelex_get_directive_line_ (&text, finput);
1144 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1145 (*debug_hooks->define) (lineno, text);
1147 goto skipline;
1150 else if (c == 'u')
1152 if (getc (finput) == 'n'
1153 && getc (finput) == 'd'
1154 && getc (finput) == 'e'
1155 && getc (finput) == 'f'
1156 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1157 || c == EOF))
1159 char *text;
1161 c = ffelex_get_directive_line_ (&text, finput);
1163 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1164 (*debug_hooks->undef) (lineno, text);
1166 goto skipline;
1169 else if (c == 'l')
1171 if (getc (finput) == 'i'
1172 && getc (finput) == 'n'
1173 && getc (finput) == 'e'
1174 && ((c = getc (finput)) == ' ' || c == '\t'))
1175 goto linenum;
1177 else if (c == 'i')
1179 if (getc (finput) == 'd'
1180 && getc (finput) == 'e'
1181 && getc (finput) == 'n'
1182 && getc (finput) == 't'
1183 && ((c = getc (finput)) == ' ' || c == '\t'))
1185 /* #ident. The pedantic warning is now in cpp. */
1187 /* Here we have just seen `#ident '.
1188 A string constant should follow. */
1190 while (c == ' ' || c == '\t')
1191 c = getc (finput);
1193 /* If no argument, ignore the line. */
1194 if (c == '\n' || c == EOF)
1195 return c;
1197 c = ffelex_cfelex_ (&token, finput, c);
1199 if ((token == NULL)
1200 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1202 error ("invalid #ident");
1203 goto skipline;
1206 if (! flag_no_ident)
1208 #ifdef ASM_OUTPUT_IDENT
1209 ASM_OUTPUT_IDENT (asm_out_file,
1210 ffelex_token_text (token));
1211 #endif
1214 /* Skip the rest of this line. */
1215 goto skipline;
1219 error ("undefined or invalid # directive");
1220 goto skipline;
1223 linenum:
1224 /* Here we have either `#line' or `# <nonletter>'.
1225 In either case, it should be a line number; a digit should follow. */
1227 while (c == ' ' || c == '\t')
1228 c = ffelex_getc_ (finput);
1230 /* If the # is the only nonwhite char on the line,
1231 just ignore it. Check the new newline. */
1232 if (c == '\n' || c == EOF)
1233 return c;
1235 /* Something follows the #; read a token. */
1237 c = ffelex_cfelex_ (&token, finput, c);
1239 if ((token != NULL)
1240 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1242 int old_lineno = lineno;
1243 const char *old_input_filename = input_filename;
1244 ffewhereFile wf;
1246 /* subtract one, because it is the following line that
1247 gets the specified number */
1248 int l = atoi (ffelex_token_text (token)) - 1;
1250 /* Is this the last nonwhite stuff on the line? */
1251 while (c == ' ' || c == '\t')
1252 c = ffelex_getc_ (finput);
1253 if (c == '\n' || c == EOF)
1255 /* No more: store the line number and check following line. */
1256 lineno = l;
1257 if (!ffelex_kludge_flag_)
1259 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1261 if (token != NULL)
1262 ffelex_token_kill (token);
1264 return c;
1267 /* More follows: it must be a string constant (filename). */
1269 /* Read the string constant. */
1270 c = ffelex_cfelex_ (&token, finput, c);
1272 if ((token == NULL)
1273 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1275 error ("invalid #line");
1276 goto skipline;
1279 lineno = l;
1281 if (ffelex_kludge_flag_)
1282 input_filename = ggc_strdup (ffelex_token_text (token));
1283 else
1285 wf = ffewhere_file_new (ffelex_token_text (token),
1286 ffelex_token_length (token));
1287 input_filename = ffewhere_file_name (wf);
1288 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1291 #if 0 /* Not sure what g77 should do with this yet. */
1292 /* Each change of file name
1293 reinitializes whether we are now in a system header. */
1294 in_system_header = 0;
1295 #endif
1297 if (main_input_filename == 0)
1298 main_input_filename = input_filename;
1300 /* Is this the last nonwhite stuff on the line? */
1301 while (c == ' ' || c == '\t')
1302 c = getc (finput);
1303 if (c == '\n' || c == EOF)
1305 if (!ffelex_kludge_flag_)
1307 /* Update the name in the top element of input_file_stack. */
1308 if (input_file_stack)
1309 input_file_stack->name = input_filename;
1311 if (token != NULL)
1312 ffelex_token_kill (token);
1314 return c;
1317 c = ffelex_cfelex_ (&token, finput, c);
1319 /* `1' after file name means entering new file.
1320 `2' after file name means just left a file. */
1322 if ((token != NULL)
1323 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1325 int num = atoi (ffelex_token_text (token));
1327 if (ffelex_kludge_flag_)
1329 lineno = 1;
1330 input_filename = old_input_filename;
1331 error ("use `#line ...' instead of `# ...' in first line");
1334 if (num == 1)
1336 /* Pushing to a new file. */
1337 ffelex_file_push_ (old_lineno, input_filename);
1339 else if (num == 2)
1341 /* Popping out of a file. */
1342 ffelex_file_pop_ (input_filename);
1345 /* Is this the last nonwhite stuff on the line? */
1346 while (c == ' ' || c == '\t')
1347 c = getc (finput);
1348 if (c == '\n' || c == EOF)
1350 if (token != NULL)
1351 ffelex_token_kill (token);
1352 return c;
1355 c = ffelex_cfelex_ (&token, finput, c);
1358 /* `3' after file name means this is a system header file. */
1360 #if 0 /* Not sure what g77 should do with this yet. */
1361 if ((token != NULL)
1362 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1363 && (atoi (ffelex_token_text (token)) == 3))
1364 in_system_header = 1;
1365 #endif
1367 while (c == ' ' || c == '\t')
1368 c = getc (finput);
1369 if (((token != NULL)
1370 || (c != '\n' && c != EOF))
1371 && ffelex_kludge_flag_)
1373 lineno = 1;
1374 input_filename = old_input_filename;
1375 error ("use `#line ...' instead of `# ...' in first line");
1377 if (c == '\n' || c == EOF)
1379 if (token != NULL && !ffelex_kludge_flag_)
1380 ffelex_token_kill (token);
1381 return c;
1384 else
1385 error ("invalid #-line");
1387 /* skip the rest of this line. */
1388 skipline:
1389 if ((token != NULL) && !ffelex_kludge_flag_)
1390 ffelex_token_kill (token);
1391 while ((c = getc (finput)) != EOF && c != '\n')
1393 return c;
1396 /* "Image" a character onto the card image, return incremented column number.
1398 Normally invoking this function as in
1399 column = ffelex_image_char_ (c, column);
1400 is the same as doing:
1401 ffelex_card_image_[column++] = c;
1403 However, tabs and carriage returns are handled specially, to preserve
1404 the visual "image" of the input line (in most editors) in the card
1405 image.
1407 Carriage returns are ignored, as they are assumed to be followed
1408 by newlines.
1410 A tab is handled by first doing:
1411 ffelex_card_image_[column++] = ' ';
1412 That is, it translates to at least one space. Then, as many spaces
1413 are imaged as necessary to bring the column number to the next tab
1414 position, where tab positions start in the ninth column and each
1415 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1416 is set to TRUE to notify the lexer that a tab was seen.
1418 Columns are numbered and tab stops set as illustrated below:
1420 012345670123456701234567...
1421 x y z
1422 xx yy zz
1424 xxxxxxx yyyyyyy zzzzzzz
1425 xxxxxxxx yyyyyyyy... */
1427 static ffewhereColumnNumber
1428 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1430 ffewhereColumnNumber old_column = column;
1432 if (column >= ffelex_card_size_)
1434 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1436 if (ffelex_bad_line_)
1437 return column;
1439 if ((newmax >> 1) != ffelex_card_size_)
1440 { /* Overflowed column number. */
1441 overflow: /* :::::::::::::::::::: */
1443 ffelex_bad_line_ = TRUE;
1444 strcpy (&ffelex_card_image_[column - 3], "...");
1445 ffelex_card_length_ = column;
1446 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1447 ffelex_linecount_current_, column + 1);
1448 return column;
1451 ffelex_card_image_
1452 = malloc_resize_ksr (malloc_pool_image (),
1453 ffelex_card_image_,
1454 newmax + 9,
1455 ffelex_card_size_ + 9);
1456 ffelex_card_size_ = newmax;
1459 switch (c)
1461 case '\r':
1462 break;
1464 case '\t':
1465 ffelex_saw_tab_ = TRUE;
1466 ffelex_card_image_[column++] = ' ';
1467 while ((column & 7) != 0)
1468 ffelex_card_image_[column++] = ' ';
1469 break;
1471 case '\0':
1472 if (!ffelex_bad_line_)
1474 ffelex_bad_line_ = TRUE;
1475 strcpy (&ffelex_card_image_[column], "[\\0]");
1476 ffelex_card_length_ = column + 4;
1477 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1478 FFEBAD_severityFATAL);
1479 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1480 ffebad_finish ();
1481 column += 4;
1483 break;
1485 default:
1486 ffelex_card_image_[column++] = c;
1487 break;
1490 if (column < old_column)
1492 column = old_column;
1493 goto overflow; /* :::::::::::::::::::: */
1496 return column;
1499 static void
1500 ffelex_include_ ()
1502 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1503 FILE *include_file = ffelex_include_file_;
1504 /* The rest of this is to push, and after the INCLUDE file is processed,
1505 pop, the static lexer state info that pertains to each particular
1506 input file. */
1507 char *card_image;
1508 ffewhereColumnNumber card_size = ffelex_card_size_;
1509 ffewhereColumnNumber card_length = ffelex_card_length_;
1510 ffewhereLine current_wl = ffelex_current_wl_;
1511 ffewhereColumn current_wc = ffelex_current_wc_;
1512 bool saw_tab = ffelex_saw_tab_;
1513 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1514 ffewhereFile current_wf = ffelex_current_wf_;
1515 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1516 ffewhereLineNumber linecount_offset
1517 = ffewhere_line_filelinenum (current_wl);
1518 int old_lineno = lineno;
1519 const char *old_input_filename = input_filename;
1521 if (card_length != 0)
1523 card_image = malloc_new_ks (malloc_pool_image (),
1524 "FFELEX saved card image",
1525 card_length);
1526 memcpy (card_image, ffelex_card_image_, card_length);
1528 else
1529 card_image = NULL;
1531 ffelex_set_include_ = FALSE;
1533 ffelex_next_line_ ();
1535 ffewhere_file_set (include_wherefile, TRUE, 0);
1537 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1539 if (ffelex_include_free_form_)
1540 ffelex_file_free (include_wherefile, include_file);
1541 else
1542 ffelex_file_fixed (include_wherefile, include_file);
1544 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1546 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1548 ffecom_close_include (include_file);
1550 if (card_length != 0)
1552 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1553 #error "need to handle possible reduction of card size here!!"
1554 #endif
1555 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1556 memcpy (ffelex_card_image_, card_image, card_length);
1558 ffelex_card_image_[card_length] = '\0';
1560 input_filename = old_input_filename;
1561 lineno = old_lineno;
1562 ffelex_linecount_current_ = linecount_current;
1563 ffelex_current_wf_ = current_wf;
1564 ffelex_final_nontab_column_ = final_nontab_column;
1565 ffelex_saw_tab_ = saw_tab;
1566 ffelex_current_wc_ = current_wc;
1567 ffelex_current_wl_ = current_wl;
1568 ffelex_card_length_ = card_length;
1569 ffelex_card_size_ = card_size;
1572 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1574 ffewhereColumnNumber col;
1575 int c; // Char at col.
1576 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1577 // We have a continuation indicator.
1579 If there are <n> spaces starting at ffelex_card_image_[col] up through
1580 the null character, where <n> is 0 or greater, returns TRUE. */
1582 static bool
1583 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1585 while (ffelex_card_image_[col] != '\0')
1587 if (ffelex_card_image_[col++] != ' ')
1588 return FALSE;
1590 return TRUE;
1593 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1595 ffewhereColumnNumber col;
1596 int c; // Char at col.
1597 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1598 // We have a continuation indicator.
1600 If there are <n> spaces starting at ffelex_card_image_[col] up through
1601 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1603 static bool
1604 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1606 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1608 if (ffelex_card_image_[col++] != ' ')
1609 return FALSE;
1611 return TRUE;
1614 static void
1615 ffelex_next_line_ ()
1617 ffelex_linecount_current_ = ffelex_linecount_next_;
1618 ++ffelex_linecount_next_;
1619 ++lineno;
1622 static void
1623 ffelex_send_token_ ()
1625 ++ffelex_number_of_tokens_;
1627 ffelex_backslash_ (EOF, 0);
1629 if (ffelex_token_->text == NULL)
1631 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1633 ffelex_append_to_token_ ('\0');
1634 ffelex_token_->length = 0;
1637 else
1638 ffelex_token_->text[ffelex_token_->length] = '\0';
1640 assert (ffelex_raw_mode_ == 0);
1642 if (ffelex_token_->type == FFELEX_typeNAMES)
1644 ffewhere_line_kill (ffelex_token_->currentnames_line);
1645 ffewhere_column_kill (ffelex_token_->currentnames_col);
1648 assert (ffelex_handler_ != NULL);
1649 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1650 assert (ffelex_handler_ != NULL);
1652 ffelex_token_kill (ffelex_token_);
1654 ffelex_token_ = ffelex_token_new_ ();
1655 ffelex_token_->uses = 1;
1656 ffelex_token_->text = NULL;
1657 if (ffelex_raw_mode_ < 0)
1659 ffelex_token_->type = FFELEX_typeCHARACTER;
1660 ffelex_token_->where_line = ffelex_raw_where_line_;
1661 ffelex_token_->where_col = ffelex_raw_where_col_;
1662 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1663 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1665 else
1667 ffelex_token_->type = FFELEX_typeNONE;
1668 ffelex_token_->where_line = ffewhere_line_unknown ();
1669 ffelex_token_->where_col = ffewhere_column_unknown ();
1672 if (ffelex_set_include_)
1673 ffelex_include_ ();
1676 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1678 return ffelex_swallow_tokens_;
1680 Return this handler when you don't want to look at any more tokens in the
1681 statement because you've encountered an unrecoverable error in the
1682 statement. */
1684 static ffelexHandler
1685 ffelex_swallow_tokens_ (ffelexToken t)
1687 assert (ffelex_eos_handler_ != NULL);
1689 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1690 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1691 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1693 return (ffelexHandler) ffelex_swallow_tokens_;
1696 static ffelexToken
1697 ffelex_token_new_ ()
1699 ffelexToken t;
1701 ++ffelex_total_tokens_;
1703 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1704 "FFELEX token", sizeof (*t));
1705 t->id_ = ffelex_token_nextid_++;
1706 return t;
1709 static const char *
1710 ffelex_type_string_ (ffelexType type)
1712 static const char *const types[] = {
1713 "FFELEX_typeNONE",
1714 "FFELEX_typeCOMMENT",
1715 "FFELEX_typeEOS",
1716 "FFELEX_typeEOF",
1717 "FFELEX_typeERROR",
1718 "FFELEX_typeRAW",
1719 "FFELEX_typeQUOTE",
1720 "FFELEX_typeDOLLAR",
1721 "FFELEX_typeHASH",
1722 "FFELEX_typePERCENT",
1723 "FFELEX_typeAMPERSAND",
1724 "FFELEX_typeAPOSTROPHE",
1725 "FFELEX_typeOPEN_PAREN",
1726 "FFELEX_typeCLOSE_PAREN",
1727 "FFELEX_typeASTERISK",
1728 "FFELEX_typePLUS",
1729 "FFELEX_typeMINUS",
1730 "FFELEX_typePERIOD",
1731 "FFELEX_typeSLASH",
1732 "FFELEX_typeNUMBER",
1733 "FFELEX_typeOPEN_ANGLE",
1734 "FFELEX_typeEQUALS",
1735 "FFELEX_typeCLOSE_ANGLE",
1736 "FFELEX_typeNAME",
1737 "FFELEX_typeCOMMA",
1738 "FFELEX_typePOWER",
1739 "FFELEX_typeCONCAT",
1740 "FFELEX_typeDEBUG",
1741 "FFELEX_typeNAMES",
1742 "FFELEX_typeHOLLERITH",
1743 "FFELEX_typeCHARACTER",
1744 "FFELEX_typeCOLON",
1745 "FFELEX_typeSEMICOLON",
1746 "FFELEX_typeUNDERSCORE",
1747 "FFELEX_typeQUESTION",
1748 "FFELEX_typeOPEN_ARRAY",
1749 "FFELEX_typeCLOSE_ARRAY",
1750 "FFELEX_typeCOLONCOLON",
1751 "FFELEX_typeREL_LE",
1752 "FFELEX_typeREL_NE",
1753 "FFELEX_typeREL_EQ",
1754 "FFELEX_typePOINTS",
1755 "FFELEX_typeREL_GE"
1758 if (type >= ARRAY_SIZE (types))
1759 return "???";
1760 return types[type];
1763 void
1764 ffelex_display_token (ffelexToken t)
1766 if (t == NULL)
1767 t = ffelex_token_;
1769 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1770 ffewhereColumnNumber_f "u)",
1771 t->id_,
1772 ffelex_type_string_ (t->type),
1773 ffewhere_line_number (t->where_line),
1774 ffewhere_column_number (t->where_col));
1776 if (t->text != NULL)
1777 fprintf (dmpout, ": \"%.*s\"\n",
1778 (int) t->length,
1779 t->text);
1780 else
1781 fprintf (dmpout, ".\n");
1784 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1786 if (ffelex_expecting_character())
1787 // next token delivered by lexer will be CHARACTER.
1789 If the most recent call to ffelex_set_expecting_hollerith since the last
1790 token was delivered by the lexer passed a length of -1, then we return
1791 TRUE, because the next token we deliver will be typeCHARACTER, else we
1792 return FALSE. */
1794 bool
1795 ffelex_expecting_character ()
1797 return (ffelex_raw_mode_ != 0);
1800 /* ffelex_file_fixed -- Lex a given file in fixed source form
1802 ffewhere wf;
1803 FILE *f;
1804 ffelex_file_fixed(wf,f);
1806 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1808 ffelexHandler
1809 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1811 register int c = 0; /* Character currently under consideration. */
1812 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1813 bool disallow_continuation_line;
1814 bool ignore_disallowed_continuation = FALSE;
1815 int latest_char_in_file = 0; /* For getting back into comment-skipping
1816 code. */
1817 ffelexType lextype;
1818 ffewhereColumnNumber first_label_char; /* First char of label --
1819 column number. */
1820 char label_string[6]; /* Text of label. */
1821 int labi; /* Length of label text. */
1822 bool finish_statement; /* Previous statement finished? */
1823 bool have_content; /* This line have content? */
1824 bool just_do_label; /* Nothing but label (and continuation?) on
1825 line. */
1827 /* Lex is called for a particular file, not for a particular program unit.
1828 Yet the two events do share common characteristics. The first line in a
1829 file or in a program unit cannot be a continuation line. No token can
1830 be in mid-formation. No current label for the statement exists, since
1831 there is no current statement. */
1833 assert (ffelex_handler_ != NULL);
1835 lineno = 0;
1836 input_filename = ffewhere_file_name (wf);
1837 ffelex_current_wf_ = wf;
1838 disallow_continuation_line = TRUE;
1839 ignore_disallowed_continuation = FALSE;
1840 ffelex_token_->type = FFELEX_typeNONE;
1841 ffelex_number_of_tokens_ = 0;
1842 ffelex_label_tokens_ = 0;
1843 ffelex_current_wl_ = ffewhere_line_unknown ();
1844 ffelex_current_wc_ = ffewhere_column_unknown ();
1845 latest_char_in_file = '\n';
1847 goto first_line; /* :::::::::::::::::::: */
1849 /* Come here to get a new line. */
1851 beginning_of_line: /* :::::::::::::::::::: */
1853 disallow_continuation_line = FALSE;
1855 /* Come here directly when last line didn't clarify the continuation issue. */
1857 beginning_of_line_again: /* :::::::::::::::::::: */
1859 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1860 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1862 ffelex_card_image_
1863 = malloc_resize_ks (malloc_pool_image (),
1864 ffelex_card_image_,
1865 FFELEX_columnINITIAL_SIZE_ + 9,
1866 ffelex_card_size_ + 9);
1867 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1869 #endif
1871 first_line: /* :::::::::::::::::::: */
1873 c = latest_char_in_file;
1874 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1877 end_of_file: /* :::::::::::::::::::: */
1879 /* Line ending in EOF instead of \n still counts as a whole line. */
1881 ffelex_finish_statement_ ();
1882 ffewhere_line_kill (ffelex_current_wl_);
1883 ffewhere_column_kill (ffelex_current_wc_);
1884 return (ffelexHandler) ffelex_handler_;
1887 ffelex_next_line_ ();
1889 ffelex_bad_line_ = FALSE;
1891 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1893 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1894 || (lextype == FFELEX_typeERROR)
1895 || (lextype == FFELEX_typeSLASH)
1896 || (lextype == FFELEX_typeHASH))
1898 /* Test most frequent type of line first, etc. */
1899 if ((lextype == FFELEX_typeCOMMENT)
1900 || ((lextype == FFELEX_typeSLASH)
1901 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1903 /* Typical case (straight comment), just ignore rest of line. */
1904 comment_line: /* :::::::::::::::::::: */
1906 while ((c != '\n') && (c != EOF))
1907 c = getc (f);
1909 else if (lextype == FFELEX_typeHASH)
1910 c = ffelex_hash_ (f);
1911 else if (lextype == FFELEX_typeSLASH)
1913 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1914 ffelex_card_image_[0] = '/';
1915 ffelex_card_image_[1] = c;
1916 column = 2;
1917 goto bad_first_character; /* :::::::::::::::::::: */
1919 else
1920 /* typeERROR or unsupported typeHASH. */
1921 { /* Bad first character, get line and display
1922 it with message. */
1923 column = ffelex_image_char_ (c, 0);
1925 bad_first_character: /* :::::::::::::::::::: */
1927 ffelex_bad_line_ = TRUE;
1928 while (((c = getc (f)) != '\n') && (c != EOF))
1929 column = ffelex_image_char_ (c, column);
1930 ffelex_card_image_[column] = '\0';
1931 ffelex_card_length_ = column;
1932 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
1933 ffelex_linecount_current_, 1);
1936 /* Read past last char in line. */
1938 if (c == EOF)
1940 ffelex_next_line_ ();
1941 goto end_of_file; /* :::::::::::::::::::: */
1944 c = getc (f);
1946 ffelex_next_line_ ();
1948 if (c == EOF)
1949 goto end_of_file; /* :::::::::::::::::::: */
1951 ffelex_bad_line_ = FALSE;
1952 } /* while [c, first char, means comment] */
1954 ffelex_saw_tab_
1955 = (c == '&')
1956 || (ffelex_final_nontab_column_ == 0);
1958 if (lextype == FFELEX_typeDEBUG)
1959 c = ' '; /* A 'D' or 'd' in column 1 with the
1960 debug-lines option on. */
1962 column = ffelex_image_char_ (c, 0);
1964 /* Read the entire line in as is (with whitespace processing). */
1966 while (((c = getc (f)) != '\n') && (c != EOF))
1967 column = ffelex_image_char_ (c, column);
1969 if (ffelex_bad_line_)
1971 ffelex_card_image_[column] = '\0';
1972 ffelex_card_length_ = column;
1973 goto comment_line; /* :::::::::::::::::::: */
1976 /* If no tab, cut off line after column 72/132. */
1978 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
1980 /* Technically, we should now fill ffelex_card_image_ up thru column
1981 72/132 with spaces, since character/hollerith constants must count
1982 them in that manner. To save CPU time in several ways (avoid a loop
1983 here that would be used only when we actually end a line in
1984 character-constant mode; avoid writing memory unnecessarily; avoid a
1985 loop later checking spaces when not scanning for character-constant
1986 characters), we don't do this, and we do the appropriate thing when
1987 we encounter end-of-line while actually processing a character
1988 constant. */
1990 column = ffelex_final_nontab_column_;
1993 ffelex_card_image_[column] = '\0';
1994 ffelex_card_length_ = column;
1996 /* Save next char in file so we can use register-based c while analyzing
1997 line we just read. */
1999 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2001 have_content = FALSE;
2003 /* Handle label, if any. */
2005 labi = 0;
2006 first_label_char = FFEWHERE_columnUNKNOWN;
2007 for (column = 0; column < 5; ++column)
2009 switch (c = ffelex_card_image_[column])
2011 case '\0':
2012 case '!':
2013 goto stop_looking; /* :::::::::::::::::::: */
2015 case ' ':
2016 break;
2018 case '0':
2019 case '1':
2020 case '2':
2021 case '3':
2022 case '4':
2023 case '5':
2024 case '6':
2025 case '7':
2026 case '8':
2027 case '9':
2028 label_string[labi++] = c;
2029 if (first_label_char == FFEWHERE_columnUNKNOWN)
2030 first_label_char = column + 1;
2031 break;
2033 case '&':
2034 if (column != 0)
2036 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2037 ffelex_linecount_current_,
2038 column + 1);
2039 goto beginning_of_line_again; /* :::::::::::::::::::: */
2041 if (ffe_is_pedantic ())
2042 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2043 ffelex_linecount_current_, 1);
2044 finish_statement = FALSE;
2045 just_do_label = FALSE;
2046 goto got_a_continuation; /* :::::::::::::::::::: */
2048 case '/':
2049 if (ffelex_card_image_[column + 1] == '*')
2050 goto stop_looking; /* :::::::::::::::::::: */
2051 /* Fall through. */
2052 default:
2053 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2054 ffelex_linecount_current_, column + 1);
2055 goto beginning_of_line_again; /* :::::::::::::::::::: */
2059 stop_looking: /* :::::::::::::::::::: */
2061 label_string[labi] = '\0';
2063 /* Find first nonblank char starting with continuation column. */
2065 if (column == 5) /* In which case we didn't see end of line in
2066 label field. */
2067 while ((c = ffelex_card_image_[column]) == ' ')
2068 ++column;
2070 /* Now we're trying to figure out whether this is a continuation line and
2071 whether there's anything else of substance on the line. The cases are
2072 as follows:
2074 1. If a line has an explicit continuation character (other than the digit
2075 zero), then if it also has a label, the label is ignored and an error
2076 message is printed. Any remaining text on the line is passed to the
2077 parser tasks, thus even an all-blank line (possibly with an ignored
2078 label) aside from a positive continuation character might have meaning
2079 in the midst of a character or hollerith constant.
2081 2. If a line has no explicit continuation character (that is, it has a
2082 space in column 6 and the first non-space character past column 6 is
2083 not a digit 0-9), then there are two possibilities:
2085 A. A label is present and/or a non-space (and non-comment) character
2086 appears somewhere after column 6. Terminate processing of the previous
2087 statement, if any, send the new label for the next statement, if any,
2088 and start processing a new statement with this non-blank character, if
2089 any.
2091 B. The line is essentially blank, except for a possible comment character.
2092 Don't terminate processing of the previous statement and don't pass any
2093 characters to the parser tasks, since the line is not flagged as a
2094 continuation line. We treat it just like a completely blank line.
2096 3. If a line has a continuation character of zero (0), then we terminate
2097 processing of the previous statement, if any, send the new label for the
2098 next statement, if any, and start processing a new statement, if any
2099 non-blank characters are present.
2101 If, when checking to see if we should terminate the previous statement, it
2102 is found that there is no previous statement but that there is an
2103 outstanding label, substitute CONTINUE as the statement for the label
2104 and display an error message. */
2106 finish_statement = FALSE;
2107 just_do_label = FALSE;
2109 switch (c)
2111 case '!': /* ANSI Fortran 90 says ! in column 6 is
2112 continuation. */
2113 /* VXT Fortran says ! anywhere is comment, even column 6. */
2114 if (ffe_is_vxt () || (column != 5))
2115 goto no_tokens_on_line; /* :::::::::::::::::::: */
2116 goto got_a_continuation; /* :::::::::::::::::::: */
2118 case '/':
2119 if (ffelex_card_image_[column + 1] != '*')
2120 goto some_other_character; /* :::::::::::::::::::: */
2121 /* Fall through. */
2122 if (column == 5)
2124 /* This seems right to do. But it is close to call, since / * starting
2125 in column 6 will thus be interpreted as a continuation line
2126 beginning with '*'. */
2128 goto got_a_continuation;/* :::::::::::::::::::: */
2130 /* Fall through. */
2131 case '\0':
2132 /* End of line. Therefore may be continued-through line, so handle
2133 pending label as possible to-be-continued and drive end-of-statement
2134 for any previous statement, else treat as blank line. */
2136 no_tokens_on_line: /* :::::::::::::::::::: */
2138 if (ffe_is_pedantic () && (c == '/'))
2139 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2140 ffelex_linecount_current_, column + 1);
2141 if (first_label_char != FFEWHERE_columnUNKNOWN)
2142 { /* Can't be a continued-through line if it
2143 has a label. */
2144 finish_statement = TRUE;
2145 have_content = TRUE;
2146 just_do_label = TRUE;
2147 break;
2149 goto beginning_of_line_again; /* :::::::::::::::::::: */
2151 case '0':
2152 if (ffe_is_pedantic () && (column != 5))
2153 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2154 ffelex_linecount_current_, column + 1);
2155 finish_statement = TRUE;
2156 goto check_for_content; /* :::::::::::::::::::: */
2158 case '1':
2159 case '2':
2160 case '3':
2161 case '4':
2162 case '5':
2163 case '6':
2164 case '7':
2165 case '8':
2166 case '9':
2168 /* NOTE: This label can be reached directly from the code
2169 that lexes the label field in columns 1-5. */
2170 got_a_continuation: /* :::::::::::::::::::: */
2172 if (first_label_char != FFEWHERE_columnUNKNOWN)
2174 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2175 ffelex_linecount_current_,
2176 first_label_char,
2177 ffelex_linecount_current_,
2178 column + 1);
2179 first_label_char = FFEWHERE_columnUNKNOWN;
2181 if (disallow_continuation_line)
2183 if (!ignore_disallowed_continuation)
2184 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2185 ffelex_linecount_current_, column + 1);
2186 goto beginning_of_line_again; /* :::::::::::::::::::: */
2188 if (ffe_is_pedantic () && (column != 5))
2189 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2190 ffelex_linecount_current_, column + 1);
2191 if ((ffelex_raw_mode_ != 0)
2192 && (((c = ffelex_card_image_[column + 1]) != '\0')
2193 || !ffelex_saw_tab_))
2195 ++column;
2196 have_content = TRUE;
2197 break;
2200 check_for_content: /* :::::::::::::::::::: */
2202 while ((c = ffelex_card_image_[++column]) == ' ')
2204 if ((c == '\0')
2205 || (c == '!')
2206 || ((c == '/')
2207 && (ffelex_card_image_[column + 1] == '*')))
2209 if (ffe_is_pedantic () && (c == '/'))
2210 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2211 ffelex_linecount_current_, column + 1);
2212 just_do_label = TRUE;
2214 else
2215 have_content = TRUE;
2216 break;
2218 default:
2220 some_other_character: /* :::::::::::::::::::: */
2222 if (column == 5)
2223 goto got_a_continuation;/* :::::::::::::::::::: */
2225 /* Here is the very normal case of a regular character starting in
2226 column 7 or beyond with a blank in column 6. */
2228 finish_statement = TRUE;
2229 have_content = TRUE;
2230 break;
2233 if (have_content
2234 || (first_label_char != FFEWHERE_columnUNKNOWN))
2236 /* The line has content of some kind, install new end-statement
2237 point for error messages. Note that "content" includes cases
2238 where there's little apparent content but enough to finish
2239 a statement. That's because finishing a statement can trigger
2240 an impending INCLUDE, and that requires accurate line info being
2241 maintained by the lexer. */
2243 if (finish_statement)
2244 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2246 ffewhere_line_kill (ffelex_current_wl_);
2247 ffewhere_column_kill (ffelex_current_wc_);
2248 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2249 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2252 /* We delay this for a combination of reasons. Mainly, it can start
2253 INCLUDE processing, and we want to delay that until the lexer's
2254 info on the line is coherent. And we want to delay that until we're
2255 sure there's a reason to make that info coherent, to avoid saving
2256 lots of useless lines. */
2258 if (finish_statement)
2259 ffelex_finish_statement_ ();
2261 /* If label is present, enclose it in a NUMBER token and send it along. */
2263 if (first_label_char != FFEWHERE_columnUNKNOWN)
2265 assert (ffelex_token_->type == FFELEX_typeNONE);
2266 ffelex_token_->type = FFELEX_typeNUMBER;
2267 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2268 strcpy (ffelex_token_->text, label_string);
2269 ffelex_token_->where_line
2270 = ffewhere_line_use (ffelex_current_wl_);
2271 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2272 ffelex_token_->length = labi;
2273 ffelex_send_token_ ();
2274 ++ffelex_label_tokens_;
2277 if (just_do_label)
2278 goto beginning_of_line; /* :::::::::::::::::::: */
2280 /* Here is the main engine for parsing. c holds the character at column.
2281 It is already known that c is not a blank, end of line, or shriek,
2282 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2283 character/hollerith constant). A partially filled token may already
2284 exist in ffelex_token_. One special case: if, when the end of the line
2285 is reached, continuation_line is FALSE and the only token on the line is
2286 END, then it is indeed the last statement. We don't look for
2287 continuation lines during this program unit in that case. This is
2288 according to ANSI. */
2290 if (ffelex_raw_mode_ != 0)
2293 parse_raw_character: /* :::::::::::::::::::: */
2295 if (c == '\0')
2297 ffewhereColumnNumber i;
2299 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2300 goto beginning_of_line; /* :::::::::::::::::::: */
2302 /* Pad out line with "virtual" spaces. */
2304 for (i = column; i < ffelex_final_nontab_column_; ++i)
2305 ffelex_card_image_[i] = ' ';
2306 ffelex_card_image_[i] = '\0';
2307 ffelex_card_length_ = i;
2308 c = ' ';
2311 switch (ffelex_raw_mode_)
2313 case -3:
2314 c = ffelex_backslash_ (c, column);
2315 if (c == EOF)
2316 break;
2318 if (!ffelex_backslash_reconsider_)
2319 ffelex_append_to_token_ (c);
2320 ffelex_raw_mode_ = -1;
2321 break;
2323 case -2:
2324 if (c == ffelex_raw_char_)
2326 ffelex_raw_mode_ = -1;
2327 ffelex_append_to_token_ (c);
2329 else
2331 ffelex_raw_mode_ = 0;
2332 ffelex_backslash_reconsider_ = TRUE;
2334 break;
2336 case -1:
2337 if (c == ffelex_raw_char_)
2338 ffelex_raw_mode_ = -2;
2339 else
2341 c = ffelex_backslash_ (c, column);
2342 if (c == EOF)
2344 ffelex_raw_mode_ = -3;
2345 break;
2348 ffelex_append_to_token_ (c);
2350 break;
2352 default:
2353 c = ffelex_backslash_ (c, column);
2354 if (c == EOF)
2355 break;
2357 if (!ffelex_backslash_reconsider_)
2359 ffelex_append_to_token_ (c);
2360 --ffelex_raw_mode_;
2362 break;
2365 if (ffelex_backslash_reconsider_)
2366 ffelex_backslash_reconsider_ = FALSE;
2367 else
2368 c = ffelex_card_image_[++column];
2370 if (ffelex_raw_mode_ == 0)
2372 ffelex_send_token_ ();
2373 assert (ffelex_raw_mode_ == 0);
2374 while (c == ' ')
2375 c = ffelex_card_image_[++column];
2376 if ((c == '\0')
2377 || (c == '!')
2378 || ((c == '/')
2379 && (ffelex_card_image_[column + 1] == '*')))
2380 goto beginning_of_line; /* :::::::::::::::::::: */
2381 goto parse_nonraw_character; /* :::::::::::::::::::: */
2383 goto parse_raw_character; /* :::::::::::::::::::: */
2386 parse_nonraw_character: /* :::::::::::::::::::: */
2388 switch (ffelex_token_->type)
2390 case FFELEX_typeNONE:
2391 switch (c)
2393 case '\"':
2394 ffelex_token_->type = FFELEX_typeQUOTE;
2395 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2396 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2397 ffelex_send_token_ ();
2398 break;
2400 case '$':
2401 ffelex_token_->type = FFELEX_typeDOLLAR;
2402 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2403 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2404 ffelex_send_token_ ();
2405 break;
2407 case '%':
2408 ffelex_token_->type = FFELEX_typePERCENT;
2409 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2410 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2411 ffelex_send_token_ ();
2412 break;
2414 case '&':
2415 ffelex_token_->type = FFELEX_typeAMPERSAND;
2416 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2417 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2418 ffelex_send_token_ ();
2419 break;
2421 case '\'':
2422 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2423 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2424 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2425 ffelex_send_token_ ();
2426 break;
2428 case '(':
2429 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2430 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2431 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2432 break;
2434 case ')':
2435 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2436 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2437 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2438 ffelex_send_token_ ();
2439 break;
2441 case '*':
2442 ffelex_token_->type = FFELEX_typeASTERISK;
2443 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2444 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2445 break;
2447 case '+':
2448 ffelex_token_->type = FFELEX_typePLUS;
2449 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2450 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2451 ffelex_send_token_ ();
2452 break;
2454 case ',':
2455 ffelex_token_->type = FFELEX_typeCOMMA;
2456 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2457 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2458 ffelex_send_token_ ();
2459 break;
2461 case '-':
2462 ffelex_token_->type = FFELEX_typeMINUS;
2463 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2464 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2465 ffelex_send_token_ ();
2466 break;
2468 case '.':
2469 ffelex_token_->type = FFELEX_typePERIOD;
2470 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2471 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2472 ffelex_send_token_ ();
2473 break;
2475 case '/':
2476 ffelex_token_->type = FFELEX_typeSLASH;
2477 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2478 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2479 break;
2481 case '0':
2482 case '1':
2483 case '2':
2484 case '3':
2485 case '4':
2486 case '5':
2487 case '6':
2488 case '7':
2489 case '8':
2490 case '9':
2491 ffelex_token_->type
2492 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2493 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2494 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2495 ffelex_append_to_token_ (c);
2496 break;
2498 case ':':
2499 ffelex_token_->type = FFELEX_typeCOLON;
2500 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2501 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2502 break;
2504 case ';':
2505 ffelex_token_->type = FFELEX_typeSEMICOLON;
2506 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2507 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2508 ffelex_permit_include_ = TRUE;
2509 ffelex_send_token_ ();
2510 ffelex_permit_include_ = FALSE;
2511 break;
2513 case '<':
2514 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2515 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2516 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2517 break;
2519 case '=':
2520 ffelex_token_->type = FFELEX_typeEQUALS;
2521 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2522 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2523 break;
2525 case '>':
2526 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2527 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2528 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2529 break;
2531 case '?':
2532 ffelex_token_->type = FFELEX_typeQUESTION;
2533 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2534 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2535 ffelex_send_token_ ();
2536 break;
2538 case '_':
2539 if (1 || ffe_is_90 ())
2541 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2542 ffelex_token_->where_line
2543 = ffewhere_line_use (ffelex_current_wl_);
2544 ffelex_token_->where_col
2545 = ffewhere_column_new (column + 1);
2546 ffelex_send_token_ ();
2547 break;
2549 /* Fall through. */
2550 case 'A':
2551 case 'B':
2552 case 'C':
2553 case 'D':
2554 case 'E':
2555 case 'F':
2556 case 'G':
2557 case 'H':
2558 case 'I':
2559 case 'J':
2560 case 'K':
2561 case 'L':
2562 case 'M':
2563 case 'N':
2564 case 'O':
2565 case 'P':
2566 case 'Q':
2567 case 'R':
2568 case 'S':
2569 case 'T':
2570 case 'U':
2571 case 'V':
2572 case 'W':
2573 case 'X':
2574 case 'Y':
2575 case 'Z':
2576 case 'a':
2577 case 'b':
2578 case 'c':
2579 case 'd':
2580 case 'e':
2581 case 'f':
2582 case 'g':
2583 case 'h':
2584 case 'i':
2585 case 'j':
2586 case 'k':
2587 case 'l':
2588 case 'm':
2589 case 'n':
2590 case 'o':
2591 case 'p':
2592 case 'q':
2593 case 'r':
2594 case 's':
2595 case 't':
2596 case 'u':
2597 case 'v':
2598 case 'w':
2599 case 'x':
2600 case 'y':
2601 case 'z':
2602 c = ffesrc_char_source (c);
2604 if (ffesrc_char_match_init (c, 'H', 'h')
2605 && ffelex_expecting_hollerith_ != 0)
2607 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2608 ffelex_token_->type = FFELEX_typeHOLLERITH;
2609 ffelex_token_->where_line = ffelex_raw_where_line_;
2610 ffelex_token_->where_col = ffelex_raw_where_col_;
2611 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2612 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2613 c = ffelex_card_image_[++column];
2614 goto parse_raw_character; /* :::::::::::::::::::: */
2617 if (ffelex_names_)
2619 ffelex_token_->where_line
2620 = ffewhere_line_use (ffelex_token_->currentnames_line
2621 = ffewhere_line_use (ffelex_current_wl_));
2622 ffelex_token_->where_col
2623 = ffewhere_column_use (ffelex_token_->currentnames_col
2624 = ffewhere_column_new (column + 1));
2625 ffelex_token_->type = FFELEX_typeNAMES;
2627 else
2629 ffelex_token_->where_line
2630 = ffewhere_line_use (ffelex_current_wl_);
2631 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2632 ffelex_token_->type = FFELEX_typeNAME;
2634 ffelex_append_to_token_ (c);
2635 break;
2637 default:
2638 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2639 ffelex_linecount_current_, column + 1);
2640 ffelex_finish_statement_ ();
2641 disallow_continuation_line = TRUE;
2642 ignore_disallowed_continuation = TRUE;
2643 goto beginning_of_line_again; /* :::::::::::::::::::: */
2645 break;
2647 case FFELEX_typeNAME:
2648 switch (c)
2650 case 'A':
2651 case 'B':
2652 case 'C':
2653 case 'D':
2654 case 'E':
2655 case 'F':
2656 case 'G':
2657 case 'H':
2658 case 'I':
2659 case 'J':
2660 case 'K':
2661 case 'L':
2662 case 'M':
2663 case 'N':
2664 case 'O':
2665 case 'P':
2666 case 'Q':
2667 case 'R':
2668 case 'S':
2669 case 'T':
2670 case 'U':
2671 case 'V':
2672 case 'W':
2673 case 'X':
2674 case 'Y':
2675 case 'Z':
2676 case 'a':
2677 case 'b':
2678 case 'c':
2679 case 'd':
2680 case 'e':
2681 case 'f':
2682 case 'g':
2683 case 'h':
2684 case 'i':
2685 case 'j':
2686 case 'k':
2687 case 'l':
2688 case 'm':
2689 case 'n':
2690 case 'o':
2691 case 'p':
2692 case 'q':
2693 case 'r':
2694 case 's':
2695 case 't':
2696 case 'u':
2697 case 'v':
2698 case 'w':
2699 case 'x':
2700 case 'y':
2701 case 'z':
2702 c = ffesrc_char_source (c);
2703 /* Fall through. */
2704 case '0':
2705 case '1':
2706 case '2':
2707 case '3':
2708 case '4':
2709 case '5':
2710 case '6':
2711 case '7':
2712 case '8':
2713 case '9':
2714 case '_':
2715 case '$':
2716 if ((c == '$')
2717 && !ffe_is_dollar_ok ())
2719 ffelex_send_token_ ();
2720 goto parse_next_character; /* :::::::::::::::::::: */
2722 ffelex_append_to_token_ (c);
2723 break;
2725 default:
2726 ffelex_send_token_ ();
2727 goto parse_next_character; /* :::::::::::::::::::: */
2729 break;
2731 case FFELEX_typeNAMES:
2732 switch (c)
2734 case 'A':
2735 case 'B':
2736 case 'C':
2737 case 'D':
2738 case 'E':
2739 case 'F':
2740 case 'G':
2741 case 'H':
2742 case 'I':
2743 case 'J':
2744 case 'K':
2745 case 'L':
2746 case 'M':
2747 case 'N':
2748 case 'O':
2749 case 'P':
2750 case 'Q':
2751 case 'R':
2752 case 'S':
2753 case 'T':
2754 case 'U':
2755 case 'V':
2756 case 'W':
2757 case 'X':
2758 case 'Y':
2759 case 'Z':
2760 case 'a':
2761 case 'b':
2762 case 'c':
2763 case 'd':
2764 case 'e':
2765 case 'f':
2766 case 'g':
2767 case 'h':
2768 case 'i':
2769 case 'j':
2770 case 'k':
2771 case 'l':
2772 case 'm':
2773 case 'n':
2774 case 'o':
2775 case 'p':
2776 case 'q':
2777 case 'r':
2778 case 's':
2779 case 't':
2780 case 'u':
2781 case 'v':
2782 case 'w':
2783 case 'x':
2784 case 'y':
2785 case 'z':
2786 c = ffesrc_char_source (c);
2787 /* Fall through. */
2788 case '0':
2789 case '1':
2790 case '2':
2791 case '3':
2792 case '4':
2793 case '5':
2794 case '6':
2795 case '7':
2796 case '8':
2797 case '9':
2798 case '_':
2799 case '$':
2800 if ((c == '$')
2801 && !ffe_is_dollar_ok ())
2803 ffelex_send_token_ ();
2804 goto parse_next_character; /* :::::::::::::::::::: */
2806 if (ffelex_token_->length < FFEWHERE_indexMAX)
2808 ffewhere_track (&ffelex_token_->currentnames_line,
2809 &ffelex_token_->currentnames_col,
2810 ffelex_token_->wheretrack,
2811 ffelex_token_->length,
2812 ffelex_linecount_current_,
2813 column + 1);
2815 ffelex_append_to_token_ (c);
2816 break;
2818 default:
2819 ffelex_send_token_ ();
2820 goto parse_next_character; /* :::::::::::::::::::: */
2822 break;
2824 case FFELEX_typeNUMBER:
2825 switch (c)
2827 case '0':
2828 case '1':
2829 case '2':
2830 case '3':
2831 case '4':
2832 case '5':
2833 case '6':
2834 case '7':
2835 case '8':
2836 case '9':
2837 ffelex_append_to_token_ (c);
2838 break;
2840 default:
2841 ffelex_send_token_ ();
2842 goto parse_next_character; /* :::::::::::::::::::: */
2844 break;
2846 case FFELEX_typeASTERISK:
2847 switch (c)
2849 case '*': /* ** */
2850 ffelex_token_->type = FFELEX_typePOWER;
2851 ffelex_send_token_ ();
2852 break;
2854 default: /* * not followed by another *. */
2855 ffelex_send_token_ ();
2856 goto parse_next_character; /* :::::::::::::::::::: */
2858 break;
2860 case FFELEX_typeCOLON:
2861 switch (c)
2863 case ':': /* :: */
2864 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2865 ffelex_send_token_ ();
2866 break;
2868 default: /* : not followed by another :. */
2869 ffelex_send_token_ ();
2870 goto parse_next_character; /* :::::::::::::::::::: */
2872 break;
2874 case FFELEX_typeSLASH:
2875 switch (c)
2877 case '/': /* // */
2878 ffelex_token_->type = FFELEX_typeCONCAT;
2879 ffelex_send_token_ ();
2880 break;
2882 case ')': /* /) */
2883 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2884 ffelex_send_token_ ();
2885 break;
2887 case '=': /* /= */
2888 ffelex_token_->type = FFELEX_typeREL_NE;
2889 ffelex_send_token_ ();
2890 break;
2892 default:
2893 ffelex_send_token_ ();
2894 goto parse_next_character; /* :::::::::::::::::::: */
2896 break;
2898 case FFELEX_typeOPEN_PAREN:
2899 switch (c)
2901 case '/': /* (/ */
2902 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2903 ffelex_send_token_ ();
2904 break;
2906 default:
2907 ffelex_send_token_ ();
2908 goto parse_next_character; /* :::::::::::::::::::: */
2910 break;
2912 case FFELEX_typeOPEN_ANGLE:
2913 switch (c)
2915 case '=': /* <= */
2916 ffelex_token_->type = FFELEX_typeREL_LE;
2917 ffelex_send_token_ ();
2918 break;
2920 default:
2921 ffelex_send_token_ ();
2922 goto parse_next_character; /* :::::::::::::::::::: */
2924 break;
2926 case FFELEX_typeEQUALS:
2927 switch (c)
2929 case '=': /* == */
2930 ffelex_token_->type = FFELEX_typeREL_EQ;
2931 ffelex_send_token_ ();
2932 break;
2934 case '>': /* => */
2935 ffelex_token_->type = FFELEX_typePOINTS;
2936 ffelex_send_token_ ();
2937 break;
2939 default:
2940 ffelex_send_token_ ();
2941 goto parse_next_character; /* :::::::::::::::::::: */
2943 break;
2945 case FFELEX_typeCLOSE_ANGLE:
2946 switch (c)
2948 case '=': /* >= */
2949 ffelex_token_->type = FFELEX_typeREL_GE;
2950 ffelex_send_token_ ();
2951 break;
2953 default:
2954 ffelex_send_token_ ();
2955 goto parse_next_character; /* :::::::::::::::::::: */
2957 break;
2959 default:
2960 assert ("Serious error!!" == NULL);
2961 abort ();
2962 break;
2965 c = ffelex_card_image_[++column];
2967 parse_next_character: /* :::::::::::::::::::: */
2969 if (ffelex_raw_mode_ != 0)
2970 goto parse_raw_character; /* :::::::::::::::::::: */
2972 while (c == ' ')
2973 c = ffelex_card_image_[++column];
2975 if ((c == '\0')
2976 || (c == '!')
2977 || ((c == '/')
2978 && (ffelex_card_image_[column + 1] == '*')))
2980 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
2981 && (ffelex_token_->type == FFELEX_typeNAMES)
2982 && (ffelex_token_->length == 3)
2983 && (ffesrc_strncmp_2c (ffe_case_match (),
2984 ffelex_token_->text,
2985 "END", "end", "End",
2987 == 0))
2989 ffelex_finish_statement_ ();
2990 disallow_continuation_line = TRUE;
2991 ignore_disallowed_continuation = FALSE;
2992 goto beginning_of_line_again; /* :::::::::::::::::::: */
2994 goto beginning_of_line; /* :::::::::::::::::::: */
2996 goto parse_nonraw_character; /* :::::::::::::::::::: */
2999 /* ffelex_file_free -- Lex a given file in free source form
3001 ffewhere wf;
3002 FILE *f;
3003 ffelex_file_free(wf,f);
3005 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3007 ffelexHandler
3008 ffelex_file_free (ffewhereFile wf, FILE *f)
3010 register int c = 0; /* Character currently under consideration. */
3011 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3012 bool continuation_line = FALSE;
3013 ffewhereColumnNumber continuation_column;
3014 int latest_char_in_file = 0; /* For getting back into comment-skipping
3015 code. */
3017 /* Lex is called for a particular file, not for a particular program unit.
3018 Yet the two events do share common characteristics. The first line in a
3019 file or in a program unit cannot be a continuation line. No token can
3020 be in mid-formation. No current label for the statement exists, since
3021 there is no current statement. */
3023 assert (ffelex_handler_ != NULL);
3025 lineno = 0;
3026 input_filename = ffewhere_file_name (wf);
3027 ffelex_current_wf_ = wf;
3028 continuation_line = FALSE;
3029 ffelex_token_->type = FFELEX_typeNONE;
3030 ffelex_number_of_tokens_ = 0;
3031 ffelex_current_wl_ = ffewhere_line_unknown ();
3032 ffelex_current_wc_ = ffewhere_column_unknown ();
3033 latest_char_in_file = '\n';
3035 /* Come here to get a new line. */
3037 beginning_of_line: /* :::::::::::::::::::: */
3039 c = latest_char_in_file;
3040 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3043 end_of_file: /* :::::::::::::::::::: */
3045 /* Line ending in EOF instead of \n still counts as a whole line. */
3047 ffelex_finish_statement_ ();
3048 ffewhere_line_kill (ffelex_current_wl_);
3049 ffewhere_column_kill (ffelex_current_wc_);
3050 return (ffelexHandler) ffelex_handler_;
3053 ffelex_next_line_ ();
3055 ffelex_bad_line_ = FALSE;
3057 /* Skip over initial-comment and empty lines as quickly as possible! */
3059 while ((c == '\n')
3060 || (c == '!')
3061 || (c == '#'))
3063 if (c == '#')
3064 c = ffelex_hash_ (f);
3066 comment_line: /* :::::::::::::::::::: */
3068 while ((c != '\n') && (c != EOF))
3069 c = getc (f);
3071 if (c == EOF)
3073 ffelex_next_line_ ();
3074 goto end_of_file; /* :::::::::::::::::::: */
3077 c = getc (f);
3079 ffelex_next_line_ ();
3081 if (c == EOF)
3082 goto end_of_file; /* :::::::::::::::::::: */
3085 ffelex_saw_tab_ = FALSE;
3087 column = ffelex_image_char_ (c, 0);
3089 /* Read the entire line in as is (with whitespace processing). */
3091 while (((c = getc (f)) != '\n') && (c != EOF))
3092 column = ffelex_image_char_ (c, column);
3094 if (ffelex_bad_line_)
3096 ffelex_card_image_[column] = '\0';
3097 ffelex_card_length_ = column;
3098 goto comment_line; /* :::::::::::::::::::: */
3101 /* If no tab, cut off line after column 132. */
3103 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3104 column = FFELEX_FREE_MAX_COLUMNS_;
3106 ffelex_card_image_[column] = '\0';
3107 ffelex_card_length_ = column;
3109 /* Save next char in file so we can use register-based c while analyzing
3110 line we just read. */
3112 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3114 column = 0;
3115 continuation_column = 0;
3117 /* Skip over initial spaces to see if the first nonblank character
3118 is exclamation point, newline, or EOF (line is therefore a comment) or
3119 ampersand (line is therefore a continuation line). */
3121 while ((c = ffelex_card_image_[column]) == ' ')
3122 ++column;
3124 switch (c)
3126 case '!':
3127 case '\0':
3128 goto beginning_of_line; /* :::::::::::::::::::: */
3130 case '&':
3131 continuation_column = column + 1;
3132 break;
3134 default:
3135 break;
3138 /* The line definitely has content of some kind, install new end-statement
3139 point for error messages. */
3141 ffewhere_line_kill (ffelex_current_wl_);
3142 ffewhere_column_kill (ffelex_current_wc_);
3143 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3144 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3146 /* Figure out which column to start parsing at. */
3148 if (continuation_line)
3150 if (continuation_column == 0)
3152 if (ffelex_raw_mode_ != 0)
3154 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3155 ffelex_linecount_current_, column + 1);
3157 else if (ffelex_token_->type != FFELEX_typeNONE)
3159 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3160 ffelex_linecount_current_, column + 1);
3163 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3164 { /* Line contains only a single "&" as only
3165 nonblank character. */
3166 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3167 ffelex_linecount_current_, continuation_column);
3168 goto beginning_of_line; /* :::::::::::::::::::: */
3170 column = continuation_column;
3172 else
3173 column = 0;
3175 c = ffelex_card_image_[column];
3176 continuation_line = FALSE;
3178 /* Here is the main engine for parsing. c holds the character at column.
3179 It is already known that c is not a blank, end of line, or shriek,
3180 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3181 character/hollerith constant). A partially filled token may already
3182 exist in ffelex_token_. */
3184 if (ffelex_raw_mode_ != 0)
3187 parse_raw_character: /* :::::::::::::::::::: */
3189 switch (c)
3191 case '&':
3192 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3194 continuation_line = TRUE;
3195 goto beginning_of_line; /* :::::::::::::::::::: */
3197 break;
3199 case '\0':
3200 ffelex_finish_statement_ ();
3201 goto beginning_of_line; /* :::::::::::::::::::: */
3203 default:
3204 break;
3207 switch (ffelex_raw_mode_)
3209 case -3:
3210 c = ffelex_backslash_ (c, column);
3211 if (c == EOF)
3212 break;
3214 if (!ffelex_backslash_reconsider_)
3215 ffelex_append_to_token_ (c);
3216 ffelex_raw_mode_ = -1;
3217 break;
3219 case -2:
3220 if (c == ffelex_raw_char_)
3222 ffelex_raw_mode_ = -1;
3223 ffelex_append_to_token_ (c);
3225 else
3227 ffelex_raw_mode_ = 0;
3228 ffelex_backslash_reconsider_ = TRUE;
3230 break;
3232 case -1:
3233 if (c == ffelex_raw_char_)
3234 ffelex_raw_mode_ = -2;
3235 else
3237 c = ffelex_backslash_ (c, column);
3238 if (c == EOF)
3240 ffelex_raw_mode_ = -3;
3241 break;
3244 ffelex_append_to_token_ (c);
3246 break;
3248 default:
3249 c = ffelex_backslash_ (c, column);
3250 if (c == EOF)
3251 break;
3253 if (!ffelex_backslash_reconsider_)
3255 ffelex_append_to_token_ (c);
3256 --ffelex_raw_mode_;
3258 break;
3261 if (ffelex_backslash_reconsider_)
3262 ffelex_backslash_reconsider_ = FALSE;
3263 else
3264 c = ffelex_card_image_[++column];
3266 if (ffelex_raw_mode_ == 0)
3268 ffelex_send_token_ ();
3269 assert (ffelex_raw_mode_ == 0);
3270 while (c == ' ')
3271 c = ffelex_card_image_[++column];
3272 if ((c == '\0') || (c == '!'))
3274 ffelex_finish_statement_ ();
3275 goto beginning_of_line; /* :::::::::::::::::::: */
3277 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3279 continuation_line = TRUE;
3280 goto beginning_of_line; /* :::::::::::::::::::: */
3282 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3284 goto parse_raw_character; /* :::::::::::::::::::: */
3287 parse_nonraw_character: /* :::::::::::::::::::: */
3289 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3291 continuation_line = TRUE;
3292 goto beginning_of_line; /* :::::::::::::::::::: */
3295 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3297 switch (ffelex_token_->type)
3299 case FFELEX_typeNONE:
3300 if (c == ' ')
3301 { /* Otherwise
3302 finish-statement/continue-statement
3303 already checked. */
3304 while (c == ' ')
3305 c = ffelex_card_image_[++column];
3306 if ((c == '\0') || (c == '!'))
3308 ffelex_finish_statement_ ();
3309 goto beginning_of_line; /* :::::::::::::::::::: */
3311 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3313 continuation_line = TRUE;
3314 goto beginning_of_line; /* :::::::::::::::::::: */
3318 switch (c)
3320 case '\"':
3321 ffelex_token_->type = FFELEX_typeQUOTE;
3322 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3323 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3324 ffelex_send_token_ ();
3325 break;
3327 case '$':
3328 ffelex_token_->type = FFELEX_typeDOLLAR;
3329 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3330 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3331 ffelex_send_token_ ();
3332 break;
3334 case '%':
3335 ffelex_token_->type = FFELEX_typePERCENT;
3336 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3337 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3338 ffelex_send_token_ ();
3339 break;
3341 case '&':
3342 ffelex_token_->type = FFELEX_typeAMPERSAND;
3343 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3344 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3345 ffelex_send_token_ ();
3346 break;
3348 case '\'':
3349 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3350 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3351 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3352 ffelex_send_token_ ();
3353 break;
3355 case '(':
3356 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3357 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3358 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3359 break;
3361 case ')':
3362 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3363 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3364 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3365 ffelex_send_token_ ();
3366 break;
3368 case '*':
3369 ffelex_token_->type = FFELEX_typeASTERISK;
3370 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3371 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3372 break;
3374 case '+':
3375 ffelex_token_->type = FFELEX_typePLUS;
3376 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3377 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3378 ffelex_send_token_ ();
3379 break;
3381 case ',':
3382 ffelex_token_->type = FFELEX_typeCOMMA;
3383 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3384 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3385 ffelex_send_token_ ();
3386 break;
3388 case '-':
3389 ffelex_token_->type = FFELEX_typeMINUS;
3390 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3391 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3392 ffelex_send_token_ ();
3393 break;
3395 case '.':
3396 ffelex_token_->type = FFELEX_typePERIOD;
3397 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3398 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3399 ffelex_send_token_ ();
3400 break;
3402 case '/':
3403 ffelex_token_->type = FFELEX_typeSLASH;
3404 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3405 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3406 break;
3408 case '0':
3409 case '1':
3410 case '2':
3411 case '3':
3412 case '4':
3413 case '5':
3414 case '6':
3415 case '7':
3416 case '8':
3417 case '9':
3418 ffelex_token_->type
3419 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3420 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3421 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3422 ffelex_append_to_token_ (c);
3423 break;
3425 case ':':
3426 ffelex_token_->type = FFELEX_typeCOLON;
3427 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3428 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3429 break;
3431 case ';':
3432 ffelex_token_->type = FFELEX_typeSEMICOLON;
3433 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3434 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3435 ffelex_permit_include_ = TRUE;
3436 ffelex_send_token_ ();
3437 ffelex_permit_include_ = FALSE;
3438 break;
3440 case '<':
3441 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3442 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3443 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3444 break;
3446 case '=':
3447 ffelex_token_->type = FFELEX_typeEQUALS;
3448 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3449 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3450 break;
3452 case '>':
3453 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3454 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3455 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3456 break;
3458 case '?':
3459 ffelex_token_->type = FFELEX_typeQUESTION;
3460 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3461 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3462 ffelex_send_token_ ();
3463 break;
3465 case '_':
3466 if (1 || ffe_is_90 ())
3468 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3469 ffelex_token_->where_line
3470 = ffewhere_line_use (ffelex_current_wl_);
3471 ffelex_token_->where_col
3472 = ffewhere_column_new (column + 1);
3473 ffelex_send_token_ ();
3474 break;
3476 /* Fall through. */
3477 case 'A':
3478 case 'B':
3479 case 'C':
3480 case 'D':
3481 case 'E':
3482 case 'F':
3483 case 'G':
3484 case 'H':
3485 case 'I':
3486 case 'J':
3487 case 'K':
3488 case 'L':
3489 case 'M':
3490 case 'N':
3491 case 'O':
3492 case 'P':
3493 case 'Q':
3494 case 'R':
3495 case 'S':
3496 case 'T':
3497 case 'U':
3498 case 'V':
3499 case 'W':
3500 case 'X':
3501 case 'Y':
3502 case 'Z':
3503 case 'a':
3504 case 'b':
3505 case 'c':
3506 case 'd':
3507 case 'e':
3508 case 'f':
3509 case 'g':
3510 case 'h':
3511 case 'i':
3512 case 'j':
3513 case 'k':
3514 case 'l':
3515 case 'm':
3516 case 'n':
3517 case 'o':
3518 case 'p':
3519 case 'q':
3520 case 'r':
3521 case 's':
3522 case 't':
3523 case 'u':
3524 case 'v':
3525 case 'w':
3526 case 'x':
3527 case 'y':
3528 case 'z':
3529 c = ffesrc_char_source (c);
3531 if (ffesrc_char_match_init (c, 'H', 'h')
3532 && ffelex_expecting_hollerith_ != 0)
3534 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3535 ffelex_token_->type = FFELEX_typeHOLLERITH;
3536 ffelex_token_->where_line = ffelex_raw_where_line_;
3537 ffelex_token_->where_col = ffelex_raw_where_col_;
3538 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3539 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3540 c = ffelex_card_image_[++column];
3541 goto parse_raw_character; /* :::::::::::::::::::: */
3544 if (ffelex_names_pure_)
3546 ffelex_token_->where_line
3547 = ffewhere_line_use (ffelex_token_->currentnames_line
3548 = ffewhere_line_use (ffelex_current_wl_));
3549 ffelex_token_->where_col
3550 = ffewhere_column_use (ffelex_token_->currentnames_col
3551 = ffewhere_column_new (column + 1));
3552 ffelex_token_->type = FFELEX_typeNAMES;
3554 else
3556 ffelex_token_->where_line
3557 = ffewhere_line_use (ffelex_current_wl_);
3558 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3559 ffelex_token_->type = FFELEX_typeNAME;
3561 ffelex_append_to_token_ (c);
3562 break;
3564 default:
3565 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3566 ffelex_linecount_current_, column + 1);
3567 ffelex_finish_statement_ ();
3568 goto beginning_of_line; /* :::::::::::::::::::: */
3570 break;
3572 case FFELEX_typeNAME:
3573 switch (c)
3575 case 'A':
3576 case 'B':
3577 case 'C':
3578 case 'D':
3579 case 'E':
3580 case 'F':
3581 case 'G':
3582 case 'H':
3583 case 'I':
3584 case 'J':
3585 case 'K':
3586 case 'L':
3587 case 'M':
3588 case 'N':
3589 case 'O':
3590 case 'P':
3591 case 'Q':
3592 case 'R':
3593 case 'S':
3594 case 'T':
3595 case 'U':
3596 case 'V':
3597 case 'W':
3598 case 'X':
3599 case 'Y':
3600 case 'Z':
3601 case 'a':
3602 case 'b':
3603 case 'c':
3604 case 'd':
3605 case 'e':
3606 case 'f':
3607 case 'g':
3608 case 'h':
3609 case 'i':
3610 case 'j':
3611 case 'k':
3612 case 'l':
3613 case 'm':
3614 case 'n':
3615 case 'o':
3616 case 'p':
3617 case 'q':
3618 case 'r':
3619 case 's':
3620 case 't':
3621 case 'u':
3622 case 'v':
3623 case 'w':
3624 case 'x':
3625 case 'y':
3626 case 'z':
3627 c = ffesrc_char_source (c);
3628 /* Fall through. */
3629 case '0':
3630 case '1':
3631 case '2':
3632 case '3':
3633 case '4':
3634 case '5':
3635 case '6':
3636 case '7':
3637 case '8':
3638 case '9':
3639 case '_':
3640 case '$':
3641 if ((c == '$')
3642 && !ffe_is_dollar_ok ())
3644 ffelex_send_token_ ();
3645 goto parse_next_character; /* :::::::::::::::::::: */
3647 ffelex_append_to_token_ (c);
3648 break;
3650 default:
3651 ffelex_send_token_ ();
3652 goto parse_next_character; /* :::::::::::::::::::: */
3654 break;
3656 case FFELEX_typeNAMES:
3657 switch (c)
3659 case 'A':
3660 case 'B':
3661 case 'C':
3662 case 'D':
3663 case 'E':
3664 case 'F':
3665 case 'G':
3666 case 'H':
3667 case 'I':
3668 case 'J':
3669 case 'K':
3670 case 'L':
3671 case 'M':
3672 case 'N':
3673 case 'O':
3674 case 'P':
3675 case 'Q':
3676 case 'R':
3677 case 'S':
3678 case 'T':
3679 case 'U':
3680 case 'V':
3681 case 'W':
3682 case 'X':
3683 case 'Y':
3684 case 'Z':
3685 case 'a':
3686 case 'b':
3687 case 'c':
3688 case 'd':
3689 case 'e':
3690 case 'f':
3691 case 'g':
3692 case 'h':
3693 case 'i':
3694 case 'j':
3695 case 'k':
3696 case 'l':
3697 case 'm':
3698 case 'n':
3699 case 'o':
3700 case 'p':
3701 case 'q':
3702 case 'r':
3703 case 's':
3704 case 't':
3705 case 'u':
3706 case 'v':
3707 case 'w':
3708 case 'x':
3709 case 'y':
3710 case 'z':
3711 c = ffesrc_char_source (c);
3712 /* Fall through. */
3713 case '0':
3714 case '1':
3715 case '2':
3716 case '3':
3717 case '4':
3718 case '5':
3719 case '6':
3720 case '7':
3721 case '8':
3722 case '9':
3723 case '_':
3724 case '$':
3725 if ((c == '$')
3726 && !ffe_is_dollar_ok ())
3728 ffelex_send_token_ ();
3729 goto parse_next_character; /* :::::::::::::::::::: */
3731 if (ffelex_token_->length < FFEWHERE_indexMAX)
3733 ffewhere_track (&ffelex_token_->currentnames_line,
3734 &ffelex_token_->currentnames_col,
3735 ffelex_token_->wheretrack,
3736 ffelex_token_->length,
3737 ffelex_linecount_current_,
3738 column + 1);
3740 ffelex_append_to_token_ (c);
3741 break;
3743 default:
3744 ffelex_send_token_ ();
3745 goto parse_next_character; /* :::::::::::::::::::: */
3747 break;
3749 case FFELEX_typeNUMBER:
3750 switch (c)
3752 case '0':
3753 case '1':
3754 case '2':
3755 case '3':
3756 case '4':
3757 case '5':
3758 case '6':
3759 case '7':
3760 case '8':
3761 case '9':
3762 ffelex_append_to_token_ (c);
3763 break;
3765 default:
3766 ffelex_send_token_ ();
3767 goto parse_next_character; /* :::::::::::::::::::: */
3769 break;
3771 case FFELEX_typeASTERISK:
3772 switch (c)
3774 case '*': /* ** */
3775 ffelex_token_->type = FFELEX_typePOWER;
3776 ffelex_send_token_ ();
3777 break;
3779 default: /* * not followed by another *. */
3780 ffelex_send_token_ ();
3781 goto parse_next_character; /* :::::::::::::::::::: */
3783 break;
3785 case FFELEX_typeCOLON:
3786 switch (c)
3788 case ':': /* :: */
3789 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3790 ffelex_send_token_ ();
3791 break;
3793 default: /* : not followed by another :. */
3794 ffelex_send_token_ ();
3795 goto parse_next_character; /* :::::::::::::::::::: */
3797 break;
3799 case FFELEX_typeSLASH:
3800 switch (c)
3802 case '/': /* // */
3803 ffelex_token_->type = FFELEX_typeCONCAT;
3804 ffelex_send_token_ ();
3805 break;
3807 case ')': /* /) */
3808 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3809 ffelex_send_token_ ();
3810 break;
3812 case '=': /* /= */
3813 ffelex_token_->type = FFELEX_typeREL_NE;
3814 ffelex_send_token_ ();
3815 break;
3817 default:
3818 ffelex_send_token_ ();
3819 goto parse_next_character; /* :::::::::::::::::::: */
3821 break;
3823 case FFELEX_typeOPEN_PAREN:
3824 switch (c)
3826 case '/': /* (/ */
3827 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3828 ffelex_send_token_ ();
3829 break;
3831 default:
3832 ffelex_send_token_ ();
3833 goto parse_next_character; /* :::::::::::::::::::: */
3835 break;
3837 case FFELEX_typeOPEN_ANGLE:
3838 switch (c)
3840 case '=': /* <= */
3841 ffelex_token_->type = FFELEX_typeREL_LE;
3842 ffelex_send_token_ ();
3843 break;
3845 default:
3846 ffelex_send_token_ ();
3847 goto parse_next_character; /* :::::::::::::::::::: */
3849 break;
3851 case FFELEX_typeEQUALS:
3852 switch (c)
3854 case '=': /* == */
3855 ffelex_token_->type = FFELEX_typeREL_EQ;
3856 ffelex_send_token_ ();
3857 break;
3859 case '>': /* => */
3860 ffelex_token_->type = FFELEX_typePOINTS;
3861 ffelex_send_token_ ();
3862 break;
3864 default:
3865 ffelex_send_token_ ();
3866 goto parse_next_character; /* :::::::::::::::::::: */
3868 break;
3870 case FFELEX_typeCLOSE_ANGLE:
3871 switch (c)
3873 case '=': /* >= */
3874 ffelex_token_->type = FFELEX_typeREL_GE;
3875 ffelex_send_token_ ();
3876 break;
3878 default:
3879 ffelex_send_token_ ();
3880 goto parse_next_character; /* :::::::::::::::::::: */
3882 break;
3884 default:
3885 assert ("Serious error!" == NULL);
3886 abort ();
3887 break;
3890 c = ffelex_card_image_[++column];
3892 parse_next_character: /* :::::::::::::::::::: */
3894 if (ffelex_raw_mode_ != 0)
3895 goto parse_raw_character; /* :::::::::::::::::::: */
3897 if ((c == '\0') || (c == '!'))
3899 ffelex_finish_statement_ ();
3900 goto beginning_of_line; /* :::::::::::::::::::: */
3902 goto parse_nonraw_character; /* :::::::::::::::::::: */
3905 /* See the code in com.c that calls this to understand why. */
3907 void
3908 ffelex_hash_kludge (FILE *finput)
3910 /* If you change this constant string, you have to change whatever
3911 code might thus be affected by it in terms of having to use
3912 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3913 static char match[] = "# 1 \"";
3914 static int kludge[ARRAY_SIZE (match) + 1];
3915 int c;
3916 char *p;
3917 int *q;
3919 /* Read chars as long as they match the target string.
3920 Copy them into an array that will serve as a record
3921 of what we read (essentially a multi-char ungetc(),
3922 for code that uses ffelex_getc_ instead of getc() elsewhere
3923 in the lexer. */
3924 for (p = &match[0], q = &kludge[0], c = getc (finput);
3925 (c == *p) && (*p != '\0') && (c != EOF);
3926 ++p, ++q, c = getc (finput))
3927 *q = c;
3929 *q = c; /* Might be EOF, which requires int. */
3930 *++q = 0;
3932 ffelex_kludge_chars_ = &kludge[0];
3934 if (*p == 0)
3936 ffelex_kludge_flag_ = TRUE;
3937 ++ffelex_kludge_chars_;
3938 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
3939 ffelex_kludge_flag_ = FALSE;
3943 void
3944 ffelex_init_1 ()
3946 unsigned int i;
3948 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
3949 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
3950 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
3951 "FFELEX card image",
3952 FFELEX_columnINITIAL_SIZE_ + 9);
3953 ffelex_card_image_[0] = '\0';
3955 for (i = 0; i < 256; ++i)
3956 ffelex_first_char_[i] = FFELEX_typeERROR;
3958 ffelex_first_char_['\t'] = FFELEX_typeRAW;
3959 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
3960 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
3961 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
3962 ffelex_first_char_['\r'] = FFELEX_typeRAW;
3963 ffelex_first_char_[' '] = FFELEX_typeRAW;
3964 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
3965 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
3966 ffelex_first_char_['/'] = FFELEX_typeSLASH;
3967 ffelex_first_char_['&'] = FFELEX_typeRAW;
3968 ffelex_first_char_['#'] = FFELEX_typeHASH;
3970 for (i = '0'; i <= '9'; ++i)
3971 ffelex_first_char_[i] = FFELEX_typeRAW;
3973 if ((ffe_case_match () == FFE_caseNONE)
3974 || ((ffe_case_match () == FFE_caseUPPER)
3975 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
3976 || ((ffe_case_match () == FFE_caseLOWER)
3977 && (ffe_case_source () == FFE_caseLOWER)))
3979 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
3980 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
3982 if ((ffe_case_match () == FFE_caseNONE)
3983 || ((ffe_case_match () == FFE_caseLOWER)
3984 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
3985 || ((ffe_case_match () == FFE_caseUPPER)
3986 && (ffe_case_source () == FFE_caseUPPER)))
3988 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
3989 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
3992 ffelex_linecount_current_ = 0;
3993 ffelex_linecount_next_ = 1;
3994 ffelex_raw_mode_ = 0;
3995 ffelex_set_include_ = FALSE;
3996 ffelex_permit_include_ = FALSE;
3997 ffelex_names_ = TRUE; /* First token in program is a names. */
3998 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
3999 FORMAT. */
4000 ffelex_hexnum_ = FALSE;
4001 ffelex_expecting_hollerith_ = 0;
4002 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4003 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4005 ffelex_token_ = ffelex_token_new_ ();
4006 ffelex_token_->type = FFELEX_typeNONE;
4007 ffelex_token_->uses = 1;
4008 ffelex_token_->where_line = ffewhere_line_unknown ();
4009 ffelex_token_->where_col = ffewhere_column_unknown ();
4010 ffelex_token_->text = NULL;
4012 ffelex_handler_ = NULL;
4015 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4017 if (ffelex_is_names_expected())
4018 // Deliver NAMES token
4019 else
4020 // Deliver NAME token
4022 Must be called while lexer is active, obviously. */
4024 bool
4025 ffelex_is_names_expected ()
4027 return ffelex_names_;
4030 /* Current card image, which has the master linecount number
4031 ffelex_linecount_current_. */
4033 char *
4034 ffelex_line ()
4036 return ffelex_card_image_;
4039 /* ffelex_line_length -- Return length of current lexer line
4041 printf("Length is %lu\n",ffelex_line_length());
4043 Must be called while lexer is active, obviously. */
4045 ffewhereColumnNumber
4046 ffelex_line_length ()
4048 return ffelex_card_length_;
4051 /* Master line count of current card image, or 0 if no card image
4052 is current. */
4054 ffewhereLineNumber
4055 ffelex_line_number ()
4057 return ffelex_linecount_current_;
4060 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4062 ffelex_set_expecting_hollerith(0);
4064 Lex initially assumes no hollerith constant is about to show up. If
4065 syntactic analysis expects one, it should call this function with the
4066 number of characters expected in the constant immediately after recognizing
4067 the decimal number preceding the "H" and the constant itself. Then, if
4068 the next character is indeed H, the lexer will interpret it as beginning
4069 a hollerith constant and ship the token formed by reading the specified
4070 number of characters (interpreting blanks and otherwise-comments too)
4071 from the input file. It is up to syntactic analysis to call this routine
4072 again with 0 to turn hollerith detection off immediately upon receiving
4073 the token that might or might not be HOLLERITH.
4075 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4076 character constant. Pass the expected termination character (apostrophe
4077 or quote).
4079 Pass for length either the length of the hollerith (must be > 0), -1
4080 meaning expecting a character constant, or 0 to cancel expectation of
4081 a hollerith only after calling it with a length of > 0 and receiving the
4082 next token (which may or may not have been a HOLLERITH token).
4084 Pass for which either an apostrophe or quote when passing length of -1.
4085 Else which is a don't-care.
4087 Pass for line and column the line/column info for the token beginning the
4088 character or hollerith constant, for use in error messages, when passing
4089 a length of -1 -- this function will invoke ffewhere_line/column_use to
4090 make its own copies. Else line and column are don't-cares (when length
4091 is 0) and the outstanding copies of the previous line/column info, if
4092 still around, are killed.
4094 21-Feb-90 JCB 3.1
4095 When called with length of 0, also zero ffelex_raw_mode_. This is
4096 so ffest_save_ can undo the effects of replaying tokens like
4097 APOSTROPHE and QUOTE.
4098 25-Jan-90 JCB 3.0
4099 New line, column arguments allow error messages to point to the true
4100 beginning of a character/hollerith constant, rather than the beginning
4101 of the content part, which makes them more consistent and helpful.
4102 05-Nov-89 JCB 2.0
4103 New "which" argument allows caller to specify termination character,
4104 which should be apostrophe or double-quote, to support Fortran 90. */
4106 void
4107 ffelex_set_expecting_hollerith (long length, char which,
4108 ffewhereLine line, ffewhereColumn column)
4111 /* First kill the pending line/col info, if any (should only be pending
4112 when this call has length==0, the previous call had length>0, and a
4113 non-HOLLERITH token was sent in between the calls, but play it safe). */
4115 ffewhere_line_kill (ffelex_raw_where_line_);
4116 ffewhere_column_kill (ffelex_raw_where_col_);
4118 /* Now handle the length function. */
4119 switch (length)
4121 case 0:
4122 ffelex_expecting_hollerith_ = 0;
4123 ffelex_raw_mode_ = 0;
4124 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4125 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4126 return; /* Don't set new line/column info from args. */
4128 case -1:
4129 ffelex_raw_mode_ = -1;
4130 ffelex_raw_char_ = which;
4131 break;
4133 default: /* length > 0 */
4134 ffelex_expecting_hollerith_ = length;
4135 break;
4138 /* Now set new line/column information from passed args. */
4140 ffelex_raw_where_line_ = ffewhere_line_use (line);
4141 ffelex_raw_where_col_ = ffewhere_column_use (column);
4144 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4146 ffelex_set_handler((ffelexHandler) my_first_handler);
4148 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4149 after they return, but not while they are active. */
4151 void
4152 ffelex_set_handler (ffelexHandler first)
4154 ffelex_handler_ = first;
4157 /* ffelex_set_hexnum -- Set hexnum flag
4159 ffelex_set_hexnum(TRUE);
4161 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4162 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4163 the character as the first of the next token. But when parsing a
4164 hexadecimal number, by calling this function with TRUE before starting
4165 the parse of the token itself, lex will interpret [0-9] as the start
4166 of a NAME token. */
4168 void
4169 ffelex_set_hexnum (bool f)
4171 ffelex_hexnum_ = f;
4174 /* ffelex_set_include -- Set INCLUDE file to be processed next
4176 ffewhereFile wf; // The ffewhereFile object for the file.
4177 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4178 FILE *fi; // The file to INCLUDE.
4179 ffelex_set_include(wf,free_form,fi);
4181 Must be called only after receiving the EOS token following a valid
4182 INCLUDE statement specifying a file that has already been successfully
4183 opened. */
4185 void
4186 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4188 assert (ffelex_permit_include_);
4189 assert (!ffelex_set_include_);
4190 ffelex_set_include_ = TRUE;
4191 ffelex_include_free_form_ = free_form;
4192 ffelex_include_file_ = fi;
4193 ffelex_include_wherefile_ = wf;
4196 /* ffelex_set_names -- Set names/name flag, names = TRUE
4198 ffelex_set_names(FALSE);
4200 Lex initially assumes multiple names should be formed. If this function is
4201 called with FALSE, then single names are formed instead. The differences
4202 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4203 and in whether full source-location tracking is performed (it is for
4204 multiple names, not for single names), which is more expensive in terms of
4205 CPU time. */
4207 void
4208 ffelex_set_names (bool f)
4210 ffelex_names_ = f;
4211 if (!f)
4212 ffelex_names_pure_ = FALSE;
4215 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4217 ffelex_set_names_pure(FALSE);
4219 Like ffelex_set_names, except affects both lexers. Normally, the
4220 free-form lexer need not generate NAMES tokens because adjacent NAME
4221 tokens must be separated by spaces which causes the lexer to generate
4222 separate tokens for analysis (whereas in fixed-form the spaces are
4223 ignored resulting in one long token). But in FORMAT statements, for
4224 some reason, the Fortran 90 standard specifies that spaces can occur
4225 anywhere within a format-item-list with no effect on the format spec
4226 (except of course within character string edit descriptors), which means
4227 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4228 statement handling, the existence of spaces makes it hard to deal with,
4229 because each token is seen distinctly (i.e. seven tokens in the latter
4230 example). But when no spaces are provided, as in the former example,
4231 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4232 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4233 One, ffest_kw_format_ does a substring rather than full-string match,
4234 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4235 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4236 and three, error reporting can point to the actual character rather than
4237 at or prior to it. The first two things could be resolved by providing
4238 alternate functions fairly easy, thus allowing FORMAT handling to expect
4239 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4240 changes to FORMAT parsing), but the third, error reporting, would suffer,
4241 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4242 to exactly where the compilers thinks the problem is, to even begin to get
4243 a handle on it. So there. */
4245 void
4246 ffelex_set_names_pure (bool f)
4248 ffelex_names_pure_ = f;
4249 ffelex_names_ = f;
4252 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4254 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4255 start_char_index);
4257 Returns first_handler if start_char_index chars into master_token (which
4258 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4259 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4260 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4261 and sends it to first_handler. If anything other than NAME is sent, the
4262 character at the end of it in the master token is examined to see if it
4263 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4264 the handler returned by first_handler is invoked with that token, and
4265 this process is repeated until the end of the master token or a NAME
4266 token is reached. */
4268 ffelexHandler
4269 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4270 ffeTokenLength start)
4272 unsigned char *p;
4273 ffeTokenLength i;
4274 ffelexToken t;
4276 p = ffelex_token_text (master) + (i = start);
4278 while (*p != '\0')
4280 if (ISDIGIT (*p))
4282 t = ffelex_token_number_from_names (master, i);
4283 p += ffelex_token_length (t);
4284 i += ffelex_token_length (t);
4286 else if (ffesrc_is_name_init (*p))
4288 t = ffelex_token_name_from_names (master, i, 0);
4289 p += ffelex_token_length (t);
4290 i += ffelex_token_length (t);
4292 else if (*p == '$')
4294 t = ffelex_token_dollar_from_names (master, i);
4295 ++p;
4296 ++i;
4298 else if (*p == '_')
4300 t = ffelex_token_uscore_from_names (master, i);
4301 ++p;
4302 ++i;
4304 else
4306 assert ("not a valid NAMES character" == NULL);
4307 t = NULL;
4309 assert (first != NULL);
4310 first = (ffelexHandler) (*first) (t);
4311 ffelex_token_kill (t);
4314 return first;
4317 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4319 return ffelex_swallow_tokens;
4321 Return this handler when you don't want to look at any more tokens in the
4322 statement because you've encountered an unrecoverable error in the
4323 statement. */
4325 ffelexHandler
4326 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4328 assert (handler != NULL);
4330 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4331 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4332 return (ffelexHandler) (*handler) (t);
4334 ffelex_eos_handler_ = handler;
4335 return (ffelexHandler) ffelex_swallow_tokens_;
4338 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4340 ffelexToken t;
4341 t = ffelex_token_dollar_from_names(t,6);
4343 It's as if you made a new token of dollar type having the dollar
4344 at, in the example above, the sixth character of the NAMES token. */
4346 ffelexToken
4347 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4349 ffelexToken nt;
4351 assert (t != NULL);
4352 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4353 assert (start < t->length);
4354 assert (t->text[start] == '$');
4356 /* Now make the token. */
4358 nt = ffelex_token_new_ ();
4359 nt->type = FFELEX_typeDOLLAR;
4360 nt->length = 0;
4361 nt->uses = 1;
4362 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4363 t->where_col, t->wheretrack, start);
4364 nt->text = NULL;
4365 return nt;
4368 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4370 ffelexToken t;
4371 ffelex_token_kill(t);
4373 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4375 void
4376 ffelex_token_kill (ffelexToken t)
4378 assert (t != NULL);
4380 assert (t->uses > 0);
4382 if (--t->uses != 0)
4383 return;
4385 --ffelex_total_tokens_;
4387 if (t->type == FFELEX_typeNAMES)
4388 ffewhere_track_kill (t->where_line, t->where_col,
4389 t->wheretrack, t->length);
4390 ffewhere_line_kill (t->where_line);
4391 ffewhere_column_kill (t->where_col);
4392 if (t->text != NULL)
4393 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4394 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4397 /* Make a new NAME token that is a substring of a NAMES token. */
4399 ffelexToken
4400 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4401 ffeTokenLength len)
4403 ffelexToken nt;
4405 assert (t != NULL);
4406 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4407 assert (start < t->length);
4408 if (len == 0)
4409 len = t->length - start;
4410 else
4412 assert (len > 0);
4413 assert ((start + len) <= t->length);
4415 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4417 nt = ffelex_token_new_ ();
4418 nt->type = FFELEX_typeNAME;
4419 nt->size = len; /* Assume nobody's gonna fiddle with token
4420 text. */
4421 nt->length = len;
4422 nt->uses = 1;
4423 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4424 t->where_col, t->wheretrack, start);
4425 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4426 len + 1);
4427 strncpy (nt->text, t->text + start, len);
4428 nt->text[len] = '\0';
4429 return nt;
4432 /* Make a new NAMES token that is a substring of another NAMES token. */
4434 ffelexToken
4435 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4436 ffeTokenLength len)
4438 ffelexToken nt;
4440 assert (t != NULL);
4441 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4442 assert (start < t->length);
4443 if (len == 0)
4444 len = t->length - start;
4445 else
4447 assert (len > 0);
4448 assert ((start + len) <= t->length);
4450 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4452 nt = ffelex_token_new_ ();
4453 nt->type = FFELEX_typeNAMES;
4454 nt->size = len; /* Assume nobody's gonna fiddle with token
4455 text. */
4456 nt->length = len;
4457 nt->uses = 1;
4458 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4459 t->where_col, t->wheretrack, start);
4460 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4461 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4462 len + 1);
4463 strncpy (nt->text, t->text + start, len);
4464 nt->text[len] = '\0';
4465 return nt;
4468 /* Make a new CHARACTER token. */
4470 ffelexToken
4471 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4473 ffelexToken t;
4475 t = ffelex_token_new_ ();
4476 t->type = FFELEX_typeCHARACTER;
4477 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4478 t->uses = 1;
4479 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4480 t->size + 1);
4481 strcpy (t->text, s);
4482 t->where_line = ffewhere_line_use (l);
4483 t->where_col = ffewhere_column_new (c);
4484 return t;
4487 /* Make a new EOF token right after end of file. */
4489 ffelexToken
4490 ffelex_token_new_eof ()
4492 ffelexToken t;
4494 t = ffelex_token_new_ ();
4495 t->type = FFELEX_typeEOF;
4496 t->uses = 1;
4497 t->text = NULL;
4498 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4499 t->where_col = ffewhere_column_new (1);
4500 return t;
4503 /* Make a new NAME token. */
4505 ffelexToken
4506 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4508 ffelexToken t;
4510 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4512 t = ffelex_token_new_ ();
4513 t->type = FFELEX_typeNAME;
4514 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4515 t->uses = 1;
4516 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4517 t->size + 1);
4518 strcpy (t->text, s);
4519 t->where_line = ffewhere_line_use (l);
4520 t->where_col = ffewhere_column_new (c);
4521 return t;
4524 /* Make a new NAMES token. */
4526 ffelexToken
4527 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4529 ffelexToken t;
4531 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4533 t = ffelex_token_new_ ();
4534 t->type = FFELEX_typeNAMES;
4535 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4536 t->uses = 1;
4537 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4538 t->size + 1);
4539 strcpy (t->text, s);
4540 t->where_line = ffewhere_line_use (l);
4541 t->where_col = ffewhere_column_new (c);
4542 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4543 names. */
4544 return t;
4547 /* Make a new NUMBER token.
4549 The first character of the string must be a digit, and only the digits
4550 are copied into the new number. So this may be used to easily extract
4551 a NUMBER token from within any text string. Then the length of the
4552 resulting token may be used to calculate where the digits stopped
4553 in the original string. */
4555 ffelexToken
4556 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4558 ffelexToken t;
4559 ffeTokenLength len;
4561 /* How long is the string of decimal digits at s? */
4563 len = strspn (s, "0123456789");
4565 /* Make sure there is at least one digit. */
4567 assert (len != 0);
4569 /* Now make the token. */
4571 t = ffelex_token_new_ ();
4572 t->type = FFELEX_typeNUMBER;
4573 t->length = t->size = len; /* Assume it won't get bigger. */
4574 t->uses = 1;
4575 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4576 len + 1);
4577 strncpy (t->text, s, len);
4578 t->text[len] = '\0';
4579 t->where_line = ffewhere_line_use (l);
4580 t->where_col = ffewhere_column_new (c);
4581 return t;
4584 /* Make a new token of any type that doesn't contain text. A private
4585 function that is used by public macros in the interface file. */
4587 ffelexToken
4588 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4590 ffelexToken t;
4592 t = ffelex_token_new_ ();
4593 t->type = type;
4594 t->uses = 1;
4595 t->text = NULL;
4596 t->where_line = ffewhere_line_use (l);
4597 t->where_col = ffewhere_column_new (c);
4598 return t;
4601 /* Make a new NUMBER token from an existing NAMES token.
4603 Like ffelex_token_new_number, this function calculates the length
4604 of the digit string itself. */
4606 ffelexToken
4607 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4609 ffelexToken nt;
4610 ffeTokenLength len;
4612 assert (t != NULL);
4613 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4614 assert (start < t->length);
4616 /* How long is the string of decimal digits at s? */
4618 len = strspn (t->text + start, "0123456789");
4620 /* Make sure there is at least one digit. */
4622 assert (len != 0);
4624 /* Now make the token. */
4626 nt = ffelex_token_new_ ();
4627 nt->type = FFELEX_typeNUMBER;
4628 nt->size = len; /* Assume nobody's gonna fiddle with token
4629 text. */
4630 nt->length = len;
4631 nt->uses = 1;
4632 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4633 t->where_col, t->wheretrack, start);
4634 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4635 len + 1);
4636 strncpy (nt->text, t->text + start, len);
4637 nt->text[len] = '\0';
4638 return nt;
4641 /* Make a new UNDERSCORE token from a NAMES token. */
4643 ffelexToken
4644 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4646 ffelexToken nt;
4648 assert (t != NULL);
4649 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4650 assert (start < t->length);
4651 assert (t->text[start] == '_');
4653 /* Now make the token. */
4655 nt = ffelex_token_new_ ();
4656 nt->type = FFELEX_typeUNDERSCORE;
4657 nt->uses = 1;
4658 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4659 t->where_col, t->wheretrack, start);
4660 nt->text = NULL;
4661 return nt;
4664 /* ffelex_token_use -- Return another instance of a token
4666 ffelexToken t;
4667 t = ffelex_token_use(t);
4669 In a sense, the new token is a copy of the old, though it might be the
4670 same with just a new use count.
4672 We use the use count method (easy). */
4674 ffelexToken
4675 ffelex_token_use (ffelexToken t)
4677 if (t == NULL)
4678 assert ("_token_use: null token" == NULL);
4679 t->uses++;
4680 return t;