[flang] Add explanatory messages to grammar for language extensions

Extend "extension<LanguageFeature>()" to incorporate an explanatory
message better than the current generic "nonstandard usage:".

Differential Revision: https://reviews.llvm.org/D122035
This commit is contained in:
Peter Klausler 2022-03-14 15:23:49 -07:00
parent ddca66622c
commit 2d8b6a4784
7 changed files with 128 additions and 63 deletions

View File

@ -65,13 +65,16 @@ constexpr auto namedIntrinsicOperator{
".EQV." >> pure(DefinedOperator::IntrinsicOperator::EQV) ||
".NEQV." >> pure(DefinedOperator::IntrinsicOperator::NEQV) ||
extension<LanguageFeature::XOROperator>(
"nonstandard usage: .XOR. spelling of .NEQV."_port_en_US,
".XOR." >> pure(DefinedOperator::IntrinsicOperator::NEQV)) ||
extension<LanguageFeature::LogicalAbbreviations>(
"nonstandard usage: abbreviated logical operator"_port_en_US,
".N." >> pure(DefinedOperator::IntrinsicOperator::NOT) ||
".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
extension<LanguageFeature::XOROperator>(
".X." >> pure(DefinedOperator::IntrinsicOperator::NEQV)))};
".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
extension<LanguageFeature::XOROperator>(
"nonstandard usage: .X. spelling of .NEQV."_port_en_US,
".X." >> pure(DefinedOperator::IntrinsicOperator::NEQV)))};
constexpr auto intrinsicOperator{
"**" >> pure(DefinedOperator::IntrinsicOperator::Power) ||
@ -83,6 +86,7 @@ constexpr auto intrinsicOperator{
"-" >> pure(DefinedOperator::IntrinsicOperator::Subtract) ||
"<=" >> pure(DefinedOperator::IntrinsicOperator::LE) ||
extension<LanguageFeature::AlternativeNE>(
"nonstandard usage: <> spelling of /= or .NE."_port_en_US,
"<>" >> pure(DefinedOperator::IntrinsicOperator::NE)) ||
"<" >> pure(DefinedOperator::IntrinsicOperator::LT) ||
"==" >> pure(DefinedOperator::IntrinsicOperator::EQ) ||
@ -178,6 +182,7 @@ TYPE_CONTEXT_PARSER("declaration type spec"_en_US,
construct<DeclarationTypeSpec>("*" >>
construct<DeclarationTypeSpec::ClassStar>())) ||
extension<LanguageFeature::DECStructures>(
"nonstandard usage: STRUCTURE"_port_en_US,
construct<DeclarationTypeSpec>(
// As is also done for the STRUCTURE statement, the name of
// the structure includes the surrounding slashes to avoid
@ -202,9 +207,11 @@ TYPE_CONTEXT_PARSER("intrinsic type spec"_en_US,
"CHARACTER" >> maybe(Parser<CharSelector>{}))),
construct<IntrinsicTypeSpec>(construct<IntrinsicTypeSpec::Logical>(
"LOGICAL" >> maybe(kindSelector))),
extension<LanguageFeature::DoubleComplex>(construct<IntrinsicTypeSpec>(
"DOUBLE COMPLEX" >> construct<IntrinsicTypeSpec::DoubleComplex>())),
extension<LanguageFeature::Byte>(
extension<LanguageFeature::DoubleComplex>(
"nonstandard usage: DOUBLE COMPLEX"_port_en_US,
construct<IntrinsicTypeSpec>("DOUBLE COMPLEX" >>
construct<IntrinsicTypeSpec::DoubleComplex>())),
extension<LanguageFeature::Byte>("nonstandard usage: BYTE"_port_en_US,
construct<IntrinsicTypeSpec>(construct<IntegerTypeSpec>(
"BYTE" >> construct<std::optional<KindSelector>>(pure(1)))))))
@ -215,8 +222,10 @@ TYPE_PARSER(construct<IntegerTypeSpec>("INTEGER" >> maybe(kindSelector)))
// Legacy extension: kind-selector -> * digit-string
TYPE_PARSER(construct<KindSelector>(
parenthesized(maybe("KIND ="_tok) >> scalarIntConstantExpr)) ||
extension<LanguageFeature::StarKind>(construct<KindSelector>(
construct<KindSelector::StarSize>("*" >> digitString64 / spaceCheck))))
extension<LanguageFeature::StarKind>(
"nonstandard usage: TYPE*KIND syntax"_port_en_US,
construct<KindSelector>(construct<KindSelector::StarSize>(
"*" >> digitString64 / spaceCheck))))
// R707 signed-int-literal-constant -> [sign] int-literal-constant
TYPE_PARSER(sourced(construct<SignedIntLiteralConstant>(
@ -251,7 +260,9 @@ constexpr auto signedRealLiteralConstant{
// Extension: Q
// R717 exponent -> signed-digit-string
constexpr auto exponentPart{
("ed"_ch || extension<LanguageFeature::QuadPrecision>("q"_ch)) >>
("ed"_ch ||
extension<LanguageFeature::QuadPrecision>(
"nonstandard usage: Q exponent"_port_en_US, "q"_ch)) >>
SignedDigitString{}};
TYPE_CONTEXT_PARSER("REAL literal constant"_en_US,
@ -431,6 +442,7 @@ TYPE_CONTEXT_PARSER("component declaration"_en_US,
// The source field of the Name will be replaced with a distinct generated name.
TYPE_CONTEXT_PARSER("%FILL item"_en_US,
extension<LanguageFeature::DECStructures>(
"nonstandard usage: %FILL"_port_en_US,
construct<FillDecl>(space >> sourced("%FILL" >> construct<Name>()),
maybe(Parser<ComponentArraySpec>{}), maybe("*" >> charLength))))
TYPE_PARSER(construct<ComponentOrFill>(Parser<ComponentDecl>{}) ||
@ -475,10 +487,12 @@ constexpr auto initialDataTarget{indirect(designator)};
TYPE_PARSER(construct<Initialization>("=>" >> nullInit) ||
construct<Initialization>("=>" >> initialDataTarget) ||
construct<Initialization>("=" >> constantExpr) ||
extension<LanguageFeature::SlashInitialization>(construct<Initialization>(
"/" >> nonemptyList("expected values"_err_en_US,
indirect(Parser<DataStmtValue>{})) /
"/")))
extension<LanguageFeature::SlashInitialization>(
"nonstandard usage: /initialization/"_port_en_US,
construct<Initialization>(
"/" >> nonemptyList("expected values"_err_en_US,
indirect(Parser<DataStmtValue>{})) /
"/")))
// R745 private-components-stmt -> PRIVATE
// R747 binding-private-stmt -> PRIVATE
@ -608,10 +622,12 @@ TYPE_PARSER(
nonemptyList("expected entity declarations"_err_en_US,
entityDeclWithoutEqInit)) ||
// PGI-only extension: comma in place of doubled colons
extension<LanguageFeature::MissingColons>(construct<TypeDeclarationStmt>(
declarationTypeSpec, defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
withMessage("expected entity declarations"_err_en_US,
"," >> nonemptyList(entityDecl)))))
extension<LanguageFeature::MissingColons>(
"nonstandard usage: ',' in place of '::'"_port_en_US,
construct<TypeDeclarationStmt>(declarationTypeSpec,
defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
withMessage("expected entity declarations"_err_en_US,
"," >> nonemptyList(entityDecl)))))
// R802 attr-spec ->
// access-spec | ALLOCATABLE | ASYNCHRONOUS |
@ -841,6 +857,7 @@ TYPE_PARSER(sourced(first(construct<DataStmtConstant>(literalConstant),
construct<DataStmtConstant>(signedRealLiteralConstant),
construct<DataStmtConstant>(signedIntLiteralConstant),
extension<LanguageFeature::SignedComplexLiteral>(
"nonstandard usage: signed COMPLEX literal"_port_en_US,
construct<DataStmtConstant>(Parser<SignedComplexLiteralConstant>{})),
construct<DataStmtConstant>(nullInit),
construct<DataStmtConstant>(indirect(designator) / !"("_tok),
@ -869,8 +886,10 @@ TYPE_CONTEXT_PARSER("PARAMETER statement"_en_US,
construct<ParameterStmt>(
"PARAMETER" >> parenthesized(nonemptyList(Parser<NamedConstantDef>{}))))
TYPE_CONTEXT_PARSER("old style PARAMETER statement"_en_US,
extension<LanguageFeature::OldStyleParameter>(construct<OldParameterStmt>(
"PARAMETER" >> nonemptyList(Parser<NamedConstantDef>{}))))
extension<LanguageFeature::OldStyleParameter>(
"nonstandard usage: PARAMETER without parentheses"_port_en_US,
construct<OldParameterStmt>(
"PARAMETER" >> nonemptyList(Parser<NamedConstantDef>{}))))
// R852 named-constant-def -> named-constant = constant-expr
TYPE_PARSER(construct<NamedConstantDef>(namedConstant, "=" >> constantExpr))
@ -1024,6 +1043,7 @@ TYPE_CONTEXT_PARSER("designator"_en_US,
constexpr auto percentOrDot{"%"_tok ||
// legacy VAX extension for RECORD field access
extension<LanguageFeature::DECStructures>(
"nonstandard usage: component access with '.' in place of '%'"_port_en_US,
"."_tok / lookAhead(OldStructureComponentName{}))};
// R902 variable -> designator | function-reference
@ -1184,10 +1204,12 @@ TYPE_PARSER(beginDirective >>
maybe(("="_tok || ":"_tok) >> digitString64))))) /
endDirective)
TYPE_PARSER(extension<LanguageFeature::CrayPointer>(construct<BasedPointerStmt>(
"POINTER" >> nonemptyList("expected POINTER associations"_err_en_US,
construct<BasedPointer>("(" >> objectName / ",",
objectName, maybe(Parser<ArraySpec>{}) / ")")))))
TYPE_PARSER(extension<LanguageFeature::CrayPointer>(
"nonstandard usage: based POINTER"_port_en_US,
construct<BasedPointerStmt>(
"POINTER" >> nonemptyList("expected POINTER associations"_err_en_US,
construct<BasedPointer>("(" >> objectName / ",",
objectName, maybe(Parser<ArraySpec>{}) / ")")))))
// Subtle: the name includes the surrounding slashes, which avoids
// clashes with other uses of the name in the same scope.
@ -1206,10 +1228,12 @@ TYPE_PARSER(construct<StructureField>(statement(StructureComponents{})) ||
construct<StructureField>(indirect(nestedStructureDef)))
TYPE_CONTEXT_PARSER("STRUCTURE definition"_en_US,
extension<LanguageFeature::DECStructures>(construct<StructureDef>(
statement(Parser<StructureStmt>{}), many(Parser<StructureField>{}),
statement(
construct<StructureDef::EndStructureStmt>("END STRUCTURE"_tok)))))
extension<LanguageFeature::DECStructures>(
"nonstandard usage: STRUCTURE"_port_en_US,
construct<StructureDef>(statement(Parser<StructureStmt>{}),
many(Parser<StructureField>{}),
statement(construct<StructureDef::EndStructureStmt>(
"END STRUCTURE"_tok)))))
TYPE_CONTEXT_PARSER("UNION definition"_en_US,
construct<Union>(statement(construct<Union::UnionStmt>("UNION"_tok)),

View File

@ -845,7 +845,8 @@ template <LanguageFeature LF, typename PA> class NonstandardParser {
public:
using resultType = typename PA::resultType;
constexpr NonstandardParser(const NonstandardParser &) = default;
constexpr NonstandardParser(PA parser) : parser_{parser} {}
constexpr NonstandardParser(PA parser, MessageFixedText msg)
: parser_{parser}, message_{msg} {}
std::optional<resultType> Parse(ParseState &state) const {
if (UserState * ustate{state.userState()}) {
if (!ustate->features().IsEnabled(LF)) {
@ -855,19 +856,20 @@ public:
auto at{state.GetLocation()};
auto result{parser_.Parse(state)};
if (result) {
state.Nonstandard(CharBlock{at, std::max(state.GetLocation(), at + 1)},
LF, "nonstandard usage"_port_en_US);
state.Nonstandard(
CharBlock{at, std::max(state.GetLocation(), at + 1)}, LF, message_);
}
return result;
}
private:
const PA parser_;
const MessageFixedText message_;
};
template <LanguageFeature LF, typename PA>
inline constexpr auto extension(PA parser) {
return NonstandardParser<LF, PA>(parser);
inline constexpr auto extension(MessageFixedText feature, PA parser) {
return NonstandardParser<LF, PA>(parser, feature);
}
// If a is a parser for some deprecated or deleted language feature LF,

View File

@ -76,6 +76,7 @@ TYPE_PARSER(recovery(
construct<ExecutionPartConstruct>(
statement(indirect(dataStmt))),
extension<LanguageFeature::ExecutionPartNamelist>(
"nonstandard usage: NAMELIST in execution part"_port_en_US,
construct<ExecutionPartConstruct>(
statement(indirect(Parser<NamelistStmt>{})))),
obsoleteExecutionPartConstruct))),

View File

@ -44,6 +44,7 @@ TYPE_PARSER(construct<AcSpec>(maybe(typeSpec / "::"),
TYPE_PARSER(
// PGI/Intel extension: accept triplets in array constructors
extension<LanguageFeature::TripletInArrayConstructor>(
"nonstandard usage: triplet in array constructor"_port_en_US,
construct<AcValue>(construct<AcValue::Triplet>(scalarIntExpr,
":" >> scalarIntExpr, maybe(":" >> scalarIntExpr)))) ||
construct<AcValue>(indirect(expr)) ||
@ -76,10 +77,13 @@ constexpr auto primary{instrumented("primary"_en_US,
construct<Expr>(Parser<ArrayConstructor>{}),
// PGI/XLF extension: COMPLEX constructor (x,y)
extension<LanguageFeature::ComplexConstructor>(
"nonstandard usage: generalized COMPLEX constructor"_port_en_US,
construct<Expr>(parenthesized(
construct<Expr::ComplexConstructor>(expr, "," >> expr)))),
extension<LanguageFeature::PercentLOC>(construct<Expr>("%LOC" >>
parenthesized(construct<Expr::PercentLoc>(indirect(variable)))))))};
extension<LanguageFeature::PercentLOC>(
"nonstandard usage: %LOC"_port_en_US,
construct<Expr>("%LOC" >> parenthesized(construct<Expr::PercentLoc>(
indirect(variable)))))))};
// R1002 level-1-expr -> [defined-unary-op] primary
// TODO: Reasonable extension: permit multiple defined-unary-ops
@ -87,8 +91,10 @@ constexpr auto level1Expr{sourced(
first(primary, // must come before define op to resolve .TRUE._8 ambiguity
construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)),
extension<LanguageFeature::SignedPrimary>(
"nonstandard usage: signed primary"_port_en_US,
construct<Expr>(construct<Expr::UnaryPlus>("+" >> primary))),
extension<LanguageFeature::SignedPrimary>(
"nonstandard usage: signed primary"_port_en_US,
construct<Expr>(construct<Expr::Negate>("-" >> primary)))))};
// R1004 mult-operand -> level-1-expr [power-op mult-operand]
@ -244,6 +250,7 @@ struct Level4Expr {
(".EQ."_tok || "=="_tok) >> applyLambda(eq, level3Expr) ||
(".NE."_tok || "/="_tok ||
extension<LanguageFeature::AlternativeNE>(
"nonstandard usage: <> for /= or .NE."_port_en_US,
"<>"_tok /* PGI/Cray extension; Cray also has .LG. */)) >>
applyLambda(ne, level3Expr) ||
(".GE."_tok || ">="_tok) >> applyLambda(ge, level3Expr) ||
@ -273,6 +280,7 @@ constexpr AndOperand andOperand;
inline constexpr auto logicalOp(const char *op, const char *abbrev) {
return TokenStringMatch{op} ||
extension<LanguageFeature::LogicalAbbreviations>(
"nonstandard usage: abbreviated LOGICAL operator"_port_en_US,
TokenStringMatch{abbrev});
}
@ -356,6 +364,7 @@ struct Level5Expr {
auto more{attempt(sourced(".EQV." >> applyLambda(eqv, equivOperand) ||
(".NEQV."_tok ||
extension<LanguageFeature::XOROperator>(
"nonstandard usage: .XOR./.X. spelling of .NEQV."_port_en_US,
logicalOp(".XOR.", ".X."))) >>
applyLambda(neqv, equivOperand)))};
while (std::optional<Expr> next{more.Parse(state)}) {
@ -397,8 +406,10 @@ template <> std::optional<Expr> Parser<Expr>::Parse(ParseState &state) {
// and intrinsic operator names; this is handled by attempting their parses
// first, and by name resolution on their definitions, for best errors.
// N.B. The name of the operator is captured with the dots around it.
constexpr auto definedOpNameChar{
letter || extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
constexpr auto definedOpNameChar{letter ||
extension<LanguageFeature::PunctuationInNames>(
"nonstandard usage: non-alphabetic character in defined operator"_port_en_US,
"$@"_ch)};
TYPE_PARSER(
space >> construct<DefinedOpName>(sourced("."_ch >>
some(definedOpNameChar) >> construct<Name>() / "."_ch)))

View File

@ -85,6 +85,7 @@ TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
construct<ConnectSpec>("ERR =" >> errLabel),
construct<ConnectSpec>("FILE =" >> fileNameExpr),
extension<LanguageFeature::FileName>(
"nonstandard usage: NAME= in place of FILE="_port_en_US,
construct<ConnectSpec>("NAME =" >> fileNameExpr)),
construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
"FORM =" >> pure(ConnectSpec::CharExpr::Kind::Form),
@ -108,15 +109,19 @@ TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
"SIGN =" >> pure(ConnectSpec::CharExpr::Kind::Sign),
scalarDefaultCharExpr)),
construct<ConnectSpec>("STATUS =" >> statusExpr),
extension<LanguageFeature::Carriagecontrol>(construct<ConnectSpec>(
construct<ConnectSpec::CharExpr>("CARRIAGECONTROL =" >>
pure(ConnectSpec::CharExpr::Kind::Carriagecontrol),
scalarDefaultCharExpr))),
extension<LanguageFeature::Carriagecontrol>(
"nonstandard usage: CARRIAGECONTROL="_port_en_US,
construct<ConnectSpec>(
construct<ConnectSpec::CharExpr>("CARRIAGECONTROL =" >>
pure(ConnectSpec::CharExpr::Kind::Carriagecontrol),
scalarDefaultCharExpr))),
extension<LanguageFeature::Convert>(
"nonstandard usage: CONVERT="_port_en_US,
construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
"CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert),
scalarDefaultCharExpr))),
extension<LanguageFeature::Dispose>(
"nonstandard usage: DISPOSE="_port_en_US,
construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
"DISPOSE =" >> pure(ConnectSpec::CharExpr::Kind::Dispose),
scalarDefaultCharExpr)))))
@ -145,6 +150,7 @@ TYPE_CONTEXT_PARSER("CLOSE statement"_en_US,
// rewriting in semantics when we know that CVAR is character.
constexpr auto inputItemList{
extension<LanguageFeature::IOListLeadingComma>(
"nonstandard usage: leading comma in input item list"_port_en_US,
some("," >> inputItem)) || // legacy extension: leading comma
optionalList(inputItem)};
@ -226,6 +232,7 @@ TYPE_PARSER(first(construct<IoControlSpec>("UNIT =" >> ioUnit),
// R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
constexpr auto outputItemList{
extension<LanguageFeature::IOListLeadingComma>(
"nonstandard usage: leading comma in output item list"_port_en_US,
some("," >> outputItem)) || // legacy: allow leading comma
optionalList(outputItem)};
@ -486,18 +493,23 @@ TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Write),
scalarDefaultCharVariable)),
extension<LanguageFeature::Carriagecontrol>(
"nonstandard usage: CARRIAGECONTROL="_port_en_US,
construct<InquireSpec>("CARRIAGECONTROL =" >>
construct<InquireSpec::CharVar>(
pure(InquireSpec::CharVar::Kind::Carriagecontrol),
scalarDefaultCharVariable))),
extension<LanguageFeature::Convert>(construct<InquireSpec>(
"CONVERT =" >> construct<InquireSpec::CharVar>(
pure(InquireSpec::CharVar::Kind::Convert),
scalarDefaultCharVariable))),
extension<LanguageFeature::Dispose>(construct<InquireSpec>(
"DISPOSE =" >> construct<InquireSpec::CharVar>(
pure(InquireSpec::CharVar::Kind::Dispose),
scalarDefaultCharVariable)))))
extension<LanguageFeature::Convert>(
"nonstandard usage: CONVERT="_port_en_US,
construct<InquireSpec>(
"CONVERT =" >> construct<InquireSpec::CharVar>(
pure(InquireSpec::CharVar::Kind::Convert),
scalarDefaultCharVariable))),
extension<LanguageFeature::Dispose>(
"nonstandard usage: DISPOSE="_port_en_US,
construct<InquireSpec>(
"DISPOSE =" >> construct<InquireSpec::CharVar>(
pure(InquireSpec::CharVar::Kind::Dispose),
scalarDefaultCharVariable)))))
// R1230 inquire-stmt ->
// INQUIRE ( inquire-spec-list ) |
@ -591,6 +603,7 @@ TYPE_PARSER(construct<format::IntrinsicTypeDataEditDesc>(
noInt, noInt) ||
// PGI/Intel extension: omitting width (and all else that follows)
extension<LanguageFeature::AbbreviatedEditDescriptor>(
"nonstandard usage: abbreviated edit descriptor"_port_en_US,
construct<format::IntrinsicTypeDataEditDesc>(
"I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
("B"_tok / !letter /* don't occlude BN & BZ */) >>
@ -673,8 +686,9 @@ TYPE_PARSER(construct<format::ControlEditDesc>(
"P" >> construct<format::ControlEditDesc>(
pure(format::ControlEditDesc::Kind::DP))) ||
extension<LanguageFeature::AdditionalFormats>(
"nonstandard usage: $ and \\ control edit descriptors"_port_en_US,
"$" >> construct<format::ControlEditDesc>(
pure(format::ControlEditDesc::Kind::Dollar)) ||
"\\" >> construct<format::ControlEditDesc>(
pure(format::ControlEditDesc::Kind::Backslash))))
"\\" >> construct<format::ControlEditDesc>(
pure(format::ControlEditDesc::Kind::Backslash))))
} // namespace Fortran::parser

View File

@ -54,11 +54,13 @@ static constexpr auto globalCompilerDirective{
// 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<Program>(
extension<LanguageFeature::EmptySourceFile>(skipStuffBeforeStatement >>
!nextCh >> pure<std::list<ProgramUnit>>()) ||
some(globalCompilerDirective || normalProgramUnit) /
skipStuffBeforeStatement))
TYPE_PARSER(
construct<Program>(extension<LanguageFeature::EmptySourceFile>(
"nonstandard usage: empty source file"_port_en_US,
skipStuffBeforeStatement >> !nextCh >>
pure<std::list<ProgramUnit>>()) ||
some(globalCompilerDirective || normalProgramUnit) /
skipStuffBeforeStatement))
// R504 specification-part ->
// [use-stmt]... [import-stmt]... [implicit-part]
@ -204,6 +206,7 @@ TYPE_CONTEXT_PARSER("main program"_en_US,
TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
construct<ProgramStmt>("PROGRAM" >> name /
maybe(extension<LanguageFeature::ProgramParentheses>(
"nonstandard usage: parentheses in PROGRAM statement"_port_en_US,
parenthesized(ok)))))
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
@ -449,10 +452,14 @@ TYPE_PARSER(construct<ActualArgSpec>(
// Semantics sorts it all out later.
TYPE_PARSER(construct<ActualArg>(expr) ||
construct<ActualArg>(Parser<AltReturnSpec>{}) ||
extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
construct<ActualArg::PercentRef>("%REF" >> parenthesized(variable)))) ||
extension<LanguageFeature::PercentRefAndVal>(construct<ActualArg>(
construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
extension<LanguageFeature::PercentRefAndVal>(
"nonstandard usage: %REF"_port_en_US,
construct<ActualArg>(construct<ActualArg::PercentRef>(
"%REF" >> parenthesized(variable)))) ||
extension<LanguageFeature::PercentRefAndVal>(
"nonstandard usage: %VAL"_port_en_US,
construct<ActualArg>(
construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
// R1525 alt-return-spec -> * label
TYPE_PARSER(construct<AltReturnSpec>(star >> label))
@ -485,6 +492,7 @@ TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US,
construct<FunctionStmt>(many(prefixSpec), "FUNCTION" >> name,
parenthesized(optionalList(name)), maybe(suffix)) ||
extension<LanguageFeature::OmitFunctionDummies>(
"nonstandard usage: FUNCTION statement without dummy argument list"_port_en_US,
construct<FunctionStmt>( // PGI & Intel accept "FUNCTION F"
many(prefixSpec), "FUNCTION" >> name,
construct<std::list<Name>>(),

View File

@ -655,15 +655,20 @@ constexpr auto underscore{"_"_ch};
// Cray and gfortran accept '$', but not as the first character.
// Cray accepts '@' as well.
constexpr auto otherIdChar{underscore / !"'\""_ch ||
extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
extension<LanguageFeature::PunctuationInNames>(
"nonstandard usage: punctuation in name"_port_en_US, "$@"_ch)};
constexpr auto logicalTRUE{
(".TRUE."_tok ||
extension<LanguageFeature::LogicalAbbreviations>(".T."_tok)) >>
extension<LanguageFeature::LogicalAbbreviations>(
"nonstandard usage: .T. spelling of .TRUE."_port_en_US,
".T."_tok)) >>
pure(true)};
constexpr auto logicalFALSE{
(".FALSE."_tok ||
extension<LanguageFeature::LogicalAbbreviations>(".F."_tok)) >>
extension<LanguageFeature::LogicalAbbreviations>(
"nonstandard usage: .F. spelling of .FALSE."_port_en_US,
".F."_tok)) >>
pure(false)};
// deprecated: Hollerith literals