xref: /llvm-project/flang/lib/Parser/program-parsers.cpp (revision 64ab3302d5a130c00b66a6957b2e7f0c9b9c537d)
1 //===-- lib/Parser/program-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 program units
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 // R501 program -> program-unit [program-unit]...
24 // This is the top-level production for the Fortran language.
25 // F'2018 6.3.1 defines a program unit as a sequence of one or more lines,
26 // implying that a line can't be part of two distinct program units.
27 // Consequently, a program unit END statement should be the last statement
28 // on its line.  We parse those END statements via unterminatedStatement()
29 // and then skip over the end of the line here.
30 TYPE_PARSER(construct<Program>(
31     extension<LanguageFeature::EmptySourceFile>(skipStuffBeforeStatement >>
32         !nextCh >> defaulted(cut >> some(Parser<ProgramUnit>{}))) ||
33     some(StartNewSubprogram{} >> Parser<ProgramUnit>{} / skipMany(";"_tok) /
34             space / recovery(endOfLine, SkipPast<'\n'>{})) /
35         skipStuffBeforeStatement))
36 
37 // R502 program-unit ->
38 //        main-program | external-subprogram | module | submodule | block-data
39 // R503 external-subprogram -> function-subprogram | subroutine-subprogram
40 // N.B. "module" must precede "external-subprogram" in this sequence of
41 // alternatives to avoid ambiguity with the MODULE keyword prefix that
42 // they recognize.  I.e., "modulesubroutinefoo" should start a module
43 // "subroutinefoo", not a subroutine "foo" with the MODULE prefix.  The
44 // ambiguity is exacerbated by the extension that accepts a function
45 // statement without an otherwise empty list of dummy arguments.  That
46 // MODULE prefix is disallowed by a constraint (C1547) in this context,
47 // so the standard language is not ambiguous, but disabling its misrecognition
48 // here would require context-sensitive keyword recognition or (or via)
49 // variant parsers for several productions; giving the "module" production
50 // priority here is a cleaner solution, though regrettably subtle.  Enforcing
51 // C1547 is done in semantics.
52 TYPE_PARSER(construct<ProgramUnit>(indirect(Parser<Module>{})) ||
53     construct<ProgramUnit>(indirect(functionSubprogram)) ||
54     construct<ProgramUnit>(indirect(subroutineSubprogram)) ||
55     construct<ProgramUnit>(indirect(Parser<Submodule>{})) ||
56     construct<ProgramUnit>(indirect(Parser<BlockData>{})) ||
57     construct<ProgramUnit>(indirect(Parser<MainProgram>{})))
58 
59 // R504 specification-part ->
60 //         [use-stmt]... [import-stmt]... [implicit-part]
61 //         [declaration-construct]...
62 TYPE_CONTEXT_PARSER("specification part"_en_US,
63     construct<SpecificationPart>(many(openmpDeclarativeConstruct),
64         many(statement(indirect(Parser<UseStmt>{}))),
65         many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
66         implicitPart, many(declarationConstruct)))
67 
68 // R507 declaration-construct ->
69 //        specification-construct | data-stmt | format-stmt |
70 //        entry-stmt | stmt-function-stmt
71 // N.B. These parsers incorporate recognition of some other statements that
72 // may have been misplaced in the sequence of statements that are acceptable
73 // as a specification part in order to improve error recovery.
74 // Also note that many instances of specification-part in the standard grammar
75 // are in contexts that impose constraints on the kinds of statements that
76 // are allowed, and so we have a variant production for declaration-construct
77 // that implements those constraints.
78 constexpr auto execPartLookAhead{
79     first(actionStmt >> ok, ompEndLoopDirective >> ok, openmpConstruct >> ok,
80         "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
81         "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
82 constexpr auto declErrorRecovery{
83     stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery};
84 constexpr auto misplacedSpecificationStmt{Parser<UseStmt>{} >>
85         fail<DeclarationConstruct>("misplaced USE statement"_err_en_US) ||
86     Parser<ImportStmt>{} >>
87         fail<DeclarationConstruct>(
88             "IMPORT statements must follow any USE statements and precede all other declarations"_err_en_US) ||
89     Parser<ImplicitStmt>{} >>
90         fail<DeclarationConstruct>(
91             "IMPLICIT statements must follow USE and IMPORT and precede all other declarations"_err_en_US)};
92 
93 TYPE_PARSER(recovery(
94     withMessage("expected declaration construct"_err_en_US,
95         CONTEXT_PARSER("declaration construct"_en_US,
96             first(construct<DeclarationConstruct>(specificationConstruct),
97                 construct<DeclarationConstruct>(statement(indirect(dataStmt))),
98                 construct<DeclarationConstruct>(
99                     statement(indirect(formatStmt))),
100                 construct<DeclarationConstruct>(statement(indirect(entryStmt))),
101                 construct<DeclarationConstruct>(
102                     statement(indirect(Parser<StmtFunctionStmt>{}))),
103                 misplacedSpecificationStmt))),
104     construct<DeclarationConstruct>(declErrorRecovery)))
105 
106 // R507 variant of declaration-construct for use in limitedSpecificationPart.
107 constexpr auto invalidDeclarationStmt{formatStmt >>
108         fail<DeclarationConstruct>(
109             "FORMAT statements are not permitted in this specification part"_err_en_US) ||
110     entryStmt >>
111         fail<DeclarationConstruct>(
112             "ENTRY statements are not permitted in this specification part"_err_en_US)};
113 
114 constexpr auto limitedDeclarationConstruct{recovery(
115     withMessage("expected declaration construct"_err_en_US,
116         inContext("declaration construct"_en_US,
117             first(construct<DeclarationConstruct>(specificationConstruct),
118                 construct<DeclarationConstruct>(statement(indirect(dataStmt))),
119                 misplacedSpecificationStmt, invalidDeclarationStmt))),
120     construct<DeclarationConstruct>(
121         stmtErrorRecoveryStart >> skipStmtErrorRecovery))};
122 
123 // R504 variant for many contexts (modules, submodules, BLOCK DATA subprograms,
124 // and interfaces) which have constraints on their specification parts that
125 // preclude FORMAT, ENTRY, and statement functions, and benefit from
126 // specialized error recovery in the event of a spurious executable
127 // statement.
128 constexpr auto limitedSpecificationPart{inContext("specification part"_en_US,
129     construct<SpecificationPart>(many(openmpDeclarativeConstruct),
130         many(statement(indirect(Parser<UseStmt>{}))),
131         many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
132         implicitPart, many(limitedDeclarationConstruct)))};
133 
134 // R508 specification-construct ->
135 //        derived-type-def | enum-def | generic-stmt | interface-block |
136 //        parameter-stmt | procedure-declaration-stmt |
137 //        other-specification-stmt | type-declaration-stmt
138 TYPE_CONTEXT_PARSER("specification construct"_en_US,
139     first(construct<SpecificationConstruct>(indirect(Parser<DerivedTypeDef>{})),
140         construct<SpecificationConstruct>(indirect(Parser<EnumDef>{})),
141         construct<SpecificationConstruct>(
142             statement(indirect(Parser<GenericStmt>{}))),
143         construct<SpecificationConstruct>(indirect(interfaceBlock)),
144         construct<SpecificationConstruct>(statement(indirect(parameterStmt))),
145         construct<SpecificationConstruct>(
146             statement(indirect(oldParameterStmt))),
147         construct<SpecificationConstruct>(
148             statement(indirect(Parser<ProcedureDeclarationStmt>{}))),
149         construct<SpecificationConstruct>(
150             statement(Parser<OtherSpecificationStmt>{})),
151         construct<SpecificationConstruct>(
152             statement(indirect(typeDeclarationStmt))),
153         construct<SpecificationConstruct>(indirect(Parser<StructureDef>{})),
154         construct<SpecificationConstruct>(indirect(openmpDeclarativeConstruct)),
155         construct<SpecificationConstruct>(indirect(compilerDirective))))
156 
157 // R513 other-specification-stmt ->
158 //        access-stmt | allocatable-stmt | asynchronous-stmt | bind-stmt |
159 //        codimension-stmt | contiguous-stmt | dimension-stmt | external-stmt |
160 //        intent-stmt | intrinsic-stmt | namelist-stmt | optional-stmt |
161 //        pointer-stmt | protected-stmt | save-stmt | target-stmt |
162 //        volatile-stmt | value-stmt | common-stmt | equivalence-stmt
163 TYPE_PARSER(first(
164     construct<OtherSpecificationStmt>(indirect(Parser<AccessStmt>{})),
165     construct<OtherSpecificationStmt>(indirect(Parser<AllocatableStmt>{})),
166     construct<OtherSpecificationStmt>(indirect(Parser<AsynchronousStmt>{})),
167     construct<OtherSpecificationStmt>(indirect(Parser<BindStmt>{})),
168     construct<OtherSpecificationStmt>(indirect(Parser<CodimensionStmt>{})),
169     construct<OtherSpecificationStmt>(indirect(Parser<ContiguousStmt>{})),
170     construct<OtherSpecificationStmt>(indirect(Parser<DimensionStmt>{})),
171     construct<OtherSpecificationStmt>(indirect(Parser<ExternalStmt>{})),
172     construct<OtherSpecificationStmt>(indirect(Parser<IntentStmt>{})),
173     construct<OtherSpecificationStmt>(indirect(Parser<IntrinsicStmt>{})),
174     construct<OtherSpecificationStmt>(indirect(Parser<NamelistStmt>{})),
175     construct<OtherSpecificationStmt>(indirect(Parser<OptionalStmt>{})),
176     construct<OtherSpecificationStmt>(indirect(Parser<PointerStmt>{})),
177     construct<OtherSpecificationStmt>(indirect(Parser<ProtectedStmt>{})),
178     construct<OtherSpecificationStmt>(indirect(Parser<SaveStmt>{})),
179     construct<OtherSpecificationStmt>(indirect(Parser<TargetStmt>{})),
180     construct<OtherSpecificationStmt>(indirect(Parser<ValueStmt>{})),
181     construct<OtherSpecificationStmt>(indirect(Parser<VolatileStmt>{})),
182     construct<OtherSpecificationStmt>(indirect(Parser<CommonStmt>{})),
183     construct<OtherSpecificationStmt>(indirect(Parser<EquivalenceStmt>{})),
184     construct<OtherSpecificationStmt>(indirect(Parser<BasedPointerStmt>{}))))
185 
186 // R1401 main-program ->
187 //         [program-stmt] [specification-part] [execution-part]
188 //         [internal-subprogram-part] end-program-stmt
189 TYPE_CONTEXT_PARSER("main program"_en_US,
190     construct<MainProgram>(maybe(statement(Parser<ProgramStmt>{})),
191         specificationPart, executionPart, maybe(internalSubprogramPart),
192         unterminatedStatement(Parser<EndProgramStmt>{})))
193 
194 // R1402 program-stmt -> PROGRAM program-name
195 // PGI allows empty parentheses after the name.
196 TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
197     construct<ProgramStmt>("PROGRAM" >> name /
198             maybe(extension<LanguageFeature::ProgramParentheses>(
199                 parenthesized(ok)))))
200 
201 // R1403 end-program-stmt -> END [PROGRAM [program-name]]
202 TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
203     construct<EndProgramStmt>(recovery(
204         "END PROGRAM" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
205 
206 // R1404 module ->
207 //         module-stmt [specification-part] [module-subprogram-part]
208 //         end-module-stmt
209 TYPE_CONTEXT_PARSER("module"_en_US,
210     construct<Module>(statement(Parser<ModuleStmt>{}), limitedSpecificationPart,
211         maybe(Parser<ModuleSubprogramPart>{}),
212         unterminatedStatement(Parser<EndModuleStmt>{})))
213 
214 // R1405 module-stmt -> MODULE module-name
215 TYPE_CONTEXT_PARSER(
216     "MODULE statement"_en_US, construct<ModuleStmt>("MODULE" >> name))
217 
218 // R1406 end-module-stmt -> END [MODULE [module-name]]
219 TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
220     construct<EndModuleStmt>(recovery(
221         "END MODULE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
222 
223 // R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
224 TYPE_CONTEXT_PARSER("module subprogram part"_en_US,
225     construct<ModuleSubprogramPart>(statement(containsStmt),
226         many(StartNewSubprogram{} >> Parser<ModuleSubprogram>{})))
227 
228 // R1408 module-subprogram ->
229 //         function-subprogram | subroutine-subprogram |
230 //         separate-module-subprogram
231 TYPE_PARSER(construct<ModuleSubprogram>(indirect(functionSubprogram)) ||
232     construct<ModuleSubprogram>(indirect(subroutineSubprogram)) ||
233     construct<ModuleSubprogram>(indirect(Parser<SeparateModuleSubprogram>{})))
234 
235 // R1410 module-nature -> INTRINSIC | NON_INTRINSIC
236 constexpr auto moduleNature{
237     "INTRINSIC" >> pure(UseStmt::ModuleNature::Intrinsic) ||
238     "NON_INTRINSIC" >> pure(UseStmt::ModuleNature::Non_Intrinsic)};
239 
240 // R1409 use-stmt ->
241 //         USE [[, module-nature] ::] module-name [, rename-list] |
242 //         USE [[, module-nature] ::] module-name , ONLY : [only-list]
243 // N.B. Lookahead to the end of the statement is necessary to resolve
244 // ambiguity with assignments and statement function definitions that
245 // begin with the letters "USE".
246 TYPE_PARSER(construct<UseStmt>("USE" >> optionalBeforeColons(moduleNature),
247                 name, ", ONLY :" >> optionalList(Parser<Only>{})) ||
248     construct<UseStmt>("USE" >> optionalBeforeColons(moduleNature), name,
249         defaulted("," >>
250             nonemptyList("expected renamings"_err_en_US, Parser<Rename>{})) /
251             lookAhead(endOfStmt)))
252 
253 // R1411 rename ->
254 //         local-name => use-name |
255 //         OPERATOR ( local-defined-operator ) =>
256 //           OPERATOR ( use-defined-operator )
257 TYPE_PARSER(construct<Rename>("OPERATOR (" >>
258                 construct<Rename::Operators>(
259                     definedOpName / ") => OPERATOR (", definedOpName / ")")) ||
260     construct<Rename>(construct<Rename::Names>(name, "=>" >> name)))
261 
262 // R1412 only -> generic-spec | only-use-name | rename
263 // R1413 only-use-name -> use-name
264 TYPE_PARSER(construct<Only>(Parser<Rename>{}) ||
265     construct<Only>(indirect(genericSpec)) ||
266     construct<Only>(name))  // TODO: ambiguous, accepted by genericSpec
267 
268 // R1416 submodule ->
269 //         submodule-stmt [specification-part] [module-subprogram-part]
270 //         end-submodule-stmt
271 TYPE_CONTEXT_PARSER("submodule"_en_US,
272     construct<Submodule>(statement(Parser<SubmoduleStmt>{}),
273         limitedSpecificationPart, maybe(Parser<ModuleSubprogramPart>{}),
274         unterminatedStatement(Parser<EndSubmoduleStmt>{})))
275 
276 // R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name
277 TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US,
278     construct<SubmoduleStmt>(
279         "SUBMODULE" >> parenthesized(Parser<ParentIdentifier>{}), name))
280 
281 // R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name]
282 TYPE_PARSER(construct<ParentIdentifier>(name, maybe(":" >> name)))
283 
284 // R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
285 TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
286     construct<EndSubmoduleStmt>(
287         recovery("END SUBMODULE" >> maybe(name) || bareEnd,
288             progUnitEndStmtErrorRecovery)))
289 
290 // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
291 TYPE_CONTEXT_PARSER("BLOCK DATA subprogram"_en_US,
292     construct<BlockData>(statement(Parser<BlockDataStmt>{}),
293         limitedSpecificationPart,
294         unterminatedStatement(Parser<EndBlockDataStmt>{})))
295 
296 // R1421 block-data-stmt -> BLOCK DATA [block-data-name]
297 TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
298     construct<BlockDataStmt>("BLOCK DATA" >> maybe(name)))
299 
300 // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
301 TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
302     construct<EndBlockDataStmt>(
303         recovery("END BLOCK DATA" >> maybe(name) || bareEnd,
304             progUnitEndStmtErrorRecovery)))
305 
306 // R1501 interface-block ->
307 //         interface-stmt [interface-specification]... end-interface-stmt
308 TYPE_PARSER(construct<InterfaceBlock>(statement(Parser<InterfaceStmt>{}),
309     many(Parser<InterfaceSpecification>{}),
310     statement(Parser<EndInterfaceStmt>{})))
311 
312 // R1502 interface-specification -> interface-body | procedure-stmt
313 TYPE_PARSER(construct<InterfaceSpecification>(Parser<InterfaceBody>{}) ||
314     construct<InterfaceSpecification>(statement(Parser<ProcedureStmt>{})))
315 
316 // R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE
317 TYPE_PARSER(construct<InterfaceStmt>("INTERFACE" >> maybe(genericSpec)) ||
318     construct<InterfaceStmt>(construct<Abstract>("ABSTRACT INTERFACE"_sptok)))
319 
320 // R1504 end-interface-stmt -> END INTERFACE [generic-spec]
321 TYPE_PARSER(construct<EndInterfaceStmt>("END INTERFACE" >> maybe(genericSpec)))
322 
323 // R1505 interface-body ->
324 //         function-stmt [specification-part] end-function-stmt |
325 //         subroutine-stmt [specification-part] end-subroutine-stmt
326 TYPE_CONTEXT_PARSER("interface body"_en_US,
327     construct<InterfaceBody>(
328         construct<InterfaceBody::Function>(statement(functionStmt),
329             indirect(limitedSpecificationPart), statement(endFunctionStmt))) ||
330         construct<InterfaceBody>(construct<InterfaceBody::Subroutine>(
331             statement(subroutineStmt), indirect(limitedSpecificationPart),
332             statement(endSubroutineStmt))))
333 
334 // R1507 specific-procedure -> procedure-name
335 constexpr auto specificProcedures{
336     nonemptyList("expected specific procedure names"_err_en_US, name)};
337 
338 // R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
339 TYPE_PARSER(construct<ProcedureStmt>("MODULE PROCEDURE"_sptok >>
340                     pure(ProcedureStmt::Kind::ModuleProcedure),
341                 maybe("::"_tok) >> specificProcedures) ||
342     construct<ProcedureStmt>(
343         "PROCEDURE" >> pure(ProcedureStmt::Kind::Procedure),
344         maybe("::"_tok) >> specificProcedures))
345 
346 // R1508 generic-spec ->
347 //         generic-name | OPERATOR ( defined-operator ) |
348 //         ASSIGNMENT ( = ) | defined-io-generic-spec
349 // R1509 defined-io-generic-spec ->
350 //         READ ( FORMATTED ) | READ ( UNFORMATTED ) |
351 //         WRITE ( FORMATTED ) | WRITE ( UNFORMATTED )
352 TYPE_PARSER(sourced(first(construct<GenericSpec>("OPERATOR" >>
353                               parenthesized(Parser<DefinedOperator>{})),
354     construct<GenericSpec>(
355         construct<GenericSpec::Assignment>("ASSIGNMENT ( = )"_tok)),
356     construct<GenericSpec>(
357         construct<GenericSpec::ReadFormatted>("READ ( FORMATTED )"_tok)),
358     construct<GenericSpec>(
359         construct<GenericSpec::ReadUnformatted>("READ ( UNFORMATTED )"_tok)),
360     construct<GenericSpec>(
361         construct<GenericSpec::WriteFormatted>("WRITE ( FORMATTED )"_tok)),
362     construct<GenericSpec>(
363         construct<GenericSpec::WriteUnformatted>("WRITE ( UNFORMATTED )"_tok)),
364     construct<GenericSpec>(name))))
365 
366 // R1510 generic-stmt ->
367 //         GENERIC [, access-spec] :: generic-spec => specific-procedure-list
368 TYPE_PARSER(construct<GenericStmt>("GENERIC" >> maybe("," >> accessSpec),
369     "::" >> genericSpec, "=>" >> specificProcedures))
370 
371 // R1511 external-stmt -> EXTERNAL [::] external-name-list
372 TYPE_PARSER(
373     "EXTERNAL" >> maybe("::"_tok) >> construct<ExternalStmt>(listOfNames))
374 
375 // R1512 procedure-declaration-stmt ->
376 //         PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::]
377 //         proc-decl-list
378 TYPE_PARSER("PROCEDURE" >>
379     construct<ProcedureDeclarationStmt>(parenthesized(maybe(procInterface)),
380         optionalListBeforeColons(Parser<ProcAttrSpec>{}),
381         nonemptyList("expected procedure declarations"_err_en_US, procDecl)))
382 
383 // R1513 proc-interface -> interface-name | declaration-type-spec
384 // R1516 interface-name -> name
385 // N.B. Simple names of intrinsic types (e.g., "REAL") are not
386 // ambiguous here - they take precedence over derived type names
387 // thanks to C1516.
388 TYPE_PARSER(
389     construct<ProcInterface>(declarationTypeSpec / lookAhead(")"_tok)) ||
390     construct<ProcInterface>(name))
391 
392 // R1514 proc-attr-spec ->
393 //         access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |
394 //         OPTIONAL | POINTER | PROTECTED | SAVE
395 TYPE_PARSER(construct<ProcAttrSpec>(accessSpec) ||
396     construct<ProcAttrSpec>(languageBindingSpec) ||
397     construct<ProcAttrSpec>("INTENT" >> parenthesized(intentSpec)) ||
398     construct<ProcAttrSpec>(optional) || construct<ProcAttrSpec>(pointer) ||
399     construct<ProcAttrSpec>(protectedAttr) || construct<ProcAttrSpec>(save))
400 
401 // R1515 proc-decl -> procedure-entity-name [=> proc-pointer-init]
402 TYPE_PARSER(construct<ProcDecl>(name, maybe("=>" >> Parser<ProcPointerInit>{})))
403 
404 // R1517 proc-pointer-init -> null-init | initial-proc-target
405 // R1518 initial-proc-target -> procedure-name
406 TYPE_PARSER(
407     construct<ProcPointerInit>(nullInit) || construct<ProcPointerInit>(name))
408 
409 // R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list
410 TYPE_PARSER(
411     "INTRINSIC" >> maybe("::"_tok) >> construct<IntrinsicStmt>(listOfNames))
412 
413 // R1520 function-reference -> procedure-designator ( [actual-arg-spec-list] )
414 TYPE_CONTEXT_PARSER("function reference"_en_US,
415     construct<FunctionReference>(
416         sourced(construct<Call>(Parser<ProcedureDesignator>{},
417             parenthesized(optionalList(actualArgSpec))))) /
418         !"["_tok)
419 
420 // R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )]
421 TYPE_PARSER(construct<CallStmt>(
422     sourced(construct<Call>("CALL" >> Parser<ProcedureDesignator>{},
423         defaulted(parenthesized(optionalList(actualArgSpec)))))))
424 
425 // R1522 procedure-designator ->
426 //         procedure-name | proc-component-ref | data-ref % binding-name
427 TYPE_PARSER(construct<ProcedureDesignator>(Parser<ProcComponentRef>{}) ||
428     construct<ProcedureDesignator>(name))
429 
430 // R1523 actual-arg-spec -> [keyword =] actual-arg
431 TYPE_PARSER(construct<ActualArgSpec>(
432     maybe(keyword / "=" / !"="_ch), Parser<ActualArg>{}))
433 
434 // R1524 actual-arg ->
435 //         expr | variable | procedure-name | proc-component-ref |
436 //         alt-return-spec
437 // N.B. the "procedure-name" and "proc-component-ref" alternatives can't
438 // yet be distinguished from "variable", many instances of which can't be
439 // distinguished from "expr" anyway (to do so would misparse structure
440 // constructors and function calls as array elements).
441 // Semantics sorts it all out later.
442 TYPE_PARSER(construct<ActualArg>(expr) ||
443     construct<ActualArg>(Parser<AltReturnSpec>{}) ||
444     extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
445         construct<ActualArg::PercentRef>("%REF" >> parenthesized(variable)))) ||
446     extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
447         construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
448 
449 // R1525 alt-return-spec -> * label
450 TYPE_PARSER(construct<AltReturnSpec>(star >> label))
451 
452 // R1527 prefix-spec ->
453 //         declaration-type-spec | ELEMENTAL | IMPURE | MODULE |
454 //         NON_RECURSIVE | PURE | RECURSIVE
455 TYPE_PARSER(first(construct<PrefixSpec>(declarationTypeSpec),
456     construct<PrefixSpec>(construct<PrefixSpec::Elemental>("ELEMENTAL"_tok)),
457     construct<PrefixSpec>(construct<PrefixSpec::Impure>("IMPURE"_tok)),
458     construct<PrefixSpec>(construct<PrefixSpec::Module>("MODULE"_tok)),
459     construct<PrefixSpec>(
460         construct<PrefixSpec::Non_Recursive>("NON_RECURSIVE"_tok)),
461     construct<PrefixSpec>(construct<PrefixSpec::Pure>("PURE"_tok)),
462     construct<PrefixSpec>(construct<PrefixSpec::Recursive>("RECURSIVE"_tok))))
463 
464 // R1529 function-subprogram ->
465 //         function-stmt [specification-part] [execution-part]
466 //         [internal-subprogram-part] end-function-stmt
467 TYPE_CONTEXT_PARSER("FUNCTION subprogram"_en_US,
468     construct<FunctionSubprogram>(statement(functionStmt), specificationPart,
469         executionPart, maybe(internalSubprogramPart),
470         unterminatedStatement(endFunctionStmt)))
471 
472 // R1530 function-stmt ->
473 //         [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix]
474 // R1526 prefix -> prefix-spec [prefix-spec]...
475 // R1531 dummy-arg-name -> name
476 TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US,
477     construct<FunctionStmt>(many(prefixSpec), "FUNCTION" >> name,
478         parenthesized(optionalList(name)), maybe(suffix)) ||
479         extension<LanguageFeature::OmitFunctionDummies>(
480             construct<FunctionStmt>(  // PGI & Intel accept "FUNCTION F"
481                 many(prefixSpec), "FUNCTION" >> name,
482                 construct<std::list<Name>>(),
483                 construct<std::optional<Suffix>>())))
484 
485 // R1532 suffix ->
486 //         proc-language-binding-spec [RESULT ( result-name )] |
487 //         RESULT ( result-name ) [proc-language-binding-spec]
488 TYPE_PARSER(construct<Suffix>(
489                 languageBindingSpec, maybe("RESULT" >> parenthesized(name))) ||
490     construct<Suffix>(
491         "RESULT" >> parenthesized(name), maybe(languageBindingSpec)))
492 
493 // R1533 end-function-stmt -> END [FUNCTION [function-name]]
494 TYPE_PARSER(construct<EndFunctionStmt>(recovery(
495     "END FUNCTION" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
496 
497 // R1534 subroutine-subprogram ->
498 //         subroutine-stmt [specification-part] [execution-part]
499 //         [internal-subprogram-part] end-subroutine-stmt
500 TYPE_CONTEXT_PARSER("SUBROUTINE subprogram"_en_US,
501     construct<SubroutineSubprogram>(statement(subroutineStmt),
502         specificationPart, executionPart, maybe(internalSubprogramPart),
503         unterminatedStatement(endSubroutineStmt)))
504 
505 // R1535 subroutine-stmt ->
506 //         [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] )
507 //         [proc-language-binding-spec]]
508 TYPE_PARSER(
509     construct<SubroutineStmt>(many(prefixSpec), "SUBROUTINE" >> name,
510         parenthesized(optionalList(dummyArg)), maybe(languageBindingSpec)) ||
511     construct<SubroutineStmt>(many(prefixSpec), "SUBROUTINE" >> name,
512         defaulted(cut >> many(dummyArg)),
513         defaulted(cut >> maybe(languageBindingSpec))))
514 
515 // R1536 dummy-arg -> dummy-arg-name | *
516 TYPE_PARSER(construct<DummyArg>(name) || construct<DummyArg>(star))
517 
518 // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
519 TYPE_PARSER(construct<EndSubroutineStmt>(recovery(
520     "END SUBROUTINE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
521 
522 // R1538 separate-module-subprogram ->
523 //         mp-subprogram-stmt [specification-part] [execution-part]
524 //         [internal-subprogram-part] end-mp-subprogram-stmt
525 TYPE_CONTEXT_PARSER("separate module subprogram"_en_US,
526     construct<SeparateModuleSubprogram>(statement(Parser<MpSubprogramStmt>{}),
527         specificationPart, executionPart, maybe(internalSubprogramPart),
528         statement(Parser<EndMpSubprogramStmt>{})))
529 
530 // R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name
531 TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
532     construct<MpSubprogramStmt>("MODULE PROCEDURE"_sptok >> name))
533 
534 // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
535 TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
536     construct<EndMpSubprogramStmt>(
537         recovery("END PROCEDURE" >> maybe(name) || bareEnd,
538             progUnitEndStmtErrorRecovery)))
539 
540 // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
541 TYPE_PARSER(
542     "ENTRY" >> (construct<EntryStmt>(name,
543                     parenthesized(optionalList(dummyArg)), maybe(suffix)) ||
544                    construct<EntryStmt>(name, construct<std::list<DummyArg>>(),
545                        construct<std::optional<Suffix>>())))
546 
547 // R1542 return-stmt -> RETURN [scalar-int-expr]
548 TYPE_CONTEXT_PARSER("RETURN statement"_en_US,
549     construct<ReturnStmt>("RETURN" >> maybe(scalarIntExpr)))
550 
551 // R1543 contains-stmt -> CONTAINS
552 TYPE_PARSER(construct<ContainsStmt>("CONTAINS"_tok))
553 
554 // R1544 stmt-function-stmt ->
555 //         function-name ( [dummy-arg-name-list] ) = scalar-expr
556 TYPE_CONTEXT_PARSER("statement function definition"_en_US,
557     construct<StmtFunctionStmt>(
558         name, parenthesized(optionalList(name)), "=" >> scalar(expr)))
559 }
560