From 1e1ea723c514371e30d95f6f79c02ef56d389069 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Mon, 2 Apr 2018 16:06:18 -0700 Subject: [PATCH] [flang] Better error recovery, some debugging. Original-commit: flang-compiler/f18@b7509f0e5be796e0b29a481215f3950c8276d76d Reviewed-on: https://github.com/flang-compiler/f18/pull/38 Tree-same-pre-rewrite: false --- flang/lib/parser/grammar.h | 45 ++++++++++++++++++++++++++------------------ flang/lib/parser/parsing.cc | 28 +++++++++++++-------------- flang/lib/parser/parsing.h | 2 +- flang/tools/f18/f18.cc | 4 ++-- flang/tools/f18/test-sema.cc | 5 +++-- flang/tools/f18/test-type.cc | 5 +++-- 6 files changed, 49 insertions(+), 40 deletions(-) diff --git a/flang/lib/parser/grammar.h b/flang/lib/parser/grammar.h index 57ab8c8..e3a91f4 100644 --- a/flang/lib/parser/grammar.h +++ b/flang/lib/parser/grammar.h @@ -176,7 +176,7 @@ template inline constexpr auto unterminatedStatement(const PA &p) { } constexpr auto endOfLine = "\n"_ch / skipEmptyLines || - fail("expected end of line"_en_US); + fail("expected end of line"_err_en_US); constexpr auto endOfStmt = space >> (";"_ch / skipMany(";"_tok) / maybe(endOfLine) || endOfLine); @@ -558,7 +558,7 @@ constexpr auto executableConstruct = constexpr auto obsoleteExecutionPartConstruct = recovery( ignoredStatementPrefix >> fail( - "obsolete legacy extension is not supported"_en_US), + "obsolete legacy extension is not supported"_err_en_US), construct{}( statement("REDIMENSION" >> name >> parenthesized(nonemptyList(Parser{})) >> ok) >> @@ -872,7 +872,11 @@ TYPE_PARSER(construct{}(Parser{}) || construct{}(Parser{})) // R730 end-type-stmt -> END TYPE [type-name] -TYPE_PARSER("END TYPE" >> construct{}(maybe(name))) +constexpr auto noNameEnd = "END" >> defaulted(cut >> maybe(name)); +constexpr auto bareEnd = noNameEnd / lookAhead(endOfStmt); +constexpr auto endStmtErrorRecovery = noNameEnd / SkipTo<'\n'>{}; +TYPE_PARSER(construct{}( + recovery("END TYPE" >> maybe(name), endStmtErrorRecovery))) // R731 sequence-stmt -> SEQUENCE TYPE_PARSER("SEQUENCE" >> construct{}) @@ -1070,7 +1074,8 @@ TYPE_PARSER( construct{}(namedConstant, maybe("=" >> scalarIntConstantExpr))) // R763 end-enum-stmt -> END ENUM -TYPE_PARSER("END ENUM" >> construct{}) +TYPE_PARSER(recovery("END ENUM"_tok, "END" >> SkipTo<'\n'>{}) >> + construct{}) // R764 boz-literal-constant -> binary-constant | octal-constant | hex-constant // R765 binary-constant -> B ' digit [digit]... ' | B " digit [digit]... " @@ -3237,9 +3242,9 @@ TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US, "PROGRAM" >> name / maybe(extension(parenthesized(ok))))) // R1403 end-program-stmt -> END [PROGRAM [program-name]] -constexpr auto bareEnd = "END" >> defaulted(cut >> maybe(name)); TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US, - construct{}("END PROGRAM" >> maybe(name) || bareEnd)) + construct{}(recovery( + "END PROGRAM" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1404 module -> // module-stmt [specification-part] [module-subprogram-part] @@ -3255,7 +3260,8 @@ TYPE_CONTEXT_PARSER( // R1406 end-module-stmt -> END [MODULE [module-name]] TYPE_CONTEXT_PARSER("END MODULE statement"_en_US, - construct{}("END MODULE" >> maybe(name) || bareEnd)) + construct{}( + recovery("END MODULE" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1407 module-subprogram-part -> contains-stmt [module-subprogram]... TYPE_CONTEXT_PARSER("module subprogram part"_en_US, @@ -3303,19 +3309,20 @@ TYPE_PARSER(construct{}(Parser{}) || TYPE_CONTEXT_PARSER("submodule"_en_US, construct{}(statement(Parser{}), specificationPart, maybe(Parser{}), - statement(Parser{}))) + unterminatedStatement(Parser{}))) // R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US, - "SUBMODULE" >> construct{}( - parenthesized(Parser{}), name)) + 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{}("END SUBMODULE" >> maybe(name) || bareEnd)) + construct{}(recovery( + "END SUBMODULE" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt TYPE_CONTEXT_PARSER("BLOCK DATA subprogram"_en_US, @@ -3328,7 +3335,8 @@ TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US, // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]] TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US, - construct{}("END BLOCK DATA" >> maybe(name) || bareEnd)) + construct{}(recovery( + "END BLOCK DATA" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1501 interface-block -> // interface-stmt [interface-specification]... end-interface-stmt @@ -3461,7 +3469,7 @@ std::optional Parser::Parse( return {FunctionReference{std::move(call.value())}}; } } - state->PutMessage("expected (arguments)"_en_US); + state->Say("expected (arguments)"_err_en_US); } state->PopContext(); return {}; @@ -3554,8 +3562,8 @@ TYPE_PARSER(construct{}( "RESULT" >> parenthesized(name), maybe(languageBindingSpec))) // R1533 end-function-stmt -> END [FUNCTION [function-name]] -TYPE_PARSER( - construct{}("END FUNCTION" >> maybe(name) || bareEnd)) +TYPE_PARSER(construct{}( + recovery("END FUNCTION" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1534 subroutine-subprogram -> // subroutine-stmt [specification-part] [execution-part] @@ -3579,8 +3587,8 @@ TYPE_PARSER( TYPE_PARSER(construct{}(name) || construct{}(star)) // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]] -TYPE_PARSER( - construct{}("END SUBROUTINE" >> maybe(name) || bareEnd)) +TYPE_PARSER(construct{}( + recovery("END SUBROUTINE" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1538 separate-module-subprogram -> // mp-subprogram-stmt [specification-part] [execution-part] @@ -3596,7 +3604,8 @@ TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US, // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]] TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US, - construct{}("END PROCEDURE" >> maybe(name) || bareEnd)) + construct{}(recovery( + "END PROCEDURE" >> maybe(name) || bareEnd, endStmtErrorRecovery))) // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]] TYPE_PARSER("ENTRY" >> diff --git a/flang/lib/parser/parsing.cc b/flang/lib/parser/parsing.cc index 71ff71f..2ce013f 100644 --- a/flang/lib/parser/parsing.cc +++ b/flang/lib/parser/parsing.cc @@ -80,27 +80,25 @@ void Parsing::Parse() { messages_.Annex(parseState.messages()); } -std::optional Parsing::ForTesting( - std::string path, std::ostream &err) { - Parsing parsing; - parsing.Prescan(path, Options{}); - if (parsing.messages().AnyFatalError()) { - parsing.messages().Emit(err); +bool Parsing::ForTesting(std::string path, std::ostream &err) { + Prescan(path, Options{}); + if (messages_.AnyFatalError()) { + messages_.Emit(err); err << "could not scan " << path << '\n'; - return {}; + return false; } - parsing.Parse(); - parsing.messages().Emit(err); - if (!parsing.consumedWholeFile()) { + Parse(); + messages_.Emit(err); + if (!consumedWholeFile_) { err << "f18 parser FAIL; final position: "; - parsing.Identify(err, parsing.finalRestingPlace(), " "); - return {}; + Identify(err, finalRestingPlace_, " "); + return false; } - if (parsing.messages().AnyFatalError()) { + if (messages_.AnyFatalError() || !parseTree_.has_value()) { err << "could not parse " << path << '\n'; - return {}; + return false; } - return std::move(parsing.parseTree()); + return true; } } // namespace parser } // namespace Fortran diff --git a/flang/lib/parser/parsing.h b/flang/lib/parser/parsing.h index 655d461..ed32613 100644 --- a/flang/lib/parser/parsing.h +++ b/flang/lib/parser/parsing.h @@ -49,7 +49,7 @@ public: o, cooked_.GetProvenance(at).start(), prefix, echoSourceLine); } - static std::optional ForTesting(std::string path, std::ostream &); + bool ForTesting(std::string path, std::ostream &); private: Options options_; diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index 1a7bc32..2089443 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -163,8 +163,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options, parsing.Identify(std::cerr, parsing.finalRestingPlace(), " "); exit(EXIT_FAILURE); } - if (!parsing.messages().empty() && - (driver.warningsAreErrors || parsing.messages().AnyFatalError()) || + if ((!parsing.messages().empty() && + (driver.warningsAreErrors || parsing.messages().AnyFatalError())) || !parsing.parseTree().has_value()) { std::cerr << driver.prefix << "could not parse " << path << '\n'; exit(EXIT_FAILURE); diff --git a/flang/tools/f18/test-sema.cc b/flang/tools/f18/test-sema.cc index 38c98bf..1ec522a 100644 --- a/flang/tools/f18/test-sema.cc +++ b/flang/tools/f18/test-sema.cc @@ -22,8 +22,9 @@ int main(int argc, char *const argv[]) { return EXIT_FAILURE; } std::string path{argv[1]}; - if (std::optional parseTree{Parsing::ForTesting(path, std::cerr)}) { - DoSemanticAnalysis(parsing.messages().cooked(), *parseTree); + Parsing parsing; + if (parsing.ForTesting(path, std::cerr)) { + DoSemanticAnalysis(parsing.messages().cooked(), *parsing.parseTree()); return EXIT_SUCCESS; } return EXIT_FAILURE; diff --git a/flang/tools/f18/test-type.cc b/flang/tools/f18/test-type.cc index c584618..6dfd8bc 100644 --- a/flang/tools/f18/test-type.cc +++ b/flang/tools/f18/test-type.cc @@ -15,8 +15,9 @@ int main(int argc, char *const argv[]) { return EXIT_FAILURE; } std::string path{argv[1]}; - if (std::optional parseTree{Parsing::ForTesting(path, std::cerr)}) { - semantics::MakeTypes(std::cout, *parseTree); + Parsing parsing; + if (parsing.ForTesting(path, std::cerr)) { + semantics::MakeTypes(std::cout, *parsing.parseTree()); return EXIT_SUCCESS; } return EXIT_FAILURE; -- 2.7.4