1 //===-- lib/Parser/stmt-parser.h --------------------------------*- C++ -*-===// 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 #ifndef FORTRAN_PARSER_STMT_PARSER_H_ 10 #define FORTRAN_PARSER_STMT_PARSER_H_ 11 12 // Basic parsing of statements. 13 14 #include "basic-parsers.h" 15 #include "token-parsers.h" 16 17 namespace Fortran::parser { 18 19 // statement(p) parses Statement<P> for some statement type P that is the 20 // result type of the argument parser p, while also handling labels and 21 // end-of-statement markers. 22 23 // R611 label -> digit [digit]... 24 constexpr auto label{space >> digitString64 / spaceCheck}; 25 26 template <typename PA> 27 inline constexpr auto unterminatedStatement(const PA &p) { 28 return skipStuffBeforeStatement >> 29 sourced(construct<Statement<typename PA::resultType>>( 30 maybe(label), space >> p)); 31 } 32 33 constexpr auto atEndOfStmt{space >> 34 withMessage("expected end of statement"_err_en_US, lookAhead(";\n"_ch))}; 35 constexpr auto checkEndOfKnownStmt{recovery(atEndOfStmt, SkipTo<'\n'>{})}; 36 37 constexpr auto endOfLine{ 38 "\n"_ch >> ok || fail("expected end of line"_err_en_US)}; 39 40 constexpr auto semicolons{";"_ch >> skipMany(";"_tok) / space / maybe("\n"_ch)}; 41 constexpr auto endOfStmt{ 42 space >> withMessage("expected end of statement"_err_en_US, 43 semicolons || endOfLine)}; 44 constexpr auto forceEndOfStmt{recovery(endOfStmt, SkipPast<'\n'>{})}; 45 46 template <typename PA> inline constexpr auto statement(const PA &p) { 47 return unterminatedStatement(p) / endOfStmt; 48 } 49 50 // unlabeledStatement() is basically statement() for those few situations 51 // in Fortran where a statement cannot have a label. 52 template <typename PA> inline constexpr auto unlabeledStatement(const PA &p) { 53 return space >> 54 sourced(construct<UnlabeledStatement<typename PA::resultType>>(p)); 55 } 56 57 // This unambiguousStatement() variant of statement() provides better error 58 // recovery for contexts containing statements that might have trailing 59 // garbage, but it must be used only when no instance of the statement in 60 // question could also be a legal prefix of some other statement that might 61 // be valid at that point. It only makes sense to use this within "some()" 62 // or "many()" so as to not end the list of statements. 63 template <typename PA> inline constexpr auto unambiguousStatement(const PA &p) { 64 return unterminatedStatement(p) / forceEndOfStmt; 65 } 66 67 constexpr auto ignoredStatementPrefix{ 68 skipStuffBeforeStatement >> maybe(label) >> maybe(name / ":") >> space}; 69 70 // Error recovery within a statement() call: skip *to* the end of the line, 71 // unless at an END or CONTAINS statement. 72 constexpr auto inStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> 73 SkipTo<'\n'>{} >> construct<ErrorRecovery>()}; 74 75 // Error recovery within statement sequences: skip *past* the end of the line, 76 // but not over an END or CONTAINS statement. 77 constexpr auto skipStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> 78 SkipPast<'\n'>{} >> construct<ErrorRecovery>()}; 79 80 // Error recovery across statements: skip the line, unless it looks 81 // like it might end the containing construct. 82 constexpr auto stmtErrorRecoveryStart{ignoredStatementPrefix}; 83 constexpr auto skipBadLine{SkipPast<'\n'>{} >> construct<ErrorRecovery>()}; 84 constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >> 85 !"END"_tok >> !"CONTAINS"_tok >> !"ELSE"_tok >> !"CASE"_tok >> 86 !"TYPE IS"_tok >> !"CLASS"_tok >> !"RANK"_tok >> 87 !("!$ACC "_sptok >> "END"_tok) >> 88 !("!$OMP "_sptok >> ("END"_tok || "SECTION"_id)) >> skipBadLine}; 89 90 // END statement error recovery 91 constexpr auto missingOptionalName{pure<std::optional<Name>>()}; 92 constexpr auto noNameEnd{"END" >> missingOptionalName}; 93 94 // For unrecognizable construct END statements. Be sure to not consume 95 // a program unit's END statement. 96 constexpr auto progUnitEndStmt{ 97 "END" >> (lookAhead("\n"_ch) || "SUBROUTINE"_tok || "FUNCTION"_tok || 98 "PROCEDURE"_tok || "MODULE"_tok || "SUBMODULE"_tok || 99 "PROGRAM"_tok || "BLOCK DATA"_tok)}; 100 constexpr auto constructEndStmtErrorRecovery{ 101 !progUnitEndStmt >> ("END"_tok >> SkipTo<'\n'>{} || ok)}; 102 constexpr auto namedConstructEndStmtErrorRecovery{ 103 constructEndStmtErrorRecovery >> missingOptionalName}; 104 105 constexpr auto progUnitEndStmtErrorRecovery{ 106 (many(!"END"_tok >> SkipPast<'\n'>{}) >> 107 ("END"_tok >> SkipTo<'\n'>{} || consumedAllInput)) >> 108 missingOptionalName}; 109 110 constexpr auto beginDirective{skipStuffBeforeStatement >> "!"_ch}; 111 constexpr auto endDirective{space >> endOfLine}; 112 113 } // namespace Fortran::parser 114 #endif // FORTRAN_PARSER_STMT_PARSER_H_ 115