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)
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
29 #if FFECOM_targetCURRENT == FFECOM_targetGCC
37 #ifdef DWARF_DEBUGGING_INFO
41 static void ffelex_append_to_token_ (char c);
42 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
43 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
44 ffewhereColumnNumber cn0);
45 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
46 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
47 ffewhereColumnNumber cn1);
48 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
49 ffewhereColumnNumber cn0);
50 static void ffelex_finish_statement_ (void);
51 #if FFECOM_targetCURRENT == FFECOM_targetGCC
52 static int ffelex_get_directive_line_ (char **text, FILE *finput);
53 static int ffelex_hash_ (FILE *f);
55 static ffewhereColumnNumber ffelex_image_char_ (int c,
56 ffewhereColumnNumber col);
57 static void ffelex_include_ (void);
58 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
59 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
60 static void ffelex_next_line_ (void);
61 static void ffelex_prepare_eos_ (void);
62 static void ffelex_send_token_ (void);
63 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
64 static ffelexToken ffelex_token_new_ (void);
66 /* Pertaining to the geometry of the input file. */
68 /* Initial size for card image to be allocated. */
69 #define FFELEX_columnINITIAL_SIZE_ 255
71 /* The card image itself, which grows as source lines get longer. It
72 has room for ffelex_card_size_ + 8 characters, and the length of the
73 current image is ffelex_card_length_. (The + 8 characters are made
74 available for easy handling of tabs and such.) */
75 static char *ffelex_card_image_;
76 static ffewhereColumnNumber ffelex_card_size_;
77 static ffewhereColumnNumber ffelex_card_length_;
79 /* Max width for free-form lines (ISO F90). */
80 #define FFELEX_FREE_MAX_COLUMNS_ 132
82 /* True if we saw a tab on the current line, as this (currently) means
83 the line is therefore treated as though final_nontab_column_ were
85 static bool ffelex_saw_tab_;
87 /* TRUE if current line is known to be erroneous, so don't bother
88 expanding room for it just to display it. */
89 static bool ffelex_bad_line_ = FALSE;
91 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
92 static ffewhereColumnNumber ffelex_final_nontab_column_;
94 /* Array for quickly deciding what kind of line the current card has,
95 based on its first character. */
96 static ffelexType ffelex_first_char_[256];
98 /* Pertaining to file management. */
100 /* The wf argument of the most recent active ffelex_file_(fixed,free)
102 static ffewhereFile ffelex_current_wf_;
104 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
106 static bool ffelex_permit_include_;
108 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
110 static bool ffelex_set_include_;
112 /* Information on the pending INCLUDE file. */
113 static FILE *ffelex_include_file_;
114 static bool ffelex_include_free_form_;
115 static ffewhereFile ffelex_include_wherefile_;
117 /* Current master line count. */
118 static ffewhereLineNumber ffelex_linecount_current_;
119 /* Next master line count. */
120 static ffewhereLineNumber ffelex_linecount_next_;
122 /* ffewhere info on the latest (currently active) line read from the
123 active source file. */
124 static ffewhereLine ffelex_current_wl_;
125 static ffewhereColumn ffelex_current_wc_;
127 /* Pertaining to tokens in general. */
129 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
131 #define FFELEX_columnTOKEN_SIZE_ 63
132 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
133 #error "token size too small!"
136 /* Current token being lexed. */
137 static ffelexToken ffelex_token_;
139 /* Handler for current token. */
140 static ffelexHandler ffelex_handler_;
142 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
143 static bool ffelex_names_;
145 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
146 static bool ffelex_names_pure_;
148 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
150 static bool ffelex_hexnum_;
152 /* For ffelex_swallow_tokens(). */
153 static ffelexHandler ffelex_eos_handler_;
155 /* Number of tokens sent since last EOS or beginning of input file
156 (include INCLUDEd files). */
157 static unsigned long int ffelex_number_of_tokens_;
159 /* Number of labels sent (as NUMBER tokens) since last reset of
160 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
161 (Fixed-form source only.) */
162 static unsigned long int ffelex_label_tokens_;
164 /* Metering for token management, to catch token-memory leaks. */
165 static long int ffelex_total_tokens_ = 0;
166 static long int ffelex_old_total_tokens_ = 1;
167 static long int ffelex_token_nextid_ = 0;
169 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
171 /* >0 if a Hollerith constant of that length might be in mid-lex, used
172 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
173 mode (see ffelex_raw_mode_). */
174 static long int ffelex_expecting_hollerith_;
176 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
177 -2: Possible closing apostrophe/quote seen in CHARACTER.
178 -1: Lexing CHARACTER.
179 0: Not lexing CHARACTER or HOLLERITH.
180 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
181 static long int ffelex_raw_mode_;
183 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
184 static char ffelex_raw_char_;
186 /* TRUE when backslash processing had to use most recent character
187 to finish its state engine, but that character is not part of
188 the backslash sequence, so must be reconsidered as a "normal"
189 character in CHARACTER/HOLLERITH lexing. */
190 static bool ffelex_backslash_reconsider_ = FALSE;
192 /* Characters preread before lexing happened (might include EOF). */
193 static int *ffelex_kludge_chars_ = NULL;
195 /* Doing the kludge processing, so not initialized yet. */
196 static bool ffelex_kludge_flag_ = FALSE;
198 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
199 static ffewhereLine ffelex_raw_where_line_;
200 static ffewhereColumn ffelex_raw_where_col_;
203 /* Call this to append another character to the current token. If it isn't
204 currently big enough for it, it will be enlarged. The current token
205 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
208 ffelex_append_to_token_ (char c)
210 if (ffelex_token_->text == NULL)
213 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
214 FFELEX_columnTOKEN_SIZE_ + 1);
215 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
216 ffelex_token_->length = 0;
218 else if (ffelex_token_->length >= ffelex_token_->size)
221 = malloc_resize_ksr (malloc_pool_image (),
223 (ffelex_token_->size << 1) + 1,
224 ffelex_token_->size + 1);
225 ffelex_token_->size <<= 1;
226 assert (ffelex_token_->length < ffelex_token_->size);
229 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
230 please contact fortran@gnu.org if you wish to fund work to
231 port g77 to non-ASCII machines.
233 ffelex_token_->text[ffelex_token_->length++] = c;
236 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
240 ffelex_backslash_ (int c, ffewhereColumnNumber col)
242 static int state = 0;
243 static unsigned int count;
245 static unsigned int firstdig = 0;
247 static ffewhereLineNumber line;
248 static ffewhereColumnNumber column;
250 /* See gcc/c-lex.c readescape() for a straightforward version
251 of this state engine for handling backslashes in character/
252 hollerith constants. */
255 #define warn_traditional 0
256 #define flag_traditional 0
262 && (ffelex_raw_mode_ != 0)
263 && ffe_is_backslash ())
267 line = ffelex_linecount_current_;
273 state = 0; /* Assume simple case. */
277 if (warn_traditional)
279 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
280 FFEBAD_severityWARNING);
281 ffelex_bad_here_ (0, line, column);
285 if (flag_traditional)
294 case '0': case '1': case '2': case '3': case '4':
295 case '5': case '6': case '7':
301 case '\\': case '\'': case '"':
304 #if 0 /* Inappropriate for Fortran. */
306 ffelex_next_line_ ();
312 return TARGET_NEWLINE;
327 if (warn_traditional)
329 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
330 FFEBAD_severityWARNING);
331 ffelex_bad_here_ (0, line, column);
335 if (flag_traditional)
340 #if 0 /* Vertical tab is present in common usage compilers. */
341 if (flag_traditional)
358 ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
359 FFEBAD_severityPEDANTIC);
360 ffelex_bad_here_ (0, line, column);
364 return (c == 'E' || c == 'e') ? 033 : c;
370 if (c >= 040 && c < 0177)
376 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
377 FFEBAD_severityPEDANTIC);
378 ffelex_bad_here_ (0, line, column);
384 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
385 FFEBAD_severityPEDANTIC);
386 ffelex_bad_here_ (0, line, column);
393 sprintf (&m[0], "%x", c);
394 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
395 FFEBAD_severityPEDANTIC);
396 ffelex_bad_here_ (0, line, column);
404 if ((c >= 'a' && c <= 'f')
405 || (c >= 'A' && c <= 'F')
406 || (c >= '0' && c <= '9'))
409 if (c >= 'a' && c <= 'f')
410 code += c - 'a' + 10;
411 if (c >= 'A' && c <= 'F')
412 code += c - 'A' + 10;
413 if (c >= '0' && c <= '9')
415 if (code != 0 || count != 0)
429 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
430 FFEBAD_severityFATAL);
431 ffelex_bad_here_ (0, line, column);
435 /* Digits are all 0's. Ok. */
437 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
439 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
442 ffebad_start_msg_lex ("Hex escape at %0 out of range",
443 FFEBAD_severityPEDANTIC);
444 ffelex_bad_here_ (0, line, column);
450 if ((c <= '7') && (c >= '0') && (count++ < 3))
452 code = (code * 8) + (c - '0');
459 assert ("bad backslash state" == NULL);
463 /* Come here when code has a built character, and c is the next
464 character that might (or might not) be the next one in the constant. */
466 /* Don't bother doing this check for each character going into
467 CHARACTER or HOLLERITH constants, just the escaped-value ones.
468 gcc apparently checks every single character, which seems
469 like it'd be kinda slow and not worth doing anyway. */
472 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
473 && code >= (1 << TYPE_PRECISION (char_type_node)))
475 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
476 FFEBAD_severityFATAL);
477 ffelex_bad_here_ (0, line, column);
483 /* Known end of constant, just append this character. */
484 ffelex_append_to_token_ (code);
485 if (ffelex_raw_mode_ > 0)
490 /* Have two characters to handle. Do the first, then leave it to the
491 caller to detect anything special about the second. */
493 ffelex_append_to_token_ (code);
494 if (ffelex_raw_mode_ > 0)
496 ffelex_backslash_reconsider_ = TRUE;
500 /* ffelex_bad_1_ -- Issue diagnostic with one source point
502 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
504 Creates ffewhere line and column objects for the source point, sends them
505 along with the error code to ffebad, then kills the line and column
506 objects before returning. */
509 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
514 wl0 = ffewhere_line_new (ln0);
515 wc0 = ffewhere_column_new (cn0);
516 ffebad_start_lex (errnum);
517 ffebad_here (0, wl0, wc0);
519 ffewhere_line_kill (wl0);
520 ffewhere_column_kill (wc0);
523 /* ffelex_bad_2_ -- Issue diagnostic with two source points
525 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
526 otherline,othercolumn);
528 Creates ffewhere line and column objects for the source points, sends them
529 along with the error code to ffebad, then kills the line and column
530 objects before returning. */
533 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
534 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
536 ffewhereLine wl0, wl1;
537 ffewhereColumn wc0, wc1;
539 wl0 = ffewhere_line_new (ln0);
540 wc0 = ffewhere_column_new (cn0);
541 wl1 = ffewhere_line_new (ln1);
542 wc1 = ffewhere_column_new (cn1);
543 ffebad_start_lex (errnum);
544 ffebad_here (0, wl0, wc0);
545 ffebad_here (1, wl1, wc1);
547 ffewhere_line_kill (wl0);
548 ffewhere_column_kill (wc0);
549 ffewhere_line_kill (wl1);
550 ffewhere_column_kill (wc1);
554 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
555 ffewhereColumnNumber cn0)
560 wl0 = ffewhere_line_new (ln0);
561 wc0 = ffewhere_column_new (cn0);
562 ffebad_here (n, wl0, wc0);
563 ffewhere_line_kill (wl0);
564 ffewhere_column_kill (wc0);
567 #if FFECOM_targetCURRENT == FFECOM_targetGCC
569 ffelex_getc_ (FILE *finput)
573 if (ffelex_kludge_chars_ == NULL)
574 return getc (finput);
576 c = *ffelex_kludge_chars_++;
580 ffelex_kludge_chars_ = NULL;
581 return getc (finput);
585 #if FFECOM_targetCURRENT == FFECOM_targetGCC
587 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
589 register int c = getc (finput);
591 register unsigned count;
592 unsigned firstdig = 0;
600 if (warn_traditional)
601 warning ("the meaning of `\\x' varies with -traditional");
603 if (flag_traditional)
612 if (!(c >= 'a' && c <= 'f')
613 && !(c >= 'A' && c <= 'F')
614 && !(c >= '0' && c <= '9'))
621 if (c >= 'a' && c <= 'f')
622 code += c - 'a' + 10;
623 if (c >= 'A' && c <= 'F')
624 code += c - 'A' + 10;
625 if (c >= '0' && c <= '9')
627 if (code != 0 || count != 0)
636 error ("\\x used with no following hex digits");
638 /* Digits are all 0's. Ok. */
640 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
643 << (TYPE_PRECISION (integer_type_node) - (count - 1)
646 pedwarn ("hex escape out of range");
649 case '0': case '1': case '2': case '3': case '4':
650 case '5': case '6': case '7':
653 while ((c <= '7') && (c >= '0') && (count++ < 3))
655 code = (code * 8) + (c - '0');
662 case '\\': case '\'': case '"':
666 ffelex_next_line_ ();
676 return TARGET_NEWLINE;
691 if (warn_traditional)
692 warning ("the meaning of `\\a' varies with -traditional");
694 if (flag_traditional)
699 #if 0 /* Vertical tab is present in common usage compilers. */
700 if (flag_traditional)
708 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
714 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
718 /* `\%' is used to prevent SCCS from getting confused. */
721 pedwarn ("non-ANSI escape sequence `\\%c'", c);
724 if (c >= 040 && c < 0177)
725 pedwarn ("unknown escape sequence `\\%c'", c);
727 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
732 /* A miniature version of the C front-end lexer. */
734 #if FFECOM_targetCURRENT == FFECOM_targetGCC
736 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
743 register unsigned buffer_length;
745 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
746 ffelex_token_kill (*xtoken);
750 case '0': case '1': case '2': case '3': case '4':
751 case '5': case '6': case '7': case '8': case '9':
752 buffer_length = ARRAY_SIZE (buff);
755 r = &buff[buffer_length];
761 register unsigned bytes_used = (p - q);
764 q = (char *)xrealloc (q, buffer_length);
766 r = &q[buffer_length];
768 c = ffelex_getc_ (finput);
773 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
774 ffewhere_column_unknown ());
782 buffer_length = ARRAY_SIZE (buff);
785 r = &buff[buffer_length];
786 c = ffelex_getc_ (finput);
800 case '\\': /* ~~~~~ */
801 c = ffelex_cfebackslash_ (&use_d, &d, finput);
806 error ("Badly formed directive -- no closing quote");
816 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
821 register unsigned bytes_used = (p - q);
823 buffer_length = bytes_used * 2;
824 q = (char *)xrealloc (q, buffer_length);
826 r = &q[buffer_length];
835 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
836 ffewhere_column_unknown ());
853 #if FFECOM_targetCURRENT == FFECOM_targetGCC
855 ffelex_file_pop_ (const char *input_filename)
857 if (input_file_stack->next)
859 struct file_stack *p = input_file_stack;
860 input_file_stack = p->next;
862 input_file_stack_tick++;
863 #ifdef DWARF_DEBUGGING_INFO
864 if (debug_info_level == DINFO_LEVEL_VERBOSE
865 && write_symbols == DWARF_DEBUG)
866 dwarfout_resume_previous_source_file (input_file_stack->line);
867 #endif /* DWARF_DEBUGGING_INFO */
870 error ("#-lines for entering and leaving files don't match");
872 /* Now that we've pushed or popped the input stack,
873 update the name in the top element. */
874 if (input_file_stack)
875 input_file_stack->name = input_filename;
879 #if FFECOM_targetCURRENT == FFECOM_targetGCC
881 ffelex_file_push_ (int old_lineno, const char *input_filename)
884 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
886 input_file_stack->line = old_lineno;
887 p->next = input_file_stack;
888 p->name = input_filename;
889 input_file_stack = p;
890 input_file_stack_tick++;
891 #ifdef DWARF_DEBUGGING_INFO
892 if (debug_info_level == DINFO_LEVEL_VERBOSE
893 && write_symbols == DWARF_DEBUG)
894 dwarfout_start_new_source_file (input_filename);
895 #endif /* DWARF_DEBUGGING_INFO */
897 /* Now that we've pushed or popped the input stack,
898 update the name in the top element. */
899 if (input_file_stack)
900 input_file_stack->name = input_filename;
904 /* Prepare to finish a statement-in-progress by sending the current
905 token, if any, then setting up EOS as the current token with the
906 appropriate current pointer. The caller can then move the current
907 pointer before actually sending EOS, if desired, as it is in
908 typical fixed-form cases. */
911 ffelex_prepare_eos_ ()
913 if (ffelex_token_->type != FFELEX_typeNONE)
915 ffelex_backslash_ (EOF, 0);
917 switch (ffelex_raw_mode_)
923 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
924 : FFEBAD_NO_CLOSING_QUOTE);
925 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
926 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
937 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
938 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
939 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
940 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
943 /* Make sure the token has some text, might as well fill up with spaces. */
946 ffelex_append_to_token_ (' ');
947 } while (--ffelex_raw_mode_ > 0);
951 ffelex_raw_mode_ = 0;
952 ffelex_send_token_ ();
954 ffelex_token_->type = FFELEX_typeEOS;
955 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
956 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
960 ffelex_finish_statement_ ()
962 if ((ffelex_number_of_tokens_ == 0)
963 && (ffelex_token_->type == FFELEX_typeNONE))
964 return; /* Don't have a statement pending. */
966 if (ffelex_token_->type != FFELEX_typeEOS)
967 ffelex_prepare_eos_ ();
969 ffelex_permit_include_ = TRUE;
970 ffelex_send_token_ ();
971 ffelex_permit_include_ = FALSE;
972 ffelex_number_of_tokens_ = 0;
973 ffelex_label_tokens_ = 0;
974 ffelex_names_ = TRUE;
975 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
976 ffelex_hexnum_ = FALSE;
978 if (!ffe_is_ffedebug ())
981 /* For debugging purposes only. */
983 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
985 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
986 ffelex_old_total_tokens_, ffelex_total_tokens_);
987 ffelex_old_total_tokens_ = ffelex_total_tokens_;
991 /* Copied from gcc/c-common.c get_directive_line. */
993 #if FFECOM_targetCURRENT == FFECOM_targetGCC
995 ffelex_get_directive_line_ (char **text, FILE *finput)
997 static char *directive_buffer = NULL;
998 static unsigned buffer_length = 0;
1000 register char *buffer_limit;
1001 register int looking_for = 0;
1002 register int char_escaped = 0;
1004 if (buffer_length == 0)
1006 directive_buffer = (char *)xmalloc (128);
1007 buffer_length = 128;
1010 buffer_limit = &directive_buffer[buffer_length];
1012 for (p = directive_buffer; ; )
1016 /* Make buffer bigger if it is full. */
1017 if (p >= buffer_limit)
1019 register unsigned bytes_used = (p - directive_buffer);
1023 = (char *)xrealloc (directive_buffer, buffer_length);
1024 p = &directive_buffer[bytes_used];
1025 buffer_limit = &directive_buffer[buffer_length];
1030 /* Discard initial whitespace. */
1031 if ((c == ' ' || c == '\t') && p == directive_buffer)
1034 /* Detect the end of the directive. */
1035 if ((c == '\n' && looking_for == 0)
1038 if (looking_for != 0)
1039 error ("Bad directive -- missing close-quote");
1042 *text = directive_buffer;
1048 ffelex_next_line_ ();
1050 /* Handle string and character constant syntax. */
1053 if (looking_for == c && !char_escaped)
1054 looking_for = 0; /* Found terminator... stop looking. */
1057 if (c == '\'' || c == '"')
1058 looking_for = c; /* Don't stop buffering until we see another
1059 one of these (or an EOF). */
1061 /* Handle backslash. */
1062 char_escaped = (c == '\\' && ! char_escaped);
1067 /* Handle # directives that make it through (or are generated by) the
1068 preprocessor. As much as reasonably possible, emulate the behavior
1069 of the gcc compiler phase cc1, though interactions between #include
1070 and INCLUDE might possibly produce bizarre results in terms of
1071 error reporting and the generation of debugging info vis-a-vis the
1072 locations of some things.
1074 Returns the next character unhandled, which is always newline or EOF. */
1076 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1078 #if defined HANDLE_PRAGMA
1079 /* Local versions of these macros, that can be passed as function pointers. */
1083 return getc (finput);
1090 ungetc (arg, finput);
1092 #endif /* HANDLE_PRAGMA */
1095 ffelex_hash_ (FILE *finput)
1098 ffelexToken token = NULL;
1100 /* Read first nonwhite char after the `#'. */
1102 c = ffelex_getc_ (finput);
1103 while (c == ' ' || c == '\t')
1104 c = ffelex_getc_ (finput);
1106 /* If a letter follows, then if the word here is `line', skip
1107 it and ignore it; otherwise, ignore the line, with an error
1108 if the word isn't `pragma', `ident', `define', or `undef'. */
1110 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
1114 if (getc (finput) == 'r'
1115 && getc (finput) == 'a'
1116 && getc (finput) == 'g'
1117 && getc (finput) == 'm'
1118 && getc (finput) == 'a'
1119 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1122 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1123 static char buffer [128];
1124 char * buff = buffer;
1126 /* Read the pragma name into a buffer.
1127 ISSPACE() may evaluate its argument more than once! */
1128 while (((c = getc (finput)), ISSPACE(c)))
1136 while (c != EOF && ! ISSPACE (c) && c != '\n'
1137 && buff < buffer + 128);
1142 #ifdef HANDLE_PRAGMA
1143 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1145 #endif /* HANDLE_PRAGMA */
1146 #ifdef HANDLE_GENERIC_PRAGMAS
1147 if (handle_generic_pragma (buffer))
1149 #endif /* !HANDLE_GENERIC_PRAGMAS */
1151 /* Issue a warning message if we have been asked to do so.
1152 Ignoring unknown pragmas in system header file unless
1153 an explcit -Wunknown-pragmas has been given. */
1154 if (warn_unknown_pragmas > 1
1155 || (warn_unknown_pragmas && ! in_system_header))
1156 warning ("ignoring pragma: %s", token_buffer);
1164 if (getc (finput) == 'e'
1165 && getc (finput) == 'f'
1166 && getc (finput) == 'i'
1167 && getc (finput) == 'n'
1168 && getc (finput) == 'e'
1169 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1174 c = ffelex_get_directive_line_ (&text, finput);
1176 #ifdef DWARF_DEBUGGING_INFO
1177 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1178 && (write_symbols == DWARF_DEBUG))
1179 dwarfout_define (lineno, text);
1180 #endif /* DWARF_DEBUGGING_INFO */
1187 if (getc (finput) == 'n'
1188 && getc (finput) == 'd'
1189 && getc (finput) == 'e'
1190 && getc (finput) == 'f'
1191 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1196 c = ffelex_get_directive_line_ (&text, finput);
1198 #ifdef DWARF_DEBUGGING_INFO
1199 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1200 && (write_symbols == DWARF_DEBUG))
1201 dwarfout_undef (lineno, text);
1202 #endif /* DWARF_DEBUGGING_INFO */
1209 if (getc (finput) == 'i'
1210 && getc (finput) == 'n'
1211 && getc (finput) == 'e'
1212 && ((c = getc (finput)) == ' ' || c == '\t'))
1217 if (getc (finput) == 'd'
1218 && getc (finput) == 'e'
1219 && getc (finput) == 'n'
1220 && getc (finput) == 't'
1221 && ((c = getc (finput)) == ' ' || c == '\t'))
1223 /* #ident. The pedantic warning is now in cpp. */
1225 /* Here we have just seen `#ident '.
1226 A string constant should follow. */
1228 while (c == ' ' || c == '\t')
1231 /* If no argument, ignore the line. */
1232 if (c == '\n' || c == EOF)
1235 c = ffelex_cfelex_ (&token, finput, c);
1238 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1240 error ("invalid #ident");
1244 if (! flag_no_ident)
1246 #ifdef ASM_OUTPUT_IDENT
1247 ASM_OUTPUT_IDENT (asm_out_file,
1248 ffelex_token_text (token));
1252 /* Skip the rest of this line. */
1257 error ("undefined or invalid # directive");
1262 /* Here we have either `#line' or `# <nonletter>'.
1263 In either case, it should be a line number; a digit should follow. */
1265 while (c == ' ' || c == '\t')
1266 c = ffelex_getc_ (finput);
1268 /* If the # is the only nonwhite char on the line,
1269 just ignore it. Check the new newline. */
1270 if (c == '\n' || c == EOF)
1273 /* Something follows the #; read a token. */
1275 c = ffelex_cfelex_ (&token, finput, c);
1278 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1280 int old_lineno = lineno;
1281 const char *old_input_filename = input_filename;
1284 /* subtract one, because it is the following line that
1285 gets the specified number */
1286 int l = atoi (ffelex_token_text (token)) - 1;
1288 /* Is this the last nonwhite stuff on the line? */
1289 while (c == ' ' || c == '\t')
1290 c = ffelex_getc_ (finput);
1291 if (c == '\n' || c == EOF)
1293 /* No more: store the line number and check following line. */
1295 if (!ffelex_kludge_flag_)
1297 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1300 ffelex_token_kill (token);
1305 /* More follows: it must be a string constant (filename). */
1307 /* Read the string constant. */
1308 c = ffelex_cfelex_ (&token, finput, c);
1311 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1313 error ("invalid #line");
1319 if (ffelex_kludge_flag_)
1320 input_filename = ggc_strdup (ffelex_token_text (token));
1323 wf = ffewhere_file_new (ffelex_token_text (token),
1324 ffelex_token_length (token));
1325 input_filename = ffewhere_file_name (wf);
1326 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1329 #if 0 /* Not sure what g77 should do with this yet. */
1330 /* Each change of file name
1331 reinitializes whether we are now in a system header. */
1332 in_system_header = 0;
1335 if (main_input_filename == 0)
1336 main_input_filename = input_filename;
1338 /* Is this the last nonwhite stuff on the line? */
1339 while (c == ' ' || c == '\t')
1341 if (c == '\n' || c == EOF)
1343 if (!ffelex_kludge_flag_)
1345 /* Update the name in the top element of input_file_stack. */
1346 if (input_file_stack)
1347 input_file_stack->name = input_filename;
1350 ffelex_token_kill (token);
1355 c = ffelex_cfelex_ (&token, finput, c);
1357 /* `1' after file name means entering new file.
1358 `2' after file name means just left a file. */
1361 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1363 int num = atoi (ffelex_token_text (token));
1365 if (ffelex_kludge_flag_)
1368 input_filename = old_input_filename;
1369 error ("Use `#line ...' instead of `# ...' in first line");
1374 /* Pushing to a new file. */
1375 ffelex_file_push_ (old_lineno, input_filename);
1379 /* Popping out of a file. */
1380 ffelex_file_pop_ (input_filename);
1383 /* Is this the last nonwhite stuff on the line? */
1384 while (c == ' ' || c == '\t')
1386 if (c == '\n' || c == EOF)
1389 ffelex_token_kill (token);
1393 c = ffelex_cfelex_ (&token, finput, c);
1396 /* `3' after file name means this is a system header file. */
1398 #if 0 /* Not sure what g77 should do with this yet. */
1400 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1401 && (atoi (ffelex_token_text (token)) == 3))
1402 in_system_header = 1;
1405 while (c == ' ' || c == '\t')
1407 if (((token != NULL)
1408 || (c != '\n' && c != EOF))
1409 && ffelex_kludge_flag_)
1412 input_filename = old_input_filename;
1413 error ("Use `#line ...' instead of `# ...' in first line");
1415 if (c == '\n' || c == EOF)
1417 if (token != NULL && !ffelex_kludge_flag_)
1418 ffelex_token_kill (token);
1423 error ("invalid #-line");
1425 /* skip the rest of this line. */
1427 if ((token != NULL) && !ffelex_kludge_flag_)
1428 ffelex_token_kill (token);
1429 while ((c = getc (finput)) != EOF && c != '\n')
1433 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1435 /* "Image" a character onto the card image, return incremented column number.
1437 Normally invoking this function as in
1438 column = ffelex_image_char_ (c, column);
1439 is the same as doing:
1440 ffelex_card_image_[column++] = c;
1442 However, tabs and carriage returns are handled specially, to preserve
1443 the visual "image" of the input line (in most editors) in the card
1446 Carriage returns are ignored, as they are assumed to be followed
1449 A tab is handled by first doing:
1450 ffelex_card_image_[column++] = ' ';
1451 That is, it translates to at least one space. Then, as many spaces
1452 are imaged as necessary to bring the column number to the next tab
1453 position, where tab positions start in the ninth column and each
1454 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1455 is set to TRUE to notify the lexer that a tab was seen.
1457 Columns are numbered and tab stops set as illustrated below:
1459 012345670123456701234567...
1463 xxxxxxx yyyyyyy zzzzzzz
1464 xxxxxxxx yyyyyyyy... */
1466 static ffewhereColumnNumber
1467 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1469 ffewhereColumnNumber old_column = column;
1471 if (column >= ffelex_card_size_)
1473 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1475 if (ffelex_bad_line_)
1478 if ((newmax >> 1) != ffelex_card_size_)
1479 { /* Overflowed column number. */
1480 overflow: /* :::::::::::::::::::: */
1482 ffelex_bad_line_ = TRUE;
1483 strcpy (&ffelex_card_image_[column - 3], "...");
1484 ffelex_card_length_ = column;
1485 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1486 ffelex_linecount_current_, column + 1);
1491 = malloc_resize_ksr (malloc_pool_image (),
1494 ffelex_card_size_ + 9);
1495 ffelex_card_size_ = newmax;
1504 ffelex_saw_tab_ = TRUE;
1505 ffelex_card_image_[column++] = ' ';
1506 while ((column & 7) != 0)
1507 ffelex_card_image_[column++] = ' ';
1511 if (!ffelex_bad_line_)
1513 ffelex_bad_line_ = TRUE;
1514 strcpy (&ffelex_card_image_[column], "[\\0]");
1515 ffelex_card_length_ = column + 4;
1516 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1517 FFEBAD_severityFATAL);
1518 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1525 ffelex_card_image_[column++] = c;
1529 if (column < old_column)
1531 column = old_column;
1532 goto overflow; /* :::::::::::::::::::: */
1541 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1542 FILE *include_file = ffelex_include_file_;
1543 /* The rest of this is to push, and after the INCLUDE file is processed,
1544 pop, the static lexer state info that pertains to each particular
1547 ffewhereColumnNumber card_size = ffelex_card_size_;
1548 ffewhereColumnNumber card_length = ffelex_card_length_;
1549 ffewhereLine current_wl = ffelex_current_wl_;
1550 ffewhereColumn current_wc = ffelex_current_wc_;
1551 bool saw_tab = ffelex_saw_tab_;
1552 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1553 ffewhereFile current_wf = ffelex_current_wf_;
1554 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1555 ffewhereLineNumber linecount_offset
1556 = ffewhere_line_filelinenum (current_wl);
1557 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1558 int old_lineno = lineno;
1559 const char *old_input_filename = input_filename;
1562 if (card_length != 0)
1564 card_image = malloc_new_ks (malloc_pool_image (),
1565 "FFELEX saved card image",
1567 memcpy (card_image, ffelex_card_image_, card_length);
1572 ffelex_set_include_ = FALSE;
1574 ffelex_next_line_ ();
1576 ffewhere_file_set (include_wherefile, TRUE, 0);
1578 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1579 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1580 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1582 if (ffelex_include_free_form_)
1583 ffelex_file_free (include_wherefile, include_file);
1585 ffelex_file_fixed (include_wherefile, include_file);
1587 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1588 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1589 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1591 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1593 ffecom_close_include (include_file);
1595 if (card_length != 0)
1597 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1598 #error "need to handle possible reduction of card size here!!"
1600 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1601 memcpy (ffelex_card_image_, card_image, card_length);
1603 ffelex_card_image_[card_length] = '\0';
1605 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1606 input_filename = old_input_filename;
1607 lineno = old_lineno;
1609 ffelex_linecount_current_ = linecount_current;
1610 ffelex_current_wf_ = current_wf;
1611 ffelex_final_nontab_column_ = final_nontab_column;
1612 ffelex_saw_tab_ = saw_tab;
1613 ffelex_current_wc_ = current_wc;
1614 ffelex_current_wl_ = current_wl;
1615 ffelex_card_length_ = card_length;
1616 ffelex_card_size_ = card_size;
1619 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1621 ffewhereColumnNumber col;
1622 int c; // Char at col.
1623 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1624 // We have a continuation indicator.
1626 If there are <n> spaces starting at ffelex_card_image_[col] up through
1627 the null character, where <n> is 0 or greater, returns TRUE. */
1630 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1632 while (ffelex_card_image_[col] != '\0')
1634 if (ffelex_card_image_[col++] != ' ')
1640 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1642 ffewhereColumnNumber col;
1643 int c; // Char at col.
1644 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1645 // We have a continuation indicator.
1647 If there are <n> spaces starting at ffelex_card_image_[col] up through
1648 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1651 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1653 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1655 if (ffelex_card_image_[col++] != ' ')
1662 ffelex_next_line_ ()
1664 ffelex_linecount_current_ = ffelex_linecount_next_;
1665 ++ffelex_linecount_next_;
1666 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1672 ffelex_send_token_ ()
1674 ++ffelex_number_of_tokens_;
1676 ffelex_backslash_ (EOF, 0);
1678 if (ffelex_token_->text == NULL)
1680 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1682 ffelex_append_to_token_ ('\0');
1683 ffelex_token_->length = 0;
1687 ffelex_token_->text[ffelex_token_->length] = '\0';
1689 assert (ffelex_raw_mode_ == 0);
1691 if (ffelex_token_->type == FFELEX_typeNAMES)
1693 ffewhere_line_kill (ffelex_token_->currentnames_line);
1694 ffewhere_column_kill (ffelex_token_->currentnames_col);
1697 assert (ffelex_handler_ != NULL);
1698 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1699 assert (ffelex_handler_ != NULL);
1701 ffelex_token_kill (ffelex_token_);
1703 ffelex_token_ = ffelex_token_new_ ();
1704 ffelex_token_->uses = 1;
1705 ffelex_token_->text = NULL;
1706 if (ffelex_raw_mode_ < 0)
1708 ffelex_token_->type = FFELEX_typeCHARACTER;
1709 ffelex_token_->where_line = ffelex_raw_where_line_;
1710 ffelex_token_->where_col = ffelex_raw_where_col_;
1711 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1712 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1716 ffelex_token_->type = FFELEX_typeNONE;
1717 ffelex_token_->where_line = ffewhere_line_unknown ();
1718 ffelex_token_->where_col = ffewhere_column_unknown ();
1721 if (ffelex_set_include_)
1725 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1727 return ffelex_swallow_tokens_;
1729 Return this handler when you don't want to look at any more tokens in the
1730 statement because you've encountered an unrecoverable error in the
1733 static ffelexHandler
1734 ffelex_swallow_tokens_ (ffelexToken t)
1736 assert (ffelex_eos_handler_ != NULL);
1738 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1739 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1740 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1742 return (ffelexHandler) ffelex_swallow_tokens_;
1746 ffelex_token_new_ ()
1750 ++ffelex_total_tokens_;
1752 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1753 "FFELEX token", sizeof (*t));
1754 t->id_ = ffelex_token_nextid_++;
1759 ffelex_type_string_ (ffelexType type)
1761 static const char *types[] = {
1763 "FFELEX_typeCOMMENT",
1769 "FFELEX_typeDOLLAR",
1771 "FFELEX_typePERCENT",
1772 "FFELEX_typeAMPERSAND",
1773 "FFELEX_typeAPOSTROPHE",
1774 "FFELEX_typeOPEN_PAREN",
1775 "FFELEX_typeCLOSE_PAREN",
1776 "FFELEX_typeASTERISK",
1779 "FFELEX_typePERIOD",
1781 "FFELEX_typeNUMBER",
1782 "FFELEX_typeOPEN_ANGLE",
1783 "FFELEX_typeEQUALS",
1784 "FFELEX_typeCLOSE_ANGLE",
1788 "FFELEX_typeCONCAT",
1791 "FFELEX_typeHOLLERITH",
1792 "FFELEX_typeCHARACTER",
1794 "FFELEX_typeSEMICOLON",
1795 "FFELEX_typeUNDERSCORE",
1796 "FFELEX_typeQUESTION",
1797 "FFELEX_typeOPEN_ARRAY",
1798 "FFELEX_typeCLOSE_ARRAY",
1799 "FFELEX_typeCOLONCOLON",
1800 "FFELEX_typeREL_LE",
1801 "FFELEX_typeREL_NE",
1802 "FFELEX_typeREL_EQ",
1803 "FFELEX_typePOINTS",
1807 if (type >= ARRAY_SIZE (types))
1813 ffelex_display_token (ffelexToken t)
1818 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1819 ffewhereColumnNumber_f "u)",
1821 ffelex_type_string_ (t->type),
1822 ffewhere_line_number (t->where_line),
1823 ffewhere_column_number (t->where_col));
1825 if (t->text != NULL)
1826 fprintf (dmpout, ": \"%.*s\"\n",
1830 fprintf (dmpout, ".\n");
1833 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1835 if (ffelex_expecting_character())
1836 // next token delivered by lexer will be CHARACTER.
1838 If the most recent call to ffelex_set_expecting_hollerith since the last
1839 token was delivered by the lexer passed a length of -1, then we return
1840 TRUE, because the next token we deliver will be typeCHARACTER, else we
1844 ffelex_expecting_character ()
1846 return (ffelex_raw_mode_ != 0);
1849 /* ffelex_file_fixed -- Lex a given file in fixed source form
1853 ffelex_file_fixed(wf,f);
1855 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1858 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1860 register int c = 0; /* Character currently under consideration. */
1861 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1862 bool disallow_continuation_line;
1863 bool ignore_disallowed_continuation = FALSE;
1864 int latest_char_in_file = 0; /* For getting back into comment-skipping
1867 ffewhereColumnNumber first_label_char; /* First char of label --
1869 char label_string[6]; /* Text of label. */
1870 int labi; /* Length of label text. */
1871 bool finish_statement; /* Previous statement finished? */
1872 bool have_content; /* This line have content? */
1873 bool just_do_label; /* Nothing but label (and continuation?) on
1876 /* Lex is called for a particular file, not for a particular program unit.
1877 Yet the two events do share common characteristics. The first line in a
1878 file or in a program unit cannot be a continuation line. No token can
1879 be in mid-formation. No current label for the statement exists, since
1880 there is no current statement. */
1882 assert (ffelex_handler_ != NULL);
1884 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1886 input_filename = ffewhere_file_name (wf);
1888 ffelex_current_wf_ = wf;
1889 disallow_continuation_line = TRUE;
1890 ignore_disallowed_continuation = FALSE;
1891 ffelex_token_->type = FFELEX_typeNONE;
1892 ffelex_number_of_tokens_ = 0;
1893 ffelex_label_tokens_ = 0;
1894 ffelex_current_wl_ = ffewhere_line_unknown ();
1895 ffelex_current_wc_ = ffewhere_column_unknown ();
1896 latest_char_in_file = '\n';
1898 if (ffe_is_null_version ())
1900 /* Just substitute a "program" directly here. */
1902 char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
1906 for (p = &line[0]; *p != '\0'; ++p)
1907 column = ffelex_image_char_ (*p, column);
1911 goto have_line; /* :::::::::::::::::::: */
1914 goto first_line; /* :::::::::::::::::::: */
1916 /* Come here to get a new line. */
1918 beginning_of_line: /* :::::::::::::::::::: */
1920 disallow_continuation_line = FALSE;
1922 /* Come here directly when last line didn't clarify the continuation issue. */
1924 beginning_of_line_again: /* :::::::::::::::::::: */
1926 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1927 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1930 = malloc_resize_ks (malloc_pool_image (),
1932 FFELEX_columnINITIAL_SIZE_ + 9,
1933 ffelex_card_size_ + 9);
1934 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1938 first_line: /* :::::::::::::::::::: */
1940 c = latest_char_in_file;
1941 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1944 end_of_file: /* :::::::::::::::::::: */
1946 /* Line ending in EOF instead of \n still counts as a whole line. */
1948 ffelex_finish_statement_ ();
1949 ffewhere_line_kill (ffelex_current_wl_);
1950 ffewhere_column_kill (ffelex_current_wc_);
1951 return (ffelexHandler) ffelex_handler_;
1954 ffelex_next_line_ ();
1956 ffelex_bad_line_ = FALSE;
1958 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1960 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1961 || (lextype == FFELEX_typeERROR)
1962 || (lextype == FFELEX_typeSLASH)
1963 || (lextype == FFELEX_typeHASH))
1965 /* Test most frequent type of line first, etc. */
1966 if ((lextype == FFELEX_typeCOMMENT)
1967 || ((lextype == FFELEX_typeSLASH)
1968 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1970 /* Typical case (straight comment), just ignore rest of line. */
1971 comment_line: /* :::::::::::::::::::: */
1973 while ((c != '\n') && (c != EOF))
1976 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1977 else if (lextype == FFELEX_typeHASH)
1978 c = ffelex_hash_ (f);
1980 else if (lextype == FFELEX_typeSLASH)
1982 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1983 ffelex_card_image_[0] = '/';
1984 ffelex_card_image_[1] = c;
1986 goto bad_first_character; /* :::::::::::::::::::: */
1989 /* typeERROR or unsupported typeHASH. */
1990 { /* Bad first character, get line and display
1992 column = ffelex_image_char_ (c, 0);
1994 bad_first_character: /* :::::::::::::::::::: */
1996 ffelex_bad_line_ = TRUE;
1997 while (((c = getc (f)) != '\n') && (c != EOF))
1998 column = ffelex_image_char_ (c, column);
1999 ffelex_card_image_[column] = '\0';
2000 ffelex_card_length_ = column;
2001 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
2002 ffelex_linecount_current_, 1);
2005 /* Read past last char in line. */
2009 ffelex_next_line_ ();
2010 goto end_of_file; /* :::::::::::::::::::: */
2015 ffelex_next_line_ ();
2018 goto end_of_file; /* :::::::::::::::::::: */
2020 ffelex_bad_line_ = FALSE;
2021 } /* while [c, first char, means comment] */
2025 || (ffelex_final_nontab_column_ == 0);
2027 if (lextype == FFELEX_typeDEBUG)
2028 c = ' '; /* A 'D' or 'd' in column 1 with the
2029 debug-lines option on. */
2031 column = ffelex_image_char_ (c, 0);
2033 /* Read the entire line in as is (with whitespace processing). */
2035 while (((c = getc (f)) != '\n') && (c != EOF))
2036 column = ffelex_image_char_ (c, column);
2038 if (ffelex_bad_line_)
2040 ffelex_card_image_[column] = '\0';
2041 ffelex_card_length_ = column;
2042 goto comment_line; /* :::::::::::::::::::: */
2045 /* If no tab, cut off line after column 72/132. */
2047 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
2049 /* Technically, we should now fill ffelex_card_image_ up thru column
2050 72/132 with spaces, since character/hollerith constants must count
2051 them in that manner. To save CPU time in several ways (avoid a loop
2052 here that would be used only when we actually end a line in
2053 character-constant mode; avoid writing memory unnecessarily; avoid a
2054 loop later checking spaces when not scanning for character-constant
2055 characters), we don't do this, and we do the appropriate thing when
2056 we encounter end-of-line while actually processing a character
2059 column = ffelex_final_nontab_column_;
2062 have_line: /* :::::::::::::::::::: */
2064 ffelex_card_image_[column] = '\0';
2065 ffelex_card_length_ = column;
2067 /* Save next char in file so we can use register-based c while analyzing
2068 line we just read. */
2070 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2072 have_content = FALSE;
2074 /* Handle label, if any. */
2077 first_label_char = FFEWHERE_columnUNKNOWN;
2078 for (column = 0; column < 5; ++column)
2080 switch (c = ffelex_card_image_[column])
2084 goto stop_looking; /* :::::::::::::::::::: */
2099 label_string[labi++] = c;
2100 if (first_label_char == FFEWHERE_columnUNKNOWN)
2101 first_label_char = column + 1;
2107 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2108 ffelex_linecount_current_,
2110 goto beginning_of_line_again; /* :::::::::::::::::::: */
2112 if (ffe_is_pedantic ())
2113 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2114 ffelex_linecount_current_, 1);
2115 finish_statement = FALSE;
2116 just_do_label = FALSE;
2117 goto got_a_continuation; /* :::::::::::::::::::: */
2120 if (ffelex_card_image_[column + 1] == '*')
2121 goto stop_looking; /* :::::::::::::::::::: */
2124 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2125 ffelex_linecount_current_, column + 1);
2126 goto beginning_of_line_again; /* :::::::::::::::::::: */
2130 stop_looking: /* :::::::::::::::::::: */
2132 label_string[labi] = '\0';
2134 /* Find first nonblank char starting with continuation column. */
2136 if (column == 5) /* In which case we didn't see end of line in
2138 while ((c = ffelex_card_image_[column]) == ' ')
2141 /* Now we're trying to figure out whether this is a continuation line and
2142 whether there's anything else of substance on the line. The cases are
2145 1. If a line has an explicit continuation character (other than the digit
2146 zero), then if it also has a label, the label is ignored and an error
2147 message is printed. Any remaining text on the line is passed to the
2148 parser tasks, thus even an all-blank line (possibly with an ignored
2149 label) aside from a positive continuation character might have meaning
2150 in the midst of a character or hollerith constant.
2152 2. If a line has no explicit continuation character (that is, it has a
2153 space in column 6 and the first non-space character past column 6 is
2154 not a digit 0-9), then there are two possibilities:
2156 A. A label is present and/or a non-space (and non-comment) character
2157 appears somewhere after column 6. Terminate processing of the previous
2158 statement, if any, send the new label for the next statement, if any,
2159 and start processing a new statement with this non-blank character, if
2162 B. The line is essentially blank, except for a possible comment character.
2163 Don't terminate processing of the previous statement and don't pass any
2164 characters to the parser tasks, since the line is not flagged as a
2165 continuation line. We treat it just like a completely blank line.
2167 3. If a line has a continuation character of zero (0), then we terminate
2168 processing of the previous statement, if any, send the new label for the
2169 next statement, if any, and start processing a new statement, if any
2170 non-blank characters are present.
2172 If, when checking to see if we should terminate the previous statement, it
2173 is found that there is no previous statement but that there is an
2174 outstanding label, substitute CONTINUE as the statement for the label
2175 and display an error message. */
2177 finish_statement = FALSE;
2178 just_do_label = FALSE;
2182 case '!': /* ANSI Fortran 90 says ! in column 6 is
2184 /* VXT Fortran says ! anywhere is comment, even column 6. */
2185 if (ffe_is_vxt () || (column != 5))
2186 goto no_tokens_on_line; /* :::::::::::::::::::: */
2187 goto got_a_continuation; /* :::::::::::::::::::: */
2190 if (ffelex_card_image_[column + 1] != '*')
2191 goto some_other_character; /* :::::::::::::::::::: */
2195 /* This seems right to do. But it is close to call, since / * starting
2196 in column 6 will thus be interpreted as a continuation line
2197 beginning with '*'. */
2199 goto got_a_continuation;/* :::::::::::::::::::: */
2203 /* End of line. Therefore may be continued-through line, so handle
2204 pending label as possible to-be-continued and drive end-of-statement
2205 for any previous statement, else treat as blank line. */
2207 no_tokens_on_line: /* :::::::::::::::::::: */
2209 if (ffe_is_pedantic () && (c == '/'))
2210 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2211 ffelex_linecount_current_, column + 1);
2212 if (first_label_char != FFEWHERE_columnUNKNOWN)
2213 { /* Can't be a continued-through line if it
2215 finish_statement = TRUE;
2216 have_content = TRUE;
2217 just_do_label = TRUE;
2220 goto beginning_of_line_again; /* :::::::::::::::::::: */
2223 if (ffe_is_pedantic () && (column != 5))
2224 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2225 ffelex_linecount_current_, column + 1);
2226 finish_statement = TRUE;
2227 goto check_for_content; /* :::::::::::::::::::: */
2239 /* NOTE: This label can be reached directly from the code
2240 that lexes the label field in columns 1-5. */
2241 got_a_continuation: /* :::::::::::::::::::: */
2243 if (first_label_char != FFEWHERE_columnUNKNOWN)
2245 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2246 ffelex_linecount_current_,
2248 ffelex_linecount_current_,
2250 first_label_char = FFEWHERE_columnUNKNOWN;
2252 if (disallow_continuation_line)
2254 if (!ignore_disallowed_continuation)
2255 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2256 ffelex_linecount_current_, column + 1);
2257 goto beginning_of_line_again; /* :::::::::::::::::::: */
2259 if (ffe_is_pedantic () && (column != 5))
2260 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2261 ffelex_linecount_current_, column + 1);
2262 if ((ffelex_raw_mode_ != 0)
2263 && (((c = ffelex_card_image_[column + 1]) != '\0')
2264 || !ffelex_saw_tab_))
2267 have_content = TRUE;
2271 check_for_content: /* :::::::::::::::::::: */
2273 while ((c = ffelex_card_image_[++column]) == ' ')
2278 && (ffelex_card_image_[column + 1] == '*')))
2280 if (ffe_is_pedantic () && (c == '/'))
2281 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2282 ffelex_linecount_current_, column + 1);
2283 just_do_label = TRUE;
2286 have_content = TRUE;
2291 some_other_character: /* :::::::::::::::::::: */
2294 goto got_a_continuation;/* :::::::::::::::::::: */
2296 /* Here is the very normal case of a regular character starting in
2297 column 7 or beyond with a blank in column 6. */
2299 finish_statement = TRUE;
2300 have_content = TRUE;
2305 || (first_label_char != FFEWHERE_columnUNKNOWN))
2307 /* The line has content of some kind, install new end-statement
2308 point for error messages. Note that "content" includes cases
2309 where there's little apparent content but enough to finish
2310 a statement. That's because finishing a statement can trigger
2311 an impending INCLUDE, and that requires accurate line info being
2312 maintained by the lexer. */
2314 if (finish_statement)
2315 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2317 ffewhere_line_kill (ffelex_current_wl_);
2318 ffewhere_column_kill (ffelex_current_wc_);
2319 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2320 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2323 /* We delay this for a combination of reasons. Mainly, it can start
2324 INCLUDE processing, and we want to delay that until the lexer's
2325 info on the line is coherent. And we want to delay that until we're
2326 sure there's a reason to make that info coherent, to avoid saving
2327 lots of useless lines. */
2329 if (finish_statement)
2330 ffelex_finish_statement_ ();
2332 /* If label is present, enclose it in a NUMBER token and send it along. */
2334 if (first_label_char != FFEWHERE_columnUNKNOWN)
2336 assert (ffelex_token_->type == FFELEX_typeNONE);
2337 ffelex_token_->type = FFELEX_typeNUMBER;
2338 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2339 strcpy (ffelex_token_->text, label_string);
2340 ffelex_token_->where_line
2341 = ffewhere_line_use (ffelex_current_wl_);
2342 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2343 ffelex_token_->length = labi;
2344 ffelex_send_token_ ();
2345 ++ffelex_label_tokens_;
2349 goto beginning_of_line; /* :::::::::::::::::::: */
2351 /* Here is the main engine for parsing. c holds the character at column.
2352 It is already known that c is not a blank, end of line, or shriek,
2353 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2354 character/hollerith constant). A partially filled token may already
2355 exist in ffelex_token_. One special case: if, when the end of the line
2356 is reached, continuation_line is FALSE and the only token on the line is
2357 END, then it is indeed the last statement. We don't look for
2358 continuation lines during this program unit in that case. This is
2359 according to ANSI. */
2361 if (ffelex_raw_mode_ != 0)
2364 parse_raw_character: /* :::::::::::::::::::: */
2368 ffewhereColumnNumber i;
2370 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2371 goto beginning_of_line; /* :::::::::::::::::::: */
2373 /* Pad out line with "virtual" spaces. */
2375 for (i = column; i < ffelex_final_nontab_column_; ++i)
2376 ffelex_card_image_[i] = ' ';
2377 ffelex_card_image_[i] = '\0';
2378 ffelex_card_length_ = i;
2382 switch (ffelex_raw_mode_)
2385 c = ffelex_backslash_ (c, column);
2389 if (!ffelex_backslash_reconsider_)
2390 ffelex_append_to_token_ (c);
2391 ffelex_raw_mode_ = -1;
2395 if (c == ffelex_raw_char_)
2397 ffelex_raw_mode_ = -1;
2398 ffelex_append_to_token_ (c);
2402 ffelex_raw_mode_ = 0;
2403 ffelex_backslash_reconsider_ = TRUE;
2408 if (c == ffelex_raw_char_)
2409 ffelex_raw_mode_ = -2;
2412 c = ffelex_backslash_ (c, column);
2415 ffelex_raw_mode_ = -3;
2419 ffelex_append_to_token_ (c);
2424 c = ffelex_backslash_ (c, column);
2428 if (!ffelex_backslash_reconsider_)
2430 ffelex_append_to_token_ (c);
2436 if (ffelex_backslash_reconsider_)
2437 ffelex_backslash_reconsider_ = FALSE;
2439 c = ffelex_card_image_[++column];
2441 if (ffelex_raw_mode_ == 0)
2443 ffelex_send_token_ ();
2444 assert (ffelex_raw_mode_ == 0);
2446 c = ffelex_card_image_[++column];
2450 && (ffelex_card_image_[column + 1] == '*')))
2451 goto beginning_of_line; /* :::::::::::::::::::: */
2452 goto parse_nonraw_character; /* :::::::::::::::::::: */
2454 goto parse_raw_character; /* :::::::::::::::::::: */
2457 parse_nonraw_character: /* :::::::::::::::::::: */
2459 switch (ffelex_token_->type)
2461 case FFELEX_typeNONE:
2465 ffelex_token_->type = FFELEX_typeQUOTE;
2466 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2467 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2468 ffelex_send_token_ ();
2472 ffelex_token_->type = FFELEX_typeDOLLAR;
2473 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2474 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2475 ffelex_send_token_ ();
2479 ffelex_token_->type = FFELEX_typePERCENT;
2480 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2481 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2482 ffelex_send_token_ ();
2486 ffelex_token_->type = FFELEX_typeAMPERSAND;
2487 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2488 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2489 ffelex_send_token_ ();
2493 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2494 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2495 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2496 ffelex_send_token_ ();
2500 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2501 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2502 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2506 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2507 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2508 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2509 ffelex_send_token_ ();
2513 ffelex_token_->type = FFELEX_typeASTERISK;
2514 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2515 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2519 ffelex_token_->type = FFELEX_typePLUS;
2520 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2521 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2522 ffelex_send_token_ ();
2526 ffelex_token_->type = FFELEX_typeCOMMA;
2527 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2528 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2529 ffelex_send_token_ ();
2533 ffelex_token_->type = FFELEX_typeMINUS;
2534 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2535 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2536 ffelex_send_token_ ();
2540 ffelex_token_->type = FFELEX_typePERIOD;
2541 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2542 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2543 ffelex_send_token_ ();
2547 ffelex_token_->type = FFELEX_typeSLASH;
2548 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2549 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2563 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2564 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2565 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2566 ffelex_append_to_token_ (c);
2570 ffelex_token_->type = FFELEX_typeCOLON;
2571 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2572 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2576 ffelex_token_->type = FFELEX_typeSEMICOLON;
2577 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2578 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2579 ffelex_permit_include_ = TRUE;
2580 ffelex_send_token_ ();
2581 ffelex_permit_include_ = FALSE;
2585 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2586 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2587 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2591 ffelex_token_->type = FFELEX_typeEQUALS;
2592 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2593 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2597 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2598 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2599 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2603 ffelex_token_->type = FFELEX_typeQUESTION;
2604 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2605 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2606 ffelex_send_token_ ();
2610 if (1 || ffe_is_90 ())
2612 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2613 ffelex_token_->where_line
2614 = ffewhere_line_use (ffelex_current_wl_);
2615 ffelex_token_->where_col
2616 = ffewhere_column_new (column + 1);
2617 ffelex_send_token_ ();
2673 c = ffesrc_char_source (c);
2675 if (ffesrc_char_match_init (c, 'H', 'h')
2676 && ffelex_expecting_hollerith_ != 0)
2678 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2679 ffelex_token_->type = FFELEX_typeHOLLERITH;
2680 ffelex_token_->where_line = ffelex_raw_where_line_;
2681 ffelex_token_->where_col = ffelex_raw_where_col_;
2682 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2683 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2684 c = ffelex_card_image_[++column];
2685 goto parse_raw_character; /* :::::::::::::::::::: */
2690 ffelex_token_->where_line
2691 = ffewhere_line_use (ffelex_token_->currentnames_line
2692 = ffewhere_line_use (ffelex_current_wl_));
2693 ffelex_token_->where_col
2694 = ffewhere_column_use (ffelex_token_->currentnames_col
2695 = ffewhere_column_new (column + 1));
2696 ffelex_token_->type = FFELEX_typeNAMES;
2700 ffelex_token_->where_line
2701 = ffewhere_line_use (ffelex_current_wl_);
2702 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2703 ffelex_token_->type = FFELEX_typeNAME;
2705 ffelex_append_to_token_ (c);
2709 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2710 ffelex_linecount_current_, column + 1);
2711 ffelex_finish_statement_ ();
2712 disallow_continuation_line = TRUE;
2713 ignore_disallowed_continuation = TRUE;
2714 goto beginning_of_line_again; /* :::::::::::::::::::: */
2718 case FFELEX_typeNAME:
2773 c = ffesrc_char_source (c);
2788 && !ffe_is_dollar_ok ())
2790 ffelex_send_token_ ();
2791 goto parse_next_character; /* :::::::::::::::::::: */
2793 ffelex_append_to_token_ (c);
2797 ffelex_send_token_ ();
2798 goto parse_next_character; /* :::::::::::::::::::: */
2802 case FFELEX_typeNAMES:
2857 c = ffesrc_char_source (c);
2872 && !ffe_is_dollar_ok ())
2874 ffelex_send_token_ ();
2875 goto parse_next_character; /* :::::::::::::::::::: */
2877 if (ffelex_token_->length < FFEWHERE_indexMAX)
2879 ffewhere_track (&ffelex_token_->currentnames_line,
2880 &ffelex_token_->currentnames_col,
2881 ffelex_token_->wheretrack,
2882 ffelex_token_->length,
2883 ffelex_linecount_current_,
2886 ffelex_append_to_token_ (c);
2890 ffelex_send_token_ ();
2891 goto parse_next_character; /* :::::::::::::::::::: */
2895 case FFELEX_typeNUMBER:
2908 ffelex_append_to_token_ (c);
2912 ffelex_send_token_ ();
2913 goto parse_next_character; /* :::::::::::::::::::: */
2917 case FFELEX_typeASTERISK:
2921 ffelex_token_->type = FFELEX_typePOWER;
2922 ffelex_send_token_ ();
2925 default: /* * not followed by another *. */
2926 ffelex_send_token_ ();
2927 goto parse_next_character; /* :::::::::::::::::::: */
2931 case FFELEX_typeCOLON:
2935 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2936 ffelex_send_token_ ();
2939 default: /* : not followed by another :. */
2940 ffelex_send_token_ ();
2941 goto parse_next_character; /* :::::::::::::::::::: */
2945 case FFELEX_typeSLASH:
2949 ffelex_token_->type = FFELEX_typeCONCAT;
2950 ffelex_send_token_ ();
2954 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2955 ffelex_send_token_ ();
2959 ffelex_token_->type = FFELEX_typeREL_NE;
2960 ffelex_send_token_ ();
2964 ffelex_send_token_ ();
2965 goto parse_next_character; /* :::::::::::::::::::: */
2969 case FFELEX_typeOPEN_PAREN:
2973 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2974 ffelex_send_token_ ();
2978 ffelex_send_token_ ();
2979 goto parse_next_character; /* :::::::::::::::::::: */
2983 case FFELEX_typeOPEN_ANGLE:
2987 ffelex_token_->type = FFELEX_typeREL_LE;
2988 ffelex_send_token_ ();
2992 ffelex_send_token_ ();
2993 goto parse_next_character; /* :::::::::::::::::::: */
2997 case FFELEX_typeEQUALS:
3001 ffelex_token_->type = FFELEX_typeREL_EQ;
3002 ffelex_send_token_ ();
3006 ffelex_token_->type = FFELEX_typePOINTS;
3007 ffelex_send_token_ ();
3011 ffelex_send_token_ ();
3012 goto parse_next_character; /* :::::::::::::::::::: */
3016 case FFELEX_typeCLOSE_ANGLE:
3020 ffelex_token_->type = FFELEX_typeREL_GE;
3021 ffelex_send_token_ ();
3025 ffelex_send_token_ ();
3026 goto parse_next_character; /* :::::::::::::::::::: */
3031 assert ("Serious error!!" == NULL);
3036 c = ffelex_card_image_[++column];
3038 parse_next_character: /* :::::::::::::::::::: */
3040 if (ffelex_raw_mode_ != 0)
3041 goto parse_raw_character; /* :::::::::::::::::::: */
3044 c = ffelex_card_image_[++column];
3049 && (ffelex_card_image_[column + 1] == '*')))
3051 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
3052 && (ffelex_token_->type == FFELEX_typeNAMES)
3053 && (ffelex_token_->length == 3)
3054 && (ffesrc_strncmp_2c (ffe_case_match (),
3055 ffelex_token_->text,
3056 "END", "end", "End",
3060 ffelex_finish_statement_ ();
3061 disallow_continuation_line = TRUE;
3062 ignore_disallowed_continuation = FALSE;
3063 goto beginning_of_line_again; /* :::::::::::::::::::: */
3065 goto beginning_of_line; /* :::::::::::::::::::: */
3067 goto parse_nonraw_character; /* :::::::::::::::::::: */
3070 /* ffelex_file_free -- Lex a given file in free source form
3074 ffelex_file_free(wf,f);
3076 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3079 ffelex_file_free (ffewhereFile wf, FILE *f)
3081 register int c = 0; /* Character currently under consideration. */
3082 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3083 bool continuation_line = FALSE;
3084 ffewhereColumnNumber continuation_column;
3085 int latest_char_in_file = 0; /* For getting back into comment-skipping
3088 /* Lex is called for a particular file, not for a particular program unit.
3089 Yet the two events do share common characteristics. The first line in a
3090 file or in a program unit cannot be a continuation line. No token can
3091 be in mid-formation. No current label for the statement exists, since
3092 there is no current statement. */
3094 assert (ffelex_handler_ != NULL);
3096 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3098 input_filename = ffewhere_file_name (wf);
3100 ffelex_current_wf_ = wf;
3101 continuation_line = FALSE;
3102 ffelex_token_->type = FFELEX_typeNONE;
3103 ffelex_number_of_tokens_ = 0;
3104 ffelex_current_wl_ = ffewhere_line_unknown ();
3105 ffelex_current_wc_ = ffewhere_column_unknown ();
3106 latest_char_in_file = '\n';
3108 /* Come here to get a new line. */
3110 beginning_of_line: /* :::::::::::::::::::: */
3112 c = latest_char_in_file;
3113 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3116 end_of_file: /* :::::::::::::::::::: */
3118 /* Line ending in EOF instead of \n still counts as a whole line. */
3120 ffelex_finish_statement_ ();
3121 ffewhere_line_kill (ffelex_current_wl_);
3122 ffewhere_column_kill (ffelex_current_wc_);
3123 return (ffelexHandler) ffelex_handler_;
3126 ffelex_next_line_ ();
3128 ffelex_bad_line_ = FALSE;
3130 /* Skip over initial-comment and empty lines as quickly as possible! */
3138 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3139 c = ffelex_hash_ (f);
3141 /* Don't skip over # line after all. */
3146 comment_line: /* :::::::::::::::::::: */
3148 while ((c != '\n') && (c != EOF))
3153 ffelex_next_line_ ();
3154 goto end_of_file; /* :::::::::::::::::::: */
3159 ffelex_next_line_ ();
3162 goto end_of_file; /* :::::::::::::::::::: */
3165 ffelex_saw_tab_ = FALSE;
3167 column = ffelex_image_char_ (c, 0);
3169 /* Read the entire line in as is (with whitespace processing). */
3171 while (((c = getc (f)) != '\n') && (c != EOF))
3172 column = ffelex_image_char_ (c, column);
3174 if (ffelex_bad_line_)
3176 ffelex_card_image_[column] = '\0';
3177 ffelex_card_length_ = column;
3178 goto comment_line; /* :::::::::::::::::::: */
3181 /* If no tab, cut off line after column 132. */
3183 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3184 column = FFELEX_FREE_MAX_COLUMNS_;
3186 ffelex_card_image_[column] = '\0';
3187 ffelex_card_length_ = column;
3189 /* Save next char in file so we can use register-based c while analyzing
3190 line we just read. */
3192 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3195 continuation_column = 0;
3197 /* Skip over initial spaces to see if the first nonblank character
3198 is exclamation point, newline, or EOF (line is therefore a comment) or
3199 ampersand (line is therefore a continuation line). */
3201 while ((c = ffelex_card_image_[column]) == ' ')
3208 goto beginning_of_line; /* :::::::::::::::::::: */
3211 continuation_column = column + 1;
3218 /* The line definitely has content of some kind, install new end-statement
3219 point for error messages. */
3221 ffewhere_line_kill (ffelex_current_wl_);
3222 ffewhere_column_kill (ffelex_current_wc_);
3223 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3224 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3226 /* Figure out which column to start parsing at. */
3228 if (continuation_line)
3230 if (continuation_column == 0)
3232 if (ffelex_raw_mode_ != 0)
3234 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3235 ffelex_linecount_current_, column + 1);
3237 else if (ffelex_token_->type != FFELEX_typeNONE)
3239 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3240 ffelex_linecount_current_, column + 1);
3243 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3244 { /* Line contains only a single "&" as only
3245 nonblank character. */
3246 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3247 ffelex_linecount_current_, continuation_column);
3248 goto beginning_of_line; /* :::::::::::::::::::: */
3250 column = continuation_column;
3255 c = ffelex_card_image_[column];
3256 continuation_line = FALSE;
3258 /* Here is the main engine for parsing. c holds the character at column.
3259 It is already known that c is not a blank, end of line, or shriek,
3260 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3261 character/hollerith constant). A partially filled token may already
3262 exist in ffelex_token_. */
3264 if (ffelex_raw_mode_ != 0)
3267 parse_raw_character: /* :::::::::::::::::::: */
3272 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3274 continuation_line = TRUE;
3275 goto beginning_of_line; /* :::::::::::::::::::: */
3280 ffelex_finish_statement_ ();
3281 goto beginning_of_line; /* :::::::::::::::::::: */
3287 switch (ffelex_raw_mode_)
3290 c = ffelex_backslash_ (c, column);
3294 if (!ffelex_backslash_reconsider_)
3295 ffelex_append_to_token_ (c);
3296 ffelex_raw_mode_ = -1;
3300 if (c == ffelex_raw_char_)
3302 ffelex_raw_mode_ = -1;
3303 ffelex_append_to_token_ (c);
3307 ffelex_raw_mode_ = 0;
3308 ffelex_backslash_reconsider_ = TRUE;
3313 if (c == ffelex_raw_char_)
3314 ffelex_raw_mode_ = -2;
3317 c = ffelex_backslash_ (c, column);
3320 ffelex_raw_mode_ = -3;
3324 ffelex_append_to_token_ (c);
3329 c = ffelex_backslash_ (c, column);
3333 if (!ffelex_backslash_reconsider_)
3335 ffelex_append_to_token_ (c);
3341 if (ffelex_backslash_reconsider_)
3342 ffelex_backslash_reconsider_ = FALSE;
3344 c = ffelex_card_image_[++column];
3346 if (ffelex_raw_mode_ == 0)
3348 ffelex_send_token_ ();
3349 assert (ffelex_raw_mode_ == 0);
3351 c = ffelex_card_image_[++column];
3352 if ((c == '\0') || (c == '!'))
3354 ffelex_finish_statement_ ();
3355 goto beginning_of_line; /* :::::::::::::::::::: */
3357 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3359 continuation_line = TRUE;
3360 goto beginning_of_line; /* :::::::::::::::::::: */
3362 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3364 goto parse_raw_character; /* :::::::::::::::::::: */
3367 parse_nonraw_character: /* :::::::::::::::::::: */
3369 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3371 continuation_line = TRUE;
3372 goto beginning_of_line; /* :::::::::::::::::::: */
3375 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3377 switch (ffelex_token_->type)
3379 case FFELEX_typeNONE:
3382 finish-statement/continue-statement
3385 c = ffelex_card_image_[++column];
3386 if ((c == '\0') || (c == '!'))
3388 ffelex_finish_statement_ ();
3389 goto beginning_of_line; /* :::::::::::::::::::: */
3391 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3393 continuation_line = TRUE;
3394 goto beginning_of_line; /* :::::::::::::::::::: */
3401 ffelex_token_->type = FFELEX_typeQUOTE;
3402 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3403 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3404 ffelex_send_token_ ();
3408 ffelex_token_->type = FFELEX_typeDOLLAR;
3409 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3410 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3411 ffelex_send_token_ ();
3415 ffelex_token_->type = FFELEX_typePERCENT;
3416 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3417 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3418 ffelex_send_token_ ();
3422 ffelex_token_->type = FFELEX_typeAMPERSAND;
3423 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3424 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3425 ffelex_send_token_ ();
3429 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3430 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3431 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3432 ffelex_send_token_ ();
3436 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3437 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3438 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3442 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3443 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3444 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3445 ffelex_send_token_ ();
3449 ffelex_token_->type = FFELEX_typeASTERISK;
3450 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3451 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3455 ffelex_token_->type = FFELEX_typePLUS;
3456 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3457 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3458 ffelex_send_token_ ();
3462 ffelex_token_->type = FFELEX_typeCOMMA;
3463 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3464 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3465 ffelex_send_token_ ();
3469 ffelex_token_->type = FFELEX_typeMINUS;
3470 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3471 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3472 ffelex_send_token_ ();
3476 ffelex_token_->type = FFELEX_typePERIOD;
3477 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3478 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3479 ffelex_send_token_ ();
3483 ffelex_token_->type = FFELEX_typeSLASH;
3484 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3485 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3499 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3500 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3501 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3502 ffelex_append_to_token_ (c);
3506 ffelex_token_->type = FFELEX_typeCOLON;
3507 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3508 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3512 ffelex_token_->type = FFELEX_typeSEMICOLON;
3513 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3514 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3515 ffelex_permit_include_ = TRUE;
3516 ffelex_send_token_ ();
3517 ffelex_permit_include_ = FALSE;
3521 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3522 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3523 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3527 ffelex_token_->type = FFELEX_typeEQUALS;
3528 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3529 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3533 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3534 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3535 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3539 ffelex_token_->type = FFELEX_typeQUESTION;
3540 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3541 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3542 ffelex_send_token_ ();
3546 if (1 || ffe_is_90 ())
3548 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3549 ffelex_token_->where_line
3550 = ffewhere_line_use (ffelex_current_wl_);
3551 ffelex_token_->where_col
3552 = ffewhere_column_new (column + 1);
3553 ffelex_send_token_ ();
3609 c = ffesrc_char_source (c);
3611 if (ffesrc_char_match_init (c, 'H', 'h')
3612 && ffelex_expecting_hollerith_ != 0)
3614 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3615 ffelex_token_->type = FFELEX_typeHOLLERITH;
3616 ffelex_token_->where_line = ffelex_raw_where_line_;
3617 ffelex_token_->where_col = ffelex_raw_where_col_;
3618 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3619 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3620 c = ffelex_card_image_[++column];
3621 goto parse_raw_character; /* :::::::::::::::::::: */
3624 if (ffelex_names_pure_)
3626 ffelex_token_->where_line
3627 = ffewhere_line_use (ffelex_token_->currentnames_line
3628 = ffewhere_line_use (ffelex_current_wl_));
3629 ffelex_token_->where_col
3630 = ffewhere_column_use (ffelex_token_->currentnames_col
3631 = ffewhere_column_new (column + 1));
3632 ffelex_token_->type = FFELEX_typeNAMES;
3636 ffelex_token_->where_line
3637 = ffewhere_line_use (ffelex_current_wl_);
3638 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3639 ffelex_token_->type = FFELEX_typeNAME;
3641 ffelex_append_to_token_ (c);
3645 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3646 ffelex_linecount_current_, column + 1);
3647 ffelex_finish_statement_ ();
3648 goto beginning_of_line; /* :::::::::::::::::::: */
3652 case FFELEX_typeNAME:
3707 c = ffesrc_char_source (c);
3722 && !ffe_is_dollar_ok ())
3724 ffelex_send_token_ ();
3725 goto parse_next_character; /* :::::::::::::::::::: */
3727 ffelex_append_to_token_ (c);
3731 ffelex_send_token_ ();
3732 goto parse_next_character; /* :::::::::::::::::::: */
3736 case FFELEX_typeNAMES:
3791 c = ffesrc_char_source (c);
3806 && !ffe_is_dollar_ok ())
3808 ffelex_send_token_ ();
3809 goto parse_next_character; /* :::::::::::::::::::: */
3811 if (ffelex_token_->length < FFEWHERE_indexMAX)
3813 ffewhere_track (&ffelex_token_->currentnames_line,
3814 &ffelex_token_->currentnames_col,
3815 ffelex_token_->wheretrack,
3816 ffelex_token_->length,
3817 ffelex_linecount_current_,
3820 ffelex_append_to_token_ (c);
3824 ffelex_send_token_ ();
3825 goto parse_next_character; /* :::::::::::::::::::: */
3829 case FFELEX_typeNUMBER:
3842 ffelex_append_to_token_ (c);
3846 ffelex_send_token_ ();
3847 goto parse_next_character; /* :::::::::::::::::::: */
3851 case FFELEX_typeASTERISK:
3855 ffelex_token_->type = FFELEX_typePOWER;
3856 ffelex_send_token_ ();
3859 default: /* * not followed by another *. */
3860 ffelex_send_token_ ();
3861 goto parse_next_character; /* :::::::::::::::::::: */
3865 case FFELEX_typeCOLON:
3869 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3870 ffelex_send_token_ ();
3873 default: /* : not followed by another :. */
3874 ffelex_send_token_ ();
3875 goto parse_next_character; /* :::::::::::::::::::: */
3879 case FFELEX_typeSLASH:
3883 ffelex_token_->type = FFELEX_typeCONCAT;
3884 ffelex_send_token_ ();
3888 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3889 ffelex_send_token_ ();
3893 ffelex_token_->type = FFELEX_typeREL_NE;
3894 ffelex_send_token_ ();
3898 ffelex_send_token_ ();
3899 goto parse_next_character; /* :::::::::::::::::::: */
3903 case FFELEX_typeOPEN_PAREN:
3907 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3908 ffelex_send_token_ ();
3912 ffelex_send_token_ ();
3913 goto parse_next_character; /* :::::::::::::::::::: */
3917 case FFELEX_typeOPEN_ANGLE:
3921 ffelex_token_->type = FFELEX_typeREL_LE;
3922 ffelex_send_token_ ();
3926 ffelex_send_token_ ();
3927 goto parse_next_character; /* :::::::::::::::::::: */
3931 case FFELEX_typeEQUALS:
3935 ffelex_token_->type = FFELEX_typeREL_EQ;
3936 ffelex_send_token_ ();
3940 ffelex_token_->type = FFELEX_typePOINTS;
3941 ffelex_send_token_ ();
3945 ffelex_send_token_ ();
3946 goto parse_next_character; /* :::::::::::::::::::: */
3950 case FFELEX_typeCLOSE_ANGLE:
3954 ffelex_token_->type = FFELEX_typeREL_GE;
3955 ffelex_send_token_ ();
3959 ffelex_send_token_ ();
3960 goto parse_next_character; /* :::::::::::::::::::: */
3965 assert ("Serious error!" == NULL);
3970 c = ffelex_card_image_[++column];
3972 parse_next_character: /* :::::::::::::::::::: */
3974 if (ffelex_raw_mode_ != 0)
3975 goto parse_raw_character; /* :::::::::::::::::::: */
3977 if ((c == '\0') || (c == '!'))
3979 ffelex_finish_statement_ ();
3980 goto beginning_of_line; /* :::::::::::::::::::: */
3982 goto parse_nonraw_character; /* :::::::::::::::::::: */
3985 /* See the code in com.c that calls this to understand why. */
3987 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3989 ffelex_hash_kludge (FILE *finput)
3991 /* If you change this constant string, you have to change whatever
3992 code might thus be affected by it in terms of having to use
3993 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3994 static char match[] = "# 1 \"";
3995 static int kludge[ARRAY_SIZE (match) + 1];
4000 /* Read chars as long as they match the target string.
4001 Copy them into an array that will serve as a record
4002 of what we read (essentially a multi-char ungetc(),
4003 for code that uses ffelex_getc_ instead of getc() elsewhere
4005 for (p = &match[0], q = &kludge[0], c = getc (finput);
4006 (c == *p) && (*p != '\0') && (c != EOF);
4007 ++p, ++q, c = getc (finput))
4010 *q = c; /* Might be EOF, which requires int. */
4013 ffelex_kludge_chars_ = &kludge[0];
4017 ffelex_kludge_flag_ = TRUE;
4018 ++ffelex_kludge_chars_;
4019 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
4020 ffelex_kludge_flag_ = FALSE;
4030 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
4031 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
4032 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
4033 "FFELEX card image",
4034 FFELEX_columnINITIAL_SIZE_ + 9);
4035 ffelex_card_image_[0] = '\0';
4037 for (i = 0; i < 256; ++i)
4038 ffelex_first_char_[i] = FFELEX_typeERROR;
4040 ffelex_first_char_['\t'] = FFELEX_typeRAW;
4041 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
4042 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
4043 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
4044 ffelex_first_char_['\r'] = FFELEX_typeRAW;
4045 ffelex_first_char_[' '] = FFELEX_typeRAW;
4046 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
4047 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
4048 ffelex_first_char_['/'] = FFELEX_typeSLASH;
4049 ffelex_first_char_['&'] = FFELEX_typeRAW;
4050 ffelex_first_char_['#'] = FFELEX_typeHASH;
4052 for (i = '0'; i <= '9'; ++i)
4053 ffelex_first_char_[i] = FFELEX_typeRAW;
4055 if ((ffe_case_match () == FFE_caseNONE)
4056 || ((ffe_case_match () == FFE_caseUPPER)
4057 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
4058 || ((ffe_case_match () == FFE_caseLOWER)
4059 && (ffe_case_source () == FFE_caseLOWER)))
4061 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
4062 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
4064 if ((ffe_case_match () == FFE_caseNONE)
4065 || ((ffe_case_match () == FFE_caseLOWER)
4066 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
4067 || ((ffe_case_match () == FFE_caseUPPER)
4068 && (ffe_case_source () == FFE_caseUPPER)))
4070 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
4071 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
4074 ffelex_linecount_current_ = 0;
4075 ffelex_linecount_next_ = 1;
4076 ffelex_raw_mode_ = 0;
4077 ffelex_set_include_ = FALSE;
4078 ffelex_permit_include_ = FALSE;
4079 ffelex_names_ = TRUE; /* First token in program is a names. */
4080 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
4082 ffelex_hexnum_ = FALSE;
4083 ffelex_expecting_hollerith_ = 0;
4084 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4085 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4087 ffelex_token_ = ffelex_token_new_ ();
4088 ffelex_token_->type = FFELEX_typeNONE;
4089 ffelex_token_->uses = 1;
4090 ffelex_token_->where_line = ffewhere_line_unknown ();
4091 ffelex_token_->where_col = ffewhere_column_unknown ();
4092 ffelex_token_->text = NULL;
4094 ffelex_handler_ = NULL;
4097 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4099 if (ffelex_is_names_expected())
4100 // Deliver NAMES token
4102 // Deliver NAME token
4104 Must be called while lexer is active, obviously. */
4107 ffelex_is_names_expected ()
4109 return ffelex_names_;
4112 /* Current card image, which has the master linecount number
4113 ffelex_linecount_current_. */
4118 return ffelex_card_image_;
4121 /* ffelex_line_length -- Return length of current lexer line
4123 printf("Length is %lu\n",ffelex_line_length());
4125 Must be called while lexer is active, obviously. */
4127 ffewhereColumnNumber
4128 ffelex_line_length ()
4130 return ffelex_card_length_;
4133 /* Master line count of current card image, or 0 if no card image
4137 ffelex_line_number ()
4139 return ffelex_linecount_current_;
4142 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4144 ffelex_set_expecting_hollerith(0);
4146 Lex initially assumes no hollerith constant is about to show up. If
4147 syntactic analysis expects one, it should call this function with the
4148 number of characters expected in the constant immediately after recognizing
4149 the decimal number preceding the "H" and the constant itself. Then, if
4150 the next character is indeed H, the lexer will interpret it as beginning
4151 a hollerith constant and ship the token formed by reading the specified
4152 number of characters (interpreting blanks and otherwise-comments too)
4153 from the input file. It is up to syntactic analysis to call this routine
4154 again with 0 to turn hollerith detection off immediately upon receiving
4155 the token that might or might not be HOLLERITH.
4157 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4158 character constant. Pass the expected termination character (apostrophe
4161 Pass for length either the length of the hollerith (must be > 0), -1
4162 meaning expecting a character constant, or 0 to cancel expectation of
4163 a hollerith only after calling it with a length of > 0 and receiving the
4164 next token (which may or may not have been a HOLLERITH token).
4166 Pass for which either an apostrophe or quote when passing length of -1.
4167 Else which is a don't-care.
4169 Pass for line and column the line/column info for the token beginning the
4170 character or hollerith constant, for use in error messages, when passing
4171 a length of -1 -- this function will invoke ffewhere_line/column_use to
4172 make its own copies. Else line and column are don't-cares (when length
4173 is 0) and the outstanding copies of the previous line/column info, if
4174 still around, are killed.
4177 When called with length of 0, also zero ffelex_raw_mode_. This is
4178 so ffest_save_ can undo the effects of replaying tokens like
4179 APOSTROPHE and QUOTE.
4181 New line, column arguments allow error messages to point to the true
4182 beginning of a character/hollerith constant, rather than the beginning
4183 of the content part, which makes them more consistent and helpful.
4185 New "which" argument allows caller to specify termination character,
4186 which should be apostrophe or double-quote, to support Fortran 90. */
4189 ffelex_set_expecting_hollerith (long length, char which,
4190 ffewhereLine line, ffewhereColumn column)
4193 /* First kill the pending line/col info, if any (should only be pending
4194 when this call has length==0, the previous call had length>0, and a
4195 non-HOLLERITH token was sent in between the calls, but play it safe). */
4197 ffewhere_line_kill (ffelex_raw_where_line_);
4198 ffewhere_column_kill (ffelex_raw_where_col_);
4200 /* Now handle the length function. */
4204 ffelex_expecting_hollerith_ = 0;
4205 ffelex_raw_mode_ = 0;
4206 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4207 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4208 return; /* Don't set new line/column info from args. */
4211 ffelex_raw_mode_ = -1;
4212 ffelex_raw_char_ = which;
4215 default: /* length > 0 */
4216 ffelex_expecting_hollerith_ = length;
4220 /* Now set new line/column information from passed args. */
4222 ffelex_raw_where_line_ = ffewhere_line_use (line);
4223 ffelex_raw_where_col_ = ffewhere_column_use (column);
4226 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4228 ffelex_set_handler((ffelexHandler) my_first_handler);
4230 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4231 after they return, but not while they are active. */
4234 ffelex_set_handler (ffelexHandler first)
4236 ffelex_handler_ = first;
4239 /* ffelex_set_hexnum -- Set hexnum flag
4241 ffelex_set_hexnum(TRUE);
4243 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4244 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4245 the character as the first of the next token. But when parsing a
4246 hexadecimal number, by calling this function with TRUE before starting
4247 the parse of the token itself, lex will interpret [0-9] as the start
4251 ffelex_set_hexnum (bool f)
4256 /* ffelex_set_include -- Set INCLUDE file to be processed next
4258 ffewhereFile wf; // The ffewhereFile object for the file.
4259 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4260 FILE *fi; // The file to INCLUDE.
4261 ffelex_set_include(wf,free_form,fi);
4263 Must be called only after receiving the EOS token following a valid
4264 INCLUDE statement specifying a file that has already been successfully
4268 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4270 assert (ffelex_permit_include_);
4271 assert (!ffelex_set_include_);
4272 ffelex_set_include_ = TRUE;
4273 ffelex_include_free_form_ = free_form;
4274 ffelex_include_file_ = fi;
4275 ffelex_include_wherefile_ = wf;
4278 /* ffelex_set_names -- Set names/name flag, names = TRUE
4280 ffelex_set_names(FALSE);
4282 Lex initially assumes multiple names should be formed. If this function is
4283 called with FALSE, then single names are formed instead. The differences
4284 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4285 and in whether full source-location tracking is performed (it is for
4286 multiple names, not for single names), which is more expensive in terms of
4290 ffelex_set_names (bool f)
4294 ffelex_names_pure_ = FALSE;
4297 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4299 ffelex_set_names_pure(FALSE);
4301 Like ffelex_set_names, except affects both lexers. Normally, the
4302 free-form lexer need not generate NAMES tokens because adjacent NAME
4303 tokens must be separated by spaces which causes the lexer to generate
4304 separate tokens for analysis (whereas in fixed-form the spaces are
4305 ignored resulting in one long token). But in FORMAT statements, for
4306 some reason, the Fortran 90 standard specifies that spaces can occur
4307 anywhere within a format-item-list with no effect on the format spec
4308 (except of course within character string edit descriptors), which means
4309 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4310 statement handling, the existence of spaces makes it hard to deal with,
4311 because each token is seen distinctly (i.e. seven tokens in the latter
4312 example). But when no spaces are provided, as in the former example,
4313 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4314 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4315 One, ffest_kw_format_ does a substring rather than full-string match,
4316 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4317 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4318 and three, error reporting can point to the actual character rather than
4319 at or prior to it. The first two things could be resolved by providing
4320 alternate functions fairly easy, thus allowing FORMAT handling to expect
4321 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4322 changes to FORMAT parsing), but the third, error reporting, would suffer,
4323 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4324 to exactly where the compilers thinks the problem is, to even begin to get
4325 a handle on it. So there. */
4328 ffelex_set_names_pure (bool f)
4330 ffelex_names_pure_ = f;
4334 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4336 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4339 Returns first_handler if start_char_index chars into master_token (which
4340 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4341 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4342 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4343 and sends it to first_handler. If anything other than NAME is sent, the
4344 character at the end of it in the master token is examined to see if it
4345 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4346 the handler returned by first_handler is invoked with that token, and
4347 this process is repeated until the end of the master token or a NAME
4348 token is reached. */
4351 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4352 ffeTokenLength start)
4358 p = ffelex_token_text (master) + (i = start);
4364 t = ffelex_token_number_from_names (master, i);
4365 p += ffelex_token_length (t);
4366 i += ffelex_token_length (t);
4368 else if (ffesrc_is_name_init (*p))
4370 t = ffelex_token_name_from_names (master, i, 0);
4371 p += ffelex_token_length (t);
4372 i += ffelex_token_length (t);
4376 t = ffelex_token_dollar_from_names (master, i);
4382 t = ffelex_token_uscore_from_names (master, i);
4388 assert ("not a valid NAMES character" == NULL);
4391 assert (first != NULL);
4392 first = (ffelexHandler) (*first) (t);
4393 ffelex_token_kill (t);
4399 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4401 return ffelex_swallow_tokens;
4403 Return this handler when you don't want to look at any more tokens in the
4404 statement because you've encountered an unrecoverable error in the
4408 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4410 assert (handler != NULL);
4412 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4413 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4414 return (ffelexHandler) (*handler) (t);
4416 ffelex_eos_handler_ = handler;
4417 return (ffelexHandler) ffelex_swallow_tokens_;
4420 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4423 t = ffelex_token_dollar_from_names(t,6);
4425 It's as if you made a new token of dollar type having the dollar
4426 at, in the example above, the sixth character of the NAMES token. */
4429 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4434 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4435 assert (start < t->length);
4436 assert (t->text[start] == '$');
4438 /* Now make the token. */
4440 nt = ffelex_token_new_ ();
4441 nt->type = FFELEX_typeDOLLAR;
4444 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4445 t->where_col, t->wheretrack, start);
4450 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4453 ffelex_token_kill(t);
4455 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4458 ffelex_token_kill (ffelexToken t)
4462 assert (t->uses > 0);
4467 --ffelex_total_tokens_;
4469 if (t->type == FFELEX_typeNAMES)
4470 ffewhere_track_kill (t->where_line, t->where_col,
4471 t->wheretrack, t->length);
4472 ffewhere_line_kill (t->where_line);
4473 ffewhere_column_kill (t->where_col);
4474 if (t->text != NULL)
4475 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4476 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4479 /* Make a new NAME token that is a substring of a NAMES token. */
4482 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4488 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4489 assert (start < t->length);
4491 len = t->length - start;
4495 assert ((start + len) <= t->length);
4497 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4499 nt = ffelex_token_new_ ();
4500 nt->type = FFELEX_typeNAME;
4501 nt->size = len; /* Assume nobody's gonna fiddle with token
4505 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4506 t->where_col, t->wheretrack, start);
4507 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4509 strncpy (nt->text, t->text + start, len);
4510 nt->text[len] = '\0';
4514 /* Make a new NAMES token that is a substring of another NAMES token. */
4517 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4523 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4524 assert (start < t->length);
4526 len = t->length - start;
4530 assert ((start + len) <= t->length);
4532 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4534 nt = ffelex_token_new_ ();
4535 nt->type = FFELEX_typeNAMES;
4536 nt->size = len; /* Assume nobody's gonna fiddle with token
4540 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4541 t->where_col, t->wheretrack, start);
4542 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4543 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4545 strncpy (nt->text, t->text + start, len);
4546 nt->text[len] = '\0';
4550 /* Make a new CHARACTER token. */
4553 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4557 t = ffelex_token_new_ ();
4558 t->type = FFELEX_typeCHARACTER;
4559 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4561 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4563 strcpy (t->text, s);
4564 t->where_line = ffewhere_line_use (l);
4565 t->where_col = ffewhere_column_new (c);
4569 /* Make a new EOF token right after end of file. */
4572 ffelex_token_new_eof ()
4576 t = ffelex_token_new_ ();
4577 t->type = FFELEX_typeEOF;
4580 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4581 t->where_col = ffewhere_column_new (1);
4585 /* Make a new NAME token. */
4588 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4592 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4594 t = ffelex_token_new_ ();
4595 t->type = FFELEX_typeNAME;
4596 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4598 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4600 strcpy (t->text, s);
4601 t->where_line = ffewhere_line_use (l);
4602 t->where_col = ffewhere_column_new (c);
4606 /* Make a new NAMES token. */
4609 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4613 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4615 t = ffelex_token_new_ ();
4616 t->type = FFELEX_typeNAMES;
4617 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4619 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4621 strcpy (t->text, s);
4622 t->where_line = ffewhere_line_use (l);
4623 t->where_col = ffewhere_column_new (c);
4624 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4629 /* Make a new NUMBER token.
4631 The first character of the string must be a digit, and only the digits
4632 are copied into the new number. So this may be used to easily extract
4633 a NUMBER token from within any text string. Then the length of the
4634 resulting token may be used to calculate where the digits stopped
4635 in the original string. */
4638 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4643 /* How long is the string of decimal digits at s? */
4645 len = strspn (s, "0123456789");
4647 /* Make sure there is at least one digit. */
4651 /* Now make the token. */
4653 t = ffelex_token_new_ ();
4654 t->type = FFELEX_typeNUMBER;
4655 t->length = t->size = len; /* Assume it won't get bigger. */
4657 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4659 strncpy (t->text, s, len);
4660 t->text[len] = '\0';
4661 t->where_line = ffewhere_line_use (l);
4662 t->where_col = ffewhere_column_new (c);
4666 /* Make a new token of any type that doesn't contain text. A private
4667 function that is used by public macros in the interface file. */
4670 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4674 t = ffelex_token_new_ ();
4678 t->where_line = ffewhere_line_use (l);
4679 t->where_col = ffewhere_column_new (c);
4683 /* Make a new NUMBER token from an existing NAMES token.
4685 Like ffelex_token_new_number, this function calculates the length
4686 of the digit string itself. */
4689 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4695 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4696 assert (start < t->length);
4698 /* How long is the string of decimal digits at s? */
4700 len = strspn (t->text + start, "0123456789");
4702 /* Make sure there is at least one digit. */
4706 /* Now make the token. */
4708 nt = ffelex_token_new_ ();
4709 nt->type = FFELEX_typeNUMBER;
4710 nt->size = len; /* Assume nobody's gonna fiddle with token
4714 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4715 t->where_col, t->wheretrack, start);
4716 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4718 strncpy (nt->text, t->text + start, len);
4719 nt->text[len] = '\0';
4723 /* Make a new UNDERSCORE token from a NAMES token. */
4726 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4731 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4732 assert (start < t->length);
4733 assert (t->text[start] == '_');
4735 /* Now make the token. */
4737 nt = ffelex_token_new_ ();
4738 nt->type = FFELEX_typeUNDERSCORE;
4740 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4741 t->where_col, t->wheretrack, start);
4746 /* ffelex_token_use -- Return another instance of a token
4749 t = ffelex_token_use(t);
4751 In a sense, the new token is a copy of the old, though it might be the
4752 same with just a new use count.
4754 We use the use count method (easy). */
4757 ffelex_token_use (ffelexToken t)
4760 assert ("_token_use: null token" == NULL);