]> gcc.gnu.org Git - gcc.git/blame - gcc/fortran/io.c
Update FSF address.
[gcc.git] / gcc / fortran / io.c
CommitLineData
6de9cd9a 1/* Deal with I/O statements & related stuff.
ec378180 2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation,
50d78f96 3 Inc.
6de9cd9a
DN
4 Contributed by Andy Vaught
5
9fc4d79b 6This file is part of GCC.
6de9cd9a 7
9fc4d79b
TS
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
6de9cd9a 12
9fc4d79b
TS
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
6de9cd9a
DN
17
18You should have received a copy of the GNU General Public License
9fc4d79b 19along with GCC; see the file COPYING. If not, write to the Free
ab57747b
KC
20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2102110-1301, USA. */
6de9cd9a
DN
22
23#include "config.h"
24#include "system.h"
25#include "flags.h"
6de9cd9a
DN
26#include "gfortran.h"
27#include "match.h"
28#include "parse.h"
29
30gfc_st_label format_asterisk =
31 { -1, ST_LABEL_FORMAT, ST_LABEL_FORMAT, NULL, 0,
4eeaf81e 32 {NULL, NULL}, NULL, NULL};
6de9cd9a
DN
33
34typedef struct
35{
36 const char *name, *spec;
37 bt type;
38}
39io_tag;
40
41static const io_tag
42 tag_file = { "FILE", " file = %e", BT_CHARACTER },
43 tag_status = { "STATUS", " status = %e", BT_CHARACTER},
44 tag_e_access = {"ACCESS", " access = %e", BT_CHARACTER},
45 tag_e_form = {"FORM", " form = %e", BT_CHARACTER},
46 tag_e_recl = {"RECL", " recl = %e", BT_INTEGER},
47 tag_e_blank = {"BLANK", " blank = %e", BT_CHARACTER},
48 tag_e_position = {"POSITION", " position = %e", BT_CHARACTER},
49 tag_e_action = {"ACTION", " action = %e", BT_CHARACTER},
50 tag_e_delim = {"DELIM", " delim = %e", BT_CHARACTER},
51 tag_e_pad = {"PAD", " pad = %e", BT_CHARACTER},
52 tag_unit = {"UNIT", " unit = %e", BT_INTEGER},
53 tag_advance = {"ADVANCE", " advance = %e", BT_CHARACTER},
54 tag_rec = {"REC", " rec = %e", BT_INTEGER},
55 tag_format = {"FORMAT", NULL, BT_CHARACTER},
56 tag_iostat = {"IOSTAT", " iostat = %v", BT_INTEGER},
57 tag_size = {"SIZE", " size = %v", BT_INTEGER},
58 tag_exist = {"EXIST", " exist = %v", BT_LOGICAL},
59 tag_opened = {"OPENED", " opened = %v", BT_LOGICAL},
60 tag_named = {"NAMED", " named = %v", BT_LOGICAL},
61 tag_name = {"NAME", " name = %v", BT_CHARACTER},
62 tag_number = {"NUMBER", " number = %v", BT_INTEGER},
63 tag_s_access = {"ACCESS", " access = %v", BT_CHARACTER},
64 tag_sequential = {"SEQUENTIAL", " sequential = %v", BT_CHARACTER},
65 tag_direct = {"DIRECT", " direct = %v", BT_CHARACTER},
66 tag_s_form = {"FORM", " form = %v", BT_CHARACTER},
67 tag_formatted = {"FORMATTED", " formatted = %v", BT_CHARACTER},
68 tag_unformatted = {"UNFORMATTED", " unformatted = %v", BT_CHARACTER},
69 tag_s_recl = {"RECL", " recl = %v", BT_INTEGER},
70 tag_nextrec = {"NEXTREC", " nextrec = %v", BT_INTEGER},
71 tag_s_blank = {"BLANK", " blank = %v", BT_CHARACTER},
72 tag_s_position = {"POSITION", " position = %v", BT_CHARACTER},
73 tag_s_action = {"ACTION", " action = %v", BT_CHARACTER},
74 tag_read = {"READ", " read = %v", BT_CHARACTER},
75 tag_write = {"WRITE", " write = %v", BT_CHARACTER},
76 tag_readwrite = {"READWRITE", " readwrite = %v", BT_CHARACTER},
77 tag_s_delim = {"DELIM", " delim = %v", BT_CHARACTER},
78 tag_s_pad = {"PAD", " pad = %v", BT_CHARACTER},
79 tag_iolength = {"IOLENGTH", " iolength = %v", BT_INTEGER},
80 tag_err = {"ERR", " err = %l", BT_UNKNOWN},
81 tag_end = {"END", " end = %l", BT_UNKNOWN},
82 tag_eor = {"EOR", " eor = %l", BT_UNKNOWN};
83
84static gfc_dt *current_dt;
85
86#define RESOLVE_TAG(x, y) if (resolve_tag(x, y) == FAILURE) return FAILURE;
87
88
89/**************** Fortran 95 FORMAT parser *****************/
90
91/* FORMAT tokens returned by format_lex(). */
92typedef enum
93{
94 FMT_NONE, FMT_UNKNOWN, FMT_SIGNED_INT, FMT_ZERO, FMT_POSINT, FMT_PERIOD,
95 FMT_COMMA, FMT_COLON, FMT_SLASH, FMT_DOLLAR, FMT_POS, FMT_LPAREN,
96 FMT_RPAREN, FMT_X, FMT_SIGN, FMT_BLANK, FMT_CHAR, FMT_P, FMT_IBOZ, FMT_F,
97 FMT_E, FMT_EXT, FMT_G, FMT_L, FMT_A, FMT_D, FMT_H, FMT_END
98}
99format_token;
100
101/* Local variables for checking format strings. The saved_token is
102 used to back up by a single format token during the parsing
103 process. */
104static char *format_string;
105static int format_length, use_last_char;
106
107static format_token saved_token;
108
109static enum
110{ MODE_STRING, MODE_FORMAT, MODE_COPY }
111mode;
112
113
114/* Return the next character in the format string. */
115
116static char
117next_char (int in_string)
118{
119 static char c;
120
121 if (use_last_char)
122 {
123 use_last_char = 0;
124 return c;
125 }
126
127 format_length++;
128
129 if (mode == MODE_STRING)
130 c = *format_string++;
131 else
132 {
133 c = gfc_next_char_literal (in_string);
134 if (c == '\n')
135 c = '\0';
136
137 if (mode == MODE_COPY)
138 *format_string++ = c;
139 }
140
141 c = TOUPPER (c);
142 return c;
143}
144
145
146/* Back up one character position. Only works once. */
147
148static void
149unget_char (void)
150{
151
152 use_last_char = 1;
153}
154
155static int value = 0;
156
157/* Simple lexical analyzer for getting the next token in a FORMAT
158 statement. */
159
160static format_token
161format_lex (void)
162{
163 format_token token;
164 char c, delim;
165 int zflag;
166 int negative_flag;
167
168 if (saved_token != FMT_NONE)
169 {
170 token = saved_token;
171 saved_token = FMT_NONE;
172 return token;
173 }
174
175 do
176 {
177 c = next_char (0);
178 }
179 while (gfc_is_whitespace (c));
180
181 negative_flag = 0;
182 switch (c)
183 {
184 case '-':
185 negative_flag = 1;
186 case '+':
187 c = next_char (0);
188 if (!ISDIGIT (c))
189 {
190 token = FMT_UNKNOWN;
191 break;
192 }
193
194 value = c - '0';
195
196 do
197 {
198 c = next_char (0);
199 if(ISDIGIT (c))
200 value = 10 * value + c - '0';
201 }
202 while (ISDIGIT (c));
203
204 unget_char ();
205
206 if (negative_flag)
207 value = -value;
208
209 token = FMT_SIGNED_INT;
210 break;
211
212 case '0':
213 case '1':
214 case '2':
215 case '3':
216 case '4':
217 case '5':
218 case '6':
219 case '7':
220 case '8':
221 case '9':
222 zflag = (c == '0');
223
224 value = c - '0';
225
226 do
227 {
228 c = next_char (0);
229 if (c != '0')
230 zflag = 0;
231 if (ISDIGIT (c))
232 value = 10 * value + c - '0';
233 }
234 while (ISDIGIT (c));
235
236 unget_char ();
237 token = zflag ? FMT_ZERO : FMT_POSINT;
238 break;
239
240 case '.':
241 token = FMT_PERIOD;
242 break;
243
244 case ',':
245 token = FMT_COMMA;
246 break;
247
248 case ':':
249 token = FMT_COLON;
250 break;
251
252 case '/':
253 token = FMT_SLASH;
254 break;
255
256 case '$':
257 token = FMT_DOLLAR;
258 break;
259
260 case 'T':
261 c = next_char (0);
262 if (c != 'L' && c != 'R')
263 unget_char ();
264
265 token = FMT_POS;
266 break;
267
268 case '(':
269 token = FMT_LPAREN;
270 break;
271
272 case ')':
273 token = FMT_RPAREN;
274 break;
275
276 case 'X':
277 token = FMT_X;
278 break;
279
280 case 'S':
281 c = next_char (0);
282 if (c != 'P' && c != 'S')
283 unget_char ();
284
285 token = FMT_SIGN;
286 break;
287
288 case 'B':
289 c = next_char (0);
290 if (c == 'N' || c == 'Z')
291 token = FMT_BLANK;
292 else
293 {
294 unget_char ();
295 token = FMT_IBOZ;
296 }
297
298 break;
299
300 case '\'':
301 case '"':
302 delim = c;
303
304 value = 0;
305
306 for (;;)
307 {
308 c = next_char (1);
309 if (c == '\0')
310 {
311 token = FMT_END;
312 break;
313 }
314
315 if (c == delim)
316 {
317 c = next_char (1);
318
319 if (c == '\0')
320 {
321 token = FMT_END;
322 break;
323 }
324
325 if (c != delim)
326 {
327 unget_char ();
328 token = FMT_CHAR;
329 break;
330 }
331 }
332 value++;
333 }
334 break;
335
336 case 'P':
337 token = FMT_P;
338 break;
339
340 case 'I':
341 case 'O':
342 case 'Z':
343 token = FMT_IBOZ;
344 break;
345
346 case 'F':
347 token = FMT_F;
348 break;
349
350 case 'E':
351 c = next_char (0);
352 if (c == 'N' || c == 'S')
353 token = FMT_EXT;
354 else
355 {
356 token = FMT_E;
357 unget_char ();
358 }
359
360 break;
361
362 case 'G':
363 token = FMT_G;
364 break;
365
366 case 'H':
367 token = FMT_H;
368 break;
369
370 case 'L':
371 token = FMT_L;
372 break;
373
374 case 'A':
375 token = FMT_A;
376 break;
377
378 case 'D':
379 token = FMT_D;
380 break;
381
382 case '\0':
383 token = FMT_END;
384 break;
385
386 default:
387 token = FMT_UNKNOWN;
388 break;
389 }
390
391 return token;
392}
393
394
395/* Check a format statement. The format string, either from a FORMAT
396 statement or a constant in an I/O statement has already been parsed
397 by itself, and we are checking it for validity. The dual origin
398 means that the warning message is a little less than great. */
399
400static try
401check_format (void)
402{
403 const char *posint_required = "Positive width required";
404 const char *period_required = "Period required";
405 const char *nonneg_required = "Nonnegative width required";
406 const char *unexpected_element = "Unexpected element";
407 const char *unexpected_end = "Unexpected end of format string";
408
409 const char *error;
410 format_token t, u;
411 int level;
412 int repeat;
413 try rv;
414
415 use_last_char = 0;
416 saved_token = FMT_NONE;
417 level = 0;
418 repeat = 0;
419 rv = SUCCESS;
420
421 t = format_lex ();
422 if (t != FMT_LPAREN)
423 {
424 error = "Missing leading left parenthesis";
425 goto syntax;
426 }
427
428 t = format_lex ();
429 if (t == FMT_RPAREN)
430 goto finished; /* Empty format is legal */
431 saved_token = t;
432
433format_item:
434 /* In this state, the next thing has to be a format item. */
435 t = format_lex ();
53d8a8ac 436format_item_1:
6de9cd9a
DN
437 switch (t)
438 {
439 case FMT_POSINT:
440 repeat = value;
441 t = format_lex ();
442 if (t == FMT_LPAREN)
443 {
444 level++;
445 goto format_item;
446 }
447
448 if (t == FMT_SLASH)
449 goto optional_comma;
450
451 goto data_desc;
452
453 case FMT_LPAREN:
454 level++;
455 goto format_item;
456
457 case FMT_SIGNED_INT:
458 /* Signed integer can only precede a P format. */
459 t = format_lex ();
460 if (t != FMT_P)
461 {
462 error = "Expected P edit descriptor";
463 goto syntax;
464 }
465
466 goto data_desc;
467
468 case FMT_P:
8be123d4 469 /* P requires a prior number. */
6de9cd9a
DN
470 error = "P descriptor requires leading scale factor";
471 goto syntax;
472
473 case FMT_X:
8be123d4 474 /* X requires a prior number if we're being pedantic. */
e433aaee
RS
475 if (gfc_notify_std (GFC_STD_GNU, "Extension: X descriptor "
476 "requires leading space count at %C")
477 == FAILURE)
478 return FAILURE;
479 goto between_desc;
6de9cd9a
DN
480
481 case FMT_SIGN:
482 case FMT_BLANK:
6de9cd9a
DN
483 goto between_desc;
484
11670eeb
RS
485 case FMT_CHAR:
486 goto extension_optional_comma;
487
6de9cd9a
DN
488 case FMT_COLON:
489 case FMT_SLASH:
490 goto optional_comma;
491
492 case FMT_DOLLAR:
493 t = format_lex ();
c9330b03
FXC
494
495 if (gfc_notify_std (GFC_STD_GNU, "Extension: $ descriptor at %C")
496 == FAILURE)
497 return FAILURE;
6de9cd9a
DN
498 if (t != FMT_RPAREN || level > 0)
499 {
c9330b03 500 error = "$ must be the last specifier";
6de9cd9a
DN
501 goto syntax;
502 }
503
504 goto finished;
505
506 case FMT_POS:
507 case FMT_IBOZ:
508 case FMT_F:
509 case FMT_E:
510 case FMT_EXT:
511 case FMT_G:
512 case FMT_L:
513 case FMT_A:
514 case FMT_D:
515 goto data_desc;
516
517 case FMT_H:
518 goto data_desc;
519
520 case FMT_END:
521 error = unexpected_end;
522 goto syntax;
523
524 default:
525 error = unexpected_element;
526 goto syntax;
527 }
528
529data_desc:
530 /* In this state, t must currently be a data descriptor.
531 Deal with things that can/must follow the descriptor. */
532 switch (t)
533 {
534 case FMT_SIGN:
535 case FMT_BLANK:
536 case FMT_X:
537 break;
538
539 case FMT_P:
540 if (pedantic)
541 {
542 t = format_lex ();
543 if (t == FMT_POSINT)
544 {
545 error = "Repeat count cannot follow P descriptor";
546 goto syntax;
547 }
548
549 saved_token = t;
550 }
551
552 goto optional_comma;
553
554 case FMT_POS:
555 case FMT_L:
556 t = format_lex ();
557 if (t == FMT_POSINT)
558 break;
559
560 error = posint_required;
561 goto syntax;
562
563 case FMT_A:
564 t = format_lex ();
565 if (t != FMT_POSINT)
566 saved_token = t;
567 break;
568
569 case FMT_D:
570 case FMT_E:
571 case FMT_G:
572 case FMT_EXT:
573 u = format_lex ();
574 if (u != FMT_POSINT)
575 {
576 error = posint_required;
577 goto syntax;
578 }
579
580 u = format_lex ();
581 if (u != FMT_PERIOD)
582 {
583 error = period_required;
584 goto syntax;
585 }
586
587 u = format_lex ();
588 if (u != FMT_ZERO && u != FMT_POSINT)
589 {
590 error = nonneg_required;
591 goto syntax;
592 }
593
594 if (t == FMT_D)
595 break;
596
597 /* Look for optional exponent. */
598 u = format_lex ();
599 if (u != FMT_E)
600 {
601 saved_token = u;
602 }
603 else
604 {
605 u = format_lex ();
606 if (u != FMT_POSINT)
607 {
608 error = "Positive exponent width required";
609 goto syntax;
610 }
611 }
612
613 break;
614
615 case FMT_F:
616 t = format_lex ();
617 if (t != FMT_ZERO && t != FMT_POSINT)
618 {
619 error = nonneg_required;
620 goto syntax;
621 }
622
623 t = format_lex ();
624 if (t != FMT_PERIOD)
625 {
626 error = period_required;
627 goto syntax;
628 }
629
630 t = format_lex ();
631 if (t != FMT_ZERO && t != FMT_POSINT)
632 {
633 error = nonneg_required;
634 goto syntax;
635 }
636
637 break;
638
639 case FMT_H:
640 if(mode == MODE_STRING)
641 {
642 format_string += value;
643 format_length -= value;
644 }
645 else
646 {
647 while(repeat >0)
648 {
b160dd28 649 next_char(1);
6de9cd9a
DN
650 repeat -- ;
651 }
652 }
653 break;
654
655 case FMT_IBOZ:
656 t = format_lex ();
657 if (t != FMT_ZERO && t != FMT_POSINT)
658 {
659 error = nonneg_required;
660 goto syntax;
661 }
662
663 t = format_lex ();
664 if (t != FMT_PERIOD)
665 {
666 saved_token = t;
667 }
668 else
669 {
670 t = format_lex ();
671 if (t != FMT_ZERO && t != FMT_POSINT)
672 {
673 error = nonneg_required;
674 goto syntax;
675 }
676 }
677
678 break;
679
680 default:
681 error = unexpected_element;
682 goto syntax;
683 }
684
685between_desc:
686 /* Between a descriptor and what comes next. */
687 t = format_lex ();
688 switch (t)
689 {
690
691 case FMT_COMMA:
692 goto format_item;
693
694 case FMT_RPAREN:
695 level--;
696 if (level < 0)
697 goto finished;
698 goto between_desc;
699
700 case FMT_COLON:
701 case FMT_SLASH:
702 goto optional_comma;
703
704 case FMT_END:
705 error = unexpected_end;
706 goto syntax;
707
708 default:
53d8a8ac
AP
709 if (gfc_notify_std (GFC_STD_GNU, "Extension: Missing comma at %C")
710 == FAILURE)
711 return FAILURE;
712 goto format_item_1;
6de9cd9a
DN
713 }
714
715optional_comma:
716 /* Optional comma is a weird between state where we've just finished
717 reading a colon, slash or P descriptor. */
718 t = format_lex ();
719 switch (t)
720 {
721 case FMT_COMMA:
722 break;
723
724 case FMT_RPAREN:
725 level--;
726 if (level < 0)
727 goto finished;
728 goto between_desc;
729
730 default:
731 /* Assume that we have another format item. */
732 saved_token = t;
733 break;
734 }
735
736 goto format_item;
737
11670eeb
RS
738extension_optional_comma:
739 /* As a GNU extension, permit a missing comma after a string literal. */
740 t = format_lex ();
741 switch (t)
742 {
743 case FMT_COMMA:
744 break;
745
746 case FMT_RPAREN:
747 level--;
748 if (level < 0)
749 goto finished;
750 goto between_desc;
751
752 case FMT_COLON:
753 case FMT_SLASH:
754 goto optional_comma;
755
756 case FMT_END:
757 error = unexpected_end;
758 goto syntax;
759
760 default:
761 if (gfc_notify_std (GFC_STD_GNU, "Extension: Missing comma at %C")
762 == FAILURE)
763 return FAILURE;
764 saved_token = t;
765 break;
766 }
767
768 goto format_item;
769
6de9cd9a
DN
770syntax:
771 /* Something went wrong. If the format we're checking is a string,
772 generate a warning, since the program is correct. If the format
773 is in a FORMAT statement, this messes up parsing, which is an
774 error. */
775 if (mode != MODE_STRING)
776 gfc_error ("%s in format string at %C", error);
777 else
778 {
779 gfc_warning ("%s in format string at %C", error);
780
781 /* TODO: More elaborate measures are needed to show where a problem
782 is within a format string that has been calculated. */
783 }
784
785 rv = FAILURE;
786
787finished:
788 return rv;
789}
790
791
792/* Given an expression node that is a constant string, see if it looks
793 like a format string. */
794
795static void
796check_format_string (gfc_expr * e)
797{
798
799 mode = MODE_STRING;
800 format_string = e->value.character.string;
801 check_format ();
802}
803
804
805/************ Fortran 95 I/O statement matchers *************/
806
807/* Match a FORMAT statement. This amounts to actually parsing the
808 format descriptors in order to correctly locate the end of the
809 format string. */
810
811match
812gfc_match_format (void)
813{
814 gfc_expr *e;
815 locus start;
816
817 if (gfc_statement_label == NULL)
818 {
819 gfc_error ("Missing format label at %C");
820 return MATCH_ERROR;
821 }
822 gfc_gobble_whitespace ();
823
824 mode = MODE_FORMAT;
825 format_length = 0;
826
63645982 827 start = gfc_current_locus;
6de9cd9a
DN
828
829 if (check_format () == FAILURE)
830 return MATCH_ERROR;
831
832 if (gfc_match_eos () != MATCH_YES)
833 {
834 gfc_syntax_error (ST_FORMAT);
835 return MATCH_ERROR;
836 }
837
838 /* The label doesn't get created until after the statement is done
839 being matched, so we have to leave the string for later. */
840
63645982 841 gfc_current_locus = start; /* Back to the beginning */
6de9cd9a
DN
842
843 new_st.loc = start;
844 new_st.op = EXEC_NOP;
845
846 e = gfc_get_expr();
847 e->expr_type = EXPR_CONSTANT;
848 e->ts.type = BT_CHARACTER;
9d64df18 849 e->ts.kind = gfc_default_character_kind;
6de9cd9a
DN
850 e->where = start;
851 e->value.character.string = format_string = gfc_getmem(format_length+1);
852 e->value.character.length = format_length;
853 gfc_statement_label->format = e;
854
855 mode = MODE_COPY;
856 check_format (); /* Guaranteed to succeed */
857 gfc_match_eos (); /* Guaranteed to succeed */
858
859 return MATCH_YES;
860}
861
862
863/* Match an expression I/O tag of some sort. */
864
865static match
866match_etag (const io_tag * tag, gfc_expr ** v)
867{
868 gfc_expr *result;
869 match m;
870
871 m = gfc_match (tag->spec, &result);
872 if (m != MATCH_YES)
873 return m;
874
875 if (*v != NULL)
876 {
877 gfc_error ("Duplicate %s specification at %C", tag->name);
878 gfc_free_expr (result);
879 return MATCH_ERROR;
880 }
881
882 *v = result;
883 return MATCH_YES;
884}
885
886
887/* Match a variable I/O tag of some sort. */
888
889static match
890match_vtag (const io_tag * tag, gfc_expr ** v)
891{
892 gfc_expr *result;
893 match m;
894
895 m = gfc_match (tag->spec, &result);
896 if (m != MATCH_YES)
897 return m;
898
899 if (*v != NULL)
900 {
901 gfc_error ("Duplicate %s specification at %C", tag->name);
902 gfc_free_expr (result);
903 return MATCH_ERROR;
904 }
905
906 if (result->symtree->n.sym->attr.intent == INTENT_IN)
907 {
908 gfc_error ("Variable tag cannot be INTENT(IN) at %C");
909 gfc_free_expr (result);
910 return MATCH_ERROR;
911 }
912
913 if (gfc_pure (NULL) && gfc_impure_variable (result->symtree->n.sym))
914 {
915 gfc_error ("Variable tag cannot be assigned in PURE procedure at %C");
916 gfc_free_expr (result);
917 return MATCH_ERROR;
918 }
919
920 *v = result;
921 return MATCH_YES;
922}
923
924
c9583ed2
TS
925/* Match I/O tags that cause variables to become redefined. */
926
927static match
928match_out_tag(const io_tag *tag, gfc_expr **result)
929{
930 match m;
931
932 m = match_vtag(tag, result);
933 if (m == MATCH_YES)
934 gfc_check_do_variable((*result)->symtree);
935
936 return m;
937}
938
939
6de9cd9a
DN
940/* Match a label I/O tag. */
941
942static match
943match_ltag (const io_tag * tag, gfc_st_label ** label)
944{
945 match m;
946 gfc_st_label *old;
947
948 old = *label;
949 m = gfc_match (tag->spec, label);
950 if (m == MATCH_YES && old != 0)
951 {
952 gfc_error ("Duplicate %s label specification at %C", tag->name);
953 return MATCH_ERROR;
954 }
955
956 return m;
957}
958
959
960/* Do expression resolution and type-checking on an expression tag. */
961
962static try
963resolve_tag (const io_tag * tag, gfc_expr * e)
964{
965
966 if (e == NULL)
967 return SUCCESS;
968
969 if (gfc_resolve_expr (e) == FAILURE)
970 return FAILURE;
971
972 if (e->ts.type != tag->type)
973 {
974 /* Format label can be integer varibale. */
c1df75d1 975 if (tag != &tag_format || e->ts.type != BT_INTEGER)
6de9cd9a 976 {
bf3ddf8a
FW
977 gfc_error ("%s tag at %L must be of type %s or %s", tag->name,
978 &e->where, gfc_basic_typename (tag->type),
979 gfc_basic_typename (BT_INTEGER));
6de9cd9a
DN
980 return FAILURE;
981 }
982 }
983
984 if (tag == &tag_format)
985 {
986 if (e->rank != 1 && e->rank != 0)
987 {
988 gfc_error ("FORMAT tag at %L cannot be array of strings",
989 &e->where);
990 return FAILURE;
991 }
ce2df7c6
FW
992 /* Check assigned label. */
993 if (e->expr_type == EXPR_VARIABLE && e->ts.type == BT_INTEGER
994 && e->symtree->n.sym->attr.assign != 1)
995 {
996 gfc_error ("Variable '%s' has not been assigned a format label at %L",
997 e->symtree->n.sym->name, &e->where);
998 return FAILURE;
999 }
6de9cd9a
DN
1000 }
1001 else
1002 {
1003 if (e->rank != 0)
1004 {
1005 gfc_error ("%s tag at %L must be scalar", tag->name, &e->where);
1006 return FAILURE;
1007 }
1008 }
1009
1010 return SUCCESS;
1011}
1012
1013
1014/* Match a single tag of an OPEN statement. */
1015
1016static match
1017match_open_element (gfc_open * open)
1018{
1019 match m;
1020
1021 m = match_etag (&tag_unit, &open->unit);
1022 if (m != MATCH_NO)
1023 return m;
c9583ed2 1024 m = match_out_tag (&tag_iostat, &open->iostat);
6de9cd9a
DN
1025 if (m != MATCH_NO)
1026 return m;
1027 m = match_etag (&tag_file, &open->file);
1028 if (m != MATCH_NO)
1029 return m;
1030 m = match_etag (&tag_status, &open->status);
1031 if (m != MATCH_NO)
1032 return m;
1033 m = match_etag (&tag_e_access, &open->access);
1034 if (m != MATCH_NO)
1035 return m;
1036 m = match_etag (&tag_e_form, &open->form);
1037 if (m != MATCH_NO)
1038 return m;
1039 m = match_etag (&tag_e_recl, &open->recl);
1040 if (m != MATCH_NO)
1041 return m;
1042 m = match_etag (&tag_e_blank, &open->blank);
1043 if (m != MATCH_NO)
1044 return m;
1045 m = match_etag (&tag_e_position, &open->position);
1046 if (m != MATCH_NO)
1047 return m;
1048 m = match_etag (&tag_e_action, &open->action);
1049 if (m != MATCH_NO)
1050 return m;
1051 m = match_etag (&tag_e_delim, &open->delim);
1052 if (m != MATCH_NO)
1053 return m;
1054 m = match_etag (&tag_e_pad, &open->pad);
1055 if (m != MATCH_NO)
1056 return m;
1057 m = match_ltag (&tag_err, &open->err);
1058 if (m != MATCH_NO)
1059 return m;
1060
1061 return MATCH_NO;
1062}
1063
1064
1065/* Free the gfc_open structure and all the expressions it contains. */
1066
1067void
1068gfc_free_open (gfc_open * open)
1069{
1070
1071 if (open == NULL)
1072 return;
1073
1074 gfc_free_expr (open->unit);
1075 gfc_free_expr (open->iostat);
1076 gfc_free_expr (open->file);
1077 gfc_free_expr (open->status);
1078 gfc_free_expr (open->access);
1079 gfc_free_expr (open->form);
1080 gfc_free_expr (open->recl);
1081 gfc_free_expr (open->blank);
1082 gfc_free_expr (open->position);
1083 gfc_free_expr (open->action);
1084 gfc_free_expr (open->delim);
1085 gfc_free_expr (open->pad);
1086
1087 gfc_free (open);
1088}
1089
1090
1091/* Resolve everything in a gfc_open structure. */
1092
1093try
1094gfc_resolve_open (gfc_open * open)
1095{
1096
1097 RESOLVE_TAG (&tag_unit, open->unit);
1098 RESOLVE_TAG (&tag_iostat, open->iostat);
1099 RESOLVE_TAG (&tag_file, open->file);
1100 RESOLVE_TAG (&tag_status, open->status);
1101 RESOLVE_TAG (&tag_e_form, open->form);
1102 RESOLVE_TAG (&tag_e_recl, open->recl);
1103
1104 RESOLVE_TAG (&tag_e_blank, open->blank);
1105 RESOLVE_TAG (&tag_e_position, open->position);
1106 RESOLVE_TAG (&tag_e_action, open->action);
1107 RESOLVE_TAG (&tag_e_delim, open->delim);
1108 RESOLVE_TAG (&tag_e_pad, open->pad);
1109
1110 if (gfc_reference_st_label (open->err, ST_LABEL_TARGET) == FAILURE)
1111 return FAILURE;
1112
1113 return SUCCESS;
1114}
1115
1116
e7dc5b4f 1117/* Match an OPEN statement. */
6de9cd9a
DN
1118
1119match
1120gfc_match_open (void)
1121{
1122 gfc_open *open;
1123 match m;
1124
1125 m = gfc_match_char ('(');
1126 if (m == MATCH_NO)
1127 return m;
1128
1129 open = gfc_getmem (sizeof (gfc_open));
1130
1131 m = match_open_element (open);
1132
1133 if (m == MATCH_ERROR)
1134 goto cleanup;
1135 if (m == MATCH_NO)
1136 {
1137 m = gfc_match_expr (&open->unit);
1138 if (m == MATCH_NO)
1139 goto syntax;
1140 if (m == MATCH_ERROR)
1141 goto cleanup;
1142 }
1143
1144 for (;;)
1145 {
1146 if (gfc_match_char (')') == MATCH_YES)
1147 break;
1148 if (gfc_match_char (',') != MATCH_YES)
1149 goto syntax;
1150
1151 m = match_open_element (open);
1152 if (m == MATCH_ERROR)
1153 goto cleanup;
1154 if (m == MATCH_NO)
1155 goto syntax;
1156 }
1157
1158 if (gfc_match_eos () == MATCH_NO)
1159 goto syntax;
1160
1161 if (gfc_pure (NULL))
1162 {
1163 gfc_error ("OPEN statement not allowed in PURE procedure at %C");
1164 goto cleanup;
1165 }
1166
1167 new_st.op = EXEC_OPEN;
1168 new_st.ext.open = open;
1169 return MATCH_YES;
1170
1171syntax:
1172 gfc_syntax_error (ST_OPEN);
1173
1174cleanup:
1175 gfc_free_open (open);
1176 return MATCH_ERROR;
1177}
1178
1179
1180/* Free a gfc_close structure an all its expressions. */
1181
1182void
1183gfc_free_close (gfc_close * close)
1184{
1185
1186 if (close == NULL)
1187 return;
1188
1189 gfc_free_expr (close->unit);
1190 gfc_free_expr (close->iostat);
1191 gfc_free_expr (close->status);
1192
1193 gfc_free (close);
1194}
1195
1196
e7dc5b4f 1197/* Match elements of a CLOSE statement. */
6de9cd9a
DN
1198
1199static match
1200match_close_element (gfc_close * close)
1201{
1202 match m;
1203
1204 m = match_etag (&tag_unit, &close->unit);
1205 if (m != MATCH_NO)
1206 return m;
1207 m = match_etag (&tag_status, &close->status);
1208 if (m != MATCH_NO)
1209 return m;
c9583ed2 1210 m = match_out_tag (&tag_iostat, &close->iostat);
6de9cd9a
DN
1211 if (m != MATCH_NO)
1212 return m;
1213 m = match_ltag (&tag_err, &close->err);
1214 if (m != MATCH_NO)
1215 return m;
1216
1217 return MATCH_NO;
1218}
1219
1220
1221/* Match a CLOSE statement. */
1222
1223match
1224gfc_match_close (void)
1225{
1226 gfc_close *close;
1227 match m;
1228
1229 m = gfc_match_char ('(');
1230 if (m == MATCH_NO)
1231 return m;
1232
1233 close = gfc_getmem (sizeof (gfc_close));
1234
1235 m = match_close_element (close);
1236
1237 if (m == MATCH_ERROR)
1238 goto cleanup;
1239 if (m == MATCH_NO)
1240 {
1241 m = gfc_match_expr (&close->unit);
1242 if (m == MATCH_NO)
1243 goto syntax;
1244 if (m == MATCH_ERROR)
1245 goto cleanup;
1246 }
1247
1248 for (;;)
1249 {
1250 if (gfc_match_char (')') == MATCH_YES)
1251 break;
1252 if (gfc_match_char (',') != MATCH_YES)
1253 goto syntax;
1254
1255 m = match_close_element (close);
1256 if (m == MATCH_ERROR)
1257 goto cleanup;
1258 if (m == MATCH_NO)
1259 goto syntax;
1260 }
1261
1262 if (gfc_match_eos () == MATCH_NO)
1263 goto syntax;
1264
1265 if (gfc_pure (NULL))
1266 {
1267 gfc_error ("CLOSE statement not allowed in PURE procedure at %C");
1268 goto cleanup;
1269 }
1270
1271 new_st.op = EXEC_CLOSE;
1272 new_st.ext.close = close;
1273 return MATCH_YES;
1274
1275syntax:
1276 gfc_syntax_error (ST_CLOSE);
1277
1278cleanup:
1279 gfc_free_close (close);
1280 return MATCH_ERROR;
1281}
1282
1283
1284/* Resolve everything in a gfc_close structure. */
1285
1286try
1287gfc_resolve_close (gfc_close * close)
1288{
1289
1290 RESOLVE_TAG (&tag_unit, close->unit);
1291 RESOLVE_TAG (&tag_iostat, close->iostat);
1292 RESOLVE_TAG (&tag_status, close->status);
1293
1294 if (gfc_reference_st_label (close->err, ST_LABEL_TARGET) == FAILURE)
1295 return FAILURE;
1296
1297 return SUCCESS;
1298}
1299
1300
1301/* Free a gfc_filepos structure. */
1302
1303void
1304gfc_free_filepos (gfc_filepos * fp)
1305{
1306
1307 gfc_free_expr (fp->unit);
1308 gfc_free_expr (fp->iostat);
1309 gfc_free (fp);
1310}
1311
1312
1313/* Match elements of a REWIND, BACKSPACE or ENDFILE statement. */
1314
1315static match
1316match_file_element (gfc_filepos * fp)
1317{
1318 match m;
1319
1320 m = match_etag (&tag_unit, &fp->unit);
1321 if (m != MATCH_NO)
1322 return m;
c9583ed2 1323 m = match_out_tag (&tag_iostat, &fp->iostat);
6de9cd9a
DN
1324 if (m != MATCH_NO)
1325 return m;
1326 m = match_ltag (&tag_err, &fp->err);
1327 if (m != MATCH_NO)
1328 return m;
1329
1330 return MATCH_NO;
1331}
1332
1333
1334/* Match the second half of the file-positioning statements, REWIND,
1335 BACKSPACE or ENDFILE. */
1336
1337static match
1338match_filepos (gfc_statement st, gfc_exec_op op)
1339{
1340 gfc_filepos *fp;
1341 match m;
1342
1343 fp = gfc_getmem (sizeof (gfc_filepos));
1344
1345 if (gfc_match_char ('(') == MATCH_NO)
1346 {
1347 m = gfc_match_expr (&fp->unit);
1348 if (m == MATCH_ERROR)
1349 goto cleanup;
1350 if (m == MATCH_NO)
1351 goto syntax;
1352
1353 goto done;
1354 }
1355
1356 m = match_file_element (fp);
1357 if (m == MATCH_ERROR)
1358 goto done;
1359 if (m == MATCH_NO)
1360 {
1361 m = gfc_match_expr (&fp->unit);
1362 if (m == MATCH_ERROR)
1363 goto done;
1364 if (m == MATCH_NO)
1365 goto syntax;
1366 }
1367
1368 for (;;)
1369 {
1370 if (gfc_match_char (')') == MATCH_YES)
1371 break;
1372 if (gfc_match_char (',') != MATCH_YES)
1373 goto syntax;
1374
1375 m = match_file_element (fp);
1376 if (m == MATCH_ERROR)
1377 goto cleanup;
1378 if (m == MATCH_NO)
1379 goto syntax;
1380 }
1381
1382done:
1383 if (gfc_match_eos () != MATCH_YES)
1384 goto syntax;
1385
1386 if (gfc_pure (NULL))
1387 {
1388 gfc_error ("%s statement not allowed in PURE procedure at %C",
1389 gfc_ascii_statement (st));
1390
1391 goto cleanup;
1392 }
1393
1394 new_st.op = op;
1395 new_st.ext.filepos = fp;
1396 return MATCH_YES;
1397
1398syntax:
1399 gfc_syntax_error (st);
1400
1401cleanup:
1402 gfc_free_filepos (fp);
1403 return MATCH_ERROR;
1404}
1405
1406
1407try
1408gfc_resolve_filepos (gfc_filepos * fp)
1409{
1410
1411 RESOLVE_TAG (&tag_unit, fp->unit);
1412 if (gfc_reference_st_label (fp->err, ST_LABEL_TARGET) == FAILURE)
1413 return FAILURE;
1414
1415 return SUCCESS;
1416}
1417
1418
1419/* Match the file positioning statements: ENDFILE, BACKSPACE or
1420 REWIND. */
1421
1422match
1423gfc_match_endfile (void)
1424{
1425
1426 return match_filepos (ST_END_FILE, EXEC_ENDFILE);
1427}
1428
1429match
1430gfc_match_backspace (void)
1431{
1432
1433 return match_filepos (ST_BACKSPACE, EXEC_BACKSPACE);
1434}
1435
1436match
1437gfc_match_rewind (void)
1438{
1439
1440 return match_filepos (ST_REWIND, EXEC_REWIND);
1441}
1442
1443
e7dc5b4f 1444/******************** Data Transfer Statements *********************/
6de9cd9a
DN
1445
1446typedef enum
1447{ M_READ, M_WRITE, M_PRINT, M_INQUIRE }
1448io_kind;
1449
1450
1451/* Return a default unit number. */
1452
1453static gfc_expr *
1454default_unit (io_kind k)
1455{
1456 int unit;
1457
1458 if (k == M_READ)
1459 unit = 5;
1460 else
1461 unit = 6;
1462
1463 return gfc_int_expr (unit);
1464}
1465
1466
1467/* Match a unit specification for a data transfer statement. */
1468
1469static match
1470match_dt_unit (io_kind k, gfc_dt * dt)
1471{
1472 gfc_expr *e;
1473
1474 if (gfc_match_char ('*') == MATCH_YES)
1475 {
1476 if (dt->io_unit != NULL)
1477 goto conflict;
1478
1479 dt->io_unit = default_unit (k);
1480 return MATCH_YES;
1481 }
1482
1483 if (gfc_match_expr (&e) == MATCH_YES)
1484 {
1485 if (dt->io_unit != NULL)
1486 {
1487 gfc_free_expr (e);
1488 goto conflict;
1489 }
1490
1491 dt->io_unit = e;
1492 return MATCH_YES;
1493 }
1494
1495 return MATCH_NO;
1496
1497conflict:
1498 gfc_error ("Duplicate UNIT specification at %C");
1499 return MATCH_ERROR;
1500}
1501
1502
1503/* Match a format specification. */
1504
1505static match
1506match_dt_format (gfc_dt * dt)
1507{
1508 locus where;
1509 gfc_expr *e;
1510 gfc_st_label *label;
1511
63645982 1512 where = gfc_current_locus;
6de9cd9a
DN
1513
1514 if (gfc_match_char ('*') == MATCH_YES)
1515 {
1516 if (dt->format_expr != NULL || dt->format_label != NULL)
1517 goto conflict;
1518
1519 dt->format_label = &format_asterisk;
1520 return MATCH_YES;
1521 }
1522
1523 if (gfc_match_st_label (&label, 0) == MATCH_YES)
1524 {
1525 if (dt->format_expr != NULL || dt->format_label != NULL)
1526 {
1527 gfc_free_st_label (label);
1528 goto conflict;
1529 }
1530
1531 if (gfc_reference_st_label (label, ST_LABEL_FORMAT) == FAILURE)
1532 return MATCH_ERROR;
1533
1534 dt->format_label = label;
1535 return MATCH_YES;
1536 }
1537
1538 if (gfc_match_expr (&e) == MATCH_YES)
1539 {
1540 if (dt->format_expr != NULL || dt->format_label != NULL)
1541 {
1542 gfc_free_expr (e);
1543 goto conflict;
1544 }
6de9cd9a
DN
1545 dt->format_expr = e;
1546 return MATCH_YES;
1547 }
1548
63645982 1549 gfc_current_locus = where; /* The only case where we have to restore */
6de9cd9a
DN
1550
1551 return MATCH_NO;
1552
1553conflict:
1554 gfc_error ("Duplicate format specification at %C");
1555 return MATCH_ERROR;
1556}
1557
1558
1559/* Traverse a namelist that is part of a READ statement to make sure
1560 that none of the variables in the namelist are INTENT(IN). Returns
1561 nonzero if we find such a variable. */
1562
1563static int
1564check_namelist (gfc_symbol * sym)
1565{
1566 gfc_namelist *p;
1567
1568 for (p = sym->namelist; p; p = p->next)
1569 if (p->sym->attr.intent == INTENT_IN)
1570 {
1571 gfc_error ("Symbol '%s' in namelist '%s' is INTENT(IN) at %C",
1572 p->sym->name, sym->name);
1573 return 1;
1574 }
1575
1576 return 0;
1577}
1578
1579
1580/* Match a single data transfer element. */
1581
1582static match
1583match_dt_element (io_kind k, gfc_dt * dt)
1584{
1585 char name[GFC_MAX_SYMBOL_LEN + 1];
1586 gfc_symbol *sym;
1587 match m;
1588
1589 if (gfc_match (" unit =") == MATCH_YES)
1590 {
1591 m = match_dt_unit (k, dt);
1592 if (m != MATCH_NO)
1593 return m;
1594 }
1595
1596 if (gfc_match (" fmt =") == MATCH_YES)
1597 {
1598 m = match_dt_format (dt);
1599 if (m != MATCH_NO)
1600 return m;
1601 }
1602
1603 if (gfc_match (" nml = %n", name) == MATCH_YES)
1604 {
1605 if (dt->namelist != NULL)
1606 {
1607 gfc_error ("Duplicate NML specification at %C");
1608 return MATCH_ERROR;
1609 }
1610
1611 if (gfc_find_symbol (name, NULL, 1, &sym))
1612 return MATCH_ERROR;
1613
1614 if (sym == NULL || sym->attr.flavor != FL_NAMELIST)
1615 {
1616 gfc_error ("Symbol '%s' at %C must be a NAMELIST group name",
1617 sym != NULL ? sym->name : name);
1618 return MATCH_ERROR;
1619 }
1620
1621 dt->namelist = sym;
1622 if (k == M_READ && check_namelist (sym))
1623 return MATCH_ERROR;
1624
1625 return MATCH_YES;
1626 }
1627
1628 m = match_etag (&tag_rec, &dt->rec);
1629 if (m != MATCH_NO)
1630 return m;
c9583ed2 1631 m = match_out_tag (&tag_iostat, &dt->iostat);
6de9cd9a
DN
1632 if (m != MATCH_NO)
1633 return m;
1634 m = match_ltag (&tag_err, &dt->err);
1635 if (m != MATCH_NO)
1636 return m;
1637 m = match_etag (&tag_advance, &dt->advance);
1638 if (m != MATCH_NO)
1639 return m;
c9583ed2 1640 m = match_out_tag (&tag_size, &dt->size);
6de9cd9a
DN
1641 if (m != MATCH_NO)
1642 return m;
1643
1644 m = match_ltag (&tag_end, &dt->end);
1645 if (m == MATCH_YES)
63645982 1646 dt->end_where = gfc_current_locus;
6de9cd9a
DN
1647 if (m != MATCH_NO)
1648 return m;
1649
1650 m = match_ltag (&tag_eor, &dt->eor);
1651 if (m == MATCH_YES)
63645982 1652 dt->eor_where = gfc_current_locus;
6de9cd9a
DN
1653 if (m != MATCH_NO)
1654 return m;
1655
1656 return MATCH_NO;
1657}
1658
1659
1660/* Free a data transfer structure and everything below it. */
1661
1662void
1663gfc_free_dt (gfc_dt * dt)
1664{
1665
1666 if (dt == NULL)
1667 return;
1668
1669 gfc_free_expr (dt->io_unit);
1670 gfc_free_expr (dt->format_expr);
1671 gfc_free_expr (dt->rec);
1672 gfc_free_expr (dt->advance);
1673 gfc_free_expr (dt->iostat);
1674 gfc_free_expr (dt->size);
1675
1676 gfc_free (dt);
1677}
1678
1679
1680/* Resolve everything in a gfc_dt structure. */
1681
1682try
1683gfc_resolve_dt (gfc_dt * dt)
1684{
1685 gfc_expr *e;
1686
1687 RESOLVE_TAG (&tag_format, dt->format_expr);
1688 RESOLVE_TAG (&tag_rec, dt->rec);
1689 RESOLVE_TAG (&tag_advance, dt->advance);
1690 RESOLVE_TAG (&tag_iostat, dt->iostat);
1691 RESOLVE_TAG (&tag_size, dt->size);
1692
1693 e = dt->io_unit;
1694 if (gfc_resolve_expr (e) == SUCCESS
1695 && (e->ts.type != BT_INTEGER
1696 && (e->ts.type != BT_CHARACTER
1697 || e->expr_type != EXPR_VARIABLE)))
1698 {
1699 gfc_error
1700 ("UNIT specification at %L must be an INTEGER expression or a "
1701 "CHARACTER variable", &e->where);
1702 return FAILURE;
1703 }
1704
1705 /* Sanity checks on data transfer statements. */
1706 if (e->ts.type == BT_CHARACTER)
1707 {
1708 if (dt->rec != NULL)
1709 {
1710 gfc_error ("REC tag at %L is incompatible with internal file",
1711 &dt->rec->where);
1712 return FAILURE;
1713 }
1714
1715 if (dt->namelist != NULL)
1716 {
1717 gfc_error ("Internal file at %L is incompatible with namelist",
1718 &dt->io_unit->where);
1719 return FAILURE;
1720 }
1721
1722 if (dt->advance != NULL)
1723 {
1724 gfc_error ("ADVANCE tag at %L is incompatible with internal file",
1725 &dt->advance->where);
1726 return FAILURE;
1727 }
1728 }
1729
1730 if (dt->rec != NULL)
1731 {
1732 if (dt->end != NULL)
1733 {
1734 gfc_error ("REC tag at %L is incompatible with END tag",
1735 &dt->rec->where);
1736 return FAILURE;
1737 }
1738
1739 if (dt->format_label == &format_asterisk)
1740 {
1741 gfc_error
1742 ("END tag at %L is incompatible with list directed format (*)",
1743 &dt->end_where);
1744 return FAILURE;
1745 }
1746
1747 if (dt->namelist != NULL)
1748 {
1749 gfc_error ("REC tag at %L is incompatible with namelist",
1750 &dt->rec->where);
1751 return FAILURE;
1752 }
1753 }
1754
1755 if (dt->advance != NULL && dt->format_label == &format_asterisk)
1756 {
1757 gfc_error ("ADVANCE tag at %L is incompatible with list directed "
1758 "format (*)", &dt->advance->where);
1759 return FAILURE;
1760 }
1761
1762 if (dt->eor != 0 && dt->advance == NULL)
1763 {
1764 gfc_error ("EOR tag at %L requires an ADVANCE tag", &dt->eor_where);
1765 return FAILURE;
1766 }
1767
1768 if (dt->size != NULL && dt->advance == NULL)
1769 {
1770 gfc_error ("SIZE tag at %L requires an ADVANCE tag", &dt->size->where);
1771 return FAILURE;
1772 }
1773
1774 /* TODO: Make sure the ADVANCE tag is 'yes' or 'no' if it is a string
1775 constant. */
1776
1777 if (gfc_reference_st_label (dt->err, ST_LABEL_TARGET) == FAILURE)
1778 return FAILURE;
1779
1780 if (gfc_reference_st_label (dt->end, ST_LABEL_TARGET) == FAILURE)
1781 return FAILURE;
1782
1783 if (gfc_reference_st_label (dt->eor, ST_LABEL_TARGET) == FAILURE)
1784 return FAILURE;
1785
1f2959f0 1786 /* Check the format label actually exists. */
6de9cd9a
DN
1787 if (dt->format_label && dt->format_label != &format_asterisk
1788 && dt->format_label->defined == ST_LABEL_UNKNOWN)
1789 {
1790 gfc_error ("FORMAT label %d at %L not defined", dt->format_label->value,
1791 &dt->format_label->where);
1792 return FAILURE;
1793 }
1794 return SUCCESS;
1795}
1796
1797
1798/* Given an io_kind, return its name. */
1799
1800static const char *
1801io_kind_name (io_kind k)
1802{
1803 const char *name;
1804
1805 switch (k)
1806 {
1807 case M_READ:
1808 name = "READ";
1809 break;
1810 case M_WRITE:
1811 name = "WRITE";
1812 break;
1813 case M_PRINT:
1814 name = "PRINT";
1815 break;
1816 case M_INQUIRE:
1817 name = "INQUIRE";
1818 break;
1819 default:
1820 gfc_internal_error ("io_kind_name(): bad I/O-kind");
1821 }
1822
1823 return name;
1824}
1825
1826
1827/* Match an IO iteration statement of the form:
1828
1829 ( [<IO element> ,] <IO element>, I = <expr>, <expr> [, <expr> ] )
1830
1831 which is equivalent to a single IO element. This function is
1832 mutually recursive with match_io_element(). */
1833
1834static match match_io_element (io_kind k, gfc_code **);
1835
1836static match
1837match_io_iterator (io_kind k, gfc_code ** result)
1838{
1839 gfc_code *head, *tail, *new;
1840 gfc_iterator *iter;
1841 locus old_loc;
1842 match m;
1843 int n;
1844
1845 iter = NULL;
1846 head = NULL;
63645982 1847 old_loc = gfc_current_locus;
6de9cd9a
DN
1848
1849 if (gfc_match_char ('(') != MATCH_YES)
1850 return MATCH_NO;
1851
1852 m = match_io_element (k, &head);
1853 tail = head;
1854
1855 if (m != MATCH_YES || gfc_match_char (',') != MATCH_YES)
1856 {
1857 m = MATCH_NO;
1858 goto cleanup;
1859 }
1860
1861 /* Can't be anything but an IO iterator. Build a list. */
1862 iter = gfc_get_iterator ();
1863
1864 for (n = 1;; n++)
1865 {
1866 m = gfc_match_iterator (iter, 0);
1867 if (m == MATCH_ERROR)
1868 goto cleanup;
1869 if (m == MATCH_YES)
c9583ed2
TS
1870 {
1871 gfc_check_do_variable (iter->var->symtree);
1872 break;
1873 }
6de9cd9a
DN
1874
1875 m = match_io_element (k, &new);
1876 if (m == MATCH_ERROR)
1877 goto cleanup;
1878 if (m == MATCH_NO)
1879 {
1880 if (n > 2)
1881 goto syntax;
1882 goto cleanup;
1883 }
1884
1885 tail = gfc_append_code (tail, new);
1886
1887 if (gfc_match_char (',') != MATCH_YES)
1888 {
1889 if (n > 2)
1890 goto syntax;
1891 m = MATCH_NO;
1892 goto cleanup;
1893 }
1894 }
1895
1896 if (gfc_match_char (')') != MATCH_YES)
1897 goto syntax;
1898
1899 new = gfc_get_code ();
1900 new->op = EXEC_DO;
1901 new->ext.iterator = iter;
1902
1903 new->block = gfc_get_code ();
1904 new->block->op = EXEC_DO;
1905 new->block->next = head;
1906
1907 *result = new;
1908 return MATCH_YES;
1909
1910syntax:
1911 gfc_error ("Syntax error in I/O iterator at %C");
1912 m = MATCH_ERROR;
1913
1914cleanup:
1915 gfc_free_iterator (iter, 1);
1916 gfc_free_statements (head);
63645982 1917 gfc_current_locus = old_loc;
6de9cd9a
DN
1918 return m;
1919}
1920
1921
1922/* Match a single element of an IO list, which is either a single
1923 expression or an IO Iterator. */
1924
1925static match
1926match_io_element (io_kind k, gfc_code ** cpp)
1927{
1928 gfc_expr *expr;
1929 gfc_code *cp;
1930 match m;
1931
1932 expr = NULL;
1933
1934 m = match_io_iterator (k, cpp);
1935 if (m == MATCH_YES)
1936 return MATCH_YES;
1937
1938 if (k == M_READ)
1939 {
1940 m = gfc_match_variable (&expr, 0);
1941 if (m == MATCH_NO)
1942 gfc_error ("Expected variable in READ statement at %C");
1943 }
1944 else
1945 {
1946 m = gfc_match_expr (&expr);
1947 if (m == MATCH_NO)
1948 gfc_error ("Expected expression in %s statement at %C",
1949 io_kind_name (k));
1950 }
1951
1952 if (m == MATCH_YES)
1953 switch (k)
1954 {
1955 case M_READ:
1956 if (expr->symtree->n.sym->attr.intent == INTENT_IN)
1957 {
1958 gfc_error
1959 ("Variable '%s' in input list at %C cannot be INTENT(IN)",
1960 expr->symtree->n.sym->name);
1961 m = MATCH_ERROR;
1962 }
1963
1964 if (gfc_pure (NULL)
1965 && gfc_impure_variable (expr->symtree->n.sym)
1966 && current_dt->io_unit->ts.type == BT_CHARACTER)
1967 {
1968 gfc_error ("Cannot read to variable '%s' in PURE procedure at %C",
1969 expr->symtree->n.sym->name);
1970 m = MATCH_ERROR;
1971 }
1972
c9583ed2
TS
1973 if (gfc_check_do_variable (expr->symtree))
1974 m = MATCH_ERROR;
1975
6de9cd9a
DN
1976 break;
1977
1978 case M_WRITE:
1979 if (current_dt->io_unit->ts.type == BT_CHARACTER
1980 && gfc_pure (NULL)
1981 && current_dt->io_unit->expr_type == EXPR_VARIABLE
1982 && gfc_impure_variable (current_dt->io_unit->symtree->n.sym))
1983 {
1984 gfc_error
1985 ("Cannot write to internal file unit '%s' at %C inside a "
1986 "PURE procedure", current_dt->io_unit->symtree->n.sym->name);
1987 m = MATCH_ERROR;
1988 }
1989
1990 break;
1991
1992 default:
1993 break;
1994 }
1995
1996 if (m != MATCH_YES)
1997 {
1998 gfc_free_expr (expr);
1999 return MATCH_ERROR;
2000 }
2001
2002 cp = gfc_get_code ();
2003 cp->op = EXEC_TRANSFER;
2004 cp->expr = expr;
2005
2006 *cpp = cp;
2007 return MATCH_YES;
2008}
2009
2010
2011/* Match an I/O list, building gfc_code structures as we go. */
2012
2013static match
2014match_io_list (io_kind k, gfc_code ** head_p)
2015{
2016 gfc_code *head, *tail, *new;
2017 match m;
2018
2019 *head_p = head = tail = NULL;
2020 if (gfc_match_eos () == MATCH_YES)
2021 return MATCH_YES;
2022
2023 for (;;)
2024 {
2025 m = match_io_element (k, &new);
2026 if (m == MATCH_ERROR)
2027 goto cleanup;
2028 if (m == MATCH_NO)
2029 goto syntax;
2030
2031 tail = gfc_append_code (tail, new);
2032 if (head == NULL)
2033 head = new;
2034
2035 if (gfc_match_eos () == MATCH_YES)
2036 break;
2037 if (gfc_match_char (',') != MATCH_YES)
2038 goto syntax;
2039 }
2040
2041 *head_p = head;
2042 return MATCH_YES;
2043
2044syntax:
2045 gfc_error ("Syntax error in %s statement at %C", io_kind_name (k));
2046
2047cleanup:
2048 gfc_free_statements (head);
2049 return MATCH_ERROR;
2050}
2051
2052
2053/* Attach the data transfer end node. */
2054
2055static void
2056terminate_io (gfc_code * io_code)
2057{
2058 gfc_code *c;
2059
2060 if (io_code == NULL)
2061 io_code = &new_st;
2062
2063 c = gfc_get_code ();
2064 c->op = EXEC_DT_END;
2065
2066 /* Point to structure that is already there */
2067 c->ext.dt = new_st.ext.dt;
2068 gfc_append_code (io_code, c);
2069}
2070
2071
2072/* Match a READ, WRITE or PRINT statement. */
2073
2074static match
2075match_io (io_kind k)
2076{
2077 char name[GFC_MAX_SYMBOL_LEN + 1];
2078 gfc_code *io_code;
2079 gfc_symbol *sym;
2080 gfc_expr *expr;
0ff0dfbf 2081 int comma_flag, c;
6de9cd9a
DN
2082 locus where;
2083 gfc_dt *dt;
2084 match m;
2085
2086 comma_flag = 0;
2087 current_dt = dt = gfc_getmem (sizeof (gfc_dt));
2088
2089 if (gfc_match_char ('(') == MATCH_NO)
2090 {
2091 if (k == M_WRITE)
2092 goto syntax;
2093
0ff0dfbf
TS
2094 if (gfc_current_form == FORM_FREE)
2095 {
2096 c = gfc_peek_char();
2097 if (c != ' ' && c != '*' && c != '\'' && c != '"')
2098 {
2099 m = MATCH_NO;
2100 goto cleanup;
2101 }
2102 }
2103
6de9cd9a
DN
2104 m = match_dt_format (dt);
2105 if (m == MATCH_ERROR)
2106 goto cleanup;
2107 if (m == MATCH_NO)
2108 goto syntax;
2109
2110 comma_flag = 1;
2111 dt->io_unit = default_unit (k);
2112 goto get_io_list;
2113 }
2114
2115 /* Match a control list */
2116 if (match_dt_element (k, dt) == MATCH_YES)
2117 goto next;
2118 if (match_dt_unit (k, dt) != MATCH_YES)
2119 goto loop;
2120
2121 if (gfc_match_char (')') == MATCH_YES)
2122 goto get_io_list;
2123 if (gfc_match_char (',') != MATCH_YES)
2124 goto syntax;
2125
2126 m = match_dt_element (k, dt);
2127 if (m == MATCH_YES)
2128 goto next;
2129 if (m == MATCH_ERROR)
2130 goto cleanup;
2131
2132 m = match_dt_format (dt);
2133 if (m == MATCH_YES)
2134 goto next;
2135 if (m == MATCH_ERROR)
2136 goto cleanup;
2137
63645982 2138 where = gfc_current_locus;
6de9cd9a
DN
2139
2140 if (gfc_match_name (name) == MATCH_YES
2141 && !gfc_find_symbol (name, NULL, 1, &sym)
2142 && sym->attr.flavor == FL_NAMELIST)
2143 {
2144 dt->namelist = sym;
2145 if (k == M_READ && check_namelist (sym))
2146 {
2147 m = MATCH_ERROR;
2148 goto cleanup;
2149 }
2150 goto next;
2151 }
2152
63645982 2153 gfc_current_locus = where;
6de9cd9a
DN
2154
2155 goto loop; /* No matches, try regular elements */
2156
2157next:
2158 if (gfc_match_char (')') == MATCH_YES)
2159 goto get_io_list;
2160 if (gfc_match_char (',') != MATCH_YES)
2161 goto syntax;
2162
2163loop:
2164 for (;;)
2165 {
2166 m = match_dt_element (k, dt);
2167 if (m == MATCH_NO)
2168 goto syntax;
2169 if (m == MATCH_ERROR)
2170 goto cleanup;
2171
2172 if (gfc_match_char (')') == MATCH_YES)
2173 break;
2174 if (gfc_match_char (',') != MATCH_YES)
2175 goto syntax;
2176 }
2177
2178get_io_list:
2179 /* Optional leading comma (non-standard). */
cdde7b65
TS
2180 if (!comma_flag
2181 && gfc_match_char (',') == MATCH_YES
2182 && k == M_WRITE
c9583ed2
TS
2183 && gfc_notify_std (GFC_STD_GNU, "Extension: Comma before output "
2184 "item list at %C is an extension") == FAILURE)
cdde7b65 2185 return MATCH_ERROR;
6de9cd9a
DN
2186
2187 io_code = NULL;
2188 if (gfc_match_eos () != MATCH_YES)
2189 {
2190 if (comma_flag && gfc_match_char (',') != MATCH_YES)
2191 {
2192 gfc_error ("Expected comma in I/O list at %C");
2193 m = MATCH_ERROR;
2194 goto cleanup;
2195 }
2196
2197 m = match_io_list (k, &io_code);
2198 if (m == MATCH_ERROR)
2199 goto cleanup;
2200 if (m == MATCH_NO)
2201 goto syntax;
2202 }
2203
2204 /* A full IO statement has been matched. */
2205 if (dt->io_unit->expr_type == EXPR_VARIABLE
2206 && k == M_WRITE
2207 && dt->io_unit->ts.type == BT_CHARACTER
2208 && dt->io_unit->symtree->n.sym->attr.intent == INTENT_IN)
2209 {
2210 gfc_error ("Internal file '%s' at %L is INTENT(IN)",
2211 dt->io_unit->symtree->n.sym->name, &dt->io_unit->where);
2212 m = MATCH_ERROR;
2213 goto cleanup;
2214 }
2215
2216 expr = dt->format_expr;
2217
2218 if (expr != NULL && expr->expr_type == EXPR_CONSTANT)
2219 check_format_string (expr);
2220
2221 if (gfc_pure (NULL)
2222 && (k == M_READ || k == M_WRITE)
2223 && dt->io_unit->ts.type != BT_CHARACTER)
2224 {
2225 gfc_error
2226 ("io-unit in %s statement at %C must be an internal file in a "
2227 "PURE procedure", io_kind_name (k));
2228 m = MATCH_ERROR;
2229 goto cleanup;
2230 }
2231
2232 new_st.op = (k == M_READ) ? EXEC_READ : EXEC_WRITE;
2233 new_st.ext.dt = dt;
2234 new_st.next = io_code;
2235
2236 terminate_io (io_code);
2237
2238 return MATCH_YES;
2239
2240syntax:
2241 gfc_error ("Syntax error in %s statement at %C", io_kind_name (k));
2242 m = MATCH_ERROR;
2243
2244cleanup:
2245 gfc_free_dt (dt);
2246 return m;
2247}
2248
2249
2250match
2251gfc_match_read (void)
2252{
2253 return match_io (M_READ);
2254}
2255
2256match
2257gfc_match_write (void)
2258{
2259 return match_io (M_WRITE);
2260}
2261
2262match
2263gfc_match_print (void)
2264{
2265 match m;
2266
2267 m = match_io (M_PRINT);
2268 if (m != MATCH_YES)
2269 return m;
2270
2271 if (gfc_pure (NULL))
2272 {
2273 gfc_error ("PRINT statement at %C not allowed within PURE procedure");
2274 return MATCH_ERROR;
2275 }
2276
2277 return MATCH_YES;
2278}
2279
2280
2281/* Free a gfc_inquire structure. */
2282
2283void
2284gfc_free_inquire (gfc_inquire * inquire)
2285{
2286
2287 if (inquire == NULL)
2288 return;
2289
2290 gfc_free_expr (inquire->unit);
2291 gfc_free_expr (inquire->file);
2292 gfc_free_expr (inquire->iostat);
2293 gfc_free_expr (inquire->exist);
2294 gfc_free_expr (inquire->opened);
2295 gfc_free_expr (inquire->number);
2296 gfc_free_expr (inquire->named);
2297 gfc_free_expr (inquire->name);
2298 gfc_free_expr (inquire->access);
2299 gfc_free_expr (inquire->sequential);
2300 gfc_free_expr (inquire->direct);
2301 gfc_free_expr (inquire->form);
2302 gfc_free_expr (inquire->formatted);
2303 gfc_free_expr (inquire->unformatted);
2304 gfc_free_expr (inquire->recl);
2305 gfc_free_expr (inquire->nextrec);
2306 gfc_free_expr (inquire->blank);
2307 gfc_free_expr (inquire->position);
2308 gfc_free_expr (inquire->action);
2309 gfc_free_expr (inquire->read);
2310 gfc_free_expr (inquire->write);
2311 gfc_free_expr (inquire->readwrite);
2312 gfc_free_expr (inquire->delim);
2313 gfc_free_expr (inquire->pad);
2314 gfc_free_expr (inquire->iolength);
2315
2316 gfc_free (inquire);
2317}
2318
2319
2320/* Match an element of an INQUIRE statement. */
2321
2322#define RETM if (m != MATCH_NO) return m;
2323
2324static match
2325match_inquire_element (gfc_inquire * inquire)
2326{
2327 match m;
2328
2329 m = match_etag (&tag_unit, &inquire->unit);
2330 RETM m = match_etag (&tag_file, &inquire->file);
2331 RETM m = match_ltag (&tag_err, &inquire->err);
c9583ed2 2332 RETM m = match_out_tag (&tag_iostat, &inquire->iostat);
6de9cd9a
DN
2333 RETM m = match_vtag (&tag_exist, &inquire->exist);
2334 RETM m = match_vtag (&tag_opened, &inquire->opened);
2335 RETM m = match_vtag (&tag_named, &inquire->named);
2336 RETM m = match_vtag (&tag_name, &inquire->name);
c9583ed2 2337 RETM m = match_out_tag (&tag_number, &inquire->number);
6de9cd9a
DN
2338 RETM m = match_vtag (&tag_s_access, &inquire->access);
2339 RETM m = match_vtag (&tag_sequential, &inquire->sequential);
2340 RETM m = match_vtag (&tag_direct, &inquire->direct);
2341 RETM m = match_vtag (&tag_s_form, &inquire->form);
2342 RETM m = match_vtag (&tag_formatted, &inquire->formatted);
2343 RETM m = match_vtag (&tag_unformatted, &inquire->unformatted);
c9583ed2
TS
2344 RETM m = match_out_tag (&tag_s_recl, &inquire->recl);
2345 RETM m = match_out_tag (&tag_nextrec, &inquire->nextrec);
6de9cd9a
DN
2346 RETM m = match_vtag (&tag_s_blank, &inquire->blank);
2347 RETM m = match_vtag (&tag_s_position, &inquire->position);
2348 RETM m = match_vtag (&tag_s_action, &inquire->action);
2349 RETM m = match_vtag (&tag_read, &inquire->read);
2350 RETM m = match_vtag (&tag_write, &inquire->write);
2351 RETM m = match_vtag (&tag_readwrite, &inquire->readwrite);
2352 RETM m = match_vtag (&tag_s_delim, &inquire->delim);
2353 RETM m = match_vtag (&tag_s_pad, &inquire->pad);
2354 RETM m = match_vtag (&tag_iolength, &inquire->iolength);
2355 RETM return MATCH_NO;
2356}
2357
2358#undef RETM
2359
2360
2361match
2362gfc_match_inquire (void)
2363{
2364 gfc_inquire *inquire;
2365 gfc_code *code;
2366 match m;
44998b65 2367 locus loc;
6de9cd9a
DN
2368
2369 m = gfc_match_char ('(');
2370 if (m == MATCH_NO)
2371 return m;
2372
2373 inquire = gfc_getmem (sizeof (gfc_inquire));
2374
44998b65
JB
2375 loc = gfc_current_locus;
2376
6de9cd9a
DN
2377 m = match_inquire_element (inquire);
2378 if (m == MATCH_ERROR)
2379 goto cleanup;
2380 if (m == MATCH_NO)
2381 {
2382 m = gfc_match_expr (&inquire->unit);
2383 if (m == MATCH_ERROR)
2384 goto cleanup;
2385 if (m == MATCH_NO)
2386 goto syntax;
2387 }
2388
2389 /* See if we have the IOLENGTH form of the inquire statement. */
2390 if (inquire->iolength != NULL)
2391 {
2392 if (gfc_match_char (')') != MATCH_YES)
2393 goto syntax;
2394
2395 m = match_io_list (M_INQUIRE, &code);
2396 if (m == MATCH_ERROR)
2397 goto cleanup;
2398 if (m == MATCH_NO)
2399 goto syntax;
2400
2401 terminate_io (code);
2402
2403 new_st.op = EXEC_IOLENGTH;
2404 new_st.expr = inquire->iolength;
8750f9cd 2405 new_st.ext.inquire = inquire;
6de9cd9a
DN
2406
2407 if (gfc_pure (NULL))
2408 {
2409 gfc_free_statements (code);
2410 gfc_error ("INQUIRE statement not allowed in PURE procedure at %C");
2411 return MATCH_ERROR;
2412 }
2413
2414 new_st.next = code;
2415 return MATCH_YES;
2416 }
2417
2418 /* At this point, we have the non-IOLENGTH inquire statement. */
2419 for (;;)
2420 {
2421 if (gfc_match_char (')') == MATCH_YES)
2422 break;
2423 if (gfc_match_char (',') != MATCH_YES)
2424 goto syntax;
2425
2426 m = match_inquire_element (inquire);
2427 if (m == MATCH_ERROR)
2428 goto cleanup;
2429 if (m == MATCH_NO)
2430 goto syntax;
2431
2432 if (inquire->iolength != NULL)
2433 {
2434 gfc_error ("IOLENGTH tag invalid in INQUIRE statement at %C");
2435 goto cleanup;
2436 }
2437 }
2438
2439 if (gfc_match_eos () != MATCH_YES)
2440 goto syntax;
2441
44998b65
JB
2442 if (inquire->unit != NULL && inquire->file != NULL)
2443 {
2444 gfc_error ("INQUIRE statement at %L cannot contain both FILE and"
2445 " UNIT specifiers", &loc);
2446 goto cleanup;
2447 }
2448
2449 if (inquire->unit == NULL && inquire->file == NULL)
2450 {
2451 gfc_error ("INQUIRE statement at %L requires either FILE or"
2452 " UNIT specifier", &loc);
2453 goto cleanup;
2454 }
2455
6de9cd9a
DN
2456 if (gfc_pure (NULL))
2457 {
2458 gfc_error ("INQUIRE statement not allowed in PURE procedure at %C");
2459 goto cleanup;
2460 }
2461
2462 new_st.op = EXEC_INQUIRE;
2463 new_st.ext.inquire = inquire;
2464 return MATCH_YES;
2465
2466syntax:
2467 gfc_syntax_error (ST_INQUIRE);
2468
2469cleanup:
2470 gfc_free_inquire (inquire);
2471 return MATCH_ERROR;
2472}
2473
2474
2475/* Resolve everything in a gfc_inquire structure. */
2476
2477try
2478gfc_resolve_inquire (gfc_inquire * inquire)
2479{
2480
2481 RESOLVE_TAG (&tag_unit, inquire->unit);
2482 RESOLVE_TAG (&tag_file, inquire->file);
2483 RESOLVE_TAG (&tag_iostat, inquire->iostat);
2484 RESOLVE_TAG (&tag_exist, inquire->exist);
2485 RESOLVE_TAG (&tag_opened, inquire->opened);
2486 RESOLVE_TAG (&tag_number, inquire->number);
2487 RESOLVE_TAG (&tag_named, inquire->named);
2488 RESOLVE_TAG (&tag_name, inquire->name);
2489 RESOLVE_TAG (&tag_s_access, inquire->access);
2490 RESOLVE_TAG (&tag_sequential, inquire->sequential);
2491 RESOLVE_TAG (&tag_direct, inquire->direct);
2492 RESOLVE_TAG (&tag_s_form, inquire->form);
2493 RESOLVE_TAG (&tag_formatted, inquire->formatted);
2494 RESOLVE_TAG (&tag_unformatted, inquire->unformatted);
2495 RESOLVE_TAG (&tag_s_recl, inquire->recl);
2496 RESOLVE_TAG (&tag_nextrec, inquire->nextrec);
2497 RESOLVE_TAG (&tag_s_blank, inquire->blank);
2498 RESOLVE_TAG (&tag_s_position, inquire->position);
2499 RESOLVE_TAG (&tag_s_action, inquire->action);
2500 RESOLVE_TAG (&tag_read, inquire->read);
2501 RESOLVE_TAG (&tag_write, inquire->write);
2502 RESOLVE_TAG (&tag_readwrite, inquire->readwrite);
2503 RESOLVE_TAG (&tag_s_delim, inquire->delim);
2504 RESOLVE_TAG (&tag_s_pad, inquire->pad);
8750f9cd 2505 RESOLVE_TAG (&tag_iolength, inquire->iolength);
6de9cd9a
DN
2506
2507 if (gfc_reference_st_label (inquire->err, ST_LABEL_TARGET) == FAILURE)
2508 return FAILURE;
2509
8750f9cd 2510 return SUCCESS;
6de9cd9a 2511}
This page took 0.657595 seconds and 5 git commands to generate.