[flang] Fix parsing error on PROCEDURE statement in derived type definition.

Improve error recovery in that context.

Original-commit: flang-compiler/f18@b9e48504e6
Reviewed-on: https://github.com/flang-compiler/f18/pull/21
This commit is contained in:
peter klausler 2018-03-01 11:28:13 -08:00
parent a4a355940c
commit 1b0705ca0f
6 changed files with 56 additions and 20 deletions

View File

@ -78,6 +78,9 @@ They are `constexpr`, so they should be viewed as type-safe macros.
* `deprecated(p)` parses p if strict standard compliance is disabled,
with a warning if deprecated usage warnings are enabled.
* `inContext(..., p)` runs p within an error message context.
* `recovery(p, q)` is equivalent to `p || q`, except that error messages
generated from the first parser are retained, and a flag is set in
the ParseState to remember that error recovery was necessary.
Note that
```

View File

@ -193,6 +193,20 @@ template<typename PA> inline constexpr auto statement(const PA &p) {
return unterminatedStatement(p) / endOfStmt;
}
// Error recovery within statements: skip to the end of the line,
// but not over an END or CONTAINS statement.
constexpr auto skipToEndOfLine = SkipTo<'\n'>{} >> construct<ErrorRecovery>{};
constexpr auto stmtErrorRecovery =
!"END"_tok >> !"CONTAINS"_tok >> skipToEndOfLine;
// Error recovery across statements: skip the line, unless it looks
// like it might end the containing construct.
constexpr auto errorRecoveryStart = skipMany("\n"_tok) >> maybe(label);
constexpr auto skipBadLine = SkipPast<'\n'>{} >> construct<ErrorRecovery>{};
constexpr auto executionPartErrorRecovery = errorRecoveryStart >> !"END"_tok >>
!"ELSE"_tok >> !"CONTAINS"_tok >> !"CASE"_tok >> !"TYPE IS"_tok >>
!"CLASS"_tok >> !"RANK"_tok >> skipBadLine;
// R507 declaration-construct ->
// specification-construct | data-stmt | format-stmt |
// entry-stmt | stmt-function-stmt
@ -536,11 +550,6 @@ constexpr auto executableConstruct =
construct<ExecutableConstruct>{}(indirect(whereConstruct)) ||
construct<ExecutableConstruct>{}(indirect(forallConstruct));
constexpr auto executionPartErrorRecovery = skipMany("\n"_tok) >>
maybe(label) >> !"END"_tok >> !"ELSE"_tok >> !"CONTAINS"_tok >>
!"CASE"_tok >> !"TYPE IS"_tok >> !"CLASS"_tok >>
!"RANK"_tok >> SkipPast<'\n'>{} >> construct<ErrorRecovery>{};
// R510 execution-part-construct ->
// executable-construct | format-stmt | entry-stmt | data-stmt
// Extension (PGI/Intel): also accept NAMELIST in execution part
@ -903,14 +912,13 @@ TYPE_PARSER(
construct<TypeParamDecl>{}(name, maybe("=" >> scalarIntConstantExpr)))
// R736 component-def-stmt -> data-component-def-stmt |
// proc-component-def-stmt
TYPE_PARSER(construct<ComponentDefStmt>{}(Parser<DataComponentDefStmt>{}) ||
construct<ComponentDefStmt>{}(Parser<ProcComponentDefStmt>{})
// Accidental extension: PGI accepts type-param-def-stmt in
// component-part of derived-type-def. Not enabled here.
// ||
// extension(construct<ComponentDefStmt>{}(Parser<TypeParamDefStmt>{})
)
// proc-component-def-stmt
// Accidental extension not enabled here: PGI accepts type-param-def-stmt in
// component-part of derived-type-def.
TYPE_PARSER(
recovery(construct<ComponentDefStmt>{}(Parser<DataComponentDefStmt>{}) ||
construct<ComponentDefStmt>{}(Parser<ProcComponentDefStmt>{}),
construct<ComponentDefStmt>{}(stmtErrorRecovery)))
// R737 data-component-def-stmt ->
// declaration-type-spec [[, component-attr-spec-list] ::]
@ -996,10 +1004,11 @@ TYPE_CONTEXT_PARSER("type bound procedure part"_en_US,
// R748 type-bound-proc-binding ->
// type-bound-procedure-stmt | type-bound-generic-stmt |
// final-procedure-stmt
TYPE_PARSER(
TYPE_PARSER(recovery(
construct<TypeBoundProcBinding>{}(Parser<TypeBoundProcedureStmt>{}) ||
construct<TypeBoundProcBinding>{}(Parser<TypeBoundGenericStmt>{}) ||
construct<TypeBoundProcBinding>{}(Parser<FinalProcedureStmt>{}))
construct<TypeBoundProcBinding>{}(Parser<TypeBoundGenericStmt>{}) ||
construct<TypeBoundProcBinding>{}(Parser<FinalProcedureStmt>{}),
construct<TypeBoundProcBinding>{}(stmtErrorRecovery)))
// R749 type-bound-procedure-stmt ->
// PROCEDURE [[, bind-attr-list] ::] type-bound-proc-decl-list |
@ -3384,8 +3393,8 @@ TYPE_PARSER("PROCEDURE" >>
// R1513 proc-interface -> interface-name | declaration-type-spec
// R1516 interface-name -> name
TYPE_PARSER(construct<ProcInterface>{}(name) ||
construct<ProcInterface>{}(declarationTypeSpec))
TYPE_PARSER(construct<ProcInterface>{}(declarationTypeSpec) ||
construct<ProcInterface>{}(name))
// R1514 proc-attr-spec ->
// access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |

View File

@ -154,6 +154,13 @@ public:
return {ch};
}
std::optional<char> PeekAtNextChar() {
if (p_ >= limit_) {
return {};
}
return {*p_};
}
private:
// Text remaining to be parsed
const CookedSource &cooked_;

View File

@ -973,7 +973,7 @@ struct ProcComponentDefStmt {
// R736 component-def-stmt -> data-component-def-stmt | proc-component-def-stmt
struct ComponentDefStmt {
UNION_CLASS_BOILERPLATE(ComponentDefStmt);
std::variant<DataComponentDefStmt, ProcComponentDefStmt
std::variant<DataComponentDefStmt, ProcComponentDefStmt, ErrorRecovery
// , TypeParamDefStmt -- PGI accidental extension, not enabled
>
u;
@ -1036,7 +1036,8 @@ WRAPPER_CLASS(FinalProcedureStmt, std::list<Name>);
// final-procedure-stmt
struct TypeBoundProcBinding {
UNION_CLASS_BOILERPLATE(TypeBoundProcBinding);
std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt>
std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt,
ErrorRecovery>
u;
};

View File

@ -404,6 +404,21 @@ template<char goal> struct SkipPast {
}
};
template<char goal> struct SkipTo {
using resultType = Success;
constexpr SkipTo() {}
constexpr SkipTo(const SkipTo &) {}
static std::optional<Success> Parse(ParseState *state) {
while (std::optional<char> ch{state->PeekAtNextChar()}) {
if (*ch == goal) {
return {Success{}};
}
state->GetNextChar();
}
return {};
}
};
// A common idiom in the Fortran grammar is an optional item (usually
// a nonempty comma-separated list) that, if present, must follow a comma
// and precede a doubled colon. When the item is absent, the comma must

View File

@ -236,6 +236,7 @@ static void visitDerivedTypeDef(const DerivedTypeDef &dtd) {
[&](const ProcComponentDefStmt &x) {
TODO("ProcComponentDefStmt");
},
[&](const ErrorRecovery &) {},
},
cds.statement.u);
}