xref: /llvm-project/flang/lib/Parser/io-parsers.cpp (revision 455ed8de4f878160be9cfd17db891b326fb4a6a2)
1 //===-- lib/Parser/io-parsers.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // Per-type parsers for I/O statements and FORMAT
10 
11 #include "basic-parsers.h"
12 #include "debug-parser.h"
13 #include "expr-parsers.h"
14 #include "misc-parsers.h"
15 #include "stmt-parser.h"
16 #include "token-parsers.h"
17 #include "type-parser-implementation.h"
18 #include "flang/Parser/characters.h"
19 #include "flang/Parser/parse-tree.h"
20 
21 namespace Fortran::parser {
22 // R1201 io-unit -> file-unit-number | * | internal-file-variable
23 // R1203 internal-file-variable -> char-variable
24 // R905 char-variable -> variable
25 // "char-variable" is attempted first since it's not type constrained but
26 // syntactically ambiguous with "file-unit-number", which is constrained.
27 TYPE_PARSER(construct<IoUnit>(variable / !"="_tok) ||
28     construct<IoUnit>(fileUnitNumber) || construct<IoUnit>(star))
29 
30 // R1202 file-unit-number -> scalar-int-expr
31 TYPE_PARSER(construct<FileUnitNumber>(scalarIntExpr / !"="_tok))
32 
33 // R1204 open-stmt -> OPEN ( connect-spec-list )
34 TYPE_CONTEXT_PARSER("OPEN statement"_en_US,
35     construct<OpenStmt>(
36         "OPEN (" >> nonemptyList("expected connection specifications"_err_en_US,
37                         Parser<ConnectSpec>{}) /
38             ")"))
39 
40 // R1206 file-name-expr -> scalar-default-char-expr
41 constexpr auto fileNameExpr{scalarDefaultCharExpr};
42 
43 // R1205 connect-spec ->
44 //         [UNIT =] file-unit-number | ACCESS = scalar-default-char-expr |
45 //         ACTION = scalar-default-char-expr |
46 //         ASYNCHRONOUS = scalar-default-char-expr |
47 //         BLANK = scalar-default-char-expr |
48 //         DECIMAL = scalar-default-char-expr |
49 //         DELIM = scalar-default-char-expr |
50 //         ENCODING = scalar-default-char-expr | ERR = label |
51 //         FILE = file-name-expr | FORM = scalar-default-char-expr |
52 //         IOMSG = iomsg-variable | IOSTAT = scalar-int-variable |
53 //         NEWUNIT = scalar-int-variable | PAD = scalar-default-char-expr |
54 //         POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
55 //         ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
56 //         STATUS = scalar-default-char-expr
57 //         @ | CONVERT = scalar-default-char-variable
58 //         @ | DISPOSE = scalar-default-char-variable
59 constexpr auto statusExpr{construct<StatusExpr>(scalarDefaultCharExpr)};
60 constexpr auto errLabel{construct<ErrLabel>(label)};
61 
62 TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
63     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
64         "ACCESS =" >> pure(ConnectSpec::CharExpr::Kind::Access),
65         scalarDefaultCharExpr)),
66     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
67         "ACTION =" >> pure(ConnectSpec::CharExpr::Kind::Action),
68         scalarDefaultCharExpr)),
69     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
70         "ASYNCHRONOUS =" >> pure(ConnectSpec::CharExpr::Kind::Asynchronous),
71         scalarDefaultCharExpr)),
72     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
73         "BLANK =" >> pure(ConnectSpec::CharExpr::Kind::Blank),
74         scalarDefaultCharExpr)),
75     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
76         "DECIMAL =" >> pure(ConnectSpec::CharExpr::Kind::Decimal),
77         scalarDefaultCharExpr)),
78     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
79         "DELIM =" >> pure(ConnectSpec::CharExpr::Kind::Delim),
80         scalarDefaultCharExpr)),
81     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
82         "ENCODING =" >> pure(ConnectSpec::CharExpr::Kind::Encoding),
83         scalarDefaultCharExpr)),
84     construct<ConnectSpec>("ERR =" >> errLabel),
85     construct<ConnectSpec>("FILE =" >> fileNameExpr),
86     extension<LanguageFeature::FileName>(
87         construct<ConnectSpec>("NAME =" >> fileNameExpr)),
88     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
89         "FORM =" >> pure(ConnectSpec::CharExpr::Kind::Form),
90         scalarDefaultCharExpr)),
91     construct<ConnectSpec>("IOMSG =" >> msgVariable),
92     construct<ConnectSpec>("IOSTAT =" >> statVariable),
93     construct<ConnectSpec>(construct<ConnectSpec::Newunit>(
94         "NEWUNIT =" >> scalar(integer(variable)))),
95     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
96         "PAD =" >> pure(ConnectSpec::CharExpr::Kind::Pad),
97         scalarDefaultCharExpr)),
98     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
99         "POSITION =" >> pure(ConnectSpec::CharExpr::Kind::Position),
100         scalarDefaultCharExpr)),
101     construct<ConnectSpec>(
102         construct<ConnectSpec::Recl>("RECL =" >> scalarIntExpr)),
103     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
104         "ROUND =" >> pure(ConnectSpec::CharExpr::Kind::Round),
105         scalarDefaultCharExpr)),
106     construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
107         "SIGN =" >> pure(ConnectSpec::CharExpr::Kind::Sign),
108         scalarDefaultCharExpr)),
109     construct<ConnectSpec>("STATUS =" >> statusExpr),
110     extension<LanguageFeature::Convert>(
111         construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
112             "CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert),
113             scalarDefaultCharExpr))),
114     extension<LanguageFeature::Dispose>(
115         construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
116             "DISPOSE =" >> pure(ConnectSpec::CharExpr::Kind::Dispose),
117             scalarDefaultCharExpr)))))
118 
119 // R1209 close-spec ->
120 //         [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
121 //         IOMSG = iomsg-variable | ERR = label |
122 //         STATUS = scalar-default-char-expr
123 constexpr auto closeSpec{first(
124     construct<CloseStmt::CloseSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
125     construct<CloseStmt::CloseSpec>("IOSTAT =" >> statVariable),
126     construct<CloseStmt::CloseSpec>("IOMSG =" >> msgVariable),
127     construct<CloseStmt::CloseSpec>("ERR =" >> errLabel),
128     construct<CloseStmt::CloseSpec>("STATUS =" >> statusExpr))};
129 
130 // R1208 close-stmt -> CLOSE ( close-spec-list )
131 TYPE_CONTEXT_PARSER("CLOSE statement"_en_US,
132     construct<CloseStmt>("CLOSE" >> parenthesized(nonemptyList(closeSpec))))
133 
134 // R1210 read-stmt ->
135 //         READ ( io-control-spec-list ) [input-item-list] |
136 //         READ format [, input-item-list]
137 constexpr auto inputItemList{
138     extension<LanguageFeature::IOListLeadingComma>(
139         some("," >> inputItem)) || // legacy extension: leading comma
140     optionalList(inputItem)};
141 
142 TYPE_CONTEXT_PARSER("READ statement"_en_US,
143     construct<ReadStmt>("READ (" >>
144             construct<std::optional<IoUnit>>(maybe("UNIT ="_tok) >> ioUnit),
145         "," >> construct<std::optional<Format>>(format),
146         defaulted("," >> nonemptyList(ioControlSpec)) / ")", inputItemList) ||
147         construct<ReadStmt>(
148             "READ (" >> construct<std::optional<IoUnit>>(ioUnit),
149             construct<std::optional<Format>>(),
150             defaulted("," >> nonemptyList(ioControlSpec)) / ")",
151             inputItemList) ||
152         construct<ReadStmt>("READ" >> construct<std::optional<IoUnit>>(),
153             construct<std::optional<Format>>(),
154             parenthesized(nonemptyList(ioControlSpec)), inputItemList) ||
155         construct<ReadStmt>("READ" >> construct<std::optional<IoUnit>>(),
156             construct<std::optional<Format>>(format),
157             construct<std::list<IoControlSpec>>(), many("," >> inputItem)))
158 
159 // R1214 id-variable -> scalar-int-variable
160 constexpr auto idVariable{construct<IdVariable>(scalarIntVariable)};
161 
162 // R1213 io-control-spec ->
163 //         [UNIT =] io-unit | [FMT =] format | [NML =] namelist-group-name |
164 //         ADVANCE = scalar-default-char-expr |
165 //         ASYNCHRONOUS = scalar-default-char-constant-expr |
166 //         BLANK = scalar-default-char-expr |
167 //         DECIMAL = scalar-default-char-expr |
168 //         DELIM = scalar-default-char-expr | END = label | EOR = label |
169 //         ERR = label | ID = id-variable | IOMSG = iomsg-variable |
170 //         IOSTAT = scalar-int-variable | PAD = scalar-default-char-expr |
171 //         POS = scalar-int-expr | REC = scalar-int-expr |
172 //         ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
173 //         SIZE = scalar-int-variable
174 constexpr auto endLabel{construct<EndLabel>(label)};
175 constexpr auto eorLabel{construct<EorLabel>(label)};
176 TYPE_PARSER(first(construct<IoControlSpec>("UNIT =" >> ioUnit),
177     construct<IoControlSpec>("FMT =" >> format),
178     construct<IoControlSpec>("NML =" >> name),
179     construct<IoControlSpec>(
180         "ADVANCE =" >> construct<IoControlSpec::CharExpr>(
181                            pure(IoControlSpec::CharExpr::Kind::Advance),
182                            scalarDefaultCharExpr)),
183     construct<IoControlSpec>(construct<IoControlSpec::Asynchronous>(
184         "ASYNCHRONOUS =" >> scalarDefaultCharConstantExpr)),
185     construct<IoControlSpec>("BLANK =" >>
186         construct<IoControlSpec::CharExpr>(
187             pure(IoControlSpec::CharExpr::Kind::Blank), scalarDefaultCharExpr)),
188     construct<IoControlSpec>(
189         "DECIMAL =" >> construct<IoControlSpec::CharExpr>(
190                            pure(IoControlSpec::CharExpr::Kind::Decimal),
191                            scalarDefaultCharExpr)),
192     construct<IoControlSpec>("DELIM =" >>
193         construct<IoControlSpec::CharExpr>(
194             pure(IoControlSpec::CharExpr::Kind::Delim), scalarDefaultCharExpr)),
195     construct<IoControlSpec>("END =" >> endLabel),
196     construct<IoControlSpec>("EOR =" >> eorLabel),
197     construct<IoControlSpec>("ERR =" >> errLabel),
198     construct<IoControlSpec>("ID =" >> idVariable),
199     construct<IoControlSpec>("IOMSG = " >> msgVariable),
200     construct<IoControlSpec>("IOSTAT = " >> statVariable),
201     construct<IoControlSpec>("PAD =" >>
202         construct<IoControlSpec::CharExpr>(
203             pure(IoControlSpec::CharExpr::Kind::Pad), scalarDefaultCharExpr)),
204     construct<IoControlSpec>(
205         "POS =" >> construct<IoControlSpec::Pos>(scalarIntExpr)),
206     construct<IoControlSpec>(
207         "REC =" >> construct<IoControlSpec::Rec>(scalarIntExpr)),
208     construct<IoControlSpec>("ROUND =" >>
209         construct<IoControlSpec::CharExpr>(
210             pure(IoControlSpec::CharExpr::Kind::Round), scalarDefaultCharExpr)),
211     construct<IoControlSpec>("SIGN =" >>
212         construct<IoControlSpec::CharExpr>(
213             pure(IoControlSpec::CharExpr::Kind::Sign), scalarDefaultCharExpr)),
214     construct<IoControlSpec>(
215         "SIZE =" >> construct<IoControlSpec::Size>(scalarIntVariable))))
216 
217 // R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
218 constexpr auto outputItemList{
219     extension<LanguageFeature::IOListLeadingComma>(
220         some("," >> outputItem)) || // legacy: allow leading comma
221     optionalList(outputItem)};
222 
223 TYPE_CONTEXT_PARSER("WRITE statement"_en_US,
224     construct<WriteStmt>("WRITE (" >>
225             construct<std::optional<IoUnit>>(maybe("UNIT ="_tok) >> ioUnit),
226         "," >> construct<std::optional<Format>>(format),
227         defaulted("," >> nonemptyList(ioControlSpec)) / ")", outputItemList) ||
228         construct<WriteStmt>(
229             "WRITE (" >> construct<std::optional<IoUnit>>(ioUnit),
230             construct<std::optional<Format>>(),
231             defaulted("," >> nonemptyList(ioControlSpec)) / ")",
232             outputItemList) ||
233         construct<WriteStmt>("WRITE" >> construct<std::optional<IoUnit>>(),
234             construct<std::optional<Format>>(),
235             parenthesized(nonemptyList(ioControlSpec)), outputItemList))
236 
237 // R1212 print-stmt PRINT format [, output-item-list]
238 TYPE_CONTEXT_PARSER("PRINT statement"_en_US,
239     construct<PrintStmt>(
240         "PRINT" >> format, defaulted("," >> nonemptyList(outputItem))))
241 
242 // R1215 format -> default-char-expr | label | *
243 // deprecated(ASSIGN): | scalar-int-name
244 TYPE_PARSER(construct<Format>(label / !"_."_ch) ||
245     construct<Format>(expr / !"="_tok) || construct<Format>(star))
246 
247 // R1216 input-item -> variable | io-implied-do
248 TYPE_PARSER(construct<InputItem>(variable) ||
249     construct<InputItem>(indirect(inputImpliedDo)))
250 
251 // R1217 output-item -> expr | io-implied-do
252 TYPE_PARSER(construct<OutputItem>(expr) ||
253     construct<OutputItem>(indirect(outputImpliedDo)))
254 
255 // R1220 io-implied-do-control ->
256 //         do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr]
257 constexpr auto ioImpliedDoControl{loopBounds(scalarIntExpr)};
258 
259 // R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control )
260 // R1219 io-implied-do-object -> input-item | output-item
261 TYPE_CONTEXT_PARSER("input implied DO"_en_US,
262     parenthesized(
263         construct<InputImpliedDo>(nonemptyList(inputItem / lookAhead(","_tok)),
264             "," >> ioImpliedDoControl)))
265 TYPE_CONTEXT_PARSER("output implied DO"_en_US,
266     parenthesized(construct<OutputImpliedDo>(
267         nonemptyList(outputItem / lookAhead(","_tok)),
268         "," >> ioImpliedDoControl)))
269 
270 // R1222 wait-stmt -> WAIT ( wait-spec-list )
271 TYPE_CONTEXT_PARSER("WAIT statement"_en_US,
272     "WAIT" >>
273         parenthesized(construct<WaitStmt>(nonemptyList(Parser<WaitSpec>{}))))
274 
275 // R1223 wait-spec ->
276 //         [UNIT =] file-unit-number | END = label | EOR = label | ERR = label |
277 //         ID = scalar-int-expr | IOMSG = iomsg-variable |
278 //         IOSTAT = scalar-int-variable
279 constexpr auto idExpr{construct<IdExpr>(scalarIntExpr)};
280 
281 TYPE_PARSER(first(construct<WaitSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
282     construct<WaitSpec>("END =" >> endLabel),
283     construct<WaitSpec>("EOR =" >> eorLabel),
284     construct<WaitSpec>("ERR =" >> errLabel),
285     construct<WaitSpec>("ID =" >> idExpr),
286     construct<WaitSpec>("IOMSG =" >> msgVariable),
287     construct<WaitSpec>("IOSTAT =" >> statVariable)))
288 
289 template <typename A> common::IfNoLvalue<std::list<A>, A> singletonList(A &&x) {
290   std::list<A> result;
291   result.push_front(std::move(x));
292   return result;
293 }
294 constexpr auto bareUnitNumberAsList{
295     applyFunction(singletonList<PositionOrFlushSpec>,
296         construct<PositionOrFlushSpec>(fileUnitNumber))};
297 constexpr auto positionOrFlushSpecList{
298     parenthesized(nonemptyList(positionOrFlushSpec)) || bareUnitNumberAsList};
299 
300 // R1224 backspace-stmt ->
301 //         BACKSPACE file-unit-number | BACKSPACE ( position-spec-list )
302 TYPE_CONTEXT_PARSER("BACKSPACE statement"_en_US,
303     construct<BackspaceStmt>("BACKSPACE" >> positionOrFlushSpecList))
304 
305 // R1225 endfile-stmt ->
306 //         ENDFILE file-unit-number | ENDFILE ( position-spec-list )
307 TYPE_CONTEXT_PARSER("ENDFILE statement"_en_US,
308     construct<EndfileStmt>("ENDFILE" >> positionOrFlushSpecList))
309 
310 // R1226 rewind-stmt -> REWIND file-unit-number | REWIND ( position-spec-list )
311 TYPE_CONTEXT_PARSER("REWIND statement"_en_US,
312     construct<RewindStmt>("REWIND" >> positionOrFlushSpecList))
313 
314 // R1227 position-spec ->
315 //         [UNIT =] file-unit-number | IOMSG = iomsg-variable |
316 //         IOSTAT = scalar-int-variable | ERR = label
317 // R1229 flush-spec ->
318 //         [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
319 //         IOMSG = iomsg-variable | ERR = label
320 TYPE_PARSER(
321     construct<PositionOrFlushSpec>(maybe("UNIT ="_tok) >> fileUnitNumber) ||
322     construct<PositionOrFlushSpec>("IOMSG =" >> msgVariable) ||
323     construct<PositionOrFlushSpec>("IOSTAT =" >> statVariable) ||
324     construct<PositionOrFlushSpec>("ERR =" >> errLabel))
325 
326 // R1228 flush-stmt -> FLUSH file-unit-number | FLUSH ( flush-spec-list )
327 TYPE_CONTEXT_PARSER("FLUSH statement"_en_US,
328     construct<FlushStmt>("FLUSH" >> positionOrFlushSpecList))
329 
330 // R1231 inquire-spec ->
331 //         [UNIT =] file-unit-number | FILE = file-name-expr |
332 //         ACCESS = scalar-default-char-variable |
333 //         ACTION = scalar-default-char-variable |
334 //         ASYNCHRONOUS = scalar-default-char-variable |
335 //         BLANK = scalar-default-char-variable |
336 //         DECIMAL = scalar-default-char-variable |
337 //         DELIM = scalar-default-char-variable |
338 //         ENCODING = scalar-default-char-variable |
339 //         ERR = label | EXIST = scalar-logical-variable |
340 //         FORM = scalar-default-char-variable |
341 //         FORMATTED = scalar-default-char-variable |
342 //         ID = scalar-int-expr | IOMSG = iomsg-variable |
343 //         IOSTAT = scalar-int-variable |
344 //         NAME = scalar-default-char-variable |
345 //         NAMED = scalar-logical-variable |
346 //         NEXTREC = scalar-int-variable | NUMBER = scalar-int-variable |
347 //         OPENED = scalar-logical-variable |
348 //         PAD = scalar-default-char-variable |
349 //         PENDING = scalar-logical-variable | POS = scalar-int-variable |
350 //         POSITION = scalar-default-char-variable |
351 //         READ = scalar-default-char-variable |
352 //         READWRITE = scalar-default-char-variable |
353 //         RECL = scalar-int-variable | ROUND = scalar-default-char-variable |
354 //         SEQUENTIAL = scalar-default-char-variable |
355 //         SIGN = scalar-default-char-variable |
356 //         SIZE = scalar-int-variable |
357 //         STREAM = scalar-default-char-variable |
358 //         STATUS = scalar-default-char-variable |
359 //         WRITE = scalar-default-char-variable
360 //         @ | CONVERT = scalar-default-char-variable
361 //           | DISPOSE = scalar-default-char-variable
362 TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
363     construct<InquireSpec>("FILE =" >> fileNameExpr),
364     construct<InquireSpec>(
365         "ACCESS =" >> construct<InquireSpec::CharVar>(
366                           pure(InquireSpec::CharVar::Kind::Access),
367                           scalarDefaultCharVariable)),
368     construct<InquireSpec>(
369         "ACTION =" >> construct<InquireSpec::CharVar>(
370                           pure(InquireSpec::CharVar::Kind::Action),
371                           scalarDefaultCharVariable)),
372     construct<InquireSpec>(
373         "ASYNCHRONOUS =" >> construct<InquireSpec::CharVar>(
374                                 pure(InquireSpec::CharVar::Kind::Asynchronous),
375                                 scalarDefaultCharVariable)),
376     construct<InquireSpec>("BLANK =" >>
377         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Blank),
378             scalarDefaultCharVariable)),
379     construct<InquireSpec>(
380         "DECIMAL =" >> construct<InquireSpec::CharVar>(
381                            pure(InquireSpec::CharVar::Kind::Decimal),
382                            scalarDefaultCharVariable)),
383     construct<InquireSpec>("DELIM =" >>
384         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Delim),
385             scalarDefaultCharVariable)),
386     construct<InquireSpec>(
387         "DIRECT =" >> construct<InquireSpec::CharVar>(
388                           pure(InquireSpec::CharVar::Kind::Direct),
389                           scalarDefaultCharVariable)),
390     construct<InquireSpec>(
391         "ENCODING =" >> construct<InquireSpec::CharVar>(
392                             pure(InquireSpec::CharVar::Kind::Encoding),
393                             scalarDefaultCharVariable)),
394     construct<InquireSpec>("ERR =" >> errLabel),
395     construct<InquireSpec>("EXIST =" >>
396         construct<InquireSpec::LogVar>(
397             pure(InquireSpec::LogVar::Kind::Exist), scalarLogicalVariable)),
398     construct<InquireSpec>("FORM =" >>
399         construct<InquireSpec::CharVar>(
400             pure(InquireSpec::CharVar::Kind::Form), scalarDefaultCharVariable)),
401     construct<InquireSpec>(
402         "FORMATTED =" >> construct<InquireSpec::CharVar>(
403                              pure(InquireSpec::CharVar::Kind::Formatted),
404                              scalarDefaultCharVariable)),
405     construct<InquireSpec>("ID =" >> idExpr),
406     construct<InquireSpec>("IOMSG =" >>
407         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Iomsg),
408             scalarDefaultCharVariable)),
409     construct<InquireSpec>("IOSTAT =" >>
410         construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Iostat),
411             scalar(integer(variable)))),
412     construct<InquireSpec>("NAME =" >>
413         construct<InquireSpec::CharVar>(
414             pure(InquireSpec::CharVar::Kind::Name), scalarDefaultCharVariable)),
415     construct<InquireSpec>("NAMED =" >>
416         construct<InquireSpec::LogVar>(
417             pure(InquireSpec::LogVar::Kind::Named), scalarLogicalVariable)),
418     construct<InquireSpec>("NEXTREC =" >>
419         construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Nextrec),
420             scalar(integer(variable)))),
421     construct<InquireSpec>("NUMBER =" >>
422         construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Number),
423             scalar(integer(variable)))),
424     construct<InquireSpec>("OPENED =" >>
425         construct<InquireSpec::LogVar>(
426             pure(InquireSpec::LogVar::Kind::Opened), scalarLogicalVariable)),
427     construct<InquireSpec>("PAD =" >>
428         construct<InquireSpec::CharVar>(
429             pure(InquireSpec::CharVar::Kind::Pad), scalarDefaultCharVariable)),
430     construct<InquireSpec>("PENDING =" >>
431         construct<InquireSpec::LogVar>(
432             pure(InquireSpec::LogVar::Kind::Pending), scalarLogicalVariable)),
433     construct<InquireSpec>("POS =" >>
434         construct<InquireSpec::IntVar>(
435             pure(InquireSpec::IntVar::Kind::Pos), scalar(integer(variable)))),
436     construct<InquireSpec>(
437         "POSITION =" >> construct<InquireSpec::CharVar>(
438                             pure(InquireSpec::CharVar::Kind::Position),
439                             scalarDefaultCharVariable)),
440     construct<InquireSpec>("READ =" >>
441         construct<InquireSpec::CharVar>(
442             pure(InquireSpec::CharVar::Kind::Read), scalarDefaultCharVariable)),
443     construct<InquireSpec>(
444         "READWRITE =" >> construct<InquireSpec::CharVar>(
445                              pure(InquireSpec::CharVar::Kind::Readwrite),
446                              scalarDefaultCharVariable)),
447     construct<InquireSpec>("RECL =" >>
448         construct<InquireSpec::IntVar>(
449             pure(InquireSpec::IntVar::Kind::Recl), scalar(integer(variable)))),
450     construct<InquireSpec>("ROUND =" >>
451         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Round),
452             scalarDefaultCharVariable)),
453     construct<InquireSpec>(
454         "SEQUENTIAL =" >> construct<InquireSpec::CharVar>(
455                               pure(InquireSpec::CharVar::Kind::Sequential),
456                               scalarDefaultCharVariable)),
457     construct<InquireSpec>("SIGN =" >>
458         construct<InquireSpec::CharVar>(
459             pure(InquireSpec::CharVar::Kind::Sign), scalarDefaultCharVariable)),
460     construct<InquireSpec>("SIZE =" >>
461         construct<InquireSpec::IntVar>(
462             pure(InquireSpec::IntVar::Kind::Size), scalar(integer(variable)))),
463     construct<InquireSpec>(
464         "STREAM =" >> construct<InquireSpec::CharVar>(
465                           pure(InquireSpec::CharVar::Kind::Stream),
466                           scalarDefaultCharVariable)),
467     construct<InquireSpec>(
468         "STATUS =" >> construct<InquireSpec::CharVar>(
469                           pure(InquireSpec::CharVar::Kind::Status),
470                           scalarDefaultCharVariable)),
471     construct<InquireSpec>(
472         "UNFORMATTED =" >> construct<InquireSpec::CharVar>(
473                                pure(InquireSpec::CharVar::Kind::Unformatted),
474                                scalarDefaultCharVariable)),
475     construct<InquireSpec>("WRITE =" >>
476         construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Write),
477             scalarDefaultCharVariable)),
478     extension<LanguageFeature::Convert>(construct<InquireSpec>(
479         "CONVERT =" >> construct<InquireSpec::CharVar>(
480                            pure(InquireSpec::CharVar::Kind::Convert),
481                            scalarDefaultCharVariable))),
482     extension<LanguageFeature::Dispose>(construct<InquireSpec>(
483         "DISPOSE =" >> construct<InquireSpec::CharVar>(
484                            pure(InquireSpec::CharVar::Kind::Dispose),
485                            scalarDefaultCharVariable)))))
486 
487 // R1230 inquire-stmt ->
488 //         INQUIRE ( inquire-spec-list ) |
489 //         INQUIRE ( IOLENGTH = scalar-int-variable ) output-item-list
490 TYPE_CONTEXT_PARSER("INQUIRE statement"_en_US,
491     "INQUIRE" >>
492         (construct<InquireStmt>(
493              parenthesized(nonemptyList(Parser<InquireSpec>{}))) ||
494             construct<InquireStmt>(construct<InquireStmt::Iolength>(
495                 parenthesized("IOLENGTH =" >> scalar(integer(variable))),
496                 nonemptyList(outputItem)))))
497 
498 // R1301 format-stmt -> FORMAT format-specification
499 // 13.2.1 allows spaces to appear "at any point" within a format specification
500 // without effect, except of course within a character string edit descriptor.
501 TYPE_CONTEXT_PARSER("FORMAT statement"_en_US,
502     construct<FormatStmt>("FORMAT" >> Parser<format::FormatSpecification>{}))
503 
504 // R1321 char-string-edit-desc
505 // N.B. C1313 disallows any kind parameter on the character literal.
506 constexpr auto charStringEditDesc{
507     space >> (charLiteralConstantWithoutKind || rawHollerithLiteral)};
508 
509 // R1303 format-items -> format-item [[,] format-item]...
510 constexpr auto formatItems{
511     nonemptySeparated(space >> Parser<format::FormatItem>{}, maybe(","_tok))};
512 
513 // R1306 r -> digit-string
514 constexpr DigitStringIgnoreSpaces repeat;
515 
516 // R1304 format-item ->
517 //         [r] data-edit-desc | control-edit-desc | char-string-edit-desc |
518 //         [r] ( format-items )
519 TYPE_PARSER(construct<format::FormatItem>(
520                 maybe(repeat), Parser<format::IntrinsicTypeDataEditDesc>{}) ||
521     construct<format::FormatItem>(
522         maybe(repeat), Parser<format::DerivedTypeDataEditDesc>{}) ||
523     construct<format::FormatItem>(Parser<format::ControlEditDesc>{}) ||
524     construct<format::FormatItem>(charStringEditDesc) ||
525     construct<format::FormatItem>(maybe(repeat), parenthesized(formatItems)))
526 
527 // R1302 format-specification ->
528 //         ( [format-items] ) | ( [format-items ,] unlimited-format-item )
529 // R1305 unlimited-format-item -> * ( format-items )
530 // minor extension: the comma is optional before the unlimited-format-item
531 TYPE_PARSER(parenthesized(construct<format::FormatSpecification>(
532                               defaulted(formatItems / maybe(","_tok)),
533                               "*" >> parenthesized(formatItems)) ||
534     construct<format::FormatSpecification>(defaulted(formatItems))))
535 // R1308 w -> digit-string
536 // R1309 m -> digit-string
537 // R1310 d -> digit-string
538 // R1311 e -> digit-string
539 constexpr auto width{repeat};
540 constexpr auto mandatoryWidth{construct<std::optional<int>>(width)};
541 constexpr auto digits{repeat};
542 constexpr auto noInt{construct<std::optional<int>>()};
543 constexpr auto mandatoryDigits{construct<std::optional<int>>("." >> width)};
544 
545 // R1307 data-edit-desc ->
546 //         I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d |
547 //         E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] |
548 //         G w [. d [E e]] | L w | A [w] | D w . d |
549 //         DT [char-literal-constant] [( v-list )]
550 // (part 1 of 2)
551 TYPE_PARSER(construct<format::IntrinsicTypeDataEditDesc>(
552                 "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
553                     "B" >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) ||
554                     "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) ||
555                     "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z),
556                 mandatoryWidth, maybe("." >> digits), noInt) ||
557     construct<format::IntrinsicTypeDataEditDesc>(
558         "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) ||
559             "D" >> pure(format::IntrinsicTypeDataEditDesc::Kind::D),
560         mandatoryWidth, mandatoryDigits, noInt) ||
561     construct<format::IntrinsicTypeDataEditDesc>(
562         "E" >> ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) ||
563                    "S" >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) ||
564                    "X" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) ||
565                    pure(format::IntrinsicTypeDataEditDesc::Kind::E)),
566         mandatoryWidth, mandatoryDigits, maybe("E" >> digits)) ||
567     construct<format::IntrinsicTypeDataEditDesc>(
568         "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G), mandatoryWidth,
569         mandatoryDigits, maybe("E" >> digits)) ||
570     construct<format::IntrinsicTypeDataEditDesc>(
571         "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) ||
572             "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L),
573         mandatoryWidth, noInt, noInt) ||
574     construct<format::IntrinsicTypeDataEditDesc>(
575         "A" >> pure(format::IntrinsicTypeDataEditDesc::Kind::A), maybe(width),
576         noInt, noInt) ||
577     // PGI/Intel extension: omitting width (and all else that follows)
578     extension<LanguageFeature::AbbreviatedEditDescriptor>(
579         construct<format::IntrinsicTypeDataEditDesc>(
580             "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
581                 ("B"_tok / !letter /* don't occlude BN & BZ */) >>
582                     pure(format::IntrinsicTypeDataEditDesc::Kind::B) ||
583                 "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) ||
584                 "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z) ||
585                 "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) ||
586                 ("D"_tok / !letter /* don't occlude DT, DC, & DP */) >>
587                     pure(format::IntrinsicTypeDataEditDesc::Kind::D) ||
588                 "E" >>
589                     ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) ||
590                         "S" >>
591                             pure(format::IntrinsicTypeDataEditDesc::Kind::ES) ||
592                         "X" >>
593                             pure(format::IntrinsicTypeDataEditDesc::Kind::EX) ||
594                         pure(format::IntrinsicTypeDataEditDesc::Kind::E)) ||
595                 "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) ||
596                 "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L),
597             noInt, noInt, noInt)))
598 
599 // R1307 data-edit-desc (part 2 of 2)
600 // R1312 v -> [sign] digit-string
601 constexpr SignedDigitStringIgnoreSpaces scaleFactor;
602 TYPE_PARSER(construct<format::DerivedTypeDataEditDesc>(
603     "D" >> "T"_tok >> defaulted(charLiteralConstantWithoutKind),
604     defaulted(parenthesized(nonemptyList(scaleFactor)))))
605 
606 // R1314 k -> [sign] digit-string
607 constexpr PositiveDigitStringIgnoreSpaces count;
608 
609 // R1313 control-edit-desc ->
610 //         position-edit-desc | [r] / | : | sign-edit-desc | k P |
611 //         blank-interp-edit-desc | round-edit-desc | decimal-edit-desc |
612 //         @ \ | $
613 // R1315 position-edit-desc -> T n | TL n | TR n | n X
614 // R1316 n -> digit-string
615 // R1317 sign-edit-desc -> SS | SP | S
616 // R1318 blank-interp-edit-desc -> BN | BZ
617 // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP
618 // R1320 decimal-edit-desc -> DC | DP
619 TYPE_PARSER(construct<format::ControlEditDesc>(
620                 "T" >> ("L" >> pure(format::ControlEditDesc::Kind::TL) ||
621                            "R" >> pure(format::ControlEditDesc::Kind::TR) ||
622                            pure(format::ControlEditDesc::Kind::T)),
623                 count) ||
624     construct<format::ControlEditDesc>(count,
625         "X" >> pure(format::ControlEditDesc::Kind::X) ||
626             "/" >> pure(format::ControlEditDesc::Kind::Slash)) ||
627     construct<format::ControlEditDesc>(
628         "X" >> pure(format::ControlEditDesc::Kind::X) ||
629         "/" >> pure(format::ControlEditDesc::Kind::Slash)) ||
630     construct<format::ControlEditDesc>(
631         scaleFactor, "P" >> pure(format::ControlEditDesc::Kind::P)) ||
632     construct<format::ControlEditDesc>(
633         ":" >> pure(format::ControlEditDesc::Kind::Colon)) ||
634     "S" >> ("S" >> construct<format::ControlEditDesc>(
635                        pure(format::ControlEditDesc::Kind::SS)) ||
636                "P" >> construct<format::ControlEditDesc>(
637                           pure(format::ControlEditDesc::Kind::SP)) ||
638                construct<format::ControlEditDesc>(
639                    pure(format::ControlEditDesc::Kind::S))) ||
640     "B" >> ("N" >> construct<format::ControlEditDesc>(
641                        pure(format::ControlEditDesc::Kind::BN)) ||
642                "Z" >> construct<format::ControlEditDesc>(
643                           pure(format::ControlEditDesc::Kind::BZ))) ||
644     "R" >> ("U" >> construct<format::ControlEditDesc>(
645                        pure(format::ControlEditDesc::Kind::RU)) ||
646                "D" >> construct<format::ControlEditDesc>(
647                           pure(format::ControlEditDesc::Kind::RD)) ||
648                "Z" >> construct<format::ControlEditDesc>(
649                           pure(format::ControlEditDesc::Kind::RZ)) ||
650                "N" >> construct<format::ControlEditDesc>(
651                           pure(format::ControlEditDesc::Kind::RN)) ||
652                "C" >> construct<format::ControlEditDesc>(
653                           pure(format::ControlEditDesc::Kind::RC)) ||
654                "P" >> construct<format::ControlEditDesc>(
655                           pure(format::ControlEditDesc::Kind::RP))) ||
656     "D" >> ("C" >> construct<format::ControlEditDesc>(
657                        pure(format::ControlEditDesc::Kind::DC)) ||
658                "P" >> construct<format::ControlEditDesc>(
659                           pure(format::ControlEditDesc::Kind::DP))) ||
660     extension<LanguageFeature::AdditionalFormats>(
661         "$" >> construct<format::ControlEditDesc>(
662                    pure(format::ControlEditDesc::Kind::Dollar)) ||
663         "\\" >> construct<format::ControlEditDesc>(
664                     pure(format::ControlEditDesc::Kind::Backslash))))
665 } // namespace Fortran::parser
666