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