Use new tail-calling mechanism on ARM.
[official-gcc.git] / gcc / f / lex.c
bloba79bab37fee9c5af277521a2053ca44a43bf56a7
1 /* Implementation of Fortran lexer
2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3 Contributed by James Craig Burley.
5 This file is part of GNU Fortran.
7 GNU Fortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Fortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Fortran; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
22 #include "proj.h"
23 #include "top.h"
24 #include "bad.h"
25 #include "com.h"
26 #include "lex.h"
27 #include "malloc.h"
28 #include "src.h"
29 #if FFECOM_targetCURRENT == FFECOM_targetGCC
30 #include "flags.j"
31 #include "input.j"
32 #include "toplev.j"
33 #include "tree.j"
34 #include "output.j" /* Must follow tree.j so TREE_CODE is defined! */
35 #include "ggc.j"
36 #endif
38 #ifdef DWARF_DEBUGGING_INFO
39 void dwarfout_resume_previous_source_file (register unsigned);
40 void dwarfout_start_new_source_file (register char *);
41 void dwarfout_define (register unsigned, register char *);
42 void dwarfout_undef (register unsigned, register char *);
43 #endif DWARF_DEBUGGING_INFO
45 static void ffelex_append_to_token_ (char c);
46 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
47 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
48 ffewhereColumnNumber cn0);
49 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
50 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
51 ffewhereColumnNumber cn1);
52 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
53 ffewhereColumnNumber cn0);
54 static void ffelex_finish_statement_ (void);
55 #if FFECOM_targetCURRENT == FFECOM_targetGCC
56 static int ffelex_get_directive_line_ (char **text, FILE *finput);
57 static int ffelex_hash_ (FILE *f);
58 #endif
59 static ffewhereColumnNumber ffelex_image_char_ (int c,
60 ffewhereColumnNumber col);
61 static void ffelex_include_ (void);
62 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
63 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
64 static void ffelex_next_line_ (void);
65 static void ffelex_prepare_eos_ (void);
66 static void ffelex_send_token_ (void);
67 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
68 static ffelexToken ffelex_token_new_ (void);
70 /* Pertaining to the geometry of the input file. */
72 /* Initial size for card image to be allocated. */
73 #define FFELEX_columnINITIAL_SIZE_ 255
75 /* The card image itself, which grows as source lines get longer. It
76 has room for ffelex_card_size_ + 8 characters, and the length of the
77 current image is ffelex_card_length_. (The + 8 characters are made
78 available for easy handling of tabs and such.) */
79 static char *ffelex_card_image_;
80 static ffewhereColumnNumber ffelex_card_size_;
81 static ffewhereColumnNumber ffelex_card_length_;
83 /* Max width for free-form lines (ISO F90). */
84 #define FFELEX_FREE_MAX_COLUMNS_ 132
86 /* True if we saw a tab on the current line, as this (currently) means
87 the line is therefore treated as though final_nontab_column_ were
88 infinite. */
89 static bool ffelex_saw_tab_;
91 /* TRUE if current line is known to be erroneous, so don't bother
92 expanding room for it just to display it. */
93 static bool ffelex_bad_line_ = FALSE;
95 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
96 static ffewhereColumnNumber ffelex_final_nontab_column_;
98 /* Array for quickly deciding what kind of line the current card has,
99 based on its first character. */
100 static ffelexType ffelex_first_char_[256];
102 /* Pertaining to file management. */
104 /* The wf argument of the most recent active ffelex_file_(fixed,free)
105 function. */
106 static ffewhereFile ffelex_current_wf_;
108 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
109 can be called). */
110 static bool ffelex_permit_include_;
112 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
113 called). */
114 static bool ffelex_set_include_;
116 /* Information on the pending INCLUDE file. */
117 static FILE *ffelex_include_file_;
118 static bool ffelex_include_free_form_;
119 static ffewhereFile ffelex_include_wherefile_;
121 /* Current master line count. */
122 static ffewhereLineNumber ffelex_linecount_current_;
123 /* Next master line count. */
124 static ffewhereLineNumber ffelex_linecount_next_;
126 /* ffewhere info on the latest (currently active) line read from the
127 active source file. */
128 static ffewhereLine ffelex_current_wl_;
129 static ffewhereColumn ffelex_current_wc_;
131 /* Pertaining to tokens in general. */
133 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
134 token. */
135 #define FFELEX_columnTOKEN_SIZE_ 63
136 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
137 #error "token size too small!"
138 #endif
140 /* Current token being lexed. */
141 static ffelexToken ffelex_token_;
143 /* Handler for current token. */
144 static ffelexHandler ffelex_handler_;
146 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
147 static bool ffelex_names_;
149 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
150 static bool ffelex_names_pure_;
152 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
153 numbers. */
154 static bool ffelex_hexnum_;
156 /* For ffelex_swallow_tokens(). */
157 static ffelexHandler ffelex_eos_handler_;
159 /* Number of tokens sent since last EOS or beginning of input file
160 (include INCLUDEd files). */
161 static unsigned long int ffelex_number_of_tokens_;
163 /* Number of labels sent (as NUMBER tokens) since last reset of
164 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
165 (Fixed-form source only.) */
166 static unsigned long int ffelex_label_tokens_;
168 /* Metering for token management, to catch token-memory leaks. */
169 static long int ffelex_total_tokens_ = 0;
170 static long int ffelex_old_total_tokens_ = 1;
171 static long int ffelex_token_nextid_ = 0;
173 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
175 /* >0 if a Hollerith constant of that length might be in mid-lex, used
176 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
177 mode (see ffelex_raw_mode_). */
178 static long int ffelex_expecting_hollerith_;
180 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
181 -2: Possible closing apostrophe/quote seen in CHARACTER.
182 -1: Lexing CHARACTER.
183 0: Not lexing CHARACTER or HOLLERITH.
184 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
185 static long int ffelex_raw_mode_;
187 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
188 static char ffelex_raw_char_;
190 /* TRUE when backslash processing had to use most recent character
191 to finish its state engine, but that character is not part of
192 the backslash sequence, so must be reconsidered as a "normal"
193 character in CHARACTER/HOLLERITH lexing. */
194 static bool ffelex_backslash_reconsider_ = FALSE;
196 /* Characters preread before lexing happened (might include EOF). */
197 static int *ffelex_kludge_chars_ = NULL;
199 /* Doing the kludge processing, so not initialized yet. */
200 static bool ffelex_kludge_flag_ = FALSE;
202 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
203 static ffewhereLine ffelex_raw_where_line_;
204 static ffewhereColumn ffelex_raw_where_col_;
207 /* Call this to append another character to the current token. If it isn't
208 currently big enough for it, it will be enlarged. The current token
209 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
211 static void
212 ffelex_append_to_token_ (char c)
214 if (ffelex_token_->text == NULL)
216 ffelex_token_->text
217 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
218 FFELEX_columnTOKEN_SIZE_ + 1);
219 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
220 ffelex_token_->length = 0;
222 else if (ffelex_token_->length >= ffelex_token_->size)
224 ffelex_token_->text
225 = malloc_resize_ksr (malloc_pool_image (),
226 ffelex_token_->text,
227 (ffelex_token_->size << 1) + 1,
228 ffelex_token_->size + 1);
229 ffelex_token_->size <<= 1;
230 assert (ffelex_token_->length < ffelex_token_->size);
232 #ifdef MAP_CHARACTER
233 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
234 please contact fortran@gnu.org if you wish to fund work to
235 port g77 to non-ASCII machines.
236 #endif
237 ffelex_token_->text[ffelex_token_->length++] = c;
240 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
241 being lexed. */
243 static int
244 ffelex_backslash_ (int c, ffewhereColumnNumber col)
246 static int state = 0;
247 static unsigned int count;
248 static int code;
249 static unsigned int firstdig = 0;
250 static int nonnull;
251 static ffewhereLineNumber line;
252 static ffewhereColumnNumber column;
254 /* See gcc/c-lex.c readescape() for a straightforward version
255 of this state engine for handling backslashes in character/
256 hollerith constants. */
258 #define wide_flag 0
259 #define warn_traditional 0
260 #define flag_traditional 0
262 switch (state)
264 case 0:
265 if ((c == '\\')
266 && (ffelex_raw_mode_ != 0)
267 && ffe_is_backslash ())
269 state = 1;
270 column = col + 1;
271 line = ffelex_linecount_current_;
272 return EOF;
274 return c;
276 case 1:
277 state = 0; /* Assume simple case. */
278 switch (c)
280 case 'x':
281 if (warn_traditional)
283 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
284 FFEBAD_severityWARNING);
285 ffelex_bad_here_ (0, line, column);
286 ffebad_finish ();
289 if (flag_traditional)
290 return c;
292 code = 0;
293 count = 0;
294 nonnull = 0;
295 state = 2;
296 return EOF;
298 case '0': case '1': case '2': case '3': case '4':
299 case '5': case '6': case '7':
300 code = c - '0';
301 count = 1;
302 state = 3;
303 return EOF;
305 case '\\': case '\'': case '"':
306 return c;
308 #if 0 /* Inappropriate for Fortran. */
309 case '\n':
310 ffelex_next_line_ ();
311 *ignore_ptr = 1;
312 return 0;
313 #endif
315 case 'n':
316 return TARGET_NEWLINE;
318 case 't':
319 return TARGET_TAB;
321 case 'r':
322 return TARGET_CR;
324 case 'f':
325 return TARGET_FF;
327 case 'b':
328 return TARGET_BS;
330 case 'a':
331 if (warn_traditional)
333 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
334 FFEBAD_severityWARNING);
335 ffelex_bad_here_ (0, line, column);
336 ffebad_finish ();
339 if (flag_traditional)
340 return c;
341 return TARGET_BELL;
343 case 'v':
344 #if 0 /* Vertical tab is present in common usage compilers. */
345 if (flag_traditional)
346 return c;
347 #endif
348 return TARGET_VT;
350 case 'e':
351 case 'E':
352 case '(':
353 case '{':
354 case '[':
355 case '%':
356 if (pedantic)
358 char m[2];
360 m[0] = c;
361 m[1] = '\0';
362 ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
363 FFEBAD_severityPEDANTIC);
364 ffelex_bad_here_ (0, line, column);
365 ffebad_string (m);
366 ffebad_finish ();
368 return (c == 'E' || c == 'e') ? 033 : c;
370 case '?':
371 return c;
373 default:
374 if (c >= 040 && c < 0177)
376 char m[2];
378 m[0] = c;
379 m[1] = '\0';
380 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
381 FFEBAD_severityPEDANTIC);
382 ffelex_bad_here_ (0, line, column);
383 ffebad_string (m);
384 ffebad_finish ();
386 else if (c == EOF)
388 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
389 FFEBAD_severityPEDANTIC);
390 ffelex_bad_here_ (0, line, column);
391 ffebad_finish ();
393 else
395 char m[20];
397 sprintf (&m[0], "%x", c);
398 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
399 FFEBAD_severityPEDANTIC);
400 ffelex_bad_here_ (0, line, column);
401 ffebad_string (m);
402 ffebad_finish ();
405 return c;
407 case 2:
408 if ((c >= 'a' && c <= 'f')
409 || (c >= 'A' && c <= 'F')
410 || (c >= '0' && c <= '9'))
412 code *= 16;
413 if (c >= 'a' && c <= 'f')
414 code += c - 'a' + 10;
415 if (c >= 'A' && c <= 'F')
416 code += c - 'A' + 10;
417 if (c >= '0' && c <= '9')
418 code += c - '0';
419 if (code != 0 || count != 0)
421 if (count == 0)
422 firstdig = code;
423 count++;
425 nonnull = 1;
426 return EOF;
429 state = 0;
431 if (! nonnull)
433 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
434 FFEBAD_severityFATAL);
435 ffelex_bad_here_ (0, line, column);
436 ffebad_finish ();
438 else if (count == 0)
439 /* Digits are all 0's. Ok. */
441 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
442 || (count > 1
443 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
444 <= (int) firstdig)))
446 ffebad_start_msg_lex ("Hex escape at %0 out of range",
447 FFEBAD_severityPEDANTIC);
448 ffelex_bad_here_ (0, line, column);
449 ffebad_finish ();
451 break;
453 case 3:
454 if ((c <= '7') && (c >= '0') && (count++ < 3))
456 code = (code * 8) + (c - '0');
457 return EOF;
459 state = 0;
460 break;
462 default:
463 assert ("bad backslash state" == NULL);
464 abort ();
467 /* Come here when code has a built character, and c is the next
468 character that might (or might not) be the next one in the constant. */
470 /* Don't bother doing this check for each character going into
471 CHARACTER or HOLLERITH constants, just the escaped-value ones.
472 gcc apparently checks every single character, which seems
473 like it'd be kinda slow and not worth doing anyway. */
475 if (!wide_flag
476 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
477 && code >= (1 << TYPE_PRECISION (char_type_node)))
479 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
480 FFEBAD_severityFATAL);
481 ffelex_bad_here_ (0, line, column);
482 ffebad_finish ();
485 if (c == EOF)
487 /* Known end of constant, just append this character. */
488 ffelex_append_to_token_ (code);
489 if (ffelex_raw_mode_ > 0)
490 --ffelex_raw_mode_;
491 return EOF;
494 /* Have two characters to handle. Do the first, then leave it to the
495 caller to detect anything special about the second. */
497 ffelex_append_to_token_ (code);
498 if (ffelex_raw_mode_ > 0)
499 --ffelex_raw_mode_;
500 ffelex_backslash_reconsider_ = TRUE;
501 return c;
504 /* ffelex_bad_1_ -- Issue diagnostic with one source point
506 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
508 Creates ffewhere line and column objects for the source point, sends them
509 along with the error code to ffebad, then kills the line and column
510 objects before returning. */
512 static void
513 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
515 ffewhereLine wl0;
516 ffewhereColumn wc0;
518 wl0 = ffewhere_line_new (ln0);
519 wc0 = ffewhere_column_new (cn0);
520 ffebad_start_lex (errnum);
521 ffebad_here (0, wl0, wc0);
522 ffebad_finish ();
523 ffewhere_line_kill (wl0);
524 ffewhere_column_kill (wc0);
527 /* ffelex_bad_2_ -- Issue diagnostic with two source points
529 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
530 otherline,othercolumn);
532 Creates ffewhere line and column objects for the source points, sends them
533 along with the error code to ffebad, then kills the line and column
534 objects before returning. */
536 static void
537 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
538 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
540 ffewhereLine wl0, wl1;
541 ffewhereColumn wc0, wc1;
543 wl0 = ffewhere_line_new (ln0);
544 wc0 = ffewhere_column_new (cn0);
545 wl1 = ffewhere_line_new (ln1);
546 wc1 = ffewhere_column_new (cn1);
547 ffebad_start_lex (errnum);
548 ffebad_here (0, wl0, wc0);
549 ffebad_here (1, wl1, wc1);
550 ffebad_finish ();
551 ffewhere_line_kill (wl0);
552 ffewhere_column_kill (wc0);
553 ffewhere_line_kill (wl1);
554 ffewhere_column_kill (wc1);
557 static void
558 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
559 ffewhereColumnNumber cn0)
561 ffewhereLine wl0;
562 ffewhereColumn wc0;
564 wl0 = ffewhere_line_new (ln0);
565 wc0 = ffewhere_column_new (cn0);
566 ffebad_here (n, wl0, wc0);
567 ffewhere_line_kill (wl0);
568 ffewhere_column_kill (wc0);
571 #if FFECOM_targetCURRENT == FFECOM_targetGCC
572 static int
573 ffelex_getc_ (FILE *finput)
575 int c;
577 if (ffelex_kludge_chars_ == NULL)
578 return getc (finput);
580 c = *ffelex_kludge_chars_++;
581 if (c != 0)
582 return c;
584 ffelex_kludge_chars_ = NULL;
585 return getc (finput);
588 #endif
589 #if FFECOM_targetCURRENT == FFECOM_targetGCC
590 static int
591 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
593 register int c = getc (finput);
594 register int code;
595 register unsigned count;
596 unsigned firstdig = 0;
597 int nonnull;
599 *use_d = 0;
601 switch (c)
603 case 'x':
604 if (warn_traditional)
605 warning ("the meaning of `\\x' varies with -traditional");
607 if (flag_traditional)
608 return c;
610 code = 0;
611 count = 0;
612 nonnull = 0;
613 while (1)
615 c = getc (finput);
616 if (!(c >= 'a' && c <= 'f')
617 && !(c >= 'A' && c <= 'F')
618 && !(c >= '0' && c <= '9'))
620 *use_d = 1;
621 *d = c;
622 break;
624 code *= 16;
625 if (c >= 'a' && c <= 'f')
626 code += c - 'a' + 10;
627 if (c >= 'A' && c <= 'F')
628 code += c - 'A' + 10;
629 if (c >= '0' && c <= '9')
630 code += c - '0';
631 if (code != 0 || count != 0)
633 if (count == 0)
634 firstdig = code;
635 count++;
637 nonnull = 1;
639 if (! nonnull)
640 error ("\\x used with no following hex digits");
641 else if (count == 0)
642 /* Digits are all 0's. Ok. */
644 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
645 || (count > 1
646 && (((unsigned) 1
647 << (TYPE_PRECISION (integer_type_node) - (count - 1)
648 * 4))
649 <= firstdig)))
650 pedwarn ("hex escape out of range");
651 return code;
653 case '0': case '1': case '2': case '3': case '4':
654 case '5': case '6': case '7':
655 code = 0;
656 count = 0;
657 while ((c <= '7') && (c >= '0') && (count++ < 3))
659 code = (code * 8) + (c - '0');
660 c = getc (finput);
662 *use_d = 1;
663 *d = c;
664 return code;
666 case '\\': case '\'': case '"':
667 return c;
669 case '\n':
670 ffelex_next_line_ ();
671 *use_d = 2;
672 return 0;
674 case EOF:
675 *use_d = 1;
676 *d = EOF;
677 return EOF;
679 case 'n':
680 return TARGET_NEWLINE;
682 case 't':
683 return TARGET_TAB;
685 case 'r':
686 return TARGET_CR;
688 case 'f':
689 return TARGET_FF;
691 case 'b':
692 return TARGET_BS;
694 case 'a':
695 if (warn_traditional)
696 warning ("the meaning of `\\a' varies with -traditional");
698 if (flag_traditional)
699 return c;
700 return TARGET_BELL;
702 case 'v':
703 #if 0 /* Vertical tab is present in common usage compilers. */
704 if (flag_traditional)
705 return c;
706 #endif
707 return TARGET_VT;
709 case 'e':
710 case 'E':
711 if (pedantic)
712 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
713 return 033;
715 case '?':
716 return c;
718 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
719 case '(':
720 case '{':
721 case '[':
722 /* `\%' is used to prevent SCCS from getting confused. */
723 case '%':
724 if (pedantic)
725 pedwarn ("non-ANSI escape sequence `\\%c'", c);
726 return c;
728 if (c >= 040 && c < 0177)
729 pedwarn ("unknown escape sequence `\\%c'", c);
730 else
731 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
732 return c;
735 #endif
736 /* A miniature version of the C front-end lexer. */
738 #if FFECOM_targetCURRENT == FFECOM_targetGCC
739 static int
740 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
742 ffelexToken token;
743 char buff[129];
744 char *p;
745 char *q;
746 char *r;
747 register unsigned buffer_length;
749 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
750 ffelex_token_kill (*xtoken);
752 switch (c)
754 case '0': case '1': case '2': case '3': case '4':
755 case '5': case '6': case '7': case '8': case '9':
756 buffer_length = ARRAY_SIZE (buff);
757 p = &buff[0];
758 q = p;
759 r = &buff[buffer_length];
760 for (;;)
762 *p++ = c;
763 if (p >= r)
765 register unsigned bytes_used = (p - q);
767 buffer_length *= 2;
768 q = (char *)xrealloc (q, buffer_length);
769 p = &q[bytes_used];
770 r = &q[buffer_length];
772 c = ffelex_getc_ (finput);
773 if (! ISDIGIT (c))
774 break;
776 *p = '\0';
777 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
778 ffewhere_column_unknown ());
780 if (q != &buff[0])
781 free (q);
783 break;
785 case '\"':
786 buffer_length = ARRAY_SIZE (buff);
787 p = &buff[0];
788 q = p;
789 r = &buff[buffer_length];
790 c = ffelex_getc_ (finput);
791 for (;;)
793 bool done = FALSE;
794 int use_d = 0;
795 int d;
797 switch (c)
799 case '\"':
800 c = getc (finput);
801 done = TRUE;
802 break;
804 case '\\': /* ~~~~~ */
805 c = ffelex_cfebackslash_ (&use_d, &d, finput);
806 break;
808 case EOF:
809 case '\n':
810 fatal ("Badly formed directive -- no closing quote");
811 done = TRUE;
812 break;
814 default:
815 break;
817 if (done)
818 break;
820 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
822 *p++ = c;
823 if (p >= r)
825 register unsigned bytes_used = (p - q);
827 buffer_length = bytes_used * 2;
828 q = (char *)xrealloc (q, buffer_length);
829 p = &q[bytes_used];
830 r = &q[buffer_length];
833 if (use_d == 1)
834 c = d;
835 else
836 c = getc (finput);
838 *p = '\0';
839 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
840 ffewhere_column_unknown ());
842 if (q != &buff[0])
843 free (q);
845 break;
847 default:
848 token = NULL;
849 break;
852 *xtoken = token;
853 return c;
855 #endif
857 #if FFECOM_targetCURRENT == FFECOM_targetGCC
858 static void
859 ffelex_file_pop_ (char *input_filename)
861 if (input_file_stack->next)
863 struct file_stack *p = input_file_stack;
864 input_file_stack = p->next;
865 free (p);
866 input_file_stack_tick++;
867 #ifdef DWARF_DEBUGGING_INFO
868 if (debug_info_level == DINFO_LEVEL_VERBOSE
869 && write_symbols == DWARF_DEBUG)
870 dwarfout_resume_previous_source_file (input_file_stack->line);
871 #endif /* DWARF_DEBUGGING_INFO */
873 else
874 error ("#-lines for entering and leaving files don't match");
876 /* Now that we've pushed or popped the input stack,
877 update the name in the top element. */
878 if (input_file_stack)
879 input_file_stack->name = input_filename;
882 #endif
883 #if FFECOM_targetCURRENT == FFECOM_targetGCC
884 static void
885 ffelex_file_push_ (int old_lineno, char *input_filename)
887 struct file_stack *p
888 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
890 input_file_stack->line = old_lineno;
891 p->next = input_file_stack;
892 p->name = input_filename;
893 input_file_stack = p;
894 input_file_stack_tick++;
895 #ifdef DWARF_DEBUGGING_INFO
896 if (debug_info_level == DINFO_LEVEL_VERBOSE
897 && write_symbols == DWARF_DEBUG)
898 dwarfout_start_new_source_file (input_filename);
899 #endif /* DWARF_DEBUGGING_INFO */
901 /* Now that we've pushed or popped the input stack,
902 update the name in the top element. */
903 if (input_file_stack)
904 input_file_stack->name = input_filename;
906 #endif
908 /* Prepare to finish a statement-in-progress by sending the current
909 token, if any, then setting up EOS as the current token with the
910 appropriate current pointer. The caller can then move the current
911 pointer before actually sending EOS, if desired, as it is in
912 typical fixed-form cases. */
914 static void
915 ffelex_prepare_eos_ ()
917 if (ffelex_token_->type != FFELEX_typeNONE)
919 ffelex_backslash_ (EOF, 0);
921 switch (ffelex_raw_mode_)
923 case -2:
924 break;
926 case -1:
927 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
928 : FFEBAD_NO_CLOSING_QUOTE);
929 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
930 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
931 ffebad_finish ();
932 break;
934 case 0:
935 break;
937 default:
939 char num[20];
941 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
942 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
943 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
944 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
945 ffebad_string (num);
946 ffebad_finish ();
947 /* Make sure the token has some text, might as well fill up with spaces. */
950 ffelex_append_to_token_ (' ');
951 } while (--ffelex_raw_mode_ > 0);
952 break;
955 ffelex_raw_mode_ = 0;
956 ffelex_send_token_ ();
958 ffelex_token_->type = FFELEX_typeEOS;
959 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
960 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
963 static void
964 ffelex_finish_statement_ ()
966 if ((ffelex_number_of_tokens_ == 0)
967 && (ffelex_token_->type == FFELEX_typeNONE))
968 return; /* Don't have a statement pending. */
970 if (ffelex_token_->type != FFELEX_typeEOS)
971 ffelex_prepare_eos_ ();
973 ffelex_permit_include_ = TRUE;
974 ffelex_send_token_ ();
975 ffelex_permit_include_ = FALSE;
976 ffelex_number_of_tokens_ = 0;
977 ffelex_label_tokens_ = 0;
978 ffelex_names_ = TRUE;
979 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
980 ffelex_hexnum_ = FALSE;
982 if (!ffe_is_ffedebug ())
983 return;
985 /* For debugging purposes only. */
987 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
989 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
990 ffelex_old_total_tokens_, ffelex_total_tokens_);
991 ffelex_old_total_tokens_ = ffelex_total_tokens_;
995 /* Copied from gcc/c-common.c get_directive_line. */
997 #if FFECOM_targetCURRENT == FFECOM_targetGCC
998 static int
999 ffelex_get_directive_line_ (char **text, FILE *finput)
1001 static char *directive_buffer = NULL;
1002 static unsigned buffer_length = 0;
1003 register char *p;
1004 register char *buffer_limit;
1005 register int looking_for = 0;
1006 register int char_escaped = 0;
1008 if (buffer_length == 0)
1010 directive_buffer = (char *)xmalloc (128);
1011 buffer_length = 128;
1014 buffer_limit = &directive_buffer[buffer_length];
1016 for (p = directive_buffer; ; )
1018 int c;
1020 /* Make buffer bigger if it is full. */
1021 if (p >= buffer_limit)
1023 register unsigned bytes_used = (p - directive_buffer);
1025 buffer_length *= 2;
1026 directive_buffer
1027 = (char *)xrealloc (directive_buffer, buffer_length);
1028 p = &directive_buffer[bytes_used];
1029 buffer_limit = &directive_buffer[buffer_length];
1032 c = getc (finput);
1034 /* Discard initial whitespace. */
1035 if ((c == ' ' || c == '\t') && p == directive_buffer)
1036 continue;
1038 /* Detect the end of the directive. */
1039 if ((c == '\n' && looking_for == 0)
1040 || c == EOF)
1042 if (looking_for != 0)
1043 fatal ("Bad directive -- missing close-quote");
1045 *p++ = '\0';
1046 *text = directive_buffer;
1047 return c;
1050 *p++ = c;
1051 if (c == '\n')
1052 ffelex_next_line_ ();
1054 /* Handle string and character constant syntax. */
1055 if (looking_for)
1057 if (looking_for == c && !char_escaped)
1058 looking_for = 0; /* Found terminator... stop looking. */
1060 else
1061 if (c == '\'' || c == '"')
1062 looking_for = c; /* Don't stop buffering until we see another
1063 one of these (or an EOF). */
1065 /* Handle backslash. */
1066 char_escaped = (c == '\\' && ! char_escaped);
1069 #endif
1071 /* Handle # directives that make it through (or are generated by) the
1072 preprocessor. As much as reasonably possible, emulate the behavior
1073 of the gcc compiler phase cc1, though interactions between #include
1074 and INCLUDE might possibly produce bizarre results in terms of
1075 error reporting and the generation of debugging info vis-a-vis the
1076 locations of some things.
1078 Returns the next character unhandled, which is always newline or EOF. */
1080 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1082 #if defined HANDLE_PRAGMA
1083 /* Local versions of these macros, that can be passed as function pointers. */
1084 static int
1085 pragma_getc ()
1087 return getc (finput);
1090 static void
1091 pragma_ungetc (arg)
1092 int arg;
1094 ungetc (arg, finput);
1096 #endif /* HANDLE_PRAGMA */
1098 static int
1099 ffelex_hash_ (FILE *finput)
1101 register int c;
1102 ffelexToken token = NULL;
1104 /* Read first nonwhite char after the `#'. */
1106 c = ffelex_getc_ (finput);
1107 while (c == ' ' || c == '\t')
1108 c = ffelex_getc_ (finput);
1110 /* If a letter follows, then if the word here is `line', skip
1111 it and ignore it; otherwise, ignore the line, with an error
1112 if the word isn't `pragma', `ident', `define', or `undef'. */
1114 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
1116 if (c == 'p')
1118 if (getc (finput) == 'r'
1119 && getc (finput) == 'a'
1120 && getc (finput) == 'g'
1121 && getc (finput) == 'm'
1122 && getc (finput) == 'a'
1123 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1124 || c == EOF))
1126 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1127 static char buffer [128];
1128 char * buff = buffer;
1130 /* Read the pragma name into a buffer.
1131 ISSPACE() may evaluate its argument more than once! */
1132 while (((c = getc (finput)), ISSPACE(c)))
1133 continue;
1137 * buff ++ = c;
1138 c = getc (finput);
1140 while (c != EOF && ! ISSPACE (c) && c != '\n'
1141 && buff < buffer + 128);
1143 pragma_ungetc (c);
1145 * -- buff = 0;
1146 #ifdef HANDLE_PRAGMA
1147 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1148 goto skipline;
1149 #endif /* HANDLE_PRAGMA */
1150 #ifdef HANDLE_GENERIC_PRAGMAS
1151 if (handle_generic_pragma (buffer))
1152 goto skipline;
1153 #endif /* !HANDLE_GENERIC_PRAGMAS */
1155 /* Issue a warning message if we have been asked to do so.
1156 Ignoring unknown pragmas in system header file unless
1157 an explcit -Wunknown-pragmas has been given. */
1158 if (warn_unknown_pragmas > 1
1159 || (warn_unknown_pragmas && ! in_system_header))
1160 warning ("ignoring pragma: %s", token_buffer);
1161 #endif /* 0 */
1162 goto skipline;
1166 else if (c == 'd')
1168 if (getc (finput) == 'e'
1169 && getc (finput) == 'f'
1170 && getc (finput) == 'i'
1171 && getc (finput) == 'n'
1172 && getc (finput) == 'e'
1173 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1174 || c == EOF))
1176 char *text;
1178 c = ffelex_get_directive_line_ (&text, finput);
1180 #ifdef DWARF_DEBUGGING_INFO
1181 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1182 && (write_symbols == DWARF_DEBUG))
1183 dwarfout_define (lineno, text);
1184 #endif /* DWARF_DEBUGGING_INFO */
1186 goto skipline;
1189 else if (c == 'u')
1191 if (getc (finput) == 'n'
1192 && getc (finput) == 'd'
1193 && getc (finput) == 'e'
1194 && getc (finput) == 'f'
1195 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1196 || c == EOF))
1198 char *text;
1200 c = ffelex_get_directive_line_ (&text, finput);
1202 #ifdef DWARF_DEBUGGING_INFO
1203 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1204 && (write_symbols == DWARF_DEBUG))
1205 dwarfout_undef (lineno, text);
1206 #endif /* DWARF_DEBUGGING_INFO */
1208 goto skipline;
1211 else if (c == 'l')
1213 if (getc (finput) == 'i'
1214 && getc (finput) == 'n'
1215 && getc (finput) == 'e'
1216 && ((c = getc (finput)) == ' ' || c == '\t'))
1217 goto linenum;
1219 else if (c == 'i')
1221 if (getc (finput) == 'd'
1222 && getc (finput) == 'e'
1223 && getc (finput) == 'n'
1224 && getc (finput) == 't'
1225 && ((c = getc (finput)) == ' ' || c == '\t'))
1227 /* #ident. The pedantic warning is now in cpp. */
1229 /* Here we have just seen `#ident '.
1230 A string constant should follow. */
1232 while (c == ' ' || c == '\t')
1233 c = getc (finput);
1235 /* If no argument, ignore the line. */
1236 if (c == '\n' || c == EOF)
1237 return c;
1239 c = ffelex_cfelex_ (&token, finput, c);
1241 if ((token == NULL)
1242 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1244 error ("invalid #ident");
1245 goto skipline;
1248 if (! flag_no_ident)
1250 #ifdef ASM_OUTPUT_IDENT
1251 ASM_OUTPUT_IDENT (asm_out_file,
1252 ffelex_token_text (token));
1253 #endif
1256 /* Skip the rest of this line. */
1257 goto skipline;
1261 error ("undefined or invalid # directive");
1262 goto skipline;
1265 linenum:
1266 /* Here we have either `#line' or `# <nonletter>'.
1267 In either case, it should be a line number; a digit should follow. */
1269 while (c == ' ' || c == '\t')
1270 c = ffelex_getc_ (finput);
1272 /* If the # is the only nonwhite char on the line,
1273 just ignore it. Check the new newline. */
1274 if (c == '\n' || c == EOF)
1275 return c;
1277 /* Something follows the #; read a token. */
1279 c = ffelex_cfelex_ (&token, finput, c);
1281 if ((token != NULL)
1282 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1284 int old_lineno = lineno;
1285 char *old_input_filename = input_filename;
1286 ffewhereFile wf;
1288 /* subtract one, because it is the following line that
1289 gets the specified number */
1290 int l = atoi (ffelex_token_text (token)) - 1;
1292 /* Is this the last nonwhite stuff on the line? */
1293 while (c == ' ' || c == '\t')
1294 c = ffelex_getc_ (finput);
1295 if (c == '\n' || c == EOF)
1297 /* No more: store the line number and check following line. */
1298 lineno = l;
1299 if (!ffelex_kludge_flag_)
1301 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1303 if (token != NULL)
1304 ffelex_token_kill (token);
1306 return c;
1309 /* More follows: it must be a string constant (filename). */
1311 /* Read the string constant. */
1312 c = ffelex_cfelex_ (&token, finput, c);
1314 if ((token == NULL)
1315 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1317 error ("invalid #line");
1318 goto skipline;
1321 lineno = l;
1323 if (ffelex_kludge_flag_)
1324 input_filename = ggc_alloc_string (ffelex_token_text (token), -1);
1325 else
1327 wf = ffewhere_file_new (ffelex_token_text (token),
1328 ffelex_token_length (token));
1329 input_filename = ffewhere_file_name (wf);
1330 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1333 #if 0 /* Not sure what g77 should do with this yet. */
1334 /* Each change of file name
1335 reinitializes whether we are now in a system header. */
1336 in_system_header = 0;
1337 #endif
1339 if (main_input_filename == 0)
1340 main_input_filename = input_filename;
1342 /* Is this the last nonwhite stuff on the line? */
1343 while (c == ' ' || c == '\t')
1344 c = getc (finput);
1345 if (c == '\n' || c == EOF)
1347 if (!ffelex_kludge_flag_)
1349 /* Update the name in the top element of input_file_stack. */
1350 if (input_file_stack)
1351 input_file_stack->name = input_filename;
1353 if (token != NULL)
1354 ffelex_token_kill (token);
1356 return c;
1359 c = ffelex_cfelex_ (&token, finput, c);
1361 /* `1' after file name means entering new file.
1362 `2' after file name means just left a file. */
1364 if ((token != NULL)
1365 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1367 int num = atoi (ffelex_token_text (token));
1369 if (ffelex_kludge_flag_)
1371 lineno = 1;
1372 input_filename = old_input_filename;
1373 fatal ("Use `#line ...' instead of `# ...' in first line");
1376 if (num == 1)
1378 /* Pushing to a new file. */
1379 ffelex_file_push_ (old_lineno, input_filename);
1381 else if (num == 2)
1383 /* Popping out of a file. */
1384 ffelex_file_pop_ (input_filename);
1387 /* Is this the last nonwhite stuff on the line? */
1388 while (c == ' ' || c == '\t')
1389 c = getc (finput);
1390 if (c == '\n' || c == EOF)
1392 if (token != NULL)
1393 ffelex_token_kill (token);
1394 return c;
1397 c = ffelex_cfelex_ (&token, finput, c);
1400 /* `3' after file name means this is a system header file. */
1402 #if 0 /* Not sure what g77 should do with this yet. */
1403 if ((token != NULL)
1404 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1405 && (atoi (ffelex_token_text (token)) == 3))
1406 in_system_header = 1;
1407 #endif
1409 while (c == ' ' || c == '\t')
1410 c = getc (finput);
1411 if (((token != NULL)
1412 || (c != '\n' && c != EOF))
1413 && ffelex_kludge_flag_)
1415 lineno = 1;
1416 input_filename = old_input_filename;
1417 fatal ("Use `#line ...' instead of `# ...' in first line");
1420 else
1421 error ("invalid #-line");
1423 /* skip the rest of this line. */
1424 skipline:
1425 if ((token != NULL) && !ffelex_kludge_flag_)
1426 ffelex_token_kill (token);
1427 while ((c = getc (finput)) != EOF && c != '\n')
1429 return c;
1431 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1433 /* "Image" a character onto the card image, return incremented column number.
1435 Normally invoking this function as in
1436 column = ffelex_image_char_ (c, column);
1437 is the same as doing:
1438 ffelex_card_image_[column++] = c;
1440 However, tabs and carriage returns are handled specially, to preserve
1441 the visual "image" of the input line (in most editors) in the card
1442 image.
1444 Carriage returns are ignored, as they are assumed to be followed
1445 by newlines.
1447 A tab is handled by first doing:
1448 ffelex_card_image_[column++] = ' ';
1449 That is, it translates to at least one space. Then, as many spaces
1450 are imaged as necessary to bring the column number to the next tab
1451 position, where tab positions start in the ninth column and each
1452 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1453 is set to TRUE to notify the lexer that a tab was seen.
1455 Columns are numbered and tab stops set as illustrated below:
1457 012345670123456701234567...
1458 x y z
1459 xx yy zz
1461 xxxxxxx yyyyyyy zzzzzzz
1462 xxxxxxxx yyyyyyyy... */
1464 static ffewhereColumnNumber
1465 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1467 ffewhereColumnNumber old_column = column;
1469 if (column >= ffelex_card_size_)
1471 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1473 if (ffelex_bad_line_)
1474 return column;
1476 if ((newmax >> 1) != ffelex_card_size_)
1477 { /* Overflowed column number. */
1478 overflow: /* :::::::::::::::::::: */
1480 ffelex_bad_line_ = TRUE;
1481 strcpy (&ffelex_card_image_[column - 3], "...");
1482 ffelex_card_length_ = column;
1483 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1484 ffelex_linecount_current_, column + 1);
1485 return column;
1488 ffelex_card_image_
1489 = malloc_resize_ksr (malloc_pool_image (),
1490 ffelex_card_image_,
1491 newmax + 9,
1492 ffelex_card_size_ + 9);
1493 ffelex_card_size_ = newmax;
1496 switch (c)
1498 case '\r':
1499 break;
1501 case '\t':
1502 ffelex_saw_tab_ = TRUE;
1503 ffelex_card_image_[column++] = ' ';
1504 while ((column & 7) != 0)
1505 ffelex_card_image_[column++] = ' ';
1506 break;
1508 case '\0':
1509 if (!ffelex_bad_line_)
1511 ffelex_bad_line_ = TRUE;
1512 strcpy (&ffelex_card_image_[column], "[\\0]");
1513 ffelex_card_length_ = column + 4;
1514 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1515 FFEBAD_severityFATAL);
1516 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1517 ffebad_finish ();
1518 column += 4;
1520 break;
1522 default:
1523 ffelex_card_image_[column++] = c;
1524 break;
1527 if (column < old_column)
1529 column = old_column;
1530 goto overflow; /* :::::::::::::::::::: */
1533 return column;
1536 static void
1537 ffelex_include_ ()
1539 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1540 FILE *include_file = ffelex_include_file_;
1541 /* The rest of this is to push, and after the INCLUDE file is processed,
1542 pop, the static lexer state info that pertains to each particular
1543 input file. */
1544 char *card_image;
1545 ffewhereColumnNumber card_size = ffelex_card_size_;
1546 ffewhereColumnNumber card_length = ffelex_card_length_;
1547 ffewhereLine current_wl = ffelex_current_wl_;
1548 ffewhereColumn current_wc = ffelex_current_wc_;
1549 bool saw_tab = ffelex_saw_tab_;
1550 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1551 ffewhereFile current_wf = ffelex_current_wf_;
1552 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1553 ffewhereLineNumber linecount_offset
1554 = ffewhere_line_filelinenum (current_wl);
1555 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1556 int old_lineno = lineno;
1557 char *old_input_filename = input_filename;
1558 #endif
1560 if (card_length != 0)
1562 card_image = malloc_new_ks (malloc_pool_image (),
1563 "FFELEX saved card image",
1564 card_length);
1565 memcpy (card_image, ffelex_card_image_, card_length);
1567 else
1568 card_image = NULL;
1570 ffelex_set_include_ = FALSE;
1572 ffelex_next_line_ ();
1574 ffewhere_file_set (include_wherefile, TRUE, 0);
1576 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1577 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1578 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1580 if (ffelex_include_free_form_)
1581 ffelex_file_free (include_wherefile, include_file);
1582 else
1583 ffelex_file_fixed (include_wherefile, include_file);
1585 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1586 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1587 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1589 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1591 ffecom_close_include (include_file);
1593 if (card_length != 0)
1595 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1596 #error "need to handle possible reduction of card size here!!"
1597 #endif
1598 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1599 memcpy (ffelex_card_image_, card_image, card_length);
1601 ffelex_card_image_[card_length] = '\0';
1603 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1604 input_filename = old_input_filename;
1605 lineno = old_lineno;
1606 #endif
1607 ffelex_linecount_current_ = linecount_current;
1608 ffelex_current_wf_ = current_wf;
1609 ffelex_final_nontab_column_ = final_nontab_column;
1610 ffelex_saw_tab_ = saw_tab;
1611 ffelex_current_wc_ = current_wc;
1612 ffelex_current_wl_ = current_wl;
1613 ffelex_card_length_ = card_length;
1614 ffelex_card_size_ = card_size;
1617 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1619 ffewhereColumnNumber col;
1620 int c; // Char at col.
1621 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1622 // We have a continuation indicator.
1624 If there are <n> spaces starting at ffelex_card_image_[col] up through
1625 the null character, where <n> is 0 or greater, returns TRUE. */
1627 static bool
1628 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1630 while (ffelex_card_image_[col] != '\0')
1632 if (ffelex_card_image_[col++] != ' ')
1633 return FALSE;
1635 return TRUE;
1638 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1640 ffewhereColumnNumber col;
1641 int c; // Char at col.
1642 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1643 // We have a continuation indicator.
1645 If there are <n> spaces starting at ffelex_card_image_[col] up through
1646 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1648 static bool
1649 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1651 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1653 if (ffelex_card_image_[col++] != ' ')
1654 return FALSE;
1656 return TRUE;
1659 static void
1660 ffelex_next_line_ ()
1662 ffelex_linecount_current_ = ffelex_linecount_next_;
1663 ++ffelex_linecount_next_;
1664 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1665 ++lineno;
1666 #endif
1669 static void
1670 ffelex_send_token_ ()
1672 ++ffelex_number_of_tokens_;
1674 ffelex_backslash_ (EOF, 0);
1676 if (ffelex_token_->text == NULL)
1678 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1680 ffelex_append_to_token_ ('\0');
1681 ffelex_token_->length = 0;
1684 else
1685 ffelex_token_->text[ffelex_token_->length] = '\0';
1687 assert (ffelex_raw_mode_ == 0);
1689 if (ffelex_token_->type == FFELEX_typeNAMES)
1691 ffewhere_line_kill (ffelex_token_->currentnames_line);
1692 ffewhere_column_kill (ffelex_token_->currentnames_col);
1695 assert (ffelex_handler_ != NULL);
1696 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1697 assert (ffelex_handler_ != NULL);
1699 ffelex_token_kill (ffelex_token_);
1701 ffelex_token_ = ffelex_token_new_ ();
1702 ffelex_token_->uses = 1;
1703 ffelex_token_->text = NULL;
1704 if (ffelex_raw_mode_ < 0)
1706 ffelex_token_->type = FFELEX_typeCHARACTER;
1707 ffelex_token_->where_line = ffelex_raw_where_line_;
1708 ffelex_token_->where_col = ffelex_raw_where_col_;
1709 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1710 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1712 else
1714 ffelex_token_->type = FFELEX_typeNONE;
1715 ffelex_token_->where_line = ffewhere_line_unknown ();
1716 ffelex_token_->where_col = ffewhere_column_unknown ();
1719 if (ffelex_set_include_)
1720 ffelex_include_ ();
1723 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1725 return ffelex_swallow_tokens_;
1727 Return this handler when you don't want to look at any more tokens in the
1728 statement because you've encountered an unrecoverable error in the
1729 statement. */
1731 static ffelexHandler
1732 ffelex_swallow_tokens_ (ffelexToken t)
1734 assert (ffelex_eos_handler_ != NULL);
1736 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1737 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1738 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1740 return (ffelexHandler) ffelex_swallow_tokens_;
1743 static ffelexToken
1744 ffelex_token_new_ ()
1746 ffelexToken t;
1748 ++ffelex_total_tokens_;
1750 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1751 "FFELEX token", sizeof (*t));
1752 t->id_ = ffelex_token_nextid_++;
1753 return t;
1756 static const char *
1757 ffelex_type_string_ (ffelexType type)
1759 static const char *types[] = {
1760 "FFELEX_typeNONE",
1761 "FFELEX_typeCOMMENT",
1762 "FFELEX_typeEOS",
1763 "FFELEX_typeEOF",
1764 "FFELEX_typeERROR",
1765 "FFELEX_typeRAW",
1766 "FFELEX_typeQUOTE",
1767 "FFELEX_typeDOLLAR",
1768 "FFELEX_typeHASH",
1769 "FFELEX_typePERCENT",
1770 "FFELEX_typeAMPERSAND",
1771 "FFELEX_typeAPOSTROPHE",
1772 "FFELEX_typeOPEN_PAREN",
1773 "FFELEX_typeCLOSE_PAREN",
1774 "FFELEX_typeASTERISK",
1775 "FFELEX_typePLUS",
1776 "FFELEX_typeMINUS",
1777 "FFELEX_typePERIOD",
1778 "FFELEX_typeSLASH",
1779 "FFELEX_typeNUMBER",
1780 "FFELEX_typeOPEN_ANGLE",
1781 "FFELEX_typeEQUALS",
1782 "FFELEX_typeCLOSE_ANGLE",
1783 "FFELEX_typeNAME",
1784 "FFELEX_typeCOMMA",
1785 "FFELEX_typePOWER",
1786 "FFELEX_typeCONCAT",
1787 "FFELEX_typeDEBUG",
1788 "FFELEX_typeNAMES",
1789 "FFELEX_typeHOLLERITH",
1790 "FFELEX_typeCHARACTER",
1791 "FFELEX_typeCOLON",
1792 "FFELEX_typeSEMICOLON",
1793 "FFELEX_typeUNDERSCORE",
1794 "FFELEX_typeQUESTION",
1795 "FFELEX_typeOPEN_ARRAY",
1796 "FFELEX_typeCLOSE_ARRAY",
1797 "FFELEX_typeCOLONCOLON",
1798 "FFELEX_typeREL_LE",
1799 "FFELEX_typeREL_NE",
1800 "FFELEX_typeREL_EQ",
1801 "FFELEX_typePOINTS",
1802 "FFELEX_typeREL_GE"
1805 if (type >= ARRAY_SIZE (types))
1806 return "???";
1807 return types[type];
1810 void
1811 ffelex_display_token (ffelexToken t)
1813 if (t == NULL)
1814 t = ffelex_token_;
1816 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1817 ffewhereColumnNumber_f "u)",
1818 t->id_,
1819 ffelex_type_string_ (t->type),
1820 ffewhere_line_number (t->where_line),
1821 ffewhere_column_number (t->where_col));
1823 if (t->text != NULL)
1824 fprintf (dmpout, ": \"%.*s\"\n",
1825 (int) t->length,
1826 t->text);
1827 else
1828 fprintf (dmpout, ".\n");
1831 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1833 if (ffelex_expecting_character())
1834 // next token delivered by lexer will be CHARACTER.
1836 If the most recent call to ffelex_set_expecting_hollerith since the last
1837 token was delivered by the lexer passed a length of -1, then we return
1838 TRUE, because the next token we deliver will be typeCHARACTER, else we
1839 return FALSE. */
1841 bool
1842 ffelex_expecting_character ()
1844 return (ffelex_raw_mode_ != 0);
1847 /* ffelex_file_fixed -- Lex a given file in fixed source form
1849 ffewhere wf;
1850 FILE *f;
1851 ffelex_file_fixed(wf,f);
1853 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1855 ffelexHandler
1856 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1858 register int c = 0; /* Character currently under consideration. */
1859 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1860 bool disallow_continuation_line;
1861 bool ignore_disallowed_continuation = FALSE;
1862 int latest_char_in_file = 0; /* For getting back into comment-skipping
1863 code. */
1864 ffelexType lextype;
1865 ffewhereColumnNumber first_label_char; /* First char of label --
1866 column number. */
1867 char label_string[6]; /* Text of label. */
1868 int labi; /* Length of label text. */
1869 bool finish_statement; /* Previous statement finished? */
1870 bool have_content; /* This line have content? */
1871 bool just_do_label; /* Nothing but label (and continuation?) on
1872 line. */
1874 /* Lex is called for a particular file, not for a particular program unit.
1875 Yet the two events do share common characteristics. The first line in a
1876 file or in a program unit cannot be a continuation line. No token can
1877 be in mid-formation. No current label for the statement exists, since
1878 there is no current statement. */
1880 assert (ffelex_handler_ != NULL);
1882 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1883 lineno = 0;
1884 input_filename = ffewhere_file_name (wf);
1885 #endif
1886 ffelex_current_wf_ = wf;
1887 disallow_continuation_line = TRUE;
1888 ignore_disallowed_continuation = FALSE;
1889 ffelex_token_->type = FFELEX_typeNONE;
1890 ffelex_number_of_tokens_ = 0;
1891 ffelex_label_tokens_ = 0;
1892 ffelex_current_wl_ = ffewhere_line_unknown ();
1893 ffelex_current_wc_ = ffewhere_column_unknown ();
1894 latest_char_in_file = '\n';
1896 if (ffe_is_null_version ())
1898 /* Just substitute a "program" directly here. */
1900 char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
1901 char *p;
1903 column = 0;
1904 for (p = &line[0]; *p != '\0'; ++p)
1905 column = ffelex_image_char_ (*p, column);
1907 c = EOF;
1909 goto have_line; /* :::::::::::::::::::: */
1912 goto first_line; /* :::::::::::::::::::: */
1914 /* Come here to get a new line. */
1916 beginning_of_line: /* :::::::::::::::::::: */
1918 disallow_continuation_line = FALSE;
1920 /* Come here directly when last line didn't clarify the continuation issue. */
1922 beginning_of_line_again: /* :::::::::::::::::::: */
1924 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1925 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1927 ffelex_card_image_
1928 = malloc_resize_ks (malloc_pool_image (),
1929 ffelex_card_image_,
1930 FFELEX_columnINITIAL_SIZE_ + 9,
1931 ffelex_card_size_ + 9);
1932 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1934 #endif
1936 first_line: /* :::::::::::::::::::: */
1938 c = latest_char_in_file;
1939 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1942 end_of_file: /* :::::::::::::::::::: */
1944 /* Line ending in EOF instead of \n still counts as a whole line. */
1946 ffelex_finish_statement_ ();
1947 ffewhere_line_kill (ffelex_current_wl_);
1948 ffewhere_column_kill (ffelex_current_wc_);
1949 return (ffelexHandler) ffelex_handler_;
1952 ffelex_next_line_ ();
1954 ffelex_bad_line_ = FALSE;
1956 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1958 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1959 || (lextype == FFELEX_typeERROR)
1960 || (lextype == FFELEX_typeSLASH)
1961 || (lextype == FFELEX_typeHASH))
1963 /* Test most frequent type of line first, etc. */
1964 if ((lextype == FFELEX_typeCOMMENT)
1965 || ((lextype == FFELEX_typeSLASH)
1966 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1968 /* Typical case (straight comment), just ignore rest of line. */
1969 comment_line: /* :::::::::::::::::::: */
1971 while ((c != '\n') && (c != EOF))
1972 c = getc (f);
1974 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1975 else if (lextype == FFELEX_typeHASH)
1976 c = ffelex_hash_ (f);
1977 #endif
1978 else if (lextype == FFELEX_typeSLASH)
1980 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1981 ffelex_card_image_[0] = '/';
1982 ffelex_card_image_[1] = c;
1983 column = 2;
1984 goto bad_first_character; /* :::::::::::::::::::: */
1986 else
1987 /* typeERROR or unsupported typeHASH. */
1988 { /* Bad first character, get line and display
1989 it with message. */
1990 column = ffelex_image_char_ (c, 0);
1992 bad_first_character: /* :::::::::::::::::::: */
1994 ffelex_bad_line_ = TRUE;
1995 while (((c = getc (f)) != '\n') && (c != EOF))
1996 column = ffelex_image_char_ (c, column);
1997 ffelex_card_image_[column] = '\0';
1998 ffelex_card_length_ = column;
1999 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
2000 ffelex_linecount_current_, 1);
2003 /* Read past last char in line. */
2005 if (c == EOF)
2007 ffelex_next_line_ ();
2008 goto end_of_file; /* :::::::::::::::::::: */
2011 c = getc (f);
2013 ffelex_next_line_ ();
2015 if (c == EOF)
2016 goto end_of_file; /* :::::::::::::::::::: */
2018 ffelex_bad_line_ = FALSE;
2019 } /* while [c, first char, means comment] */
2021 ffelex_saw_tab_
2022 = (c == '&')
2023 || (ffelex_final_nontab_column_ == 0);
2025 if (lextype == FFELEX_typeDEBUG)
2026 c = ' '; /* A 'D' or 'd' in column 1 with the
2027 debug-lines option on. */
2029 column = ffelex_image_char_ (c, 0);
2031 /* Read the entire line in as is (with whitespace processing). */
2033 while (((c = getc (f)) != '\n') && (c != EOF))
2034 column = ffelex_image_char_ (c, column);
2036 if (ffelex_bad_line_)
2038 ffelex_card_image_[column] = '\0';
2039 ffelex_card_length_ = column;
2040 goto comment_line; /* :::::::::::::::::::: */
2043 /* If no tab, cut off line after column 72/132. */
2045 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
2047 /* Technically, we should now fill ffelex_card_image_ up thru column
2048 72/132 with spaces, since character/hollerith constants must count
2049 them in that manner. To save CPU time in several ways (avoid a loop
2050 here that would be used only when we actually end a line in
2051 character-constant mode; avoid writing memory unnecessarily; avoid a
2052 loop later checking spaces when not scanning for character-constant
2053 characters), we don't do this, and we do the appropriate thing when
2054 we encounter end-of-line while actually processing a character
2055 constant. */
2057 column = ffelex_final_nontab_column_;
2060 have_line: /* :::::::::::::::::::: */
2062 ffelex_card_image_[column] = '\0';
2063 ffelex_card_length_ = column;
2065 /* Save next char in file so we can use register-based c while analyzing
2066 line we just read. */
2068 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2070 have_content = FALSE;
2072 /* Handle label, if any. */
2074 labi = 0;
2075 first_label_char = FFEWHERE_columnUNKNOWN;
2076 for (column = 0; column < 5; ++column)
2078 switch (c = ffelex_card_image_[column])
2080 case '\0':
2081 case '!':
2082 goto stop_looking; /* :::::::::::::::::::: */
2084 case ' ':
2085 break;
2087 case '0':
2088 case '1':
2089 case '2':
2090 case '3':
2091 case '4':
2092 case '5':
2093 case '6':
2094 case '7':
2095 case '8':
2096 case '9':
2097 label_string[labi++] = c;
2098 if (first_label_char == FFEWHERE_columnUNKNOWN)
2099 first_label_char = column + 1;
2100 break;
2102 case '&':
2103 if (column != 0)
2105 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2106 ffelex_linecount_current_,
2107 column + 1);
2108 goto beginning_of_line_again; /* :::::::::::::::::::: */
2110 if (ffe_is_pedantic ())
2111 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2112 ffelex_linecount_current_, 1);
2113 finish_statement = FALSE;
2114 just_do_label = FALSE;
2115 goto got_a_continuation; /* :::::::::::::::::::: */
2117 case '/':
2118 if (ffelex_card_image_[column + 1] == '*')
2119 goto stop_looking; /* :::::::::::::::::::: */
2120 /* Fall through. */
2121 default:
2122 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2123 ffelex_linecount_current_, column + 1);
2124 goto beginning_of_line_again; /* :::::::::::::::::::: */
2128 stop_looking: /* :::::::::::::::::::: */
2130 label_string[labi] = '\0';
2132 /* Find first nonblank char starting with continuation column. */
2134 if (column == 5) /* In which case we didn't see end of line in
2135 label field. */
2136 while ((c = ffelex_card_image_[column]) == ' ')
2137 ++column;
2139 /* Now we're trying to figure out whether this is a continuation line and
2140 whether there's anything else of substance on the line. The cases are
2141 as follows:
2143 1. If a line has an explicit continuation character (other than the digit
2144 zero), then if it also has a label, the label is ignored and an error
2145 message is printed. Any remaining text on the line is passed to the
2146 parser tasks, thus even an all-blank line (possibly with an ignored
2147 label) aside from a positive continuation character might have meaning
2148 in the midst of a character or hollerith constant.
2150 2. If a line has no explicit continuation character (that is, it has a
2151 space in column 6 and the first non-space character past column 6 is
2152 not a digit 0-9), then there are two possibilities:
2154 A. A label is present and/or a non-space (and non-comment) character
2155 appears somewhere after column 6. Terminate processing of the previous
2156 statement, if any, send the new label for the next statement, if any,
2157 and start processing a new statement with this non-blank character, if
2158 any.
2160 B. The line is essentially blank, except for a possible comment character.
2161 Don't terminate processing of the previous statement and don't pass any
2162 characters to the parser tasks, since the line is not flagged as a
2163 continuation line. We treat it just like a completely blank line.
2165 3. If a line has a continuation character of zero (0), then we terminate
2166 processing of the previous statement, if any, send the new label for the
2167 next statement, if any, and start processing a new statement, if any
2168 non-blank characters are present.
2170 If, when checking to see if we should terminate the previous statement, it
2171 is found that there is no previous statement but that there is an
2172 outstanding label, substitute CONTINUE as the statement for the label
2173 and display an error message. */
2175 finish_statement = FALSE;
2176 just_do_label = FALSE;
2178 switch (c)
2180 case '!': /* ANSI Fortran 90 says ! in column 6 is
2181 continuation. */
2182 /* VXT Fortran says ! anywhere is comment, even column 6. */
2183 if (ffe_is_vxt () || (column != 5))
2184 goto no_tokens_on_line; /* :::::::::::::::::::: */
2185 goto got_a_continuation; /* :::::::::::::::::::: */
2187 case '/':
2188 if (ffelex_card_image_[column + 1] != '*')
2189 goto some_other_character; /* :::::::::::::::::::: */
2190 /* Fall through. */
2191 if (column == 5)
2193 /* This seems right to do. But it is close to call, since / * starting
2194 in column 6 will thus be interpreted as a continuation line
2195 beginning with '*'. */
2197 goto got_a_continuation;/* :::::::::::::::::::: */
2199 /* Fall through. */
2200 case '\0':
2201 /* End of line. Therefore may be continued-through line, so handle
2202 pending label as possible to-be-continued and drive end-of-statement
2203 for any previous statement, else treat as blank line. */
2205 no_tokens_on_line: /* :::::::::::::::::::: */
2207 if (ffe_is_pedantic () && (c == '/'))
2208 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2209 ffelex_linecount_current_, column + 1);
2210 if (first_label_char != FFEWHERE_columnUNKNOWN)
2211 { /* Can't be a continued-through line if it
2212 has a label. */
2213 finish_statement = TRUE;
2214 have_content = TRUE;
2215 just_do_label = TRUE;
2216 break;
2218 goto beginning_of_line_again; /* :::::::::::::::::::: */
2220 case '0':
2221 if (ffe_is_pedantic () && (column != 5))
2222 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2223 ffelex_linecount_current_, column + 1);
2224 finish_statement = TRUE;
2225 goto check_for_content; /* :::::::::::::::::::: */
2227 case '1':
2228 case '2':
2229 case '3':
2230 case '4':
2231 case '5':
2232 case '6':
2233 case '7':
2234 case '8':
2235 case '9':
2237 /* NOTE: This label can be reached directly from the code
2238 that lexes the label field in columns 1-5. */
2239 got_a_continuation: /* :::::::::::::::::::: */
2241 if (first_label_char != FFEWHERE_columnUNKNOWN)
2243 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2244 ffelex_linecount_current_,
2245 first_label_char,
2246 ffelex_linecount_current_,
2247 column + 1);
2248 first_label_char = FFEWHERE_columnUNKNOWN;
2250 if (disallow_continuation_line)
2252 if (!ignore_disallowed_continuation)
2253 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2254 ffelex_linecount_current_, column + 1);
2255 goto beginning_of_line_again; /* :::::::::::::::::::: */
2257 if (ffe_is_pedantic () && (column != 5))
2258 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2259 ffelex_linecount_current_, column + 1);
2260 if ((ffelex_raw_mode_ != 0)
2261 && (((c = ffelex_card_image_[column + 1]) != '\0')
2262 || !ffelex_saw_tab_))
2264 ++column;
2265 have_content = TRUE;
2266 break;
2269 check_for_content: /* :::::::::::::::::::: */
2271 while ((c = ffelex_card_image_[++column]) == ' ')
2273 if ((c == '\0')
2274 || (c == '!')
2275 || ((c == '/')
2276 && (ffelex_card_image_[column + 1] == '*')))
2278 if (ffe_is_pedantic () && (c == '/'))
2279 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2280 ffelex_linecount_current_, column + 1);
2281 just_do_label = TRUE;
2283 else
2284 have_content = TRUE;
2285 break;
2287 default:
2289 some_other_character: /* :::::::::::::::::::: */
2291 if (column == 5)
2292 goto got_a_continuation;/* :::::::::::::::::::: */
2294 /* Here is the very normal case of a regular character starting in
2295 column 7 or beyond with a blank in column 6. */
2297 finish_statement = TRUE;
2298 have_content = TRUE;
2299 break;
2302 if (have_content
2303 || (first_label_char != FFEWHERE_columnUNKNOWN))
2305 /* The line has content of some kind, install new end-statement
2306 point for error messages. Note that "content" includes cases
2307 where there's little apparent content but enough to finish
2308 a statement. That's because finishing a statement can trigger
2309 an impending INCLUDE, and that requires accurate line info being
2310 maintained by the lexer. */
2312 if (finish_statement)
2313 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2315 ffewhere_line_kill (ffelex_current_wl_);
2316 ffewhere_column_kill (ffelex_current_wc_);
2317 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2318 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2321 /* We delay this for a combination of reasons. Mainly, it can start
2322 INCLUDE processing, and we want to delay that until the lexer's
2323 info on the line is coherent. And we want to delay that until we're
2324 sure there's a reason to make that info coherent, to avoid saving
2325 lots of useless lines. */
2327 if (finish_statement)
2328 ffelex_finish_statement_ ();
2330 /* If label is present, enclose it in a NUMBER token and send it along. */
2332 if (first_label_char != FFEWHERE_columnUNKNOWN)
2334 assert (ffelex_token_->type == FFELEX_typeNONE);
2335 ffelex_token_->type = FFELEX_typeNUMBER;
2336 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2337 strcpy (ffelex_token_->text, label_string);
2338 ffelex_token_->where_line
2339 = ffewhere_line_use (ffelex_current_wl_);
2340 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2341 ffelex_token_->length = labi;
2342 ffelex_send_token_ ();
2343 ++ffelex_label_tokens_;
2346 if (just_do_label)
2347 goto beginning_of_line; /* :::::::::::::::::::: */
2349 /* Here is the main engine for parsing. c holds the character at column.
2350 It is already known that c is not a blank, end of line, or shriek,
2351 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2352 character/hollerith constant). A partially filled token may already
2353 exist in ffelex_token_. One special case: if, when the end of the line
2354 is reached, continuation_line is FALSE and the only token on the line is
2355 END, then it is indeed the last statement. We don't look for
2356 continuation lines during this program unit in that case. This is
2357 according to ANSI. */
2359 if (ffelex_raw_mode_ != 0)
2362 parse_raw_character: /* :::::::::::::::::::: */
2364 if (c == '\0')
2366 ffewhereColumnNumber i;
2368 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2369 goto beginning_of_line; /* :::::::::::::::::::: */
2371 /* Pad out line with "virtual" spaces. */
2373 for (i = column; i < ffelex_final_nontab_column_; ++i)
2374 ffelex_card_image_[i] = ' ';
2375 ffelex_card_image_[i] = '\0';
2376 ffelex_card_length_ = i;
2377 c = ' ';
2380 switch (ffelex_raw_mode_)
2382 case -3:
2383 c = ffelex_backslash_ (c, column);
2384 if (c == EOF)
2385 break;
2387 if (!ffelex_backslash_reconsider_)
2388 ffelex_append_to_token_ (c);
2389 ffelex_raw_mode_ = -1;
2390 break;
2392 case -2:
2393 if (c == ffelex_raw_char_)
2395 ffelex_raw_mode_ = -1;
2396 ffelex_append_to_token_ (c);
2398 else
2400 ffelex_raw_mode_ = 0;
2401 ffelex_backslash_reconsider_ = TRUE;
2403 break;
2405 case -1:
2406 if (c == ffelex_raw_char_)
2407 ffelex_raw_mode_ = -2;
2408 else
2410 c = ffelex_backslash_ (c, column);
2411 if (c == EOF)
2413 ffelex_raw_mode_ = -3;
2414 break;
2417 ffelex_append_to_token_ (c);
2419 break;
2421 default:
2422 c = ffelex_backslash_ (c, column);
2423 if (c == EOF)
2424 break;
2426 if (!ffelex_backslash_reconsider_)
2428 ffelex_append_to_token_ (c);
2429 --ffelex_raw_mode_;
2431 break;
2434 if (ffelex_backslash_reconsider_)
2435 ffelex_backslash_reconsider_ = FALSE;
2436 else
2437 c = ffelex_card_image_[++column];
2439 if (ffelex_raw_mode_ == 0)
2441 ffelex_send_token_ ();
2442 assert (ffelex_raw_mode_ == 0);
2443 while (c == ' ')
2444 c = ffelex_card_image_[++column];
2445 if ((c == '\0')
2446 || (c == '!')
2447 || ((c == '/')
2448 && (ffelex_card_image_[column + 1] == '*')))
2449 goto beginning_of_line; /* :::::::::::::::::::: */
2450 goto parse_nonraw_character; /* :::::::::::::::::::: */
2452 goto parse_raw_character; /* :::::::::::::::::::: */
2455 parse_nonraw_character: /* :::::::::::::::::::: */
2457 switch (ffelex_token_->type)
2459 case FFELEX_typeNONE:
2460 switch (c)
2462 case '\"':
2463 ffelex_token_->type = FFELEX_typeQUOTE;
2464 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2465 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2466 ffelex_send_token_ ();
2467 break;
2469 case '$':
2470 ffelex_token_->type = FFELEX_typeDOLLAR;
2471 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2472 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2473 ffelex_send_token_ ();
2474 break;
2476 case '%':
2477 ffelex_token_->type = FFELEX_typePERCENT;
2478 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2479 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2480 ffelex_send_token_ ();
2481 break;
2483 case '&':
2484 ffelex_token_->type = FFELEX_typeAMPERSAND;
2485 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2486 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2487 ffelex_send_token_ ();
2488 break;
2490 case '\'':
2491 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2492 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2493 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2494 ffelex_send_token_ ();
2495 break;
2497 case '(':
2498 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2499 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2500 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2501 break;
2503 case ')':
2504 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2505 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2506 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2507 ffelex_send_token_ ();
2508 break;
2510 case '*':
2511 ffelex_token_->type = FFELEX_typeASTERISK;
2512 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2513 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2514 break;
2516 case '+':
2517 ffelex_token_->type = FFELEX_typePLUS;
2518 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2519 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2520 ffelex_send_token_ ();
2521 break;
2523 case ',':
2524 ffelex_token_->type = FFELEX_typeCOMMA;
2525 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2526 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2527 ffelex_send_token_ ();
2528 break;
2530 case '-':
2531 ffelex_token_->type = FFELEX_typeMINUS;
2532 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2533 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2534 ffelex_send_token_ ();
2535 break;
2537 case '.':
2538 ffelex_token_->type = FFELEX_typePERIOD;
2539 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2540 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2541 ffelex_send_token_ ();
2542 break;
2544 case '/':
2545 ffelex_token_->type = FFELEX_typeSLASH;
2546 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2547 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2548 break;
2550 case '0':
2551 case '1':
2552 case '2':
2553 case '3':
2554 case '4':
2555 case '5':
2556 case '6':
2557 case '7':
2558 case '8':
2559 case '9':
2560 ffelex_token_->type
2561 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2562 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2563 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2564 ffelex_append_to_token_ (c);
2565 break;
2567 case ':':
2568 ffelex_token_->type = FFELEX_typeCOLON;
2569 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2570 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2571 break;
2573 case ';':
2574 ffelex_token_->type = FFELEX_typeSEMICOLON;
2575 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2576 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2577 ffelex_permit_include_ = TRUE;
2578 ffelex_send_token_ ();
2579 ffelex_permit_include_ = FALSE;
2580 break;
2582 case '<':
2583 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2584 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2585 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2586 break;
2588 case '=':
2589 ffelex_token_->type = FFELEX_typeEQUALS;
2590 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2591 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2592 break;
2594 case '>':
2595 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2596 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2597 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2598 break;
2600 case '?':
2601 ffelex_token_->type = FFELEX_typeQUESTION;
2602 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2603 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2604 ffelex_send_token_ ();
2605 break;
2607 case '_':
2608 if (1 || ffe_is_90 ())
2610 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2611 ffelex_token_->where_line
2612 = ffewhere_line_use (ffelex_current_wl_);
2613 ffelex_token_->where_col
2614 = ffewhere_column_new (column + 1);
2615 ffelex_send_token_ ();
2616 break;
2618 /* Fall through. */
2619 case 'A':
2620 case 'B':
2621 case 'C':
2622 case 'D':
2623 case 'E':
2624 case 'F':
2625 case 'G':
2626 case 'H':
2627 case 'I':
2628 case 'J':
2629 case 'K':
2630 case 'L':
2631 case 'M':
2632 case 'N':
2633 case 'O':
2634 case 'P':
2635 case 'Q':
2636 case 'R':
2637 case 'S':
2638 case 'T':
2639 case 'U':
2640 case 'V':
2641 case 'W':
2642 case 'X':
2643 case 'Y':
2644 case 'Z':
2645 case 'a':
2646 case 'b':
2647 case 'c':
2648 case 'd':
2649 case 'e':
2650 case 'f':
2651 case 'g':
2652 case 'h':
2653 case 'i':
2654 case 'j':
2655 case 'k':
2656 case 'l':
2657 case 'm':
2658 case 'n':
2659 case 'o':
2660 case 'p':
2661 case 'q':
2662 case 'r':
2663 case 's':
2664 case 't':
2665 case 'u':
2666 case 'v':
2667 case 'w':
2668 case 'x':
2669 case 'y':
2670 case 'z':
2671 c = ffesrc_char_source (c);
2673 if (ffesrc_char_match_init (c, 'H', 'h')
2674 && ffelex_expecting_hollerith_ != 0)
2676 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2677 ffelex_token_->type = FFELEX_typeHOLLERITH;
2678 ffelex_token_->where_line = ffelex_raw_where_line_;
2679 ffelex_token_->where_col = ffelex_raw_where_col_;
2680 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2681 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2682 c = ffelex_card_image_[++column];
2683 goto parse_raw_character; /* :::::::::::::::::::: */
2686 if (ffelex_names_)
2688 ffelex_token_->where_line
2689 = ffewhere_line_use (ffelex_token_->currentnames_line
2690 = ffewhere_line_use (ffelex_current_wl_));
2691 ffelex_token_->where_col
2692 = ffewhere_column_use (ffelex_token_->currentnames_col
2693 = ffewhere_column_new (column + 1));
2694 ffelex_token_->type = FFELEX_typeNAMES;
2696 else
2698 ffelex_token_->where_line
2699 = ffewhere_line_use (ffelex_current_wl_);
2700 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2701 ffelex_token_->type = FFELEX_typeNAME;
2703 ffelex_append_to_token_ (c);
2704 break;
2706 default:
2707 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2708 ffelex_linecount_current_, column + 1);
2709 ffelex_finish_statement_ ();
2710 disallow_continuation_line = TRUE;
2711 ignore_disallowed_continuation = TRUE;
2712 goto beginning_of_line_again; /* :::::::::::::::::::: */
2714 break;
2716 case FFELEX_typeNAME:
2717 switch (c)
2719 case 'A':
2720 case 'B':
2721 case 'C':
2722 case 'D':
2723 case 'E':
2724 case 'F':
2725 case 'G':
2726 case 'H':
2727 case 'I':
2728 case 'J':
2729 case 'K':
2730 case 'L':
2731 case 'M':
2732 case 'N':
2733 case 'O':
2734 case 'P':
2735 case 'Q':
2736 case 'R':
2737 case 'S':
2738 case 'T':
2739 case 'U':
2740 case 'V':
2741 case 'W':
2742 case 'X':
2743 case 'Y':
2744 case 'Z':
2745 case 'a':
2746 case 'b':
2747 case 'c':
2748 case 'd':
2749 case 'e':
2750 case 'f':
2751 case 'g':
2752 case 'h':
2753 case 'i':
2754 case 'j':
2755 case 'k':
2756 case 'l':
2757 case 'm':
2758 case 'n':
2759 case 'o':
2760 case 'p':
2761 case 'q':
2762 case 'r':
2763 case 's':
2764 case 't':
2765 case 'u':
2766 case 'v':
2767 case 'w':
2768 case 'x':
2769 case 'y':
2770 case 'z':
2771 c = ffesrc_char_source (c);
2772 /* Fall through. */
2773 case '0':
2774 case '1':
2775 case '2':
2776 case '3':
2777 case '4':
2778 case '5':
2779 case '6':
2780 case '7':
2781 case '8':
2782 case '9':
2783 case '_':
2784 case '$':
2785 if ((c == '$')
2786 && !ffe_is_dollar_ok ())
2788 ffelex_send_token_ ();
2789 goto parse_next_character; /* :::::::::::::::::::: */
2791 ffelex_append_to_token_ (c);
2792 break;
2794 default:
2795 ffelex_send_token_ ();
2796 goto parse_next_character; /* :::::::::::::::::::: */
2798 break;
2800 case FFELEX_typeNAMES:
2801 switch (c)
2803 case 'A':
2804 case 'B':
2805 case 'C':
2806 case 'D':
2807 case 'E':
2808 case 'F':
2809 case 'G':
2810 case 'H':
2811 case 'I':
2812 case 'J':
2813 case 'K':
2814 case 'L':
2815 case 'M':
2816 case 'N':
2817 case 'O':
2818 case 'P':
2819 case 'Q':
2820 case 'R':
2821 case 'S':
2822 case 'T':
2823 case 'U':
2824 case 'V':
2825 case 'W':
2826 case 'X':
2827 case 'Y':
2828 case 'Z':
2829 case 'a':
2830 case 'b':
2831 case 'c':
2832 case 'd':
2833 case 'e':
2834 case 'f':
2835 case 'g':
2836 case 'h':
2837 case 'i':
2838 case 'j':
2839 case 'k':
2840 case 'l':
2841 case 'm':
2842 case 'n':
2843 case 'o':
2844 case 'p':
2845 case 'q':
2846 case 'r':
2847 case 's':
2848 case 't':
2849 case 'u':
2850 case 'v':
2851 case 'w':
2852 case 'x':
2853 case 'y':
2854 case 'z':
2855 c = ffesrc_char_source (c);
2856 /* Fall through. */
2857 case '0':
2858 case '1':
2859 case '2':
2860 case '3':
2861 case '4':
2862 case '5':
2863 case '6':
2864 case '7':
2865 case '8':
2866 case '9':
2867 case '_':
2868 case '$':
2869 if ((c == '$')
2870 && !ffe_is_dollar_ok ())
2872 ffelex_send_token_ ();
2873 goto parse_next_character; /* :::::::::::::::::::: */
2875 if (ffelex_token_->length < FFEWHERE_indexMAX)
2877 ffewhere_track (&ffelex_token_->currentnames_line,
2878 &ffelex_token_->currentnames_col,
2879 ffelex_token_->wheretrack,
2880 ffelex_token_->length,
2881 ffelex_linecount_current_,
2882 column + 1);
2884 ffelex_append_to_token_ (c);
2885 break;
2887 default:
2888 ffelex_send_token_ ();
2889 goto parse_next_character; /* :::::::::::::::::::: */
2891 break;
2893 case FFELEX_typeNUMBER:
2894 switch (c)
2896 case '0':
2897 case '1':
2898 case '2':
2899 case '3':
2900 case '4':
2901 case '5':
2902 case '6':
2903 case '7':
2904 case '8':
2905 case '9':
2906 ffelex_append_to_token_ (c);
2907 break;
2909 default:
2910 ffelex_send_token_ ();
2911 goto parse_next_character; /* :::::::::::::::::::: */
2913 break;
2915 case FFELEX_typeASTERISK:
2916 switch (c)
2918 case '*': /* ** */
2919 ffelex_token_->type = FFELEX_typePOWER;
2920 ffelex_send_token_ ();
2921 break;
2923 default: /* * not followed by another *. */
2924 ffelex_send_token_ ();
2925 goto parse_next_character; /* :::::::::::::::::::: */
2927 break;
2929 case FFELEX_typeCOLON:
2930 switch (c)
2932 case ':': /* :: */
2933 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2934 ffelex_send_token_ ();
2935 break;
2937 default: /* : not followed by another :. */
2938 ffelex_send_token_ ();
2939 goto parse_next_character; /* :::::::::::::::::::: */
2941 break;
2943 case FFELEX_typeSLASH:
2944 switch (c)
2946 case '/': /* // */
2947 ffelex_token_->type = FFELEX_typeCONCAT;
2948 ffelex_send_token_ ();
2949 break;
2951 case ')': /* /) */
2952 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2953 ffelex_send_token_ ();
2954 break;
2956 case '=': /* /= */
2957 ffelex_token_->type = FFELEX_typeREL_NE;
2958 ffelex_send_token_ ();
2959 break;
2961 default:
2962 ffelex_send_token_ ();
2963 goto parse_next_character; /* :::::::::::::::::::: */
2965 break;
2967 case FFELEX_typeOPEN_PAREN:
2968 switch (c)
2970 case '/': /* (/ */
2971 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2972 ffelex_send_token_ ();
2973 break;
2975 default:
2976 ffelex_send_token_ ();
2977 goto parse_next_character; /* :::::::::::::::::::: */
2979 break;
2981 case FFELEX_typeOPEN_ANGLE:
2982 switch (c)
2984 case '=': /* <= */
2985 ffelex_token_->type = FFELEX_typeREL_LE;
2986 ffelex_send_token_ ();
2987 break;
2989 default:
2990 ffelex_send_token_ ();
2991 goto parse_next_character; /* :::::::::::::::::::: */
2993 break;
2995 case FFELEX_typeEQUALS:
2996 switch (c)
2998 case '=': /* == */
2999 ffelex_token_->type = FFELEX_typeREL_EQ;
3000 ffelex_send_token_ ();
3001 break;
3003 case '>': /* => */
3004 ffelex_token_->type = FFELEX_typePOINTS;
3005 ffelex_send_token_ ();
3006 break;
3008 default:
3009 ffelex_send_token_ ();
3010 goto parse_next_character; /* :::::::::::::::::::: */
3012 break;
3014 case FFELEX_typeCLOSE_ANGLE:
3015 switch (c)
3017 case '=': /* >= */
3018 ffelex_token_->type = FFELEX_typeREL_GE;
3019 ffelex_send_token_ ();
3020 break;
3022 default:
3023 ffelex_send_token_ ();
3024 goto parse_next_character; /* :::::::::::::::::::: */
3026 break;
3028 default:
3029 assert ("Serious error!!" == NULL);
3030 abort ();
3031 break;
3034 c = ffelex_card_image_[++column];
3036 parse_next_character: /* :::::::::::::::::::: */
3038 if (ffelex_raw_mode_ != 0)
3039 goto parse_raw_character; /* :::::::::::::::::::: */
3041 while (c == ' ')
3042 c = ffelex_card_image_[++column];
3044 if ((c == '\0')
3045 || (c == '!')
3046 || ((c == '/')
3047 && (ffelex_card_image_[column + 1] == '*')))
3049 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
3050 && (ffelex_token_->type == FFELEX_typeNAMES)
3051 && (ffelex_token_->length == 3)
3052 && (ffesrc_strncmp_2c (ffe_case_match (),
3053 ffelex_token_->text,
3054 "END", "end", "End",
3056 == 0))
3058 ffelex_finish_statement_ ();
3059 disallow_continuation_line = TRUE;
3060 ignore_disallowed_continuation = FALSE;
3061 goto beginning_of_line_again; /* :::::::::::::::::::: */
3063 goto beginning_of_line; /* :::::::::::::::::::: */
3065 goto parse_nonraw_character; /* :::::::::::::::::::: */
3068 /* ffelex_file_free -- Lex a given file in free source form
3070 ffewhere wf;
3071 FILE *f;
3072 ffelex_file_free(wf,f);
3074 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3076 ffelexHandler
3077 ffelex_file_free (ffewhereFile wf, FILE *f)
3079 register int c = 0; /* Character currently under consideration. */
3080 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3081 bool continuation_line = FALSE;
3082 ffewhereColumnNumber continuation_column;
3083 int latest_char_in_file = 0; /* For getting back into comment-skipping
3084 code. */
3086 /* Lex is called for a particular file, not for a particular program unit.
3087 Yet the two events do share common characteristics. The first line in a
3088 file or in a program unit cannot be a continuation line. No token can
3089 be in mid-formation. No current label for the statement exists, since
3090 there is no current statement. */
3092 assert (ffelex_handler_ != NULL);
3094 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3095 lineno = 0;
3096 input_filename = ffewhere_file_name (wf);
3097 #endif
3098 ffelex_current_wf_ = wf;
3099 continuation_line = FALSE;
3100 ffelex_token_->type = FFELEX_typeNONE;
3101 ffelex_number_of_tokens_ = 0;
3102 ffelex_current_wl_ = ffewhere_line_unknown ();
3103 ffelex_current_wc_ = ffewhere_column_unknown ();
3104 latest_char_in_file = '\n';
3106 /* Come here to get a new line. */
3108 beginning_of_line: /* :::::::::::::::::::: */
3110 c = latest_char_in_file;
3111 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3114 end_of_file: /* :::::::::::::::::::: */
3116 /* Line ending in EOF instead of \n still counts as a whole line. */
3118 ffelex_finish_statement_ ();
3119 ffewhere_line_kill (ffelex_current_wl_);
3120 ffewhere_column_kill (ffelex_current_wc_);
3121 return (ffelexHandler) ffelex_handler_;
3124 ffelex_next_line_ ();
3126 ffelex_bad_line_ = FALSE;
3128 /* Skip over initial-comment and empty lines as quickly as possible! */
3130 while ((c == '\n')
3131 || (c == '!')
3132 || (c == '#'))
3134 if (c == '#')
3136 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3137 c = ffelex_hash_ (f);
3138 #else
3139 /* Don't skip over # line after all. */
3140 break;
3141 #endif
3144 comment_line: /* :::::::::::::::::::: */
3146 while ((c != '\n') && (c != EOF))
3147 c = getc (f);
3149 if (c == EOF)
3151 ffelex_next_line_ ();
3152 goto end_of_file; /* :::::::::::::::::::: */
3155 c = getc (f);
3157 ffelex_next_line_ ();
3159 if (c == EOF)
3160 goto end_of_file; /* :::::::::::::::::::: */
3163 ffelex_saw_tab_ = FALSE;
3165 column = ffelex_image_char_ (c, 0);
3167 /* Read the entire line in as is (with whitespace processing). */
3169 while (((c = getc (f)) != '\n') && (c != EOF))
3170 column = ffelex_image_char_ (c, column);
3172 if (ffelex_bad_line_)
3174 ffelex_card_image_[column] = '\0';
3175 ffelex_card_length_ = column;
3176 goto comment_line; /* :::::::::::::::::::: */
3179 /* If no tab, cut off line after column 132. */
3181 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3182 column = FFELEX_FREE_MAX_COLUMNS_;
3184 ffelex_card_image_[column] = '\0';
3185 ffelex_card_length_ = column;
3187 /* Save next char in file so we can use register-based c while analyzing
3188 line we just read. */
3190 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3192 column = 0;
3193 continuation_column = 0;
3195 /* Skip over initial spaces to see if the first nonblank character
3196 is exclamation point, newline, or EOF (line is therefore a comment) or
3197 ampersand (line is therefore a continuation line). */
3199 while ((c = ffelex_card_image_[column]) == ' ')
3200 ++column;
3202 switch (c)
3204 case '!':
3205 case '\0':
3206 goto beginning_of_line; /* :::::::::::::::::::: */
3208 case '&':
3209 continuation_column = column + 1;
3210 break;
3212 default:
3213 break;
3216 /* The line definitely has content of some kind, install new end-statement
3217 point for error messages. */
3219 ffewhere_line_kill (ffelex_current_wl_);
3220 ffewhere_column_kill (ffelex_current_wc_);
3221 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3222 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3224 /* Figure out which column to start parsing at. */
3226 if (continuation_line)
3228 if (continuation_column == 0)
3230 if (ffelex_raw_mode_ != 0)
3232 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3233 ffelex_linecount_current_, column + 1);
3235 else if (ffelex_token_->type != FFELEX_typeNONE)
3237 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3238 ffelex_linecount_current_, column + 1);
3241 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3242 { /* Line contains only a single "&" as only
3243 nonblank character. */
3244 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3245 ffelex_linecount_current_, continuation_column);
3246 goto beginning_of_line; /* :::::::::::::::::::: */
3248 column = continuation_column;
3250 else
3251 column = 0;
3253 c = ffelex_card_image_[column];
3254 continuation_line = FALSE;
3256 /* Here is the main engine for parsing. c holds the character at column.
3257 It is already known that c is not a blank, end of line, or shriek,
3258 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3259 character/hollerith constant). A partially filled token may already
3260 exist in ffelex_token_. */
3262 if (ffelex_raw_mode_ != 0)
3265 parse_raw_character: /* :::::::::::::::::::: */
3267 switch (c)
3269 case '&':
3270 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3272 continuation_line = TRUE;
3273 goto beginning_of_line; /* :::::::::::::::::::: */
3275 break;
3277 case '\0':
3278 ffelex_finish_statement_ ();
3279 goto beginning_of_line; /* :::::::::::::::::::: */
3281 default:
3282 break;
3285 switch (ffelex_raw_mode_)
3287 case -3:
3288 c = ffelex_backslash_ (c, column);
3289 if (c == EOF)
3290 break;
3292 if (!ffelex_backslash_reconsider_)
3293 ffelex_append_to_token_ (c);
3294 ffelex_raw_mode_ = -1;
3295 break;
3297 case -2:
3298 if (c == ffelex_raw_char_)
3300 ffelex_raw_mode_ = -1;
3301 ffelex_append_to_token_ (c);
3303 else
3305 ffelex_raw_mode_ = 0;
3306 ffelex_backslash_reconsider_ = TRUE;
3308 break;
3310 case -1:
3311 if (c == ffelex_raw_char_)
3312 ffelex_raw_mode_ = -2;
3313 else
3315 c = ffelex_backslash_ (c, column);
3316 if (c == EOF)
3318 ffelex_raw_mode_ = -3;
3319 break;
3322 ffelex_append_to_token_ (c);
3324 break;
3326 default:
3327 c = ffelex_backslash_ (c, column);
3328 if (c == EOF)
3329 break;
3331 if (!ffelex_backslash_reconsider_)
3333 ffelex_append_to_token_ (c);
3334 --ffelex_raw_mode_;
3336 break;
3339 if (ffelex_backslash_reconsider_)
3340 ffelex_backslash_reconsider_ = FALSE;
3341 else
3342 c = ffelex_card_image_[++column];
3344 if (ffelex_raw_mode_ == 0)
3346 ffelex_send_token_ ();
3347 assert (ffelex_raw_mode_ == 0);
3348 while (c == ' ')
3349 c = ffelex_card_image_[++column];
3350 if ((c == '\0') || (c == '!'))
3352 ffelex_finish_statement_ ();
3353 goto beginning_of_line; /* :::::::::::::::::::: */
3355 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3357 continuation_line = TRUE;
3358 goto beginning_of_line; /* :::::::::::::::::::: */
3360 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3362 goto parse_raw_character; /* :::::::::::::::::::: */
3365 parse_nonraw_character: /* :::::::::::::::::::: */
3367 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3369 continuation_line = TRUE;
3370 goto beginning_of_line; /* :::::::::::::::::::: */
3373 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3375 switch (ffelex_token_->type)
3377 case FFELEX_typeNONE:
3378 if (c == ' ')
3379 { /* Otherwise
3380 finish-statement/continue-statement
3381 already checked. */
3382 while (c == ' ')
3383 c = ffelex_card_image_[++column];
3384 if ((c == '\0') || (c == '!'))
3386 ffelex_finish_statement_ ();
3387 goto beginning_of_line; /* :::::::::::::::::::: */
3389 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3391 continuation_line = TRUE;
3392 goto beginning_of_line; /* :::::::::::::::::::: */
3396 switch (c)
3398 case '\"':
3399 ffelex_token_->type = FFELEX_typeQUOTE;
3400 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3401 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3402 ffelex_send_token_ ();
3403 break;
3405 case '$':
3406 ffelex_token_->type = FFELEX_typeDOLLAR;
3407 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3408 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3409 ffelex_send_token_ ();
3410 break;
3412 case '%':
3413 ffelex_token_->type = FFELEX_typePERCENT;
3414 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3415 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3416 ffelex_send_token_ ();
3417 break;
3419 case '&':
3420 ffelex_token_->type = FFELEX_typeAMPERSAND;
3421 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3422 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3423 ffelex_send_token_ ();
3424 break;
3426 case '\'':
3427 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3428 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3429 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3430 ffelex_send_token_ ();
3431 break;
3433 case '(':
3434 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3435 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3436 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3437 break;
3439 case ')':
3440 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3441 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3442 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3443 ffelex_send_token_ ();
3444 break;
3446 case '*':
3447 ffelex_token_->type = FFELEX_typeASTERISK;
3448 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3449 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3450 break;
3452 case '+':
3453 ffelex_token_->type = FFELEX_typePLUS;
3454 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3455 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3456 ffelex_send_token_ ();
3457 break;
3459 case ',':
3460 ffelex_token_->type = FFELEX_typeCOMMA;
3461 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3462 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3463 ffelex_send_token_ ();
3464 break;
3466 case '-':
3467 ffelex_token_->type = FFELEX_typeMINUS;
3468 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3469 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3470 ffelex_send_token_ ();
3471 break;
3473 case '.':
3474 ffelex_token_->type = FFELEX_typePERIOD;
3475 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3476 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3477 ffelex_send_token_ ();
3478 break;
3480 case '/':
3481 ffelex_token_->type = FFELEX_typeSLASH;
3482 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3483 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3484 break;
3486 case '0':
3487 case '1':
3488 case '2':
3489 case '3':
3490 case '4':
3491 case '5':
3492 case '6':
3493 case '7':
3494 case '8':
3495 case '9':
3496 ffelex_token_->type
3497 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3498 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3499 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3500 ffelex_append_to_token_ (c);
3501 break;
3503 case ':':
3504 ffelex_token_->type = FFELEX_typeCOLON;
3505 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3506 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3507 break;
3509 case ';':
3510 ffelex_token_->type = FFELEX_typeSEMICOLON;
3511 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3512 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3513 ffelex_permit_include_ = TRUE;
3514 ffelex_send_token_ ();
3515 ffelex_permit_include_ = FALSE;
3516 break;
3518 case '<':
3519 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3520 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3521 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3522 break;
3524 case '=':
3525 ffelex_token_->type = FFELEX_typeEQUALS;
3526 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3527 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3528 break;
3530 case '>':
3531 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3532 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3533 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3534 break;
3536 case '?':
3537 ffelex_token_->type = FFELEX_typeQUESTION;
3538 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3539 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3540 ffelex_send_token_ ();
3541 break;
3543 case '_':
3544 if (1 || ffe_is_90 ())
3546 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3547 ffelex_token_->where_line
3548 = ffewhere_line_use (ffelex_current_wl_);
3549 ffelex_token_->where_col
3550 = ffewhere_column_new (column + 1);
3551 ffelex_send_token_ ();
3552 break;
3554 /* Fall through. */
3555 case 'A':
3556 case 'B':
3557 case 'C':
3558 case 'D':
3559 case 'E':
3560 case 'F':
3561 case 'G':
3562 case 'H':
3563 case 'I':
3564 case 'J':
3565 case 'K':
3566 case 'L':
3567 case 'M':
3568 case 'N':
3569 case 'O':
3570 case 'P':
3571 case 'Q':
3572 case 'R':
3573 case 'S':
3574 case 'T':
3575 case 'U':
3576 case 'V':
3577 case 'W':
3578 case 'X':
3579 case 'Y':
3580 case 'Z':
3581 case 'a':
3582 case 'b':
3583 case 'c':
3584 case 'd':
3585 case 'e':
3586 case 'f':
3587 case 'g':
3588 case 'h':
3589 case 'i':
3590 case 'j':
3591 case 'k':
3592 case 'l':
3593 case 'm':
3594 case 'n':
3595 case 'o':
3596 case 'p':
3597 case 'q':
3598 case 'r':
3599 case 's':
3600 case 't':
3601 case 'u':
3602 case 'v':
3603 case 'w':
3604 case 'x':
3605 case 'y':
3606 case 'z':
3607 c = ffesrc_char_source (c);
3609 if (ffesrc_char_match_init (c, 'H', 'h')
3610 && ffelex_expecting_hollerith_ != 0)
3612 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3613 ffelex_token_->type = FFELEX_typeHOLLERITH;
3614 ffelex_token_->where_line = ffelex_raw_where_line_;
3615 ffelex_token_->where_col = ffelex_raw_where_col_;
3616 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3617 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3618 c = ffelex_card_image_[++column];
3619 goto parse_raw_character; /* :::::::::::::::::::: */
3622 if (ffelex_names_pure_)
3624 ffelex_token_->where_line
3625 = ffewhere_line_use (ffelex_token_->currentnames_line
3626 = ffewhere_line_use (ffelex_current_wl_));
3627 ffelex_token_->where_col
3628 = ffewhere_column_use (ffelex_token_->currentnames_col
3629 = ffewhere_column_new (column + 1));
3630 ffelex_token_->type = FFELEX_typeNAMES;
3632 else
3634 ffelex_token_->where_line
3635 = ffewhere_line_use (ffelex_current_wl_);
3636 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3637 ffelex_token_->type = FFELEX_typeNAME;
3639 ffelex_append_to_token_ (c);
3640 break;
3642 default:
3643 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3644 ffelex_linecount_current_, column + 1);
3645 ffelex_finish_statement_ ();
3646 goto beginning_of_line; /* :::::::::::::::::::: */
3648 break;
3650 case FFELEX_typeNAME:
3651 switch (c)
3653 case 'A':
3654 case 'B':
3655 case 'C':
3656 case 'D':
3657 case 'E':
3658 case 'F':
3659 case 'G':
3660 case 'H':
3661 case 'I':
3662 case 'J':
3663 case 'K':
3664 case 'L':
3665 case 'M':
3666 case 'N':
3667 case 'O':
3668 case 'P':
3669 case 'Q':
3670 case 'R':
3671 case 'S':
3672 case 'T':
3673 case 'U':
3674 case 'V':
3675 case 'W':
3676 case 'X':
3677 case 'Y':
3678 case 'Z':
3679 case 'a':
3680 case 'b':
3681 case 'c':
3682 case 'd':
3683 case 'e':
3684 case 'f':
3685 case 'g':
3686 case 'h':
3687 case 'i':
3688 case 'j':
3689 case 'k':
3690 case 'l':
3691 case 'm':
3692 case 'n':
3693 case 'o':
3694 case 'p':
3695 case 'q':
3696 case 'r':
3697 case 's':
3698 case 't':
3699 case 'u':
3700 case 'v':
3701 case 'w':
3702 case 'x':
3703 case 'y':
3704 case 'z':
3705 c = ffesrc_char_source (c);
3706 /* Fall through. */
3707 case '0':
3708 case '1':
3709 case '2':
3710 case '3':
3711 case '4':
3712 case '5':
3713 case '6':
3714 case '7':
3715 case '8':
3716 case '9':
3717 case '_':
3718 case '$':
3719 if ((c == '$')
3720 && !ffe_is_dollar_ok ())
3722 ffelex_send_token_ ();
3723 goto parse_next_character; /* :::::::::::::::::::: */
3725 ffelex_append_to_token_ (c);
3726 break;
3728 default:
3729 ffelex_send_token_ ();
3730 goto parse_next_character; /* :::::::::::::::::::: */
3732 break;
3734 case FFELEX_typeNAMES:
3735 switch (c)
3737 case 'A':
3738 case 'B':
3739 case 'C':
3740 case 'D':
3741 case 'E':
3742 case 'F':
3743 case 'G':
3744 case 'H':
3745 case 'I':
3746 case 'J':
3747 case 'K':
3748 case 'L':
3749 case 'M':
3750 case 'N':
3751 case 'O':
3752 case 'P':
3753 case 'Q':
3754 case 'R':
3755 case 'S':
3756 case 'T':
3757 case 'U':
3758 case 'V':
3759 case 'W':
3760 case 'X':
3761 case 'Y':
3762 case 'Z':
3763 case 'a':
3764 case 'b':
3765 case 'c':
3766 case 'd':
3767 case 'e':
3768 case 'f':
3769 case 'g':
3770 case 'h':
3771 case 'i':
3772 case 'j':
3773 case 'k':
3774 case 'l':
3775 case 'm':
3776 case 'n':
3777 case 'o':
3778 case 'p':
3779 case 'q':
3780 case 'r':
3781 case 's':
3782 case 't':
3783 case 'u':
3784 case 'v':
3785 case 'w':
3786 case 'x':
3787 case 'y':
3788 case 'z':
3789 c = ffesrc_char_source (c);
3790 /* Fall through. */
3791 case '0':
3792 case '1':
3793 case '2':
3794 case '3':
3795 case '4':
3796 case '5':
3797 case '6':
3798 case '7':
3799 case '8':
3800 case '9':
3801 case '_':
3802 case '$':
3803 if ((c == '$')
3804 && !ffe_is_dollar_ok ())
3806 ffelex_send_token_ ();
3807 goto parse_next_character; /* :::::::::::::::::::: */
3809 if (ffelex_token_->length < FFEWHERE_indexMAX)
3811 ffewhere_track (&ffelex_token_->currentnames_line,
3812 &ffelex_token_->currentnames_col,
3813 ffelex_token_->wheretrack,
3814 ffelex_token_->length,
3815 ffelex_linecount_current_,
3816 column + 1);
3818 ffelex_append_to_token_ (c);
3819 break;
3821 default:
3822 ffelex_send_token_ ();
3823 goto parse_next_character; /* :::::::::::::::::::: */
3825 break;
3827 case FFELEX_typeNUMBER:
3828 switch (c)
3830 case '0':
3831 case '1':
3832 case '2':
3833 case '3':
3834 case '4':
3835 case '5':
3836 case '6':
3837 case '7':
3838 case '8':
3839 case '9':
3840 ffelex_append_to_token_ (c);
3841 break;
3843 default:
3844 ffelex_send_token_ ();
3845 goto parse_next_character; /* :::::::::::::::::::: */
3847 break;
3849 case FFELEX_typeASTERISK:
3850 switch (c)
3852 case '*': /* ** */
3853 ffelex_token_->type = FFELEX_typePOWER;
3854 ffelex_send_token_ ();
3855 break;
3857 default: /* * not followed by another *. */
3858 ffelex_send_token_ ();
3859 goto parse_next_character; /* :::::::::::::::::::: */
3861 break;
3863 case FFELEX_typeCOLON:
3864 switch (c)
3866 case ':': /* :: */
3867 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3868 ffelex_send_token_ ();
3869 break;
3871 default: /* : not followed by another :. */
3872 ffelex_send_token_ ();
3873 goto parse_next_character; /* :::::::::::::::::::: */
3875 break;
3877 case FFELEX_typeSLASH:
3878 switch (c)
3880 case '/': /* // */
3881 ffelex_token_->type = FFELEX_typeCONCAT;
3882 ffelex_send_token_ ();
3883 break;
3885 case ')': /* /) */
3886 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3887 ffelex_send_token_ ();
3888 break;
3890 case '=': /* /= */
3891 ffelex_token_->type = FFELEX_typeREL_NE;
3892 ffelex_send_token_ ();
3893 break;
3895 default:
3896 ffelex_send_token_ ();
3897 goto parse_next_character; /* :::::::::::::::::::: */
3899 break;
3901 case FFELEX_typeOPEN_PAREN:
3902 switch (c)
3904 case '/': /* (/ */
3905 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3906 ffelex_send_token_ ();
3907 break;
3909 default:
3910 ffelex_send_token_ ();
3911 goto parse_next_character; /* :::::::::::::::::::: */
3913 break;
3915 case FFELEX_typeOPEN_ANGLE:
3916 switch (c)
3918 case '=': /* <= */
3919 ffelex_token_->type = FFELEX_typeREL_LE;
3920 ffelex_send_token_ ();
3921 break;
3923 default:
3924 ffelex_send_token_ ();
3925 goto parse_next_character; /* :::::::::::::::::::: */
3927 break;
3929 case FFELEX_typeEQUALS:
3930 switch (c)
3932 case '=': /* == */
3933 ffelex_token_->type = FFELEX_typeREL_EQ;
3934 ffelex_send_token_ ();
3935 break;
3937 case '>': /* => */
3938 ffelex_token_->type = FFELEX_typePOINTS;
3939 ffelex_send_token_ ();
3940 break;
3942 default:
3943 ffelex_send_token_ ();
3944 goto parse_next_character; /* :::::::::::::::::::: */
3946 break;
3948 case FFELEX_typeCLOSE_ANGLE:
3949 switch (c)
3951 case '=': /* >= */
3952 ffelex_token_->type = FFELEX_typeREL_GE;
3953 ffelex_send_token_ ();
3954 break;
3956 default:
3957 ffelex_send_token_ ();
3958 goto parse_next_character; /* :::::::::::::::::::: */
3960 break;
3962 default:
3963 assert ("Serious error!" == NULL);
3964 abort ();
3965 break;
3968 c = ffelex_card_image_[++column];
3970 parse_next_character: /* :::::::::::::::::::: */
3972 if (ffelex_raw_mode_ != 0)
3973 goto parse_raw_character; /* :::::::::::::::::::: */
3975 if ((c == '\0') || (c == '!'))
3977 ffelex_finish_statement_ ();
3978 goto beginning_of_line; /* :::::::::::::::::::: */
3980 goto parse_nonraw_character; /* :::::::::::::::::::: */
3983 /* See the code in com.c that calls this to understand why. */
3985 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3986 void
3987 ffelex_hash_kludge (FILE *finput)
3989 /* If you change this constant string, you have to change whatever
3990 code might thus be affected by it in terms of having to use
3991 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3992 static char match[] = "# 1 \"";
3993 static int kludge[ARRAY_SIZE (match) + 1];
3994 int c;
3995 char *p;
3996 int *q;
3998 /* Read chars as long as they match the target string.
3999 Copy them into an array that will serve as a record
4000 of what we read (essentially a multi-char ungetc(),
4001 for code that uses ffelex_getc_ instead of getc() elsewhere
4002 in the lexer. */
4003 for (p = &match[0], q = &kludge[0], c = getc (finput);
4004 (c == *p) && (*p != '\0') && (c != EOF);
4005 ++p, ++q, c = getc (finput))
4006 *q = c;
4008 *q = c; /* Might be EOF, which requires int. */
4009 *++q = 0;
4011 ffelex_kludge_chars_ = &kludge[0];
4013 if (*p == 0)
4015 ffelex_kludge_flag_ = TRUE;
4016 ++ffelex_kludge_chars_;
4017 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
4018 ffelex_kludge_flag_ = FALSE;
4022 #endif
4023 void
4024 ffelex_init_1 ()
4026 unsigned int i;
4028 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
4029 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
4030 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
4031 "FFELEX card image",
4032 FFELEX_columnINITIAL_SIZE_ + 9);
4033 ffelex_card_image_[0] = '\0';
4035 for (i = 0; i < 256; ++i)
4036 ffelex_first_char_[i] = FFELEX_typeERROR;
4038 ffelex_first_char_['\t'] = FFELEX_typeRAW;
4039 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
4040 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
4041 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
4042 ffelex_first_char_['\r'] = FFELEX_typeRAW;
4043 ffelex_first_char_[' '] = FFELEX_typeRAW;
4044 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
4045 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
4046 ffelex_first_char_['/'] = FFELEX_typeSLASH;
4047 ffelex_first_char_['&'] = FFELEX_typeRAW;
4048 ffelex_first_char_['#'] = FFELEX_typeHASH;
4050 for (i = '0'; i <= '9'; ++i)
4051 ffelex_first_char_[i] = FFELEX_typeRAW;
4053 if ((ffe_case_match () == FFE_caseNONE)
4054 || ((ffe_case_match () == FFE_caseUPPER)
4055 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
4056 || ((ffe_case_match () == FFE_caseLOWER)
4057 && (ffe_case_source () == FFE_caseLOWER)))
4059 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
4060 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
4062 if ((ffe_case_match () == FFE_caseNONE)
4063 || ((ffe_case_match () == FFE_caseLOWER)
4064 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
4065 || ((ffe_case_match () == FFE_caseUPPER)
4066 && (ffe_case_source () == FFE_caseUPPER)))
4068 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
4069 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
4072 ffelex_linecount_current_ = 0;
4073 ffelex_linecount_next_ = 1;
4074 ffelex_raw_mode_ = 0;
4075 ffelex_set_include_ = FALSE;
4076 ffelex_permit_include_ = FALSE;
4077 ffelex_names_ = TRUE; /* First token in program is a names. */
4078 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
4079 FORMAT. */
4080 ffelex_hexnum_ = FALSE;
4081 ffelex_expecting_hollerith_ = 0;
4082 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4083 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4085 ffelex_token_ = ffelex_token_new_ ();
4086 ffelex_token_->type = FFELEX_typeNONE;
4087 ffelex_token_->uses = 1;
4088 ffelex_token_->where_line = ffewhere_line_unknown ();
4089 ffelex_token_->where_col = ffewhere_column_unknown ();
4090 ffelex_token_->text = NULL;
4092 ffelex_handler_ = NULL;
4095 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4097 if (ffelex_is_names_expected())
4098 // Deliver NAMES token
4099 else
4100 // Deliver NAME token
4102 Must be called while lexer is active, obviously. */
4104 bool
4105 ffelex_is_names_expected ()
4107 return ffelex_names_;
4110 /* Current card image, which has the master linecount number
4111 ffelex_linecount_current_. */
4113 char *
4114 ffelex_line ()
4116 return ffelex_card_image_;
4119 /* ffelex_line_length -- Return length of current lexer line
4121 printf("Length is %lu\n",ffelex_line_length());
4123 Must be called while lexer is active, obviously. */
4125 ffewhereColumnNumber
4126 ffelex_line_length ()
4128 return ffelex_card_length_;
4131 /* Master line count of current card image, or 0 if no card image
4132 is current. */
4134 ffewhereLineNumber
4135 ffelex_line_number ()
4137 return ffelex_linecount_current_;
4140 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4142 ffelex_set_expecting_hollerith(0);
4144 Lex initially assumes no hollerith constant is about to show up. If
4145 syntactic analysis expects one, it should call this function with the
4146 number of characters expected in the constant immediately after recognizing
4147 the decimal number preceding the "H" and the constant itself. Then, if
4148 the next character is indeed H, the lexer will interpret it as beginning
4149 a hollerith constant and ship the token formed by reading the specified
4150 number of characters (interpreting blanks and otherwise-comments too)
4151 from the input file. It is up to syntactic analysis to call this routine
4152 again with 0 to turn hollerith detection off immediately upon receiving
4153 the token that might or might not be HOLLERITH.
4155 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4156 character constant. Pass the expected termination character (apostrophe
4157 or quote).
4159 Pass for length either the length of the hollerith (must be > 0), -1
4160 meaning expecting a character constant, or 0 to cancel expectation of
4161 a hollerith only after calling it with a length of > 0 and receiving the
4162 next token (which may or may not have been a HOLLERITH token).
4164 Pass for which either an apostrophe or quote when passing length of -1.
4165 Else which is a don't-care.
4167 Pass for line and column the line/column info for the token beginning the
4168 character or hollerith constant, for use in error messages, when passing
4169 a length of -1 -- this function will invoke ffewhere_line/column_use to
4170 make its own copies. Else line and column are don't-cares (when length
4171 is 0) and the outstanding copies of the previous line/column info, if
4172 still around, are killed.
4174 21-Feb-90 JCB 3.1
4175 When called with length of 0, also zero ffelex_raw_mode_. This is
4176 so ffest_save_ can undo the effects of replaying tokens like
4177 APOSTROPHE and QUOTE.
4178 25-Jan-90 JCB 3.0
4179 New line, column arguments allow error messages to point to the true
4180 beginning of a character/hollerith constant, rather than the beginning
4181 of the content part, which makes them more consistent and helpful.
4182 05-Nov-89 JCB 2.0
4183 New "which" argument allows caller to specify termination character,
4184 which should be apostrophe or double-quote, to support Fortran 90. */
4186 void
4187 ffelex_set_expecting_hollerith (long length, char which,
4188 ffewhereLine line, ffewhereColumn column)
4191 /* First kill the pending line/col info, if any (should only be pending
4192 when this call has length==0, the previous call had length>0, and a
4193 non-HOLLERITH token was sent in between the calls, but play it safe). */
4195 ffewhere_line_kill (ffelex_raw_where_line_);
4196 ffewhere_column_kill (ffelex_raw_where_col_);
4198 /* Now handle the length function. */
4199 switch (length)
4201 case 0:
4202 ffelex_expecting_hollerith_ = 0;
4203 ffelex_raw_mode_ = 0;
4204 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4205 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4206 return; /* Don't set new line/column info from args. */
4208 case -1:
4209 ffelex_raw_mode_ = -1;
4210 ffelex_raw_char_ = which;
4211 break;
4213 default: /* length > 0 */
4214 ffelex_expecting_hollerith_ = length;
4215 break;
4218 /* Now set new line/column information from passed args. */
4220 ffelex_raw_where_line_ = ffewhere_line_use (line);
4221 ffelex_raw_where_col_ = ffewhere_column_use (column);
4224 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4226 ffelex_set_handler((ffelexHandler) my_first_handler);
4228 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4229 after they return, but not while they are active. */
4231 void
4232 ffelex_set_handler (ffelexHandler first)
4234 ffelex_handler_ = first;
4237 /* ffelex_set_hexnum -- Set hexnum flag
4239 ffelex_set_hexnum(TRUE);
4241 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4242 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4243 the character as the first of the next token. But when parsing a
4244 hexadecimal number, by calling this function with TRUE before starting
4245 the parse of the token itself, lex will interpret [0-9] as the start
4246 of a NAME token. */
4248 void
4249 ffelex_set_hexnum (bool f)
4251 ffelex_hexnum_ = f;
4254 /* ffelex_set_include -- Set INCLUDE file to be processed next
4256 ffewhereFile wf; // The ffewhereFile object for the file.
4257 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4258 FILE *fi; // The file to INCLUDE.
4259 ffelex_set_include(wf,free_form,fi);
4261 Must be called only after receiving the EOS token following a valid
4262 INCLUDE statement specifying a file that has already been successfully
4263 opened. */
4265 void
4266 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4268 assert (ffelex_permit_include_);
4269 assert (!ffelex_set_include_);
4270 ffelex_set_include_ = TRUE;
4271 ffelex_include_free_form_ = free_form;
4272 ffelex_include_file_ = fi;
4273 ffelex_include_wherefile_ = wf;
4276 /* ffelex_set_names -- Set names/name flag, names = TRUE
4278 ffelex_set_names(FALSE);
4280 Lex initially assumes multiple names should be formed. If this function is
4281 called with FALSE, then single names are formed instead. The differences
4282 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4283 and in whether full source-location tracking is performed (it is for
4284 multiple names, not for single names), which is more expensive in terms of
4285 CPU time. */
4287 void
4288 ffelex_set_names (bool f)
4290 ffelex_names_ = f;
4291 if (!f)
4292 ffelex_names_pure_ = FALSE;
4295 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4297 ffelex_set_names_pure(FALSE);
4299 Like ffelex_set_names, except affects both lexers. Normally, the
4300 free-form lexer need not generate NAMES tokens because adjacent NAME
4301 tokens must be separated by spaces which causes the lexer to generate
4302 separate tokens for analysis (whereas in fixed-form the spaces are
4303 ignored resulting in one long token). But in FORMAT statements, for
4304 some reason, the Fortran 90 standard specifies that spaces can occur
4305 anywhere within a format-item-list with no effect on the format spec
4306 (except of course within character string edit descriptors), which means
4307 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4308 statement handling, the existence of spaces makes it hard to deal with,
4309 because each token is seen distinctly (i.e. seven tokens in the latter
4310 example). But when no spaces are provided, as in the former example,
4311 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4312 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4313 One, ffest_kw_format_ does a substring rather than full-string match,
4314 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4315 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4316 and three, error reporting can point to the actual character rather than
4317 at or prior to it. The first two things could be resolved by providing
4318 alternate functions fairly easy, thus allowing FORMAT handling to expect
4319 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4320 changes to FORMAT parsing), but the third, error reporting, would suffer,
4321 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4322 to exactly where the compilers thinks the problem is, to even begin to get
4323 a handle on it. So there. */
4325 void
4326 ffelex_set_names_pure (bool f)
4328 ffelex_names_pure_ = f;
4329 ffelex_names_ = f;
4332 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4334 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4335 start_char_index);
4337 Returns first_handler if start_char_index chars into master_token (which
4338 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4339 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4340 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4341 and sends it to first_handler. If anything other than NAME is sent, the
4342 character at the end of it in the master token is examined to see if it
4343 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4344 the handler returned by first_handler is invoked with that token, and
4345 this process is repeated until the end of the master token or a NAME
4346 token is reached. */
4348 ffelexHandler
4349 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4350 ffeTokenLength start)
4352 unsigned char *p;
4353 ffeTokenLength i;
4354 ffelexToken t;
4356 p = ffelex_token_text (master) + (i = start);
4358 while (*p != '\0')
4360 if (ISDIGIT (*p))
4362 t = ffelex_token_number_from_names (master, i);
4363 p += ffelex_token_length (t);
4364 i += ffelex_token_length (t);
4366 else if (ffesrc_is_name_init (*p))
4368 t = ffelex_token_name_from_names (master, i, 0);
4369 p += ffelex_token_length (t);
4370 i += ffelex_token_length (t);
4372 else if (*p == '$')
4374 t = ffelex_token_dollar_from_names (master, i);
4375 ++p;
4376 ++i;
4378 else if (*p == '_')
4380 t = ffelex_token_uscore_from_names (master, i);
4381 ++p;
4382 ++i;
4384 else
4386 assert ("not a valid NAMES character" == NULL);
4387 t = NULL;
4389 assert (first != NULL);
4390 first = (ffelexHandler) (*first) (t);
4391 ffelex_token_kill (t);
4394 return first;
4397 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4399 return ffelex_swallow_tokens;
4401 Return this handler when you don't want to look at any more tokens in the
4402 statement because you've encountered an unrecoverable error in the
4403 statement. */
4405 ffelexHandler
4406 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4408 assert (handler != NULL);
4410 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4411 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4412 return (ffelexHandler) (*handler) (t);
4414 ffelex_eos_handler_ = handler;
4415 return (ffelexHandler) ffelex_swallow_tokens_;
4418 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4420 ffelexToken t;
4421 t = ffelex_token_dollar_from_names(t,6);
4423 It's as if you made a new token of dollar type having the dollar
4424 at, in the example above, the sixth character of the NAMES token. */
4426 ffelexToken
4427 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4429 ffelexToken nt;
4431 assert (t != NULL);
4432 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4433 assert (start < t->length);
4434 assert (t->text[start] == '$');
4436 /* Now make the token. */
4438 nt = ffelex_token_new_ ();
4439 nt->type = FFELEX_typeDOLLAR;
4440 nt->length = 0;
4441 nt->uses = 1;
4442 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4443 t->where_col, t->wheretrack, start);
4444 nt->text = NULL;
4445 return nt;
4448 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4450 ffelexToken t;
4451 ffelex_token_kill(t);
4453 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4455 void
4456 ffelex_token_kill (ffelexToken t)
4458 assert (t != NULL);
4460 assert (t->uses > 0);
4462 if (--t->uses != 0)
4463 return;
4465 --ffelex_total_tokens_;
4467 if (t->type == FFELEX_typeNAMES)
4468 ffewhere_track_kill (t->where_line, t->where_col,
4469 t->wheretrack, t->length);
4470 ffewhere_line_kill (t->where_line);
4471 ffewhere_column_kill (t->where_col);
4472 if (t->text != NULL)
4473 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4474 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4477 /* Make a new NAME token that is a substring of a NAMES token. */
4479 ffelexToken
4480 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4481 ffeTokenLength len)
4483 ffelexToken nt;
4485 assert (t != NULL);
4486 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4487 assert (start < t->length);
4488 if (len == 0)
4489 len = t->length - start;
4490 else
4492 assert (len > 0);
4493 assert ((start + len) <= t->length);
4495 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4497 nt = ffelex_token_new_ ();
4498 nt->type = FFELEX_typeNAME;
4499 nt->size = len; /* Assume nobody's gonna fiddle with token
4500 text. */
4501 nt->length = len;
4502 nt->uses = 1;
4503 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4504 t->where_col, t->wheretrack, start);
4505 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4506 len + 1);
4507 strncpy (nt->text, t->text + start, len);
4508 nt->text[len] = '\0';
4509 return nt;
4512 /* Make a new NAMES token that is a substring of another NAMES token. */
4514 ffelexToken
4515 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4516 ffeTokenLength len)
4518 ffelexToken nt;
4520 assert (t != NULL);
4521 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4522 assert (start < t->length);
4523 if (len == 0)
4524 len = t->length - start;
4525 else
4527 assert (len > 0);
4528 assert ((start + len) <= t->length);
4530 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4532 nt = ffelex_token_new_ ();
4533 nt->type = FFELEX_typeNAMES;
4534 nt->size = len; /* Assume nobody's gonna fiddle with token
4535 text. */
4536 nt->length = len;
4537 nt->uses = 1;
4538 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4539 t->where_col, t->wheretrack, start);
4540 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4541 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4542 len + 1);
4543 strncpy (nt->text, t->text + start, len);
4544 nt->text[len] = '\0';
4545 return nt;
4548 /* Make a new CHARACTER token. */
4550 ffelexToken
4551 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4553 ffelexToken t;
4555 t = ffelex_token_new_ ();
4556 t->type = FFELEX_typeCHARACTER;
4557 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4558 t->uses = 1;
4559 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4560 t->size + 1);
4561 strcpy (t->text, s);
4562 t->where_line = ffewhere_line_use (l);
4563 t->where_col = ffewhere_column_new (c);
4564 return t;
4567 /* Make a new EOF token right after end of file. */
4569 ffelexToken
4570 ffelex_token_new_eof ()
4572 ffelexToken t;
4574 t = ffelex_token_new_ ();
4575 t->type = FFELEX_typeEOF;
4576 t->uses = 1;
4577 t->text = NULL;
4578 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4579 t->where_col = ffewhere_column_new (1);
4580 return t;
4583 /* Make a new NAME token. */
4585 ffelexToken
4586 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4588 ffelexToken t;
4590 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4592 t = ffelex_token_new_ ();
4593 t->type = FFELEX_typeNAME;
4594 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4595 t->uses = 1;
4596 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4597 t->size + 1);
4598 strcpy (t->text, s);
4599 t->where_line = ffewhere_line_use (l);
4600 t->where_col = ffewhere_column_new (c);
4601 return t;
4604 /* Make a new NAMES token. */
4606 ffelexToken
4607 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4609 ffelexToken t;
4611 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4613 t = ffelex_token_new_ ();
4614 t->type = FFELEX_typeNAMES;
4615 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4616 t->uses = 1;
4617 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4618 t->size + 1);
4619 strcpy (t->text, s);
4620 t->where_line = ffewhere_line_use (l);
4621 t->where_col = ffewhere_column_new (c);
4622 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4623 names. */
4624 return t;
4627 /* Make a new NUMBER token.
4629 The first character of the string must be a digit, and only the digits
4630 are copied into the new number. So this may be used to easily extract
4631 a NUMBER token from within any text string. Then the length of the
4632 resulting token may be used to calculate where the digits stopped
4633 in the original string. */
4635 ffelexToken
4636 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4638 ffelexToken t;
4639 ffeTokenLength len;
4641 /* How long is the string of decimal digits at s? */
4643 len = strspn (s, "0123456789");
4645 /* Make sure there is at least one digit. */
4647 assert (len != 0);
4649 /* Now make the token. */
4651 t = ffelex_token_new_ ();
4652 t->type = FFELEX_typeNUMBER;
4653 t->length = t->size = len; /* Assume it won't get bigger. */
4654 t->uses = 1;
4655 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4656 len + 1);
4657 strncpy (t->text, s, len);
4658 t->text[len] = '\0';
4659 t->where_line = ffewhere_line_use (l);
4660 t->where_col = ffewhere_column_new (c);
4661 return t;
4664 /* Make a new token of any type that doesn't contain text. A private
4665 function that is used by public macros in the interface file. */
4667 ffelexToken
4668 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4670 ffelexToken t;
4672 t = ffelex_token_new_ ();
4673 t->type = type;
4674 t->uses = 1;
4675 t->text = NULL;
4676 t->where_line = ffewhere_line_use (l);
4677 t->where_col = ffewhere_column_new (c);
4678 return t;
4681 /* Make a new NUMBER token from an existing NAMES token.
4683 Like ffelex_token_new_number, this function calculates the length
4684 of the digit string itself. */
4686 ffelexToken
4687 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4689 ffelexToken nt;
4690 ffeTokenLength len;
4692 assert (t != NULL);
4693 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4694 assert (start < t->length);
4696 /* How long is the string of decimal digits at s? */
4698 len = strspn (t->text + start, "0123456789");
4700 /* Make sure there is at least one digit. */
4702 assert (len != 0);
4704 /* Now make the token. */
4706 nt = ffelex_token_new_ ();
4707 nt->type = FFELEX_typeNUMBER;
4708 nt->size = len; /* Assume nobody's gonna fiddle with token
4709 text. */
4710 nt->length = len;
4711 nt->uses = 1;
4712 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4713 t->where_col, t->wheretrack, start);
4714 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4715 len + 1);
4716 strncpy (nt->text, t->text + start, len);
4717 nt->text[len] = '\0';
4718 return nt;
4721 /* Make a new UNDERSCORE token from a NAMES token. */
4723 ffelexToken
4724 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4726 ffelexToken nt;
4728 assert (t != NULL);
4729 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4730 assert (start < t->length);
4731 assert (t->text[start] == '_');
4733 /* Now make the token. */
4735 nt = ffelex_token_new_ ();
4736 nt->type = FFELEX_typeUNDERSCORE;
4737 nt->uses = 1;
4738 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4739 t->where_col, t->wheretrack, start);
4740 nt->text = NULL;
4741 return nt;
4744 /* ffelex_token_use -- Return another instance of a token
4746 ffelexToken t;
4747 t = ffelex_token_use(t);
4749 In a sense, the new token is a copy of the old, though it might be the
4750 same with just a new use count.
4752 We use the use count method (easy). */
4754 ffelexToken
4755 ffelex_token_use (ffelexToken t)
4757 if (t == NULL)
4758 assert ("_token_use: null token" == NULL);
4759 t->uses++;
4760 return t;