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