//===-- lib/Parser/executable-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 executable statements #include "basic-parsers.h" #include "debug-parser.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 { // Fortran allows the statement with the corresponding label at the end of // a do-construct that begins with an old-style label-do-stmt to be a // new-style END DO statement; e.g., DO 10 I=1,N; ...; 10 END DO. Usually, // END DO statements appear only at the ends of do-constructs that begin // with a nonlabel-do-stmt, so care must be taken to recognize this case and // essentially treat them like CONTINUE statements. // R514 executable-construct -> // action-stmt | associate-construct | block-construct | // case-construct | change-team-construct | critical-construct | // do-construct | if-construct | select-rank-construct | // select-type-construct | where-construct | forall-construct constexpr auto executableConstruct{ first(construct(CapturedLabelDoStmt{}), construct(EndDoStmtForCapturedLabelDoStmt{}), construct(indirect(Parser{})), // Attempt DO statements before assignment statements for better // error messages in cases like "DO10I=1,(error)". construct(statement(actionStmt)), 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(whereConstruct)), construct(indirect(forallConstruct)), construct(indirect(ompEndLoopDirective)), construct(indirect(openmpConstruct)), construct(indirect(accEndCombinedDirective)), construct(indirect(openaccConstruct)), construct(indirect(compilerDirective)))}; // R510 execution-part-construct -> // executable-construct | format-stmt | entry-stmt | data-stmt // Extension (PGI/Intel): also accept NAMELIST in execution part constexpr auto obsoleteExecutionPartConstruct{recovery(ignoredStatementPrefix >> fail( "obsolete legacy extension is not supported"_err_en_US), construct(construct(ok / statement("REDIMENSION" >> name / parenthesized(nonemptyList(Parser{}))))))}; TYPE_PARSER(recovery( withMessage("expected execution part construct"_err_en_US, CONTEXT_PARSER("execution part construct"_en_US, first(construct(executableConstruct), construct( statement(indirect(formatStmt))), construct( statement(indirect(entryStmt))), construct( statement(indirect(dataStmt))), extension( construct( statement(indirect(Parser{})))), obsoleteExecutionPartConstruct))), construct(executionPartErrorRecovery))) // R509 execution-part -> executable-construct [execution-part-construct]... TYPE_CONTEXT_PARSER("execution part"_en_US, construct(many(executionPartConstruct))) // R515 action-stmt -> // allocate-stmt | assignment-stmt | backspace-stmt | call-stmt | // close-stmt | continue-stmt | cycle-stmt | deallocate-stmt | // endfile-stmt | error-stop-stmt | event-post-stmt | event-wait-stmt | // exit-stmt | fail-image-stmt | flush-stmt | form-team-stmt | // goto-stmt | if-stmt | inquire-stmt | lock-stmt | nullify-stmt | // open-stmt | pointer-assignment-stmt | print-stmt | read-stmt | // return-stmt | rewind-stmt | stop-stmt | sync-all-stmt | // sync-images-stmt | sync-memory-stmt | sync-team-stmt | unlock-stmt | // wait-stmt | where-stmt | write-stmt | computed-goto-stmt | forall-stmt // R1159 continue-stmt -> CONTINUE // R1163 fail-image-stmt -> FAIL IMAGE TYPE_PARSER(first(construct(indirect(Parser{})), construct(indirect(assignmentStmt)), construct(indirect(pointerAssignmentStmt)), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(construct("CONTINUE"_tok)), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(construct("FAIL IMAGE"_sptok)), 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{})), // & error-stop-stmt construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(whereStmt)), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(forallStmt)), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})), construct(indirect(Parser{})))) // R1102 associate-construct -> associate-stmt block end-associate-stmt TYPE_CONTEXT_PARSER("ASSOCIATE construct"_en_US, construct(statement(Parser{}), block, statement(Parser{}))) // R1103 associate-stmt -> // [associate-construct-name :] ASSOCIATE ( association-list ) TYPE_CONTEXT_PARSER("ASSOCIATE statement"_en_US, construct(maybe(name / ":"), "ASSOCIATE" >> parenthesized(nonemptyList(Parser{})))) // R1104 association -> associate-name => selector TYPE_PARSER(construct(name, "=>" >> selector)) // R1105 selector -> expr | variable TYPE_PARSER(construct(variable) / lookAhead(","_tok || ")"_tok) || construct(expr)) // R1106 end-associate-stmt -> END ASSOCIATE [associate-construct-name] TYPE_PARSER(construct( recovery("END ASSOCIATE" >> maybe(name), endStmtErrorRecovery))) // R1107 block-construct -> // block-stmt [block-specification-part] block end-block-stmt TYPE_CONTEXT_PARSER("BLOCK construct"_en_US, construct(statement(Parser{}), Parser{}, // can be empty block, statement(Parser{}))) // R1108 block-stmt -> [block-construct-name :] BLOCK TYPE_PARSER(construct(maybe(name / ":") / "BLOCK")) // R1109 block-specification-part -> // [use-stmt]... [import-stmt]... [implicit-part] // [[declaration-construct]... specification-construct] // C1107 prohibits COMMON, EQUIVALENCE, INTENT, NAMELIST, OPTIONAL, VALUE, // and statement function definitions. C1108 prohibits SAVE /common/. // C1570 indirectly prohibits ENTRY. These constraints are best enforced later. // The odd grammar rule above would have the effect of forcing any // trailing FORMAT and DATA statements after the last specification-construct // to be recognized as part of the block-construct's block part rather than // its block-specification-part, a distinction without any apparent difference. TYPE_PARSER(construct(specificationPart)) // R1110 end-block-stmt -> END BLOCK [block-construct-name] TYPE_PARSER(construct( recovery("END BLOCK" >> maybe(name), endStmtErrorRecovery))) // R1111 change-team-construct -> change-team-stmt block end-change-team-stmt TYPE_CONTEXT_PARSER("CHANGE TEAM construct"_en_US, construct(statement(Parser{}), block, statement(Parser{}))) // R1112 change-team-stmt -> // [team-construct-name :] CHANGE TEAM // ( team-value [, coarray-association-list] [, sync-stat-list] ) TYPE_CONTEXT_PARSER("CHANGE TEAM statement"_en_US, construct(maybe(name / ":"), "CHANGE TEAM"_sptok >> "("_tok >> teamValue, defaulted("," >> nonemptyList(Parser{})), defaulted("," >> nonemptyList(statOrErrmsg))) / ")") // R1113 coarray-association -> codimension-decl => selector TYPE_PARSER( construct(Parser{}, "=>" >> selector)) // R1114 end-change-team-stmt -> // END TEAM [( [sync-stat-list] )] [team-construct-name] TYPE_CONTEXT_PARSER("END TEAM statement"_en_US, construct( "END TEAM" >> defaulted(parenthesized(optionalList(statOrErrmsg))), maybe(name))) // R1117 critical-stmt -> // [critical-construct-name :] CRITICAL [( [sync-stat-list] )] TYPE_CONTEXT_PARSER("CRITICAL statement"_en_US, construct(maybe(name / ":"), "CRITICAL" >> defaulted(parenthesized(optionalList(statOrErrmsg))))) // R1116 critical-construct -> critical-stmt block end-critical-stmt TYPE_CONTEXT_PARSER("CRITICAL construct"_en_US, construct(statement(Parser{}), block, statement(Parser{}))) // R1118 end-critical-stmt -> END CRITICAL [critical-construct-name] TYPE_PARSER(construct( recovery("END CRITICAL" >> maybe(name), endStmtErrorRecovery))) // R1119 do-construct -> do-stmt block end-do // R1120 do-stmt -> nonlabel-do-stmt | label-do-stmt TYPE_CONTEXT_PARSER("DO construct"_en_US, construct( statement(Parser{}) / EnterNonlabelDoConstruct{}, block, statement(Parser{}) / LeaveDoConstruct{})) // R1125 concurrent-header -> // ( [integer-type-spec ::] concurrent-control-list // [, scalar-mask-expr] ) TYPE_PARSER(parenthesized(construct( maybe(integerTypeSpec / "::"), nonemptyList(Parser{}), maybe("," >> scalarLogicalExpr)))) // R1126 concurrent-control -> // index-name = concurrent-limit : concurrent-limit [: concurrent-step] // R1127 concurrent-limit -> scalar-int-expr // R1128 concurrent-step -> scalar-int-expr TYPE_PARSER(construct(name / "=", scalarIntExpr / ":", scalarIntExpr, maybe(":" >> scalarIntExpr))) // R1130 locality-spec -> // LOCAL ( variable-name-list ) | LOCAL_INIT ( variable-name-list ) | // SHARED ( variable-name-list ) | DEFAULT ( NONE ) TYPE_PARSER(construct(construct( "LOCAL" >> parenthesized(listOfNames))) || construct(construct( "LOCAL_INIT"_sptok >> parenthesized(listOfNames))) || construct(construct( "SHARED" >> parenthesized(listOfNames))) || construct( construct("DEFAULT ( NONE )"_tok))) // R1123 loop-control -> // [,] do-variable = scalar-int-expr , scalar-int-expr // [, scalar-int-expr] | // [,] WHILE ( scalar-logical-expr ) | // [,] CONCURRENT concurrent-header concurrent-locality // R1129 concurrent-locality -> [locality-spec]... TYPE_CONTEXT_PARSER("loop control"_en_US, maybe(","_tok) >> (construct(loopBounds(scalarExpr)) || construct( "WHILE" >> parenthesized(scalarLogicalExpr)) || construct(construct( "CONCURRENT" >> concurrentHeader, many(Parser{}))))) // R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control] TYPE_CONTEXT_PARSER("label DO statement"_en_US, construct( maybe(name / ":"), "DO" >> label, maybe(loopControl))) // R1122 nonlabel-do-stmt -> [do-construct-name :] DO [loop-control] TYPE_CONTEXT_PARSER("nonlabel DO statement"_en_US, construct(maybe(name / ":"), "DO" >> maybe(loopControl))) // R1132 end-do-stmt -> END DO [do-construct-name] TYPE_CONTEXT_PARSER("END DO statement"_en_US, construct( recovery("END DO" >> maybe(name), endStmtErrorRecovery))) // R1133 cycle-stmt -> CYCLE [do-construct-name] TYPE_CONTEXT_PARSER( "CYCLE statement"_en_US, construct("CYCLE" >> maybe(name))) // R1134 if-construct -> // if-then-stmt block [else-if-stmt block]... // [else-stmt block] end-if-stmt // R1135 if-then-stmt -> [if-construct-name :] IF ( scalar-logical-expr ) // THEN R1136 else-if-stmt -> // ELSE IF ( scalar-logical-expr ) THEN [if-construct-name] // R1137 else-stmt -> ELSE [if-construct-name] // R1138 end-if-stmt -> END IF [if-construct-name] TYPE_CONTEXT_PARSER("IF construct"_en_US, construct( statement(construct(maybe(name / ":"), "IF" >> parenthesized(scalarLogicalExpr) / "THEN")), block, many(construct( unambiguousStatement(construct( "ELSE IF" >> parenthesized(scalarLogicalExpr), "THEN" >> maybe(name))), block)), maybe(construct( statement(construct("ELSE" >> maybe(name))), block)), statement(construct( recovery("END IF" >> maybe(name), endStmtErrorRecovery))))) // R1139 if-stmt -> IF ( scalar-logical-expr ) action-stmt TYPE_CONTEXT_PARSER("IF statement"_en_US, construct("IF" >> parenthesized(scalarLogicalExpr), unlabeledStatement(actionStmt))) // R1140 case-construct -> // select-case-stmt [case-stmt block]... end-select-stmt TYPE_CONTEXT_PARSER("SELECT CASE construct"_en_US, construct(statement(Parser{}), many(construct( unambiguousStatement(Parser{}), block)), statement(endSelectStmt))) // R1141 select-case-stmt -> [case-construct-name :] SELECT CASE ( case-expr // ) R1144 case-expr -> scalar-expr TYPE_CONTEXT_PARSER("SELECT CASE statement"_en_US, construct( maybe(name / ":"), "SELECT CASE" >> parenthesized(scalar(expr)))) // R1142 case-stmt -> CASE case-selector [case-construct-name] TYPE_CONTEXT_PARSER("CASE statement"_en_US, construct("CASE" >> Parser{}, maybe(name))) // R1143 end-select-stmt -> END SELECT [case-construct-name] // R1151 end-select-rank-stmt -> END SELECT [select-construct-name] // R1155 end-select-type-stmt -> END SELECT [select-construct-name] TYPE_PARSER(construct( recovery("END SELECT" >> maybe(name), endStmtErrorRecovery))) // R1145 case-selector -> ( case-value-range-list ) | DEFAULT constexpr auto defaultKeyword{construct("DEFAULT"_tok)}; TYPE_PARSER(parenthesized(construct( nonemptyList(Parser{}))) || construct(defaultKeyword)) // R1147 case-value -> scalar-constant-expr constexpr auto caseValue{scalar(constantExpr)}; // R1146 case-value-range -> // case-value | case-value : | : case-value | case-value : case-value TYPE_PARSER(construct(construct( construct>(caseValue), ":" >> maybe(caseValue))) || construct( construct(construct>(), ":" >> construct>(caseValue))) || construct(caseValue)) // R1148 select-rank-construct -> // select-rank-stmt [select-rank-case-stmt block]... // end-select-rank-stmt TYPE_CONTEXT_PARSER("SELECT RANK construct"_en_US, construct(statement(Parser{}), many(construct( unambiguousStatement(Parser{}), block)), statement(endSelectStmt))) // R1149 select-rank-stmt -> // [select-construct-name :] SELECT RANK // ( [associate-name =>] selector ) TYPE_CONTEXT_PARSER("SELECT RANK statement"_en_US, construct(maybe(name / ":"), "SELECT RANK"_sptok >> "("_tok >> maybe(name / "=>"), selector / ")")) // R1150 select-rank-case-stmt -> // RANK ( scalar-int-constant-expr ) [select-construct-name] | // RANK ( * ) [select-construct-name] | // RANK DEFAULT [select-construct-name] TYPE_CONTEXT_PARSER("RANK case statement"_en_US, "RANK" >> (construct( parenthesized(construct( scalarIntConstantExpr) || construct(star)) || construct(defaultKeyword), maybe(name)))) // R1152 select-type-construct -> // select-type-stmt [type-guard-stmt block]... end-select-type-stmt TYPE_CONTEXT_PARSER("SELECT TYPE construct"_en_US, construct(statement(Parser{}), many(construct( unambiguousStatement(Parser{}), block)), statement(endSelectStmt))) // R1153 select-type-stmt -> // [select-construct-name :] SELECT TYPE // ( [associate-name =>] selector ) TYPE_CONTEXT_PARSER("SELECT TYPE statement"_en_US, construct(maybe(name / ":"), "SELECT TYPE (" >> maybe(name / "=>"), selector / ")")) // R1154 type-guard-stmt -> // TYPE IS ( type-spec ) [select-construct-name] | // CLASS IS ( derived-type-spec ) [select-construct-name] | // CLASS DEFAULT [select-construct-name] TYPE_CONTEXT_PARSER("type guard statement"_en_US, construct("TYPE IS"_sptok >> parenthesized(construct(typeSpec)) || "CLASS IS"_sptok >> parenthesized(construct( derivedTypeSpec)) || construct("CLASS" >> defaultKeyword), maybe(name))) // R1156 exit-stmt -> EXIT [construct-name] TYPE_CONTEXT_PARSER( "EXIT statement"_en_US, construct("EXIT" >> maybe(name))) // R1157 goto-stmt -> GO TO label TYPE_CONTEXT_PARSER( "GOTO statement"_en_US, construct("GO TO" >> label)) // R1158 computed-goto-stmt -> GO TO ( label-list ) [,] scalar-int-expr TYPE_CONTEXT_PARSER("computed GOTO statement"_en_US, construct("GO TO" >> parenthesized(nonemptyList(label)), maybe(","_tok) >> scalarIntExpr)) // R1160 stop-stmt -> STOP [stop-code] [, QUIET = scalar-logical-expr] // R1161 error-stop-stmt -> // ERROR STOP [stop-code] [, QUIET = scalar-logical-expr] TYPE_CONTEXT_PARSER("STOP statement"_en_US, construct("STOP" >> pure(StopStmt::Kind::Stop) || "ERROR STOP"_sptok >> pure(StopStmt::Kind::ErrorStop), maybe(Parser{}), maybe(", QUIET =" >> scalarLogicalExpr))) // R1162 stop-code -> scalar-default-char-expr | scalar-int-expr // The two alternatives for stop-code can't be distinguished at // parse time. TYPE_PARSER(construct(scalar(expr))) // R1164 sync-all-stmt -> SYNC ALL [( [sync-stat-list] )] TYPE_CONTEXT_PARSER("SYNC ALL statement"_en_US, construct("SYNC ALL"_sptok >> defaulted(parenthesized(optionalList(statOrErrmsg))))) // R1166 sync-images-stmt -> SYNC IMAGES ( image-set [, sync-stat-list] ) // R1167 image-set -> int-expr | * TYPE_CONTEXT_PARSER("SYNC IMAGES statement"_en_US, "SYNC IMAGES"_sptok >> parenthesized(construct( construct(intExpr) || construct(star), defaulted("," >> nonemptyList(statOrErrmsg))))) // R1168 sync-memory-stmt -> SYNC MEMORY [( [sync-stat-list] )] TYPE_CONTEXT_PARSER("SYNC MEMORY statement"_en_US, construct("SYNC MEMORY"_sptok >> defaulted(parenthesized(optionalList(statOrErrmsg))))) // R1169 sync-team-stmt -> SYNC TEAM ( team-value [, sync-stat-list] ) TYPE_CONTEXT_PARSER("SYNC TEAM statement"_en_US, construct("SYNC TEAM"_sptok >> "("_tok >> teamValue, defaulted("," >> nonemptyList(statOrErrmsg)) / ")")) // R1170 event-post-stmt -> EVENT POST ( event-variable [, sync-stat-list] ) // R1171 event-variable -> scalar-variable TYPE_CONTEXT_PARSER("EVENT POST statement"_en_US, construct("EVENT POST"_sptok >> "("_tok >> scalar(variable), defaulted("," >> nonemptyList(statOrErrmsg)) / ")")) // R1172 event-wait-stmt -> // EVENT WAIT ( event-variable [, event-wait-spec-list] ) TYPE_CONTEXT_PARSER("EVENT WAIT statement"_en_US, construct("EVENT WAIT"_sptok >> "("_tok >> scalar(variable), defaulted("," >> nonemptyList(Parser{})) / ")")) // R1174 until-spec -> UNTIL_COUNT = scalar-int-expr constexpr auto untilSpec{"UNTIL_COUNT =" >> scalarIntExpr}; // R1173 event-wait-spec -> until-spec | sync-stat TYPE_PARSER(construct(untilSpec) || construct(statOrErrmsg)) // R1177 team-variable -> scalar-variable constexpr auto teamVariable{scalar(variable)}; // R1175 form-team-stmt -> // FORM TEAM ( team-number , team-variable [, form-team-spec-list] ) // R1176 team-number -> scalar-int-expr TYPE_CONTEXT_PARSER("FORM TEAM statement"_en_US, construct("FORM TEAM"_sptok >> "("_tok >> scalarIntExpr, "," >> teamVariable, defaulted("," >> nonemptyList(Parser{})) / ")")) // R1178 form-team-spec -> NEW_INDEX = scalar-int-expr | sync-stat TYPE_PARSER( construct("NEW_INDEX =" >> scalarIntExpr) || construct(statOrErrmsg)) // R1182 lock-variable -> scalar-variable constexpr auto lockVariable{scalar(variable)}; // R1179 lock-stmt -> LOCK ( lock-variable [, lock-stat-list] ) TYPE_CONTEXT_PARSER("LOCK statement"_en_US, construct("LOCK (" >> lockVariable, defaulted("," >> nonemptyList(Parser{})) / ")")) // R1180 lock-stat -> ACQUIRED_LOCK = scalar-logical-variable | sync-stat TYPE_PARSER( construct("ACQUIRED_LOCK =" >> scalarLogicalVariable) || construct(statOrErrmsg)) // R1181 unlock-stmt -> UNLOCK ( lock-variable [, sync-stat-list] ) TYPE_CONTEXT_PARSER("UNLOCK statement"_en_US, construct("UNLOCK (" >> lockVariable, defaulted("," >> nonemptyList(statOrErrmsg)) / ")")) } // namespace Fortran::parser