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
30 #if FFECOM_targetCURRENT == FFECOM_targetGCC
38 static void ffelex_append_to_token_ (char c);
39 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
40 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
41 ffewhereColumnNumber cn0);
42 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
43 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
44 ffewhereColumnNumber cn1);
45 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
46 ffewhereColumnNumber cn0);
47 static void ffelex_finish_statement_ (void);
48 #if FFECOM_targetCURRENT == FFECOM_targetGCC
49 static int ffelex_get_directive_line_ (char **text, FILE *finput);
50 static int ffelex_hash_ (FILE *f);
52 static ffewhereColumnNumber ffelex_image_char_ (int c,
53 ffewhereColumnNumber col);
54 static void ffelex_include_ (void);
55 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
56 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
57 static void ffelex_next_line_ (void);
58 static void ffelex_prepare_eos_ (void);
59 static void ffelex_send_token_ (void);
60 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
61 static ffelexToken ffelex_token_new_ (void);
63 /* Pertaining to the geometry of the input file. */
65 /* Initial size for card image to be allocated. */
66 #define FFELEX_columnINITIAL_SIZE_ 255
68 /* The card image itself, which grows as source lines get longer. It
69 has room for ffelex_card_size_ + 8 characters, and the length of the
70 current image is ffelex_card_length_. (The + 8 characters are made
71 available for easy handling of tabs and such.) */
72 static char *ffelex_card_image_;
73 static ffewhereColumnNumber ffelex_card_size_;
74 static ffewhereColumnNumber ffelex_card_length_;
76 /* Max width for free-form lines (ISO F90). */
77 #define FFELEX_FREE_MAX_COLUMNS_ 132
79 /* True if we saw a tab on the current line, as this (currently) means
80 the line is therefore treated as though final_nontab_column_ were
82 static bool ffelex_saw_tab_;
84 /* TRUE if current line is known to be erroneous, so don't bother
85 expanding room for it just to display it. */
86 static bool ffelex_bad_line_ = FALSE;
88 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
89 static ffewhereColumnNumber ffelex_final_nontab_column_;
91 /* Array for quickly deciding what kind of line the current card has,
92 based on its first character. */
93 static ffelexType ffelex_first_char_[256];
95 /* Pertaining to file management. */
97 /* The wf argument of the most recent active ffelex_file_(fixed,free)
99 static ffewhereFile ffelex_current_wf_;
101 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
103 static bool ffelex_permit_include_;
105 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
107 static bool ffelex_set_include_;
109 /* Information on the pending INCLUDE file. */
110 static FILE *ffelex_include_file_;
111 static bool ffelex_include_free_form_;
112 static ffewhereFile ffelex_include_wherefile_;
114 /* Current master line count. */
115 static ffewhereLineNumber ffelex_linecount_current_;
116 /* Next master line count. */
117 static ffewhereLineNumber ffelex_linecount_next_;
119 /* ffewhere info on the latest (currently active) line read from the
120 active source file. */
121 static ffewhereLine ffelex_current_wl_;
122 static ffewhereColumn ffelex_current_wc_;
124 /* Pertaining to tokens in general. */
126 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
128 #define FFELEX_columnTOKEN_SIZE_ 63
129 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
130 #error "token size too small!"
133 /* Current token being lexed. */
134 static ffelexToken ffelex_token_;
136 /* Handler for current token. */
137 static ffelexHandler ffelex_handler_;
139 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
140 static bool ffelex_names_;
142 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
143 static bool ffelex_names_pure_;
145 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
147 static bool ffelex_hexnum_;
149 /* For ffelex_swallow_tokens(). */
150 static ffelexHandler ffelex_eos_handler_;
152 /* Number of tokens sent since last EOS or beginning of input file
153 (include INCLUDEd files). */
154 static unsigned long int ffelex_number_of_tokens_;
156 /* Number of labels sent (as NUMBER tokens) since last reset of
157 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
158 (Fixed-form source only.) */
159 static unsigned long int ffelex_label_tokens_;
161 /* Metering for token management, to catch token-memory leaks. */
162 static long int ffelex_total_tokens_ = 0;
163 static long int ffelex_old_total_tokens_ = 1;
164 static long int ffelex_token_nextid_ = 0;
166 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
168 /* >0 if a Hollerith constant of that length might be in mid-lex, used
169 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
170 mode (see ffelex_raw_mode_). */
171 static long int ffelex_expecting_hollerith_;
173 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
174 -2: Possible closing apostrophe/quote seen in CHARACTER.
175 -1: Lexing CHARACTER.
176 0: Not lexing CHARACTER or HOLLERITH.
177 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
178 static long int ffelex_raw_mode_;
180 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
181 static char ffelex_raw_char_;
183 /* TRUE when backslash processing had to use most recent character
184 to finish its state engine, but that character is not part of
185 the backslash sequence, so must be reconsidered as a "normal"
186 character in CHARACTER/HOLLERITH lexing. */
187 static bool ffelex_backslash_reconsider_ = FALSE;
189 /* Characters preread before lexing happened (might include EOF). */
190 static int *ffelex_kludge_chars_ = NULL;
192 /* Doing the kludge processing, so not initialized yet. */
193 static bool ffelex_kludge_flag_ = FALSE;
195 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
196 static ffewhereLine ffelex_raw_where_line_;
197 static ffewhereColumn ffelex_raw_where_col_;
200 /* Call this to append another character to the current token. If it isn't
201 currently big enough for it, it will be enlarged. The current token
202 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
205 ffelex_append_to_token_ (char c)
207 if (ffelex_token_->text == NULL)
210 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
211 FFELEX_columnTOKEN_SIZE_ + 1);
212 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
213 ffelex_token_->length = 0;
215 else if (ffelex_token_->length >= ffelex_token_->size)
218 = malloc_resize_ksr (malloc_pool_image (),
220 (ffelex_token_->size << 1) + 1,
221 ffelex_token_->size + 1);
222 ffelex_token_->size <<= 1;
223 assert (ffelex_token_->length < ffelex_token_->size);
226 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
227 please contact fortran@gnu.org if you wish to fund work to
228 port g77 to non-ASCII machines.
230 ffelex_token_->text[ffelex_token_->length++] = c;
233 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
237 ffelex_backslash_ (int c, ffewhereColumnNumber col)
239 static int state = 0;
240 static unsigned int count;
242 static unsigned int firstdig = 0;
244 static ffewhereLineNumber line;
245 static ffewhereColumnNumber column;
247 /* See gcc/c-lex.c readescape() for a straightforward version
248 of this state engine for handling backslashes in character/
249 hollerith constants. */
252 #define warn_traditional 0
253 #define flag_traditional 0
259 && (ffelex_raw_mode_ != 0)
260 && ffe_is_backslash ())
264 line = ffelex_linecount_current_;
270 state = 0; /* Assume simple case. */
274 if (warn_traditional)
276 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
277 FFEBAD_severityWARNING);
278 ffelex_bad_here_ (0, line, column);
282 if (flag_traditional)
291 case '0': case '1': case '2': case '3': case '4':
292 case '5': case '6': case '7':
298 case '\\': case '\'': case '"':
301 #if 0 /* Inappropriate for Fortran. */
303 ffelex_next_line_ ();
309 return TARGET_NEWLINE;
324 if (warn_traditional)
326 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
327 FFEBAD_severityWARNING);
328 ffelex_bad_here_ (0, line, column);
332 if (flag_traditional)
337 #if 0 /* Vertical tab is present in common usage compilers. */
338 if (flag_traditional)
355 ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
356 FFEBAD_severityPEDANTIC);
357 ffelex_bad_here_ (0, line, column);
361 return (c == 'E' || c == 'e') ? 033 : c;
367 if (c >= 040 && c < 0177)
373 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
374 FFEBAD_severityPEDANTIC);
375 ffelex_bad_here_ (0, line, column);
381 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
382 FFEBAD_severityPEDANTIC);
383 ffelex_bad_here_ (0, line, column);
390 sprintf (&m[0], "%x", c);
391 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
392 FFEBAD_severityPEDANTIC);
393 ffelex_bad_here_ (0, line, column);
401 if ((c >= 'a' && c <= 'f')
402 || (c >= 'A' && c <= 'F')
403 || (c >= '0' && c <= '9'))
406 if (c >= 'a' && c <= 'f')
407 code += c - 'a' + 10;
408 if (c >= 'A' && c <= 'F')
409 code += c - 'A' + 10;
410 if (c >= '0' && c <= '9')
412 if (code != 0 || count != 0)
426 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
427 FFEBAD_severityFATAL);
428 ffelex_bad_here_ (0, line, column);
432 /* Digits are all 0's. Ok. */
434 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
436 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
439 ffebad_start_msg_lex ("Hex escape at %0 out of range",
440 FFEBAD_severityPEDANTIC);
441 ffelex_bad_here_ (0, line, column);
447 if ((c <= '7') && (c >= '0') && (count++ < 3))
449 code = (code * 8) + (c - '0');
456 assert ("bad backslash state" == NULL);
460 /* Come here when code has a built character, and c is the next
461 character that might (or might not) be the next one in the constant. */
463 /* Don't bother doing this check for each character going into
464 CHARACTER or HOLLERITH constants, just the escaped-value ones.
465 gcc apparently checks every single character, which seems
466 like it'd be kinda slow and not worth doing anyway. */
469 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
470 && code >= (1 << TYPE_PRECISION (char_type_node)))
472 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
473 FFEBAD_severityFATAL);
474 ffelex_bad_here_ (0, line, column);
480 /* Known end of constant, just append this character. */
481 ffelex_append_to_token_ (code);
482 if (ffelex_raw_mode_ > 0)
487 /* Have two characters to handle. Do the first, then leave it to the
488 caller to detect anything special about the second. */
490 ffelex_append_to_token_ (code);
491 if (ffelex_raw_mode_ > 0)
493 ffelex_backslash_reconsider_ = TRUE;
497 /* ffelex_bad_1_ -- Issue diagnostic with one source point
499 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
501 Creates ffewhere line and column objects for the source point, sends them
502 along with the error code to ffebad, then kills the line and column
503 objects before returning. */
506 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
511 wl0 = ffewhere_line_new (ln0);
512 wc0 = ffewhere_column_new (cn0);
513 ffebad_start_lex (errnum);
514 ffebad_here (0, wl0, wc0);
516 ffewhere_line_kill (wl0);
517 ffewhere_column_kill (wc0);
520 /* ffelex_bad_2_ -- Issue diagnostic with two source points
522 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
523 otherline,othercolumn);
525 Creates ffewhere line and column objects for the source points, sends them
526 along with the error code to ffebad, then kills the line and column
527 objects before returning. */
530 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
531 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
533 ffewhereLine wl0, wl1;
534 ffewhereColumn wc0, wc1;
536 wl0 = ffewhere_line_new (ln0);
537 wc0 = ffewhere_column_new (cn0);
538 wl1 = ffewhere_line_new (ln1);
539 wc1 = ffewhere_column_new (cn1);
540 ffebad_start_lex (errnum);
541 ffebad_here (0, wl0, wc0);
542 ffebad_here (1, wl1, wc1);
544 ffewhere_line_kill (wl0);
545 ffewhere_column_kill (wc0);
546 ffewhere_line_kill (wl1);
547 ffewhere_column_kill (wc1);
551 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
552 ffewhereColumnNumber cn0)
557 wl0 = ffewhere_line_new (ln0);
558 wc0 = ffewhere_column_new (cn0);
559 ffebad_here (n, wl0, wc0);
560 ffewhere_line_kill (wl0);
561 ffewhere_column_kill (wc0);
564 #if FFECOM_targetCURRENT == FFECOM_targetGCC
566 ffelex_getc_ (FILE *finput)
570 if (ffelex_kludge_chars_ == NULL)
571 return getc (finput);
573 c = *ffelex_kludge_chars_++;
577 ffelex_kludge_chars_ = NULL;
578 return getc (finput);
582 #if FFECOM_targetCURRENT == FFECOM_targetGCC
584 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
586 register int c = getc (finput);
588 register unsigned count;
589 unsigned firstdig = 0;
597 if (warn_traditional)
598 warning ("the meaning of `\\x' varies with -traditional");
600 if (flag_traditional)
609 if (!(c >= 'a' && c <= 'f')
610 && !(c >= 'A' && c <= 'F')
611 && !(c >= '0' && c <= '9'))
618 if (c >= 'a' && c <= 'f')
619 code += c - 'a' + 10;
620 if (c >= 'A' && c <= 'F')
621 code += c - 'A' + 10;
622 if (c >= '0' && c <= '9')
624 if (code != 0 || count != 0)
633 error ("\\x used with no following hex digits");
635 /* Digits are all 0's. Ok. */
637 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
640 << (TYPE_PRECISION (integer_type_node) - (count - 1)
643 pedwarn ("hex escape out of range");
646 case '0': case '1': case '2': case '3': case '4':
647 case '5': case '6': case '7':
650 while ((c <= '7') && (c >= '0') && (count++ < 3))
652 code = (code * 8) + (c - '0');
659 case '\\': case '\'': case '"':
663 ffelex_next_line_ ();
673 return TARGET_NEWLINE;
688 if (warn_traditional)
689 warning ("the meaning of `\\a' varies with -traditional");
691 if (flag_traditional)
696 #if 0 /* Vertical tab is present in common usage compilers. */
697 if (flag_traditional)
705 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
711 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
715 /* `\%' is used to prevent SCCS from getting confused. */
718 pedwarn ("non-ANSI escape sequence `\\%c'", c);
721 if (c >= 040 && c < 0177)
722 pedwarn ("unknown escape sequence `\\%c'", c);
724 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
729 /* A miniature version of the C front-end lexer. */
731 #if FFECOM_targetCURRENT == FFECOM_targetGCC
733 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
740 register unsigned buffer_length;
742 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
743 ffelex_token_kill (*xtoken);
747 case '0': case '1': case '2': case '3': case '4':
748 case '5': case '6': case '7': case '8': case '9':
749 buffer_length = ARRAY_SIZE (buff);
752 r = &buff[buffer_length];
758 register unsigned bytes_used = (p - q);
761 q = (char *)xrealloc (q, buffer_length);
763 r = &q[buffer_length];
765 c = ffelex_getc_ (finput);
770 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
771 ffewhere_column_unknown ());
779 buffer_length = ARRAY_SIZE (buff);
782 r = &buff[buffer_length];
783 c = ffelex_getc_ (finput);
797 case '\\': /* ~~~~~ */
798 c = ffelex_cfebackslash_ (&use_d, &d, finput);
803 error ("Badly formed directive -- no closing quote");
813 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
818 register unsigned bytes_used = (p - q);
820 buffer_length = bytes_used * 2;
821 q = (char *)xrealloc (q, buffer_length);
823 r = &q[buffer_length];
832 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
833 ffewhere_column_unknown ());
850 #if FFECOM_targetCURRENT == FFECOM_targetGCC
852 ffelex_file_pop_ (const char *input_filename)
854 if (input_file_stack->next)
856 struct file_stack *p = input_file_stack;
857 input_file_stack = p->next;
859 input_file_stack_tick++;
860 (*debug_hooks->end_source_file) (input_file_stack->line);
863 error ("#-lines for entering and leaving files don't match");
865 /* Now that we've pushed or popped the input stack,
866 update the name in the top element. */
867 if (input_file_stack)
868 input_file_stack->name = input_filename;
872 #if FFECOM_targetCURRENT == FFECOM_targetGCC
874 ffelex_file_push_ (int old_lineno, const char *input_filename)
877 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
879 input_file_stack->line = old_lineno;
880 p->next = input_file_stack;
881 p->name = input_filename;
882 input_file_stack = p;
883 input_file_stack_tick++;
885 (*debug_hooks->start_source_file) (0, input_filename);
887 /* Now that we've pushed or popped the input stack,
888 update the name in the top element. */
889 if (input_file_stack)
890 input_file_stack->name = input_filename;
894 /* Prepare to finish a statement-in-progress by sending the current
895 token, if any, then setting up EOS as the current token with the
896 appropriate current pointer. The caller can then move the current
897 pointer before actually sending EOS, if desired, as it is in
898 typical fixed-form cases. */
901 ffelex_prepare_eos_ ()
903 if (ffelex_token_->type != FFELEX_typeNONE)
905 ffelex_backslash_ (EOF, 0);
907 switch (ffelex_raw_mode_)
913 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
914 : FFEBAD_NO_CLOSING_QUOTE);
915 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
916 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
927 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
928 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
929 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
930 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
933 /* Make sure the token has some text, might as well fill up with spaces. */
936 ffelex_append_to_token_ (' ');
937 } while (--ffelex_raw_mode_ > 0);
941 ffelex_raw_mode_ = 0;
942 ffelex_send_token_ ();
944 ffelex_token_->type = FFELEX_typeEOS;
945 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
946 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
950 ffelex_finish_statement_ ()
952 if ((ffelex_number_of_tokens_ == 0)
953 && (ffelex_token_->type == FFELEX_typeNONE))
954 return; /* Don't have a statement pending. */
956 if (ffelex_token_->type != FFELEX_typeEOS)
957 ffelex_prepare_eos_ ();
959 ffelex_permit_include_ = TRUE;
960 ffelex_send_token_ ();
961 ffelex_permit_include_ = FALSE;
962 ffelex_number_of_tokens_ = 0;
963 ffelex_label_tokens_ = 0;
964 ffelex_names_ = TRUE;
965 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
966 ffelex_hexnum_ = FALSE;
968 if (!ffe_is_ffedebug ())
971 /* For debugging purposes only. */
973 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
975 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
976 ffelex_old_total_tokens_, ffelex_total_tokens_);
977 ffelex_old_total_tokens_ = ffelex_total_tokens_;
981 /* Copied from gcc/c-common.c get_directive_line. */
983 #if FFECOM_targetCURRENT == FFECOM_targetGCC
985 ffelex_get_directive_line_ (char **text, FILE *finput)
987 static char *directive_buffer = NULL;
988 static unsigned buffer_length = 0;
990 register char *buffer_limit;
991 register int looking_for = 0;
992 register int char_escaped = 0;
994 if (buffer_length == 0)
996 directive_buffer = (char *)xmalloc (128);
1000 buffer_limit = &directive_buffer[buffer_length];
1002 for (p = directive_buffer; ; )
1006 /* Make buffer bigger if it is full. */
1007 if (p >= buffer_limit)
1009 register unsigned bytes_used = (p - directive_buffer);
1013 = (char *)xrealloc (directive_buffer, buffer_length);
1014 p = &directive_buffer[bytes_used];
1015 buffer_limit = &directive_buffer[buffer_length];
1020 /* Discard initial whitespace. */
1021 if ((c == ' ' || c == '\t') && p == directive_buffer)
1024 /* Detect the end of the directive. */
1025 if ((c == '\n' && looking_for == 0)
1028 if (looking_for != 0)
1029 error ("Bad directive -- missing close-quote");
1032 *text = directive_buffer;
1038 ffelex_next_line_ ();
1040 /* Handle string and character constant syntax. */
1043 if (looking_for == c && !char_escaped)
1044 looking_for = 0; /* Found terminator... stop looking. */
1047 if (c == '\'' || c == '"')
1048 looking_for = c; /* Don't stop buffering until we see another
1049 one of these (or an EOF). */
1051 /* Handle backslash. */
1052 char_escaped = (c == '\\' && ! char_escaped);
1057 /* Handle # directives that make it through (or are generated by) the
1058 preprocessor. As much as reasonably possible, emulate the behavior
1059 of the gcc compiler phase cc1, though interactions between #include
1060 and INCLUDE might possibly produce bizarre results in terms of
1061 error reporting and the generation of debugging info vis-a-vis the
1062 locations of some things.
1064 Returns the next character unhandled, which is always newline or EOF. */
1066 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1068 #if defined HANDLE_PRAGMA
1069 /* Local versions of these macros, that can be passed as function pointers. */
1073 return getc (finput);
1080 ungetc (arg, finput);
1082 #endif /* HANDLE_PRAGMA */
1085 ffelex_hash_ (FILE *finput)
1088 ffelexToken token = NULL;
1090 /* Read first nonwhite char after the `#'. */
1092 c = ffelex_getc_ (finput);
1093 while (c == ' ' || c == '\t')
1094 c = ffelex_getc_ (finput);
1096 /* If a letter follows, then if the word here is `line', skip
1097 it and ignore it; otherwise, ignore the line, with an error
1098 if the word isn't `pragma', `ident', `define', or `undef'. */
1100 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
1104 if (getc (finput) == 'r'
1105 && getc (finput) == 'a'
1106 && getc (finput) == 'g'
1107 && getc (finput) == 'm'
1108 && getc (finput) == 'a'
1109 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1112 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1113 static char buffer [128];
1114 char * buff = buffer;
1116 /* Read the pragma name into a buffer.
1117 ISSPACE() may evaluate its argument more than once! */
1118 while (((c = getc (finput)), ISSPACE(c)))
1126 while (c != EOF && ! ISSPACE (c) && c != '\n'
1127 && buff < buffer + 128);
1132 #ifdef HANDLE_PRAGMA
1133 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1135 #endif /* HANDLE_PRAGMA */
1136 #ifdef HANDLE_GENERIC_PRAGMAS
1137 if (handle_generic_pragma (buffer))
1139 #endif /* !HANDLE_GENERIC_PRAGMAS */
1141 /* Issue a warning message if we have been asked to do so.
1142 Ignoring unknown pragmas in system header file unless
1143 an explcit -Wunknown-pragmas has been given. */
1144 if (warn_unknown_pragmas > 1
1145 || (warn_unknown_pragmas && ! in_system_header))
1146 warning ("ignoring pragma: %s", token_buffer);
1154 if (getc (finput) == 'e'
1155 && getc (finput) == 'f'
1156 && getc (finput) == 'i'
1157 && getc (finput) == 'n'
1158 && getc (finput) == 'e'
1159 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1164 c = ffelex_get_directive_line_ (&text, finput);
1166 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1167 (*debug_hooks->define) (lineno, text);
1174 if (getc (finput) == 'n'
1175 && getc (finput) == 'd'
1176 && getc (finput) == 'e'
1177 && getc (finput) == 'f'
1178 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1183 c = ffelex_get_directive_line_ (&text, finput);
1185 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1186 (*debug_hooks->undef) (lineno, text);
1193 if (getc (finput) == 'i'
1194 && getc (finput) == 'n'
1195 && getc (finput) == 'e'
1196 && ((c = getc (finput)) == ' ' || c == '\t'))
1201 if (getc (finput) == 'd'
1202 && getc (finput) == 'e'
1203 && getc (finput) == 'n'
1204 && getc (finput) == 't'
1205 && ((c = getc (finput)) == ' ' || c == '\t'))
1207 /* #ident. The pedantic warning is now in cpp. */
1209 /* Here we have just seen `#ident '.
1210 A string constant should follow. */
1212 while (c == ' ' || c == '\t')
1215 /* If no argument, ignore the line. */
1216 if (c == '\n' || c == EOF)
1219 c = ffelex_cfelex_ (&token, finput, c);
1222 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1224 error ("invalid #ident");
1228 if (! flag_no_ident)
1230 #ifdef ASM_OUTPUT_IDENT
1231 ASM_OUTPUT_IDENT (asm_out_file,
1232 ffelex_token_text (token));
1236 /* Skip the rest of this line. */
1241 error ("undefined or invalid # directive");
1246 /* Here we have either `#line' or `# <nonletter>'.
1247 In either case, it should be a line number; a digit should follow. */
1249 while (c == ' ' || c == '\t')
1250 c = ffelex_getc_ (finput);
1252 /* If the # is the only nonwhite char on the line,
1253 just ignore it. Check the new newline. */
1254 if (c == '\n' || c == EOF)
1257 /* Something follows the #; read a token. */
1259 c = ffelex_cfelex_ (&token, finput, c);
1262 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1264 int old_lineno = lineno;
1265 const char *old_input_filename = input_filename;
1268 /* subtract one, because it is the following line that
1269 gets the specified number */
1270 int l = atoi (ffelex_token_text (token)) - 1;
1272 /* Is this the last nonwhite stuff on the line? */
1273 while (c == ' ' || c == '\t')
1274 c = ffelex_getc_ (finput);
1275 if (c == '\n' || c == EOF)
1277 /* No more: store the line number and check following line. */
1279 if (!ffelex_kludge_flag_)
1281 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1284 ffelex_token_kill (token);
1289 /* More follows: it must be a string constant (filename). */
1291 /* Read the string constant. */
1292 c = ffelex_cfelex_ (&token, finput, c);
1295 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1297 error ("invalid #line");
1303 if (ffelex_kludge_flag_)
1304 input_filename = ggc_strdup (ffelex_token_text (token));
1307 wf = ffewhere_file_new (ffelex_token_text (token),
1308 ffelex_token_length (token));
1309 input_filename = ffewhere_file_name (wf);
1310 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1313 #if 0 /* Not sure what g77 should do with this yet. */
1314 /* Each change of file name
1315 reinitializes whether we are now in a system header. */
1316 in_system_header = 0;
1319 if (main_input_filename == 0)
1320 main_input_filename = input_filename;
1322 /* Is this the last nonwhite stuff on the line? */
1323 while (c == ' ' || c == '\t')
1325 if (c == '\n' || c == EOF)
1327 if (!ffelex_kludge_flag_)
1329 /* Update the name in the top element of input_file_stack. */
1330 if (input_file_stack)
1331 input_file_stack->name = input_filename;
1334 ffelex_token_kill (token);
1339 c = ffelex_cfelex_ (&token, finput, c);
1341 /* `1' after file name means entering new file.
1342 `2' after file name means just left a file. */
1345 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1347 int num = atoi (ffelex_token_text (token));
1349 if (ffelex_kludge_flag_)
1352 input_filename = old_input_filename;
1353 error ("Use `#line ...' instead of `# ...' in first line");
1358 /* Pushing to a new file. */
1359 ffelex_file_push_ (old_lineno, input_filename);
1363 /* Popping out of a file. */
1364 ffelex_file_pop_ (input_filename);
1367 /* Is this the last nonwhite stuff on the line? */
1368 while (c == ' ' || c == '\t')
1370 if (c == '\n' || c == EOF)
1373 ffelex_token_kill (token);
1377 c = ffelex_cfelex_ (&token, finput, c);
1380 /* `3' after file name means this is a system header file. */
1382 #if 0 /* Not sure what g77 should do with this yet. */
1384 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1385 && (atoi (ffelex_token_text (token)) == 3))
1386 in_system_header = 1;
1389 while (c == ' ' || c == '\t')
1391 if (((token != NULL)
1392 || (c != '\n' && c != EOF))
1393 && ffelex_kludge_flag_)
1396 input_filename = old_input_filename;
1397 error ("Use `#line ...' instead of `# ...' in first line");
1399 if (c == '\n' || c == EOF)
1401 if (token != NULL && !ffelex_kludge_flag_)
1402 ffelex_token_kill (token);
1407 error ("invalid #-line");
1409 /* skip the rest of this line. */
1411 if ((token != NULL) && !ffelex_kludge_flag_)
1412 ffelex_token_kill (token);
1413 while ((c = getc (finput)) != EOF && c != '\n')
1417 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1419 /* "Image" a character onto the card image, return incremented column number.
1421 Normally invoking this function as in
1422 column = ffelex_image_char_ (c, column);
1423 is the same as doing:
1424 ffelex_card_image_[column++] = c;
1426 However, tabs and carriage returns are handled specially, to preserve
1427 the visual "image" of the input line (in most editors) in the card
1430 Carriage returns are ignored, as they are assumed to be followed
1433 A tab is handled by first doing:
1434 ffelex_card_image_[column++] = ' ';
1435 That is, it translates to at least one space. Then, as many spaces
1436 are imaged as necessary to bring the column number to the next tab
1437 position, where tab positions start in the ninth column and each
1438 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1439 is set to TRUE to notify the lexer that a tab was seen.
1441 Columns are numbered and tab stops set as illustrated below:
1443 012345670123456701234567...
1447 xxxxxxx yyyyyyy zzzzzzz
1448 xxxxxxxx yyyyyyyy... */
1450 static ffewhereColumnNumber
1451 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1453 ffewhereColumnNumber old_column = column;
1455 if (column >= ffelex_card_size_)
1457 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1459 if (ffelex_bad_line_)
1462 if ((newmax >> 1) != ffelex_card_size_)
1463 { /* Overflowed column number. */
1464 overflow: /* :::::::::::::::::::: */
1466 ffelex_bad_line_ = TRUE;
1467 strcpy (&ffelex_card_image_[column - 3], "...");
1468 ffelex_card_length_ = column;
1469 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1470 ffelex_linecount_current_, column + 1);
1475 = malloc_resize_ksr (malloc_pool_image (),
1478 ffelex_card_size_ + 9);
1479 ffelex_card_size_ = newmax;
1488 ffelex_saw_tab_ = TRUE;
1489 ffelex_card_image_[column++] = ' ';
1490 while ((column & 7) != 0)
1491 ffelex_card_image_[column++] = ' ';
1495 if (!ffelex_bad_line_)
1497 ffelex_bad_line_ = TRUE;
1498 strcpy (&ffelex_card_image_[column], "[\\0]");
1499 ffelex_card_length_ = column + 4;
1500 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1501 FFEBAD_severityFATAL);
1502 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1509 ffelex_card_image_[column++] = c;
1513 if (column < old_column)
1515 column = old_column;
1516 goto overflow; /* :::::::::::::::::::: */
1525 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1526 FILE *include_file = ffelex_include_file_;
1527 /* The rest of this is to push, and after the INCLUDE file is processed,
1528 pop, the static lexer state info that pertains to each particular
1531 ffewhereColumnNumber card_size = ffelex_card_size_;
1532 ffewhereColumnNumber card_length = ffelex_card_length_;
1533 ffewhereLine current_wl = ffelex_current_wl_;
1534 ffewhereColumn current_wc = ffelex_current_wc_;
1535 bool saw_tab = ffelex_saw_tab_;
1536 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1537 ffewhereFile current_wf = ffelex_current_wf_;
1538 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1539 ffewhereLineNumber linecount_offset
1540 = ffewhere_line_filelinenum (current_wl);
1541 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1542 int old_lineno = lineno;
1543 const char *old_input_filename = input_filename;
1546 if (card_length != 0)
1548 card_image = malloc_new_ks (malloc_pool_image (),
1549 "FFELEX saved card image",
1551 memcpy (card_image, ffelex_card_image_, card_length);
1556 ffelex_set_include_ = FALSE;
1558 ffelex_next_line_ ();
1560 ffewhere_file_set (include_wherefile, TRUE, 0);
1562 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1563 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1564 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1566 if (ffelex_include_free_form_)
1567 ffelex_file_free (include_wherefile, include_file);
1569 ffelex_file_fixed (include_wherefile, include_file);
1571 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1572 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1573 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1575 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1577 ffecom_close_include (include_file);
1579 if (card_length != 0)
1581 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1582 #error "need to handle possible reduction of card size here!!"
1584 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1585 memcpy (ffelex_card_image_, card_image, card_length);
1587 ffelex_card_image_[card_length] = '\0';
1589 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1590 input_filename = old_input_filename;
1591 lineno = old_lineno;
1593 ffelex_linecount_current_ = linecount_current;
1594 ffelex_current_wf_ = current_wf;
1595 ffelex_final_nontab_column_ = final_nontab_column;
1596 ffelex_saw_tab_ = saw_tab;
1597 ffelex_current_wc_ = current_wc;
1598 ffelex_current_wl_ = current_wl;
1599 ffelex_card_length_ = card_length;
1600 ffelex_card_size_ = card_size;
1603 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1605 ffewhereColumnNumber col;
1606 int c; // Char at col.
1607 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1608 // We have a continuation indicator.
1610 If there are <n> spaces starting at ffelex_card_image_[col] up through
1611 the null character, where <n> is 0 or greater, returns TRUE. */
1614 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1616 while (ffelex_card_image_[col] != '\0')
1618 if (ffelex_card_image_[col++] != ' ')
1624 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1626 ffewhereColumnNumber col;
1627 int c; // Char at col.
1628 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1629 // We have a continuation indicator.
1631 If there are <n> spaces starting at ffelex_card_image_[col] up through
1632 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1635 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1637 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1639 if (ffelex_card_image_[col++] != ' ')
1646 ffelex_next_line_ ()
1648 ffelex_linecount_current_ = ffelex_linecount_next_;
1649 ++ffelex_linecount_next_;
1650 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1656 ffelex_send_token_ ()
1658 ++ffelex_number_of_tokens_;
1660 ffelex_backslash_ (EOF, 0);
1662 if (ffelex_token_->text == NULL)
1664 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1666 ffelex_append_to_token_ ('\0');
1667 ffelex_token_->length = 0;
1671 ffelex_token_->text[ffelex_token_->length] = '\0';
1673 assert (ffelex_raw_mode_ == 0);
1675 if (ffelex_token_->type == FFELEX_typeNAMES)
1677 ffewhere_line_kill (ffelex_token_->currentnames_line);
1678 ffewhere_column_kill (ffelex_token_->currentnames_col);
1681 assert (ffelex_handler_ != NULL);
1682 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1683 assert (ffelex_handler_ != NULL);
1685 ffelex_token_kill (ffelex_token_);
1687 ffelex_token_ = ffelex_token_new_ ();
1688 ffelex_token_->uses = 1;
1689 ffelex_token_->text = NULL;
1690 if (ffelex_raw_mode_ < 0)
1692 ffelex_token_->type = FFELEX_typeCHARACTER;
1693 ffelex_token_->where_line = ffelex_raw_where_line_;
1694 ffelex_token_->where_col = ffelex_raw_where_col_;
1695 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1696 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1700 ffelex_token_->type = FFELEX_typeNONE;
1701 ffelex_token_->where_line = ffewhere_line_unknown ();
1702 ffelex_token_->where_col = ffewhere_column_unknown ();
1705 if (ffelex_set_include_)
1709 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1711 return ffelex_swallow_tokens_;
1713 Return this handler when you don't want to look at any more tokens in the
1714 statement because you've encountered an unrecoverable error in the
1717 static ffelexHandler
1718 ffelex_swallow_tokens_ (ffelexToken t)
1720 assert (ffelex_eos_handler_ != NULL);
1722 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1723 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1724 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1726 return (ffelexHandler) ffelex_swallow_tokens_;
1730 ffelex_token_new_ ()
1734 ++ffelex_total_tokens_;
1736 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1737 "FFELEX token", sizeof (*t));
1738 t->id_ = ffelex_token_nextid_++;
1743 ffelex_type_string_ (ffelexType type)
1745 static const char *types[] = {
1747 "FFELEX_typeCOMMENT",
1753 "FFELEX_typeDOLLAR",
1755 "FFELEX_typePERCENT",
1756 "FFELEX_typeAMPERSAND",
1757 "FFELEX_typeAPOSTROPHE",
1758 "FFELEX_typeOPEN_PAREN",
1759 "FFELEX_typeCLOSE_PAREN",
1760 "FFELEX_typeASTERISK",
1763 "FFELEX_typePERIOD",
1765 "FFELEX_typeNUMBER",
1766 "FFELEX_typeOPEN_ANGLE",
1767 "FFELEX_typeEQUALS",
1768 "FFELEX_typeCLOSE_ANGLE",
1772 "FFELEX_typeCONCAT",
1775 "FFELEX_typeHOLLERITH",
1776 "FFELEX_typeCHARACTER",
1778 "FFELEX_typeSEMICOLON",
1779 "FFELEX_typeUNDERSCORE",
1780 "FFELEX_typeQUESTION",
1781 "FFELEX_typeOPEN_ARRAY",
1782 "FFELEX_typeCLOSE_ARRAY",
1783 "FFELEX_typeCOLONCOLON",
1784 "FFELEX_typeREL_LE",
1785 "FFELEX_typeREL_NE",
1786 "FFELEX_typeREL_EQ",
1787 "FFELEX_typePOINTS",
1791 if (type >= ARRAY_SIZE (types))
1797 ffelex_display_token (ffelexToken t)
1802 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1803 ffewhereColumnNumber_f "u)",
1805 ffelex_type_string_ (t->type),
1806 ffewhere_line_number (t->where_line),
1807 ffewhere_column_number (t->where_col));
1809 if (t->text != NULL)
1810 fprintf (dmpout, ": \"%.*s\"\n",
1814 fprintf (dmpout, ".\n");
1817 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1819 if (ffelex_expecting_character())
1820 // next token delivered by lexer will be CHARACTER.
1822 If the most recent call to ffelex_set_expecting_hollerith since the last
1823 token was delivered by the lexer passed a length of -1, then we return
1824 TRUE, because the next token we deliver will be typeCHARACTER, else we
1828 ffelex_expecting_character ()
1830 return (ffelex_raw_mode_ != 0);
1833 /* ffelex_file_fixed -- Lex a given file in fixed source form
1837 ffelex_file_fixed(wf,f);
1839 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1842 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1844 register int c = 0; /* Character currently under consideration. */
1845 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1846 bool disallow_continuation_line;
1847 bool ignore_disallowed_continuation = FALSE;
1848 int latest_char_in_file = 0; /* For getting back into comment-skipping
1851 ffewhereColumnNumber first_label_char; /* First char of label --
1853 char label_string[6]; /* Text of label. */
1854 int labi; /* Length of label text. */
1855 bool finish_statement; /* Previous statement finished? */
1856 bool have_content; /* This line have content? */
1857 bool just_do_label; /* Nothing but label (and continuation?) on
1860 /* Lex is called for a particular file, not for a particular program unit.
1861 Yet the two events do share common characteristics. The first line in a
1862 file or in a program unit cannot be a continuation line. No token can
1863 be in mid-formation. No current label for the statement exists, since
1864 there is no current statement. */
1866 assert (ffelex_handler_ != NULL);
1868 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1870 input_filename = ffewhere_file_name (wf);
1872 ffelex_current_wf_ = wf;
1873 disallow_continuation_line = TRUE;
1874 ignore_disallowed_continuation = FALSE;
1875 ffelex_token_->type = FFELEX_typeNONE;
1876 ffelex_number_of_tokens_ = 0;
1877 ffelex_label_tokens_ = 0;
1878 ffelex_current_wl_ = ffewhere_line_unknown ();
1879 ffelex_current_wc_ = ffewhere_column_unknown ();
1880 latest_char_in_file = '\n';
1882 if (ffe_is_null_version ())
1884 /* Just substitute a "program" directly here. */
1886 char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
1890 for (p = &line[0]; *p != '\0'; ++p)
1891 column = ffelex_image_char_ (*p, column);
1895 goto have_line; /* :::::::::::::::::::: */
1898 goto first_line; /* :::::::::::::::::::: */
1900 /* Come here to get a new line. */
1902 beginning_of_line: /* :::::::::::::::::::: */
1904 disallow_continuation_line = FALSE;
1906 /* Come here directly when last line didn't clarify the continuation issue. */
1908 beginning_of_line_again: /* :::::::::::::::::::: */
1910 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1911 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1914 = malloc_resize_ks (malloc_pool_image (),
1916 FFELEX_columnINITIAL_SIZE_ + 9,
1917 ffelex_card_size_ + 9);
1918 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1922 first_line: /* :::::::::::::::::::: */
1924 c = latest_char_in_file;
1925 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1928 end_of_file: /* :::::::::::::::::::: */
1930 /* Line ending in EOF instead of \n still counts as a whole line. */
1932 ffelex_finish_statement_ ();
1933 ffewhere_line_kill (ffelex_current_wl_);
1934 ffewhere_column_kill (ffelex_current_wc_);
1935 return (ffelexHandler) ffelex_handler_;
1938 ffelex_next_line_ ();
1940 ffelex_bad_line_ = FALSE;
1942 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1944 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1945 || (lextype == FFELEX_typeERROR)
1946 || (lextype == FFELEX_typeSLASH)
1947 || (lextype == FFELEX_typeHASH))
1949 /* Test most frequent type of line first, etc. */
1950 if ((lextype == FFELEX_typeCOMMENT)
1951 || ((lextype == FFELEX_typeSLASH)
1952 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1954 /* Typical case (straight comment), just ignore rest of line. */
1955 comment_line: /* :::::::::::::::::::: */
1957 while ((c != '\n') && (c != EOF))
1960 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1961 else if (lextype == FFELEX_typeHASH)
1962 c = ffelex_hash_ (f);
1964 else if (lextype == FFELEX_typeSLASH)
1966 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1967 ffelex_card_image_[0] = '/';
1968 ffelex_card_image_[1] = c;
1970 goto bad_first_character; /* :::::::::::::::::::: */
1973 /* typeERROR or unsupported typeHASH. */
1974 { /* Bad first character, get line and display
1976 column = ffelex_image_char_ (c, 0);
1978 bad_first_character: /* :::::::::::::::::::: */
1980 ffelex_bad_line_ = TRUE;
1981 while (((c = getc (f)) != '\n') && (c != EOF))
1982 column = ffelex_image_char_ (c, column);
1983 ffelex_card_image_[column] = '\0';
1984 ffelex_card_length_ = column;
1985 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
1986 ffelex_linecount_current_, 1);
1989 /* Read past last char in line. */
1993 ffelex_next_line_ ();
1994 goto end_of_file; /* :::::::::::::::::::: */
1999 ffelex_next_line_ ();
2002 goto end_of_file; /* :::::::::::::::::::: */
2004 ffelex_bad_line_ = FALSE;
2005 } /* while [c, first char, means comment] */
2009 || (ffelex_final_nontab_column_ == 0);
2011 if (lextype == FFELEX_typeDEBUG)
2012 c = ' '; /* A 'D' or 'd' in column 1 with the
2013 debug-lines option on. */
2015 column = ffelex_image_char_ (c, 0);
2017 /* Read the entire line in as is (with whitespace processing). */
2019 while (((c = getc (f)) != '\n') && (c != EOF))
2020 column = ffelex_image_char_ (c, column);
2022 if (ffelex_bad_line_)
2024 ffelex_card_image_[column] = '\0';
2025 ffelex_card_length_ = column;
2026 goto comment_line; /* :::::::::::::::::::: */
2029 /* If no tab, cut off line after column 72/132. */
2031 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
2033 /* Technically, we should now fill ffelex_card_image_ up thru column
2034 72/132 with spaces, since character/hollerith constants must count
2035 them in that manner. To save CPU time in several ways (avoid a loop
2036 here that would be used only when we actually end a line in
2037 character-constant mode; avoid writing memory unnecessarily; avoid a
2038 loop later checking spaces when not scanning for character-constant
2039 characters), we don't do this, and we do the appropriate thing when
2040 we encounter end-of-line while actually processing a character
2043 column = ffelex_final_nontab_column_;
2046 have_line: /* :::::::::::::::::::: */
2048 ffelex_card_image_[column] = '\0';
2049 ffelex_card_length_ = column;
2051 /* Save next char in file so we can use register-based c while analyzing
2052 line we just read. */
2054 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2056 have_content = FALSE;
2058 /* Handle label, if any. */
2061 first_label_char = FFEWHERE_columnUNKNOWN;
2062 for (column = 0; column < 5; ++column)
2064 switch (c = ffelex_card_image_[column])
2068 goto stop_looking; /* :::::::::::::::::::: */
2083 label_string[labi++] = c;
2084 if (first_label_char == FFEWHERE_columnUNKNOWN)
2085 first_label_char = column + 1;
2091 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2092 ffelex_linecount_current_,
2094 goto beginning_of_line_again; /* :::::::::::::::::::: */
2096 if (ffe_is_pedantic ())
2097 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2098 ffelex_linecount_current_, 1);
2099 finish_statement = FALSE;
2100 just_do_label = FALSE;
2101 goto got_a_continuation; /* :::::::::::::::::::: */
2104 if (ffelex_card_image_[column + 1] == '*')
2105 goto stop_looking; /* :::::::::::::::::::: */
2108 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2109 ffelex_linecount_current_, column + 1);
2110 goto beginning_of_line_again; /* :::::::::::::::::::: */
2114 stop_looking: /* :::::::::::::::::::: */
2116 label_string[labi] = '\0';
2118 /* Find first nonblank char starting with continuation column. */
2120 if (column == 5) /* In which case we didn't see end of line in
2122 while ((c = ffelex_card_image_[column]) == ' ')
2125 /* Now we're trying to figure out whether this is a continuation line and
2126 whether there's anything else of substance on the line. The cases are
2129 1. If a line has an explicit continuation character (other than the digit
2130 zero), then if it also has a label, the label is ignored and an error
2131 message is printed. Any remaining text on the line is passed to the
2132 parser tasks, thus even an all-blank line (possibly with an ignored
2133 label) aside from a positive continuation character might have meaning
2134 in the midst of a character or hollerith constant.
2136 2. If a line has no explicit continuation character (that is, it has a
2137 space in column 6 and the first non-space character past column 6 is
2138 not a digit 0-9), then there are two possibilities:
2140 A. A label is present and/or a non-space (and non-comment) character
2141 appears somewhere after column 6. Terminate processing of the previous
2142 statement, if any, send the new label for the next statement, if any,
2143 and start processing a new statement with this non-blank character, if
2146 B. The line is essentially blank, except for a possible comment character.
2147 Don't terminate processing of the previous statement and don't pass any
2148 characters to the parser tasks, since the line is not flagged as a
2149 continuation line. We treat it just like a completely blank line.
2151 3. If a line has a continuation character of zero (0), then we terminate
2152 processing of the previous statement, if any, send the new label for the
2153 next statement, if any, and start processing a new statement, if any
2154 non-blank characters are present.
2156 If, when checking to see if we should terminate the previous statement, it
2157 is found that there is no previous statement but that there is an
2158 outstanding label, substitute CONTINUE as the statement for the label
2159 and display an error message. */
2161 finish_statement = FALSE;
2162 just_do_label = FALSE;
2166 case '!': /* ANSI Fortran 90 says ! in column 6 is
2168 /* VXT Fortran says ! anywhere is comment, even column 6. */
2169 if (ffe_is_vxt () || (column != 5))
2170 goto no_tokens_on_line; /* :::::::::::::::::::: */
2171 goto got_a_continuation; /* :::::::::::::::::::: */
2174 if (ffelex_card_image_[column + 1] != '*')
2175 goto some_other_character; /* :::::::::::::::::::: */
2179 /* This seems right to do. But it is close to call, since / * starting
2180 in column 6 will thus be interpreted as a continuation line
2181 beginning with '*'. */
2183 goto got_a_continuation;/* :::::::::::::::::::: */
2187 /* End of line. Therefore may be continued-through line, so handle
2188 pending label as possible to-be-continued and drive end-of-statement
2189 for any previous statement, else treat as blank line. */
2191 no_tokens_on_line: /* :::::::::::::::::::: */
2193 if (ffe_is_pedantic () && (c == '/'))
2194 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2195 ffelex_linecount_current_, column + 1);
2196 if (first_label_char != FFEWHERE_columnUNKNOWN)
2197 { /* Can't be a continued-through line if it
2199 finish_statement = TRUE;
2200 have_content = TRUE;
2201 just_do_label = TRUE;
2204 goto beginning_of_line_again; /* :::::::::::::::::::: */
2207 if (ffe_is_pedantic () && (column != 5))
2208 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2209 ffelex_linecount_current_, column + 1);
2210 finish_statement = TRUE;
2211 goto check_for_content; /* :::::::::::::::::::: */
2223 /* NOTE: This label can be reached directly from the code
2224 that lexes the label field in columns 1-5. */
2225 got_a_continuation: /* :::::::::::::::::::: */
2227 if (first_label_char != FFEWHERE_columnUNKNOWN)
2229 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2230 ffelex_linecount_current_,
2232 ffelex_linecount_current_,
2234 first_label_char = FFEWHERE_columnUNKNOWN;
2236 if (disallow_continuation_line)
2238 if (!ignore_disallowed_continuation)
2239 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2240 ffelex_linecount_current_, column + 1);
2241 goto beginning_of_line_again; /* :::::::::::::::::::: */
2243 if (ffe_is_pedantic () && (column != 5))
2244 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2245 ffelex_linecount_current_, column + 1);
2246 if ((ffelex_raw_mode_ != 0)
2247 && (((c = ffelex_card_image_[column + 1]) != '\0')
2248 || !ffelex_saw_tab_))
2251 have_content = TRUE;
2255 check_for_content: /* :::::::::::::::::::: */
2257 while ((c = ffelex_card_image_[++column]) == ' ')
2262 && (ffelex_card_image_[column + 1] == '*')))
2264 if (ffe_is_pedantic () && (c == '/'))
2265 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2266 ffelex_linecount_current_, column + 1);
2267 just_do_label = TRUE;
2270 have_content = TRUE;
2275 some_other_character: /* :::::::::::::::::::: */
2278 goto got_a_continuation;/* :::::::::::::::::::: */
2280 /* Here is the very normal case of a regular character starting in
2281 column 7 or beyond with a blank in column 6. */
2283 finish_statement = TRUE;
2284 have_content = TRUE;
2289 || (first_label_char != FFEWHERE_columnUNKNOWN))
2291 /* The line has content of some kind, install new end-statement
2292 point for error messages. Note that "content" includes cases
2293 where there's little apparent content but enough to finish
2294 a statement. That's because finishing a statement can trigger
2295 an impending INCLUDE, and that requires accurate line info being
2296 maintained by the lexer. */
2298 if (finish_statement)
2299 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2301 ffewhere_line_kill (ffelex_current_wl_);
2302 ffewhere_column_kill (ffelex_current_wc_);
2303 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2304 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2307 /* We delay this for a combination of reasons. Mainly, it can start
2308 INCLUDE processing, and we want to delay that until the lexer's
2309 info on the line is coherent. And we want to delay that until we're
2310 sure there's a reason to make that info coherent, to avoid saving
2311 lots of useless lines. */
2313 if (finish_statement)
2314 ffelex_finish_statement_ ();
2316 /* If label is present, enclose it in a NUMBER token and send it along. */
2318 if (first_label_char != FFEWHERE_columnUNKNOWN)
2320 assert (ffelex_token_->type == FFELEX_typeNONE);
2321 ffelex_token_->type = FFELEX_typeNUMBER;
2322 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2323 strcpy (ffelex_token_->text, label_string);
2324 ffelex_token_->where_line
2325 = ffewhere_line_use (ffelex_current_wl_);
2326 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2327 ffelex_token_->length = labi;
2328 ffelex_send_token_ ();
2329 ++ffelex_label_tokens_;
2333 goto beginning_of_line; /* :::::::::::::::::::: */
2335 /* Here is the main engine for parsing. c holds the character at column.
2336 It is already known that c is not a blank, end of line, or shriek,
2337 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2338 character/hollerith constant). A partially filled token may already
2339 exist in ffelex_token_. One special case: if, when the end of the line
2340 is reached, continuation_line is FALSE and the only token on the line is
2341 END, then it is indeed the last statement. We don't look for
2342 continuation lines during this program unit in that case. This is
2343 according to ANSI. */
2345 if (ffelex_raw_mode_ != 0)
2348 parse_raw_character: /* :::::::::::::::::::: */
2352 ffewhereColumnNumber i;
2354 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2355 goto beginning_of_line; /* :::::::::::::::::::: */
2357 /* Pad out line with "virtual" spaces. */
2359 for (i = column; i < ffelex_final_nontab_column_; ++i)
2360 ffelex_card_image_[i] = ' ';
2361 ffelex_card_image_[i] = '\0';
2362 ffelex_card_length_ = i;
2366 switch (ffelex_raw_mode_)
2369 c = ffelex_backslash_ (c, column);
2373 if (!ffelex_backslash_reconsider_)
2374 ffelex_append_to_token_ (c);
2375 ffelex_raw_mode_ = -1;
2379 if (c == ffelex_raw_char_)
2381 ffelex_raw_mode_ = -1;
2382 ffelex_append_to_token_ (c);
2386 ffelex_raw_mode_ = 0;
2387 ffelex_backslash_reconsider_ = TRUE;
2392 if (c == ffelex_raw_char_)
2393 ffelex_raw_mode_ = -2;
2396 c = ffelex_backslash_ (c, column);
2399 ffelex_raw_mode_ = -3;
2403 ffelex_append_to_token_ (c);
2408 c = ffelex_backslash_ (c, column);
2412 if (!ffelex_backslash_reconsider_)
2414 ffelex_append_to_token_ (c);
2420 if (ffelex_backslash_reconsider_)
2421 ffelex_backslash_reconsider_ = FALSE;
2423 c = ffelex_card_image_[++column];
2425 if (ffelex_raw_mode_ == 0)
2427 ffelex_send_token_ ();
2428 assert (ffelex_raw_mode_ == 0);
2430 c = ffelex_card_image_[++column];
2434 && (ffelex_card_image_[column + 1] == '*')))
2435 goto beginning_of_line; /* :::::::::::::::::::: */
2436 goto parse_nonraw_character; /* :::::::::::::::::::: */
2438 goto parse_raw_character; /* :::::::::::::::::::: */
2441 parse_nonraw_character: /* :::::::::::::::::::: */
2443 switch (ffelex_token_->type)
2445 case FFELEX_typeNONE:
2449 ffelex_token_->type = FFELEX_typeQUOTE;
2450 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2451 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2452 ffelex_send_token_ ();
2456 ffelex_token_->type = FFELEX_typeDOLLAR;
2457 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2458 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2459 ffelex_send_token_ ();
2463 ffelex_token_->type = FFELEX_typePERCENT;
2464 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2465 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2466 ffelex_send_token_ ();
2470 ffelex_token_->type = FFELEX_typeAMPERSAND;
2471 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2472 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2473 ffelex_send_token_ ();
2477 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2478 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2479 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2480 ffelex_send_token_ ();
2484 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2485 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2486 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2490 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2491 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2492 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2493 ffelex_send_token_ ();
2497 ffelex_token_->type = FFELEX_typeASTERISK;
2498 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2499 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2503 ffelex_token_->type = FFELEX_typePLUS;
2504 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2505 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2506 ffelex_send_token_ ();
2510 ffelex_token_->type = FFELEX_typeCOMMA;
2511 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2512 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2513 ffelex_send_token_ ();
2517 ffelex_token_->type = FFELEX_typeMINUS;
2518 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2519 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2520 ffelex_send_token_ ();
2524 ffelex_token_->type = FFELEX_typePERIOD;
2525 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2526 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2527 ffelex_send_token_ ();
2531 ffelex_token_->type = FFELEX_typeSLASH;
2532 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2533 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2547 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2548 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2549 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2550 ffelex_append_to_token_ (c);
2554 ffelex_token_->type = FFELEX_typeCOLON;
2555 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2556 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2560 ffelex_token_->type = FFELEX_typeSEMICOLON;
2561 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2562 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2563 ffelex_permit_include_ = TRUE;
2564 ffelex_send_token_ ();
2565 ffelex_permit_include_ = FALSE;
2569 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2570 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2571 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2575 ffelex_token_->type = FFELEX_typeEQUALS;
2576 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2577 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2581 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2582 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2583 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2587 ffelex_token_->type = FFELEX_typeQUESTION;
2588 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2589 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2590 ffelex_send_token_ ();
2594 if (1 || ffe_is_90 ())
2596 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2597 ffelex_token_->where_line
2598 = ffewhere_line_use (ffelex_current_wl_);
2599 ffelex_token_->where_col
2600 = ffewhere_column_new (column + 1);
2601 ffelex_send_token_ ();
2657 c = ffesrc_char_source (c);
2659 if (ffesrc_char_match_init (c, 'H', 'h')
2660 && ffelex_expecting_hollerith_ != 0)
2662 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2663 ffelex_token_->type = FFELEX_typeHOLLERITH;
2664 ffelex_token_->where_line = ffelex_raw_where_line_;
2665 ffelex_token_->where_col = ffelex_raw_where_col_;
2666 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2667 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2668 c = ffelex_card_image_[++column];
2669 goto parse_raw_character; /* :::::::::::::::::::: */
2674 ffelex_token_->where_line
2675 = ffewhere_line_use (ffelex_token_->currentnames_line
2676 = ffewhere_line_use (ffelex_current_wl_));
2677 ffelex_token_->where_col
2678 = ffewhere_column_use (ffelex_token_->currentnames_col
2679 = ffewhere_column_new (column + 1));
2680 ffelex_token_->type = FFELEX_typeNAMES;
2684 ffelex_token_->where_line
2685 = ffewhere_line_use (ffelex_current_wl_);
2686 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2687 ffelex_token_->type = FFELEX_typeNAME;
2689 ffelex_append_to_token_ (c);
2693 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2694 ffelex_linecount_current_, column + 1);
2695 ffelex_finish_statement_ ();
2696 disallow_continuation_line = TRUE;
2697 ignore_disallowed_continuation = TRUE;
2698 goto beginning_of_line_again; /* :::::::::::::::::::: */
2702 case FFELEX_typeNAME:
2757 c = ffesrc_char_source (c);
2772 && !ffe_is_dollar_ok ())
2774 ffelex_send_token_ ();
2775 goto parse_next_character; /* :::::::::::::::::::: */
2777 ffelex_append_to_token_ (c);
2781 ffelex_send_token_ ();
2782 goto parse_next_character; /* :::::::::::::::::::: */
2786 case FFELEX_typeNAMES:
2841 c = ffesrc_char_source (c);
2856 && !ffe_is_dollar_ok ())
2858 ffelex_send_token_ ();
2859 goto parse_next_character; /* :::::::::::::::::::: */
2861 if (ffelex_token_->length < FFEWHERE_indexMAX)
2863 ffewhere_track (&ffelex_token_->currentnames_line,
2864 &ffelex_token_->currentnames_col,
2865 ffelex_token_->wheretrack,
2866 ffelex_token_->length,
2867 ffelex_linecount_current_,
2870 ffelex_append_to_token_ (c);
2874 ffelex_send_token_ ();
2875 goto parse_next_character; /* :::::::::::::::::::: */
2879 case FFELEX_typeNUMBER:
2892 ffelex_append_to_token_ (c);
2896 ffelex_send_token_ ();
2897 goto parse_next_character; /* :::::::::::::::::::: */
2901 case FFELEX_typeASTERISK:
2905 ffelex_token_->type = FFELEX_typePOWER;
2906 ffelex_send_token_ ();
2909 default: /* * not followed by another *. */
2910 ffelex_send_token_ ();
2911 goto parse_next_character; /* :::::::::::::::::::: */
2915 case FFELEX_typeCOLON:
2919 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2920 ffelex_send_token_ ();
2923 default: /* : not followed by another :. */
2924 ffelex_send_token_ ();
2925 goto parse_next_character; /* :::::::::::::::::::: */
2929 case FFELEX_typeSLASH:
2933 ffelex_token_->type = FFELEX_typeCONCAT;
2934 ffelex_send_token_ ();
2938 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2939 ffelex_send_token_ ();
2943 ffelex_token_->type = FFELEX_typeREL_NE;
2944 ffelex_send_token_ ();
2948 ffelex_send_token_ ();
2949 goto parse_next_character; /* :::::::::::::::::::: */
2953 case FFELEX_typeOPEN_PAREN:
2957 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2958 ffelex_send_token_ ();
2962 ffelex_send_token_ ();
2963 goto parse_next_character; /* :::::::::::::::::::: */
2967 case FFELEX_typeOPEN_ANGLE:
2971 ffelex_token_->type = FFELEX_typeREL_LE;
2972 ffelex_send_token_ ();
2976 ffelex_send_token_ ();
2977 goto parse_next_character; /* :::::::::::::::::::: */
2981 case FFELEX_typeEQUALS:
2985 ffelex_token_->type = FFELEX_typeREL_EQ;
2986 ffelex_send_token_ ();
2990 ffelex_token_->type = FFELEX_typePOINTS;
2991 ffelex_send_token_ ();
2995 ffelex_send_token_ ();
2996 goto parse_next_character; /* :::::::::::::::::::: */
3000 case FFELEX_typeCLOSE_ANGLE:
3004 ffelex_token_->type = FFELEX_typeREL_GE;
3005 ffelex_send_token_ ();
3009 ffelex_send_token_ ();
3010 goto parse_next_character; /* :::::::::::::::::::: */
3015 assert ("Serious error!!" == NULL);
3020 c = ffelex_card_image_[++column];
3022 parse_next_character: /* :::::::::::::::::::: */
3024 if (ffelex_raw_mode_ != 0)
3025 goto parse_raw_character; /* :::::::::::::::::::: */
3028 c = ffelex_card_image_[++column];
3033 && (ffelex_card_image_[column + 1] == '*')))
3035 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
3036 && (ffelex_token_->type == FFELEX_typeNAMES)
3037 && (ffelex_token_->length == 3)
3038 && (ffesrc_strncmp_2c (ffe_case_match (),
3039 ffelex_token_->text,
3040 "END", "end", "End",
3044 ffelex_finish_statement_ ();
3045 disallow_continuation_line = TRUE;
3046 ignore_disallowed_continuation = FALSE;
3047 goto beginning_of_line_again; /* :::::::::::::::::::: */
3049 goto beginning_of_line; /* :::::::::::::::::::: */
3051 goto parse_nonraw_character; /* :::::::::::::::::::: */
3054 /* ffelex_file_free -- Lex a given file in free source form
3058 ffelex_file_free(wf,f);
3060 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3063 ffelex_file_free (ffewhereFile wf, FILE *f)
3065 register int c = 0; /* Character currently under consideration. */
3066 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3067 bool continuation_line = FALSE;
3068 ffewhereColumnNumber continuation_column;
3069 int latest_char_in_file = 0; /* For getting back into comment-skipping
3072 /* Lex is called for a particular file, not for a particular program unit.
3073 Yet the two events do share common characteristics. The first line in a
3074 file or in a program unit cannot be a continuation line. No token can
3075 be in mid-formation. No current label for the statement exists, since
3076 there is no current statement. */
3078 assert (ffelex_handler_ != NULL);
3080 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3082 input_filename = ffewhere_file_name (wf);
3084 ffelex_current_wf_ = wf;
3085 continuation_line = FALSE;
3086 ffelex_token_->type = FFELEX_typeNONE;
3087 ffelex_number_of_tokens_ = 0;
3088 ffelex_current_wl_ = ffewhere_line_unknown ();
3089 ffelex_current_wc_ = ffewhere_column_unknown ();
3090 latest_char_in_file = '\n';
3092 /* Come here to get a new line. */
3094 beginning_of_line: /* :::::::::::::::::::: */
3096 c = latest_char_in_file;
3097 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3100 end_of_file: /* :::::::::::::::::::: */
3102 /* Line ending in EOF instead of \n still counts as a whole line. */
3104 ffelex_finish_statement_ ();
3105 ffewhere_line_kill (ffelex_current_wl_);
3106 ffewhere_column_kill (ffelex_current_wc_);
3107 return (ffelexHandler) ffelex_handler_;
3110 ffelex_next_line_ ();
3112 ffelex_bad_line_ = FALSE;
3114 /* Skip over initial-comment and empty lines as quickly as possible! */
3122 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3123 c = ffelex_hash_ (f);
3125 /* Don't skip over # line after all. */
3130 comment_line: /* :::::::::::::::::::: */
3132 while ((c != '\n') && (c != EOF))
3137 ffelex_next_line_ ();
3138 goto end_of_file; /* :::::::::::::::::::: */
3143 ffelex_next_line_ ();
3146 goto end_of_file; /* :::::::::::::::::::: */
3149 ffelex_saw_tab_ = FALSE;
3151 column = ffelex_image_char_ (c, 0);
3153 /* Read the entire line in as is (with whitespace processing). */
3155 while (((c = getc (f)) != '\n') && (c != EOF))
3156 column = ffelex_image_char_ (c, column);
3158 if (ffelex_bad_line_)
3160 ffelex_card_image_[column] = '\0';
3161 ffelex_card_length_ = column;
3162 goto comment_line; /* :::::::::::::::::::: */
3165 /* If no tab, cut off line after column 132. */
3167 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3168 column = FFELEX_FREE_MAX_COLUMNS_;
3170 ffelex_card_image_[column] = '\0';
3171 ffelex_card_length_ = column;
3173 /* Save next char in file so we can use register-based c while analyzing
3174 line we just read. */
3176 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3179 continuation_column = 0;
3181 /* Skip over initial spaces to see if the first nonblank character
3182 is exclamation point, newline, or EOF (line is therefore a comment) or
3183 ampersand (line is therefore a continuation line). */
3185 while ((c = ffelex_card_image_[column]) == ' ')
3192 goto beginning_of_line; /* :::::::::::::::::::: */
3195 continuation_column = column + 1;
3202 /* The line definitely has content of some kind, install new end-statement
3203 point for error messages. */
3205 ffewhere_line_kill (ffelex_current_wl_);
3206 ffewhere_column_kill (ffelex_current_wc_);
3207 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3208 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3210 /* Figure out which column to start parsing at. */
3212 if (continuation_line)
3214 if (continuation_column == 0)
3216 if (ffelex_raw_mode_ != 0)
3218 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3219 ffelex_linecount_current_, column + 1);
3221 else if (ffelex_token_->type != FFELEX_typeNONE)
3223 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3224 ffelex_linecount_current_, column + 1);
3227 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3228 { /* Line contains only a single "&" as only
3229 nonblank character. */
3230 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3231 ffelex_linecount_current_, continuation_column);
3232 goto beginning_of_line; /* :::::::::::::::::::: */
3234 column = continuation_column;
3239 c = ffelex_card_image_[column];
3240 continuation_line = FALSE;
3242 /* Here is the main engine for parsing. c holds the character at column.
3243 It is already known that c is not a blank, end of line, or shriek,
3244 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3245 character/hollerith constant). A partially filled token may already
3246 exist in ffelex_token_. */
3248 if (ffelex_raw_mode_ != 0)
3251 parse_raw_character: /* :::::::::::::::::::: */
3256 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3258 continuation_line = TRUE;
3259 goto beginning_of_line; /* :::::::::::::::::::: */
3264 ffelex_finish_statement_ ();
3265 goto beginning_of_line; /* :::::::::::::::::::: */
3271 switch (ffelex_raw_mode_)
3274 c = ffelex_backslash_ (c, column);
3278 if (!ffelex_backslash_reconsider_)
3279 ffelex_append_to_token_ (c);
3280 ffelex_raw_mode_ = -1;
3284 if (c == ffelex_raw_char_)
3286 ffelex_raw_mode_ = -1;
3287 ffelex_append_to_token_ (c);
3291 ffelex_raw_mode_ = 0;
3292 ffelex_backslash_reconsider_ = TRUE;
3297 if (c == ffelex_raw_char_)
3298 ffelex_raw_mode_ = -2;
3301 c = ffelex_backslash_ (c, column);
3304 ffelex_raw_mode_ = -3;
3308 ffelex_append_to_token_ (c);
3313 c = ffelex_backslash_ (c, column);
3317 if (!ffelex_backslash_reconsider_)
3319 ffelex_append_to_token_ (c);
3325 if (ffelex_backslash_reconsider_)
3326 ffelex_backslash_reconsider_ = FALSE;
3328 c = ffelex_card_image_[++column];
3330 if (ffelex_raw_mode_ == 0)
3332 ffelex_send_token_ ();
3333 assert (ffelex_raw_mode_ == 0);
3335 c = ffelex_card_image_[++column];
3336 if ((c == '\0') || (c == '!'))
3338 ffelex_finish_statement_ ();
3339 goto beginning_of_line; /* :::::::::::::::::::: */
3341 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3343 continuation_line = TRUE;
3344 goto beginning_of_line; /* :::::::::::::::::::: */
3346 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3348 goto parse_raw_character; /* :::::::::::::::::::: */
3351 parse_nonraw_character: /* :::::::::::::::::::: */
3353 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3355 continuation_line = TRUE;
3356 goto beginning_of_line; /* :::::::::::::::::::: */
3359 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3361 switch (ffelex_token_->type)
3363 case FFELEX_typeNONE:
3366 finish-statement/continue-statement
3369 c = ffelex_card_image_[++column];
3370 if ((c == '\0') || (c == '!'))
3372 ffelex_finish_statement_ ();
3373 goto beginning_of_line; /* :::::::::::::::::::: */
3375 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3377 continuation_line = TRUE;
3378 goto beginning_of_line; /* :::::::::::::::::::: */
3385 ffelex_token_->type = FFELEX_typeQUOTE;
3386 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3387 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3388 ffelex_send_token_ ();
3392 ffelex_token_->type = FFELEX_typeDOLLAR;
3393 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3394 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3395 ffelex_send_token_ ();
3399 ffelex_token_->type = FFELEX_typePERCENT;
3400 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3401 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3402 ffelex_send_token_ ();
3406 ffelex_token_->type = FFELEX_typeAMPERSAND;
3407 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3408 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3409 ffelex_send_token_ ();
3413 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3414 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3415 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3416 ffelex_send_token_ ();
3420 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3421 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3422 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3426 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3427 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3428 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3429 ffelex_send_token_ ();
3433 ffelex_token_->type = FFELEX_typeASTERISK;
3434 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3435 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3439 ffelex_token_->type = FFELEX_typePLUS;
3440 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3441 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3442 ffelex_send_token_ ();
3446 ffelex_token_->type = FFELEX_typeCOMMA;
3447 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3448 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3449 ffelex_send_token_ ();
3453 ffelex_token_->type = FFELEX_typeMINUS;
3454 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3455 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3456 ffelex_send_token_ ();
3460 ffelex_token_->type = FFELEX_typePERIOD;
3461 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3462 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3463 ffelex_send_token_ ();
3467 ffelex_token_->type = FFELEX_typeSLASH;
3468 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3469 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3483 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3484 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3485 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3486 ffelex_append_to_token_ (c);
3490 ffelex_token_->type = FFELEX_typeCOLON;
3491 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3492 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3496 ffelex_token_->type = FFELEX_typeSEMICOLON;
3497 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3498 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3499 ffelex_permit_include_ = TRUE;
3500 ffelex_send_token_ ();
3501 ffelex_permit_include_ = FALSE;
3505 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3506 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3507 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3511 ffelex_token_->type = FFELEX_typeEQUALS;
3512 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3513 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3517 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3518 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3519 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3523 ffelex_token_->type = FFELEX_typeQUESTION;
3524 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3525 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3526 ffelex_send_token_ ();
3530 if (1 || ffe_is_90 ())
3532 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3533 ffelex_token_->where_line
3534 = ffewhere_line_use (ffelex_current_wl_);
3535 ffelex_token_->where_col
3536 = ffewhere_column_new (column + 1);
3537 ffelex_send_token_ ();
3593 c = ffesrc_char_source (c);
3595 if (ffesrc_char_match_init (c, 'H', 'h')
3596 && ffelex_expecting_hollerith_ != 0)
3598 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3599 ffelex_token_->type = FFELEX_typeHOLLERITH;
3600 ffelex_token_->where_line = ffelex_raw_where_line_;
3601 ffelex_token_->where_col = ffelex_raw_where_col_;
3602 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3603 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3604 c = ffelex_card_image_[++column];
3605 goto parse_raw_character; /* :::::::::::::::::::: */
3608 if (ffelex_names_pure_)
3610 ffelex_token_->where_line
3611 = ffewhere_line_use (ffelex_token_->currentnames_line
3612 = ffewhere_line_use (ffelex_current_wl_));
3613 ffelex_token_->where_col
3614 = ffewhere_column_use (ffelex_token_->currentnames_col
3615 = ffewhere_column_new (column + 1));
3616 ffelex_token_->type = FFELEX_typeNAMES;
3620 ffelex_token_->where_line
3621 = ffewhere_line_use (ffelex_current_wl_);
3622 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3623 ffelex_token_->type = FFELEX_typeNAME;
3625 ffelex_append_to_token_ (c);
3629 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3630 ffelex_linecount_current_, column + 1);
3631 ffelex_finish_statement_ ();
3632 goto beginning_of_line; /* :::::::::::::::::::: */
3636 case FFELEX_typeNAME:
3691 c = ffesrc_char_source (c);
3706 && !ffe_is_dollar_ok ())
3708 ffelex_send_token_ ();
3709 goto parse_next_character; /* :::::::::::::::::::: */
3711 ffelex_append_to_token_ (c);
3715 ffelex_send_token_ ();
3716 goto parse_next_character; /* :::::::::::::::::::: */
3720 case FFELEX_typeNAMES:
3775 c = ffesrc_char_source (c);
3790 && !ffe_is_dollar_ok ())
3792 ffelex_send_token_ ();
3793 goto parse_next_character; /* :::::::::::::::::::: */
3795 if (ffelex_token_->length < FFEWHERE_indexMAX)
3797 ffewhere_track (&ffelex_token_->currentnames_line,
3798 &ffelex_token_->currentnames_col,
3799 ffelex_token_->wheretrack,
3800 ffelex_token_->length,
3801 ffelex_linecount_current_,
3804 ffelex_append_to_token_ (c);
3808 ffelex_send_token_ ();
3809 goto parse_next_character; /* :::::::::::::::::::: */
3813 case FFELEX_typeNUMBER:
3826 ffelex_append_to_token_ (c);
3830 ffelex_send_token_ ();
3831 goto parse_next_character; /* :::::::::::::::::::: */
3835 case FFELEX_typeASTERISK:
3839 ffelex_token_->type = FFELEX_typePOWER;
3840 ffelex_send_token_ ();
3843 default: /* * not followed by another *. */
3844 ffelex_send_token_ ();
3845 goto parse_next_character; /* :::::::::::::::::::: */
3849 case FFELEX_typeCOLON:
3853 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3854 ffelex_send_token_ ();
3857 default: /* : not followed by another :. */
3858 ffelex_send_token_ ();
3859 goto parse_next_character; /* :::::::::::::::::::: */
3863 case FFELEX_typeSLASH:
3867 ffelex_token_->type = FFELEX_typeCONCAT;
3868 ffelex_send_token_ ();
3872 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3873 ffelex_send_token_ ();
3877 ffelex_token_->type = FFELEX_typeREL_NE;
3878 ffelex_send_token_ ();
3882 ffelex_send_token_ ();
3883 goto parse_next_character; /* :::::::::::::::::::: */
3887 case FFELEX_typeOPEN_PAREN:
3891 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3892 ffelex_send_token_ ();
3896 ffelex_send_token_ ();
3897 goto parse_next_character; /* :::::::::::::::::::: */
3901 case FFELEX_typeOPEN_ANGLE:
3905 ffelex_token_->type = FFELEX_typeREL_LE;
3906 ffelex_send_token_ ();
3910 ffelex_send_token_ ();
3911 goto parse_next_character; /* :::::::::::::::::::: */
3915 case FFELEX_typeEQUALS:
3919 ffelex_token_->type = FFELEX_typeREL_EQ;
3920 ffelex_send_token_ ();
3924 ffelex_token_->type = FFELEX_typePOINTS;
3925 ffelex_send_token_ ();
3929 ffelex_send_token_ ();
3930 goto parse_next_character; /* :::::::::::::::::::: */
3934 case FFELEX_typeCLOSE_ANGLE:
3938 ffelex_token_->type = FFELEX_typeREL_GE;
3939 ffelex_send_token_ ();
3943 ffelex_send_token_ ();
3944 goto parse_next_character; /* :::::::::::::::::::: */
3949 assert ("Serious error!" == NULL);
3954 c = ffelex_card_image_[++column];
3956 parse_next_character: /* :::::::::::::::::::: */
3958 if (ffelex_raw_mode_ != 0)
3959 goto parse_raw_character; /* :::::::::::::::::::: */
3961 if ((c == '\0') || (c == '!'))
3963 ffelex_finish_statement_ ();
3964 goto beginning_of_line; /* :::::::::::::::::::: */
3966 goto parse_nonraw_character; /* :::::::::::::::::::: */
3969 /* See the code in com.c that calls this to understand why. */
3971 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3973 ffelex_hash_kludge (FILE *finput)
3975 /* If you change this constant string, you have to change whatever
3976 code might thus be affected by it in terms of having to use
3977 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3978 static char match[] = "# 1 \"";
3979 static int kludge[ARRAY_SIZE (match) + 1];
3984 /* Read chars as long as they match the target string.
3985 Copy them into an array that will serve as a record
3986 of what we read (essentially a multi-char ungetc(),
3987 for code that uses ffelex_getc_ instead of getc() elsewhere
3989 for (p = &match[0], q = &kludge[0], c = getc (finput);
3990 (c == *p) && (*p != '\0') && (c != EOF);
3991 ++p, ++q, c = getc (finput))
3994 *q = c; /* Might be EOF, which requires int. */
3997 ffelex_kludge_chars_ = &kludge[0];
4001 ffelex_kludge_flag_ = TRUE;
4002 ++ffelex_kludge_chars_;
4003 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
4004 ffelex_kludge_flag_ = FALSE;
4014 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
4015 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
4016 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
4017 "FFELEX card image",
4018 FFELEX_columnINITIAL_SIZE_ + 9);
4019 ffelex_card_image_[0] = '\0';
4021 for (i = 0; i < 256; ++i)
4022 ffelex_first_char_[i] = FFELEX_typeERROR;
4024 ffelex_first_char_['\t'] = FFELEX_typeRAW;
4025 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
4026 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
4027 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
4028 ffelex_first_char_['\r'] = FFELEX_typeRAW;
4029 ffelex_first_char_[' '] = FFELEX_typeRAW;
4030 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
4031 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
4032 ffelex_first_char_['/'] = FFELEX_typeSLASH;
4033 ffelex_first_char_['&'] = FFELEX_typeRAW;
4034 ffelex_first_char_['#'] = FFELEX_typeHASH;
4036 for (i = '0'; i <= '9'; ++i)
4037 ffelex_first_char_[i] = FFELEX_typeRAW;
4039 if ((ffe_case_match () == FFE_caseNONE)
4040 || ((ffe_case_match () == FFE_caseUPPER)
4041 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
4042 || ((ffe_case_match () == FFE_caseLOWER)
4043 && (ffe_case_source () == FFE_caseLOWER)))
4045 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
4046 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
4048 if ((ffe_case_match () == FFE_caseNONE)
4049 || ((ffe_case_match () == FFE_caseLOWER)
4050 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
4051 || ((ffe_case_match () == FFE_caseUPPER)
4052 && (ffe_case_source () == FFE_caseUPPER)))
4054 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
4055 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
4058 ffelex_linecount_current_ = 0;
4059 ffelex_linecount_next_ = 1;
4060 ffelex_raw_mode_ = 0;
4061 ffelex_set_include_ = FALSE;
4062 ffelex_permit_include_ = FALSE;
4063 ffelex_names_ = TRUE; /* First token in program is a names. */
4064 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
4066 ffelex_hexnum_ = FALSE;
4067 ffelex_expecting_hollerith_ = 0;
4068 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4069 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4071 ffelex_token_ = ffelex_token_new_ ();
4072 ffelex_token_->type = FFELEX_typeNONE;
4073 ffelex_token_->uses = 1;
4074 ffelex_token_->where_line = ffewhere_line_unknown ();
4075 ffelex_token_->where_col = ffewhere_column_unknown ();
4076 ffelex_token_->text = NULL;
4078 ffelex_handler_ = NULL;
4081 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4083 if (ffelex_is_names_expected())
4084 // Deliver NAMES token
4086 // Deliver NAME token
4088 Must be called while lexer is active, obviously. */
4091 ffelex_is_names_expected ()
4093 return ffelex_names_;
4096 /* Current card image, which has the master linecount number
4097 ffelex_linecount_current_. */
4102 return ffelex_card_image_;
4105 /* ffelex_line_length -- Return length of current lexer line
4107 printf("Length is %lu\n",ffelex_line_length());
4109 Must be called while lexer is active, obviously. */
4111 ffewhereColumnNumber
4112 ffelex_line_length ()
4114 return ffelex_card_length_;
4117 /* Master line count of current card image, or 0 if no card image
4121 ffelex_line_number ()
4123 return ffelex_linecount_current_;
4126 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4128 ffelex_set_expecting_hollerith(0);
4130 Lex initially assumes no hollerith constant is about to show up. If
4131 syntactic analysis expects one, it should call this function with the
4132 number of characters expected in the constant immediately after recognizing
4133 the decimal number preceding the "H" and the constant itself. Then, if
4134 the next character is indeed H, the lexer will interpret it as beginning
4135 a hollerith constant and ship the token formed by reading the specified
4136 number of characters (interpreting blanks and otherwise-comments too)
4137 from the input file. It is up to syntactic analysis to call this routine
4138 again with 0 to turn hollerith detection off immediately upon receiving
4139 the token that might or might not be HOLLERITH.
4141 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4142 character constant. Pass the expected termination character (apostrophe
4145 Pass for length either the length of the hollerith (must be > 0), -1
4146 meaning expecting a character constant, or 0 to cancel expectation of
4147 a hollerith only after calling it with a length of > 0 and receiving the
4148 next token (which may or may not have been a HOLLERITH token).
4150 Pass for which either an apostrophe or quote when passing length of -1.
4151 Else which is a don't-care.
4153 Pass for line and column the line/column info for the token beginning the
4154 character or hollerith constant, for use in error messages, when passing
4155 a length of -1 -- this function will invoke ffewhere_line/column_use to
4156 make its own copies. Else line and column are don't-cares (when length
4157 is 0) and the outstanding copies of the previous line/column info, if
4158 still around, are killed.
4161 When called with length of 0, also zero ffelex_raw_mode_. This is
4162 so ffest_save_ can undo the effects of replaying tokens like
4163 APOSTROPHE and QUOTE.
4165 New line, column arguments allow error messages to point to the true
4166 beginning of a character/hollerith constant, rather than the beginning
4167 of the content part, which makes them more consistent and helpful.
4169 New "which" argument allows caller to specify termination character,
4170 which should be apostrophe or double-quote, to support Fortran 90. */
4173 ffelex_set_expecting_hollerith (long length, char which,
4174 ffewhereLine line, ffewhereColumn column)
4177 /* First kill the pending line/col info, if any (should only be pending
4178 when this call has length==0, the previous call had length>0, and a
4179 non-HOLLERITH token was sent in between the calls, but play it safe). */
4181 ffewhere_line_kill (ffelex_raw_where_line_);
4182 ffewhere_column_kill (ffelex_raw_where_col_);
4184 /* Now handle the length function. */
4188 ffelex_expecting_hollerith_ = 0;
4189 ffelex_raw_mode_ = 0;
4190 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4191 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4192 return; /* Don't set new line/column info from args. */
4195 ffelex_raw_mode_ = -1;
4196 ffelex_raw_char_ = which;
4199 default: /* length > 0 */
4200 ffelex_expecting_hollerith_ = length;
4204 /* Now set new line/column information from passed args. */
4206 ffelex_raw_where_line_ = ffewhere_line_use (line);
4207 ffelex_raw_where_col_ = ffewhere_column_use (column);
4210 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4212 ffelex_set_handler((ffelexHandler) my_first_handler);
4214 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4215 after they return, but not while they are active. */
4218 ffelex_set_handler (ffelexHandler first)
4220 ffelex_handler_ = first;
4223 /* ffelex_set_hexnum -- Set hexnum flag
4225 ffelex_set_hexnum(TRUE);
4227 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4228 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4229 the character as the first of the next token. But when parsing a
4230 hexadecimal number, by calling this function with TRUE before starting
4231 the parse of the token itself, lex will interpret [0-9] as the start
4235 ffelex_set_hexnum (bool f)
4240 /* ffelex_set_include -- Set INCLUDE file to be processed next
4242 ffewhereFile wf; // The ffewhereFile object for the file.
4243 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4244 FILE *fi; // The file to INCLUDE.
4245 ffelex_set_include(wf,free_form,fi);
4247 Must be called only after receiving the EOS token following a valid
4248 INCLUDE statement specifying a file that has already been successfully
4252 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4254 assert (ffelex_permit_include_);
4255 assert (!ffelex_set_include_);
4256 ffelex_set_include_ = TRUE;
4257 ffelex_include_free_form_ = free_form;
4258 ffelex_include_file_ = fi;
4259 ffelex_include_wherefile_ = wf;
4262 /* ffelex_set_names -- Set names/name flag, names = TRUE
4264 ffelex_set_names(FALSE);
4266 Lex initially assumes multiple names should be formed. If this function is
4267 called with FALSE, then single names are formed instead. The differences
4268 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4269 and in whether full source-location tracking is performed (it is for
4270 multiple names, not for single names), which is more expensive in terms of
4274 ffelex_set_names (bool f)
4278 ffelex_names_pure_ = FALSE;
4281 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4283 ffelex_set_names_pure(FALSE);
4285 Like ffelex_set_names, except affects both lexers. Normally, the
4286 free-form lexer need not generate NAMES tokens because adjacent NAME
4287 tokens must be separated by spaces which causes the lexer to generate
4288 separate tokens for analysis (whereas in fixed-form the spaces are
4289 ignored resulting in one long token). But in FORMAT statements, for
4290 some reason, the Fortran 90 standard specifies that spaces can occur
4291 anywhere within a format-item-list with no effect on the format spec
4292 (except of course within character string edit descriptors), which means
4293 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4294 statement handling, the existence of spaces makes it hard to deal with,
4295 because each token is seen distinctly (i.e. seven tokens in the latter
4296 example). But when no spaces are provided, as in the former example,
4297 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4298 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4299 One, ffest_kw_format_ does a substring rather than full-string match,
4300 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4301 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4302 and three, error reporting can point to the actual character rather than
4303 at or prior to it. The first two things could be resolved by providing
4304 alternate functions fairly easy, thus allowing FORMAT handling to expect
4305 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4306 changes to FORMAT parsing), but the third, error reporting, would suffer,
4307 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4308 to exactly where the compilers thinks the problem is, to even begin to get
4309 a handle on it. So there. */
4312 ffelex_set_names_pure (bool f)
4314 ffelex_names_pure_ = f;
4318 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4320 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4323 Returns first_handler if start_char_index chars into master_token (which
4324 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4325 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4326 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4327 and sends it to first_handler. If anything other than NAME is sent, the
4328 character at the end of it in the master token is examined to see if it
4329 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4330 the handler returned by first_handler is invoked with that token, and
4331 this process is repeated until the end of the master token or a NAME
4332 token is reached. */
4335 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4336 ffeTokenLength start)
4342 p = ffelex_token_text (master) + (i = start);
4348 t = ffelex_token_number_from_names (master, i);
4349 p += ffelex_token_length (t);
4350 i += ffelex_token_length (t);
4352 else if (ffesrc_is_name_init (*p))
4354 t = ffelex_token_name_from_names (master, i, 0);
4355 p += ffelex_token_length (t);
4356 i += ffelex_token_length (t);
4360 t = ffelex_token_dollar_from_names (master, i);
4366 t = ffelex_token_uscore_from_names (master, i);
4372 assert ("not a valid NAMES character" == NULL);
4375 assert (first != NULL);
4376 first = (ffelexHandler) (*first) (t);
4377 ffelex_token_kill (t);
4383 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4385 return ffelex_swallow_tokens;
4387 Return this handler when you don't want to look at any more tokens in the
4388 statement because you've encountered an unrecoverable error in the
4392 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4394 assert (handler != NULL);
4396 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4397 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4398 return (ffelexHandler) (*handler) (t);
4400 ffelex_eos_handler_ = handler;
4401 return (ffelexHandler) ffelex_swallow_tokens_;
4404 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4407 t = ffelex_token_dollar_from_names(t,6);
4409 It's as if you made a new token of dollar type having the dollar
4410 at, in the example above, the sixth character of the NAMES token. */
4413 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4418 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4419 assert (start < t->length);
4420 assert (t->text[start] == '$');
4422 /* Now make the token. */
4424 nt = ffelex_token_new_ ();
4425 nt->type = FFELEX_typeDOLLAR;
4428 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4429 t->where_col, t->wheretrack, start);
4434 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4437 ffelex_token_kill(t);
4439 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4442 ffelex_token_kill (ffelexToken t)
4446 assert (t->uses > 0);
4451 --ffelex_total_tokens_;
4453 if (t->type == FFELEX_typeNAMES)
4454 ffewhere_track_kill (t->where_line, t->where_col,
4455 t->wheretrack, t->length);
4456 ffewhere_line_kill (t->where_line);
4457 ffewhere_column_kill (t->where_col);
4458 if (t->text != NULL)
4459 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4460 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4463 /* Make a new NAME token that is a substring of a NAMES token. */
4466 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4472 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4473 assert (start < t->length);
4475 len = t->length - start;
4479 assert ((start + len) <= t->length);
4481 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4483 nt = ffelex_token_new_ ();
4484 nt->type = FFELEX_typeNAME;
4485 nt->size = len; /* Assume nobody's gonna fiddle with token
4489 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4490 t->where_col, t->wheretrack, start);
4491 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4493 strncpy (nt->text, t->text + start, len);
4494 nt->text[len] = '\0';
4498 /* Make a new NAMES token that is a substring of another NAMES token. */
4501 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4507 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4508 assert (start < t->length);
4510 len = t->length - start;
4514 assert ((start + len) <= t->length);
4516 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4518 nt = ffelex_token_new_ ();
4519 nt->type = FFELEX_typeNAMES;
4520 nt->size = len; /* Assume nobody's gonna fiddle with token
4524 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4525 t->where_col, t->wheretrack, start);
4526 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4527 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4529 strncpy (nt->text, t->text + start, len);
4530 nt->text[len] = '\0';
4534 /* Make a new CHARACTER token. */
4537 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4541 t = ffelex_token_new_ ();
4542 t->type = FFELEX_typeCHARACTER;
4543 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4545 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4547 strcpy (t->text, s);
4548 t->where_line = ffewhere_line_use (l);
4549 t->where_col = ffewhere_column_new (c);
4553 /* Make a new EOF token right after end of file. */
4556 ffelex_token_new_eof ()
4560 t = ffelex_token_new_ ();
4561 t->type = FFELEX_typeEOF;
4564 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4565 t->where_col = ffewhere_column_new (1);
4569 /* Make a new NAME token. */
4572 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4576 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4578 t = ffelex_token_new_ ();
4579 t->type = FFELEX_typeNAME;
4580 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4582 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4584 strcpy (t->text, s);
4585 t->where_line = ffewhere_line_use (l);
4586 t->where_col = ffewhere_column_new (c);
4590 /* Make a new NAMES token. */
4593 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4597 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4599 t = ffelex_token_new_ ();
4600 t->type = FFELEX_typeNAMES;
4601 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4603 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4605 strcpy (t->text, s);
4606 t->where_line = ffewhere_line_use (l);
4607 t->where_col = ffewhere_column_new (c);
4608 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4613 /* Make a new NUMBER token.
4615 The first character of the string must be a digit, and only the digits
4616 are copied into the new number. So this may be used to easily extract
4617 a NUMBER token from within any text string. Then the length of the
4618 resulting token may be used to calculate where the digits stopped
4619 in the original string. */
4622 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4627 /* How long is the string of decimal digits at s? */
4629 len = strspn (s, "0123456789");
4631 /* Make sure there is at least one digit. */
4635 /* Now make the token. */
4637 t = ffelex_token_new_ ();
4638 t->type = FFELEX_typeNUMBER;
4639 t->length = t->size = len; /* Assume it won't get bigger. */
4641 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4643 strncpy (t->text, s, len);
4644 t->text[len] = '\0';
4645 t->where_line = ffewhere_line_use (l);
4646 t->where_col = ffewhere_column_new (c);
4650 /* Make a new token of any type that doesn't contain text. A private
4651 function that is used by public macros in the interface file. */
4654 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4658 t = ffelex_token_new_ ();
4662 t->where_line = ffewhere_line_use (l);
4663 t->where_col = ffewhere_column_new (c);
4667 /* Make a new NUMBER token from an existing NAMES token.
4669 Like ffelex_token_new_number, this function calculates the length
4670 of the digit string itself. */
4673 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4679 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4680 assert (start < t->length);
4682 /* How long is the string of decimal digits at s? */
4684 len = strspn (t->text + start, "0123456789");
4686 /* Make sure there is at least one digit. */
4690 /* Now make the token. */
4692 nt = ffelex_token_new_ ();
4693 nt->type = FFELEX_typeNUMBER;
4694 nt->size = len; /* Assume nobody's gonna fiddle with token
4698 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4699 t->where_col, t->wheretrack, start);
4700 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4702 strncpy (nt->text, t->text + start, len);
4703 nt->text[len] = '\0';
4707 /* Make a new UNDERSCORE token from a NAMES token. */
4710 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4715 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4716 assert (start < t->length);
4717 assert (t->text[start] == '_');
4719 /* Now make the token. */
4721 nt = ffelex_token_new_ ();
4722 nt->type = FFELEX_typeUNDERSCORE;
4724 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4725 t->where_col, t->wheretrack, start);
4730 /* ffelex_token_use -- Return another instance of a token
4733 t = ffelex_token_use(t);
4735 In a sense, the new token is a copy of the old, though it might be the
4736 same with just a new use count.
4738 We use the use count method (easy). */
4741 ffelex_token_use (ffelexToken t)
4744 assert ("_token_use: null token" == NULL);