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