//===-- lib/Parser/program-parsers.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Per-type parsers for program units #include "basic-parsers.h" #include "expr-parsers.h" #include "misc-parsers.h" #include "stmt-parser.h" #include "token-parsers.h" #include "type-parser-implementation.h" #include "flang/Parser/characters.h" #include "flang/Parser/parse-tree.h" namespace Fortran::parser { // R502 program-unit -> // main-program | external-subprogram | module | submodule | block-data // R503 external-subprogram -> function-subprogram | subroutine-subprogram // N.B. "module" must precede "external-subprogram" in this sequence of // alternatives to avoid ambiguity with the MODULE keyword prefix that // they recognize. I.e., "modulesubroutinefoo" should start a module // "subroutinefoo", not a subroutine "foo" with the MODULE prefix. The // ambiguity is exacerbated by the extension that accepts a function // statement without an otherwise empty list of dummy arguments. That // MODULE prefix is disallowed by a constraint (C1547) in this context, // so the standard language is not ambiguous, but disabling its misrecognition // here would require context-sensitive keyword recognition or variant parsers // for several productions; giving the "module" production priority here is a // cleaner solution, though regrettably subtle. // Enforcing C1547 is done in semantics. static constexpr auto programUnit{ construct(indirect(Parser{})) || construct(indirect(functionSubprogram)) || construct(indirect(subroutineSubprogram)) || construct(indirect(Parser{})) || construct(indirect(Parser{})) || construct(indirect(Parser{}))}; static constexpr auto normalProgramUnit{StartNewSubprogram{} >> programUnit / skipMany(";"_tok) / space / recovery(endOfLine, SkipPast<'\n'>{})}; static constexpr auto globalCompilerDirective{ construct(indirect(compilerDirective))}; static constexpr auto globalOpenACCCompilerDirective{ construct(indirect(skipStuffBeforeStatement >> "!$ACC "_sptok >> Parser{}))}; // R501 program -> program-unit [program-unit]... // This is the top-level production for the Fortran language. // F'2018 6.3.1 defines a program unit as a sequence of one or more lines, // implying that a line can't be part of two distinct program units. // Consequently, a program unit END statement should be the last statement // on its line. We parse those END statements via unterminatedStatement() // and then skip over the end of the line here. TYPE_PARSER( construct(extension( "nonstandard usage: empty source file"_port_en_US, skipStuffBeforeStatement >> !nextCh >> pure>()) || some(globalCompilerDirective || globalOpenACCCompilerDirective || normalProgramUnit) / skipStuffBeforeStatement)) // R504 specification-part -> // [use-stmt]... [import-stmt]... [implicit-part] // [declaration-construct]... TYPE_CONTEXT_PARSER("specification part"_en_US, construct(many(openaccDeclarativeConstruct), many(openmpDeclarativeConstruct), many(indirect(compilerDirective)), many(statement(indirect(Parser{}))), many(unambiguousStatement(indirect(Parser{}))), implicitPart, many(declarationConstruct))) // R507 declaration-construct -> // specification-construct | data-stmt | format-stmt | // entry-stmt | stmt-function-stmt // N.B. These parsers incorporate recognition of some other statements that // may have been misplaced in the sequence of statements that are acceptable // as a specification part in order to improve error recovery. // Also note that many instances of specification-part in the standard grammar // are in contexts that impose constraints on the kinds of statements that // are allowed, and so we have a variant production for declaration-construct // that implements those constraints. constexpr auto execPartLookAhead{first(actionStmt >> ok, openaccConstruct >> ok, openmpConstruct >> ok, "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok, "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok, "!$CUF"_tok)}; constexpr auto declErrorRecovery{ stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery}; constexpr auto misplacedSpecificationStmt{Parser{} >> fail("misplaced USE statement"_err_en_US) || Parser{} >> fail( "IMPORT statements must follow any USE statements and precede all other declarations"_err_en_US) || Parser{} >> fail( "IMPLICIT statements must follow USE and IMPORT and precede all other declarations"_err_en_US)}; TYPE_PARSER(recovery( withMessage("expected declaration construct"_err_en_US, CONTEXT_PARSER("declaration construct"_en_US, first(construct(specificationConstruct), construct(statement(indirect(dataStmt))), construct( statement(indirect(formatStmt))), construct(statement(indirect(entryStmt))), construct( statement(indirect(Parser{}))), misplacedSpecificationStmt))), construct(declErrorRecovery))) // R507 variant of declaration-construct for use in limitedSpecificationPart. constexpr auto invalidDeclarationStmt{formatStmt >> fail( "FORMAT statements are not permitted in this specification part"_err_en_US) || entryStmt >> fail( "ENTRY statements are not permitted in this specification part"_err_en_US)}; constexpr auto limitedDeclarationConstruct{recovery( withMessage("expected declaration construct"_err_en_US, inContext("declaration construct"_en_US, first(construct(specificationConstruct), construct(statement(indirect(dataStmt))), misplacedSpecificationStmt, invalidDeclarationStmt))), construct( stmtErrorRecoveryStart >> skipStmtErrorRecovery))}; // R504 variant for many contexts (modules, submodules, BLOCK DATA subprograms, // and interfaces) which have constraints on their specification parts that // preclude FORMAT, ENTRY, and statement functions, and benefit from // specialized error recovery in the event of a spurious executable // statement. constexpr auto limitedSpecificationPart{inContext("specification part"_en_US, construct(many(openaccDeclarativeConstruct), many(openmpDeclarativeConstruct), many(indirect(compilerDirective)), many(statement(indirect(Parser{}))), many(unambiguousStatement(indirect(Parser{}))), implicitPart, many(limitedDeclarationConstruct)))}; // R508 specification-construct -> // derived-type-def | enum-def | generic-stmt | interface-block | // parameter-stmt | procedure-declaration-stmt | // other-specification-stmt | type-declaration-stmt TYPE_CONTEXT_PARSER("specification construct"_en_US, first(construct(indirect(Parser{})), construct(indirect(Parser{})), construct( statement(indirect(Parser{}))), construct(indirect(interfaceBlock)), construct(statement(indirect(parameterStmt))), construct( statement(indirect(oldParameterStmt))), construct( statement(indirect(Parser{}))), construct( statement(Parser{})), construct( statement(indirect(typeDeclarationStmt))), construct(indirect(Parser{})), construct( indirect(openaccDeclarativeConstruct)), construct(indirect(openmpDeclarativeConstruct)), construct(indirect(compilerDirective)))) // R513 other-specification-stmt -> // access-stmt | allocatable-stmt | asynchronous-stmt | bind-stmt | // codimension-stmt | contiguous-stmt | dimension-stmt | external-stmt | // intent-stmt | intrinsic-stmt | namelist-stmt | optional-stmt | // pointer-stmt | protected-stmt | save-stmt | target-stmt | // volatile-stmt | value-stmt | common-stmt | equivalence-stmt | // (CUDA) CUDA-attributes-stmt TYPE_PARSER(first( construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})))) // R1401 main-program -> // [program-stmt] [specification-part] [execution-part] // [internal-subprogram-part] end-program-stmt TYPE_CONTEXT_PARSER("main program"_en_US, construct(maybe(statement(Parser{})), specificationPart, executionPart, maybe(internalSubprogramPart), unterminatedStatement(Parser{}))) // R1402 program-stmt -> PROGRAM program-name // PGI allows empty parentheses after the name. TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US, construct("PROGRAM" >> name / maybe(extension( "nonstandard usage: parentheses in PROGRAM statement"_port_en_US, parenthesized(ok))))) // R1403 end-program-stmt -> END [PROGRAM [program-name]] TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US, construct(recovery( "END PROGRAM" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1404 module -> // module-stmt [specification-part] [module-subprogram-part] // end-module-stmt TYPE_CONTEXT_PARSER("module"_en_US, construct(statement(Parser{}), limitedSpecificationPart, maybe(Parser{}), unterminatedStatement(Parser{}))) // R1405 module-stmt -> MODULE module-name TYPE_CONTEXT_PARSER( "MODULE statement"_en_US, construct("MODULE" >> name)) // R1406 end-module-stmt -> END [MODULE [module-name]] TYPE_CONTEXT_PARSER("END MODULE statement"_en_US, construct(recovery( "END MODULE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1407 module-subprogram-part -> contains-stmt [module-subprogram]... TYPE_CONTEXT_PARSER("module subprogram part"_en_US, construct(statement(containsStmt), many(StartNewSubprogram{} >> Parser{}))) // R1408 module-subprogram -> // function-subprogram | subroutine-subprogram | // separate-module-subprogram TYPE_PARSER(construct(indirect(functionSubprogram)) || construct(indirect(subroutineSubprogram)) || construct(indirect(Parser{}))) // R1410 module-nature -> INTRINSIC | NON_INTRINSIC constexpr auto moduleNature{ "INTRINSIC" >> pure(UseStmt::ModuleNature::Intrinsic) || "NON_INTRINSIC" >> pure(UseStmt::ModuleNature::Non_Intrinsic)}; // R1409 use-stmt -> // USE [[, module-nature] ::] module-name [, rename-list] | // USE [[, module-nature] ::] module-name , ONLY : [only-list] // N.B. Lookahead to the end of the statement is necessary to resolve // ambiguity with assignments and statement function definitions that // begin with the letters "USE". TYPE_PARSER(construct("USE" >> optionalBeforeColons(moduleNature), name, ", ONLY :" >> optionalList(Parser{})) || construct("USE" >> optionalBeforeColons(moduleNature), name, defaulted("," >> nonemptyList("expected renamings"_err_en_US, Parser{})) / lookAhead(endOfStmt))) // R1411 rename -> // local-name => use-name | // OPERATOR ( local-defined-operator ) => // OPERATOR ( use-defined-operator ) TYPE_PARSER(construct("OPERATOR (" >> construct( definedOpName / ") => OPERATOR (", definedOpName / ")")) || construct(construct(name, "=>" >> name))) // R1412 only -> generic-spec | only-use-name | rename // R1413 only-use-name -> use-name // N.B. generic-spec and only-use-name are ambiguous; resolved with symbols TYPE_PARSER(construct(Parser{}) || construct(indirect(genericSpec)) || construct(name)) // R1416 submodule -> // submodule-stmt [specification-part] [module-subprogram-part] // end-submodule-stmt TYPE_CONTEXT_PARSER("submodule"_en_US, construct(statement(Parser{}), limitedSpecificationPart, maybe(Parser{}), unterminatedStatement(Parser{}))) // R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US, construct( "SUBMODULE" >> parenthesized(Parser{}), name)) // R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name] TYPE_PARSER(construct(name, maybe(":" >> name))) // R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]] TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US, construct( recovery("END SUBMODULE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt TYPE_CONTEXT_PARSER("BLOCK DATA subprogram"_en_US, construct(statement(Parser{}), limitedSpecificationPart, unterminatedStatement(Parser{}))) // R1421 block-data-stmt -> BLOCK DATA [block-data-name] TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US, construct("BLOCK DATA" >> maybe(name))) // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]] TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US, construct( recovery("END BLOCK DATA" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1501 interface-block -> // interface-stmt [interface-specification]... end-interface-stmt TYPE_PARSER(construct(statement(Parser{}), many(Parser{}), statement(Parser{}))) // R1502 interface-specification -> interface-body | procedure-stmt TYPE_PARSER(construct(Parser{}) || construct(statement(Parser{}))) // R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE TYPE_PARSER(construct("INTERFACE" >> maybe(genericSpec)) || construct(construct("ABSTRACT INTERFACE"_sptok))) // R1504 end-interface-stmt -> END INTERFACE [generic-spec] TYPE_PARSER( construct(recovery("END INTERFACE" >> maybe(genericSpec), constructEndStmtErrorRecovery >> pure>()))) // R1505 interface-body -> // function-stmt [specification-part] end-function-stmt | // subroutine-stmt [specification-part] end-subroutine-stmt TYPE_CONTEXT_PARSER("interface body"_en_US, construct( construct(statement(functionStmt), indirect(limitedSpecificationPart), statement(endFunctionStmt))) || construct(construct( statement(subroutineStmt), indirect(limitedSpecificationPart), statement(endSubroutineStmt)))) // R1507 specific-procedure -> procedure-name constexpr auto specificProcedures{ nonemptyList("expected specific procedure names"_err_en_US, name)}; // R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list TYPE_PARSER(construct("MODULE PROCEDURE"_sptok >> pure(ProcedureStmt::Kind::ModuleProcedure), maybe("::"_tok) >> specificProcedures) || construct( "PROCEDURE" >> pure(ProcedureStmt::Kind::Procedure), maybe("::"_tok) >> specificProcedures)) // R1508 generic-spec -> // generic-name | OPERATOR ( defined-operator ) | // ASSIGNMENT ( = ) | defined-io-generic-spec // R1509 defined-io-generic-spec -> // READ ( FORMATTED ) | READ ( UNFORMATTED ) | // WRITE ( FORMATTED ) | WRITE ( UNFORMATTED ) TYPE_PARSER(sourced(first(construct("OPERATOR" >> parenthesized(Parser{})), construct( construct("ASSIGNMENT ( = )"_tok)), construct( construct("READ ( FORMATTED )"_tok)), construct( construct("READ ( UNFORMATTED )"_tok)), construct( construct("WRITE ( FORMATTED )"_tok)), construct( construct("WRITE ( UNFORMATTED )"_tok)), construct(name)))) // R1510 generic-stmt -> // GENERIC [, access-spec] :: generic-spec => specific-procedure-list TYPE_PARSER(construct("GENERIC" >> maybe("," >> accessSpec), "::" >> genericSpec, "=>" >> specificProcedures)) // R1511 external-stmt -> EXTERNAL [::] external-name-list TYPE_PARSER( "EXTERNAL" >> maybe("::"_tok) >> construct(listOfNames)) // R1512 procedure-declaration-stmt -> // PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::] // proc-decl-list TYPE_PARSER("PROCEDURE" >> construct(parenthesized(maybe(procInterface)), optionalListBeforeColons(Parser{}), nonemptyList("expected procedure declarations"_err_en_US, procDecl))) // R1513 proc-interface -> interface-name | declaration-type-spec // R1516 interface-name -> name // N.B. Simple names of intrinsic types (e.g., "REAL") are not // ambiguous here - they take precedence over derived type names // thanks to C1516. TYPE_PARSER( construct(declarationTypeSpec / lookAhead(")"_tok)) || construct(name)) // R1514 proc-attr-spec -> // access-spec | proc-language-binding-spec | INTENT ( intent-spec ) | // OPTIONAL | POINTER | PROTECTED | SAVE TYPE_PARSER(construct(accessSpec) || construct(languageBindingSpec) || construct("INTENT" >> parenthesized(intentSpec)) || construct(optional) || construct(pointer) || construct(protectedAttr) || construct(save)) // R1515 proc-decl -> procedure-entity-name [=> proc-pointer-init] TYPE_PARSER(construct(name, maybe("=>" >> Parser{}))) // R1517 proc-pointer-init -> null-init | initial-proc-target // R1518 initial-proc-target -> procedure-name TYPE_PARSER( construct(nullInit) || construct(name)) // R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list TYPE_PARSER( "INTRINSIC" >> maybe("::"_tok) >> construct(listOfNames)) // R1520 function-reference -> procedure-designator // ( [actual-arg-spec-list] ) TYPE_CONTEXT_PARSER("function reference"_en_US, sourced(construct( construct(Parser{}, parenthesized(optionalList(actualArgSpec))))) / !"["_tok) // R1521 call-stmt -> CALL procedure-designator [chevrons] /// [( [actual-arg-spec-list] )] // (CUDA) chevrons -> <<< scalar-expr, scalar-expr [, scalar-int-expr // [, scalar-int-expr ] ] >>> TYPE_PARSER(extension( "<<<" >> construct(scalarExpr, "," >> scalarExpr, maybe("," >> scalarIntExpr), maybe("," >> scalarIntExpr)) / ">>>")) TYPE_PARSER(construct( sourced(construct("CALL" >> Parser{}, maybe(Parser{}), defaulted(parenthesized(optionalList(actualArgSpec))))))) // R1522 procedure-designator -> // procedure-name | proc-component-ref | data-ref % binding-name TYPE_PARSER(construct(Parser{}) || construct(name)) // R1523 actual-arg-spec -> [keyword =] actual-arg TYPE_PARSER(construct( maybe(keyword / "=" / !"="_ch), Parser{})) // R1524 actual-arg -> // expr | variable | procedure-name | proc-component-ref | // alt-return-spec // N.B. the "procedure-name" and "proc-component-ref" alternatives can't // yet be distinguished from "variable", many instances of which can't be // distinguished from "expr" anyway (to do so would misparse structure // constructors and function calls as array elements). // Semantics sorts it all out later. TYPE_PARSER(construct(expr) || construct(Parser{}) || extension( "nonstandard usage: %REF"_port_en_US, construct(construct( "%REF" >> parenthesized(variable)))) || extension( "nonstandard usage: %VAL"_port_en_US, construct( construct("%VAL" >> parenthesized(expr))))) // R1525 alt-return-spec -> * label TYPE_PARSER(construct(star >> label)) // R1527 prefix-spec -> // declaration-type-spec | ELEMENTAL | IMPURE | MODULE | // NON_RECURSIVE | PURE | RECURSIVE | // (CUDA) ATTRIBUTES ( (DEVICE | GLOBAL | GRID_GLOBAL | HOST)... ) | // LAUNCH_BOUNDS(expr-list) | CLUSTER_DIMS(expr-list) TYPE_PARSER(first("DEVICE" >> pure(common::CUDASubprogramAttrs::Device), "GLOBAL" >> pure(common::CUDASubprogramAttrs::Global), "GRID_GLOBAL" >> pure(common::CUDASubprogramAttrs::Grid_Global), "HOST" >> pure(common::CUDASubprogramAttrs::Host))) TYPE_PARSER(first(construct(declarationTypeSpec), construct(construct("ELEMENTAL"_tok)), construct(construct("IMPURE"_tok)), construct(construct("MODULE"_tok)), construct( construct("NON_RECURSIVE"_tok)), construct(construct("PURE"_tok)), construct(construct("RECURSIVE"_tok)), extension( construct(construct("ATTRIBUTES" >> parenthesized( optionalList(Parser{}))))), extension(construct( construct("LAUNCH_BOUNDS" >> parenthesized(nonemptyList( "expected launch bounds"_err_en_US, scalarIntConstantExpr))))), extension(construct( construct("CLUSTER_DIMS" >> parenthesized(nonemptyList("expected cluster dimensions"_err_en_US, scalarIntConstantExpr))))))) // R1529 function-subprogram -> // function-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-function-stmt TYPE_CONTEXT_PARSER("FUNCTION subprogram"_en_US, construct(statement(functionStmt), specificationPart, executionPart, maybe(internalSubprogramPart), unterminatedStatement(endFunctionStmt))) // R1530 function-stmt -> // [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix] // R1526 prefix -> prefix-spec [prefix-spec]... // R1531 dummy-arg-name -> name TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US, construct(many(prefixSpec), "FUNCTION" >> name, parenthesized(optionalList(name)), maybe(suffix)) || extension( "nonstandard usage: FUNCTION statement without dummy argument list"_port_en_US, construct( // PGI & Intel accept "FUNCTION F" many(prefixSpec), "FUNCTION" >> name, construct>(), construct>()))) // R1532 suffix -> // proc-language-binding-spec [RESULT ( result-name )] | // RESULT ( result-name ) [proc-language-binding-spec] TYPE_PARSER(construct( languageBindingSpec, maybe("RESULT" >> parenthesized(name))) || construct( "RESULT" >> parenthesized(name), maybe(languageBindingSpec))) // R1533 end-function-stmt -> END [FUNCTION [function-name]] TYPE_PARSER(construct(recovery( "END FUNCTION" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1534 subroutine-subprogram -> // subroutine-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-subroutine-stmt TYPE_CONTEXT_PARSER("SUBROUTINE subprogram"_en_US, construct(statement(subroutineStmt), specificationPart, executionPart, maybe(internalSubprogramPart), unterminatedStatement(endSubroutineStmt))) // R1535 subroutine-stmt -> // [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] ) // [proc-language-binding-spec]] TYPE_PARSER( construct(many(prefixSpec), "SUBROUTINE" >> name, parenthesized(optionalList(dummyArg)), maybe(languageBindingSpec)) || construct(many(prefixSpec), "SUBROUTINE" >> name, pure>(), pure>())) // R1536 dummy-arg -> dummy-arg-name | * TYPE_PARSER(construct(name) || construct(star)) // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]] TYPE_PARSER(construct(recovery( "END SUBROUTINE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1538 separate-module-subprogram -> // mp-subprogram-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-mp-subprogram-stmt TYPE_CONTEXT_PARSER("separate module subprogram"_en_US, construct(statement(Parser{}), specificationPart, executionPart, maybe(internalSubprogramPart), statement(Parser{}))) // R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US, construct("MODULE PROCEDURE"_sptok >> name)) // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]] TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US, construct( recovery("END PROCEDURE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery))) // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]] TYPE_PARSER( "ENTRY" >> (construct(name, parenthesized(optionalList(dummyArg)), maybe(suffix)) || construct(name, construct>(), construct>()))) // R1542 return-stmt -> RETURN [scalar-int-expr] TYPE_CONTEXT_PARSER("RETURN statement"_en_US, construct("RETURN" >> maybe(scalarIntExpr))) // R1543 contains-stmt -> CONTAINS TYPE_PARSER(construct("CONTAINS"_tok)) // R1544 stmt-function-stmt -> // function-name ( [dummy-arg-name-list] ) = scalar-expr TYPE_CONTEXT_PARSER("statement function definition"_en_US, construct( name, parenthesized(optionalList(name)), "=" >> scalar(expr))) } // namespace Fortran::parser