xref: /llvm-project/flang/lib/Parser/executable-parsers.cpp (revision be6bc6a1e5beb84984b8e1419393c80a3fe2d3d8)
1 //===-- lib/Parser/executable-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 executable statements
10 
11 #include "basic-parsers.h"
12 #include "expr-parsers.h"
13 #include "misc-parsers.h"
14 #include "stmt-parser.h"
15 #include "token-parsers.h"
16 #include "type-parser-implementation.h"
17 #include "flang/Parser/characters.h"
18 #include "flang/Parser/parse-tree.h"
19 
20 namespace Fortran::parser {
21 
22 // Fortran allows the statement with the corresponding label at the end of
23 // a do-construct that begins with an old-style label-do-stmt to be a
24 // new-style END DO statement; e.g., DO 10 I=1,N; ...; 10 END DO.  Usually,
25 // END DO statements appear only at the ends of do-constructs that begin
26 // with a nonlabel-do-stmt, so care must be taken to recognize this case and
27 // essentially treat them like CONTINUE statements.
28 
29 // R514 executable-construct ->
30 //        action-stmt | associate-construct | block-construct |
31 //        case-construct | change-team-construct | critical-construct |
32 //        do-construct | if-construct | select-rank-construct |
33 //        select-type-construct | where-construct | forall-construct |
34 // (CUDA) CUF-kernel-do-construct
35 constexpr auto executableConstruct{first(
36     construct<ExecutableConstruct>(CapturedLabelDoStmt{}),
37     construct<ExecutableConstruct>(EndDoStmtForCapturedLabelDoStmt{}),
38     construct<ExecutableConstruct>(indirect(Parser<DoConstruct>{})),
39     // Attempt DO statements before assignment statements for better
40     // error messages in cases like "DO10I=1,(error)".
41     construct<ExecutableConstruct>(statement(actionStmt)),
42     construct<ExecutableConstruct>(indirect(Parser<AssociateConstruct>{})),
43     construct<ExecutableConstruct>(indirect(Parser<BlockConstruct>{})),
44     construct<ExecutableConstruct>(indirect(Parser<CaseConstruct>{})),
45     construct<ExecutableConstruct>(indirect(Parser<ChangeTeamConstruct>{})),
46     construct<ExecutableConstruct>(indirect(Parser<CriticalConstruct>{})),
47     construct<ExecutableConstruct>(indirect(Parser<IfConstruct>{})),
48     construct<ExecutableConstruct>(indirect(Parser<SelectRankConstruct>{})),
49     construct<ExecutableConstruct>(indirect(Parser<SelectTypeConstruct>{})),
50     construct<ExecutableConstruct>(indirect(whereConstruct)),
51     construct<ExecutableConstruct>(indirect(forallConstruct)),
52     construct<ExecutableConstruct>(indirect(ompEndLoopDirective)),
53     construct<ExecutableConstruct>(indirect(openmpConstruct)),
54     construct<ExecutableConstruct>(indirect(Parser<OpenACCConstruct>{})),
55     construct<ExecutableConstruct>(indirect(compilerDirective)),
56     construct<ExecutableConstruct>(indirect(Parser<CUFKernelDoConstruct>{})))};
57 
58 // R510 execution-part-construct ->
59 //        executable-construct | format-stmt | entry-stmt | data-stmt
60 // Extension (PGI/Intel): also accept NAMELIST in execution part
61 constexpr auto obsoleteExecutionPartConstruct{recovery(ignoredStatementPrefix >>
62         fail<ExecutionPartConstruct>(
63             "obsolete legacy extension is not supported"_err_en_US),
64     construct<ExecutionPartConstruct>(construct<ErrorRecovery>(ok /
65         statement("REDIMENSION" >> name /
66                 parenthesized(nonemptyList(Parser<AllocateShapeSpec>{}))))))};
67 
68 TYPE_PARSER(recovery(
69     CONTEXT_PARSER("execution part construct"_en_US,
70         first(construct<ExecutionPartConstruct>(executableConstruct),
71             construct<ExecutionPartConstruct>(statement(indirect(formatStmt))),
72             construct<ExecutionPartConstruct>(statement(indirect(entryStmt))),
73             construct<ExecutionPartConstruct>(statement(indirect(dataStmt))),
74             extension<LanguageFeature::ExecutionPartNamelist>(
75                 "nonstandard usage: NAMELIST in execution part"_port_en_US,
76                 construct<ExecutionPartConstruct>(
77                     statement(indirect(Parser<NamelistStmt>{})))),
78             obsoleteExecutionPartConstruct,
79             lookAhead(declarationConstruct) >> SkipTo<'\n'>{} >>
80                 fail<ExecutionPartConstruct>(
81                     "misplaced declaration in the execution part"_err_en_US))),
82     construct<ExecutionPartConstruct>(executionPartErrorRecovery)))
83 
84 // R509 execution-part -> executable-construct [execution-part-construct]...
85 TYPE_CONTEXT_PARSER("execution part"_en_US,
86     construct<ExecutionPart>(many(executionPartConstruct)))
87 
88 // R515 action-stmt ->
89 //        allocate-stmt | assignment-stmt | backspace-stmt | call-stmt |
90 //        close-stmt | continue-stmt | cycle-stmt | deallocate-stmt |
91 //        endfile-stmt | error-stop-stmt | event-post-stmt | event-wait-stmt |
92 //        exit-stmt | fail-image-stmt | flush-stmt | form-team-stmt |
93 //        goto-stmt | if-stmt | inquire-stmt | lock-stmt | notify-wait-stmt |
94 //        nullify-stmt | open-stmt | pointer-assignment-stmt | print-stmt |
95 //        read-stmt | return-stmt | rewind-stmt | stop-stmt | sync-all-stmt |
96 //        sync-images-stmt | sync-memory-stmt | sync-team-stmt | unlock-stmt |
97 //        wait-stmt | where-stmt | write-stmt | computed-goto-stmt | forall-stmt
98 // R1159 continue-stmt -> CONTINUE
99 // R1163 fail-image-stmt -> FAIL IMAGE
100 TYPE_PARSER(first(construct<ActionStmt>(indirect(Parser<AllocateStmt>{})),
101     construct<ActionStmt>(indirect(assignmentStmt)),
102     construct<ActionStmt>(indirect(pointerAssignmentStmt)),
103     construct<ActionStmt>(indirect(Parser<BackspaceStmt>{})),
104     construct<ActionStmt>(indirect(Parser<CallStmt>{})),
105     construct<ActionStmt>(indirect(Parser<CloseStmt>{})),
106     construct<ActionStmt>(construct<ContinueStmt>("CONTINUE"_tok)),
107     construct<ActionStmt>(indirect(Parser<CycleStmt>{})),
108     construct<ActionStmt>(indirect(Parser<DeallocateStmt>{})),
109     construct<ActionStmt>(indirect(Parser<EndfileStmt>{})),
110     construct<ActionStmt>(indirect(Parser<EventPostStmt>{})),
111     construct<ActionStmt>(indirect(Parser<EventWaitStmt>{})),
112     construct<ActionStmt>(indirect(Parser<ExitStmt>{})),
113     construct<ActionStmt>(construct<FailImageStmt>("FAIL IMAGE"_sptok)),
114     construct<ActionStmt>(indirect(Parser<FlushStmt>{})),
115     construct<ActionStmt>(indirect(Parser<FormTeamStmt>{})),
116     construct<ActionStmt>(indirect(Parser<GotoStmt>{})),
117     construct<ActionStmt>(indirect(Parser<IfStmt>{})),
118     construct<ActionStmt>(indirect(Parser<InquireStmt>{})),
119     construct<ActionStmt>(indirect(Parser<LockStmt>{})),
120     construct<ActionStmt>(indirect(Parser<NotifyWaitStmt>{})),
121     construct<ActionStmt>(indirect(Parser<NullifyStmt>{})),
122     construct<ActionStmt>(indirect(Parser<OpenStmt>{})),
123     construct<ActionStmt>(indirect(Parser<PrintStmt>{})),
124     construct<ActionStmt>(indirect(Parser<ReadStmt>{})),
125     construct<ActionStmt>(indirect(Parser<ReturnStmt>{})),
126     construct<ActionStmt>(indirect(Parser<RewindStmt>{})),
127     construct<ActionStmt>(indirect(Parser<StopStmt>{})), // & error-stop-stmt
128     construct<ActionStmt>(indirect(Parser<SyncAllStmt>{})),
129     construct<ActionStmt>(indirect(Parser<SyncImagesStmt>{})),
130     construct<ActionStmt>(indirect(Parser<SyncMemoryStmt>{})),
131     construct<ActionStmt>(indirect(Parser<SyncTeamStmt>{})),
132     construct<ActionStmt>(indirect(Parser<UnlockStmt>{})),
133     construct<ActionStmt>(indirect(Parser<WaitStmt>{})),
134     construct<ActionStmt>(indirect(whereStmt)),
135     construct<ActionStmt>(indirect(Parser<WriteStmt>{})),
136     construct<ActionStmt>(indirect(Parser<ComputedGotoStmt>{})),
137     construct<ActionStmt>(indirect(forallStmt)),
138     construct<ActionStmt>(indirect(Parser<ArithmeticIfStmt>{})),
139     construct<ActionStmt>(indirect(Parser<AssignStmt>{})),
140     construct<ActionStmt>(indirect(Parser<AssignedGotoStmt>{})),
141     construct<ActionStmt>(indirect(Parser<PauseStmt>{}))))
142 
143 // R1102 associate-construct -> associate-stmt block end-associate-stmt
144 TYPE_CONTEXT_PARSER("ASSOCIATE construct"_en_US,
145     construct<AssociateConstruct>(statement(Parser<AssociateStmt>{}), block,
146         statement(Parser<EndAssociateStmt>{})))
147 
148 // R1103 associate-stmt ->
149 //        [associate-construct-name :] ASSOCIATE ( association-list )
150 TYPE_CONTEXT_PARSER("ASSOCIATE statement"_en_US,
151     construct<AssociateStmt>(maybe(name / ":"),
152         "ASSOCIATE" >> parenthesized(nonemptyList(Parser<Association>{}))))
153 
154 // R1104 association -> associate-name => selector
155 TYPE_PARSER(construct<Association>(name, "=>" >> selector))
156 
157 // R1105 selector -> expr | variable
158 TYPE_PARSER(construct<Selector>(variable) / lookAhead(","_tok || ")"_tok) ||
159     construct<Selector>(expr))
160 
161 // R1106 end-associate-stmt -> END ASSOCIATE [associate-construct-name]
162 TYPE_PARSER(construct<EndAssociateStmt>(recovery(
163     "END ASSOCIATE" >> maybe(name), namedConstructEndStmtErrorRecovery)))
164 
165 // R1107 block-construct ->
166 //         block-stmt [block-specification-part] block end-block-stmt
167 TYPE_CONTEXT_PARSER("BLOCK construct"_en_US,
168     construct<BlockConstruct>(statement(Parser<BlockStmt>{}),
169         Parser<BlockSpecificationPart>{}, // can be empty
170         block, statement(Parser<EndBlockStmt>{})))
171 
172 // R1108 block-stmt -> [block-construct-name :] BLOCK
173 TYPE_PARSER(construct<BlockStmt>(maybe(name / ":") / "BLOCK"))
174 
175 // R1109 block-specification-part ->
176 //         [use-stmt]... [import-stmt]... [implicit-part]
177 //         [[declaration-construct]... specification-construct]
178 // C1107 prohibits COMMON, EQUIVALENCE, INTENT, NAMELIST, OPTIONAL, VALUE,
179 // and statement function definitions.  C1108 prohibits SAVE /common/.
180 // C1570 indirectly prohibits ENTRY.  These constraints are best enforced later.
181 // The odd grammar rule above would have the effect of forcing any
182 // trailing FORMAT and DATA statements after the last specification-construct
183 // to be recognized as part of the block-construct's block part rather than
184 // its block-specification-part, a distinction without any apparent difference.
185 TYPE_PARSER(construct<BlockSpecificationPart>(specificationPart))
186 
187 // R1110 end-block-stmt -> END BLOCK [block-construct-name]
188 TYPE_PARSER(construct<EndBlockStmt>(
189     recovery("END BLOCK" >> maybe(name), namedConstructEndStmtErrorRecovery)))
190 
191 // R1111 change-team-construct -> change-team-stmt block end-change-team-stmt
192 TYPE_CONTEXT_PARSER("CHANGE TEAM construct"_en_US,
193     construct<ChangeTeamConstruct>(statement(Parser<ChangeTeamStmt>{}), block,
194         statement(Parser<EndChangeTeamStmt>{})))
195 
196 // R1112 change-team-stmt ->
197 //         [team-construct-name :] CHANGE TEAM
198 //         ( team-value [, coarray-association-list] [, sync-stat-list] )
199 TYPE_CONTEXT_PARSER("CHANGE TEAM statement"_en_US,
200     construct<ChangeTeamStmt>(maybe(name / ":"),
201         "CHANGE TEAM"_sptok >> "("_tok >> teamValue,
202         defaulted("," >> nonemptyList(Parser<CoarrayAssociation>{})),
203         defaulted("," >> nonemptyList(statOrErrmsg))) /
204         ")")
205 
206 // R1113 coarray-association -> codimension-decl => selector
207 TYPE_PARSER(
208     construct<CoarrayAssociation>(Parser<CodimensionDecl>{}, "=>" >> selector))
209 
210 // R1114 end-change-team-stmt ->
211 //         END TEAM [( [sync-stat-list] )] [team-construct-name]
212 TYPE_CONTEXT_PARSER("END TEAM statement"_en_US,
213     construct<EndChangeTeamStmt>(
214         "END TEAM" >> defaulted(parenthesized(optionalList(statOrErrmsg))),
215         maybe(name)))
216 
217 // R1117 critical-stmt ->
218 //         [critical-construct-name :] CRITICAL [( [sync-stat-list] )]
219 TYPE_CONTEXT_PARSER("CRITICAL statement"_en_US,
220     construct<CriticalStmt>(maybe(name / ":"),
221         "CRITICAL" >> defaulted(parenthesized(optionalList(statOrErrmsg)))))
222 
223 // R1116 critical-construct -> critical-stmt block end-critical-stmt
224 TYPE_CONTEXT_PARSER("CRITICAL construct"_en_US,
225     construct<CriticalConstruct>(statement(Parser<CriticalStmt>{}), block,
226         statement(Parser<EndCriticalStmt>{})))
227 
228 // R1118 end-critical-stmt -> END CRITICAL [critical-construct-name]
229 TYPE_PARSER(construct<EndCriticalStmt>(recovery(
230     "END CRITICAL" >> maybe(name), namedConstructEndStmtErrorRecovery)))
231 
232 // R1119 do-construct -> do-stmt block end-do
233 // R1120 do-stmt -> nonlabel-do-stmt | label-do-stmt
234 TYPE_CONTEXT_PARSER("DO construct"_en_US,
235     construct<DoConstruct>(
236         statement(Parser<NonLabelDoStmt>{}) / EnterNonlabelDoConstruct{}, block,
237         statement(Parser<EndDoStmt>{}) / LeaveDoConstruct{}))
238 
239 // R1125 concurrent-header ->
240 //         ( [integer-type-spec ::] concurrent-control-list
241 //         [, scalar-mask-expr] )
242 TYPE_PARSER(parenthesized(construct<ConcurrentHeader>(
243     maybe(integerTypeSpec / "::"), nonemptyList(Parser<ConcurrentControl>{}),
244     maybe("," >> scalarLogicalExpr))))
245 
246 // R1126 concurrent-control ->
247 //         index-name = concurrent-limit : concurrent-limit [: concurrent-step]
248 // R1127 concurrent-limit -> scalar-int-expr
249 // R1128 concurrent-step -> scalar-int-expr
250 TYPE_PARSER(construct<ConcurrentControl>(name / "=", scalarIntExpr / ":",
251     scalarIntExpr, maybe(":" >> scalarIntExpr)))
252 
253 // R1130 locality-spec ->
254 //         LOCAL ( variable-name-list ) | LOCAL_INIT ( variable-name-list ) |
255 //         REDUCE ( reduce-operation : variable-name-list ) |
256 //         SHARED ( variable-name-list ) | DEFAULT ( NONE )
257 TYPE_PARSER(construct<LocalitySpec>(construct<LocalitySpec::Local>(
258                 "LOCAL" >> parenthesized(listOfNames))) ||
259     construct<LocalitySpec>(construct<LocalitySpec::LocalInit>(
260         "LOCAL_INIT"_sptok >> parenthesized(listOfNames))) ||
261     construct<LocalitySpec>(construct<LocalitySpec::Reduce>(
262         "REDUCE (" >> Parser<LocalitySpec::Reduce::Operator>{} / ":",
263         listOfNames / ")")) ||
264     construct<LocalitySpec>(construct<LocalitySpec::Shared>(
265         "SHARED" >> parenthesized(listOfNames))) ||
266     construct<LocalitySpec>(
267         construct<LocalitySpec::DefaultNone>("DEFAULT ( NONE )"_tok)))
268 
269 // R1123 loop-control ->
270 //         [,] do-variable = scalar-int-expr , scalar-int-expr
271 //           [, scalar-int-expr] |
272 //         [,] WHILE ( scalar-logical-expr ) |
273 //         [,] CONCURRENT concurrent-header concurrent-locality
274 // R1129 concurrent-locality -> [locality-spec]...
275 TYPE_CONTEXT_PARSER("loop control"_en_US,
276     maybe(","_tok) >>
277         (construct<LoopControl>(loopBounds(scalarExpr)) ||
278             construct<LoopControl>(
279                 "WHILE" >> parenthesized(scalarLogicalExpr)) ||
280             construct<LoopControl>(construct<LoopControl::Concurrent>(
281                 "CONCURRENT" >> concurrentHeader,
282                 many(Parser<LocalitySpec>{})))))
283 
284 // "DO" is a valid statement, so the loop control is optional; but for
285 // better recovery from errors in the loop control, don't parse a
286 // DO statement with a bad loop control as a DO statement that has
287 // no loop control and is followed by garbage.
288 static constexpr auto loopControlOrEndOfStmt{
289     construct<std::optional<LoopControl>>(Parser<LoopControl>{}) ||
290     lookAhead(";\n"_ch) >> construct<std::optional<LoopControl>>()};
291 
292 // R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
293 // A label-do-stmt with a do-construct-name is parsed as a nonlabel-do-stmt
294 // with an optional label.
295 TYPE_CONTEXT_PARSER("label DO statement"_en_US,
296     construct<LabelDoStmt>("DO" >> label, loopControlOrEndOfStmt))
297 
298 // R1122 nonlabel-do-stmt -> [do-construct-name :] DO [loop-control]
299 TYPE_CONTEXT_PARSER("nonlabel DO statement"_en_US,
300     construct<NonLabelDoStmt>(
301         name / ":", "DO" >> maybe(label), loopControlOrEndOfStmt) ||
302         construct<NonLabelDoStmt>(construct<std::optional<Name>>(),
303             construct<std::optional<Label>>(), "DO" >> loopControlOrEndOfStmt))
304 
305 // R1132 end-do-stmt -> END DO [do-construct-name]
306 TYPE_CONTEXT_PARSER("END DO statement"_en_US,
307     construct<EndDoStmt>(
308         recovery("END DO" >> maybe(name), namedConstructEndStmtErrorRecovery)))
309 
310 // R1133 cycle-stmt -> CYCLE [do-construct-name]
311 TYPE_CONTEXT_PARSER(
312     "CYCLE statement"_en_US, construct<CycleStmt>("CYCLE" >> maybe(name)))
313 
314 // R1134 if-construct ->
315 //         if-then-stmt block [else-if-stmt block]...
316 //         [else-stmt block] end-if-stmt
317 // R1135 if-then-stmt -> [if-construct-name :] IF ( scalar-logical-expr )
318 // THEN R1136 else-if-stmt ->
319 //         ELSE IF ( scalar-logical-expr ) THEN [if-construct-name]
320 // R1137 else-stmt -> ELSE [if-construct-name]
321 // R1138 end-if-stmt -> END IF [if-construct-name]
322 TYPE_CONTEXT_PARSER("IF construct"_en_US,
323     construct<IfConstruct>(
324         statement(construct<IfThenStmt>(maybe(name / ":"),
325             "IF" >> parenthesized(scalarLogicalExpr) /
326                     recovery("THEN"_tok, lookAhead(endOfStmt)))),
327         block,
328         many(construct<IfConstruct::ElseIfBlock>(
329             unambiguousStatement(construct<ElseIfStmt>(
330                 "ELSE IF" >> parenthesized(scalarLogicalExpr),
331                 recovery("THEN"_tok, ok) >> maybe(name))),
332             block)),
333         maybe(construct<IfConstruct::ElseBlock>(
334             statement(construct<ElseStmt>("ELSE" >> maybe(name))), block)),
335         statement(construct<EndIfStmt>(recovery(
336             "END IF" >> maybe(name), namedConstructEndStmtErrorRecovery)))))
337 
338 // R1139 if-stmt -> IF ( scalar-logical-expr ) action-stmt
339 TYPE_CONTEXT_PARSER("IF statement"_en_US,
340     construct<IfStmt>("IF" >> parenthesized(scalarLogicalExpr),
341         unlabeledStatement(actionStmt)))
342 
343 // R1140 case-construct ->
344 //         select-case-stmt [case-stmt block]... end-select-stmt
345 TYPE_CONTEXT_PARSER("SELECT CASE construct"_en_US,
346     construct<CaseConstruct>(statement(Parser<SelectCaseStmt>{}),
347         many(construct<CaseConstruct::Case>(
348             unambiguousStatement(Parser<CaseStmt>{}), block)),
349         statement(endSelectStmt)))
350 
351 // R1141 select-case-stmt -> [case-construct-name :] SELECT CASE ( case-expr
352 // ) R1144 case-expr -> scalar-expr
353 TYPE_CONTEXT_PARSER("SELECT CASE statement"_en_US,
354     construct<SelectCaseStmt>(
355         maybe(name / ":"), "SELECT CASE" >> parenthesized(scalar(expr))))
356 
357 // R1142 case-stmt -> CASE case-selector [case-construct-name]
358 TYPE_CONTEXT_PARSER("CASE statement"_en_US,
359     construct<CaseStmt>("CASE" >> Parser<CaseSelector>{}, maybe(name)))
360 
361 // R1143 end-select-stmt -> END SELECT [case-construct-name]
362 // R1151 end-select-rank-stmt -> END SELECT [select-construct-name]
363 // R1155 end-select-type-stmt -> END SELECT [select-construct-name]
364 TYPE_PARSER(construct<EndSelectStmt>(
365     recovery("END SELECT" >> maybe(name), namedConstructEndStmtErrorRecovery)))
366 
367 // R1145 case-selector -> ( case-value-range-list ) | DEFAULT
368 constexpr auto defaultKeyword{construct<Default>("DEFAULT"_tok)};
369 TYPE_PARSER(parenthesized(construct<CaseSelector>(
370                 nonemptyList(Parser<CaseValueRange>{}))) ||
371     construct<CaseSelector>(defaultKeyword))
372 
373 // R1147 case-value -> scalar-constant-expr
374 constexpr auto caseValue{scalar(constantExpr)};
375 
376 // R1146 case-value-range ->
377 //         case-value | case-value : | : case-value | case-value : case-value
378 TYPE_PARSER(construct<CaseValueRange>(construct<CaseValueRange::Range>(
379                 construct<std::optional<CaseValue>>(caseValue),
380                 ":" >> maybe(caseValue))) ||
381     construct<CaseValueRange>(
382         construct<CaseValueRange::Range>(construct<std::optional<CaseValue>>(),
383             ":" >> construct<std::optional<CaseValue>>(caseValue))) ||
384     construct<CaseValueRange>(caseValue))
385 
386 // R1148 select-rank-construct ->
387 //         select-rank-stmt [select-rank-case-stmt block]...
388 //         end-select-rank-stmt
389 TYPE_CONTEXT_PARSER("SELECT RANK construct"_en_US,
390     construct<SelectRankConstruct>(statement(Parser<SelectRankStmt>{}),
391         many(construct<SelectRankConstruct::RankCase>(
392             unambiguousStatement(Parser<SelectRankCaseStmt>{}), block)),
393         statement(endSelectStmt)))
394 
395 // R1149 select-rank-stmt ->
396 //         [select-construct-name :] SELECT RANK
397 //         ( [associate-name =>] selector )
398 TYPE_CONTEXT_PARSER("SELECT RANK statement"_en_US,
399     construct<SelectRankStmt>(maybe(name / ":"),
400         "SELECT RANK"_sptok >> "("_tok >> maybe(name / "=>"), selector / ")"))
401 
402 // R1150 select-rank-case-stmt ->
403 //         RANK ( scalar-int-constant-expr ) [select-construct-name] |
404 //         RANK ( * ) [select-construct-name] |
405 //         RANK DEFAULT [select-construct-name]
406 TYPE_CONTEXT_PARSER("RANK case statement"_en_US,
407     "RANK" >> (construct<SelectRankCaseStmt>(
408                   parenthesized(construct<SelectRankCaseStmt::Rank>(
409                                     scalarIntConstantExpr) ||
410                       construct<SelectRankCaseStmt::Rank>(star)) ||
411                       construct<SelectRankCaseStmt::Rank>(defaultKeyword),
412                   maybe(name))))
413 
414 // R1152 select-type-construct ->
415 //         select-type-stmt [type-guard-stmt block]... end-select-type-stmt
416 TYPE_CONTEXT_PARSER("SELECT TYPE construct"_en_US,
417     construct<SelectTypeConstruct>(statement(Parser<SelectTypeStmt>{}),
418         many(construct<SelectTypeConstruct::TypeCase>(
419             unambiguousStatement(Parser<TypeGuardStmt>{}), block)),
420         statement(endSelectStmt)))
421 
422 // R1153 select-type-stmt ->
423 //         [select-construct-name :] SELECT TYPE
424 //         ( [associate-name =>] selector )
425 TYPE_CONTEXT_PARSER("SELECT TYPE statement"_en_US,
426     construct<SelectTypeStmt>(maybe(name / ":"),
427         "SELECT TYPE (" >> maybe(name / "=>"), selector / ")"))
428 
429 // R1154 type-guard-stmt ->
430 //         TYPE IS ( type-spec ) [select-construct-name] |
431 //         CLASS IS ( derived-type-spec ) [select-construct-name] |
432 //         CLASS DEFAULT [select-construct-name]
433 TYPE_CONTEXT_PARSER("type guard statement"_en_US,
434     construct<TypeGuardStmt>("TYPE IS"_sptok >>
435                 parenthesized(construct<TypeGuardStmt::Guard>(typeSpec)) ||
436             "CLASS IS"_sptok >> parenthesized(construct<TypeGuardStmt::Guard>(
437                                     derivedTypeSpec)) ||
438             construct<TypeGuardStmt::Guard>("CLASS" >> defaultKeyword),
439         maybe(name)))
440 
441 // R1156 exit-stmt -> EXIT [construct-name]
442 TYPE_CONTEXT_PARSER(
443     "EXIT statement"_en_US, construct<ExitStmt>("EXIT" >> maybe(name)))
444 
445 // R1157 goto-stmt -> GO TO label
446 TYPE_CONTEXT_PARSER(
447     "GOTO statement"_en_US, construct<GotoStmt>("GO TO" >> label))
448 
449 // R1158 computed-goto-stmt -> GO TO ( label-list ) [,] scalar-int-expr
450 TYPE_CONTEXT_PARSER("computed GOTO statement"_en_US,
451     construct<ComputedGotoStmt>("GO TO" >> parenthesized(nonemptyList(label)),
452         maybe(","_tok) >> scalarIntExpr))
453 
454 // R1160 stop-stmt -> STOP [stop-code] [, QUIET = scalar-logical-expr]
455 // R1161 error-stop-stmt ->
456 //         ERROR STOP [stop-code] [, QUIET = scalar-logical-expr]
457 TYPE_CONTEXT_PARSER("STOP statement"_en_US,
458     construct<StopStmt>("STOP" >> pure(StopStmt::Kind::Stop) ||
459             "ERROR STOP"_sptok >> pure(StopStmt::Kind::ErrorStop),
460         maybe(Parser<StopCode>{}), maybe(", QUIET =" >> scalarLogicalExpr)))
461 
462 // R1162 stop-code -> scalar-default-char-expr | scalar-int-expr
463 // The two alternatives for stop-code can't be distinguished at
464 // parse time.
465 TYPE_PARSER(construct<StopCode>(scalar(expr)))
466 
467 // F2030: R1166 notify-wait-stmt ->
468 //         NOTIFY WAIT ( notify-variable [, event-wait-spec-list] )
469 TYPE_CONTEXT_PARSER("NOTIFY WAIT statement"_en_US,
470     construct<NotifyWaitStmt>(
471         "NOTIFY WAIT"_sptok >> "("_tok >> scalar(variable),
472         defaulted("," >> nonemptyList(Parser<EventWaitSpec>{})) / ")"))
473 
474 // R1164 sync-all-stmt -> SYNC ALL [( [sync-stat-list] )]
475 TYPE_CONTEXT_PARSER("SYNC ALL statement"_en_US,
476     construct<SyncAllStmt>("SYNC ALL"_sptok >>
477         defaulted(parenthesized(optionalList(statOrErrmsg)))))
478 
479 // R1166 sync-images-stmt -> SYNC IMAGES ( image-set [, sync-stat-list] )
480 // R1167 image-set -> int-expr | *
481 TYPE_CONTEXT_PARSER("SYNC IMAGES statement"_en_US,
482     "SYNC IMAGES"_sptok >> parenthesized(construct<SyncImagesStmt>(
483                                construct<SyncImagesStmt::ImageSet>(intExpr) ||
484                                    construct<SyncImagesStmt::ImageSet>(star),
485                                defaulted("," >> nonemptyList(statOrErrmsg)))))
486 
487 // R1168 sync-memory-stmt -> SYNC MEMORY [( [sync-stat-list] )]
488 TYPE_CONTEXT_PARSER("SYNC MEMORY statement"_en_US,
489     construct<SyncMemoryStmt>("SYNC MEMORY"_sptok >>
490         defaulted(parenthesized(optionalList(statOrErrmsg)))))
491 
492 // R1169 sync-team-stmt -> SYNC TEAM ( team-value [, sync-stat-list] )
493 TYPE_CONTEXT_PARSER("SYNC TEAM statement"_en_US,
494     construct<SyncTeamStmt>("SYNC TEAM"_sptok >> "("_tok >> teamValue,
495         defaulted("," >> nonemptyList(statOrErrmsg)) / ")"))
496 
497 // R1170 event-post-stmt -> EVENT POST ( event-variable [, sync-stat-list] )
498 // R1171 event-variable -> scalar-variable
499 TYPE_CONTEXT_PARSER("EVENT POST statement"_en_US,
500     construct<EventPostStmt>("EVENT POST"_sptok >> "("_tok >> scalar(variable),
501         defaulted("," >> nonemptyList(statOrErrmsg)) / ")"))
502 
503 // R1172 event-wait-stmt ->
504 //         EVENT WAIT ( event-variable [, event-wait-spec-list] )
505 TYPE_CONTEXT_PARSER("EVENT WAIT statement"_en_US,
506     construct<EventWaitStmt>("EVENT WAIT"_sptok >> "("_tok >> scalar(variable),
507         defaulted("," >> nonemptyList(Parser<EventWaitSpec>{})) / ")"))
508 
509 // R1174 until-spec -> UNTIL_COUNT = scalar-int-expr
510 constexpr auto untilSpec{"UNTIL_COUNT =" >> scalarIntExpr};
511 
512 // R1173 event-wait-spec -> until-spec | sync-stat
513 TYPE_PARSER(construct<EventWaitSpec>(untilSpec) ||
514     construct<EventWaitSpec>(statOrErrmsg))
515 
516 // R1177 team-variable -> scalar-variable
517 constexpr auto teamVariable{scalar(variable)};
518 
519 // R1175 form-team-stmt ->
520 //         FORM TEAM ( team-number , team-variable [, form-team-spec-list] )
521 // R1176 team-number -> scalar-int-expr
522 TYPE_CONTEXT_PARSER("FORM TEAM statement"_en_US,
523     construct<FormTeamStmt>("FORM TEAM"_sptok >> "("_tok >> scalarIntExpr,
524         "," >> teamVariable,
525         defaulted("," >> nonemptyList(Parser<FormTeamStmt::FormTeamSpec>{})) /
526             ")"))
527 
528 // R1178 form-team-spec -> NEW_INDEX = scalar-int-expr | sync-stat
529 TYPE_PARSER(
530     construct<FormTeamStmt::FormTeamSpec>("NEW_INDEX =" >> scalarIntExpr) ||
531     construct<FormTeamStmt::FormTeamSpec>(statOrErrmsg))
532 
533 // R1182 lock-variable -> scalar-variable
534 constexpr auto lockVariable{scalar(variable)};
535 
536 // R1179 lock-stmt -> LOCK ( lock-variable [, lock-stat-list] )
537 TYPE_CONTEXT_PARSER("LOCK statement"_en_US,
538     construct<LockStmt>("LOCK (" >> lockVariable,
539         defaulted("," >> nonemptyList(Parser<LockStmt::LockStat>{})) / ")"))
540 
541 // R1180 lock-stat -> ACQUIRED_LOCK = scalar-logical-variable | sync-stat
542 TYPE_PARSER(
543     construct<LockStmt::LockStat>("ACQUIRED_LOCK =" >> scalarLogicalVariable) ||
544     construct<LockStmt::LockStat>(statOrErrmsg))
545 
546 // R1181 unlock-stmt -> UNLOCK ( lock-variable [, sync-stat-list] )
547 TYPE_CONTEXT_PARSER("UNLOCK statement"_en_US,
548     construct<UnlockStmt>("UNLOCK (" >> lockVariable,
549         defaulted("," >> nonemptyList(statOrErrmsg)) / ")"))
550 
551 // CUF-kernel-do-construct ->
552 //   !$CUF KERNEL DO [ (scalar-int-constant-expr) ]
553 //      <<< grid, block [, stream] >>>
554 //      [ cuf-reduction... ]
555 //      do-construct
556 // star-or-expr -> * | scalar-int-expr
557 // grid -> * | scalar-int-expr | ( star-or-expr-list )
558 // block -> * | scalar-int-expr | ( star-or-expr-list )
559 // stream -> 0, scalar-int-expr | STREAM = scalar-int-expr
560 // cuf-reduction -> [ REDUCTION | REDUCE ] (
561 //                  acc-reduction-op : scalar-variable-list )
562 
563 constexpr auto starOrExpr{construct<CUFKernelDoConstruct::StarOrExpr>(
564     "*" >> pure<std::optional<ScalarIntExpr>>() ||
565     applyFunction(presentOptional<ScalarIntExpr>, scalarIntExpr))};
566 constexpr auto gridOrBlock{parenthesized(nonemptyList(starOrExpr)) ||
567     applyFunction(singletonList<CUFKernelDoConstruct::StarOrExpr>, starOrExpr)};
568 
569 TYPE_PARSER(("REDUCTION"_tok || "REDUCE"_tok) >>
570     parenthesized(construct<CUFReduction>(Parser<CUFReduction::Operator>{},
571         ":" >> nonemptyList(scalar(variable)))))
572 
573 TYPE_PARSER("<<<" >>
574     construct<CUFKernelDoConstruct::LaunchConfiguration>(gridOrBlock,
575         "," >> gridOrBlock,
576         maybe((", 0 ,"_tok || ", STREAM ="_tok) >> scalarIntExpr) / ">>>"))
577 
578 TYPE_PARSER(sourced(beginDirective >> "$CUF KERNEL DO"_tok >>
579     construct<CUFKernelDoConstruct::Directive>(
580         maybe(parenthesized(scalarIntConstantExpr)),
581         maybe(Parser<CUFKernelDoConstruct::LaunchConfiguration>{}),
582         many(Parser<CUFReduction>{}) / endDirective)))
583 TYPE_CONTEXT_PARSER("!$CUF KERNEL DO construct"_en_US,
584     extension<LanguageFeature::CUDA>(construct<CUFKernelDoConstruct>(
585         Parser<CUFKernelDoConstruct::Directive>{},
586         maybe(Parser<DoConstruct>{}))))
587 
588 } // namespace Fortran::parser
589