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
36 static void ffelex_append_to_token_ (char c);
37 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
38 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
39 ffewhereColumnNumber cn0);
40 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
41 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
42 ffewhereColumnNumber cn1);
43 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
44 ffewhereColumnNumber cn0);
45 static void ffelex_finish_statement_ (void);
46 static int ffelex_get_directive_line_ (char **text, FILE *finput);
47 static int ffelex_hash_ (FILE *f);
48 static ffewhereColumnNumber ffelex_image_char_ (int c,
49 ffewhereColumnNumber col);
50 static void ffelex_include_ (void);
51 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
52 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
53 static void ffelex_next_line_ (void);
54 static void ffelex_prepare_eos_ (void);
55 static void ffelex_send_token_ (void);
56 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
57 static ffelexToken ffelex_token_new_ (void);
59 /* Pertaining to the geometry of the input file. */
61 /* Initial size for card image to be allocated. */
62 #define FFELEX_columnINITIAL_SIZE_ 255
64 /* The card image itself, which grows as source lines get longer. It
65 has room for ffelex_card_size_ + 8 characters, and the length of the
66 current image is ffelex_card_length_. (The + 8 characters are made
67 available for easy handling of tabs and such.) */
68 static char *ffelex_card_image_;
69 static ffewhereColumnNumber ffelex_card_size_;
70 static ffewhereColumnNumber ffelex_card_length_;
72 /* Max width for free-form lines (ISO F90). */
73 #define FFELEX_FREE_MAX_COLUMNS_ 132
75 /* True if we saw a tab on the current line, as this (currently) means
76 the line is therefore treated as though final_nontab_column_ were
78 static bool ffelex_saw_tab_;
80 /* TRUE if current line is known to be erroneous, so don't bother
81 expanding room for it just to display it. */
82 static bool ffelex_bad_line_ = FALSE;
84 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
85 static ffewhereColumnNumber ffelex_final_nontab_column_;
87 /* Array for quickly deciding what kind of line the current card has,
88 based on its first character. */
89 static ffelexType ffelex_first_char_[256];
91 /* Pertaining to file management. */
93 /* The wf argument of the most recent active ffelex_file_(fixed,free)
95 static ffewhereFile ffelex_current_wf_;
97 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
99 static bool ffelex_permit_include_;
101 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
103 static bool ffelex_set_include_;
105 /* Information on the pending INCLUDE file. */
106 static FILE *ffelex_include_file_;
107 static bool ffelex_include_free_form_;
108 static ffewhereFile ffelex_include_wherefile_;
110 /* Current master line count. */
111 static ffewhereLineNumber ffelex_linecount_current_;
112 /* Next master line count. */
113 static ffewhereLineNumber ffelex_linecount_next_;
115 /* ffewhere info on the latest (currently active) line read from the
116 active source file. */
117 static ffewhereLine ffelex_current_wl_;
118 static ffewhereColumn ffelex_current_wc_;
120 /* Pertaining to tokens in general. */
122 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
124 #define FFELEX_columnTOKEN_SIZE_ 63
125 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
126 #error "token size too small!"
129 /* Current token being lexed. */
130 static ffelexToken ffelex_token_;
132 /* Handler for current token. */
133 static ffelexHandler ffelex_handler_;
135 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
136 static bool ffelex_names_;
138 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
139 static bool ffelex_names_pure_;
141 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
143 static bool ffelex_hexnum_;
145 /* For ffelex_swallow_tokens(). */
146 static ffelexHandler ffelex_eos_handler_;
148 /* Number of tokens sent since last EOS or beginning of input file
149 (include INCLUDEd files). */
150 static unsigned long int ffelex_number_of_tokens_;
152 /* Number of labels sent (as NUMBER tokens) since last reset of
153 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
154 (Fixed-form source only.) */
155 static unsigned long int ffelex_label_tokens_;
157 /* Metering for token management, to catch token-memory leaks. */
158 static long int ffelex_total_tokens_ = 0;
159 static long int ffelex_old_total_tokens_ = 1;
160 static long int ffelex_token_nextid_ = 0;
162 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
164 /* >0 if a Hollerith constant of that length might be in mid-lex, used
165 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
166 mode (see ffelex_raw_mode_). */
167 static long int ffelex_expecting_hollerith_;
169 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
170 -2: Possible closing apostrophe/quote seen in CHARACTER.
171 -1: Lexing CHARACTER.
172 0: Not lexing CHARACTER or HOLLERITH.
173 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
174 static long int ffelex_raw_mode_;
176 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
177 static char ffelex_raw_char_;
179 /* TRUE when backslash processing had to use most recent character
180 to finish its state engine, but that character is not part of
181 the backslash sequence, so must be reconsidered as a "normal"
182 character in CHARACTER/HOLLERITH lexing. */
183 static bool ffelex_backslash_reconsider_ = FALSE;
185 /* Characters preread before lexing happened (might include EOF). */
186 static int *ffelex_kludge_chars_ = NULL;
188 /* Doing the kludge processing, so not initialized yet. */
189 static bool ffelex_kludge_flag_ = FALSE;
191 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
192 static ffewhereLine ffelex_raw_where_line_;
193 static ffewhereColumn ffelex_raw_where_col_;
196 /* Call this to append another character to the current token. If it isn't
197 currently big enough for it, it will be enlarged. The current token
198 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
201 ffelex_append_to_token_ (char c)
203 if (ffelex_token_->text == NULL)
206 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
207 FFELEX_columnTOKEN_SIZE_ + 1);
208 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
209 ffelex_token_->length = 0;
211 else if (ffelex_token_->length >= ffelex_token_->size)
214 = malloc_resize_ksr (malloc_pool_image (),
216 (ffelex_token_->size << 1) + 1,
217 ffelex_token_->size + 1);
218 ffelex_token_->size <<= 1;
219 assert (ffelex_token_->length < ffelex_token_->size);
222 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
223 please contact fortran@gnu.org if you wish to fund work to
224 port g77 to non-ASCII machines.
226 ffelex_token_->text[ffelex_token_->length++] = c;
229 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
233 ffelex_backslash_ (int c, ffewhereColumnNumber col)
235 static int state = 0;
236 static unsigned int count;
238 static unsigned int firstdig = 0;
240 static ffewhereLineNumber line;
241 static ffewhereColumnNumber column;
243 /* See gcc/c-lex.c readescape() for a straightforward version
244 of this state engine for handling backslashes in character/
245 hollerith constants. */
248 #define warn_traditional 0
249 #define flag_traditional 0
255 && (ffelex_raw_mode_ != 0)
256 && ffe_is_backslash ())
260 line = ffelex_linecount_current_;
266 state = 0; /* Assume simple case. */
270 if (warn_traditional)
272 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
273 FFEBAD_severityWARNING);
274 ffelex_bad_here_ (0, line, column);
278 if (flag_traditional)
287 case '0': case '1': case '2': case '3': case '4':
288 case '5': case '6': case '7':
294 case '\\': case '\'': case '"':
297 #if 0 /* Inappropriate for Fortran. */
299 ffelex_next_line_ ();
305 return TARGET_NEWLINE;
320 if (warn_traditional)
322 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
323 FFEBAD_severityWARNING);
324 ffelex_bad_here_ (0, line, column);
328 if (flag_traditional)
333 #if 0 /* Vertical tab is present in common usage compilers. */
334 if (flag_traditional)
351 ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
352 FFEBAD_severityPEDANTIC);
353 ffelex_bad_here_ (0, line, column);
357 return (c == 'E' || c == 'e') ? 033 : c;
363 if (c >= 040 && c < 0177)
369 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
370 FFEBAD_severityPEDANTIC);
371 ffelex_bad_here_ (0, line, column);
377 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
378 FFEBAD_severityPEDANTIC);
379 ffelex_bad_here_ (0, line, column);
386 sprintf (&m[0], "%x", c);
387 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
388 FFEBAD_severityPEDANTIC);
389 ffelex_bad_here_ (0, line, column);
400 if (c >= 'a' && c <= 'f')
401 code += c - 'a' + 10;
402 if (c >= 'A' && c <= 'F')
403 code += c - 'A' + 10;
406 if (code != 0 || count != 0)
420 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
421 FFEBAD_severityFATAL);
422 ffelex_bad_here_ (0, line, column);
426 /* Digits are all 0's. Ok. */
428 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
430 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
433 ffebad_start_msg_lex ("Hex escape at %0 out of range",
434 FFEBAD_severityPEDANTIC);
435 ffelex_bad_here_ (0, line, column);
441 if ((c <= '7') && (c >= '0') && (count++ < 3))
443 code = (code * 8) + (c - '0');
450 assert ("bad backslash state" == NULL);
454 /* Come here when code has a built character, and c is the next
455 character that might (or might not) be the next one in the constant. */
457 /* Don't bother doing this check for each character going into
458 CHARACTER or HOLLERITH constants, just the escaped-value ones.
459 gcc apparently checks every single character, which seems
460 like it'd be kinda slow and not worth doing anyway. */
463 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
464 && code >= (1 << TYPE_PRECISION (char_type_node)))
466 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
467 FFEBAD_severityFATAL);
468 ffelex_bad_here_ (0, line, column);
474 /* Known end of constant, just append this character. */
475 ffelex_append_to_token_ (code);
476 if (ffelex_raw_mode_ > 0)
481 /* Have two characters to handle. Do the first, then leave it to the
482 caller to detect anything special about the second. */
484 ffelex_append_to_token_ (code);
485 if (ffelex_raw_mode_ > 0)
487 ffelex_backslash_reconsider_ = TRUE;
491 /* ffelex_bad_1_ -- Issue diagnostic with one source point
493 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
495 Creates ffewhere line and column objects for the source point, sends them
496 along with the error code to ffebad, then kills the line and column
497 objects before returning. */
500 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
505 wl0 = ffewhere_line_new (ln0);
506 wc0 = ffewhere_column_new (cn0);
507 ffebad_start_lex (errnum);
508 ffebad_here (0, wl0, wc0);
510 ffewhere_line_kill (wl0);
511 ffewhere_column_kill (wc0);
514 /* ffelex_bad_2_ -- Issue diagnostic with two source points
516 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
517 otherline,othercolumn);
519 Creates ffewhere line and column objects for the source points, sends them
520 along with the error code to ffebad, then kills the line and column
521 objects before returning. */
524 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
525 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
527 ffewhereLine wl0, wl1;
528 ffewhereColumn wc0, wc1;
530 wl0 = ffewhere_line_new (ln0);
531 wc0 = ffewhere_column_new (cn0);
532 wl1 = ffewhere_line_new (ln1);
533 wc1 = ffewhere_column_new (cn1);
534 ffebad_start_lex (errnum);
535 ffebad_here (0, wl0, wc0);
536 ffebad_here (1, wl1, wc1);
538 ffewhere_line_kill (wl0);
539 ffewhere_column_kill (wc0);
540 ffewhere_line_kill (wl1);
541 ffewhere_column_kill (wc1);
545 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
546 ffewhereColumnNumber cn0)
551 wl0 = ffewhere_line_new (ln0);
552 wc0 = ffewhere_column_new (cn0);
553 ffebad_here (n, wl0, wc0);
554 ffewhere_line_kill (wl0);
555 ffewhere_column_kill (wc0);
559 ffelex_getc_ (FILE *finput)
563 if (ffelex_kludge_chars_ == NULL)
564 return getc (finput);
566 c = *ffelex_kludge_chars_++;
570 ffelex_kludge_chars_ = NULL;
571 return getc (finput);
575 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
577 register int c = getc (finput);
579 register unsigned count;
580 unsigned firstdig = 0;
588 if (warn_traditional)
589 warning ("the meaning of `\\x' varies with -traditional");
591 if (flag_traditional)
607 if (c >= 'a' && c <= 'f')
608 code += c - 'a' + 10;
609 if (c >= 'A' && c <= 'F')
610 code += c - 'A' + 10;
613 if (code != 0 || count != 0)
622 error ("\\x used with no following hex digits");
624 /* Digits are all 0's. Ok. */
626 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
629 << (TYPE_PRECISION (integer_type_node) - (count - 1)
632 pedwarn ("hex escape out of range");
635 case '0': case '1': case '2': case '3': case '4':
636 case '5': case '6': case '7':
639 while ((c <= '7') && (c >= '0') && (count++ < 3))
641 code = (code * 8) + (c - '0');
648 case '\\': case '\'': case '"':
652 ffelex_next_line_ ();
662 return TARGET_NEWLINE;
677 if (warn_traditional)
678 warning ("the meaning of `\\a' varies with -traditional");
680 if (flag_traditional)
685 #if 0 /* Vertical tab is present in common usage compilers. */
686 if (flag_traditional)
694 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
700 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
704 /* `\%' is used to prevent SCCS from getting confused. */
707 pedwarn ("non-ANSI escape sequence `\\%c'", c);
710 if (c >= 040 && c < 0177)
711 pedwarn ("unknown escape sequence `\\%c'", c);
713 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
717 /* A miniature version of the C front-end lexer. */
720 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
727 register unsigned buffer_length;
729 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
730 ffelex_token_kill (*xtoken);
734 case '0': case '1': case '2': case '3': case '4':
735 case '5': case '6': case '7': case '8': case '9':
736 buffer_length = ARRAY_SIZE (buff);
739 r = &buff[buffer_length];
745 register unsigned bytes_used = (p - q);
748 q = (char *)xrealloc (q, buffer_length);
750 r = &q[buffer_length];
752 c = ffelex_getc_ (finput);
757 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
758 ffewhere_column_unknown ());
766 buffer_length = ARRAY_SIZE (buff);
769 r = &buff[buffer_length];
770 c = ffelex_getc_ (finput);
784 case '\\': /* ~~~~~ */
785 c = ffelex_cfebackslash_ (&use_d, &d, finput);
790 error ("Badly formed directive -- no closing quote");
800 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
805 register unsigned bytes_used = (p - q);
807 buffer_length = bytes_used * 2;
808 q = (char *)xrealloc (q, buffer_length);
810 r = &q[buffer_length];
819 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
820 ffewhere_column_unknown ());
837 ffelex_file_pop_ (const char *input_filename)
839 if (input_file_stack->next)
841 struct file_stack *p = input_file_stack;
842 input_file_stack = p->next;
844 input_file_stack_tick++;
845 (*debug_hooks->end_source_file) (input_file_stack->line);
848 error ("#-lines for entering and leaving files don't match");
850 /* Now that we've pushed or popped the input stack,
851 update the name in the top element. */
852 if (input_file_stack)
853 input_file_stack->name = input_filename;
857 ffelex_file_push_ (int old_lineno, const char *input_filename)
860 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
862 input_file_stack->line = old_lineno;
863 p->next = input_file_stack;
864 p->name = input_filename;
865 input_file_stack = p;
866 input_file_stack_tick++;
868 (*debug_hooks->start_source_file) (0, input_filename);
870 /* Now that we've pushed or popped the input stack,
871 update the name in the top element. */
872 if (input_file_stack)
873 input_file_stack->name = input_filename;
876 /* Prepare to finish a statement-in-progress by sending the current
877 token, if any, then setting up EOS as the current token with the
878 appropriate current pointer. The caller can then move the current
879 pointer before actually sending EOS, if desired, as it is in
880 typical fixed-form cases. */
883 ffelex_prepare_eos_ ()
885 if (ffelex_token_->type != FFELEX_typeNONE)
887 ffelex_backslash_ (EOF, 0);
889 switch (ffelex_raw_mode_)
895 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
896 : FFEBAD_NO_CLOSING_QUOTE);
897 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
898 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
909 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
910 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
911 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
912 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
915 /* Make sure the token has some text, might as well fill up with spaces. */
918 ffelex_append_to_token_ (' ');
919 } while (--ffelex_raw_mode_ > 0);
923 ffelex_raw_mode_ = 0;
924 ffelex_send_token_ ();
926 ffelex_token_->type = FFELEX_typeEOS;
927 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
928 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
932 ffelex_finish_statement_ ()
934 if ((ffelex_number_of_tokens_ == 0)
935 && (ffelex_token_->type == FFELEX_typeNONE))
936 return; /* Don't have a statement pending. */
938 if (ffelex_token_->type != FFELEX_typeEOS)
939 ffelex_prepare_eos_ ();
941 ffelex_permit_include_ = TRUE;
942 ffelex_send_token_ ();
943 ffelex_permit_include_ = FALSE;
944 ffelex_number_of_tokens_ = 0;
945 ffelex_label_tokens_ = 0;
946 ffelex_names_ = TRUE;
947 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
948 ffelex_hexnum_ = FALSE;
950 if (!ffe_is_ffedebug ())
953 /* For debugging purposes only. */
955 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
957 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
958 ffelex_old_total_tokens_, ffelex_total_tokens_);
959 ffelex_old_total_tokens_ = ffelex_total_tokens_;
963 /* Copied from gcc/c-common.c get_directive_line. */
966 ffelex_get_directive_line_ (char **text, FILE *finput)
968 static char *directive_buffer = NULL;
969 static unsigned buffer_length = 0;
971 register char *buffer_limit;
972 register int looking_for = 0;
973 register int char_escaped = 0;
975 if (buffer_length == 0)
977 directive_buffer = (char *)xmalloc (128);
981 buffer_limit = &directive_buffer[buffer_length];
983 for (p = directive_buffer; ; )
987 /* Make buffer bigger if it is full. */
988 if (p >= buffer_limit)
990 register unsigned bytes_used = (p - directive_buffer);
994 = (char *)xrealloc (directive_buffer, buffer_length);
995 p = &directive_buffer[bytes_used];
996 buffer_limit = &directive_buffer[buffer_length];
1001 /* Discard initial whitespace. */
1002 if ((c == ' ' || c == '\t') && p == directive_buffer)
1005 /* Detect the end of the directive. */
1006 if ((c == '\n' && looking_for == 0)
1009 if (looking_for != 0)
1010 error ("Bad directive -- missing close-quote");
1013 *text = directive_buffer;
1019 ffelex_next_line_ ();
1021 /* Handle string and character constant syntax. */
1024 if (looking_for == c && !char_escaped)
1025 looking_for = 0; /* Found terminator... stop looking. */
1028 if (c == '\'' || c == '"')
1029 looking_for = c; /* Don't stop buffering until we see another
1030 one of these (or an EOF). */
1032 /* Handle backslash. */
1033 char_escaped = (c == '\\' && ! char_escaped);
1037 /* Handle # directives that make it through (or are generated by) the
1038 preprocessor. As much as reasonably possible, emulate the behavior
1039 of the gcc compiler phase cc1, though interactions between #include
1040 and INCLUDE might possibly produce bizarre results in terms of
1041 error reporting and the generation of debugging info vis-a-vis the
1042 locations of some things.
1044 Returns the next character unhandled, which is always newline or EOF. */
1046 #if defined HANDLE_PRAGMA
1047 /* Local versions of these macros, that can be passed as function pointers. */
1051 return getc (finput);
1058 ungetc (arg, finput);
1060 #endif /* HANDLE_PRAGMA */
1063 ffelex_hash_ (FILE *finput)
1066 ffelexToken token = NULL;
1068 /* Read first nonwhite char after the `#'. */
1070 c = ffelex_getc_ (finput);
1071 while (c == ' ' || c == '\t')
1072 c = ffelex_getc_ (finput);
1074 /* If a letter follows, then if the word here is `line', skip
1075 it and ignore it; otherwise, ignore the line, with an error
1076 if the word isn't `pragma', `ident', `define', or `undef'. */
1082 if (getc (finput) == 'r'
1083 && getc (finput) == 'a'
1084 && getc (finput) == 'g'
1085 && getc (finput) == 'm'
1086 && getc (finput) == 'a'
1087 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1090 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1091 static char buffer [128];
1092 char * buff = buffer;
1094 /* Read the pragma name into a buffer.
1095 ISSPACE() may evaluate its argument more than once! */
1096 while (((c = getc (finput)), ISSPACE(c)))
1104 while (c != EOF && ! ISSPACE (c) && c != '\n'
1105 && buff < buffer + 128);
1110 #ifdef HANDLE_PRAGMA
1111 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1113 #endif /* HANDLE_PRAGMA */
1114 #ifdef HANDLE_GENERIC_PRAGMAS
1115 if (handle_generic_pragma (buffer))
1117 #endif /* !HANDLE_GENERIC_PRAGMAS */
1119 /* Issue a warning message if we have been asked to do so.
1120 Ignoring unknown pragmas in system header file unless
1121 an explcit -Wunknown-pragmas has been given. */
1122 if (warn_unknown_pragmas > 1
1123 || (warn_unknown_pragmas && ! in_system_header))
1124 warning ("ignoring pragma: %s", token_buffer);
1132 if (getc (finput) == 'e'
1133 && getc (finput) == 'f'
1134 && getc (finput) == 'i'
1135 && getc (finput) == 'n'
1136 && getc (finput) == 'e'
1137 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1142 c = ffelex_get_directive_line_ (&text, finput);
1144 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1145 (*debug_hooks->define) (lineno, text);
1152 if (getc (finput) == 'n'
1153 && getc (finput) == 'd'
1154 && getc (finput) == 'e'
1155 && getc (finput) == 'f'
1156 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1161 c = ffelex_get_directive_line_ (&text, finput);
1163 if (debug_info_level == DINFO_LEVEL_VERBOSE)
1164 (*debug_hooks->undef) (lineno, text);
1171 if (getc (finput) == 'i'
1172 && getc (finput) == 'n'
1173 && getc (finput) == 'e'
1174 && ((c = getc (finput)) == ' ' || c == '\t'))
1179 if (getc (finput) == 'd'
1180 && getc (finput) == 'e'
1181 && getc (finput) == 'n'
1182 && getc (finput) == 't'
1183 && ((c = getc (finput)) == ' ' || c == '\t'))
1185 /* #ident. The pedantic warning is now in cpp. */
1187 /* Here we have just seen `#ident '.
1188 A string constant should follow. */
1190 while (c == ' ' || c == '\t')
1193 /* If no argument, ignore the line. */
1194 if (c == '\n' || c == EOF)
1197 c = ffelex_cfelex_ (&token, finput, c);
1200 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1202 error ("invalid #ident");
1206 if (! flag_no_ident)
1208 #ifdef ASM_OUTPUT_IDENT
1209 ASM_OUTPUT_IDENT (asm_out_file,
1210 ffelex_token_text (token));
1214 /* Skip the rest of this line. */
1219 error ("undefined or invalid # directive");
1224 /* Here we have either `#line' or `# <nonletter>'.
1225 In either case, it should be a line number; a digit should follow. */
1227 while (c == ' ' || c == '\t')
1228 c = ffelex_getc_ (finput);
1230 /* If the # is the only nonwhite char on the line,
1231 just ignore it. Check the new newline. */
1232 if (c == '\n' || c == EOF)
1235 /* Something follows the #; read a token. */
1237 c = ffelex_cfelex_ (&token, finput, c);
1240 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1242 int old_lineno = lineno;
1243 const char *old_input_filename = input_filename;
1246 /* subtract one, because it is the following line that
1247 gets the specified number */
1248 int l = atoi (ffelex_token_text (token)) - 1;
1250 /* Is this the last nonwhite stuff on the line? */
1251 while (c == ' ' || c == '\t')
1252 c = ffelex_getc_ (finput);
1253 if (c == '\n' || c == EOF)
1255 /* No more: store the line number and check following line. */
1257 if (!ffelex_kludge_flag_)
1259 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1262 ffelex_token_kill (token);
1267 /* More follows: it must be a string constant (filename). */
1269 /* Read the string constant. */
1270 c = ffelex_cfelex_ (&token, finput, c);
1273 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1275 error ("invalid #line");
1281 if (ffelex_kludge_flag_)
1282 input_filename = ggc_strdup (ffelex_token_text (token));
1285 wf = ffewhere_file_new (ffelex_token_text (token),
1286 ffelex_token_length (token));
1287 input_filename = ffewhere_file_name (wf);
1288 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1291 #if 0 /* Not sure what g77 should do with this yet. */
1292 /* Each change of file name
1293 reinitializes whether we are now in a system header. */
1294 in_system_header = 0;
1297 if (main_input_filename == 0)
1298 main_input_filename = input_filename;
1300 /* Is this the last nonwhite stuff on the line? */
1301 while (c == ' ' || c == '\t')
1303 if (c == '\n' || c == EOF)
1305 if (!ffelex_kludge_flag_)
1307 /* Update the name in the top element of input_file_stack. */
1308 if (input_file_stack)
1309 input_file_stack->name = input_filename;
1312 ffelex_token_kill (token);
1317 c = ffelex_cfelex_ (&token, finput, c);
1319 /* `1' after file name means entering new file.
1320 `2' after file name means just left a file. */
1323 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1325 int num = atoi (ffelex_token_text (token));
1327 if (ffelex_kludge_flag_)
1330 input_filename = old_input_filename;
1331 error ("Use `#line ...' instead of `# ...' in first line");
1336 /* Pushing to a new file. */
1337 ffelex_file_push_ (old_lineno, input_filename);
1341 /* Popping out of a file. */
1342 ffelex_file_pop_ (input_filename);
1345 /* Is this the last nonwhite stuff on the line? */
1346 while (c == ' ' || c == '\t')
1348 if (c == '\n' || c == EOF)
1351 ffelex_token_kill (token);
1355 c = ffelex_cfelex_ (&token, finput, c);
1358 /* `3' after file name means this is a system header file. */
1360 #if 0 /* Not sure what g77 should do with this yet. */
1362 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1363 && (atoi (ffelex_token_text (token)) == 3))
1364 in_system_header = 1;
1367 while (c == ' ' || c == '\t')
1369 if (((token != NULL)
1370 || (c != '\n' && c != EOF))
1371 && ffelex_kludge_flag_)
1374 input_filename = old_input_filename;
1375 error ("Use `#line ...' instead of `# ...' in first line");
1377 if (c == '\n' || c == EOF)
1379 if (token != NULL && !ffelex_kludge_flag_)
1380 ffelex_token_kill (token);
1385 error ("invalid #-line");
1387 /* skip the rest of this line. */
1389 if ((token != NULL) && !ffelex_kludge_flag_)
1390 ffelex_token_kill (token);
1391 while ((c = getc (finput)) != EOF && c != '\n')
1396 /* "Image" a character onto the card image, return incremented column number.
1398 Normally invoking this function as in
1399 column = ffelex_image_char_ (c, column);
1400 is the same as doing:
1401 ffelex_card_image_[column++] = c;
1403 However, tabs and carriage returns are handled specially, to preserve
1404 the visual "image" of the input line (in most editors) in the card
1407 Carriage returns are ignored, as they are assumed to be followed
1410 A tab is handled by first doing:
1411 ffelex_card_image_[column++] = ' ';
1412 That is, it translates to at least one space. Then, as many spaces
1413 are imaged as necessary to bring the column number to the next tab
1414 position, where tab positions start in the ninth column and each
1415 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1416 is set to TRUE to notify the lexer that a tab was seen.
1418 Columns are numbered and tab stops set as illustrated below:
1420 012345670123456701234567...
1424 xxxxxxx yyyyyyy zzzzzzz
1425 xxxxxxxx yyyyyyyy... */
1427 static ffewhereColumnNumber
1428 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1430 ffewhereColumnNumber old_column = column;
1432 if (column >= ffelex_card_size_)
1434 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1436 if (ffelex_bad_line_)
1439 if ((newmax >> 1) != ffelex_card_size_)
1440 { /* Overflowed column number. */
1441 overflow: /* :::::::::::::::::::: */
1443 ffelex_bad_line_ = TRUE;
1444 strcpy (&ffelex_card_image_[column - 3], "...");
1445 ffelex_card_length_ = column;
1446 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1447 ffelex_linecount_current_, column + 1);
1452 = malloc_resize_ksr (malloc_pool_image (),
1455 ffelex_card_size_ + 9);
1456 ffelex_card_size_ = newmax;
1465 ffelex_saw_tab_ = TRUE;
1466 ffelex_card_image_[column++] = ' ';
1467 while ((column & 7) != 0)
1468 ffelex_card_image_[column++] = ' ';
1472 if (!ffelex_bad_line_)
1474 ffelex_bad_line_ = TRUE;
1475 strcpy (&ffelex_card_image_[column], "[\\0]");
1476 ffelex_card_length_ = column + 4;
1477 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1478 FFEBAD_severityFATAL);
1479 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1486 ffelex_card_image_[column++] = c;
1490 if (column < old_column)
1492 column = old_column;
1493 goto overflow; /* :::::::::::::::::::: */
1502 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1503 FILE *include_file = ffelex_include_file_;
1504 /* The rest of this is to push, and after the INCLUDE file is processed,
1505 pop, the static lexer state info that pertains to each particular
1508 ffewhereColumnNumber card_size = ffelex_card_size_;
1509 ffewhereColumnNumber card_length = ffelex_card_length_;
1510 ffewhereLine current_wl = ffelex_current_wl_;
1511 ffewhereColumn current_wc = ffelex_current_wc_;
1512 bool saw_tab = ffelex_saw_tab_;
1513 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1514 ffewhereFile current_wf = ffelex_current_wf_;
1515 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1516 ffewhereLineNumber linecount_offset
1517 = ffewhere_line_filelinenum (current_wl);
1518 int old_lineno = lineno;
1519 const char *old_input_filename = input_filename;
1521 if (card_length != 0)
1523 card_image = malloc_new_ks (malloc_pool_image (),
1524 "FFELEX saved card image",
1526 memcpy (card_image, ffelex_card_image_, card_length);
1531 ffelex_set_include_ = FALSE;
1533 ffelex_next_line_ ();
1535 ffewhere_file_set (include_wherefile, TRUE, 0);
1537 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1539 if (ffelex_include_free_form_)
1540 ffelex_file_free (include_wherefile, include_file);
1542 ffelex_file_fixed (include_wherefile, include_file);
1544 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1546 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1548 ffecom_close_include (include_file);
1550 if (card_length != 0)
1552 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1553 #error "need to handle possible reduction of card size here!!"
1555 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1556 memcpy (ffelex_card_image_, card_image, card_length);
1558 ffelex_card_image_[card_length] = '\0';
1560 input_filename = old_input_filename;
1561 lineno = old_lineno;
1562 ffelex_linecount_current_ = linecount_current;
1563 ffelex_current_wf_ = current_wf;
1564 ffelex_final_nontab_column_ = final_nontab_column;
1565 ffelex_saw_tab_ = saw_tab;
1566 ffelex_current_wc_ = current_wc;
1567 ffelex_current_wl_ = current_wl;
1568 ffelex_card_length_ = card_length;
1569 ffelex_card_size_ = card_size;
1572 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1574 ffewhereColumnNumber col;
1575 int c; // Char at col.
1576 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1577 // We have a continuation indicator.
1579 If there are <n> spaces starting at ffelex_card_image_[col] up through
1580 the null character, where <n> is 0 or greater, returns TRUE. */
1583 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1585 while (ffelex_card_image_[col] != '\0')
1587 if (ffelex_card_image_[col++] != ' ')
1593 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1595 ffewhereColumnNumber col;
1596 int c; // Char at col.
1597 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1598 // We have a continuation indicator.
1600 If there are <n> spaces starting at ffelex_card_image_[col] up through
1601 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1604 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1606 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1608 if (ffelex_card_image_[col++] != ' ')
1615 ffelex_next_line_ ()
1617 ffelex_linecount_current_ = ffelex_linecount_next_;
1618 ++ffelex_linecount_next_;
1623 ffelex_send_token_ ()
1625 ++ffelex_number_of_tokens_;
1627 ffelex_backslash_ (EOF, 0);
1629 if (ffelex_token_->text == NULL)
1631 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1633 ffelex_append_to_token_ ('\0');
1634 ffelex_token_->length = 0;
1638 ffelex_token_->text[ffelex_token_->length] = '\0';
1640 assert (ffelex_raw_mode_ == 0);
1642 if (ffelex_token_->type == FFELEX_typeNAMES)
1644 ffewhere_line_kill (ffelex_token_->currentnames_line);
1645 ffewhere_column_kill (ffelex_token_->currentnames_col);
1648 assert (ffelex_handler_ != NULL);
1649 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1650 assert (ffelex_handler_ != NULL);
1652 ffelex_token_kill (ffelex_token_);
1654 ffelex_token_ = ffelex_token_new_ ();
1655 ffelex_token_->uses = 1;
1656 ffelex_token_->text = NULL;
1657 if (ffelex_raw_mode_ < 0)
1659 ffelex_token_->type = FFELEX_typeCHARACTER;
1660 ffelex_token_->where_line = ffelex_raw_where_line_;
1661 ffelex_token_->where_col = ffelex_raw_where_col_;
1662 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1663 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1667 ffelex_token_->type = FFELEX_typeNONE;
1668 ffelex_token_->where_line = ffewhere_line_unknown ();
1669 ffelex_token_->where_col = ffewhere_column_unknown ();
1672 if (ffelex_set_include_)
1676 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1678 return ffelex_swallow_tokens_;
1680 Return this handler when you don't want to look at any more tokens in the
1681 statement because you've encountered an unrecoverable error in the
1684 static ffelexHandler
1685 ffelex_swallow_tokens_ (ffelexToken t)
1687 assert (ffelex_eos_handler_ != NULL);
1689 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1690 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1691 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1693 return (ffelexHandler) ffelex_swallow_tokens_;
1697 ffelex_token_new_ ()
1701 ++ffelex_total_tokens_;
1703 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1704 "FFELEX token", sizeof (*t));
1705 t->id_ = ffelex_token_nextid_++;
1710 ffelex_type_string_ (ffelexType type)
1712 static const char *const types[] = {
1714 "FFELEX_typeCOMMENT",
1720 "FFELEX_typeDOLLAR",
1722 "FFELEX_typePERCENT",
1723 "FFELEX_typeAMPERSAND",
1724 "FFELEX_typeAPOSTROPHE",
1725 "FFELEX_typeOPEN_PAREN",
1726 "FFELEX_typeCLOSE_PAREN",
1727 "FFELEX_typeASTERISK",
1730 "FFELEX_typePERIOD",
1732 "FFELEX_typeNUMBER",
1733 "FFELEX_typeOPEN_ANGLE",
1734 "FFELEX_typeEQUALS",
1735 "FFELEX_typeCLOSE_ANGLE",
1739 "FFELEX_typeCONCAT",
1742 "FFELEX_typeHOLLERITH",
1743 "FFELEX_typeCHARACTER",
1745 "FFELEX_typeSEMICOLON",
1746 "FFELEX_typeUNDERSCORE",
1747 "FFELEX_typeQUESTION",
1748 "FFELEX_typeOPEN_ARRAY",
1749 "FFELEX_typeCLOSE_ARRAY",
1750 "FFELEX_typeCOLONCOLON",
1751 "FFELEX_typeREL_LE",
1752 "FFELEX_typeREL_NE",
1753 "FFELEX_typeREL_EQ",
1754 "FFELEX_typePOINTS",
1758 if (type >= ARRAY_SIZE (types))
1764 ffelex_display_token (ffelexToken t)
1769 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1770 ffewhereColumnNumber_f "u)",
1772 ffelex_type_string_ (t->type),
1773 ffewhere_line_number (t->where_line),
1774 ffewhere_column_number (t->where_col));
1776 if (t->text != NULL)
1777 fprintf (dmpout, ": \"%.*s\"\n",
1781 fprintf (dmpout, ".\n");
1784 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1786 if (ffelex_expecting_character())
1787 // next token delivered by lexer will be CHARACTER.
1789 If the most recent call to ffelex_set_expecting_hollerith since the last
1790 token was delivered by the lexer passed a length of -1, then we return
1791 TRUE, because the next token we deliver will be typeCHARACTER, else we
1795 ffelex_expecting_character ()
1797 return (ffelex_raw_mode_ != 0);
1800 /* ffelex_file_fixed -- Lex a given file in fixed source form
1804 ffelex_file_fixed(wf,f);
1806 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1809 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1811 register int c = 0; /* Character currently under consideration. */
1812 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1813 bool disallow_continuation_line;
1814 bool ignore_disallowed_continuation = FALSE;
1815 int latest_char_in_file = 0; /* For getting back into comment-skipping
1818 ffewhereColumnNumber first_label_char; /* First char of label --
1820 char label_string[6]; /* Text of label. */
1821 int labi; /* Length of label text. */
1822 bool finish_statement; /* Previous statement finished? */
1823 bool have_content; /* This line have content? */
1824 bool just_do_label; /* Nothing but label (and continuation?) on
1827 /* Lex is called for a particular file, not for a particular program unit.
1828 Yet the two events do share common characteristics. The first line in a
1829 file or in a program unit cannot be a continuation line. No token can
1830 be in mid-formation. No current label for the statement exists, since
1831 there is no current statement. */
1833 assert (ffelex_handler_ != NULL);
1836 input_filename = ffewhere_file_name (wf);
1837 ffelex_current_wf_ = wf;
1838 disallow_continuation_line = TRUE;
1839 ignore_disallowed_continuation = FALSE;
1840 ffelex_token_->type = FFELEX_typeNONE;
1841 ffelex_number_of_tokens_ = 0;
1842 ffelex_label_tokens_ = 0;
1843 ffelex_current_wl_ = ffewhere_line_unknown ();
1844 ffelex_current_wc_ = ffewhere_column_unknown ();
1845 latest_char_in_file = '\n';
1847 if (ffe_is_null_version ())
1849 /* Just substitute a "program" directly here. */
1851 char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
1855 for (p = &line[0]; *p != '\0'; ++p)
1856 column = ffelex_image_char_ (*p, column);
1860 goto have_line; /* :::::::::::::::::::: */
1863 goto first_line; /* :::::::::::::::::::: */
1865 /* Come here to get a new line. */
1867 beginning_of_line: /* :::::::::::::::::::: */
1869 disallow_continuation_line = FALSE;
1871 /* Come here directly when last line didn't clarify the continuation issue. */
1873 beginning_of_line_again: /* :::::::::::::::::::: */
1875 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1876 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1879 = malloc_resize_ks (malloc_pool_image (),
1881 FFELEX_columnINITIAL_SIZE_ + 9,
1882 ffelex_card_size_ + 9);
1883 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1887 first_line: /* :::::::::::::::::::: */
1889 c = latest_char_in_file;
1890 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1893 end_of_file: /* :::::::::::::::::::: */
1895 /* Line ending in EOF instead of \n still counts as a whole line. */
1897 ffelex_finish_statement_ ();
1898 ffewhere_line_kill (ffelex_current_wl_);
1899 ffewhere_column_kill (ffelex_current_wc_);
1900 return (ffelexHandler) ffelex_handler_;
1903 ffelex_next_line_ ();
1905 ffelex_bad_line_ = FALSE;
1907 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1909 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1910 || (lextype == FFELEX_typeERROR)
1911 || (lextype == FFELEX_typeSLASH)
1912 || (lextype == FFELEX_typeHASH))
1914 /* Test most frequent type of line first, etc. */
1915 if ((lextype == FFELEX_typeCOMMENT)
1916 || ((lextype == FFELEX_typeSLASH)
1917 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1919 /* Typical case (straight comment), just ignore rest of line. */
1920 comment_line: /* :::::::::::::::::::: */
1922 while ((c != '\n') && (c != EOF))
1925 else if (lextype == FFELEX_typeHASH)
1926 c = ffelex_hash_ (f);
1927 else if (lextype == FFELEX_typeSLASH)
1929 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1930 ffelex_card_image_[0] = '/';
1931 ffelex_card_image_[1] = c;
1933 goto bad_first_character; /* :::::::::::::::::::: */
1936 /* typeERROR or unsupported typeHASH. */
1937 { /* Bad first character, get line and display
1939 column = ffelex_image_char_ (c, 0);
1941 bad_first_character: /* :::::::::::::::::::: */
1943 ffelex_bad_line_ = TRUE;
1944 while (((c = getc (f)) != '\n') && (c != EOF))
1945 column = ffelex_image_char_ (c, column);
1946 ffelex_card_image_[column] = '\0';
1947 ffelex_card_length_ = column;
1948 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
1949 ffelex_linecount_current_, 1);
1952 /* Read past last char in line. */
1956 ffelex_next_line_ ();
1957 goto end_of_file; /* :::::::::::::::::::: */
1962 ffelex_next_line_ ();
1965 goto end_of_file; /* :::::::::::::::::::: */
1967 ffelex_bad_line_ = FALSE;
1968 } /* while [c, first char, means comment] */
1972 || (ffelex_final_nontab_column_ == 0);
1974 if (lextype == FFELEX_typeDEBUG)
1975 c = ' '; /* A 'D' or 'd' in column 1 with the
1976 debug-lines option on. */
1978 column = ffelex_image_char_ (c, 0);
1980 /* Read the entire line in as is (with whitespace processing). */
1982 while (((c = getc (f)) != '\n') && (c != EOF))
1983 column = ffelex_image_char_ (c, column);
1985 if (ffelex_bad_line_)
1987 ffelex_card_image_[column] = '\0';
1988 ffelex_card_length_ = column;
1989 goto comment_line; /* :::::::::::::::::::: */
1992 /* If no tab, cut off line after column 72/132. */
1994 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
1996 /* Technically, we should now fill ffelex_card_image_ up thru column
1997 72/132 with spaces, since character/hollerith constants must count
1998 them in that manner. To save CPU time in several ways (avoid a loop
1999 here that would be used only when we actually end a line in
2000 character-constant mode; avoid writing memory unnecessarily; avoid a
2001 loop later checking spaces when not scanning for character-constant
2002 characters), we don't do this, and we do the appropriate thing when
2003 we encounter end-of-line while actually processing a character
2006 column = ffelex_final_nontab_column_;
2009 have_line: /* :::::::::::::::::::: */
2011 ffelex_card_image_[column] = '\0';
2012 ffelex_card_length_ = column;
2014 /* Save next char in file so we can use register-based c while analyzing
2015 line we just read. */
2017 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2019 have_content = FALSE;
2021 /* Handle label, if any. */
2024 first_label_char = FFEWHERE_columnUNKNOWN;
2025 for (column = 0; column < 5; ++column)
2027 switch (c = ffelex_card_image_[column])
2031 goto stop_looking; /* :::::::::::::::::::: */
2046 label_string[labi++] = c;
2047 if (first_label_char == FFEWHERE_columnUNKNOWN)
2048 first_label_char = column + 1;
2054 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2055 ffelex_linecount_current_,
2057 goto beginning_of_line_again; /* :::::::::::::::::::: */
2059 if (ffe_is_pedantic ())
2060 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2061 ffelex_linecount_current_, 1);
2062 finish_statement = FALSE;
2063 just_do_label = FALSE;
2064 goto got_a_continuation; /* :::::::::::::::::::: */
2067 if (ffelex_card_image_[column + 1] == '*')
2068 goto stop_looking; /* :::::::::::::::::::: */
2071 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2072 ffelex_linecount_current_, column + 1);
2073 goto beginning_of_line_again; /* :::::::::::::::::::: */
2077 stop_looking: /* :::::::::::::::::::: */
2079 label_string[labi] = '\0';
2081 /* Find first nonblank char starting with continuation column. */
2083 if (column == 5) /* In which case we didn't see end of line in
2085 while ((c = ffelex_card_image_[column]) == ' ')
2088 /* Now we're trying to figure out whether this is a continuation line and
2089 whether there's anything else of substance on the line. The cases are
2092 1. If a line has an explicit continuation character (other than the digit
2093 zero), then if it also has a label, the label is ignored and an error
2094 message is printed. Any remaining text on the line is passed to the
2095 parser tasks, thus even an all-blank line (possibly with an ignored
2096 label) aside from a positive continuation character might have meaning
2097 in the midst of a character or hollerith constant.
2099 2. If a line has no explicit continuation character (that is, it has a
2100 space in column 6 and the first non-space character past column 6 is
2101 not a digit 0-9), then there are two possibilities:
2103 A. A label is present and/or a non-space (and non-comment) character
2104 appears somewhere after column 6. Terminate processing of the previous
2105 statement, if any, send the new label for the next statement, if any,
2106 and start processing a new statement with this non-blank character, if
2109 B. The line is essentially blank, except for a possible comment character.
2110 Don't terminate processing of the previous statement and don't pass any
2111 characters to the parser tasks, since the line is not flagged as a
2112 continuation line. We treat it just like a completely blank line.
2114 3. If a line has a continuation character of zero (0), then we terminate
2115 processing of the previous statement, if any, send the new label for the
2116 next statement, if any, and start processing a new statement, if any
2117 non-blank characters are present.
2119 If, when checking to see if we should terminate the previous statement, it
2120 is found that there is no previous statement but that there is an
2121 outstanding label, substitute CONTINUE as the statement for the label
2122 and display an error message. */
2124 finish_statement = FALSE;
2125 just_do_label = FALSE;
2129 case '!': /* ANSI Fortran 90 says ! in column 6 is
2131 /* VXT Fortran says ! anywhere is comment, even column 6. */
2132 if (ffe_is_vxt () || (column != 5))
2133 goto no_tokens_on_line; /* :::::::::::::::::::: */
2134 goto got_a_continuation; /* :::::::::::::::::::: */
2137 if (ffelex_card_image_[column + 1] != '*')
2138 goto some_other_character; /* :::::::::::::::::::: */
2142 /* This seems right to do. But it is close to call, since / * starting
2143 in column 6 will thus be interpreted as a continuation line
2144 beginning with '*'. */
2146 goto got_a_continuation;/* :::::::::::::::::::: */
2150 /* End of line. Therefore may be continued-through line, so handle
2151 pending label as possible to-be-continued and drive end-of-statement
2152 for any previous statement, else treat as blank line. */
2154 no_tokens_on_line: /* :::::::::::::::::::: */
2156 if (ffe_is_pedantic () && (c == '/'))
2157 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2158 ffelex_linecount_current_, column + 1);
2159 if (first_label_char != FFEWHERE_columnUNKNOWN)
2160 { /* Can't be a continued-through line if it
2162 finish_statement = TRUE;
2163 have_content = TRUE;
2164 just_do_label = TRUE;
2167 goto beginning_of_line_again; /* :::::::::::::::::::: */
2170 if (ffe_is_pedantic () && (column != 5))
2171 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2172 ffelex_linecount_current_, column + 1);
2173 finish_statement = TRUE;
2174 goto check_for_content; /* :::::::::::::::::::: */
2186 /* NOTE: This label can be reached directly from the code
2187 that lexes the label field in columns 1-5. */
2188 got_a_continuation: /* :::::::::::::::::::: */
2190 if (first_label_char != FFEWHERE_columnUNKNOWN)
2192 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2193 ffelex_linecount_current_,
2195 ffelex_linecount_current_,
2197 first_label_char = FFEWHERE_columnUNKNOWN;
2199 if (disallow_continuation_line)
2201 if (!ignore_disallowed_continuation)
2202 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2203 ffelex_linecount_current_, column + 1);
2204 goto beginning_of_line_again; /* :::::::::::::::::::: */
2206 if (ffe_is_pedantic () && (column != 5))
2207 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2208 ffelex_linecount_current_, column + 1);
2209 if ((ffelex_raw_mode_ != 0)
2210 && (((c = ffelex_card_image_[column + 1]) != '\0')
2211 || !ffelex_saw_tab_))
2214 have_content = TRUE;
2218 check_for_content: /* :::::::::::::::::::: */
2220 while ((c = ffelex_card_image_[++column]) == ' ')
2225 && (ffelex_card_image_[column + 1] == '*')))
2227 if (ffe_is_pedantic () && (c == '/'))
2228 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2229 ffelex_linecount_current_, column + 1);
2230 just_do_label = TRUE;
2233 have_content = TRUE;
2238 some_other_character: /* :::::::::::::::::::: */
2241 goto got_a_continuation;/* :::::::::::::::::::: */
2243 /* Here is the very normal case of a regular character starting in
2244 column 7 or beyond with a blank in column 6. */
2246 finish_statement = TRUE;
2247 have_content = TRUE;
2252 || (first_label_char != FFEWHERE_columnUNKNOWN))
2254 /* The line has content of some kind, install new end-statement
2255 point for error messages. Note that "content" includes cases
2256 where there's little apparent content but enough to finish
2257 a statement. That's because finishing a statement can trigger
2258 an impending INCLUDE, and that requires accurate line info being
2259 maintained by the lexer. */
2261 if (finish_statement)
2262 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2264 ffewhere_line_kill (ffelex_current_wl_);
2265 ffewhere_column_kill (ffelex_current_wc_);
2266 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2267 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2270 /* We delay this for a combination of reasons. Mainly, it can start
2271 INCLUDE processing, and we want to delay that until the lexer's
2272 info on the line is coherent. And we want to delay that until we're
2273 sure there's a reason to make that info coherent, to avoid saving
2274 lots of useless lines. */
2276 if (finish_statement)
2277 ffelex_finish_statement_ ();
2279 /* If label is present, enclose it in a NUMBER token and send it along. */
2281 if (first_label_char != FFEWHERE_columnUNKNOWN)
2283 assert (ffelex_token_->type == FFELEX_typeNONE);
2284 ffelex_token_->type = FFELEX_typeNUMBER;
2285 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2286 strcpy (ffelex_token_->text, label_string);
2287 ffelex_token_->where_line
2288 = ffewhere_line_use (ffelex_current_wl_);
2289 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2290 ffelex_token_->length = labi;
2291 ffelex_send_token_ ();
2292 ++ffelex_label_tokens_;
2296 goto beginning_of_line; /* :::::::::::::::::::: */
2298 /* Here is the main engine for parsing. c holds the character at column.
2299 It is already known that c is not a blank, end of line, or shriek,
2300 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2301 character/hollerith constant). A partially filled token may already
2302 exist in ffelex_token_. One special case: if, when the end of the line
2303 is reached, continuation_line is FALSE and the only token on the line is
2304 END, then it is indeed the last statement. We don't look for
2305 continuation lines during this program unit in that case. This is
2306 according to ANSI. */
2308 if (ffelex_raw_mode_ != 0)
2311 parse_raw_character: /* :::::::::::::::::::: */
2315 ffewhereColumnNumber i;
2317 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2318 goto beginning_of_line; /* :::::::::::::::::::: */
2320 /* Pad out line with "virtual" spaces. */
2322 for (i = column; i < ffelex_final_nontab_column_; ++i)
2323 ffelex_card_image_[i] = ' ';
2324 ffelex_card_image_[i] = '\0';
2325 ffelex_card_length_ = i;
2329 switch (ffelex_raw_mode_)
2332 c = ffelex_backslash_ (c, column);
2336 if (!ffelex_backslash_reconsider_)
2337 ffelex_append_to_token_ (c);
2338 ffelex_raw_mode_ = -1;
2342 if (c == ffelex_raw_char_)
2344 ffelex_raw_mode_ = -1;
2345 ffelex_append_to_token_ (c);
2349 ffelex_raw_mode_ = 0;
2350 ffelex_backslash_reconsider_ = TRUE;
2355 if (c == ffelex_raw_char_)
2356 ffelex_raw_mode_ = -2;
2359 c = ffelex_backslash_ (c, column);
2362 ffelex_raw_mode_ = -3;
2366 ffelex_append_to_token_ (c);
2371 c = ffelex_backslash_ (c, column);
2375 if (!ffelex_backslash_reconsider_)
2377 ffelex_append_to_token_ (c);
2383 if (ffelex_backslash_reconsider_)
2384 ffelex_backslash_reconsider_ = FALSE;
2386 c = ffelex_card_image_[++column];
2388 if (ffelex_raw_mode_ == 0)
2390 ffelex_send_token_ ();
2391 assert (ffelex_raw_mode_ == 0);
2393 c = ffelex_card_image_[++column];
2397 && (ffelex_card_image_[column + 1] == '*')))
2398 goto beginning_of_line; /* :::::::::::::::::::: */
2399 goto parse_nonraw_character; /* :::::::::::::::::::: */
2401 goto parse_raw_character; /* :::::::::::::::::::: */
2404 parse_nonraw_character: /* :::::::::::::::::::: */
2406 switch (ffelex_token_->type)
2408 case FFELEX_typeNONE:
2412 ffelex_token_->type = FFELEX_typeQUOTE;
2413 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2414 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2415 ffelex_send_token_ ();
2419 ffelex_token_->type = FFELEX_typeDOLLAR;
2420 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2421 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2422 ffelex_send_token_ ();
2426 ffelex_token_->type = FFELEX_typePERCENT;
2427 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2428 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2429 ffelex_send_token_ ();
2433 ffelex_token_->type = FFELEX_typeAMPERSAND;
2434 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2435 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2436 ffelex_send_token_ ();
2440 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2441 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2442 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2443 ffelex_send_token_ ();
2447 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2448 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2449 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2453 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2454 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2455 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2456 ffelex_send_token_ ();
2460 ffelex_token_->type = FFELEX_typeASTERISK;
2461 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2462 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2466 ffelex_token_->type = FFELEX_typePLUS;
2467 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2468 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2469 ffelex_send_token_ ();
2473 ffelex_token_->type = FFELEX_typeCOMMA;
2474 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2475 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2476 ffelex_send_token_ ();
2480 ffelex_token_->type = FFELEX_typeMINUS;
2481 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2482 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2483 ffelex_send_token_ ();
2487 ffelex_token_->type = FFELEX_typePERIOD;
2488 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2489 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2490 ffelex_send_token_ ();
2494 ffelex_token_->type = FFELEX_typeSLASH;
2495 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2496 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2510 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2511 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2512 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2513 ffelex_append_to_token_ (c);
2517 ffelex_token_->type = FFELEX_typeCOLON;
2518 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2519 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2523 ffelex_token_->type = FFELEX_typeSEMICOLON;
2524 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2525 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2526 ffelex_permit_include_ = TRUE;
2527 ffelex_send_token_ ();
2528 ffelex_permit_include_ = FALSE;
2532 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2533 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2534 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2538 ffelex_token_->type = FFELEX_typeEQUALS;
2539 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2540 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2544 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2545 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2546 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2550 ffelex_token_->type = FFELEX_typeQUESTION;
2551 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2552 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2553 ffelex_send_token_ ();
2557 if (1 || ffe_is_90 ())
2559 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2560 ffelex_token_->where_line
2561 = ffewhere_line_use (ffelex_current_wl_);
2562 ffelex_token_->where_col
2563 = ffewhere_column_new (column + 1);
2564 ffelex_send_token_ ();
2620 c = ffesrc_char_source (c);
2622 if (ffesrc_char_match_init (c, 'H', 'h')
2623 && ffelex_expecting_hollerith_ != 0)
2625 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2626 ffelex_token_->type = FFELEX_typeHOLLERITH;
2627 ffelex_token_->where_line = ffelex_raw_where_line_;
2628 ffelex_token_->where_col = ffelex_raw_where_col_;
2629 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2630 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2631 c = ffelex_card_image_[++column];
2632 goto parse_raw_character; /* :::::::::::::::::::: */
2637 ffelex_token_->where_line
2638 = ffewhere_line_use (ffelex_token_->currentnames_line
2639 = ffewhere_line_use (ffelex_current_wl_));
2640 ffelex_token_->where_col
2641 = ffewhere_column_use (ffelex_token_->currentnames_col
2642 = ffewhere_column_new (column + 1));
2643 ffelex_token_->type = FFELEX_typeNAMES;
2647 ffelex_token_->where_line
2648 = ffewhere_line_use (ffelex_current_wl_);
2649 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2650 ffelex_token_->type = FFELEX_typeNAME;
2652 ffelex_append_to_token_ (c);
2656 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2657 ffelex_linecount_current_, column + 1);
2658 ffelex_finish_statement_ ();
2659 disallow_continuation_line = TRUE;
2660 ignore_disallowed_continuation = TRUE;
2661 goto beginning_of_line_again; /* :::::::::::::::::::: */
2665 case FFELEX_typeNAME:
2720 c = ffesrc_char_source (c);
2735 && !ffe_is_dollar_ok ())
2737 ffelex_send_token_ ();
2738 goto parse_next_character; /* :::::::::::::::::::: */
2740 ffelex_append_to_token_ (c);
2744 ffelex_send_token_ ();
2745 goto parse_next_character; /* :::::::::::::::::::: */
2749 case FFELEX_typeNAMES:
2804 c = ffesrc_char_source (c);
2819 && !ffe_is_dollar_ok ())
2821 ffelex_send_token_ ();
2822 goto parse_next_character; /* :::::::::::::::::::: */
2824 if (ffelex_token_->length < FFEWHERE_indexMAX)
2826 ffewhere_track (&ffelex_token_->currentnames_line,
2827 &ffelex_token_->currentnames_col,
2828 ffelex_token_->wheretrack,
2829 ffelex_token_->length,
2830 ffelex_linecount_current_,
2833 ffelex_append_to_token_ (c);
2837 ffelex_send_token_ ();
2838 goto parse_next_character; /* :::::::::::::::::::: */
2842 case FFELEX_typeNUMBER:
2855 ffelex_append_to_token_ (c);
2859 ffelex_send_token_ ();
2860 goto parse_next_character; /* :::::::::::::::::::: */
2864 case FFELEX_typeASTERISK:
2868 ffelex_token_->type = FFELEX_typePOWER;
2869 ffelex_send_token_ ();
2872 default: /* * not followed by another *. */
2873 ffelex_send_token_ ();
2874 goto parse_next_character; /* :::::::::::::::::::: */
2878 case FFELEX_typeCOLON:
2882 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2883 ffelex_send_token_ ();
2886 default: /* : not followed by another :. */
2887 ffelex_send_token_ ();
2888 goto parse_next_character; /* :::::::::::::::::::: */
2892 case FFELEX_typeSLASH:
2896 ffelex_token_->type = FFELEX_typeCONCAT;
2897 ffelex_send_token_ ();
2901 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2902 ffelex_send_token_ ();
2906 ffelex_token_->type = FFELEX_typeREL_NE;
2907 ffelex_send_token_ ();
2911 ffelex_send_token_ ();
2912 goto parse_next_character; /* :::::::::::::::::::: */
2916 case FFELEX_typeOPEN_PAREN:
2920 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2921 ffelex_send_token_ ();
2925 ffelex_send_token_ ();
2926 goto parse_next_character; /* :::::::::::::::::::: */
2930 case FFELEX_typeOPEN_ANGLE:
2934 ffelex_token_->type = FFELEX_typeREL_LE;
2935 ffelex_send_token_ ();
2939 ffelex_send_token_ ();
2940 goto parse_next_character; /* :::::::::::::::::::: */
2944 case FFELEX_typeEQUALS:
2948 ffelex_token_->type = FFELEX_typeREL_EQ;
2949 ffelex_send_token_ ();
2953 ffelex_token_->type = FFELEX_typePOINTS;
2954 ffelex_send_token_ ();
2958 ffelex_send_token_ ();
2959 goto parse_next_character; /* :::::::::::::::::::: */
2963 case FFELEX_typeCLOSE_ANGLE:
2967 ffelex_token_->type = FFELEX_typeREL_GE;
2968 ffelex_send_token_ ();
2972 ffelex_send_token_ ();
2973 goto parse_next_character; /* :::::::::::::::::::: */
2978 assert ("Serious error!!" == NULL);
2983 c = ffelex_card_image_[++column];
2985 parse_next_character: /* :::::::::::::::::::: */
2987 if (ffelex_raw_mode_ != 0)
2988 goto parse_raw_character; /* :::::::::::::::::::: */
2991 c = ffelex_card_image_[++column];
2996 && (ffelex_card_image_[column + 1] == '*')))
2998 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
2999 && (ffelex_token_->type == FFELEX_typeNAMES)
3000 && (ffelex_token_->length == 3)
3001 && (ffesrc_strncmp_2c (ffe_case_match (),
3002 ffelex_token_->text,
3003 "END", "end", "End",
3007 ffelex_finish_statement_ ();
3008 disallow_continuation_line = TRUE;
3009 ignore_disallowed_continuation = FALSE;
3010 goto beginning_of_line_again; /* :::::::::::::::::::: */
3012 goto beginning_of_line; /* :::::::::::::::::::: */
3014 goto parse_nonraw_character; /* :::::::::::::::::::: */
3017 /* ffelex_file_free -- Lex a given file in free source form
3021 ffelex_file_free(wf,f);
3023 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3026 ffelex_file_free (ffewhereFile wf, FILE *f)
3028 register int c = 0; /* Character currently under consideration. */
3029 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3030 bool continuation_line = FALSE;
3031 ffewhereColumnNumber continuation_column;
3032 int latest_char_in_file = 0; /* For getting back into comment-skipping
3035 /* Lex is called for a particular file, not for a particular program unit.
3036 Yet the two events do share common characteristics. The first line in a
3037 file or in a program unit cannot be a continuation line. No token can
3038 be in mid-formation. No current label for the statement exists, since
3039 there is no current statement. */
3041 assert (ffelex_handler_ != NULL);
3044 input_filename = ffewhere_file_name (wf);
3045 ffelex_current_wf_ = wf;
3046 continuation_line = FALSE;
3047 ffelex_token_->type = FFELEX_typeNONE;
3048 ffelex_number_of_tokens_ = 0;
3049 ffelex_current_wl_ = ffewhere_line_unknown ();
3050 ffelex_current_wc_ = ffewhere_column_unknown ();
3051 latest_char_in_file = '\n';
3053 /* Come here to get a new line. */
3055 beginning_of_line: /* :::::::::::::::::::: */
3057 c = latest_char_in_file;
3058 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3061 end_of_file: /* :::::::::::::::::::: */
3063 /* Line ending in EOF instead of \n still counts as a whole line. */
3065 ffelex_finish_statement_ ();
3066 ffewhere_line_kill (ffelex_current_wl_);
3067 ffewhere_column_kill (ffelex_current_wc_);
3068 return (ffelexHandler) ffelex_handler_;
3071 ffelex_next_line_ ();
3073 ffelex_bad_line_ = FALSE;
3075 /* Skip over initial-comment and empty lines as quickly as possible! */
3082 c = ffelex_hash_ (f);
3084 comment_line: /* :::::::::::::::::::: */
3086 while ((c != '\n') && (c != EOF))
3091 ffelex_next_line_ ();
3092 goto end_of_file; /* :::::::::::::::::::: */
3097 ffelex_next_line_ ();
3100 goto end_of_file; /* :::::::::::::::::::: */
3103 ffelex_saw_tab_ = FALSE;
3105 column = ffelex_image_char_ (c, 0);
3107 /* Read the entire line in as is (with whitespace processing). */
3109 while (((c = getc (f)) != '\n') && (c != EOF))
3110 column = ffelex_image_char_ (c, column);
3112 if (ffelex_bad_line_)
3114 ffelex_card_image_[column] = '\0';
3115 ffelex_card_length_ = column;
3116 goto comment_line; /* :::::::::::::::::::: */
3119 /* If no tab, cut off line after column 132. */
3121 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3122 column = FFELEX_FREE_MAX_COLUMNS_;
3124 ffelex_card_image_[column] = '\0';
3125 ffelex_card_length_ = column;
3127 /* Save next char in file so we can use register-based c while analyzing
3128 line we just read. */
3130 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3133 continuation_column = 0;
3135 /* Skip over initial spaces to see if the first nonblank character
3136 is exclamation point, newline, or EOF (line is therefore a comment) or
3137 ampersand (line is therefore a continuation line). */
3139 while ((c = ffelex_card_image_[column]) == ' ')
3146 goto beginning_of_line; /* :::::::::::::::::::: */
3149 continuation_column = column + 1;
3156 /* The line definitely has content of some kind, install new end-statement
3157 point for error messages. */
3159 ffewhere_line_kill (ffelex_current_wl_);
3160 ffewhere_column_kill (ffelex_current_wc_);
3161 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3162 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3164 /* Figure out which column to start parsing at. */
3166 if (continuation_line)
3168 if (continuation_column == 0)
3170 if (ffelex_raw_mode_ != 0)
3172 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3173 ffelex_linecount_current_, column + 1);
3175 else if (ffelex_token_->type != FFELEX_typeNONE)
3177 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3178 ffelex_linecount_current_, column + 1);
3181 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3182 { /* Line contains only a single "&" as only
3183 nonblank character. */
3184 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3185 ffelex_linecount_current_, continuation_column);
3186 goto beginning_of_line; /* :::::::::::::::::::: */
3188 column = continuation_column;
3193 c = ffelex_card_image_[column];
3194 continuation_line = FALSE;
3196 /* Here is the main engine for parsing. c holds the character at column.
3197 It is already known that c is not a blank, end of line, or shriek,
3198 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3199 character/hollerith constant). A partially filled token may already
3200 exist in ffelex_token_. */
3202 if (ffelex_raw_mode_ != 0)
3205 parse_raw_character: /* :::::::::::::::::::: */
3210 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3212 continuation_line = TRUE;
3213 goto beginning_of_line; /* :::::::::::::::::::: */
3218 ffelex_finish_statement_ ();
3219 goto beginning_of_line; /* :::::::::::::::::::: */
3225 switch (ffelex_raw_mode_)
3228 c = ffelex_backslash_ (c, column);
3232 if (!ffelex_backslash_reconsider_)
3233 ffelex_append_to_token_ (c);
3234 ffelex_raw_mode_ = -1;
3238 if (c == ffelex_raw_char_)
3240 ffelex_raw_mode_ = -1;
3241 ffelex_append_to_token_ (c);
3245 ffelex_raw_mode_ = 0;
3246 ffelex_backslash_reconsider_ = TRUE;
3251 if (c == ffelex_raw_char_)
3252 ffelex_raw_mode_ = -2;
3255 c = ffelex_backslash_ (c, column);
3258 ffelex_raw_mode_ = -3;
3262 ffelex_append_to_token_ (c);
3267 c = ffelex_backslash_ (c, column);
3271 if (!ffelex_backslash_reconsider_)
3273 ffelex_append_to_token_ (c);
3279 if (ffelex_backslash_reconsider_)
3280 ffelex_backslash_reconsider_ = FALSE;
3282 c = ffelex_card_image_[++column];
3284 if (ffelex_raw_mode_ == 0)
3286 ffelex_send_token_ ();
3287 assert (ffelex_raw_mode_ == 0);
3289 c = ffelex_card_image_[++column];
3290 if ((c == '\0') || (c == '!'))
3292 ffelex_finish_statement_ ();
3293 goto beginning_of_line; /* :::::::::::::::::::: */
3295 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3297 continuation_line = TRUE;
3298 goto beginning_of_line; /* :::::::::::::::::::: */
3300 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3302 goto parse_raw_character; /* :::::::::::::::::::: */
3305 parse_nonraw_character: /* :::::::::::::::::::: */
3307 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3309 continuation_line = TRUE;
3310 goto beginning_of_line; /* :::::::::::::::::::: */
3313 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3315 switch (ffelex_token_->type)
3317 case FFELEX_typeNONE:
3320 finish-statement/continue-statement
3323 c = ffelex_card_image_[++column];
3324 if ((c == '\0') || (c == '!'))
3326 ffelex_finish_statement_ ();
3327 goto beginning_of_line; /* :::::::::::::::::::: */
3329 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3331 continuation_line = TRUE;
3332 goto beginning_of_line; /* :::::::::::::::::::: */
3339 ffelex_token_->type = FFELEX_typeQUOTE;
3340 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3341 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3342 ffelex_send_token_ ();
3346 ffelex_token_->type = FFELEX_typeDOLLAR;
3347 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3348 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3349 ffelex_send_token_ ();
3353 ffelex_token_->type = FFELEX_typePERCENT;
3354 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3355 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3356 ffelex_send_token_ ();
3360 ffelex_token_->type = FFELEX_typeAMPERSAND;
3361 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3362 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3363 ffelex_send_token_ ();
3367 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3368 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3369 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3370 ffelex_send_token_ ();
3374 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3375 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3376 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3380 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3381 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3382 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3383 ffelex_send_token_ ();
3387 ffelex_token_->type = FFELEX_typeASTERISK;
3388 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3389 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3393 ffelex_token_->type = FFELEX_typePLUS;
3394 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3395 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3396 ffelex_send_token_ ();
3400 ffelex_token_->type = FFELEX_typeCOMMA;
3401 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3402 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3403 ffelex_send_token_ ();
3407 ffelex_token_->type = FFELEX_typeMINUS;
3408 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3409 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3410 ffelex_send_token_ ();
3414 ffelex_token_->type = FFELEX_typePERIOD;
3415 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3416 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3417 ffelex_send_token_ ();
3421 ffelex_token_->type = FFELEX_typeSLASH;
3422 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3423 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3437 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3438 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3439 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3440 ffelex_append_to_token_ (c);
3444 ffelex_token_->type = FFELEX_typeCOLON;
3445 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3446 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3450 ffelex_token_->type = FFELEX_typeSEMICOLON;
3451 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3452 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3453 ffelex_permit_include_ = TRUE;
3454 ffelex_send_token_ ();
3455 ffelex_permit_include_ = FALSE;
3459 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3460 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3461 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3465 ffelex_token_->type = FFELEX_typeEQUALS;
3466 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3467 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3471 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3472 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3473 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3477 ffelex_token_->type = FFELEX_typeQUESTION;
3478 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3479 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3480 ffelex_send_token_ ();
3484 if (1 || ffe_is_90 ())
3486 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3487 ffelex_token_->where_line
3488 = ffewhere_line_use (ffelex_current_wl_);
3489 ffelex_token_->where_col
3490 = ffewhere_column_new (column + 1);
3491 ffelex_send_token_ ();
3547 c = ffesrc_char_source (c);
3549 if (ffesrc_char_match_init (c, 'H', 'h')
3550 && ffelex_expecting_hollerith_ != 0)
3552 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3553 ffelex_token_->type = FFELEX_typeHOLLERITH;
3554 ffelex_token_->where_line = ffelex_raw_where_line_;
3555 ffelex_token_->where_col = ffelex_raw_where_col_;
3556 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3557 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3558 c = ffelex_card_image_[++column];
3559 goto parse_raw_character; /* :::::::::::::::::::: */
3562 if (ffelex_names_pure_)
3564 ffelex_token_->where_line
3565 = ffewhere_line_use (ffelex_token_->currentnames_line
3566 = ffewhere_line_use (ffelex_current_wl_));
3567 ffelex_token_->where_col
3568 = ffewhere_column_use (ffelex_token_->currentnames_col
3569 = ffewhere_column_new (column + 1));
3570 ffelex_token_->type = FFELEX_typeNAMES;
3574 ffelex_token_->where_line
3575 = ffewhere_line_use (ffelex_current_wl_);
3576 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3577 ffelex_token_->type = FFELEX_typeNAME;
3579 ffelex_append_to_token_ (c);
3583 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3584 ffelex_linecount_current_, column + 1);
3585 ffelex_finish_statement_ ();
3586 goto beginning_of_line; /* :::::::::::::::::::: */
3590 case FFELEX_typeNAME:
3645 c = ffesrc_char_source (c);
3660 && !ffe_is_dollar_ok ())
3662 ffelex_send_token_ ();
3663 goto parse_next_character; /* :::::::::::::::::::: */
3665 ffelex_append_to_token_ (c);
3669 ffelex_send_token_ ();
3670 goto parse_next_character; /* :::::::::::::::::::: */
3674 case FFELEX_typeNAMES:
3729 c = ffesrc_char_source (c);
3744 && !ffe_is_dollar_ok ())
3746 ffelex_send_token_ ();
3747 goto parse_next_character; /* :::::::::::::::::::: */
3749 if (ffelex_token_->length < FFEWHERE_indexMAX)
3751 ffewhere_track (&ffelex_token_->currentnames_line,
3752 &ffelex_token_->currentnames_col,
3753 ffelex_token_->wheretrack,
3754 ffelex_token_->length,
3755 ffelex_linecount_current_,
3758 ffelex_append_to_token_ (c);
3762 ffelex_send_token_ ();
3763 goto parse_next_character; /* :::::::::::::::::::: */
3767 case FFELEX_typeNUMBER:
3780 ffelex_append_to_token_ (c);
3784 ffelex_send_token_ ();
3785 goto parse_next_character; /* :::::::::::::::::::: */
3789 case FFELEX_typeASTERISK:
3793 ffelex_token_->type = FFELEX_typePOWER;
3794 ffelex_send_token_ ();
3797 default: /* * not followed by another *. */
3798 ffelex_send_token_ ();
3799 goto parse_next_character; /* :::::::::::::::::::: */
3803 case FFELEX_typeCOLON:
3807 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3808 ffelex_send_token_ ();
3811 default: /* : not followed by another :. */
3812 ffelex_send_token_ ();
3813 goto parse_next_character; /* :::::::::::::::::::: */
3817 case FFELEX_typeSLASH:
3821 ffelex_token_->type = FFELEX_typeCONCAT;
3822 ffelex_send_token_ ();
3826 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3827 ffelex_send_token_ ();
3831 ffelex_token_->type = FFELEX_typeREL_NE;
3832 ffelex_send_token_ ();
3836 ffelex_send_token_ ();
3837 goto parse_next_character; /* :::::::::::::::::::: */
3841 case FFELEX_typeOPEN_PAREN:
3845 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3846 ffelex_send_token_ ();
3850 ffelex_send_token_ ();
3851 goto parse_next_character; /* :::::::::::::::::::: */
3855 case FFELEX_typeOPEN_ANGLE:
3859 ffelex_token_->type = FFELEX_typeREL_LE;
3860 ffelex_send_token_ ();
3864 ffelex_send_token_ ();
3865 goto parse_next_character; /* :::::::::::::::::::: */
3869 case FFELEX_typeEQUALS:
3873 ffelex_token_->type = FFELEX_typeREL_EQ;
3874 ffelex_send_token_ ();
3878 ffelex_token_->type = FFELEX_typePOINTS;
3879 ffelex_send_token_ ();
3883 ffelex_send_token_ ();
3884 goto parse_next_character; /* :::::::::::::::::::: */
3888 case FFELEX_typeCLOSE_ANGLE:
3892 ffelex_token_->type = FFELEX_typeREL_GE;
3893 ffelex_send_token_ ();
3897 ffelex_send_token_ ();
3898 goto parse_next_character; /* :::::::::::::::::::: */
3903 assert ("Serious error!" == NULL);
3908 c = ffelex_card_image_[++column];
3910 parse_next_character: /* :::::::::::::::::::: */
3912 if (ffelex_raw_mode_ != 0)
3913 goto parse_raw_character; /* :::::::::::::::::::: */
3915 if ((c == '\0') || (c == '!'))
3917 ffelex_finish_statement_ ();
3918 goto beginning_of_line; /* :::::::::::::::::::: */
3920 goto parse_nonraw_character; /* :::::::::::::::::::: */
3923 /* See the code in com.c that calls this to understand why. */
3926 ffelex_hash_kludge (FILE *finput)
3928 /* If you change this constant string, you have to change whatever
3929 code might thus be affected by it in terms of having to use
3930 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3931 static char match[] = "# 1 \"";
3932 static int kludge[ARRAY_SIZE (match) + 1];
3937 /* Read chars as long as they match the target string.
3938 Copy them into an array that will serve as a record
3939 of what we read (essentially a multi-char ungetc(),
3940 for code that uses ffelex_getc_ instead of getc() elsewhere
3942 for (p = &match[0], q = &kludge[0], c = getc (finput);
3943 (c == *p) && (*p != '\0') && (c != EOF);
3944 ++p, ++q, c = getc (finput))
3947 *q = c; /* Might be EOF, which requires int. */
3950 ffelex_kludge_chars_ = &kludge[0];
3954 ffelex_kludge_flag_ = TRUE;
3955 ++ffelex_kludge_chars_;
3956 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
3957 ffelex_kludge_flag_ = FALSE;
3966 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
3967 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
3968 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
3969 "FFELEX card image",
3970 FFELEX_columnINITIAL_SIZE_ + 9);
3971 ffelex_card_image_[0] = '\0';
3973 for (i = 0; i < 256; ++i)
3974 ffelex_first_char_[i] = FFELEX_typeERROR;
3976 ffelex_first_char_['\t'] = FFELEX_typeRAW;
3977 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
3978 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
3979 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
3980 ffelex_first_char_['\r'] = FFELEX_typeRAW;
3981 ffelex_first_char_[' '] = FFELEX_typeRAW;
3982 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
3983 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
3984 ffelex_first_char_['/'] = FFELEX_typeSLASH;
3985 ffelex_first_char_['&'] = FFELEX_typeRAW;
3986 ffelex_first_char_['#'] = FFELEX_typeHASH;
3988 for (i = '0'; i <= '9'; ++i)
3989 ffelex_first_char_[i] = FFELEX_typeRAW;
3991 if ((ffe_case_match () == FFE_caseNONE)
3992 || ((ffe_case_match () == FFE_caseUPPER)
3993 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
3994 || ((ffe_case_match () == FFE_caseLOWER)
3995 && (ffe_case_source () == FFE_caseLOWER)))
3997 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
3998 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
4000 if ((ffe_case_match () == FFE_caseNONE)
4001 || ((ffe_case_match () == FFE_caseLOWER)
4002 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
4003 || ((ffe_case_match () == FFE_caseUPPER)
4004 && (ffe_case_source () == FFE_caseUPPER)))
4006 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
4007 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
4010 ffelex_linecount_current_ = 0;
4011 ffelex_linecount_next_ = 1;
4012 ffelex_raw_mode_ = 0;
4013 ffelex_set_include_ = FALSE;
4014 ffelex_permit_include_ = FALSE;
4015 ffelex_names_ = TRUE; /* First token in program is a names. */
4016 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
4018 ffelex_hexnum_ = FALSE;
4019 ffelex_expecting_hollerith_ = 0;
4020 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4021 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4023 ffelex_token_ = ffelex_token_new_ ();
4024 ffelex_token_->type = FFELEX_typeNONE;
4025 ffelex_token_->uses = 1;
4026 ffelex_token_->where_line = ffewhere_line_unknown ();
4027 ffelex_token_->where_col = ffewhere_column_unknown ();
4028 ffelex_token_->text = NULL;
4030 ffelex_handler_ = NULL;
4033 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4035 if (ffelex_is_names_expected())
4036 // Deliver NAMES token
4038 // Deliver NAME token
4040 Must be called while lexer is active, obviously. */
4043 ffelex_is_names_expected ()
4045 return ffelex_names_;
4048 /* Current card image, which has the master linecount number
4049 ffelex_linecount_current_. */
4054 return ffelex_card_image_;
4057 /* ffelex_line_length -- Return length of current lexer line
4059 printf("Length is %lu\n",ffelex_line_length());
4061 Must be called while lexer is active, obviously. */
4063 ffewhereColumnNumber
4064 ffelex_line_length ()
4066 return ffelex_card_length_;
4069 /* Master line count of current card image, or 0 if no card image
4073 ffelex_line_number ()
4075 return ffelex_linecount_current_;
4078 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4080 ffelex_set_expecting_hollerith(0);
4082 Lex initially assumes no hollerith constant is about to show up. If
4083 syntactic analysis expects one, it should call this function with the
4084 number of characters expected in the constant immediately after recognizing
4085 the decimal number preceding the "H" and the constant itself. Then, if
4086 the next character is indeed H, the lexer will interpret it as beginning
4087 a hollerith constant and ship the token formed by reading the specified
4088 number of characters (interpreting blanks and otherwise-comments too)
4089 from the input file. It is up to syntactic analysis to call this routine
4090 again with 0 to turn hollerith detection off immediately upon receiving
4091 the token that might or might not be HOLLERITH.
4093 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4094 character constant. Pass the expected termination character (apostrophe
4097 Pass for length either the length of the hollerith (must be > 0), -1
4098 meaning expecting a character constant, or 0 to cancel expectation of
4099 a hollerith only after calling it with a length of > 0 and receiving the
4100 next token (which may or may not have been a HOLLERITH token).
4102 Pass for which either an apostrophe or quote when passing length of -1.
4103 Else which is a don't-care.
4105 Pass for line and column the line/column info for the token beginning the
4106 character or hollerith constant, for use in error messages, when passing
4107 a length of -1 -- this function will invoke ffewhere_line/column_use to
4108 make its own copies. Else line and column are don't-cares (when length
4109 is 0) and the outstanding copies of the previous line/column info, if
4110 still around, are killed.
4113 When called with length of 0, also zero ffelex_raw_mode_. This is
4114 so ffest_save_ can undo the effects of replaying tokens like
4115 APOSTROPHE and QUOTE.
4117 New line, column arguments allow error messages to point to the true
4118 beginning of a character/hollerith constant, rather than the beginning
4119 of the content part, which makes them more consistent and helpful.
4121 New "which" argument allows caller to specify termination character,
4122 which should be apostrophe or double-quote, to support Fortran 90. */
4125 ffelex_set_expecting_hollerith (long length, char which,
4126 ffewhereLine line, ffewhereColumn column)
4129 /* First kill the pending line/col info, if any (should only be pending
4130 when this call has length==0, the previous call had length>0, and a
4131 non-HOLLERITH token was sent in between the calls, but play it safe). */
4133 ffewhere_line_kill (ffelex_raw_where_line_);
4134 ffewhere_column_kill (ffelex_raw_where_col_);
4136 /* Now handle the length function. */
4140 ffelex_expecting_hollerith_ = 0;
4141 ffelex_raw_mode_ = 0;
4142 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4143 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4144 return; /* Don't set new line/column info from args. */
4147 ffelex_raw_mode_ = -1;
4148 ffelex_raw_char_ = which;
4151 default: /* length > 0 */
4152 ffelex_expecting_hollerith_ = length;
4156 /* Now set new line/column information from passed args. */
4158 ffelex_raw_where_line_ = ffewhere_line_use (line);
4159 ffelex_raw_where_col_ = ffewhere_column_use (column);
4162 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4164 ffelex_set_handler((ffelexHandler) my_first_handler);
4166 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4167 after they return, but not while they are active. */
4170 ffelex_set_handler (ffelexHandler first)
4172 ffelex_handler_ = first;
4175 /* ffelex_set_hexnum -- Set hexnum flag
4177 ffelex_set_hexnum(TRUE);
4179 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4180 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4181 the character as the first of the next token. But when parsing a
4182 hexadecimal number, by calling this function with TRUE before starting
4183 the parse of the token itself, lex will interpret [0-9] as the start
4187 ffelex_set_hexnum (bool f)
4192 /* ffelex_set_include -- Set INCLUDE file to be processed next
4194 ffewhereFile wf; // The ffewhereFile object for the file.
4195 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4196 FILE *fi; // The file to INCLUDE.
4197 ffelex_set_include(wf,free_form,fi);
4199 Must be called only after receiving the EOS token following a valid
4200 INCLUDE statement specifying a file that has already been successfully
4204 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4206 assert (ffelex_permit_include_);
4207 assert (!ffelex_set_include_);
4208 ffelex_set_include_ = TRUE;
4209 ffelex_include_free_form_ = free_form;
4210 ffelex_include_file_ = fi;
4211 ffelex_include_wherefile_ = wf;
4214 /* ffelex_set_names -- Set names/name flag, names = TRUE
4216 ffelex_set_names(FALSE);
4218 Lex initially assumes multiple names should be formed. If this function is
4219 called with FALSE, then single names are formed instead. The differences
4220 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4221 and in whether full source-location tracking is performed (it is for
4222 multiple names, not for single names), which is more expensive in terms of
4226 ffelex_set_names (bool f)
4230 ffelex_names_pure_ = FALSE;
4233 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4235 ffelex_set_names_pure(FALSE);
4237 Like ffelex_set_names, except affects both lexers. Normally, the
4238 free-form lexer need not generate NAMES tokens because adjacent NAME
4239 tokens must be separated by spaces which causes the lexer to generate
4240 separate tokens for analysis (whereas in fixed-form the spaces are
4241 ignored resulting in one long token). But in FORMAT statements, for
4242 some reason, the Fortran 90 standard specifies that spaces can occur
4243 anywhere within a format-item-list with no effect on the format spec
4244 (except of course within character string edit descriptors), which means
4245 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4246 statement handling, the existence of spaces makes it hard to deal with,
4247 because each token is seen distinctly (i.e. seven tokens in the latter
4248 example). But when no spaces are provided, as in the former example,
4249 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4250 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4251 One, ffest_kw_format_ does a substring rather than full-string match,
4252 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4253 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4254 and three, error reporting can point to the actual character rather than
4255 at or prior to it. The first two things could be resolved by providing
4256 alternate functions fairly easy, thus allowing FORMAT handling to expect
4257 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4258 changes to FORMAT parsing), but the third, error reporting, would suffer,
4259 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4260 to exactly where the compilers thinks the problem is, to even begin to get
4261 a handle on it. So there. */
4264 ffelex_set_names_pure (bool f)
4266 ffelex_names_pure_ = f;
4270 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4272 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4275 Returns first_handler if start_char_index chars into master_token (which
4276 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4277 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4278 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4279 and sends it to first_handler. If anything other than NAME is sent, the
4280 character at the end of it in the master token is examined to see if it
4281 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4282 the handler returned by first_handler is invoked with that token, and
4283 this process is repeated until the end of the master token or a NAME
4284 token is reached. */
4287 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4288 ffeTokenLength start)
4294 p = ffelex_token_text (master) + (i = start);
4300 t = ffelex_token_number_from_names (master, i);
4301 p += ffelex_token_length (t);
4302 i += ffelex_token_length (t);
4304 else if (ffesrc_is_name_init (*p))
4306 t = ffelex_token_name_from_names (master, i, 0);
4307 p += ffelex_token_length (t);
4308 i += ffelex_token_length (t);
4312 t = ffelex_token_dollar_from_names (master, i);
4318 t = ffelex_token_uscore_from_names (master, i);
4324 assert ("not a valid NAMES character" == NULL);
4327 assert (first != NULL);
4328 first = (ffelexHandler) (*first) (t);
4329 ffelex_token_kill (t);
4335 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4337 return ffelex_swallow_tokens;
4339 Return this handler when you don't want to look at any more tokens in the
4340 statement because you've encountered an unrecoverable error in the
4344 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4346 assert (handler != NULL);
4348 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4349 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4350 return (ffelexHandler) (*handler) (t);
4352 ffelex_eos_handler_ = handler;
4353 return (ffelexHandler) ffelex_swallow_tokens_;
4356 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4359 t = ffelex_token_dollar_from_names(t,6);
4361 It's as if you made a new token of dollar type having the dollar
4362 at, in the example above, the sixth character of the NAMES token. */
4365 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4370 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4371 assert (start < t->length);
4372 assert (t->text[start] == '$');
4374 /* Now make the token. */
4376 nt = ffelex_token_new_ ();
4377 nt->type = FFELEX_typeDOLLAR;
4380 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4381 t->where_col, t->wheretrack, start);
4386 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4389 ffelex_token_kill(t);
4391 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4394 ffelex_token_kill (ffelexToken t)
4398 assert (t->uses > 0);
4403 --ffelex_total_tokens_;
4405 if (t->type == FFELEX_typeNAMES)
4406 ffewhere_track_kill (t->where_line, t->where_col,
4407 t->wheretrack, t->length);
4408 ffewhere_line_kill (t->where_line);
4409 ffewhere_column_kill (t->where_col);
4410 if (t->text != NULL)
4411 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4412 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4415 /* Make a new NAME token that is a substring of a NAMES token. */
4418 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4424 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4425 assert (start < t->length);
4427 len = t->length - start;
4431 assert ((start + len) <= t->length);
4433 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4435 nt = ffelex_token_new_ ();
4436 nt->type = FFELEX_typeNAME;
4437 nt->size = len; /* Assume nobody's gonna fiddle with token
4441 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4442 t->where_col, t->wheretrack, start);
4443 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4445 strncpy (nt->text, t->text + start, len);
4446 nt->text[len] = '\0';
4450 /* Make a new NAMES token that is a substring of another NAMES token. */
4453 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4459 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4460 assert (start < t->length);
4462 len = t->length - start;
4466 assert ((start + len) <= t->length);
4468 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4470 nt = ffelex_token_new_ ();
4471 nt->type = FFELEX_typeNAMES;
4472 nt->size = len; /* Assume nobody's gonna fiddle with token
4476 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4477 t->where_col, t->wheretrack, start);
4478 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4479 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4481 strncpy (nt->text, t->text + start, len);
4482 nt->text[len] = '\0';
4486 /* Make a new CHARACTER token. */
4489 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4493 t = ffelex_token_new_ ();
4494 t->type = FFELEX_typeCHARACTER;
4495 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4497 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4499 strcpy (t->text, s);
4500 t->where_line = ffewhere_line_use (l);
4501 t->where_col = ffewhere_column_new (c);
4505 /* Make a new EOF token right after end of file. */
4508 ffelex_token_new_eof ()
4512 t = ffelex_token_new_ ();
4513 t->type = FFELEX_typeEOF;
4516 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4517 t->where_col = ffewhere_column_new (1);
4521 /* Make a new NAME token. */
4524 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4528 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4530 t = ffelex_token_new_ ();
4531 t->type = FFELEX_typeNAME;
4532 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4534 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4536 strcpy (t->text, s);
4537 t->where_line = ffewhere_line_use (l);
4538 t->where_col = ffewhere_column_new (c);
4542 /* Make a new NAMES token. */
4545 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4549 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4551 t = ffelex_token_new_ ();
4552 t->type = FFELEX_typeNAMES;
4553 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4555 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4557 strcpy (t->text, s);
4558 t->where_line = ffewhere_line_use (l);
4559 t->where_col = ffewhere_column_new (c);
4560 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4565 /* Make a new NUMBER token.
4567 The first character of the string must be a digit, and only the digits
4568 are copied into the new number. So this may be used to easily extract
4569 a NUMBER token from within any text string. Then the length of the
4570 resulting token may be used to calculate where the digits stopped
4571 in the original string. */
4574 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4579 /* How long is the string of decimal digits at s? */
4581 len = strspn (s, "0123456789");
4583 /* Make sure there is at least one digit. */
4587 /* Now make the token. */
4589 t = ffelex_token_new_ ();
4590 t->type = FFELEX_typeNUMBER;
4591 t->length = t->size = len; /* Assume it won't get bigger. */
4593 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4595 strncpy (t->text, s, len);
4596 t->text[len] = '\0';
4597 t->where_line = ffewhere_line_use (l);
4598 t->where_col = ffewhere_column_new (c);
4602 /* Make a new token of any type that doesn't contain text. A private
4603 function that is used by public macros in the interface file. */
4606 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4610 t = ffelex_token_new_ ();
4614 t->where_line = ffewhere_line_use (l);
4615 t->where_col = ffewhere_column_new (c);
4619 /* Make a new NUMBER token from an existing NAMES token.
4621 Like ffelex_token_new_number, this function calculates the length
4622 of the digit string itself. */
4625 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4631 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4632 assert (start < t->length);
4634 /* How long is the string of decimal digits at s? */
4636 len = strspn (t->text + start, "0123456789");
4638 /* Make sure there is at least one digit. */
4642 /* Now make the token. */
4644 nt = ffelex_token_new_ ();
4645 nt->type = FFELEX_typeNUMBER;
4646 nt->size = len; /* Assume nobody's gonna fiddle with token
4650 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4651 t->where_col, t->wheretrack, start);
4652 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4654 strncpy (nt->text, t->text + start, len);
4655 nt->text[len] = '\0';
4659 /* Make a new UNDERSCORE token from a NAMES token. */
4662 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4667 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4668 assert (start < t->length);
4669 assert (t->text[start] == '_');
4671 /* Now make the token. */
4673 nt = ffelex_token_new_ ();
4674 nt->type = FFELEX_typeUNDERSCORE;
4676 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4677 t->where_col, t->wheretrack, start);
4682 /* ffelex_token_use -- Return another instance of a token
4685 t = ffelex_token_use(t);
4687 In a sense, the new token is a copy of the old, though it might be the
4688 same with just a new use count.
4690 We use the use count method (easy). */
4693 ffelex_token_use (ffelexToken t)
4696 assert ("_token_use: null token" == NULL);