* decl2.c (pending_statics_used): Make it a macro.
[official-gcc.git] / gcc / f / lex.c
blobb6198b215f1fc17858544f0d78e15f5c69e4a9a0
1 /* Implementation of Fortran lexer
2 Copyright (C) 1995-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 #endif
37 #ifdef DWARF_DEBUGGING_INFO
38 void dwarfout_resume_previous_source_file (register unsigned);
39 void dwarfout_start_new_source_file (register char *);
40 void dwarfout_define (register unsigned, register char *);
41 void dwarfout_undef (register unsigned, register char *);
42 #endif DWARF_DEBUGGING_INFO
44 static void ffelex_append_to_token_ (char c);
45 static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
46 static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
47 ffewhereColumnNumber cn0);
48 static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
49 ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
50 ffewhereColumnNumber cn1);
51 static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
52 ffewhereColumnNumber cn0);
53 static void ffelex_finish_statement_ (void);
54 #if FFECOM_targetCURRENT == FFECOM_targetGCC
55 static int ffelex_get_directive_line_ (char **text, FILE *finput);
56 static int ffelex_hash_ (FILE *f);
57 #endif
58 static ffewhereColumnNumber ffelex_image_char_ (int c,
59 ffewhereColumnNumber col);
60 static void ffelex_include_ (void);
61 static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
62 static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
63 static void ffelex_next_line_ (void);
64 static void ffelex_prepare_eos_ (void);
65 static void ffelex_send_token_ (void);
66 static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
67 static ffelexToken ffelex_token_new_ (void);
69 /* Pertaining to the geometry of the input file. */
71 /* Initial size for card image to be allocated. */
72 #define FFELEX_columnINITIAL_SIZE_ 255
74 /* The card image itself, which grows as source lines get longer. It
75 has room for ffelex_card_size_ + 8 characters, and the length of the
76 current image is ffelex_card_length_. (The + 8 characters are made
77 available for easy handling of tabs and such.) */
78 static char *ffelex_card_image_;
79 static ffewhereColumnNumber ffelex_card_size_;
80 static ffewhereColumnNumber ffelex_card_length_;
82 /* Max width for free-form lines (ISO F90). */
83 #define FFELEX_FREE_MAX_COLUMNS_ 132
85 /* True if we saw a tab on the current line, as this (currently) means
86 the line is therefore treated as though final_nontab_column_ were
87 infinite. */
88 static bool ffelex_saw_tab_;
90 /* TRUE if current line is known to be erroneous, so don't bother
91 expanding room for it just to display it. */
92 static bool ffelex_bad_line_ = FALSE;
94 /* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
95 static ffewhereColumnNumber ffelex_final_nontab_column_;
97 /* Array for quickly deciding what kind of line the current card has,
98 based on its first character. */
99 static ffelexType ffelex_first_char_[256];
101 /* Pertaining to file management. */
103 /* The wf argument of the most recent active ffelex_file_(fixed,free)
104 function. */
105 static ffewhereFile ffelex_current_wf_;
107 /* TRUE if an INCLUDE statement can be processed (ffelex_set_include
108 can be called). */
109 static bool ffelex_permit_include_;
111 /* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
112 called). */
113 static bool ffelex_set_include_;
115 /* Information on the pending INCLUDE file. */
116 static FILE *ffelex_include_file_;
117 static bool ffelex_include_free_form_;
118 static ffewhereFile ffelex_include_wherefile_;
120 /* Current master line count. */
121 static ffewhereLineNumber ffelex_linecount_current_;
122 /* Next master line count. */
123 static ffewhereLineNumber ffelex_linecount_next_;
125 /* ffewhere info on the latest (currently active) line read from the
126 active source file. */
127 static ffewhereLine ffelex_current_wl_;
128 static ffewhereColumn ffelex_current_wc_;
130 /* Pertaining to tokens in general. */
132 /* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
133 token. */
134 #define FFELEX_columnTOKEN_SIZE_ 63
135 #if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
136 #error "token size too small!"
137 #endif
139 /* Current token being lexed. */
140 static ffelexToken ffelex_token_;
142 /* Handler for current token. */
143 static ffelexHandler ffelex_handler_;
145 /* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
146 static bool ffelex_names_;
148 /* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
149 static bool ffelex_names_pure_;
151 /* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
152 numbers. */
153 static bool ffelex_hexnum_;
155 /* For ffelex_swallow_tokens(). */
156 static ffelexHandler ffelex_eos_handler_;
158 /* Number of tokens sent since last EOS or beginning of input file
159 (include INCLUDEd files). */
160 static unsigned long int ffelex_number_of_tokens_;
162 /* Number of labels sent (as NUMBER tokens) since last reset of
163 ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
164 (Fixed-form source only.) */
165 static unsigned long int ffelex_label_tokens_;
167 /* Metering for token management, to catch token-memory leaks. */
168 static long int ffelex_total_tokens_ = 0;
169 static long int ffelex_old_total_tokens_ = 1;
170 static long int ffelex_token_nextid_ = 0;
172 /* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
174 /* >0 if a Hollerith constant of that length might be in mid-lex, used
175 when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
176 mode (see ffelex_raw_mode_). */
177 static long int ffelex_expecting_hollerith_;
179 /* -3: Backslash (escape) sequence being lexed in CHARACTER.
180 -2: Possible closing apostrophe/quote seen in CHARACTER.
181 -1: Lexing CHARACTER.
182 0: Not lexing CHARACTER or HOLLERITH.
183 >0: Lexing HOLLERITH, value is # chars remaining to expect. */
184 static long int ffelex_raw_mode_;
186 /* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
187 static char ffelex_raw_char_;
189 /* TRUE when backslash processing had to use most recent character
190 to finish its state engine, but that character is not part of
191 the backslash sequence, so must be reconsidered as a "normal"
192 character in CHARACTER/HOLLERITH lexing. */
193 static bool ffelex_backslash_reconsider_ = FALSE;
195 /* Characters preread before lexing happened (might include EOF). */
196 static int *ffelex_kludge_chars_ = NULL;
198 /* Doing the kludge processing, so not initialized yet. */
199 static bool ffelex_kludge_flag_ = FALSE;
201 /* The beginning of a (possible) CHARACTER/HOLLERITH token. */
202 static ffewhereLine ffelex_raw_where_line_;
203 static ffewhereColumn ffelex_raw_where_col_;
206 /* Call this to append another character to the current token. If it isn't
207 currently big enough for it, it will be enlarged. The current token
208 must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
210 static void
211 ffelex_append_to_token_ (char c)
213 if (ffelex_token_->text == NULL)
215 ffelex_token_->text
216 = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
217 FFELEX_columnTOKEN_SIZE_ + 1);
218 ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
219 ffelex_token_->length = 0;
221 else if (ffelex_token_->length >= ffelex_token_->size)
223 ffelex_token_->text
224 = malloc_resize_ksr (malloc_pool_image (),
225 ffelex_token_->text,
226 (ffelex_token_->size << 1) + 1,
227 ffelex_token_->size + 1);
228 ffelex_token_->size <<= 1;
229 assert (ffelex_token_->length < ffelex_token_->size);
231 #ifdef MAP_CHARACTER
232 Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
233 please contact fortran@gnu.org if you wish to fund work to
234 port g77 to non-ASCII machines.
235 #endif
236 ffelex_token_->text[ffelex_token_->length++] = c;
239 /* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
240 being lexed. */
242 static int
243 ffelex_backslash_ (int c, ffewhereColumnNumber col)
245 static int state = 0;
246 static unsigned int count;
247 static int code;
248 static unsigned int firstdig = 0;
249 static int nonnull;
250 static ffewhereLineNumber line;
251 static ffewhereColumnNumber column;
253 /* See gcc/c-lex.c readescape() for a straightforward version
254 of this state engine for handling backslashes in character/
255 hollerith constants. */
257 #define wide_flag 0
258 #define warn_traditional 0
259 #define flag_traditional 0
261 switch (state)
263 case 0:
264 if ((c == '\\')
265 && (ffelex_raw_mode_ != 0)
266 && ffe_is_backslash ())
268 state = 1;
269 column = col + 1;
270 line = ffelex_linecount_current_;
271 return EOF;
273 return c;
275 case 1:
276 state = 0; /* Assume simple case. */
277 switch (c)
279 case 'x':
280 if (warn_traditional)
282 ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
283 FFEBAD_severityWARNING);
284 ffelex_bad_here_ (0, line, column);
285 ffebad_finish ();
288 if (flag_traditional)
289 return c;
291 code = 0;
292 count = 0;
293 nonnull = 0;
294 state = 2;
295 return EOF;
297 case '0': case '1': case '2': case '3': case '4':
298 case '5': case '6': case '7':
299 code = c - '0';
300 count = 1;
301 state = 3;
302 return EOF;
304 case '\\': case '\'': case '"':
305 return c;
307 #if 0 /* Inappropriate for Fortran. */
308 case '\n':
309 ffelex_next_line_ ();
310 *ignore_ptr = 1;
311 return 0;
312 #endif
314 case 'n':
315 return TARGET_NEWLINE;
317 case 't':
318 return TARGET_TAB;
320 case 'r':
321 return TARGET_CR;
323 case 'f':
324 return TARGET_FF;
326 case 'b':
327 return TARGET_BS;
329 case 'a':
330 if (warn_traditional)
332 ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
333 FFEBAD_severityWARNING);
334 ffelex_bad_here_ (0, line, column);
335 ffebad_finish ();
338 if (flag_traditional)
339 return c;
340 return TARGET_BELL;
342 case 'v':
343 #if 0 /* Vertical tab is present in common usage compilers. */
344 if (flag_traditional)
345 return c;
346 #endif
347 return TARGET_VT;
349 case 'e':
350 case 'E':
351 case '(':
352 case '{':
353 case '[':
354 case '%':
355 if (pedantic)
357 char m[2];
359 m[0] = c;
360 m[1] = '\0';
361 ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
362 FFEBAD_severityPEDANTIC);
363 ffelex_bad_here_ (0, line, column);
364 ffebad_string (m);
365 ffebad_finish ();
367 return (c == 'E' || c == 'e') ? 033 : c;
369 case '?':
370 return c;
372 default:
373 if (c >= 040 && c < 0177)
375 char m[2];
377 m[0] = c;
378 m[1] = '\0';
379 ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
380 FFEBAD_severityPEDANTIC);
381 ffelex_bad_here_ (0, line, column);
382 ffebad_string (m);
383 ffebad_finish ();
385 else if (c == EOF)
387 ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
388 FFEBAD_severityPEDANTIC);
389 ffelex_bad_here_ (0, line, column);
390 ffebad_finish ();
392 else
394 char m[20];
396 sprintf (&m[0], "%x", c);
397 ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
398 FFEBAD_severityPEDANTIC);
399 ffelex_bad_here_ (0, line, column);
400 ffebad_string (m);
401 ffebad_finish ();
404 return c;
406 case 2:
407 if ((c >= 'a' && c <= 'f')
408 || (c >= 'A' && c <= 'F')
409 || (c >= '0' && c <= '9'))
411 code *= 16;
412 if (c >= 'a' && c <= 'f')
413 code += c - 'a' + 10;
414 if (c >= 'A' && c <= 'F')
415 code += c - 'A' + 10;
416 if (c >= '0' && c <= '9')
417 code += c - '0';
418 if (code != 0 || count != 0)
420 if (count == 0)
421 firstdig = code;
422 count++;
424 nonnull = 1;
425 return EOF;
428 state = 0;
430 if (! nonnull)
432 ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
433 FFEBAD_severityFATAL);
434 ffelex_bad_here_ (0, line, column);
435 ffebad_finish ();
437 else if (count == 0)
438 /* Digits are all 0's. Ok. */
440 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
441 || (count > 1
442 && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
443 <= (int) firstdig)))
445 ffebad_start_msg_lex ("Hex escape at %0 out of range",
446 FFEBAD_severityPEDANTIC);
447 ffelex_bad_here_ (0, line, column);
448 ffebad_finish ();
450 break;
452 case 3:
453 if ((c <= '7') && (c >= '0') && (count++ < 3))
455 code = (code * 8) + (c - '0');
456 return EOF;
458 state = 0;
459 break;
461 default:
462 assert ("bad backslash state" == NULL);
463 abort ();
466 /* Come here when code has a built character, and c is the next
467 character that might (or might not) be the next one in the constant. */
469 /* Don't bother doing this check for each character going into
470 CHARACTER or HOLLERITH constants, just the escaped-value ones.
471 gcc apparently checks every single character, which seems
472 like it'd be kinda slow and not worth doing anyway. */
474 if (!wide_flag
475 && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
476 && code >= (1 << TYPE_PRECISION (char_type_node)))
478 ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
479 FFEBAD_severityFATAL);
480 ffelex_bad_here_ (0, line, column);
481 ffebad_finish ();
484 if (c == EOF)
486 /* Known end of constant, just append this character. */
487 ffelex_append_to_token_ (code);
488 if (ffelex_raw_mode_ > 0)
489 --ffelex_raw_mode_;
490 return EOF;
493 /* Have two characters to handle. Do the first, then leave it to the
494 caller to detect anything special about the second. */
496 ffelex_append_to_token_ (code);
497 if (ffelex_raw_mode_ > 0)
498 --ffelex_raw_mode_;
499 ffelex_backslash_reconsider_ = TRUE;
500 return c;
503 /* ffelex_bad_1_ -- Issue diagnostic with one source point
505 ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
507 Creates ffewhere line and column objects for the source point, sends them
508 along with the error code to ffebad, then kills the line and column
509 objects before returning. */
511 static void
512 ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
514 ffewhereLine wl0;
515 ffewhereColumn wc0;
517 wl0 = ffewhere_line_new (ln0);
518 wc0 = ffewhere_column_new (cn0);
519 ffebad_start_lex (errnum);
520 ffebad_here (0, wl0, wc0);
521 ffebad_finish ();
522 ffewhere_line_kill (wl0);
523 ffewhere_column_kill (wc0);
526 /* ffelex_bad_2_ -- Issue diagnostic with two source points
528 ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
529 otherline,othercolumn);
531 Creates ffewhere line and column objects for the source points, sends them
532 along with the error code to ffebad, then kills the line and column
533 objects before returning. */
535 static void
536 ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
537 ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
539 ffewhereLine wl0, wl1;
540 ffewhereColumn wc0, wc1;
542 wl0 = ffewhere_line_new (ln0);
543 wc0 = ffewhere_column_new (cn0);
544 wl1 = ffewhere_line_new (ln1);
545 wc1 = ffewhere_column_new (cn1);
546 ffebad_start_lex (errnum);
547 ffebad_here (0, wl0, wc0);
548 ffebad_here (1, wl1, wc1);
549 ffebad_finish ();
550 ffewhere_line_kill (wl0);
551 ffewhere_column_kill (wc0);
552 ffewhere_line_kill (wl1);
553 ffewhere_column_kill (wc1);
556 static void
557 ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
558 ffewhereColumnNumber cn0)
560 ffewhereLine wl0;
561 ffewhereColumn wc0;
563 wl0 = ffewhere_line_new (ln0);
564 wc0 = ffewhere_column_new (cn0);
565 ffebad_here (n, wl0, wc0);
566 ffewhere_line_kill (wl0);
567 ffewhere_column_kill (wc0);
570 #if FFECOM_targetCURRENT == FFECOM_targetGCC
571 static int
572 ffelex_getc_ (FILE *finput)
574 int c;
576 if (ffelex_kludge_chars_ == NULL)
577 return getc (finput);
579 c = *ffelex_kludge_chars_++;
580 if (c != 0)
581 return c;
583 ffelex_kludge_chars_ = NULL;
584 return getc (finput);
587 #endif
588 #if FFECOM_targetCURRENT == FFECOM_targetGCC
589 static int
590 ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
592 register int c = getc (finput);
593 register int code;
594 register unsigned count;
595 unsigned firstdig = 0;
596 int nonnull;
598 *use_d = 0;
600 switch (c)
602 case 'x':
603 if (warn_traditional)
604 warning ("the meaning of `\\x' varies with -traditional");
606 if (flag_traditional)
607 return c;
609 code = 0;
610 count = 0;
611 nonnull = 0;
612 while (1)
614 c = getc (finput);
615 if (!(c >= 'a' && c <= 'f')
616 && !(c >= 'A' && c <= 'F')
617 && !(c >= '0' && c <= '9'))
619 *use_d = 1;
620 *d = c;
621 break;
623 code *= 16;
624 if (c >= 'a' && c <= 'f')
625 code += c - 'a' + 10;
626 if (c >= 'A' && c <= 'F')
627 code += c - 'A' + 10;
628 if (c >= '0' && c <= '9')
629 code += c - '0';
630 if (code != 0 || count != 0)
632 if (count == 0)
633 firstdig = code;
634 count++;
636 nonnull = 1;
638 if (! nonnull)
639 error ("\\x used with no following hex digits");
640 else if (count == 0)
641 /* Digits are all 0's. Ok. */
643 else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
644 || (count > 1
645 && (((unsigned) 1
646 << (TYPE_PRECISION (integer_type_node) - (count - 1)
647 * 4))
648 <= firstdig)))
649 pedwarn ("hex escape out of range");
650 return code;
652 case '0': case '1': case '2': case '3': case '4':
653 case '5': case '6': case '7':
654 code = 0;
655 count = 0;
656 while ((c <= '7') && (c >= '0') && (count++ < 3))
658 code = (code * 8) + (c - '0');
659 c = getc (finput);
661 *use_d = 1;
662 *d = c;
663 return code;
665 case '\\': case '\'': case '"':
666 return c;
668 case '\n':
669 ffelex_next_line_ ();
670 *use_d = 2;
671 return 0;
673 case EOF:
674 *use_d = 1;
675 *d = EOF;
676 return EOF;
678 case 'n':
679 return TARGET_NEWLINE;
681 case 't':
682 return TARGET_TAB;
684 case 'r':
685 return TARGET_CR;
687 case 'f':
688 return TARGET_FF;
690 case 'b':
691 return TARGET_BS;
693 case 'a':
694 if (warn_traditional)
695 warning ("the meaning of `\\a' varies with -traditional");
697 if (flag_traditional)
698 return c;
699 return TARGET_BELL;
701 case 'v':
702 #if 0 /* Vertical tab is present in common usage compilers. */
703 if (flag_traditional)
704 return c;
705 #endif
706 return TARGET_VT;
708 case 'e':
709 case 'E':
710 if (pedantic)
711 pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
712 return 033;
714 case '?':
715 return c;
717 /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
718 case '(':
719 case '{':
720 case '[':
721 /* `\%' is used to prevent SCCS from getting confused. */
722 case '%':
723 if (pedantic)
724 pedwarn ("non-ANSI escape sequence `\\%c'", c);
725 return c;
727 if (c >= 040 && c < 0177)
728 pedwarn ("unknown escape sequence `\\%c'", c);
729 else
730 pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
731 return c;
734 #endif
735 /* A miniature version of the C front-end lexer. */
737 #if FFECOM_targetCURRENT == FFECOM_targetGCC
738 static int
739 ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
741 ffelexToken token;
742 char buff[129];
743 char *p;
744 char *q;
745 char *r;
746 register unsigned buffer_length;
748 if ((*xtoken != NULL) && !ffelex_kludge_flag_)
749 ffelex_token_kill (*xtoken);
751 switch (c)
753 case '0': case '1': case '2': case '3': case '4':
754 case '5': case '6': case '7': case '8': case '9':
755 buffer_length = ARRAY_SIZE (buff);
756 p = &buff[0];
757 q = p;
758 r = &buff[buffer_length];
759 for (;;)
761 *p++ = c;
762 if (p >= r)
764 register unsigned bytes_used = (p - q);
766 buffer_length *= 2;
767 q = (char *)xrealloc (q, buffer_length);
768 p = &q[bytes_used];
769 r = &q[buffer_length];
771 c = ffelex_getc_ (finput);
772 if (! ISDIGIT (c))
773 break;
775 *p = '\0';
776 token = ffelex_token_new_number (q, ffewhere_line_unknown (),
777 ffewhere_column_unknown ());
779 if (q != &buff[0])
780 free (q);
782 break;
784 case '\"':
785 buffer_length = ARRAY_SIZE (buff);
786 p = &buff[0];
787 q = p;
788 r = &buff[buffer_length];
789 c = ffelex_getc_ (finput);
790 for (;;)
792 bool done = FALSE;
793 int use_d = 0;
794 int d;
796 switch (c)
798 case '\"':
799 c = getc (finput);
800 done = TRUE;
801 break;
803 case '\\': /* ~~~~~ */
804 c = ffelex_cfebackslash_ (&use_d, &d, finput);
805 break;
807 case EOF:
808 case '\n':
809 fatal ("Badly formed directive -- no closing quote");
810 done = TRUE;
811 break;
813 default:
814 break;
816 if (done)
817 break;
819 if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
821 *p++ = c;
822 if (p >= r)
824 register unsigned bytes_used = (p - q);
826 buffer_length = bytes_used * 2;
827 q = (char *)xrealloc (q, buffer_length);
828 p = &q[bytes_used];
829 r = &q[buffer_length];
832 if (use_d == 1)
833 c = d;
834 else
835 c = getc (finput);
837 *p = '\0';
838 token = ffelex_token_new_character (q, ffewhere_line_unknown (),
839 ffewhere_column_unknown ());
841 if (q != &buff[0])
842 free (q);
844 break;
846 default:
847 token = NULL;
848 break;
851 *xtoken = token;
852 return c;
854 #endif
856 #if FFECOM_targetCURRENT == FFECOM_targetGCC
857 static void
858 ffelex_file_pop_ (char *input_filename)
860 if (input_file_stack->next)
862 struct file_stack *p = input_file_stack;
863 input_file_stack = p->next;
864 free (p);
865 input_file_stack_tick++;
866 #ifdef DWARF_DEBUGGING_INFO
867 if (debug_info_level == DINFO_LEVEL_VERBOSE
868 && write_symbols == DWARF_DEBUG)
869 dwarfout_resume_previous_source_file (input_file_stack->line);
870 #endif /* DWARF_DEBUGGING_INFO */
872 else
873 error ("#-lines for entering and leaving files don't match");
875 /* Now that we've pushed or popped the input stack,
876 update the name in the top element. */
877 if (input_file_stack)
878 input_file_stack->name = input_filename;
881 #endif
882 #if FFECOM_targetCURRENT == FFECOM_targetGCC
883 static void
884 ffelex_file_push_ (int old_lineno, char *input_filename)
886 struct file_stack *p
887 = (struct file_stack *) xmalloc (sizeof (struct file_stack));
889 input_file_stack->line = old_lineno;
890 p->next = input_file_stack;
891 p->name = input_filename;
892 input_file_stack = p;
893 input_file_stack_tick++;
894 #ifdef DWARF_DEBUGGING_INFO
895 if (debug_info_level == DINFO_LEVEL_VERBOSE
896 && write_symbols == DWARF_DEBUG)
897 dwarfout_start_new_source_file (input_filename);
898 #endif /* DWARF_DEBUGGING_INFO */
900 /* Now that we've pushed or popped the input stack,
901 update the name in the top element. */
902 if (input_file_stack)
903 input_file_stack->name = input_filename;
905 #endif
907 /* Prepare to finish a statement-in-progress by sending the current
908 token, if any, then setting up EOS as the current token with the
909 appropriate current pointer. The caller can then move the current
910 pointer before actually sending EOS, if desired, as it is in
911 typical fixed-form cases. */
913 static void
914 ffelex_prepare_eos_ ()
916 if (ffelex_token_->type != FFELEX_typeNONE)
918 ffelex_backslash_ (EOF, 0);
920 switch (ffelex_raw_mode_)
922 case -2:
923 break;
925 case -1:
926 ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
927 : FFEBAD_NO_CLOSING_QUOTE);
928 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
929 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
930 ffebad_finish ();
931 break;
933 case 0:
934 break;
936 default:
938 char num[20];
940 ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
941 ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
942 ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
943 sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
944 ffebad_string (num);
945 ffebad_finish ();
946 /* Make sure the token has some text, might as well fill up with spaces. */
949 ffelex_append_to_token_ (' ');
950 } while (--ffelex_raw_mode_ > 0);
951 break;
954 ffelex_raw_mode_ = 0;
955 ffelex_send_token_ ();
957 ffelex_token_->type = FFELEX_typeEOS;
958 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
959 ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
962 static void
963 ffelex_finish_statement_ ()
965 if ((ffelex_number_of_tokens_ == 0)
966 && (ffelex_token_->type == FFELEX_typeNONE))
967 return; /* Don't have a statement pending. */
969 if (ffelex_token_->type != FFELEX_typeEOS)
970 ffelex_prepare_eos_ ();
972 ffelex_permit_include_ = TRUE;
973 ffelex_send_token_ ();
974 ffelex_permit_include_ = FALSE;
975 ffelex_number_of_tokens_ = 0;
976 ffelex_label_tokens_ = 0;
977 ffelex_names_ = TRUE;
978 ffelex_names_pure_ = FALSE; /* Probably not necessary. */
979 ffelex_hexnum_ = FALSE;
981 if (!ffe_is_ffedebug ())
982 return;
984 /* For debugging purposes only. */
986 if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
988 fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
989 ffelex_old_total_tokens_, ffelex_total_tokens_);
990 ffelex_old_total_tokens_ = ffelex_total_tokens_;
994 /* Copied from gcc/c-common.c get_directive_line. */
996 #if FFECOM_targetCURRENT == FFECOM_targetGCC
997 static int
998 ffelex_get_directive_line_ (char **text, FILE *finput)
1000 static char *directive_buffer = NULL;
1001 static unsigned buffer_length = 0;
1002 register char *p;
1003 register char *buffer_limit;
1004 register int looking_for = 0;
1005 register int char_escaped = 0;
1007 if (buffer_length == 0)
1009 directive_buffer = (char *)xmalloc (128);
1010 buffer_length = 128;
1013 buffer_limit = &directive_buffer[buffer_length];
1015 for (p = directive_buffer; ; )
1017 int c;
1019 /* Make buffer bigger if it is full. */
1020 if (p >= buffer_limit)
1022 register unsigned bytes_used = (p - directive_buffer);
1024 buffer_length *= 2;
1025 directive_buffer
1026 = (char *)xrealloc (directive_buffer, buffer_length);
1027 p = &directive_buffer[bytes_used];
1028 buffer_limit = &directive_buffer[buffer_length];
1031 c = getc (finput);
1033 /* Discard initial whitespace. */
1034 if ((c == ' ' || c == '\t') && p == directive_buffer)
1035 continue;
1037 /* Detect the end of the directive. */
1038 if ((c == '\n' && looking_for == 0)
1039 || c == EOF)
1041 if (looking_for != 0)
1042 fatal ("Bad directive -- missing close-quote");
1044 *p++ = '\0';
1045 *text = directive_buffer;
1046 return c;
1049 *p++ = c;
1050 if (c == '\n')
1051 ffelex_next_line_ ();
1053 /* Handle string and character constant syntax. */
1054 if (looking_for)
1056 if (looking_for == c && !char_escaped)
1057 looking_for = 0; /* Found terminator... stop looking. */
1059 else
1060 if (c == '\'' || c == '"')
1061 looking_for = c; /* Don't stop buffering until we see another
1062 one of these (or an EOF). */
1064 /* Handle backslash. */
1065 char_escaped = (c == '\\' && ! char_escaped);
1068 #endif
1070 /* Handle # directives that make it through (or are generated by) the
1071 preprocessor. As much as reasonably possible, emulate the behavior
1072 of the gcc compiler phase cc1, though interactions between #include
1073 and INCLUDE might possibly produce bizarre results in terms of
1074 error reporting and the generation of debugging info vis-a-vis the
1075 locations of some things.
1077 Returns the next character unhandled, which is always newline or EOF. */
1079 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1081 #if defined HANDLE_PRAGMA
1082 /* Local versions of these macros, that can be passed as function pointers. */
1083 static int
1084 pragma_getc ()
1086 return getc (finput);
1089 static void
1090 pragma_ungetc (arg)
1091 int arg;
1093 ungetc (arg, finput);
1095 #endif /* HANDLE_PRAGMA */
1097 static int
1098 ffelex_hash_ (FILE *finput)
1100 register int c;
1101 ffelexToken token = NULL;
1103 /* Read first nonwhite char after the `#'. */
1105 c = ffelex_getc_ (finput);
1106 while (c == ' ' || c == '\t')
1107 c = ffelex_getc_ (finput);
1109 /* If a letter follows, then if the word here is `line', skip
1110 it and ignore it; otherwise, ignore the line, with an error
1111 if the word isn't `pragma', `ident', `define', or `undef'. */
1113 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
1115 if (c == 'p')
1117 if (getc (finput) == 'r'
1118 && getc (finput) == 'a'
1119 && getc (finput) == 'g'
1120 && getc (finput) == 'm'
1121 && getc (finput) == 'a'
1122 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1123 || c == EOF))
1125 #if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
1126 static char buffer [128];
1127 char * buff = buffer;
1129 /* Read the pragma name into a buffer.
1130 ISSPACE() may evaluate its argument more than once! */
1131 while (((c = getc (finput)), ISSPACE(c)))
1132 continue;
1136 * buff ++ = c;
1137 c = getc (finput);
1139 while (c != EOF && ! ISSPACE (c) && c != '\n'
1140 && buff < buffer + 128);
1142 pragma_ungetc (c);
1144 * -- buff = 0;
1145 #ifdef HANDLE_PRAGMA
1146 if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc, buffer))
1147 goto skipline;
1148 #endif /* HANDLE_PRAGMA */
1149 #ifdef HANDLE_GENERIC_PRAGMAS
1150 if (handle_generic_pragma (buffer))
1151 goto skipline;
1152 #endif /* !HANDLE_GENERIC_PRAGMAS */
1154 /* Issue a warning message if we have been asked to do so.
1155 Ignoring unknown pragmas in system header file unless
1156 an explcit -Wunknown-pragmas has been given. */
1157 if (warn_unknown_pragmas > 1
1158 || (warn_unknown_pragmas && ! in_system_header))
1159 warning ("ignoring pragma: %s", token_buffer);
1160 #endif /* 0 */
1161 goto skipline;
1165 else if (c == 'd')
1167 if (getc (finput) == 'e'
1168 && getc (finput) == 'f'
1169 && getc (finput) == 'i'
1170 && getc (finput) == 'n'
1171 && getc (finput) == 'e'
1172 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1173 || c == EOF))
1175 char *text;
1177 c = ffelex_get_directive_line_ (&text, finput);
1179 #ifdef DWARF_DEBUGGING_INFO
1180 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1181 && (write_symbols == DWARF_DEBUG))
1182 dwarfout_define (lineno, text);
1183 #endif /* DWARF_DEBUGGING_INFO */
1185 goto skipline;
1188 else if (c == 'u')
1190 if (getc (finput) == 'n'
1191 && getc (finput) == 'd'
1192 && getc (finput) == 'e'
1193 && getc (finput) == 'f'
1194 && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
1195 || c == EOF))
1197 char *text;
1199 c = ffelex_get_directive_line_ (&text, finput);
1201 #ifdef DWARF_DEBUGGING_INFO
1202 if ((debug_info_level == DINFO_LEVEL_VERBOSE)
1203 && (write_symbols == DWARF_DEBUG))
1204 dwarfout_undef (lineno, text);
1205 #endif /* DWARF_DEBUGGING_INFO */
1207 goto skipline;
1210 else if (c == 'l')
1212 if (getc (finput) == 'i'
1213 && getc (finput) == 'n'
1214 && getc (finput) == 'e'
1215 && ((c = getc (finput)) == ' ' || c == '\t'))
1216 goto linenum;
1218 else if (c == 'i')
1220 if (getc (finput) == 'd'
1221 && getc (finput) == 'e'
1222 && getc (finput) == 'n'
1223 && getc (finput) == 't'
1224 && ((c = getc (finput)) == ' ' || c == '\t'))
1226 /* #ident. The pedantic warning is now in cccp.c. */
1228 /* Here we have just seen `#ident '.
1229 A string constant should follow. */
1231 while (c == ' ' || c == '\t')
1232 c = getc (finput);
1234 /* If no argument, ignore the line. */
1235 if (c == '\n' || c == EOF)
1236 return c;
1238 c = ffelex_cfelex_ (&token, finput, c);
1240 if ((token == NULL)
1241 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1243 error ("invalid #ident");
1244 goto skipline;
1247 if (! flag_no_ident)
1249 #ifdef ASM_OUTPUT_IDENT
1250 ASM_OUTPUT_IDENT (asm_out_file,
1251 ffelex_token_text (token));
1252 #endif
1255 /* Skip the rest of this line. */
1256 goto skipline;
1260 error ("undefined or invalid # directive");
1261 goto skipline;
1264 linenum:
1265 /* Here we have either `#line' or `# <nonletter>'.
1266 In either case, it should be a line number; a digit should follow. */
1268 while (c == ' ' || c == '\t')
1269 c = ffelex_getc_ (finput);
1271 /* If the # is the only nonwhite char on the line,
1272 just ignore it. Check the new newline. */
1273 if (c == '\n' || c == EOF)
1274 return c;
1276 /* Something follows the #; read a token. */
1278 c = ffelex_cfelex_ (&token, finput, c);
1280 if ((token != NULL)
1281 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1283 int old_lineno = lineno;
1284 char *old_input_filename = input_filename;
1285 ffewhereFile wf;
1287 /* subtract one, because it is the following line that
1288 gets the specified number */
1289 int l = atoi (ffelex_token_text (token)) - 1;
1291 /* Is this the last nonwhite stuff on the line? */
1292 while (c == ' ' || c == '\t')
1293 c = ffelex_getc_ (finput);
1294 if (c == '\n' || c == EOF)
1296 /* No more: store the line number and check following line. */
1297 lineno = l;
1298 if (!ffelex_kludge_flag_)
1300 ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
1302 if (token != NULL)
1303 ffelex_token_kill (token);
1305 return c;
1308 /* More follows: it must be a string constant (filename). */
1310 /* Read the string constant. */
1311 c = ffelex_cfelex_ (&token, finput, c);
1313 if ((token == NULL)
1314 || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
1316 error ("invalid #line");
1317 goto skipline;
1320 lineno = l;
1322 if (ffelex_kludge_flag_)
1323 input_filename = ffelex_token_text (token);
1324 else
1326 wf = ffewhere_file_new (ffelex_token_text (token),
1327 ffelex_token_length (token));
1328 input_filename = ffewhere_file_name (wf);
1329 ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
1332 #if 0 /* Not sure what g77 should do with this yet. */
1333 /* Each change of file name
1334 reinitializes whether we are now in a system header. */
1335 in_system_header = 0;
1336 #endif
1338 if (main_input_filename == 0)
1339 main_input_filename = input_filename;
1341 /* Is this the last nonwhite stuff on the line? */
1342 while (c == ' ' || c == '\t')
1343 c = getc (finput);
1344 if (c == '\n' || c == EOF)
1346 if (!ffelex_kludge_flag_)
1348 /* Update the name in the top element of input_file_stack. */
1349 if (input_file_stack)
1350 input_file_stack->name = input_filename;
1352 if (token != NULL)
1353 ffelex_token_kill (token);
1355 return c;
1358 c = ffelex_cfelex_ (&token, finput, c);
1360 /* `1' after file name means entering new file.
1361 `2' after file name means just left a file. */
1363 if ((token != NULL)
1364 && (ffelex_token_type (token) == FFELEX_typeNUMBER))
1366 int num = atoi (ffelex_token_text (token));
1368 if (ffelex_kludge_flag_)
1370 lineno = 1;
1371 input_filename = old_input_filename;
1372 fatal ("Use `#line ...' instead of `# ...' in first line");
1375 if (num == 1)
1377 /* Pushing to a new file. */
1378 ffelex_file_push_ (old_lineno, input_filename);
1380 else if (num == 2)
1382 /* Popping out of a file. */
1383 ffelex_file_pop_ (input_filename);
1386 /* Is this the last nonwhite stuff on the line? */
1387 while (c == ' ' || c == '\t')
1388 c = getc (finput);
1389 if (c == '\n' || c == EOF)
1391 if (token != NULL)
1392 ffelex_token_kill (token);
1393 return c;
1396 c = ffelex_cfelex_ (&token, finput, c);
1399 /* `3' after file name means this is a system header file. */
1401 #if 0 /* Not sure what g77 should do with this yet. */
1402 if ((token != NULL)
1403 && (ffelex_token_type (token) == FFELEX_typeNUMBER)
1404 && (atoi (ffelex_token_text (token)) == 3))
1405 in_system_header = 1;
1406 #endif
1408 while (c == ' ' || c == '\t')
1409 c = getc (finput);
1410 if (((token != NULL)
1411 || (c != '\n' && c != EOF))
1412 && ffelex_kludge_flag_)
1414 lineno = 1;
1415 input_filename = old_input_filename;
1416 fatal ("Use `#line ...' instead of `# ...' in first line");
1419 else
1420 error ("invalid #-line");
1422 /* skip the rest of this line. */
1423 skipline:
1424 if ((token != NULL) && !ffelex_kludge_flag_)
1425 ffelex_token_kill (token);
1426 while ((c = getc (finput)) != EOF && c != '\n')
1428 return c;
1430 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1432 /* "Image" a character onto the card image, return incremented column number.
1434 Normally invoking this function as in
1435 column = ffelex_image_char_ (c, column);
1436 is the same as doing:
1437 ffelex_card_image_[column++] = c;
1439 However, tabs and carriage returns are handled specially, to preserve
1440 the visual "image" of the input line (in most editors) in the card
1441 image.
1443 Carriage returns are ignored, as they are assumed to be followed
1444 by newlines.
1446 A tab is handled by first doing:
1447 ffelex_card_image_[column++] = ' ';
1448 That is, it translates to at least one space. Then, as many spaces
1449 are imaged as necessary to bring the column number to the next tab
1450 position, where tab positions start in the ninth column and each
1451 eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
1452 is set to TRUE to notify the lexer that a tab was seen.
1454 Columns are numbered and tab stops set as illustrated below:
1456 012345670123456701234567...
1457 x y z
1458 xx yy zz
1460 xxxxxxx yyyyyyy zzzzzzz
1461 xxxxxxxx yyyyyyyy... */
1463 static ffewhereColumnNumber
1464 ffelex_image_char_ (int c, ffewhereColumnNumber column)
1466 ffewhereColumnNumber old_column = column;
1468 if (column >= ffelex_card_size_)
1470 ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
1472 if (ffelex_bad_line_)
1473 return column;
1475 if ((newmax >> 1) != ffelex_card_size_)
1476 { /* Overflowed column number. */
1477 overflow: /* :::::::::::::::::::: */
1479 ffelex_bad_line_ = TRUE;
1480 strcpy (&ffelex_card_image_[column - 3], "...");
1481 ffelex_card_length_ = column;
1482 ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
1483 ffelex_linecount_current_, column + 1);
1484 return column;
1487 ffelex_card_image_
1488 = malloc_resize_ksr (malloc_pool_image (),
1489 ffelex_card_image_,
1490 newmax + 9,
1491 ffelex_card_size_ + 9);
1492 ffelex_card_size_ = newmax;
1495 switch (c)
1497 case '\r':
1498 break;
1500 case '\t':
1501 ffelex_saw_tab_ = TRUE;
1502 ffelex_card_image_[column++] = ' ';
1503 while ((column & 7) != 0)
1504 ffelex_card_image_[column++] = ' ';
1505 break;
1507 case '\0':
1508 if (!ffelex_bad_line_)
1510 ffelex_bad_line_ = TRUE;
1511 strcpy (&ffelex_card_image_[column], "[\\0]");
1512 ffelex_card_length_ = column + 4;
1513 ffebad_start_msg_lex ("Null character at %0 -- line ignored",
1514 FFEBAD_severityFATAL);
1515 ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
1516 ffebad_finish ();
1517 column += 4;
1519 break;
1521 default:
1522 ffelex_card_image_[column++] = c;
1523 break;
1526 if (column < old_column)
1528 column = old_column;
1529 goto overflow; /* :::::::::::::::::::: */
1532 return column;
1535 static void
1536 ffelex_include_ ()
1538 ffewhereFile include_wherefile = ffelex_include_wherefile_;
1539 FILE *include_file = ffelex_include_file_;
1540 /* The rest of this is to push, and after the INCLUDE file is processed,
1541 pop, the static lexer state info that pertains to each particular
1542 input file. */
1543 char *card_image;
1544 ffewhereColumnNumber card_size = ffelex_card_size_;
1545 ffewhereColumnNumber card_length = ffelex_card_length_;
1546 ffewhereLine current_wl = ffelex_current_wl_;
1547 ffewhereColumn current_wc = ffelex_current_wc_;
1548 bool saw_tab = ffelex_saw_tab_;
1549 ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
1550 ffewhereFile current_wf = ffelex_current_wf_;
1551 ffewhereLineNumber linecount_current = ffelex_linecount_current_;
1552 ffewhereLineNumber linecount_offset
1553 = ffewhere_line_filelinenum (current_wl);
1554 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1555 int old_lineno = lineno;
1556 char *old_input_filename = input_filename;
1557 #endif
1559 if (card_length != 0)
1561 card_image = malloc_new_ks (malloc_pool_image (),
1562 "FFELEX saved card image",
1563 card_length);
1564 memcpy (card_image, ffelex_card_image_, card_length);
1566 else
1567 card_image = NULL;
1569 ffelex_set_include_ = FALSE;
1571 ffelex_next_line_ ();
1573 ffewhere_file_set (include_wherefile, TRUE, 0);
1575 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1576 ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
1577 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1579 if (ffelex_include_free_form_)
1580 ffelex_file_free (include_wherefile, include_file);
1581 else
1582 ffelex_file_fixed (include_wherefile, include_file);
1584 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1585 ffelex_file_pop_ (ffewhere_file_name (current_wf));
1586 #endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
1588 ffewhere_file_set (current_wf, TRUE, linecount_offset);
1590 ffecom_close_include (include_file);
1592 if (card_length != 0)
1594 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1595 #error "need to handle possible reduction of card size here!!"
1596 #endif
1597 assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
1598 memcpy (ffelex_card_image_, card_image, card_length);
1600 ffelex_card_image_[card_length] = '\0';
1602 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1603 input_filename = old_input_filename;
1604 lineno = old_lineno;
1605 #endif
1606 ffelex_linecount_current_ = linecount_current;
1607 ffelex_current_wf_ = current_wf;
1608 ffelex_final_nontab_column_ = final_nontab_column;
1609 ffelex_saw_tab_ = saw_tab;
1610 ffelex_current_wc_ = current_wc;
1611 ffelex_current_wl_ = current_wl;
1612 ffelex_card_length_ = card_length;
1613 ffelex_card_size_ = card_size;
1616 /* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
1618 ffewhereColumnNumber col;
1619 int c; // Char at col.
1620 if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
1621 // We have a continuation indicator.
1623 If there are <n> spaces starting at ffelex_card_image_[col] up through
1624 the null character, where <n> is 0 or greater, returns TRUE. */
1626 static bool
1627 ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
1629 while (ffelex_card_image_[col] != '\0')
1631 if (ffelex_card_image_[col++] != ' ')
1632 return FALSE;
1634 return TRUE;
1637 /* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
1639 ffewhereColumnNumber col;
1640 int c; // Char at col.
1641 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
1642 // We have a continuation indicator.
1644 If there are <n> spaces starting at ffelex_card_image_[col] up through
1645 the null character or '!', where <n> is 0 or greater, returns TRUE. */
1647 static bool
1648 ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
1650 while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
1652 if (ffelex_card_image_[col++] != ' ')
1653 return FALSE;
1655 return TRUE;
1658 static void
1659 ffelex_next_line_ ()
1661 ffelex_linecount_current_ = ffelex_linecount_next_;
1662 ++ffelex_linecount_next_;
1663 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1664 ++lineno;
1665 #endif
1668 static void
1669 ffelex_send_token_ ()
1671 ++ffelex_number_of_tokens_;
1673 ffelex_backslash_ (EOF, 0);
1675 if (ffelex_token_->text == NULL)
1677 if (ffelex_token_->type == FFELEX_typeCHARACTER)
1679 ffelex_append_to_token_ ('\0');
1680 ffelex_token_->length = 0;
1683 else
1684 ffelex_token_->text[ffelex_token_->length] = '\0';
1686 assert (ffelex_raw_mode_ == 0);
1688 if (ffelex_token_->type == FFELEX_typeNAMES)
1690 ffewhere_line_kill (ffelex_token_->currentnames_line);
1691 ffewhere_column_kill (ffelex_token_->currentnames_col);
1694 assert (ffelex_handler_ != NULL);
1695 ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
1696 assert (ffelex_handler_ != NULL);
1698 ffelex_token_kill (ffelex_token_);
1700 ffelex_token_ = ffelex_token_new_ ();
1701 ffelex_token_->uses = 1;
1702 ffelex_token_->text = NULL;
1703 if (ffelex_raw_mode_ < 0)
1705 ffelex_token_->type = FFELEX_typeCHARACTER;
1706 ffelex_token_->where_line = ffelex_raw_where_line_;
1707 ffelex_token_->where_col = ffelex_raw_where_col_;
1708 ffelex_raw_where_line_ = ffewhere_line_unknown ();
1709 ffelex_raw_where_col_ = ffewhere_column_unknown ();
1711 else
1713 ffelex_token_->type = FFELEX_typeNONE;
1714 ffelex_token_->where_line = ffewhere_line_unknown ();
1715 ffelex_token_->where_col = ffewhere_column_unknown ();
1718 if (ffelex_set_include_)
1719 ffelex_include_ ();
1722 /* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
1724 return ffelex_swallow_tokens_;
1726 Return this handler when you don't want to look at any more tokens in the
1727 statement because you've encountered an unrecoverable error in the
1728 statement. */
1730 static ffelexHandler
1731 ffelex_swallow_tokens_ (ffelexToken t)
1733 assert (ffelex_eos_handler_ != NULL);
1735 if ((ffelex_token_type (t) == FFELEX_typeEOS)
1736 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
1737 return (ffelexHandler) (*ffelex_eos_handler_) (t);
1739 return (ffelexHandler) ffelex_swallow_tokens_;
1742 static ffelexToken
1743 ffelex_token_new_ ()
1745 ffelexToken t;
1747 ++ffelex_total_tokens_;
1749 t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
1750 "FFELEX token", sizeof (*t));
1751 t->id_ = ffelex_token_nextid_++;
1752 return t;
1755 static const char *
1756 ffelex_type_string_ (ffelexType type)
1758 static const char *types[] = {
1759 "FFELEX_typeNONE",
1760 "FFELEX_typeCOMMENT",
1761 "FFELEX_typeEOS",
1762 "FFELEX_typeEOF",
1763 "FFELEX_typeERROR",
1764 "FFELEX_typeRAW",
1765 "FFELEX_typeQUOTE",
1766 "FFELEX_typeDOLLAR",
1767 "FFELEX_typeHASH",
1768 "FFELEX_typePERCENT",
1769 "FFELEX_typeAMPERSAND",
1770 "FFELEX_typeAPOSTROPHE",
1771 "FFELEX_typeOPEN_PAREN",
1772 "FFELEX_typeCLOSE_PAREN",
1773 "FFELEX_typeASTERISK",
1774 "FFELEX_typePLUS",
1775 "FFELEX_typeMINUS",
1776 "FFELEX_typePERIOD",
1777 "FFELEX_typeSLASH",
1778 "FFELEX_typeNUMBER",
1779 "FFELEX_typeOPEN_ANGLE",
1780 "FFELEX_typeEQUALS",
1781 "FFELEX_typeCLOSE_ANGLE",
1782 "FFELEX_typeNAME",
1783 "FFELEX_typeCOMMA",
1784 "FFELEX_typePOWER",
1785 "FFELEX_typeCONCAT",
1786 "FFELEX_typeDEBUG",
1787 "FFELEX_typeNAMES",
1788 "FFELEX_typeHOLLERITH",
1789 "FFELEX_typeCHARACTER",
1790 "FFELEX_typeCOLON",
1791 "FFELEX_typeSEMICOLON",
1792 "FFELEX_typeUNDERSCORE",
1793 "FFELEX_typeQUESTION",
1794 "FFELEX_typeOPEN_ARRAY",
1795 "FFELEX_typeCLOSE_ARRAY",
1796 "FFELEX_typeCOLONCOLON",
1797 "FFELEX_typeREL_LE",
1798 "FFELEX_typeREL_NE",
1799 "FFELEX_typeREL_EQ",
1800 "FFELEX_typePOINTS",
1801 "FFELEX_typeREL_GE"
1804 if (type >= ARRAY_SIZE (types))
1805 return "???";
1806 return types[type];
1809 void
1810 ffelex_display_token (ffelexToken t)
1812 if (t == NULL)
1813 t = ffelex_token_;
1815 fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
1816 ffewhereColumnNumber_f "u)",
1817 t->id_,
1818 ffelex_type_string_ (t->type),
1819 ffewhere_line_number (t->where_line),
1820 ffewhere_column_number (t->where_col));
1822 if (t->text != NULL)
1823 fprintf (dmpout, ": \"%.*s\"\n",
1824 (int) t->length,
1825 t->text);
1826 else
1827 fprintf (dmpout, ".\n");
1830 /* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
1832 if (ffelex_expecting_character())
1833 // next token delivered by lexer will be CHARACTER.
1835 If the most recent call to ffelex_set_expecting_hollerith since the last
1836 token was delivered by the lexer passed a length of -1, then we return
1837 TRUE, because the next token we deliver will be typeCHARACTER, else we
1838 return FALSE. */
1840 bool
1841 ffelex_expecting_character ()
1843 return (ffelex_raw_mode_ != 0);
1846 /* ffelex_file_fixed -- Lex a given file in fixed source form
1848 ffewhere wf;
1849 FILE *f;
1850 ffelex_file_fixed(wf,f);
1852 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
1854 ffelexHandler
1855 ffelex_file_fixed (ffewhereFile wf, FILE *f)
1857 register int c = 0; /* Character currently under consideration. */
1858 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
1859 bool disallow_continuation_line;
1860 bool ignore_disallowed_continuation = FALSE;
1861 int latest_char_in_file = 0; /* For getting back into comment-skipping
1862 code. */
1863 ffelexType lextype;
1864 ffewhereColumnNumber first_label_char; /* First char of label --
1865 column number. */
1866 char label_string[6]; /* Text of label. */
1867 int labi; /* Length of label text. */
1868 bool finish_statement; /* Previous statement finished? */
1869 bool have_content; /* This line have content? */
1870 bool just_do_label; /* Nothing but label (and continuation?) on
1871 line. */
1873 /* Lex is called for a particular file, not for a particular program unit.
1874 Yet the two events do share common characteristics. The first line in a
1875 file or in a program unit cannot be a continuation line. No token can
1876 be in mid-formation. No current label for the statement exists, since
1877 there is no current statement. */
1879 assert (ffelex_handler_ != NULL);
1881 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1882 lineno = 0;
1883 input_filename = ffewhere_file_name (wf);
1884 #endif
1885 ffelex_current_wf_ = wf;
1886 disallow_continuation_line = TRUE;
1887 ignore_disallowed_continuation = FALSE;
1888 ffelex_token_->type = FFELEX_typeNONE;
1889 ffelex_number_of_tokens_ = 0;
1890 ffelex_label_tokens_ = 0;
1891 ffelex_current_wl_ = ffewhere_line_unknown ();
1892 ffelex_current_wc_ = ffewhere_column_unknown ();
1893 latest_char_in_file = '\n';
1895 if (ffe_is_null_version ())
1897 /* Just substitute a "program" directly here. */
1899 char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
1900 char *p;
1902 column = 0;
1903 for (p = &line[0]; *p != '\0'; ++p)
1904 column = ffelex_image_char_ (*p, column);
1906 c = EOF;
1908 goto have_line; /* :::::::::::::::::::: */
1911 goto first_line; /* :::::::::::::::::::: */
1913 /* Come here to get a new line. */
1915 beginning_of_line: /* :::::::::::::::::::: */
1917 disallow_continuation_line = FALSE;
1919 /* Come here directly when last line didn't clarify the continuation issue. */
1921 beginning_of_line_again: /* :::::::::::::::::::: */
1923 #ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
1924 if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
1926 ffelex_card_image_
1927 = malloc_resize_ks (malloc_pool_image (),
1928 ffelex_card_image_,
1929 FFELEX_columnINITIAL_SIZE_ + 9,
1930 ffelex_card_size_ + 9);
1931 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
1933 #endif
1935 first_line: /* :::::::::::::::::::: */
1937 c = latest_char_in_file;
1938 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
1941 end_of_file: /* :::::::::::::::::::: */
1943 /* Line ending in EOF instead of \n still counts as a whole line. */
1945 ffelex_finish_statement_ ();
1946 ffewhere_line_kill (ffelex_current_wl_);
1947 ffewhere_column_kill (ffelex_current_wc_);
1948 return (ffelexHandler) ffelex_handler_;
1951 ffelex_next_line_ ();
1953 ffelex_bad_line_ = FALSE;
1955 /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
1957 while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
1958 || (lextype == FFELEX_typeERROR)
1959 || (lextype == FFELEX_typeSLASH)
1960 || (lextype == FFELEX_typeHASH))
1962 /* Test most frequent type of line first, etc. */
1963 if ((lextype == FFELEX_typeCOMMENT)
1964 || ((lextype == FFELEX_typeSLASH)
1965 && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
1967 /* Typical case (straight comment), just ignore rest of line. */
1968 comment_line: /* :::::::::::::::::::: */
1970 while ((c != '\n') && (c != EOF))
1971 c = getc (f);
1973 #if FFECOM_targetCURRENT == FFECOM_targetGCC
1974 else if (lextype == FFELEX_typeHASH)
1975 c = ffelex_hash_ (f);
1976 #endif
1977 else if (lextype == FFELEX_typeSLASH)
1979 /* SIDE-EFFECT ABOVE HAS HAPPENED. */
1980 ffelex_card_image_[0] = '/';
1981 ffelex_card_image_[1] = c;
1982 column = 2;
1983 goto bad_first_character; /* :::::::::::::::::::: */
1985 else
1986 /* typeERROR or unsupported typeHASH. */
1987 { /* Bad first character, get line and display
1988 it with message. */
1989 column = ffelex_image_char_ (c, 0);
1991 bad_first_character: /* :::::::::::::::::::: */
1993 ffelex_bad_line_ = TRUE;
1994 while (((c = getc (f)) != '\n') && (c != EOF))
1995 column = ffelex_image_char_ (c, column);
1996 ffelex_card_image_[column] = '\0';
1997 ffelex_card_length_ = column;
1998 ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
1999 ffelex_linecount_current_, 1);
2002 /* Read past last char in line. */
2004 if (c == EOF)
2006 ffelex_next_line_ ();
2007 goto end_of_file; /* :::::::::::::::::::: */
2010 c = getc (f);
2012 ffelex_next_line_ ();
2014 if (c == EOF)
2015 goto end_of_file; /* :::::::::::::::::::: */
2017 ffelex_bad_line_ = FALSE;
2018 } /* while [c, first char, means comment] */
2020 ffelex_saw_tab_
2021 = (c == '&')
2022 || (ffelex_final_nontab_column_ == 0);
2024 if (lextype == FFELEX_typeDEBUG)
2025 c = ' '; /* A 'D' or 'd' in column 1 with the
2026 debug-lines option on. */
2028 column = ffelex_image_char_ (c, 0);
2030 /* Read the entire line in as is (with whitespace processing). */
2032 while (((c = getc (f)) != '\n') && (c != EOF))
2033 column = ffelex_image_char_ (c, column);
2035 if (ffelex_bad_line_)
2037 ffelex_card_image_[column] = '\0';
2038 ffelex_card_length_ = column;
2039 goto comment_line; /* :::::::::::::::::::: */
2042 /* If no tab, cut off line after column 72/132. */
2044 if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
2046 /* Technically, we should now fill ffelex_card_image_ up thru column
2047 72/132 with spaces, since character/hollerith constants must count
2048 them in that manner. To save CPU time in several ways (avoid a loop
2049 here that would be used only when we actually end a line in
2050 character-constant mode; avoid writing memory unnecessarily; avoid a
2051 loop later checking spaces when not scanning for character-constant
2052 characters), we don't do this, and we do the appropriate thing when
2053 we encounter end-of-line while actually processing a character
2054 constant. */
2056 column = ffelex_final_nontab_column_;
2059 have_line: /* :::::::::::::::::::: */
2061 ffelex_card_image_[column] = '\0';
2062 ffelex_card_length_ = column;
2064 /* Save next char in file so we can use register-based c while analyzing
2065 line we just read. */
2067 latest_char_in_file = c; /* Should be either '\n' or EOF. */
2069 have_content = FALSE;
2071 /* Handle label, if any. */
2073 labi = 0;
2074 first_label_char = FFEWHERE_columnUNKNOWN;
2075 for (column = 0; column < 5; ++column)
2077 switch (c = ffelex_card_image_[column])
2079 case '\0':
2080 case '!':
2081 goto stop_looking; /* :::::::::::::::::::: */
2083 case ' ':
2084 break;
2086 case '0':
2087 case '1':
2088 case '2':
2089 case '3':
2090 case '4':
2091 case '5':
2092 case '6':
2093 case '7':
2094 case '8':
2095 case '9':
2096 label_string[labi++] = c;
2097 if (first_label_char == FFEWHERE_columnUNKNOWN)
2098 first_label_char = column + 1;
2099 break;
2101 case '&':
2102 if (column != 0)
2104 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2105 ffelex_linecount_current_,
2106 column + 1);
2107 goto beginning_of_line_again; /* :::::::::::::::::::: */
2109 if (ffe_is_pedantic ())
2110 ffelex_bad_1_ (FFEBAD_AMPERSAND,
2111 ffelex_linecount_current_, 1);
2112 finish_statement = FALSE;
2113 just_do_label = FALSE;
2114 goto got_a_continuation; /* :::::::::::::::::::: */
2116 case '/':
2117 if (ffelex_card_image_[column + 1] == '*')
2118 goto stop_looking; /* :::::::::::::::::::: */
2119 /* Fall through. */
2120 default:
2121 ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
2122 ffelex_linecount_current_, column + 1);
2123 goto beginning_of_line_again; /* :::::::::::::::::::: */
2127 stop_looking: /* :::::::::::::::::::: */
2129 label_string[labi] = '\0';
2131 /* Find first nonblank char starting with continuation column. */
2133 if (column == 5) /* In which case we didn't see end of line in
2134 label field. */
2135 while ((c = ffelex_card_image_[column]) == ' ')
2136 ++column;
2138 /* Now we're trying to figure out whether this is a continuation line and
2139 whether there's anything else of substance on the line. The cases are
2140 as follows:
2142 1. If a line has an explicit continuation character (other than the digit
2143 zero), then if it also has a label, the label is ignored and an error
2144 message is printed. Any remaining text on the line is passed to the
2145 parser tasks, thus even an all-blank line (possibly with an ignored
2146 label) aside from a positive continuation character might have meaning
2147 in the midst of a character or hollerith constant.
2149 2. If a line has no explicit continuation character (that is, it has a
2150 space in column 6 and the first non-space character past column 6 is
2151 not a digit 0-9), then there are two possibilities:
2153 A. A label is present and/or a non-space (and non-comment) character
2154 appears somewhere after column 6. Terminate processing of the previous
2155 statement, if any, send the new label for the next statement, if any,
2156 and start processing a new statement with this non-blank character, if
2157 any.
2159 B. The line is essentially blank, except for a possible comment character.
2160 Don't terminate processing of the previous statement and don't pass any
2161 characters to the parser tasks, since the line is not flagged as a
2162 continuation line. We treat it just like a completely blank line.
2164 3. If a line has a continuation character of zero (0), then we terminate
2165 processing of the previous statement, if any, send the new label for the
2166 next statement, if any, and start processing a new statement, if any
2167 non-blank characters are present.
2169 If, when checking to see if we should terminate the previous statement, it
2170 is found that there is no previous statement but that there is an
2171 outstanding label, substitute CONTINUE as the statement for the label
2172 and display an error message. */
2174 finish_statement = FALSE;
2175 just_do_label = FALSE;
2177 switch (c)
2179 case '!': /* ANSI Fortran 90 says ! in column 6 is
2180 continuation. */
2181 /* VXT Fortran says ! anywhere is comment, even column 6. */
2182 if (ffe_is_vxt () || (column != 5))
2183 goto no_tokens_on_line; /* :::::::::::::::::::: */
2184 goto got_a_continuation; /* :::::::::::::::::::: */
2186 case '/':
2187 if (ffelex_card_image_[column + 1] != '*')
2188 goto some_other_character; /* :::::::::::::::::::: */
2189 /* Fall through. */
2190 if (column == 5)
2192 /* This seems right to do. But it is close to call, since / * starting
2193 in column 6 will thus be interpreted as a continuation line
2194 beginning with '*'. */
2196 goto got_a_continuation;/* :::::::::::::::::::: */
2198 /* Fall through. */
2199 case '\0':
2200 /* End of line. Therefore may be continued-through line, so handle
2201 pending label as possible to-be-continued and drive end-of-statement
2202 for any previous statement, else treat as blank line. */
2204 no_tokens_on_line: /* :::::::::::::::::::: */
2206 if (ffe_is_pedantic () && (c == '/'))
2207 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2208 ffelex_linecount_current_, column + 1);
2209 if (first_label_char != FFEWHERE_columnUNKNOWN)
2210 { /* Can't be a continued-through line if it
2211 has a label. */
2212 finish_statement = TRUE;
2213 have_content = TRUE;
2214 just_do_label = TRUE;
2215 break;
2217 goto beginning_of_line_again; /* :::::::::::::::::::: */
2219 case '0':
2220 if (ffe_is_pedantic () && (column != 5))
2221 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2222 ffelex_linecount_current_, column + 1);
2223 finish_statement = TRUE;
2224 goto check_for_content; /* :::::::::::::::::::: */
2226 case '1':
2227 case '2':
2228 case '3':
2229 case '4':
2230 case '5':
2231 case '6':
2232 case '7':
2233 case '8':
2234 case '9':
2236 /* NOTE: This label can be reached directly from the code
2237 that lexes the label field in columns 1-5. */
2238 got_a_continuation: /* :::::::::::::::::::: */
2240 if (first_label_char != FFEWHERE_columnUNKNOWN)
2242 ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
2243 ffelex_linecount_current_,
2244 first_label_char,
2245 ffelex_linecount_current_,
2246 column + 1);
2247 first_label_char = FFEWHERE_columnUNKNOWN;
2249 if (disallow_continuation_line)
2251 if (!ignore_disallowed_continuation)
2252 ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
2253 ffelex_linecount_current_, column + 1);
2254 goto beginning_of_line_again; /* :::::::::::::::::::: */
2256 if (ffe_is_pedantic () && (column != 5))
2257 ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
2258 ffelex_linecount_current_, column + 1);
2259 if ((ffelex_raw_mode_ != 0)
2260 && (((c = ffelex_card_image_[column + 1]) != '\0')
2261 || !ffelex_saw_tab_))
2263 ++column;
2264 have_content = TRUE;
2265 break;
2268 check_for_content: /* :::::::::::::::::::: */
2270 while ((c = ffelex_card_image_[++column]) == ' ')
2272 if ((c == '\0')
2273 || (c == '!')
2274 || ((c == '/')
2275 && (ffelex_card_image_[column + 1] == '*')))
2277 if (ffe_is_pedantic () && (c == '/'))
2278 ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
2279 ffelex_linecount_current_, column + 1);
2280 just_do_label = TRUE;
2282 else
2283 have_content = TRUE;
2284 break;
2286 default:
2288 some_other_character: /* :::::::::::::::::::: */
2290 if (column == 5)
2291 goto got_a_continuation;/* :::::::::::::::::::: */
2293 /* Here is the very normal case of a regular character starting in
2294 column 7 or beyond with a blank in column 6. */
2296 finish_statement = TRUE;
2297 have_content = TRUE;
2298 break;
2301 if (have_content
2302 || (first_label_char != FFEWHERE_columnUNKNOWN))
2304 /* The line has content of some kind, install new end-statement
2305 point for error messages. Note that "content" includes cases
2306 where there's little apparent content but enough to finish
2307 a statement. That's because finishing a statement can trigger
2308 an impending INCLUDE, and that requires accurate line info being
2309 maintained by the lexer. */
2311 if (finish_statement)
2312 ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
2314 ffewhere_line_kill (ffelex_current_wl_);
2315 ffewhere_column_kill (ffelex_current_wc_);
2316 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
2317 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
2320 /* We delay this for a combination of reasons. Mainly, it can start
2321 INCLUDE processing, and we want to delay that until the lexer's
2322 info on the line is coherent. And we want to delay that until we're
2323 sure there's a reason to make that info coherent, to avoid saving
2324 lots of useless lines. */
2326 if (finish_statement)
2327 ffelex_finish_statement_ ();
2329 /* If label is present, enclose it in a NUMBER token and send it along. */
2331 if (first_label_char != FFEWHERE_columnUNKNOWN)
2333 assert (ffelex_token_->type == FFELEX_typeNONE);
2334 ffelex_token_->type = FFELEX_typeNUMBER;
2335 ffelex_append_to_token_ ('\0'); /* Make room for label text. */
2336 strcpy (ffelex_token_->text, label_string);
2337 ffelex_token_->where_line
2338 = ffewhere_line_use (ffelex_current_wl_);
2339 ffelex_token_->where_col = ffewhere_column_new (first_label_char);
2340 ffelex_token_->length = labi;
2341 ffelex_send_token_ ();
2342 ++ffelex_label_tokens_;
2345 if (just_do_label)
2346 goto beginning_of_line; /* :::::::::::::::::::: */
2348 /* Here is the main engine for parsing. c holds the character at column.
2349 It is already known that c is not a blank, end of line, or shriek,
2350 unless ffelex_raw_mode_ is not 0 (indicating we are in a
2351 character/hollerith constant). A partially filled token may already
2352 exist in ffelex_token_. One special case: if, when the end of the line
2353 is reached, continuation_line is FALSE and the only token on the line is
2354 END, then it is indeed the last statement. We don't look for
2355 continuation lines during this program unit in that case. This is
2356 according to ANSI. */
2358 if (ffelex_raw_mode_ != 0)
2361 parse_raw_character: /* :::::::::::::::::::: */
2363 if (c == '\0')
2365 ffewhereColumnNumber i;
2367 if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
2368 goto beginning_of_line; /* :::::::::::::::::::: */
2370 /* Pad out line with "virtual" spaces. */
2372 for (i = column; i < ffelex_final_nontab_column_; ++i)
2373 ffelex_card_image_[i] = ' ';
2374 ffelex_card_image_[i] = '\0';
2375 ffelex_card_length_ = i;
2376 c = ' ';
2379 switch (ffelex_raw_mode_)
2381 case -3:
2382 c = ffelex_backslash_ (c, column);
2383 if (c == EOF)
2384 break;
2386 if (!ffelex_backslash_reconsider_)
2387 ffelex_append_to_token_ (c);
2388 ffelex_raw_mode_ = -1;
2389 break;
2391 case -2:
2392 if (c == ffelex_raw_char_)
2394 ffelex_raw_mode_ = -1;
2395 ffelex_append_to_token_ (c);
2397 else
2399 ffelex_raw_mode_ = 0;
2400 ffelex_backslash_reconsider_ = TRUE;
2402 break;
2404 case -1:
2405 if (c == ffelex_raw_char_)
2406 ffelex_raw_mode_ = -2;
2407 else
2409 c = ffelex_backslash_ (c, column);
2410 if (c == EOF)
2412 ffelex_raw_mode_ = -3;
2413 break;
2416 ffelex_append_to_token_ (c);
2418 break;
2420 default:
2421 c = ffelex_backslash_ (c, column);
2422 if (c == EOF)
2423 break;
2425 if (!ffelex_backslash_reconsider_)
2427 ffelex_append_to_token_ (c);
2428 --ffelex_raw_mode_;
2430 break;
2433 if (ffelex_backslash_reconsider_)
2434 ffelex_backslash_reconsider_ = FALSE;
2435 else
2436 c = ffelex_card_image_[++column];
2438 if (ffelex_raw_mode_ == 0)
2440 ffelex_send_token_ ();
2441 assert (ffelex_raw_mode_ == 0);
2442 while (c == ' ')
2443 c = ffelex_card_image_[++column];
2444 if ((c == '\0')
2445 || (c == '!')
2446 || ((c == '/')
2447 && (ffelex_card_image_[column + 1] == '*')))
2448 goto beginning_of_line; /* :::::::::::::::::::: */
2449 goto parse_nonraw_character; /* :::::::::::::::::::: */
2451 goto parse_raw_character; /* :::::::::::::::::::: */
2454 parse_nonraw_character: /* :::::::::::::::::::: */
2456 switch (ffelex_token_->type)
2458 case FFELEX_typeNONE:
2459 switch (c)
2461 case '\"':
2462 ffelex_token_->type = FFELEX_typeQUOTE;
2463 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2464 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2465 ffelex_send_token_ ();
2466 break;
2468 case '$':
2469 ffelex_token_->type = FFELEX_typeDOLLAR;
2470 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2471 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2472 ffelex_send_token_ ();
2473 break;
2475 case '%':
2476 ffelex_token_->type = FFELEX_typePERCENT;
2477 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2478 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2479 ffelex_send_token_ ();
2480 break;
2482 case '&':
2483 ffelex_token_->type = FFELEX_typeAMPERSAND;
2484 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2485 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2486 ffelex_send_token_ ();
2487 break;
2489 case '\'':
2490 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
2491 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2492 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2493 ffelex_send_token_ ();
2494 break;
2496 case '(':
2497 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
2498 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2499 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2500 break;
2502 case ')':
2503 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
2504 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2505 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2506 ffelex_send_token_ ();
2507 break;
2509 case '*':
2510 ffelex_token_->type = FFELEX_typeASTERISK;
2511 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2512 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2513 break;
2515 case '+':
2516 ffelex_token_->type = FFELEX_typePLUS;
2517 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2518 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2519 ffelex_send_token_ ();
2520 break;
2522 case ',':
2523 ffelex_token_->type = FFELEX_typeCOMMA;
2524 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2525 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2526 ffelex_send_token_ ();
2527 break;
2529 case '-':
2530 ffelex_token_->type = FFELEX_typeMINUS;
2531 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2532 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2533 ffelex_send_token_ ();
2534 break;
2536 case '.':
2537 ffelex_token_->type = FFELEX_typePERIOD;
2538 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2539 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2540 ffelex_send_token_ ();
2541 break;
2543 case '/':
2544 ffelex_token_->type = FFELEX_typeSLASH;
2545 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2546 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2547 break;
2549 case '0':
2550 case '1':
2551 case '2':
2552 case '3':
2553 case '4':
2554 case '5':
2555 case '6':
2556 case '7':
2557 case '8':
2558 case '9':
2559 ffelex_token_->type
2560 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
2561 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2562 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2563 ffelex_append_to_token_ (c);
2564 break;
2566 case ':':
2567 ffelex_token_->type = FFELEX_typeCOLON;
2568 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2569 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2570 break;
2572 case ';':
2573 ffelex_token_->type = FFELEX_typeSEMICOLON;
2574 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2575 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2576 ffelex_permit_include_ = TRUE;
2577 ffelex_send_token_ ();
2578 ffelex_permit_include_ = FALSE;
2579 break;
2581 case '<':
2582 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
2583 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2584 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2585 break;
2587 case '=':
2588 ffelex_token_->type = FFELEX_typeEQUALS;
2589 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2590 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2591 break;
2593 case '>':
2594 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
2595 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2596 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2597 break;
2599 case '?':
2600 ffelex_token_->type = FFELEX_typeQUESTION;
2601 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
2602 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2603 ffelex_send_token_ ();
2604 break;
2606 case '_':
2607 if (1 || ffe_is_90 ())
2609 ffelex_token_->type = FFELEX_typeUNDERSCORE;
2610 ffelex_token_->where_line
2611 = ffewhere_line_use (ffelex_current_wl_);
2612 ffelex_token_->where_col
2613 = ffewhere_column_new (column + 1);
2614 ffelex_send_token_ ();
2615 break;
2617 /* Fall through. */
2618 case 'A':
2619 case 'B':
2620 case 'C':
2621 case 'D':
2622 case 'E':
2623 case 'F':
2624 case 'G':
2625 case 'H':
2626 case 'I':
2627 case 'J':
2628 case 'K':
2629 case 'L':
2630 case 'M':
2631 case 'N':
2632 case 'O':
2633 case 'P':
2634 case 'Q':
2635 case 'R':
2636 case 'S':
2637 case 'T':
2638 case 'U':
2639 case 'V':
2640 case 'W':
2641 case 'X':
2642 case 'Y':
2643 case 'Z':
2644 case 'a':
2645 case 'b':
2646 case 'c':
2647 case 'd':
2648 case 'e':
2649 case 'f':
2650 case 'g':
2651 case 'h':
2652 case 'i':
2653 case 'j':
2654 case 'k':
2655 case 'l':
2656 case 'm':
2657 case 'n':
2658 case 'o':
2659 case 'p':
2660 case 'q':
2661 case 'r':
2662 case 's':
2663 case 't':
2664 case 'u':
2665 case 'v':
2666 case 'w':
2667 case 'x':
2668 case 'y':
2669 case 'z':
2670 c = ffesrc_char_source (c);
2672 if (ffesrc_char_match_init (c, 'H', 'h')
2673 && ffelex_expecting_hollerith_ != 0)
2675 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
2676 ffelex_token_->type = FFELEX_typeHOLLERITH;
2677 ffelex_token_->where_line = ffelex_raw_where_line_;
2678 ffelex_token_->where_col = ffelex_raw_where_col_;
2679 ffelex_raw_where_line_ = ffewhere_line_unknown ();
2680 ffelex_raw_where_col_ = ffewhere_column_unknown ();
2681 c = ffelex_card_image_[++column];
2682 goto parse_raw_character; /* :::::::::::::::::::: */
2685 if (ffelex_names_)
2687 ffelex_token_->where_line
2688 = ffewhere_line_use (ffelex_token_->currentnames_line
2689 = ffewhere_line_use (ffelex_current_wl_));
2690 ffelex_token_->where_col
2691 = ffewhere_column_use (ffelex_token_->currentnames_col
2692 = ffewhere_column_new (column + 1));
2693 ffelex_token_->type = FFELEX_typeNAMES;
2695 else
2697 ffelex_token_->where_line
2698 = ffewhere_line_use (ffelex_current_wl_);
2699 ffelex_token_->where_col = ffewhere_column_new (column + 1);
2700 ffelex_token_->type = FFELEX_typeNAME;
2702 ffelex_append_to_token_ (c);
2703 break;
2705 default:
2706 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
2707 ffelex_linecount_current_, column + 1);
2708 ffelex_finish_statement_ ();
2709 disallow_continuation_line = TRUE;
2710 ignore_disallowed_continuation = TRUE;
2711 goto beginning_of_line_again; /* :::::::::::::::::::: */
2713 break;
2715 case FFELEX_typeNAME:
2716 switch (c)
2718 case 'A':
2719 case 'B':
2720 case 'C':
2721 case 'D':
2722 case 'E':
2723 case 'F':
2724 case 'G':
2725 case 'H':
2726 case 'I':
2727 case 'J':
2728 case 'K':
2729 case 'L':
2730 case 'M':
2731 case 'N':
2732 case 'O':
2733 case 'P':
2734 case 'Q':
2735 case 'R':
2736 case 'S':
2737 case 'T':
2738 case 'U':
2739 case 'V':
2740 case 'W':
2741 case 'X':
2742 case 'Y':
2743 case 'Z':
2744 case 'a':
2745 case 'b':
2746 case 'c':
2747 case 'd':
2748 case 'e':
2749 case 'f':
2750 case 'g':
2751 case 'h':
2752 case 'i':
2753 case 'j':
2754 case 'k':
2755 case 'l':
2756 case 'm':
2757 case 'n':
2758 case 'o':
2759 case 'p':
2760 case 'q':
2761 case 'r':
2762 case 's':
2763 case 't':
2764 case 'u':
2765 case 'v':
2766 case 'w':
2767 case 'x':
2768 case 'y':
2769 case 'z':
2770 c = ffesrc_char_source (c);
2771 /* Fall through. */
2772 case '0':
2773 case '1':
2774 case '2':
2775 case '3':
2776 case '4':
2777 case '5':
2778 case '6':
2779 case '7':
2780 case '8':
2781 case '9':
2782 case '_':
2783 case '$':
2784 if ((c == '$')
2785 && !ffe_is_dollar_ok ())
2787 ffelex_send_token_ ();
2788 goto parse_next_character; /* :::::::::::::::::::: */
2790 ffelex_append_to_token_ (c);
2791 break;
2793 default:
2794 ffelex_send_token_ ();
2795 goto parse_next_character; /* :::::::::::::::::::: */
2797 break;
2799 case FFELEX_typeNAMES:
2800 switch (c)
2802 case 'A':
2803 case 'B':
2804 case 'C':
2805 case 'D':
2806 case 'E':
2807 case 'F':
2808 case 'G':
2809 case 'H':
2810 case 'I':
2811 case 'J':
2812 case 'K':
2813 case 'L':
2814 case 'M':
2815 case 'N':
2816 case 'O':
2817 case 'P':
2818 case 'Q':
2819 case 'R':
2820 case 'S':
2821 case 'T':
2822 case 'U':
2823 case 'V':
2824 case 'W':
2825 case 'X':
2826 case 'Y':
2827 case 'Z':
2828 case 'a':
2829 case 'b':
2830 case 'c':
2831 case 'd':
2832 case 'e':
2833 case 'f':
2834 case 'g':
2835 case 'h':
2836 case 'i':
2837 case 'j':
2838 case 'k':
2839 case 'l':
2840 case 'm':
2841 case 'n':
2842 case 'o':
2843 case 'p':
2844 case 'q':
2845 case 'r':
2846 case 's':
2847 case 't':
2848 case 'u':
2849 case 'v':
2850 case 'w':
2851 case 'x':
2852 case 'y':
2853 case 'z':
2854 c = ffesrc_char_source (c);
2855 /* Fall through. */
2856 case '0':
2857 case '1':
2858 case '2':
2859 case '3':
2860 case '4':
2861 case '5':
2862 case '6':
2863 case '7':
2864 case '8':
2865 case '9':
2866 case '_':
2867 case '$':
2868 if ((c == '$')
2869 && !ffe_is_dollar_ok ())
2871 ffelex_send_token_ ();
2872 goto parse_next_character; /* :::::::::::::::::::: */
2874 if (ffelex_token_->length < FFEWHERE_indexMAX)
2876 ffewhere_track (&ffelex_token_->currentnames_line,
2877 &ffelex_token_->currentnames_col,
2878 ffelex_token_->wheretrack,
2879 ffelex_token_->length,
2880 ffelex_linecount_current_,
2881 column + 1);
2883 ffelex_append_to_token_ (c);
2884 break;
2886 default:
2887 ffelex_send_token_ ();
2888 goto parse_next_character; /* :::::::::::::::::::: */
2890 break;
2892 case FFELEX_typeNUMBER:
2893 switch (c)
2895 case '0':
2896 case '1':
2897 case '2':
2898 case '3':
2899 case '4':
2900 case '5':
2901 case '6':
2902 case '7':
2903 case '8':
2904 case '9':
2905 ffelex_append_to_token_ (c);
2906 break;
2908 default:
2909 ffelex_send_token_ ();
2910 goto parse_next_character; /* :::::::::::::::::::: */
2912 break;
2914 case FFELEX_typeASTERISK:
2915 switch (c)
2917 case '*': /* ** */
2918 ffelex_token_->type = FFELEX_typePOWER;
2919 ffelex_send_token_ ();
2920 break;
2922 default: /* * not followed by another *. */
2923 ffelex_send_token_ ();
2924 goto parse_next_character; /* :::::::::::::::::::: */
2926 break;
2928 case FFELEX_typeCOLON:
2929 switch (c)
2931 case ':': /* :: */
2932 ffelex_token_->type = FFELEX_typeCOLONCOLON;
2933 ffelex_send_token_ ();
2934 break;
2936 default: /* : not followed by another :. */
2937 ffelex_send_token_ ();
2938 goto parse_next_character; /* :::::::::::::::::::: */
2940 break;
2942 case FFELEX_typeSLASH:
2943 switch (c)
2945 case '/': /* // */
2946 ffelex_token_->type = FFELEX_typeCONCAT;
2947 ffelex_send_token_ ();
2948 break;
2950 case ')': /* /) */
2951 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
2952 ffelex_send_token_ ();
2953 break;
2955 case '=': /* /= */
2956 ffelex_token_->type = FFELEX_typeREL_NE;
2957 ffelex_send_token_ ();
2958 break;
2960 default:
2961 ffelex_send_token_ ();
2962 goto parse_next_character; /* :::::::::::::::::::: */
2964 break;
2966 case FFELEX_typeOPEN_PAREN:
2967 switch (c)
2969 case '/': /* (/ */
2970 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
2971 ffelex_send_token_ ();
2972 break;
2974 default:
2975 ffelex_send_token_ ();
2976 goto parse_next_character; /* :::::::::::::::::::: */
2978 break;
2980 case FFELEX_typeOPEN_ANGLE:
2981 switch (c)
2983 case '=': /* <= */
2984 ffelex_token_->type = FFELEX_typeREL_LE;
2985 ffelex_send_token_ ();
2986 break;
2988 default:
2989 ffelex_send_token_ ();
2990 goto parse_next_character; /* :::::::::::::::::::: */
2992 break;
2994 case FFELEX_typeEQUALS:
2995 switch (c)
2997 case '=': /* == */
2998 ffelex_token_->type = FFELEX_typeREL_EQ;
2999 ffelex_send_token_ ();
3000 break;
3002 case '>': /* => */
3003 ffelex_token_->type = FFELEX_typePOINTS;
3004 ffelex_send_token_ ();
3005 break;
3007 default:
3008 ffelex_send_token_ ();
3009 goto parse_next_character; /* :::::::::::::::::::: */
3011 break;
3013 case FFELEX_typeCLOSE_ANGLE:
3014 switch (c)
3016 case '=': /* >= */
3017 ffelex_token_->type = FFELEX_typeREL_GE;
3018 ffelex_send_token_ ();
3019 break;
3021 default:
3022 ffelex_send_token_ ();
3023 goto parse_next_character; /* :::::::::::::::::::: */
3025 break;
3027 default:
3028 assert ("Serious error!!" == NULL);
3029 abort ();
3030 break;
3033 c = ffelex_card_image_[++column];
3035 parse_next_character: /* :::::::::::::::::::: */
3037 if (ffelex_raw_mode_ != 0)
3038 goto parse_raw_character; /* :::::::::::::::::::: */
3040 while (c == ' ')
3041 c = ffelex_card_image_[++column];
3043 if ((c == '\0')
3044 || (c == '!')
3045 || ((c == '/')
3046 && (ffelex_card_image_[column + 1] == '*')))
3048 if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
3049 && (ffelex_token_->type == FFELEX_typeNAMES)
3050 && (ffelex_token_->length == 3)
3051 && (ffesrc_strncmp_2c (ffe_case_match (),
3052 ffelex_token_->text,
3053 "END", "end", "End",
3055 == 0))
3057 ffelex_finish_statement_ ();
3058 disallow_continuation_line = TRUE;
3059 ignore_disallowed_continuation = FALSE;
3060 goto beginning_of_line_again; /* :::::::::::::::::::: */
3062 goto beginning_of_line; /* :::::::::::::::::::: */
3064 goto parse_nonraw_character; /* :::::::::::::::::::: */
3067 /* ffelex_file_free -- Lex a given file in free source form
3069 ffewhere wf;
3070 FILE *f;
3071 ffelex_file_free(wf,f);
3073 Lexes the file according to Fortran 90 ANSI + VXT specifications. */
3075 ffelexHandler
3076 ffelex_file_free (ffewhereFile wf, FILE *f)
3078 register int c = 0; /* Character currently under consideration. */
3079 register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
3080 bool continuation_line = FALSE;
3081 ffewhereColumnNumber continuation_column;
3082 int latest_char_in_file = 0; /* For getting back into comment-skipping
3083 code. */
3085 /* Lex is called for a particular file, not for a particular program unit.
3086 Yet the two events do share common characteristics. The first line in a
3087 file or in a program unit cannot be a continuation line. No token can
3088 be in mid-formation. No current label for the statement exists, since
3089 there is no current statement. */
3091 assert (ffelex_handler_ != NULL);
3093 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3094 lineno = 0;
3095 input_filename = ffewhere_file_name (wf);
3096 #endif
3097 ffelex_current_wf_ = wf;
3098 continuation_line = FALSE;
3099 ffelex_token_->type = FFELEX_typeNONE;
3100 ffelex_number_of_tokens_ = 0;
3101 ffelex_current_wl_ = ffewhere_line_unknown ();
3102 ffelex_current_wc_ = ffewhere_column_unknown ();
3103 latest_char_in_file = '\n';
3105 /* Come here to get a new line. */
3107 beginning_of_line: /* :::::::::::::::::::: */
3109 c = latest_char_in_file;
3110 if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
3113 end_of_file: /* :::::::::::::::::::: */
3115 /* Line ending in EOF instead of \n still counts as a whole line. */
3117 ffelex_finish_statement_ ();
3118 ffewhere_line_kill (ffelex_current_wl_);
3119 ffewhere_column_kill (ffelex_current_wc_);
3120 return (ffelexHandler) ffelex_handler_;
3123 ffelex_next_line_ ();
3125 ffelex_bad_line_ = FALSE;
3127 /* Skip over initial-comment and empty lines as quickly as possible! */
3129 while ((c == '\n')
3130 || (c == '!')
3131 || (c == '#'))
3133 if (c == '#')
3135 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3136 c = ffelex_hash_ (f);
3137 #else
3138 /* Don't skip over # line after all. */
3139 break;
3140 #endif
3143 comment_line: /* :::::::::::::::::::: */
3145 while ((c != '\n') && (c != EOF))
3146 c = getc (f);
3148 if (c == EOF)
3150 ffelex_next_line_ ();
3151 goto end_of_file; /* :::::::::::::::::::: */
3154 c = getc (f);
3156 ffelex_next_line_ ();
3158 if (c == EOF)
3159 goto end_of_file; /* :::::::::::::::::::: */
3162 ffelex_saw_tab_ = FALSE;
3164 column = ffelex_image_char_ (c, 0);
3166 /* Read the entire line in as is (with whitespace processing). */
3168 while (((c = getc (f)) != '\n') && (c != EOF))
3169 column = ffelex_image_char_ (c, column);
3171 if (ffelex_bad_line_)
3173 ffelex_card_image_[column] = '\0';
3174 ffelex_card_length_ = column;
3175 goto comment_line; /* :::::::::::::::::::: */
3178 /* If no tab, cut off line after column 132. */
3180 if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
3181 column = FFELEX_FREE_MAX_COLUMNS_;
3183 ffelex_card_image_[column] = '\0';
3184 ffelex_card_length_ = column;
3186 /* Save next char in file so we can use register-based c while analyzing
3187 line we just read. */
3189 latest_char_in_file = c; /* Should be either '\n' or EOF. */
3191 column = 0;
3192 continuation_column = 0;
3194 /* Skip over initial spaces to see if the first nonblank character
3195 is exclamation point, newline, or EOF (line is therefore a comment) or
3196 ampersand (line is therefore a continuation line). */
3198 while ((c = ffelex_card_image_[column]) == ' ')
3199 ++column;
3201 switch (c)
3203 case '!':
3204 case '\0':
3205 goto beginning_of_line; /* :::::::::::::::::::: */
3207 case '&':
3208 continuation_column = column + 1;
3209 break;
3211 default:
3212 break;
3215 /* The line definitely has content of some kind, install new end-statement
3216 point for error messages. */
3218 ffewhere_line_kill (ffelex_current_wl_);
3219 ffewhere_column_kill (ffelex_current_wc_);
3220 ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
3221 ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
3223 /* Figure out which column to start parsing at. */
3225 if (continuation_line)
3227 if (continuation_column == 0)
3229 if (ffelex_raw_mode_ != 0)
3231 ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
3232 ffelex_linecount_current_, column + 1);
3234 else if (ffelex_token_->type != FFELEX_typeNONE)
3236 ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
3237 ffelex_linecount_current_, column + 1);
3240 else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
3241 { /* Line contains only a single "&" as only
3242 nonblank character. */
3243 ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
3244 ffelex_linecount_current_, continuation_column);
3245 goto beginning_of_line; /* :::::::::::::::::::: */
3247 column = continuation_column;
3249 else
3250 column = 0;
3252 c = ffelex_card_image_[column];
3253 continuation_line = FALSE;
3255 /* Here is the main engine for parsing. c holds the character at column.
3256 It is already known that c is not a blank, end of line, or shriek,
3257 unless ffelex_raw_mode_ is not 0 (indicating we are in a
3258 character/hollerith constant). A partially filled token may already
3259 exist in ffelex_token_. */
3261 if (ffelex_raw_mode_ != 0)
3264 parse_raw_character: /* :::::::::::::::::::: */
3266 switch (c)
3268 case '&':
3269 if (ffelex_is_free_char_ctx_contin_ (column + 1))
3271 continuation_line = TRUE;
3272 goto beginning_of_line; /* :::::::::::::::::::: */
3274 break;
3276 case '\0':
3277 ffelex_finish_statement_ ();
3278 goto beginning_of_line; /* :::::::::::::::::::: */
3280 default:
3281 break;
3284 switch (ffelex_raw_mode_)
3286 case -3:
3287 c = ffelex_backslash_ (c, column);
3288 if (c == EOF)
3289 break;
3291 if (!ffelex_backslash_reconsider_)
3292 ffelex_append_to_token_ (c);
3293 ffelex_raw_mode_ = -1;
3294 break;
3296 case -2:
3297 if (c == ffelex_raw_char_)
3299 ffelex_raw_mode_ = -1;
3300 ffelex_append_to_token_ (c);
3302 else
3304 ffelex_raw_mode_ = 0;
3305 ffelex_backslash_reconsider_ = TRUE;
3307 break;
3309 case -1:
3310 if (c == ffelex_raw_char_)
3311 ffelex_raw_mode_ = -2;
3312 else
3314 c = ffelex_backslash_ (c, column);
3315 if (c == EOF)
3317 ffelex_raw_mode_ = -3;
3318 break;
3321 ffelex_append_to_token_ (c);
3323 break;
3325 default:
3326 c = ffelex_backslash_ (c, column);
3327 if (c == EOF)
3328 break;
3330 if (!ffelex_backslash_reconsider_)
3332 ffelex_append_to_token_ (c);
3333 --ffelex_raw_mode_;
3335 break;
3338 if (ffelex_backslash_reconsider_)
3339 ffelex_backslash_reconsider_ = FALSE;
3340 else
3341 c = ffelex_card_image_[++column];
3343 if (ffelex_raw_mode_ == 0)
3345 ffelex_send_token_ ();
3346 assert (ffelex_raw_mode_ == 0);
3347 while (c == ' ')
3348 c = ffelex_card_image_[++column];
3349 if ((c == '\0') || (c == '!'))
3351 ffelex_finish_statement_ ();
3352 goto beginning_of_line; /* :::::::::::::::::::: */
3354 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3356 continuation_line = TRUE;
3357 goto beginning_of_line; /* :::::::::::::::::::: */
3359 goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
3361 goto parse_raw_character; /* :::::::::::::::::::: */
3364 parse_nonraw_character: /* :::::::::::::::::::: */
3366 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3368 continuation_line = TRUE;
3369 goto beginning_of_line; /* :::::::::::::::::::: */
3372 parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
3374 switch (ffelex_token_->type)
3376 case FFELEX_typeNONE:
3377 if (c == ' ')
3378 { /* Otherwise
3379 finish-statement/continue-statement
3380 already checked. */
3381 while (c == ' ')
3382 c = ffelex_card_image_[++column];
3383 if ((c == '\0') || (c == '!'))
3385 ffelex_finish_statement_ ();
3386 goto beginning_of_line; /* :::::::::::::::::::: */
3388 if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
3390 continuation_line = TRUE;
3391 goto beginning_of_line; /* :::::::::::::::::::: */
3395 switch (c)
3397 case '\"':
3398 ffelex_token_->type = FFELEX_typeQUOTE;
3399 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3400 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3401 ffelex_send_token_ ();
3402 break;
3404 case '$':
3405 ffelex_token_->type = FFELEX_typeDOLLAR;
3406 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3407 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3408 ffelex_send_token_ ();
3409 break;
3411 case '%':
3412 ffelex_token_->type = FFELEX_typePERCENT;
3413 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3414 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3415 ffelex_send_token_ ();
3416 break;
3418 case '&':
3419 ffelex_token_->type = FFELEX_typeAMPERSAND;
3420 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3421 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3422 ffelex_send_token_ ();
3423 break;
3425 case '\'':
3426 ffelex_token_->type = FFELEX_typeAPOSTROPHE;
3427 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3428 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3429 ffelex_send_token_ ();
3430 break;
3432 case '(':
3433 ffelex_token_->type = FFELEX_typeOPEN_PAREN;
3434 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3435 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3436 break;
3438 case ')':
3439 ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
3440 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3441 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3442 ffelex_send_token_ ();
3443 break;
3445 case '*':
3446 ffelex_token_->type = FFELEX_typeASTERISK;
3447 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3448 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3449 break;
3451 case '+':
3452 ffelex_token_->type = FFELEX_typePLUS;
3453 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3454 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3455 ffelex_send_token_ ();
3456 break;
3458 case ',':
3459 ffelex_token_->type = FFELEX_typeCOMMA;
3460 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3461 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3462 ffelex_send_token_ ();
3463 break;
3465 case '-':
3466 ffelex_token_->type = FFELEX_typeMINUS;
3467 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3468 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3469 ffelex_send_token_ ();
3470 break;
3472 case '.':
3473 ffelex_token_->type = FFELEX_typePERIOD;
3474 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3475 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3476 ffelex_send_token_ ();
3477 break;
3479 case '/':
3480 ffelex_token_->type = FFELEX_typeSLASH;
3481 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3482 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3483 break;
3485 case '0':
3486 case '1':
3487 case '2':
3488 case '3':
3489 case '4':
3490 case '5':
3491 case '6':
3492 case '7':
3493 case '8':
3494 case '9':
3495 ffelex_token_->type
3496 = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
3497 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3498 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3499 ffelex_append_to_token_ (c);
3500 break;
3502 case ':':
3503 ffelex_token_->type = FFELEX_typeCOLON;
3504 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3505 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3506 break;
3508 case ';':
3509 ffelex_token_->type = FFELEX_typeSEMICOLON;
3510 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3511 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3512 ffelex_permit_include_ = TRUE;
3513 ffelex_send_token_ ();
3514 ffelex_permit_include_ = FALSE;
3515 break;
3517 case '<':
3518 ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
3519 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3520 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3521 break;
3523 case '=':
3524 ffelex_token_->type = FFELEX_typeEQUALS;
3525 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3526 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3527 break;
3529 case '>':
3530 ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
3531 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3532 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3533 break;
3535 case '?':
3536 ffelex_token_->type = FFELEX_typeQUESTION;
3537 ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
3538 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3539 ffelex_send_token_ ();
3540 break;
3542 case '_':
3543 if (1 || ffe_is_90 ())
3545 ffelex_token_->type = FFELEX_typeUNDERSCORE;
3546 ffelex_token_->where_line
3547 = ffewhere_line_use (ffelex_current_wl_);
3548 ffelex_token_->where_col
3549 = ffewhere_column_new (column + 1);
3550 ffelex_send_token_ ();
3551 break;
3553 /* Fall through. */
3554 case 'A':
3555 case 'B':
3556 case 'C':
3557 case 'D':
3558 case 'E':
3559 case 'F':
3560 case 'G':
3561 case 'H':
3562 case 'I':
3563 case 'J':
3564 case 'K':
3565 case 'L':
3566 case 'M':
3567 case 'N':
3568 case 'O':
3569 case 'P':
3570 case 'Q':
3571 case 'R':
3572 case 'S':
3573 case 'T':
3574 case 'U':
3575 case 'V':
3576 case 'W':
3577 case 'X':
3578 case 'Y':
3579 case 'Z':
3580 case 'a':
3581 case 'b':
3582 case 'c':
3583 case 'd':
3584 case 'e':
3585 case 'f':
3586 case 'g':
3587 case 'h':
3588 case 'i':
3589 case 'j':
3590 case 'k':
3591 case 'l':
3592 case 'm':
3593 case 'n':
3594 case 'o':
3595 case 'p':
3596 case 'q':
3597 case 'r':
3598 case 's':
3599 case 't':
3600 case 'u':
3601 case 'v':
3602 case 'w':
3603 case 'x':
3604 case 'y':
3605 case 'z':
3606 c = ffesrc_char_source (c);
3608 if (ffesrc_char_match_init (c, 'H', 'h')
3609 && ffelex_expecting_hollerith_ != 0)
3611 ffelex_raw_mode_ = ffelex_expecting_hollerith_;
3612 ffelex_token_->type = FFELEX_typeHOLLERITH;
3613 ffelex_token_->where_line = ffelex_raw_where_line_;
3614 ffelex_token_->where_col = ffelex_raw_where_col_;
3615 ffelex_raw_where_line_ = ffewhere_line_unknown ();
3616 ffelex_raw_where_col_ = ffewhere_column_unknown ();
3617 c = ffelex_card_image_[++column];
3618 goto parse_raw_character; /* :::::::::::::::::::: */
3621 if (ffelex_names_pure_)
3623 ffelex_token_->where_line
3624 = ffewhere_line_use (ffelex_token_->currentnames_line
3625 = ffewhere_line_use (ffelex_current_wl_));
3626 ffelex_token_->where_col
3627 = ffewhere_column_use (ffelex_token_->currentnames_col
3628 = ffewhere_column_new (column + 1));
3629 ffelex_token_->type = FFELEX_typeNAMES;
3631 else
3633 ffelex_token_->where_line
3634 = ffewhere_line_use (ffelex_current_wl_);
3635 ffelex_token_->where_col = ffewhere_column_new (column + 1);
3636 ffelex_token_->type = FFELEX_typeNAME;
3638 ffelex_append_to_token_ (c);
3639 break;
3641 default:
3642 ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
3643 ffelex_linecount_current_, column + 1);
3644 ffelex_finish_statement_ ();
3645 goto beginning_of_line; /* :::::::::::::::::::: */
3647 break;
3649 case FFELEX_typeNAME:
3650 switch (c)
3652 case 'A':
3653 case 'B':
3654 case 'C':
3655 case 'D':
3656 case 'E':
3657 case 'F':
3658 case 'G':
3659 case 'H':
3660 case 'I':
3661 case 'J':
3662 case 'K':
3663 case 'L':
3664 case 'M':
3665 case 'N':
3666 case 'O':
3667 case 'P':
3668 case 'Q':
3669 case 'R':
3670 case 'S':
3671 case 'T':
3672 case 'U':
3673 case 'V':
3674 case 'W':
3675 case 'X':
3676 case 'Y':
3677 case 'Z':
3678 case 'a':
3679 case 'b':
3680 case 'c':
3681 case 'd':
3682 case 'e':
3683 case 'f':
3684 case 'g':
3685 case 'h':
3686 case 'i':
3687 case 'j':
3688 case 'k':
3689 case 'l':
3690 case 'm':
3691 case 'n':
3692 case 'o':
3693 case 'p':
3694 case 'q':
3695 case 'r':
3696 case 's':
3697 case 't':
3698 case 'u':
3699 case 'v':
3700 case 'w':
3701 case 'x':
3702 case 'y':
3703 case 'z':
3704 c = ffesrc_char_source (c);
3705 /* Fall through. */
3706 case '0':
3707 case '1':
3708 case '2':
3709 case '3':
3710 case '4':
3711 case '5':
3712 case '6':
3713 case '7':
3714 case '8':
3715 case '9':
3716 case '_':
3717 case '$':
3718 if ((c == '$')
3719 && !ffe_is_dollar_ok ())
3721 ffelex_send_token_ ();
3722 goto parse_next_character; /* :::::::::::::::::::: */
3724 ffelex_append_to_token_ (c);
3725 break;
3727 default:
3728 ffelex_send_token_ ();
3729 goto parse_next_character; /* :::::::::::::::::::: */
3731 break;
3733 case FFELEX_typeNAMES:
3734 switch (c)
3736 case 'A':
3737 case 'B':
3738 case 'C':
3739 case 'D':
3740 case 'E':
3741 case 'F':
3742 case 'G':
3743 case 'H':
3744 case 'I':
3745 case 'J':
3746 case 'K':
3747 case 'L':
3748 case 'M':
3749 case 'N':
3750 case 'O':
3751 case 'P':
3752 case 'Q':
3753 case 'R':
3754 case 'S':
3755 case 'T':
3756 case 'U':
3757 case 'V':
3758 case 'W':
3759 case 'X':
3760 case 'Y':
3761 case 'Z':
3762 case 'a':
3763 case 'b':
3764 case 'c':
3765 case 'd':
3766 case 'e':
3767 case 'f':
3768 case 'g':
3769 case 'h':
3770 case 'i':
3771 case 'j':
3772 case 'k':
3773 case 'l':
3774 case 'm':
3775 case 'n':
3776 case 'o':
3777 case 'p':
3778 case 'q':
3779 case 'r':
3780 case 's':
3781 case 't':
3782 case 'u':
3783 case 'v':
3784 case 'w':
3785 case 'x':
3786 case 'y':
3787 case 'z':
3788 c = ffesrc_char_source (c);
3789 /* Fall through. */
3790 case '0':
3791 case '1':
3792 case '2':
3793 case '3':
3794 case '4':
3795 case '5':
3796 case '6':
3797 case '7':
3798 case '8':
3799 case '9':
3800 case '_':
3801 case '$':
3802 if ((c == '$')
3803 && !ffe_is_dollar_ok ())
3805 ffelex_send_token_ ();
3806 goto parse_next_character; /* :::::::::::::::::::: */
3808 if (ffelex_token_->length < FFEWHERE_indexMAX)
3810 ffewhere_track (&ffelex_token_->currentnames_line,
3811 &ffelex_token_->currentnames_col,
3812 ffelex_token_->wheretrack,
3813 ffelex_token_->length,
3814 ffelex_linecount_current_,
3815 column + 1);
3817 ffelex_append_to_token_ (c);
3818 break;
3820 default:
3821 ffelex_send_token_ ();
3822 goto parse_next_character; /* :::::::::::::::::::: */
3824 break;
3826 case FFELEX_typeNUMBER:
3827 switch (c)
3829 case '0':
3830 case '1':
3831 case '2':
3832 case '3':
3833 case '4':
3834 case '5':
3835 case '6':
3836 case '7':
3837 case '8':
3838 case '9':
3839 ffelex_append_to_token_ (c);
3840 break;
3842 default:
3843 ffelex_send_token_ ();
3844 goto parse_next_character; /* :::::::::::::::::::: */
3846 break;
3848 case FFELEX_typeASTERISK:
3849 switch (c)
3851 case '*': /* ** */
3852 ffelex_token_->type = FFELEX_typePOWER;
3853 ffelex_send_token_ ();
3854 break;
3856 default: /* * not followed by another *. */
3857 ffelex_send_token_ ();
3858 goto parse_next_character; /* :::::::::::::::::::: */
3860 break;
3862 case FFELEX_typeCOLON:
3863 switch (c)
3865 case ':': /* :: */
3866 ffelex_token_->type = FFELEX_typeCOLONCOLON;
3867 ffelex_send_token_ ();
3868 break;
3870 default: /* : not followed by another :. */
3871 ffelex_send_token_ ();
3872 goto parse_next_character; /* :::::::::::::::::::: */
3874 break;
3876 case FFELEX_typeSLASH:
3877 switch (c)
3879 case '/': /* // */
3880 ffelex_token_->type = FFELEX_typeCONCAT;
3881 ffelex_send_token_ ();
3882 break;
3884 case ')': /* /) */
3885 ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
3886 ffelex_send_token_ ();
3887 break;
3889 case '=': /* /= */
3890 ffelex_token_->type = FFELEX_typeREL_NE;
3891 ffelex_send_token_ ();
3892 break;
3894 default:
3895 ffelex_send_token_ ();
3896 goto parse_next_character; /* :::::::::::::::::::: */
3898 break;
3900 case FFELEX_typeOPEN_PAREN:
3901 switch (c)
3903 case '/': /* (/ */
3904 ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
3905 ffelex_send_token_ ();
3906 break;
3908 default:
3909 ffelex_send_token_ ();
3910 goto parse_next_character; /* :::::::::::::::::::: */
3912 break;
3914 case FFELEX_typeOPEN_ANGLE:
3915 switch (c)
3917 case '=': /* <= */
3918 ffelex_token_->type = FFELEX_typeREL_LE;
3919 ffelex_send_token_ ();
3920 break;
3922 default:
3923 ffelex_send_token_ ();
3924 goto parse_next_character; /* :::::::::::::::::::: */
3926 break;
3928 case FFELEX_typeEQUALS:
3929 switch (c)
3931 case '=': /* == */
3932 ffelex_token_->type = FFELEX_typeREL_EQ;
3933 ffelex_send_token_ ();
3934 break;
3936 case '>': /* => */
3937 ffelex_token_->type = FFELEX_typePOINTS;
3938 ffelex_send_token_ ();
3939 break;
3941 default:
3942 ffelex_send_token_ ();
3943 goto parse_next_character; /* :::::::::::::::::::: */
3945 break;
3947 case FFELEX_typeCLOSE_ANGLE:
3948 switch (c)
3950 case '=': /* >= */
3951 ffelex_token_->type = FFELEX_typeREL_GE;
3952 ffelex_send_token_ ();
3953 break;
3955 default:
3956 ffelex_send_token_ ();
3957 goto parse_next_character; /* :::::::::::::::::::: */
3959 break;
3961 default:
3962 assert ("Serious error!" == NULL);
3963 abort ();
3964 break;
3967 c = ffelex_card_image_[++column];
3969 parse_next_character: /* :::::::::::::::::::: */
3971 if (ffelex_raw_mode_ != 0)
3972 goto parse_raw_character; /* :::::::::::::::::::: */
3974 if ((c == '\0') || (c == '!'))
3976 ffelex_finish_statement_ ();
3977 goto beginning_of_line; /* :::::::::::::::::::: */
3979 goto parse_nonraw_character; /* :::::::::::::::::::: */
3982 /* See the code in com.c that calls this to understand why. */
3984 #if FFECOM_targetCURRENT == FFECOM_targetGCC
3985 void
3986 ffelex_hash_kludge (FILE *finput)
3988 /* If you change this constant string, you have to change whatever
3989 code might thus be affected by it in terms of having to use
3990 ffelex_getc_() instead of getc() in the lexers and _hash_. */
3991 static char match[] = "# 1 \"";
3992 static int kludge[ARRAY_SIZE (match) + 1];
3993 int c;
3994 char *p;
3995 int *q;
3997 /* Read chars as long as they match the target string.
3998 Copy them into an array that will serve as a record
3999 of what we read (essentially a multi-char ungetc(),
4000 for code that uses ffelex_getc_ instead of getc() elsewhere
4001 in the lexer. */
4002 for (p = &match[0], q = &kludge[0], c = getc (finput);
4003 (c == *p) && (*p != '\0') && (c != EOF);
4004 ++p, ++q, c = getc (finput))
4005 *q = c;
4007 *q = c; /* Might be EOF, which requires int. */
4008 *++q = 0;
4010 ffelex_kludge_chars_ = &kludge[0];
4012 if (*p == 0)
4014 ffelex_kludge_flag_ = TRUE;
4015 ++ffelex_kludge_chars_;
4016 ffelex_hash_ (finput); /* Handle it NOW rather than later. */
4017 ffelex_kludge_flag_ = FALSE;
4021 #endif
4022 void
4023 ffelex_init_1 ()
4025 unsigned int i;
4027 ffelex_final_nontab_column_ = ffe_fixed_line_length ();
4028 ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
4029 ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
4030 "FFELEX card image",
4031 FFELEX_columnINITIAL_SIZE_ + 9);
4032 ffelex_card_image_[0] = '\0';
4034 for (i = 0; i < 256; ++i)
4035 ffelex_first_char_[i] = FFELEX_typeERROR;
4037 ffelex_first_char_['\t'] = FFELEX_typeRAW;
4038 ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
4039 ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
4040 ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
4041 ffelex_first_char_['\r'] = FFELEX_typeRAW;
4042 ffelex_first_char_[' '] = FFELEX_typeRAW;
4043 ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
4044 ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
4045 ffelex_first_char_['/'] = FFELEX_typeSLASH;
4046 ffelex_first_char_['&'] = FFELEX_typeRAW;
4047 ffelex_first_char_['#'] = FFELEX_typeHASH;
4049 for (i = '0'; i <= '9'; ++i)
4050 ffelex_first_char_[i] = FFELEX_typeRAW;
4052 if ((ffe_case_match () == FFE_caseNONE)
4053 || ((ffe_case_match () == FFE_caseUPPER)
4054 && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
4055 || ((ffe_case_match () == FFE_caseLOWER)
4056 && (ffe_case_source () == FFE_caseLOWER)))
4058 ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
4059 ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
4061 if ((ffe_case_match () == FFE_caseNONE)
4062 || ((ffe_case_match () == FFE_caseLOWER)
4063 && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
4064 || ((ffe_case_match () == FFE_caseUPPER)
4065 && (ffe_case_source () == FFE_caseUPPER)))
4067 ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
4068 ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
4071 ffelex_linecount_current_ = 0;
4072 ffelex_linecount_next_ = 1;
4073 ffelex_raw_mode_ = 0;
4074 ffelex_set_include_ = FALSE;
4075 ffelex_permit_include_ = FALSE;
4076 ffelex_names_ = TRUE; /* First token in program is a names. */
4077 ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
4078 FORMAT. */
4079 ffelex_hexnum_ = FALSE;
4080 ffelex_expecting_hollerith_ = 0;
4081 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4082 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4084 ffelex_token_ = ffelex_token_new_ ();
4085 ffelex_token_->type = FFELEX_typeNONE;
4086 ffelex_token_->uses = 1;
4087 ffelex_token_->where_line = ffewhere_line_unknown ();
4088 ffelex_token_->where_col = ffewhere_column_unknown ();
4089 ffelex_token_->text = NULL;
4091 ffelex_handler_ = NULL;
4094 /* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
4096 if (ffelex_is_names_expected())
4097 // Deliver NAMES token
4098 else
4099 // Deliver NAME token
4101 Must be called while lexer is active, obviously. */
4103 bool
4104 ffelex_is_names_expected ()
4106 return ffelex_names_;
4109 /* Current card image, which has the master linecount number
4110 ffelex_linecount_current_. */
4112 char *
4113 ffelex_line ()
4115 return ffelex_card_image_;
4118 /* ffelex_line_length -- Return length of current lexer line
4120 printf("Length is %lu\n",ffelex_line_length());
4122 Must be called while lexer is active, obviously. */
4124 ffewhereColumnNumber
4125 ffelex_line_length ()
4127 return ffelex_card_length_;
4130 /* Master line count of current card image, or 0 if no card image
4131 is current. */
4133 ffewhereLineNumber
4134 ffelex_line_number ()
4136 return ffelex_linecount_current_;
4139 /* ffelex_set_expecting_hollerith -- Set hollerith expectation status
4141 ffelex_set_expecting_hollerith(0);
4143 Lex initially assumes no hollerith constant is about to show up. If
4144 syntactic analysis expects one, it should call this function with the
4145 number of characters expected in the constant immediately after recognizing
4146 the decimal number preceding the "H" and the constant itself. Then, if
4147 the next character is indeed H, the lexer will interpret it as beginning
4148 a hollerith constant and ship the token formed by reading the specified
4149 number of characters (interpreting blanks and otherwise-comments too)
4150 from the input file. It is up to syntactic analysis to call this routine
4151 again with 0 to turn hollerith detection off immediately upon receiving
4152 the token that might or might not be HOLLERITH.
4154 Also call this after seeing an APOSTROPHE or QUOTE token that begins a
4155 character constant. Pass the expected termination character (apostrophe
4156 or quote).
4158 Pass for length either the length of the hollerith (must be > 0), -1
4159 meaning expecting a character constant, or 0 to cancel expectation of
4160 a hollerith only after calling it with a length of > 0 and receiving the
4161 next token (which may or may not have been a HOLLERITH token).
4163 Pass for which either an apostrophe or quote when passing length of -1.
4164 Else which is a don't-care.
4166 Pass for line and column the line/column info for the token beginning the
4167 character or hollerith constant, for use in error messages, when passing
4168 a length of -1 -- this function will invoke ffewhere_line/column_use to
4169 make its own copies. Else line and column are don't-cares (when length
4170 is 0) and the outstanding copies of the previous line/column info, if
4171 still around, are killed.
4173 21-Feb-90 JCB 3.1
4174 When called with length of 0, also zero ffelex_raw_mode_. This is
4175 so ffest_save_ can undo the effects of replaying tokens like
4176 APOSTROPHE and QUOTE.
4177 25-Jan-90 JCB 3.0
4178 New line, column arguments allow error messages to point to the true
4179 beginning of a character/hollerith constant, rather than the beginning
4180 of the content part, which makes them more consistent and helpful.
4181 05-Nov-89 JCB 2.0
4182 New "which" argument allows caller to specify termination character,
4183 which should be apostrophe or double-quote, to support Fortran 90. */
4185 void
4186 ffelex_set_expecting_hollerith (long length, char which,
4187 ffewhereLine line, ffewhereColumn column)
4190 /* First kill the pending line/col info, if any (should only be pending
4191 when this call has length==0, the previous call had length>0, and a
4192 non-HOLLERITH token was sent in between the calls, but play it safe). */
4194 ffewhere_line_kill (ffelex_raw_where_line_);
4195 ffewhere_column_kill (ffelex_raw_where_col_);
4197 /* Now handle the length function. */
4198 switch (length)
4200 case 0:
4201 ffelex_expecting_hollerith_ = 0;
4202 ffelex_raw_mode_ = 0;
4203 ffelex_raw_where_line_ = ffewhere_line_unknown ();
4204 ffelex_raw_where_col_ = ffewhere_column_unknown ();
4205 return; /* Don't set new line/column info from args. */
4207 case -1:
4208 ffelex_raw_mode_ = -1;
4209 ffelex_raw_char_ = which;
4210 break;
4212 default: /* length > 0 */
4213 ffelex_expecting_hollerith_ = length;
4214 break;
4217 /* Now set new line/column information from passed args. */
4219 ffelex_raw_where_line_ = ffewhere_line_use (line);
4220 ffelex_raw_where_col_ = ffewhere_column_use (column);
4223 /* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
4225 ffelex_set_handler((ffelexHandler) my_first_handler);
4227 Must be called before calling ffelex_file_fixed or ffelex_file_free or
4228 after they return, but not while they are active. */
4230 void
4231 ffelex_set_handler (ffelexHandler first)
4233 ffelex_handler_ = first;
4236 /* ffelex_set_hexnum -- Set hexnum flag
4238 ffelex_set_hexnum(TRUE);
4240 Lex normally interprets a token starting with [0-9] as a NUMBER token,
4241 so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
4242 the character as the first of the next token. But when parsing a
4243 hexadecimal number, by calling this function with TRUE before starting
4244 the parse of the token itself, lex will interpret [0-9] as the start
4245 of a NAME token. */
4247 void
4248 ffelex_set_hexnum (bool f)
4250 ffelex_hexnum_ = f;
4253 /* ffelex_set_include -- Set INCLUDE file to be processed next
4255 ffewhereFile wf; // The ffewhereFile object for the file.
4256 bool free_form; // TRUE means read free-form file, FALSE fixed-form.
4257 FILE *fi; // The file to INCLUDE.
4258 ffelex_set_include(wf,free_form,fi);
4260 Must be called only after receiving the EOS token following a valid
4261 INCLUDE statement specifying a file that has already been successfully
4262 opened. */
4264 void
4265 ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
4267 assert (ffelex_permit_include_);
4268 assert (!ffelex_set_include_);
4269 ffelex_set_include_ = TRUE;
4270 ffelex_include_free_form_ = free_form;
4271 ffelex_include_file_ = fi;
4272 ffelex_include_wherefile_ = wf;
4275 /* ffelex_set_names -- Set names/name flag, names = TRUE
4277 ffelex_set_names(FALSE);
4279 Lex initially assumes multiple names should be formed. If this function is
4280 called with FALSE, then single names are formed instead. The differences
4281 are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
4282 and in whether full source-location tracking is performed (it is for
4283 multiple names, not for single names), which is more expensive in terms of
4284 CPU time. */
4286 void
4287 ffelex_set_names (bool f)
4289 ffelex_names_ = f;
4290 if (!f)
4291 ffelex_names_pure_ = FALSE;
4294 /* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
4296 ffelex_set_names_pure(FALSE);
4298 Like ffelex_set_names, except affects both lexers. Normally, the
4299 free-form lexer need not generate NAMES tokens because adjacent NAME
4300 tokens must be separated by spaces which causes the lexer to generate
4301 separate tokens for analysis (whereas in fixed-form the spaces are
4302 ignored resulting in one long token). But in FORMAT statements, for
4303 some reason, the Fortran 90 standard specifies that spaces can occur
4304 anywhere within a format-item-list with no effect on the format spec
4305 (except of course within character string edit descriptors), which means
4306 that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
4307 statement handling, the existence of spaces makes it hard to deal with,
4308 because each token is seen distinctly (i.e. seven tokens in the latter
4309 example). But when no spaces are provided, as in the former example,
4310 then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
4311 NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
4312 One, ffest_kw_format_ does a substring rather than full-string match,
4313 and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
4314 may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
4315 and three, error reporting can point to the actual character rather than
4316 at or prior to it. The first two things could be resolved by providing
4317 alternate functions fairly easy, thus allowing FORMAT handling to expect
4318 both lexers to generate NAME tokens instead of NAMES (with otherwise minor
4319 changes to FORMAT parsing), but the third, error reporting, would suffer,
4320 and when one makes mistakes in a FORMAT, believe me, one wants a pointer
4321 to exactly where the compilers thinks the problem is, to even begin to get
4322 a handle on it. So there. */
4324 void
4325 ffelex_set_names_pure (bool f)
4327 ffelex_names_pure_ = f;
4328 ffelex_names_ = f;
4331 /* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
4333 return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
4334 start_char_index);
4336 Returns first_handler if start_char_index chars into master_token (which
4337 must be a NAMES token) is '\0'. Else, creates a subtoken from that
4338 char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
4339 an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
4340 and sends it to first_handler. If anything other than NAME is sent, the
4341 character at the end of it in the master token is examined to see if it
4342 begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
4343 the handler returned by first_handler is invoked with that token, and
4344 this process is repeated until the end of the master token or a NAME
4345 token is reached. */
4347 ffelexHandler
4348 ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
4349 ffeTokenLength start)
4351 unsigned char *p;
4352 ffeTokenLength i;
4353 ffelexToken t;
4355 p = ffelex_token_text (master) + (i = start);
4357 while (*p != '\0')
4359 if (ISDIGIT (*p))
4361 t = ffelex_token_number_from_names (master, i);
4362 p += ffelex_token_length (t);
4363 i += ffelex_token_length (t);
4365 else if (ffesrc_is_name_init (*p))
4367 t = ffelex_token_name_from_names (master, i, 0);
4368 p += ffelex_token_length (t);
4369 i += ffelex_token_length (t);
4371 else if (*p == '$')
4373 t = ffelex_token_dollar_from_names (master, i);
4374 ++p;
4375 ++i;
4377 else if (*p == '_')
4379 t = ffelex_token_uscore_from_names (master, i);
4380 ++p;
4381 ++i;
4383 else
4385 assert ("not a valid NAMES character" == NULL);
4386 t = NULL;
4388 assert (first != NULL);
4389 first = (ffelexHandler) (*first) (t);
4390 ffelex_token_kill (t);
4393 return first;
4396 /* ffelex_swallow_tokens -- Eat all tokens delivered to me
4398 return ffelex_swallow_tokens;
4400 Return this handler when you don't want to look at any more tokens in the
4401 statement because you've encountered an unrecoverable error in the
4402 statement. */
4404 ffelexHandler
4405 ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
4407 assert (handler != NULL);
4409 if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
4410 || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
4411 return (ffelexHandler) (*handler) (t);
4413 ffelex_eos_handler_ = handler;
4414 return (ffelexHandler) ffelex_swallow_tokens_;
4417 /* ffelex_token_dollar_from_names -- Return a dollar from within a names token
4419 ffelexToken t;
4420 t = ffelex_token_dollar_from_names(t,6);
4422 It's as if you made a new token of dollar type having the dollar
4423 at, in the example above, the sixth character of the NAMES token. */
4425 ffelexToken
4426 ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
4428 ffelexToken nt;
4430 assert (t != NULL);
4431 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4432 assert (start < t->length);
4433 assert (t->text[start] == '$');
4435 /* Now make the token. */
4437 nt = ffelex_token_new_ ();
4438 nt->type = FFELEX_typeDOLLAR;
4439 nt->length = 0;
4440 nt->uses = 1;
4441 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4442 t->where_col, t->wheretrack, start);
4443 nt->text = NULL;
4444 return nt;
4447 /* ffelex_token_kill -- Decrement use count for token, kill if no uses left
4449 ffelexToken t;
4450 ffelex_token_kill(t);
4452 Complements a call to ffelex_token_use or ffelex_token_new_.... */
4454 void
4455 ffelex_token_kill (ffelexToken t)
4457 assert (t != NULL);
4459 assert (t->uses > 0);
4461 if (--t->uses != 0)
4462 return;
4464 --ffelex_total_tokens_;
4466 if (t->type == FFELEX_typeNAMES)
4467 ffewhere_track_kill (t->where_line, t->where_col,
4468 t->wheretrack, t->length);
4469 ffewhere_line_kill (t->where_line);
4470 ffewhere_column_kill (t->where_col);
4471 if (t->text != NULL)
4472 malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
4473 malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
4476 /* Make a new NAME token that is a substring of a NAMES token. */
4478 ffelexToken
4479 ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
4480 ffeTokenLength len)
4482 ffelexToken nt;
4484 assert (t != NULL);
4485 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4486 assert (start < t->length);
4487 if (len == 0)
4488 len = t->length - start;
4489 else
4491 assert (len > 0);
4492 assert ((start + len) <= t->length);
4494 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4496 nt = ffelex_token_new_ ();
4497 nt->type = FFELEX_typeNAME;
4498 nt->size = len; /* Assume nobody's gonna fiddle with token
4499 text. */
4500 nt->length = len;
4501 nt->uses = 1;
4502 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4503 t->where_col, t->wheretrack, start);
4504 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4505 len + 1);
4506 strncpy (nt->text, t->text + start, len);
4507 nt->text[len] = '\0';
4508 return nt;
4511 /* Make a new NAMES token that is a substring of another NAMES token. */
4513 ffelexToken
4514 ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
4515 ffeTokenLength len)
4517 ffelexToken nt;
4519 assert (t != NULL);
4520 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4521 assert (start < t->length);
4522 if (len == 0)
4523 len = t->length - start;
4524 else
4526 assert (len > 0);
4527 assert ((start + len) <= t->length);
4529 assert (ffelex_is_firstnamechar ((unsigned char)(t->text[start])));
4531 nt = ffelex_token_new_ ();
4532 nt->type = FFELEX_typeNAMES;
4533 nt->size = len; /* Assume nobody's gonna fiddle with token
4534 text. */
4535 nt->length = len;
4536 nt->uses = 1;
4537 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4538 t->where_col, t->wheretrack, start);
4539 ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
4540 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4541 len + 1);
4542 strncpy (nt->text, t->text + start, len);
4543 nt->text[len] = '\0';
4544 return nt;
4547 /* Make a new CHARACTER token. */
4549 ffelexToken
4550 ffelex_token_new_character (const char *s, ffewhereLine l, ffewhereColumn c)
4552 ffelexToken t;
4554 t = ffelex_token_new_ ();
4555 t->type = FFELEX_typeCHARACTER;
4556 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4557 t->uses = 1;
4558 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4559 t->size + 1);
4560 strcpy (t->text, s);
4561 t->where_line = ffewhere_line_use (l);
4562 t->where_col = ffewhere_column_new (c);
4563 return t;
4566 /* Make a new EOF token right after end of file. */
4568 ffelexToken
4569 ffelex_token_new_eof ()
4571 ffelexToken t;
4573 t = ffelex_token_new_ ();
4574 t->type = FFELEX_typeEOF;
4575 t->uses = 1;
4576 t->text = NULL;
4577 t->where_line = ffewhere_line_new (ffelex_linecount_current_);
4578 t->where_col = ffewhere_column_new (1);
4579 return t;
4582 /* Make a new NAME token. */
4584 ffelexToken
4585 ffelex_token_new_name (const char *s, ffewhereLine l, ffewhereColumn c)
4587 ffelexToken t;
4589 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4591 t = ffelex_token_new_ ();
4592 t->type = FFELEX_typeNAME;
4593 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4594 t->uses = 1;
4595 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4596 t->size + 1);
4597 strcpy (t->text, s);
4598 t->where_line = ffewhere_line_use (l);
4599 t->where_col = ffewhere_column_new (c);
4600 return t;
4603 /* Make a new NAMES token. */
4605 ffelexToken
4606 ffelex_token_new_names (const char *s, ffewhereLine l, ffewhereColumn c)
4608 ffelexToken t;
4610 assert (ffelex_is_firstnamechar ((unsigned char)*s));
4612 t = ffelex_token_new_ ();
4613 t->type = FFELEX_typeNAMES;
4614 t->length = t->size = strlen (s); /* Assume it won't get bigger. */
4615 t->uses = 1;
4616 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4617 t->size + 1);
4618 strcpy (t->text, s);
4619 t->where_line = ffewhere_line_use (l);
4620 t->where_col = ffewhere_column_new (c);
4621 ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
4622 names. */
4623 return t;
4626 /* Make a new NUMBER token.
4628 The first character of the string must be a digit, and only the digits
4629 are copied into the new number. So this may be used to easily extract
4630 a NUMBER token from within any text string. Then the length of the
4631 resulting token may be used to calculate where the digits stopped
4632 in the original string. */
4634 ffelexToken
4635 ffelex_token_new_number (const char *s, ffewhereLine l, ffewhereColumn c)
4637 ffelexToken t;
4638 ffeTokenLength len;
4640 /* How long is the string of decimal digits at s? */
4642 len = strspn (s, "0123456789");
4644 /* Make sure there is at least one digit. */
4646 assert (len != 0);
4648 /* Now make the token. */
4650 t = ffelex_token_new_ ();
4651 t->type = FFELEX_typeNUMBER;
4652 t->length = t->size = len; /* Assume it won't get bigger. */
4653 t->uses = 1;
4654 t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4655 len + 1);
4656 strncpy (t->text, s, len);
4657 t->text[len] = '\0';
4658 t->where_line = ffewhere_line_use (l);
4659 t->where_col = ffewhere_column_new (c);
4660 return t;
4663 /* Make a new token of any type that doesn't contain text. A private
4664 function that is used by public macros in the interface file. */
4666 ffelexToken
4667 ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
4669 ffelexToken t;
4671 t = ffelex_token_new_ ();
4672 t->type = type;
4673 t->uses = 1;
4674 t->text = NULL;
4675 t->where_line = ffewhere_line_use (l);
4676 t->where_col = ffewhere_column_new (c);
4677 return t;
4680 /* Make a new NUMBER token from an existing NAMES token.
4682 Like ffelex_token_new_number, this function calculates the length
4683 of the digit string itself. */
4685 ffelexToken
4686 ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
4688 ffelexToken nt;
4689 ffeTokenLength len;
4691 assert (t != NULL);
4692 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4693 assert (start < t->length);
4695 /* How long is the string of decimal digits at s? */
4697 len = strspn (t->text + start, "0123456789");
4699 /* Make sure there is at least one digit. */
4701 assert (len != 0);
4703 /* Now make the token. */
4705 nt = ffelex_token_new_ ();
4706 nt->type = FFELEX_typeNUMBER;
4707 nt->size = len; /* Assume nobody's gonna fiddle with token
4708 text. */
4709 nt->length = len;
4710 nt->uses = 1;
4711 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4712 t->where_col, t->wheretrack, start);
4713 nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
4714 len + 1);
4715 strncpy (nt->text, t->text + start, len);
4716 nt->text[len] = '\0';
4717 return nt;
4720 /* Make a new UNDERSCORE token from a NAMES token. */
4722 ffelexToken
4723 ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
4725 ffelexToken nt;
4727 assert (t != NULL);
4728 assert (ffelex_token_type (t) == FFELEX_typeNAMES);
4729 assert (start < t->length);
4730 assert (t->text[start] == '_');
4732 /* Now make the token. */
4734 nt = ffelex_token_new_ ();
4735 nt->type = FFELEX_typeUNDERSCORE;
4736 nt->uses = 1;
4737 ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
4738 t->where_col, t->wheretrack, start);
4739 nt->text = NULL;
4740 return nt;
4743 /* ffelex_token_use -- Return another instance of a token
4745 ffelexToken t;
4746 t = ffelex_token_use(t);
4748 In a sense, the new token is a copy of the old, though it might be the
4749 same with just a new use count.
4751 We use the use count method (easy). */
4753 ffelexToken
4754 ffelex_token_use (ffelexToken t)
4756 if (t == NULL)
4757 assert ("_token_use: null token" == NULL);
4758 t->uses++;
4759 return t;