1c291436f5
Add parse-tree-mutator.h like parse-tree-visitor.h except that the Walk functions take non-const references to parse tree nodes so the Pre and Post methods of the mutator that are passed around can make changes to the parse tree. Change ExecutionPart to be a class that wraps a list so that it can be identified during parse tree walking. Add Symbol* field to parser::Name for the result of symbol resolution. In parse tree dumper, dump symbol when it is there instead of just name. Add RewriteParseTree to walk the parse tree, fill in resolved symbols in Name nodes, and make necessary changes to the structure. Currently that consists of rewriting statement functions as array assignments when appropriate. In ResolveNames, call RewriteParseTree if the resolution was successful. Recognize a statement function that comes after a mis-identified statement function and report an error. resolve08.f90 tests this case. Add -fdebug-dump-symbols to dump the scope tree and symbols in each scope. This is implemented by DumpSymbols in resolve-names.cc. Add an optional symbol to scopes that correspond to symbols (e.g. subprograms). Remove debug output from ResolveNamesVisitor as this option can be used instead. Original-commit: flang-compiler/f18@9cd3372265 Reviewed-on: https://github.com/flang-compiler/f18/pull/60 Tree-same-pre-rewrite: false
3644 lines
168 KiB
C++
3644 lines
168 KiB
C++
#ifndef FORTRAN_PARSER_GRAMMAR_H_
|
|
#define FORTRAN_PARSER_GRAMMAR_H_
|
|
|
|
// Top-level grammar specification for Fortran. These parsers drive
|
|
// the tokenization parsers in cooked-tokens.h to consume characters,
|
|
// recognize the productions of Fortran, and to construct a parse tree.
|
|
// See parser-combinators.txt for documentation on the parser combinator
|
|
// library used here to implement an LL recursive descent recognizer.
|
|
|
|
#include "basic-parsers.h"
|
|
#include "characters.h"
|
|
#include "parse-tree.h"
|
|
#include "token-parsers.h"
|
|
#include "user-state.h"
|
|
#include <cinttypes>
|
|
#include <cstdio>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
namespace Fortran {
|
|
namespace parser {
|
|
|
|
// The productions that follow are derived from the draft Fortran 2018
|
|
// standard, with some necessary modifications to remove left recursion
|
|
// and some generalization in order to defer cases where parses depend
|
|
// on the definitions of symbols. The "Rxxx" numbers that appear in
|
|
// comments refer to these numbered requirements in the Fortran standard.
|
|
|
|
// Many parsers in this grammar are defined as instances of this Parser<>
|
|
// template class. This usage requires that their Parse() member functions
|
|
// be defined separately, typically with a parsing expression wrapped up
|
|
// in an TYPE_PARSER() macro call.
|
|
template<typename A> struct Parser {
|
|
using resultType = A;
|
|
constexpr Parser() {}
|
|
static inline std::optional<A> Parse(ParseState *);
|
|
};
|
|
|
|
#define TYPE_PARSER(pexpr) \
|
|
template<> \
|
|
inline std::optional<typename decltype(pexpr)::resultType> \
|
|
Parser<typename decltype(pexpr)::resultType>::Parse(ParseState *state) { \
|
|
return (pexpr).Parse(state); \
|
|
}
|
|
|
|
#define TYPE_CONTEXT_PARSER(contextText, pexpr) \
|
|
template<> \
|
|
inline std::optional<typename decltype(pexpr)::resultType> \
|
|
Parser<typename decltype(pexpr)::resultType>::Parse(ParseState *state) { \
|
|
return inContext((contextText), (pexpr)).Parse(state); \
|
|
}
|
|
|
|
// Some specializations of Parser<> are used multiple times, or are
|
|
// of some special importance, so we instantiate them once here and
|
|
// give them names rather than referencing them as anonymous Parser<T>{}
|
|
// objects in the right-hand sides of productions.
|
|
constexpr Parser<Program> program; // R501 - the "top level" production
|
|
constexpr Parser<SpecificationPart> specificationPart; // R504
|
|
constexpr Parser<ImplicitPart> implicitPart; // R505
|
|
constexpr Parser<DeclarationConstruct> declarationConstruct; // R507
|
|
constexpr Parser<SpecificationConstruct> specificationConstruct; // R508
|
|
constexpr Parser<ExecutionPart> executionPart; // R509
|
|
constexpr Parser<ExecutionPartConstruct> executionPartConstruct; // R510
|
|
constexpr Parser<InternalSubprogramPart> internalSubprogramPart; // R511
|
|
constexpr Parser<ActionStmt> actionStmt; // R515
|
|
constexpr Parser<Name> name; // R603
|
|
constexpr Parser<LiteralConstant> literalConstant; // R605
|
|
constexpr Parser<NamedConstant> namedConstant; // R606
|
|
constexpr Parser<TypeParamValue> typeParamValue; // R701
|
|
constexpr Parser<TypeSpec> typeSpec; // R702
|
|
constexpr Parser<DeclarationTypeSpec> declarationTypeSpec; // R703
|
|
constexpr Parser<IntrinsicTypeSpec> intrinsicTypeSpec; // R704
|
|
constexpr Parser<IntegerTypeSpec> integerTypeSpec; // R705
|
|
constexpr Parser<KindSelector> kindSelector; // R706
|
|
constexpr Parser<SignedIntLiteralConstant> signedIntLiteralConstant; // R707
|
|
constexpr Parser<IntLiteralConstant> intLiteralConstant; // R708
|
|
constexpr Parser<KindParam> kindParam; // R709
|
|
constexpr Parser<RealLiteralConstant> realLiteralConstant; // R714
|
|
constexpr Parser<CharLength> charLength; // R723
|
|
constexpr Parser<CharLiteralConstant> charLiteralConstant; // R724
|
|
constexpr Parser<Initialization> initialization; // R743 & R805
|
|
constexpr Parser<DerivedTypeSpec> derivedTypeSpec; // R754
|
|
constexpr Parser<TypeDeclarationStmt> typeDeclarationStmt; // R801
|
|
constexpr Parser<NullInit> nullInit; // R806
|
|
constexpr Parser<AccessSpec> accessSpec; // R807
|
|
constexpr Parser<LanguageBindingSpec> languageBindingSpec; // R808, R1528
|
|
constexpr Parser<EntityDecl> entityDecl; // R803
|
|
constexpr Parser<CoarraySpec> coarraySpec; // R809
|
|
constexpr Parser<ArraySpec> arraySpec; // R815
|
|
constexpr Parser<ExplicitShapeSpec> explicitShapeSpec; // R816
|
|
constexpr Parser<DeferredShapeSpecList> deferredShapeSpecList; // R820
|
|
constexpr Parser<AssumedImpliedSpec> assumedImpliedSpec; // R821
|
|
constexpr Parser<IntentSpec> intentSpec; // R826
|
|
constexpr Parser<DataStmt> dataStmt; // R837
|
|
constexpr Parser<DataImpliedDo> dataImpliedDo; // R840
|
|
constexpr Parser<ParameterStmt> parameterStmt; // R851
|
|
constexpr Parser<OldParameterStmt> oldParameterStmt;
|
|
constexpr Parser<Designator> designator; // R901
|
|
constexpr Parser<Variable> variable; // R902
|
|
constexpr Parser<Substring> substring; // R908
|
|
constexpr Parser<DataRef> dataRef; // R911, R914, R917
|
|
constexpr Parser<StructureComponent> structureComponent; // R913
|
|
constexpr Parser<StatVariable> statVariable; // R929
|
|
constexpr Parser<StatOrErrmsg> statOrErrmsg; // R942 & R1165
|
|
constexpr Parser<DefinedOpName> definedOpName; // R1003, R1023, R1414, & R1415
|
|
constexpr Parser<Expr> expr; // R1022
|
|
constexpr Parser<SpecificationExpr> specificationExpr; // R1028
|
|
constexpr Parser<AssignmentStmt> assignmentStmt; // R1032
|
|
constexpr Parser<PointerAssignmentStmt> pointerAssignmentStmt; // R1033
|
|
constexpr Parser<WhereStmt> whereStmt; // R1041, R1045, R1046
|
|
constexpr Parser<WhereConstruct> whereConstruct; // R1042
|
|
constexpr Parser<WhereBodyConstruct> whereBodyConstruct; // R1044
|
|
constexpr Parser<ForallConstruct> forallConstruct; // R1050
|
|
constexpr Parser<ForallAssignmentStmt> forallAssignmentStmt; // R1053
|
|
constexpr Parser<ForallStmt> forallStmt; // R1055
|
|
constexpr Parser<Selector> selector; // R1105
|
|
constexpr Parser<EndSelectStmt> endSelectStmt; // R1143 & R1151 & R1155
|
|
constexpr Parser<LoopControl> loopControl; // R1123
|
|
constexpr Parser<ConcurrentHeader> concurrentHeader; // R1125
|
|
constexpr Parser<EndDoStmt> endDoStmt; // R1132
|
|
constexpr Parser<IoUnit> ioUnit; // R1201, R1203
|
|
constexpr Parser<FileUnitNumber> fileUnitNumber; // R1202
|
|
constexpr Parser<IoControlSpec> ioControlSpec; // R1213, R1214
|
|
constexpr Parser<Format> format; // R1215
|
|
constexpr Parser<InputItem> inputItem; // R1216
|
|
constexpr Parser<OutputItem> outputItem; // R1217
|
|
constexpr Parser<InputImpliedDo> inputImpliedDo; // R1218, R1219
|
|
constexpr Parser<OutputImpliedDo> outputImpliedDo; // R1218, R1219
|
|
constexpr Parser<PositionOrFlushSpec> positionOrFlushSpec; // R1227 & R1229
|
|
constexpr Parser<FormatStmt> formatStmt; // R1301
|
|
constexpr Parser<InterfaceBlock> interfaceBlock; // R1501
|
|
constexpr Parser<GenericSpec> genericSpec; // R1508
|
|
constexpr Parser<ProcInterface> procInterface; // R1513
|
|
constexpr Parser<ProcDecl> procDecl; // R1515
|
|
constexpr Parser<FunctionReference> functionReference; // R1520
|
|
constexpr Parser<ActualArgSpec> actualArgSpec; // R1523
|
|
constexpr Parser<PrefixSpec> prefixSpec; // R1527
|
|
constexpr Parser<FunctionSubprogram> functionSubprogram; // R1529
|
|
constexpr Parser<FunctionStmt> functionStmt; // R1530
|
|
constexpr Parser<Suffix> suffix; // R1532
|
|
constexpr Parser<EndFunctionStmt> endFunctionStmt; // R1533
|
|
constexpr Parser<SubroutineSubprogram> subroutineSubprogram; // R1534
|
|
constexpr Parser<SubroutineStmt> subroutineStmt; // R1535
|
|
constexpr Parser<DummyArg> dummyArg; // R1536
|
|
constexpr Parser<EndSubroutineStmt> endSubroutineStmt; // R1537
|
|
constexpr Parser<EntryStmt> entryStmt; // R1541
|
|
constexpr Parser<ContainsStmt> containsStmt; // R1543
|
|
constexpr Parser<CompilerDirective> compilerDirective;
|
|
|
|
// For a parser p, indirect(p) returns a parser that builds an indirect
|
|
// reference to p's return type.
|
|
template<typename PA> inline constexpr auto indirect(const PA &p) {
|
|
return construct<Indirection<typename PA::resultType>>{}(p);
|
|
}
|
|
|
|
// R711 digit-string -> digit [digit]...
|
|
// N.B. not a token -- no space is skipped
|
|
constexpr DigitString digitString;
|
|
|
|
// statement(p) parses Statement<P> for some statement type P that is the
|
|
// result type of the argument parser p, while also handling labels and
|
|
// end-of-statement markers.
|
|
|
|
// R611 label -> digit [digit]...
|
|
constexpr auto label = space >> digitString / spaceCheck;
|
|
|
|
template<typename PA>
|
|
using statementConstructor = construct<Statement<typename PA::resultType>>;
|
|
|
|
template<typename PA> inline constexpr auto unterminatedStatement(const PA &p) {
|
|
return skipEmptyLines >>
|
|
sourced(statementConstructor<PA>{}(maybe(label), space >> p));
|
|
}
|
|
|
|
constexpr auto endOfLine = "\n"_ch / skipEmptyLines ||
|
|
fail<const char *>("expected end of line"_err_en_US);
|
|
|
|
constexpr auto endOfStmt = space >>
|
|
(";"_ch / skipMany(";"_tok) / maybe(endOfLine) || endOfLine);
|
|
|
|
template<typename PA> inline constexpr auto statement(const PA &p) {
|
|
return unterminatedStatement(p) / endOfStmt;
|
|
}
|
|
|
|
constexpr auto ignoredStatementPrefix = skipEmptyLines >> maybe(label) >>
|
|
maybe(name / ":") >> space;
|
|
|
|
// Error recovery within statements: skip to the end of the line,
|
|
// but not over an END or CONTAINS statement.
|
|
constexpr auto errorRecovery = construct<ErrorRecovery>{};
|
|
constexpr auto skipToEndOfLine = SkipTo<'\n'>{} >> 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 = ignoredStatementPrefix;
|
|
constexpr auto skipBadLine = SkipPast<'\n'>{} >> errorRecovery;
|
|
constexpr auto executionPartErrorRecovery = errorRecoveryStart >> !"END"_tok >>
|
|
!"CONTAINS"_tok >> !"ELSE"_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
|
|
constexpr auto execPartLookAhead = actionStmt >> ok || "ASSOCIATE ("_tok ||
|
|
"BLOCK"_tok || "SELECT"_tok || "CHANGE TEAM"_sptok || "CRITICAL"_tok ||
|
|
"DO"_tok || "IF ("_tok || "WHERE ("_tok || "FORALL ("_tok;
|
|
constexpr auto declErrorRecovery =
|
|
errorRecoveryStart >> !execPartLookAhead >> stmtErrorRecovery;
|
|
TYPE_CONTEXT_PARSER("declaration construct"_en_US,
|
|
recovery(construct<DeclarationConstruct>{}(specificationConstruct) ||
|
|
construct<DeclarationConstruct>{}(statement(indirect(dataStmt))) ||
|
|
construct<DeclarationConstruct>{}(
|
|
statement(indirect(formatStmt))) ||
|
|
construct<DeclarationConstruct>{}(statement(indirect(entryStmt))) ||
|
|
construct<DeclarationConstruct>{}(
|
|
statement(indirect(Parser<StmtFunctionStmt>{}))),
|
|
construct<DeclarationConstruct>{}(declErrorRecovery)))
|
|
|
|
// R508 specification-construct ->
|
|
// derived-type-def | enum-def | generic-stmt | interface-block |
|
|
// parameter-stmt | procedure-declaration-stmt |
|
|
// other-specification-stmt | type-declaration-stmt
|
|
TYPE_CONTEXT_PARSER("specification construct"_en_US,
|
|
construct<SpecificationConstruct>{}(indirect(Parser<DerivedTypeDef>{})) ||
|
|
construct<SpecificationConstruct>{}(indirect(Parser<EnumDef>{})) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(indirect(Parser<GenericStmt>{}))) ||
|
|
construct<SpecificationConstruct>{}(indirect(interfaceBlock)) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(indirect(parameterStmt))) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(indirect(oldParameterStmt))) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(indirect(Parser<ProcedureDeclarationStmt>{}))) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(Parser<OtherSpecificationStmt>{})) ||
|
|
construct<SpecificationConstruct>{}(
|
|
statement(indirect(typeDeclarationStmt))) ||
|
|
construct<SpecificationConstruct>{}(indirect(Parser<StructureDef>{})) ||
|
|
construct<SpecificationConstruct>{}(indirect(compilerDirective)))
|
|
|
|
// R513 other-specification-stmt ->
|
|
// access-stmt | allocatable-stmt | asynchronous-stmt | bind-stmt |
|
|
// codimension-stmt | contiguous-stmt | dimension-stmt | external-stmt |
|
|
// intent-stmt | intrinsic-stmt | namelist-stmt | optional-stmt |
|
|
// pointer-stmt | protected-stmt | save-stmt | target-stmt |
|
|
// volatile-stmt | value-stmt | common-stmt | equivalence-stmt
|
|
TYPE_PARSER(
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<AccessStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<AllocatableStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<AsynchronousStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<BindStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<CodimensionStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<ContiguousStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<DimensionStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<ExternalStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<IntentStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<IntrinsicStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<NamelistStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<OptionalStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<PointerStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<ProtectedStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<SaveStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<TargetStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<ValueStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<VolatileStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<CommonStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<EquivalenceStmt>{})) ||
|
|
construct<OtherSpecificationStmt>{}(indirect(Parser<BasedPointerStmt>{})))
|
|
|
|
// R604 constant -> literal-constant | named-constant
|
|
// Used only via R607 int-constant and R845 data-stmt-constant.
|
|
// The look-ahead check prevents occlusion of constant-subobject in
|
|
// data-stmt-constant.
|
|
TYPE_PARSER(construct<ConstantValue>{}(literalConstant) ||
|
|
construct<ConstantValue>{}(namedConstant / !"%"_tok / !"("_tok))
|
|
|
|
// R608 intrinsic-operator ->
|
|
// power-op | mult-op | add-op | concat-op | rel-op |
|
|
// not-op | and-op | or-op | equiv-op
|
|
// R610 extended-intrinsic-op -> intrinsic-operator
|
|
// These parsers must be ordered carefully to avoid misrecognition.
|
|
constexpr auto namedIntrinsicOperator = ".LT." >>
|
|
pure(DefinedOperator::IntrinsicOperator::LT) ||
|
|
".LE." >> pure(DefinedOperator::IntrinsicOperator::LE) ||
|
|
".EQ." >> pure(DefinedOperator::IntrinsicOperator::EQ) ||
|
|
".NE." >> pure(DefinedOperator::IntrinsicOperator::NE) ||
|
|
".GE." >> pure(DefinedOperator::IntrinsicOperator::GE) ||
|
|
".GT." >> pure(DefinedOperator::IntrinsicOperator::GT) ||
|
|
".NOT." >> pure(DefinedOperator::IntrinsicOperator::NOT) ||
|
|
".AND." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
|
|
".OR." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
|
|
".EQV." >> pure(DefinedOperator::IntrinsicOperator::EQV) ||
|
|
".NEQV." >> pure(DefinedOperator::IntrinsicOperator::NEQV) ||
|
|
extension(".XOR." >> pure(DefinedOperator::IntrinsicOperator::XOR) ||
|
|
".N." >> pure(DefinedOperator::IntrinsicOperator::NOT) ||
|
|
".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
|
|
".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
|
|
".X." >> pure(DefinedOperator::IntrinsicOperator::XOR));
|
|
|
|
constexpr auto intrinsicOperator = "**" >>
|
|
pure(DefinedOperator::IntrinsicOperator::Power) ||
|
|
"*" >> pure(DefinedOperator::IntrinsicOperator::Multiply) ||
|
|
"//" >> pure(DefinedOperator::IntrinsicOperator::Concat) ||
|
|
"/=" >> pure(DefinedOperator::IntrinsicOperator::NE) ||
|
|
"/" >> pure(DefinedOperator::IntrinsicOperator::Divide) ||
|
|
"+" >> pure(DefinedOperator::IntrinsicOperator::Add) ||
|
|
"-" >> pure(DefinedOperator::IntrinsicOperator::Subtract) ||
|
|
"<=" >> pure(DefinedOperator::IntrinsicOperator::LE) ||
|
|
extension("<>" >> pure(DefinedOperator::IntrinsicOperator::NE)) ||
|
|
"<" >> pure(DefinedOperator::IntrinsicOperator::LT) ||
|
|
"==" >> pure(DefinedOperator::IntrinsicOperator::EQ) ||
|
|
">=" >> pure(DefinedOperator::IntrinsicOperator::GE) ||
|
|
">" >> pure(DefinedOperator::IntrinsicOperator::GT) ||
|
|
namedIntrinsicOperator;
|
|
|
|
// R609 defined-operator ->
|
|
// defined-unary-op | defined-binary-op | extended-intrinsic-op
|
|
TYPE_PARSER(construct<DefinedOperator>{}(intrinsicOperator) ||
|
|
construct<DefinedOperator>{}(definedOpName))
|
|
|
|
// R401 xzy-list -> xzy [, xzy]...
|
|
template<typename PA> inline constexpr auto nonemptyList(const PA &p) {
|
|
return nonemptySeparated(p, ","_tok); // p-list
|
|
}
|
|
|
|
template<typename PA> inline constexpr auto optionalList(const PA &p) {
|
|
return defaulted(nonemptySeparated(p, ","_tok)); // [p-list]
|
|
}
|
|
|
|
// R402 xzy-name -> name
|
|
|
|
// R403 scalar-xyz -> xyz
|
|
// Also define constant-xyz, int-xyz, default-char-xyz.
|
|
template<typename PA> inline constexpr auto scalar(const PA &p) {
|
|
return construct<Scalar<typename PA::resultType>>{}(p); // scalar-p
|
|
}
|
|
|
|
template<typename PA> inline constexpr auto constant(const PA &p) {
|
|
return construct<Constant<typename PA::resultType>>{}(p); // constant-p
|
|
}
|
|
|
|
template<typename PA> inline constexpr auto integer(const PA &p) {
|
|
return construct<Integer<typename PA::resultType>>{}(p); // int-p
|
|
}
|
|
|
|
template<typename PA> inline constexpr auto logical(const PA &p) {
|
|
return construct<Logical<typename PA::resultType>>{}(p); // logical-p
|
|
}
|
|
|
|
template<typename PA> inline constexpr auto defaultChar(const PA &p) {
|
|
return construct<DefaultChar<typename PA::resultType>>{}(
|
|
p); // default-char-p
|
|
}
|
|
|
|
// R1024 logical-expr -> expr
|
|
constexpr auto logicalExpr = logical(indirect(expr));
|
|
constexpr auto scalarLogicalExpr = scalar(logicalExpr);
|
|
|
|
// R1025 default-char-expr -> expr
|
|
constexpr auto defaultCharExpr = defaultChar(indirect(expr));
|
|
constexpr auto scalarDefaultCharExpr = scalar(defaultCharExpr);
|
|
|
|
// R1026 int-expr -> expr
|
|
constexpr auto intExpr = integer(indirect(expr));
|
|
constexpr auto scalarIntExpr = scalar(intExpr);
|
|
|
|
// R1029 constant-expr -> expr
|
|
constexpr auto constantExpr = constant(indirect(expr));
|
|
|
|
// R1030 default-char-constant-expr -> default-char-expr
|
|
constexpr auto scalarDefaultCharConstantExpr =
|
|
scalar(defaultChar(constantExpr));
|
|
|
|
// R1031 int-constant-expr -> int-expr
|
|
constexpr auto intConstantExpr = integer(constantExpr);
|
|
constexpr auto scalarIntConstantExpr = scalar(intConstantExpr);
|
|
|
|
// R501 program -> program-unit [program-unit]...
|
|
// This is the top-level production for the Fortran language.
|
|
struct StartNewSubprogram {
|
|
using resultType = Success;
|
|
static std::optional<Success> Parse(ParseState *state) {
|
|
if (auto ustate = state->userState()) {
|
|
ustate->NewSubprogram();
|
|
}
|
|
return {Success{}};
|
|
}
|
|
} startNewSubprogram;
|
|
|
|
TYPE_PARSER(
|
|
construct<Program>{}(
|
|
// statements consume only trailing noise; consume leading noise here.
|
|
skipEmptyLines >>
|
|
some(startNewSubprogram >> Parser<ProgramUnit>{} / endOfLine)) /
|
|
consumedAllInput)
|
|
|
|
// R502 program-unit ->
|
|
// main-program | external-subprogram | module | submodule | block-data
|
|
// R503 external-subprogram -> function-subprogram | subroutine-subprogram
|
|
TYPE_PARSER(construct<ProgramUnit>{}(indirect(functionSubprogram)) ||
|
|
construct<ProgramUnit>{}(indirect(subroutineSubprogram)) ||
|
|
construct<ProgramUnit>{}(indirect(Parser<Module>{})) ||
|
|
construct<ProgramUnit>{}(indirect(Parser<Submodule>{})) ||
|
|
construct<ProgramUnit>{}(indirect(Parser<BlockData>{})) ||
|
|
construct<ProgramUnit>{}(indirect(Parser<MainProgram>{})))
|
|
|
|
// R504 specification-part ->
|
|
// [use-stmt]... [import-stmt]... [implicit-part]
|
|
// [declaration-construct]...
|
|
TYPE_CONTEXT_PARSER("specification part"_en_US,
|
|
construct<SpecificationPart>{}(many(statement(indirect(Parser<UseStmt>{}))),
|
|
many(statement(indirect(Parser<ImportStmt>{}))), implicitPart,
|
|
many(declarationConstruct)))
|
|
|
|
// R505 implicit-part -> [implicit-part-stmt]... implicit-stmt
|
|
// TODO: Can overshoot; any trailing PARAMETER, FORMAT, & ENTRY
|
|
// statements after the last IMPLICIT should be transferred to the
|
|
// list of declaration-constructs.
|
|
TYPE_CONTEXT_PARSER("implicit part"_en_US,
|
|
construct<ImplicitPart>{}(many(Parser<ImplicitPartStmt>{})))
|
|
|
|
// R506 implicit-part-stmt ->
|
|
// implicit-stmt | parameter-stmt | format-stmt | entry-stmt
|
|
TYPE_PARSER(construct<ImplicitPartStmt>{}(
|
|
statement(indirect(Parser<ImplicitStmt>{}))) ||
|
|
construct<ImplicitPartStmt>{}(statement(indirect(parameterStmt))) ||
|
|
construct<ImplicitPartStmt>{}(statement(indirect(oldParameterStmt))) ||
|
|
construct<ImplicitPartStmt>{}(statement(indirect(formatStmt))) ||
|
|
construct<ImplicitPartStmt>{}(statement(indirect(entryStmt))))
|
|
|
|
// R512 internal-subprogram -> function-subprogram | subroutine-subprogram
|
|
constexpr auto internalSubprogram =
|
|
(construct<InternalSubprogram>{}(indirect(functionSubprogram)) ||
|
|
construct<InternalSubprogram>{}(indirect(subroutineSubprogram))) /
|
|
endOfStmt;
|
|
|
|
// R511 internal-subprogram-part -> contains-stmt [internal-subprogram]...
|
|
TYPE_CONTEXT_PARSER("internal subprogram part"_en_US,
|
|
construct<InternalSubprogramPart>{}(statement(containsStmt),
|
|
many(startNewSubprogram >> internalSubprogram)))
|
|
|
|
// 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(construct<ActionStmt>{}(indirect(Parser<AllocateStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(assignmentStmt)) ||
|
|
construct<ActionStmt>{}(indirect(Parser<BackspaceStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<CallStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<CloseStmt>{})) ||
|
|
"CONTINUE" >> construct<ActionStmt>{}(construct<ContinueStmt>{}) ||
|
|
construct<ActionStmt>{}(indirect(Parser<CycleStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<DeallocateStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<EndfileStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<EventPostStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<EventWaitStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<ExitStmt>{})) ||
|
|
"FAIL IMAGE"_sptok >> construct<ActionStmt>{}(construct<FailImageStmt>{}) ||
|
|
construct<ActionStmt>{}(indirect(Parser<FlushStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<FormTeamStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<GotoStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<IfStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<InquireStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<LockStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<NullifyStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<OpenStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(pointerAssignmentStmt)) ||
|
|
construct<ActionStmt>{}(indirect(Parser<PrintStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<ReadStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<ReturnStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<RewindStmt>{})) ||
|
|
construct<ActionStmt>{}(
|
|
indirect(Parser<StopStmt>{})) || // & error-stop-stmt
|
|
construct<ActionStmt>{}(indirect(Parser<SyncAllStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<SyncImagesStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<SyncMemoryStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<SyncTeamStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<UnlockStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<WaitStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(whereStmt)) ||
|
|
construct<ActionStmt>{}(indirect(Parser<WriteStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<ComputedGotoStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(forallStmt)) ||
|
|
construct<ActionStmt>{}(indirect(Parser<ArithmeticIfStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<AssignStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<AssignedGotoStmt>{})) ||
|
|
construct<ActionStmt>{}(indirect(Parser<PauseStmt>{})))
|
|
|
|
// 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.
|
|
struct CapturedLabelDoStmt {
|
|
static constexpr auto parser = statement(indirect(Parser<LabelDoStmt>{}));
|
|
using resultType = Statement<Indirection<LabelDoStmt>>;
|
|
static std::optional<resultType> Parse(ParseState *state) {
|
|
auto result = parser.Parse(state);
|
|
if (result) {
|
|
if (auto ustate = state->userState()) {
|
|
ustate->NewDoLabel(std::get<Label>(result->statement->t));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} capturedLabelDoStmt;
|
|
|
|
struct EndDoStmtForCapturedLabelDoStmt {
|
|
static constexpr auto parser = statement(indirect(endDoStmt));
|
|
using resultType = Statement<Indirection<EndDoStmt>>;
|
|
static std::optional<resultType> Parse(ParseState *state) {
|
|
if (auto enddo = parser.Parse(state)) {
|
|
if (enddo->label.has_value()) {
|
|
if (auto ustate = state->userState()) {
|
|
if (!ustate->InNonlabelDoConstruct() &&
|
|
ustate->IsDoLabel(enddo->label.value())) {
|
|
return enddo;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
} endDoStmtForCapturedLabelDoStmt;
|
|
|
|
// 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 =
|
|
construct<ExecutableConstruct>{}(statement(actionStmt)) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<AssociateConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<BlockConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<CaseConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<ChangeTeamConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<CriticalConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(capturedLabelDoStmt) ||
|
|
construct<ExecutableConstruct>{}(endDoStmtForCapturedLabelDoStmt) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<DoConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<IfConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<SelectRankConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(Parser<SelectTypeConstruct>{})) ||
|
|
construct<ExecutableConstruct>{}(indirect(whereConstruct)) ||
|
|
construct<ExecutableConstruct>{}(indirect(forallConstruct)) ||
|
|
construct<ExecutableConstruct>{}(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<ExecutionPartConstruct>(
|
|
"obsolete legacy extension is not supported"_err_en_US),
|
|
construct<ExecutionPartConstruct>{}(
|
|
statement("REDIMENSION" >> name >>
|
|
parenthesized(nonemptyList(Parser<AllocateShapeSpec>{})) >> ok) >>
|
|
errorRecovery));
|
|
|
|
TYPE_CONTEXT_PARSER("execution part construct"_en_US,
|
|
recovery(construct<ExecutionPartConstruct>{}(executableConstruct) ||
|
|
construct<ExecutionPartConstruct>{}(
|
|
statement(indirect(formatStmt))) ||
|
|
construct<ExecutionPartConstruct>{}(
|
|
statement(indirect(entryStmt))) ||
|
|
construct<ExecutionPartConstruct>{}(
|
|
statement(indirect(dataStmt))) ||
|
|
extension(construct<ExecutionPartConstruct>{}(
|
|
statement(indirect(Parser<NamelistStmt>{}))) ||
|
|
obsoleteExecutionPartConstruct),
|
|
construct<ExecutionPartConstruct>{}(executionPartErrorRecovery)))
|
|
|
|
// R509 execution-part -> executable-construct [execution-part-construct]...
|
|
TYPE_CONTEXT_PARSER("execution part"_en_US,
|
|
construct<ExecutionPart>{}(many(executionPartConstruct)))
|
|
|
|
// R602 underscore -> _
|
|
constexpr auto underscore = "_"_ch;
|
|
|
|
// R516 keyword -> name
|
|
// R601 alphanumeric-character -> letter | digit | underscore
|
|
// R603 name -> letter [alphanumeric-character]...
|
|
// N.B. Don't accept an underscore if it is immediately followed by a
|
|
// quotation mark, so that kindParameter_"character literal" is parsed properly.
|
|
// PGI and ifort accept '$' in identifiers, even as the initial character.
|
|
// Cray and gfortran accept '$', but not as the first character.
|
|
// Cray accepts '@' as well.
|
|
constexpr auto otherIdChar = underscore / !"'\""_ch || extension("$@"_ch);
|
|
constexpr auto nonDigitIdChar = letter || otherIdChar;
|
|
constexpr auto rawName = nonDigitIdChar >> many(nonDigitIdChar || digit);
|
|
TYPE_PARSER(space >> sourced(attempt(rawName) >> construct<Name>{}))
|
|
constexpr auto keyword = construct<Keyword>{}(name);
|
|
|
|
// R605 literal-constant ->
|
|
// int-literal-constant | real-literal-constant |
|
|
// complex-literal-constant | logical-literal-constant |
|
|
// char-literal-constant | boz-literal-constant
|
|
TYPE_PARSER(construct<LiteralConstant>{}(Parser<HollerithLiteralConstant>{}) ||
|
|
construct<LiteralConstant>{}(space >> realLiteralConstant) ||
|
|
construct<LiteralConstant>{}(intLiteralConstant) ||
|
|
construct<LiteralConstant>{}(Parser<ComplexLiteralConstant>{}) ||
|
|
construct<LiteralConstant>{}(Parser<BOZLiteralConstant>{}) ||
|
|
construct<LiteralConstant>{}(charLiteralConstant) ||
|
|
construct<LiteralConstant>{}(Parser<LogicalLiteralConstant>{}))
|
|
|
|
// R606 named-constant -> name
|
|
TYPE_PARSER(construct<NamedConstant>{}(name))
|
|
|
|
// R701 type-param-value -> scalar-int-expr | * | :
|
|
constexpr auto star = "*" >> construct<Star>{};
|
|
TYPE_PARSER(construct<TypeParamValue>{}(scalarIntExpr) ||
|
|
construct<TypeParamValue>{}(star) ||
|
|
construct<TypeParamValue>{}(":" >> construct<TypeParamValue::Deferred>{}))
|
|
|
|
// R702 type-spec -> intrinsic-type-spec | derived-type-spec
|
|
// N.B. This type-spec production is one of two instances in the Fortran
|
|
// grammar where intrinsic types and bare derived type names can clash;
|
|
// the other is below in R703 declaration-type-spec. Look-ahead is required
|
|
// to disambiguate the cases where a derived type name begins with the name
|
|
// of an intrinsic type, e.g., REALITY.
|
|
TYPE_CONTEXT_PARSER("type spec"_en_US,
|
|
construct<TypeSpec>{}(intrinsicTypeSpec / lookAhead("::"_tok || ")"_tok)) ||
|
|
construct<TypeSpec>{}(derivedTypeSpec))
|
|
|
|
// R703 declaration-type-spec ->
|
|
// intrinsic-type-spec | TYPE ( intrinsic-type-spec ) |
|
|
// TYPE ( derived-type-spec ) | CLASS ( derived-type-spec ) |
|
|
// CLASS ( * ) | TYPE ( * )
|
|
// N.B. It is critical to distribute "parenthesized()" over the alternatives
|
|
// for TYPE (...), rather than putting the alternatives within it, which
|
|
// would fail on "TYPE(real_derived)" with a misrecognition of "real" as an
|
|
// intrinsic-type-spec.
|
|
TYPE_CONTEXT_PARSER("declaration type spec"_en_US,
|
|
construct<DeclarationTypeSpec>{}(intrinsicTypeSpec) ||
|
|
"TYPE" >>
|
|
(parenthesized(
|
|
construct<DeclarationTypeSpec>{}(intrinsicTypeSpec)) ||
|
|
parenthesized(construct<DeclarationTypeSpec>{}(
|
|
construct<DeclarationTypeSpec::Type>{}(derivedTypeSpec))) ||
|
|
"( * )" >> construct<DeclarationTypeSpec>{}(
|
|
construct<DeclarationTypeSpec::TypeStar>{})) ||
|
|
"CLASS" >>
|
|
parenthesized(
|
|
construct<DeclarationTypeSpec>{}(
|
|
construct<DeclarationTypeSpec::Class>{}(derivedTypeSpec)) ||
|
|
"*" >> construct<DeclarationTypeSpec>{}(
|
|
construct<DeclarationTypeSpec::ClassStar>{})) ||
|
|
extension("RECORD /" >>
|
|
construct<DeclarationTypeSpec>{}(
|
|
construct<DeclarationTypeSpec::Record>{}(name / "/"))))
|
|
|
|
// R704 intrinsic-type-spec ->
|
|
// integer-type-spec | REAL [kind-selector] | DOUBLE PRECISION |
|
|
// COMPLEX [kind-selector] | CHARACTER [char-selector] |
|
|
// LOGICAL [kind-selector]
|
|
// Extensions: DOUBLE COMPLEX, NCHARACTER, BYTE
|
|
TYPE_CONTEXT_PARSER("intrinsic type spec"_en_US,
|
|
construct<IntrinsicTypeSpec>{}(integerTypeSpec) ||
|
|
"REAL" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Real>{}(maybe(kindSelector))) ||
|
|
"DOUBLE PRECISION" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::DoublePrecision>{}) ||
|
|
"COMPLEX" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Complex>{}(maybe(kindSelector))) ||
|
|
"CHARACTER" >> construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Character>{}(
|
|
maybe(Parser<CharSelector>{}))) ||
|
|
"LOGICAL" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Logical>{}(maybe(kindSelector))) ||
|
|
"DOUBLE COMPLEX" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
extension(construct<IntrinsicTypeSpec::DoubleComplex>{})) ||
|
|
"NCHARACTER" >> construct<IntrinsicTypeSpec>{}(extension(
|
|
construct<IntrinsicTypeSpec::NCharacter>{}(
|
|
maybe(Parser<LengthSelector>{})))) ||
|
|
extension("BYTE" >>
|
|
construct<IntrinsicTypeSpec>{}(construct<IntegerTypeSpec>{}(
|
|
construct<std::optional<KindSelector>>{}(pure(1))))))
|
|
|
|
// R705 integer-type-spec -> INTEGER [kind-selector]
|
|
TYPE_PARSER(construct<IntegerTypeSpec>{}("INTEGER" >> maybe(kindSelector)))
|
|
|
|
// R706 kind-selector -> ( [KIND =] scalar-int-constant-expr )
|
|
// Legacy extension: kind-selector -> * digit-string
|
|
TYPE_PARSER(construct<KindSelector>{}(
|
|
parenthesized(maybe("KIND ="_tok) >> scalarIntConstantExpr)) ||
|
|
extension(construct<KindSelector>{}(
|
|
construct<KindSelector::StarSize>{}("*" >> digitString / spaceCheck))))
|
|
|
|
// R710 signed-digit-string -> [sign] digit-string
|
|
// N.B. Not a complete token -- no space is skipped.
|
|
constexpr SignedDigitString signedDigitString;
|
|
|
|
// R707 signed-int-literal-constant -> [sign] int-literal-constant
|
|
TYPE_PARSER(space >> sourced(construct<SignedIntLiteralConstant>{}(
|
|
signedDigitString, maybe(underscore >> kindParam))))
|
|
|
|
// R708 int-literal-constant -> digit-string [_ kind-param]
|
|
// The negated look-ahead for a trailing underscore prevents misrecognition
|
|
// when the digit string is a numeric kind parameter of a character literal.
|
|
TYPE_PARSER(construct<IntLiteralConstant>{}(
|
|
space >> digitString, maybe(underscore >> kindParam) / !underscore))
|
|
|
|
// R709 kind-param -> digit-string | scalar-int-constant-name
|
|
TYPE_PARSER(construct<KindParam>{}(digitString) ||
|
|
construct<KindParam>{}(scalar(integer(constant(name)))))
|
|
|
|
// R712 sign -> + | -
|
|
// Not a complete token.
|
|
constexpr auto sign = "+"_ch >> pure(Sign::Positive) ||
|
|
"-"_ch >> pure(Sign::Negative);
|
|
|
|
// R713 signed-real-literal-constant -> [sign] real-literal-constant
|
|
constexpr auto signedRealLiteralConstant = space >>
|
|
construct<SignedRealLiteralConstant>{}(maybe(sign), realLiteralConstant);
|
|
|
|
// R714 real-literal-constant ->
|
|
// significand [exponent-letter exponent] [_ kind-param] |
|
|
// digit-string exponent-letter exponent [_ kind-param]
|
|
// R715 significand -> digit-string . [digit-string] | . digit-string
|
|
// R716 exponent-letter -> E | D
|
|
// Extension: Q
|
|
// R717 exponent -> signed-digit-string
|
|
// N.B. Preceding space is not skipped.
|
|
constexpr auto exponentPart =
|
|
("ed"_ch || extension("q"_ch)) >> signedDigitString;
|
|
|
|
TYPE_CONTEXT_PARSER("REAL literal constant"_en_US,
|
|
construct<RealLiteralConstant>{}(
|
|
sourced(
|
|
(skipDigitString >> "."_ch >>
|
|
!(some(letter) >> "."_ch /* don't misinterpret 1.AND. */) >>
|
|
maybe(skipDigitString) >> maybe(exponentPart) >> ok ||
|
|
"."_ch >> skipDigitString >> maybe(exponentPart) >> ok ||
|
|
skipDigitString >> exponentPart >> ok) >>
|
|
construct<RealLiteralConstant::Real>{}),
|
|
maybe(underscore >> kindParam)))
|
|
|
|
// R718 complex-literal-constant -> ( real-part , imag-part )
|
|
TYPE_CONTEXT_PARSER("COMPLEX literal constant"_en_US,
|
|
parenthesized(construct<ComplexLiteralConstant>{}(
|
|
Parser<ComplexPart>{} / ",", Parser<ComplexPart>{})))
|
|
|
|
// PGI/Intel extension: signed complex literal constant
|
|
TYPE_PARSER(construct<SignedComplexLiteralConstant>{}(
|
|
space >> sign, Parser<ComplexLiteralConstant>{}))
|
|
|
|
// R719 real-part ->
|
|
// signed-int-literal-constant | signed-real-literal-constant |
|
|
// named-constant
|
|
// R720 imag-part ->
|
|
// signed-int-literal-constant | signed-real-literal-constant |
|
|
// named-constant
|
|
TYPE_PARSER(construct<ComplexPart>{}(signedRealLiteralConstant) ||
|
|
construct<ComplexPart>{}(signedIntLiteralConstant) ||
|
|
construct<ComplexPart>{}(namedConstant))
|
|
|
|
// R721 char-selector ->
|
|
// length-selector |
|
|
// ( LEN = type-param-value , KIND = scalar-int-constant-expr ) |
|
|
// ( type-param-value , [KIND =] scalar-int-constant-expr ) |
|
|
// ( KIND = scalar-int-constant-expr [, LEN = type-param-value] )
|
|
TYPE_PARSER(construct<CharSelector>{}(Parser<LengthSelector>{}) ||
|
|
parenthesized(construct<CharSelector>{}(
|
|
"LEN =" >> typeParamValue, ", KIND =" >> scalarIntConstantExpr)) ||
|
|
parenthesized(construct<CharSelector>{}(
|
|
typeParamValue / ",", maybe("KIND ="_tok) >> scalarIntConstantExpr)) ||
|
|
parenthesized(construct<CharSelector>{}(
|
|
"KIND =" >> scalarIntConstantExpr, maybe(", LEN =" >> typeParamValue))))
|
|
|
|
// R722 length-selector -> ( [LEN =] type-param-value ) | * char-length [,]
|
|
// N.B. The trailing [,] in the production is permitted by the Standard
|
|
// only in the context of a type-declaration-stmt, but even with that
|
|
// limitation, it would seem to be unnecessary and buggy to consume the comma
|
|
// here.
|
|
TYPE_PARSER(construct<LengthSelector>{}(
|
|
parenthesized(maybe("LEN ="_tok) >> typeParamValue)) ||
|
|
construct<LengthSelector>{}("*" >> charLength /* / maybe(","_tok) */))
|
|
|
|
// R723 char-length -> ( type-param-value ) | digit-string
|
|
TYPE_PARSER(construct<CharLength>{}(parenthesized(typeParamValue)) ||
|
|
construct<CharLength>{}(space >> digitString / spaceCheck))
|
|
|
|
// R724 char-literal-constant ->
|
|
// [kind-param _] ' [rep-char]... ' |
|
|
// [kind-param _] " [rep-char]... "
|
|
// "rep-char" is any non-control character. Doubled interior quotes are
|
|
// combined. Backslash escapes can be enabled.
|
|
// PGI extension: nc'...' is Kanji.
|
|
// N.B. charLiteralConstantWithoutKind does not skip preceding space.
|
|
// N.B. the parsing of "name" takes care to not consume the '_'.
|
|
constexpr auto charLiteralConstantWithoutKind =
|
|
"'"_ch >> CharLiteral<'\''>{} || "\""_ch >> CharLiteral<'"'>{};
|
|
|
|
TYPE_CONTEXT_PARSER("CHARACTER literal constant"_en_US,
|
|
construct<CharLiteralConstant>{}(
|
|
kindParam / underscore, charLiteralConstantWithoutKind) ||
|
|
construct<CharLiteralConstant>{}(construct<std::optional<KindParam>>{},
|
|
space >> charLiteralConstantWithoutKind) ||
|
|
construct<CharLiteralConstant>{}(
|
|
"NC" >> construct<std::optional<KindParam>>{}(
|
|
construct<KindParam>{}(construct<KindParam::Kanji>{})),
|
|
charLiteralConstantWithoutKind))
|
|
|
|
// deprecated: Hollerith literals
|
|
constexpr auto rawHollerithLiteral = deprecated(HollerithLiteral{});
|
|
|
|
TYPE_CONTEXT_PARSER("Hollerith"_en_US,
|
|
construct<HollerithLiteralConstant>{}(rawHollerithLiteral))
|
|
|
|
// R725 logical-literal-constant ->
|
|
// .TRUE. [_ kind-param] | .FALSE. [_ kind-param]
|
|
// Also accept .T. and .F. as extensions.
|
|
TYPE_PARSER(construct<LogicalLiteralConstant>{}(
|
|
(".TRUE."_tok || extension(".T."_tok)) >> pure(true),
|
|
maybe(underscore >> kindParam)) ||
|
|
construct<LogicalLiteralConstant>{}(
|
|
(".FALSE."_tok || extension(".F."_tok)) >> pure(false),
|
|
maybe(underscore >> kindParam)))
|
|
|
|
// R726 derived-type-def ->
|
|
// derived-type-stmt [type-param-def-stmt]...
|
|
// [private-or-sequence]... [component-part]
|
|
// [type-bound-procedure-part] end-type-stmt
|
|
// R735 component-part -> [component-def-stmt]...
|
|
TYPE_CONTEXT_PARSER("derived type definition"_en_US,
|
|
construct<DerivedTypeDef>{}(statement(Parser<DerivedTypeStmt>{}),
|
|
many(statement(Parser<TypeParamDefStmt>{})),
|
|
many(statement(Parser<PrivateOrSequence>{})),
|
|
many(statement(Parser<ComponentDefStmt>{})),
|
|
maybe(Parser<TypeBoundProcedurePart>{}),
|
|
statement(Parser<EndTypeStmt>{})))
|
|
|
|
// R727 derived-type-stmt ->
|
|
// TYPE [[, type-attr-spec-list] ::] type-name [(
|
|
// type-param-name-list )]
|
|
TYPE_CONTEXT_PARSER("TYPE statement"_en_US,
|
|
construct<DerivedTypeStmt>{}(
|
|
"TYPE" >> optionalListBeforeColons(Parser<TypeAttrSpec>{}), name,
|
|
defaulted(parenthesized(nonemptyList(name)))))
|
|
|
|
// R728 type-attr-spec ->
|
|
// ABSTRACT | access-spec | BIND(C) | EXTENDS ( parent-type-name )
|
|
TYPE_PARSER(construct<TypeAttrSpec>{}("ABSTRACT" >> construct<Abstract>{}) ||
|
|
construct<TypeAttrSpec>{}(
|
|
"BIND ( C )" >> construct<TypeAttrSpec::BindC>{}) ||
|
|
construct<TypeAttrSpec>{}(
|
|
"EXTENDS" >> construct<TypeAttrSpec::Extends>{}(parenthesized(name))) ||
|
|
construct<TypeAttrSpec>{}(accessSpec))
|
|
|
|
// R729 private-or-sequence -> private-components-stmt | sequence-stmt
|
|
TYPE_PARSER(construct<PrivateOrSequence>{}(Parser<PrivateStmt>{}) ||
|
|
construct<PrivateOrSequence>{}(Parser<SequenceStmt>{}))
|
|
|
|
// R730 end-type-stmt -> END TYPE [type-name]
|
|
constexpr auto noNameEnd = "END" >> defaulted(cut >> maybe(name));
|
|
constexpr auto bareEnd = noNameEnd / lookAhead(endOfStmt);
|
|
constexpr auto endStmtErrorRecovery = noNameEnd / SkipTo<'\n'>{};
|
|
TYPE_PARSER(construct<EndTypeStmt>{}(
|
|
recovery("END TYPE" >> maybe(name), endStmtErrorRecovery)))
|
|
|
|
// R731 sequence-stmt -> SEQUENCE
|
|
TYPE_PARSER("SEQUENCE" >> construct<SequenceStmt>{})
|
|
|
|
// R732 type-param-def-stmt ->
|
|
// integer-type-spec , type-param-attr-spec :: type-param-decl-list
|
|
// R734 type-param-attr-spec -> KIND | LEN
|
|
TYPE_PARSER(construct<TypeParamDefStmt>{}(integerTypeSpec / ",",
|
|
"KIND" >> pure(TypeParamDefStmt::KindOrLen::Kind) ||
|
|
"LEN" >> pure(TypeParamDefStmt::KindOrLen::Len),
|
|
"::" >> nonemptyList(Parser<TypeParamDecl>{})))
|
|
|
|
// R733 type-param-decl -> type-param-name [= scalar-int-constant-expr]
|
|
TYPE_PARSER(
|
|
construct<TypeParamDecl>{}(name, maybe("=" >> scalarIntConstantExpr)))
|
|
|
|
// R736 component-def-stmt -> data-component-def-stmt |
|
|
// 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] ::]
|
|
// component-decl-list
|
|
TYPE_PARSER(construct<DataComponentDefStmt>{}(declarationTypeSpec,
|
|
optionalListBeforeColons(Parser<ComponentAttrSpec>{}),
|
|
nonemptyList(Parser<ComponentDecl>{})))
|
|
|
|
// R738 component-attr-spec ->
|
|
// access-spec | ALLOCATABLE |
|
|
// CODIMENSION lbracket coarray-spec rbracket |
|
|
// CONTIGUOUS | DIMENSION ( component-array-spec ) | POINTER
|
|
constexpr auto allocatable = "ALLOCATABLE" >> construct<Allocatable>{};
|
|
constexpr auto contiguous = "CONTIGUOUS" >> construct<Contiguous>{};
|
|
constexpr auto pointer = "POINTER" >> construct<Pointer>{};
|
|
TYPE_PARSER(construct<ComponentAttrSpec>{}(accessSpec) ||
|
|
construct<ComponentAttrSpec>{}(allocatable) ||
|
|
"CODIMENSION" >> construct<ComponentAttrSpec>{}(coarraySpec) ||
|
|
construct<ComponentAttrSpec>{}(contiguous) ||
|
|
"DIMENSION" >>
|
|
construct<ComponentAttrSpec>{}(Parser<ComponentArraySpec>{}) ||
|
|
construct<ComponentAttrSpec>{}(pointer))
|
|
|
|
// R739 component-decl ->
|
|
// component-name [( component-array-spec )]
|
|
// [lbracket coarray-spec rbracket] [* char-length]
|
|
// [component-initialization]
|
|
TYPE_CONTEXT_PARSER("component declaration"_en_US,
|
|
construct<ComponentDecl>{}(name, maybe(Parser<ComponentArraySpec>{}),
|
|
maybe(coarraySpec), maybe("*" >> charLength), maybe(initialization)))
|
|
|
|
// R740 component-array-spec ->
|
|
// explicit-shape-spec-list | deferred-shape-spec-list
|
|
// N.B. Parenthesized here rather than around references to this production.
|
|
TYPE_PARSER(construct<ComponentArraySpec>{}(
|
|
parenthesized(nonemptyList(explicitShapeSpec))) ||
|
|
construct<ComponentArraySpec>{}(parenthesized(deferredShapeSpecList)))
|
|
|
|
// R741 proc-component-def-stmt ->
|
|
// PROCEDURE ( [proc-interface] ) , proc-component-attr-spec-list
|
|
// :: proc-decl-list
|
|
TYPE_CONTEXT_PARSER("PROCEDURE component definition statement"_en_US,
|
|
"PROCEDURE" >>
|
|
construct<ProcComponentDefStmt>{}(parenthesized(maybe(procInterface)),
|
|
"," >> nonemptyList(Parser<ProcComponentAttrSpec>{}) / "::",
|
|
nonemptyList(procDecl)))
|
|
|
|
// R742 proc-component-attr-spec ->
|
|
// access-spec | NOPASS | PASS [(arg-name)] | POINTER
|
|
constexpr auto noPass = "NOPASS" >> construct<NoPass>{};
|
|
constexpr auto pass = "PASS" >> construct<Pass>{}(maybe(parenthesized(name)));
|
|
TYPE_PARSER(construct<ProcComponentAttrSpec>{}(accessSpec) ||
|
|
construct<ProcComponentAttrSpec>{}(noPass) ||
|
|
construct<ProcComponentAttrSpec>{}(pass) ||
|
|
construct<ProcComponentAttrSpec>{}(pointer))
|
|
|
|
// R744 initial-data-target -> designator
|
|
constexpr auto initialDataTarget = indirect(designator);
|
|
|
|
// R743 component-initialization ->
|
|
// = constant-expr | => null-init | => initial-data-target
|
|
// R805 initialization ->
|
|
// = constant-expr | => null-init | => initial-data-target
|
|
// Universal extension: initialization -> / data-stmt-value-list /
|
|
TYPE_PARSER("=>" >> construct<Initialization>{}(nullInit) ||
|
|
"=>" >> construct<Initialization>{}(initialDataTarget) ||
|
|
"=" >> construct<Initialization>{}(constantExpr) ||
|
|
extension("/" >> construct<Initialization>{}(
|
|
nonemptyList(indirect(Parser<DataStmtValue>{}))) /
|
|
"/"))
|
|
|
|
// R745 private-components-stmt -> PRIVATE
|
|
// R747 binding-private-stmt -> PRIVATE
|
|
TYPE_PARSER("PRIVATE" >> construct<PrivateStmt>{})
|
|
|
|
// R746 type-bound-procedure-part ->
|
|
// contains-stmt [binding-private-stmt] [type-bound-proc-binding]...
|
|
TYPE_CONTEXT_PARSER("type bound procedure part"_en_US,
|
|
construct<TypeBoundProcedurePart>{}(statement(containsStmt),
|
|
maybe(statement(Parser<PrivateStmt>{})),
|
|
many(statement(Parser<TypeBoundProcBinding>{}))))
|
|
|
|
// R748 type-bound-proc-binding ->
|
|
// type-bound-procedure-stmt | type-bound-generic-stmt |
|
|
// final-procedure-stmt
|
|
TYPE_PARSER(recovery(
|
|
construct<TypeBoundProcBinding>{}(Parser<TypeBoundProcedureStmt>{}) ||
|
|
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 |
|
|
// PROCEDURE ( interface-name ) , bind-attr-list :: binding-name-list
|
|
TYPE_CONTEXT_PARSER("type bound PROCEDURE statement"_en_US,
|
|
"PROCEDURE" >>
|
|
(construct<TypeBoundProcedureStmt>{}(
|
|
construct<TypeBoundProcedureStmt::WithInterface>{}(
|
|
parenthesized(name) / ",",
|
|
nonemptyList(Parser<BindAttr>{}) / "::",
|
|
nonemptyList(name))) ||
|
|
construct<TypeBoundProcedureStmt>{}(
|
|
construct<TypeBoundProcedureStmt::WithoutInterface>{}(
|
|
optionalListBeforeColons(Parser<BindAttr>{}),
|
|
nonemptyList(Parser<TypeBoundProcDecl>{})))))
|
|
|
|
// R750 type-bound-proc-decl -> binding-name [=> procedure-name]
|
|
TYPE_PARSER(construct<TypeBoundProcDecl>{}(name, maybe("=>" >> name)))
|
|
|
|
// R751 type-bound-generic-stmt ->
|
|
// GENERIC [, access-spec] :: generic-spec => binding-name-list
|
|
TYPE_CONTEXT_PARSER("type bound GENERIC statement"_en_US,
|
|
"GENERIC" >> construct<TypeBoundGenericStmt>{}(maybe("," >> accessSpec),
|
|
"::" >> indirect(genericSpec), "=>" >> nonemptyList(name)))
|
|
|
|
// R752 bind-attr ->
|
|
// access-spec | DEFERRED | NON_OVERRIDABLE | NOPASS | PASS [(arg-name)]
|
|
TYPE_PARSER(construct<BindAttr>{}(accessSpec) ||
|
|
"DEFERRED" >> construct<BindAttr>{}(construct<BindAttr::Deferred>{}) ||
|
|
"NON_OVERRIDABLE" >>
|
|
construct<BindAttr>{}(construct<BindAttr::Non_Overridable>{}) ||
|
|
construct<BindAttr>{}(noPass) || construct<BindAttr>{}(pass))
|
|
|
|
// R753 final-procedure-stmt -> FINAL [::] final-subroutine-name-list
|
|
TYPE_CONTEXT_PARSER("FINAL statement"_en_US,
|
|
"FINAL" >> maybe("::"_tok) >>
|
|
construct<FinalProcedureStmt>{}(nonemptyList(name)))
|
|
|
|
// R754 derived-type-spec -> type-name [(type-param-spec-list)]
|
|
TYPE_PARSER(construct<DerivedTypeSpec>{}(
|
|
name, defaulted(parenthesized(nonemptyList(Parser<TypeParamSpec>{})))))
|
|
|
|
// R755 type-param-spec -> [keyword =] type-param-value
|
|
TYPE_PARSER(construct<TypeParamSpec>{}(maybe(keyword / "="), typeParamValue))
|
|
|
|
// R756 structure-constructor -> derived-type-spec ( [component-spec-list] )
|
|
TYPE_PARSER((construct<StructureConstructor>{}(derivedTypeSpec,
|
|
parenthesized(optionalList(Parser<ComponentSpec>{}))) ||
|
|
// This alternative corrects misrecognition of the
|
|
// component-spec-list as the type-param-spec-list in
|
|
// derived-type-spec.
|
|
construct<StructureConstructor>{}(
|
|
construct<DerivedTypeSpec>{}(
|
|
name, construct<std::list<TypeParamSpec>>{}),
|
|
parenthesized(optionalList(Parser<ComponentSpec>{})))) /
|
|
!"("_tok)
|
|
|
|
// R757 component-spec -> [keyword =] component-data-source
|
|
TYPE_PARSER(construct<ComponentSpec>{}(
|
|
maybe(keyword / "="), Parser<ComponentDataSource>{}))
|
|
|
|
// R758 component-data-source -> expr | data-target | proc-target
|
|
TYPE_PARSER(construct<ComponentDataSource>{}(indirect(expr)))
|
|
|
|
// R759 enum-def ->
|
|
// enum-def-stmt enumerator-def-stmt [enumerator-def-stmt]...
|
|
// end-enum-stmt
|
|
TYPE_CONTEXT_PARSER("enum definition"_en_US,
|
|
construct<EnumDef>{}(statement(Parser<EnumDefStmt>{}),
|
|
some(statement(Parser<EnumeratorDefStmt>{})),
|
|
statement(Parser<EndEnumStmt>{})))
|
|
|
|
// R760 enum-def-stmt -> ENUM, BIND(C)
|
|
TYPE_PARSER("ENUM , BIND ( C )" >> construct<EnumDefStmt>{})
|
|
|
|
// R761 enumerator-def-stmt -> ENUMERATOR [::] enumerator-list
|
|
TYPE_CONTEXT_PARSER("ENUMERATOR statement"_en_US,
|
|
construct<EnumeratorDefStmt>{}(
|
|
"ENUMERATOR" >> maybe("::"_tok) >> nonemptyList(Parser<Enumerator>{})))
|
|
|
|
// R762 enumerator -> named-constant [= scalar-int-constant-expr]
|
|
TYPE_PARSER(
|
|
construct<Enumerator>{}(namedConstant, maybe("=" >> scalarIntConstantExpr)))
|
|
|
|
// R763 end-enum-stmt -> END ENUM
|
|
TYPE_PARSER(recovery("END ENUM"_tok, "END" >> SkipTo<'\n'>{}) >>
|
|
construct<EndEnumStmt>{})
|
|
|
|
// R764 boz-literal-constant -> binary-constant | octal-constant | hex-constant
|
|
// R765 binary-constant -> B ' digit [digit]... ' | B " digit [digit]... "
|
|
// R766 octal-constant -> O ' digit [digit]... ' | O " digit [digit]... "
|
|
// R767 hex-constant ->
|
|
// Z ' hex-digit [hex-digit]... ' | Z " hex-digit [hex-digit]... "
|
|
// extension: X accepted for Z
|
|
// extension: BOZX suffix accepted
|
|
TYPE_PARSER(construct<BOZLiteralConstant>{}(BOZLiteral{}))
|
|
|
|
// R1124 do-variable -> scalar-int-variable-name
|
|
constexpr auto doVariable = scalar(integer(name));
|
|
|
|
template<typename PA> inline constexpr auto loopBounds(const PA &p) {
|
|
return construct<LoopBounds<typename PA::resultType>>{}(
|
|
doVariable / "=", p / ",", p, maybe("," >> p));
|
|
}
|
|
|
|
// R769 array-constructor -> (/ ac-spec /) | lbracket ac-spec rbracket
|
|
TYPE_CONTEXT_PARSER("array constructor"_en_US,
|
|
construct<ArrayConstructor>{}(
|
|
"(/" >> Parser<AcSpec>{} / "/)" || bracketed(Parser<AcSpec>{})))
|
|
|
|
// R770 ac-spec -> type-spec :: | [type-spec ::] ac-value-list
|
|
TYPE_PARSER(construct<AcSpec>{}(maybe(indirect(typeSpec) / "::"),
|
|
nonemptyList(Parser<AcValue>{})) ||
|
|
construct<AcSpec>{}(indirect(typeSpec) / "::"))
|
|
|
|
// R773 ac-value -> expr | ac-implied-do
|
|
TYPE_PARSER(
|
|
// PGI/Intel extension: accept triplets in array constructors
|
|
extension(construct<AcValue>{}(construct<AcValue::Triplet>{}(
|
|
scalarIntExpr, ":" >> scalarIntExpr, maybe(":" >> scalarIntExpr)))) ||
|
|
construct<AcValue>{}(indirect(expr)) ||
|
|
construct<AcValue>{}(indirect(Parser<AcImpliedDo>{})))
|
|
|
|
// R774 ac-implied-do -> ( ac-value-list , ac-implied-do-control )
|
|
TYPE_PARSER(parenthesized(construct<AcImpliedDo>{}(
|
|
nonemptyList(Parser<AcValue>{} / lookAhead(","_tok)),
|
|
"," >> Parser<AcImpliedDoControl>{})))
|
|
|
|
// R775 ac-implied-do-control ->
|
|
// [integer-type-spec ::] ac-do-variable = scalar-int-expr ,
|
|
// scalar-int-expr [, scalar-int-expr]
|
|
// R776 ac-do-variable -> do-variable
|
|
TYPE_PARSER(construct<AcImpliedDoControl>{}(
|
|
maybe(integerTypeSpec / "::"), loopBounds(scalarIntExpr)))
|
|
|
|
// R801 type-declaration-stmt ->
|
|
// declaration-type-spec [[, attr-spec]... ::] entity-decl-list
|
|
TYPE_PARSER(construct<TypeDeclarationStmt>{}(declarationTypeSpec,
|
|
optionalListBeforeColons(Parser<AttrSpec>{}),
|
|
nonemptyList(entityDecl)) ||
|
|
// PGI-only extension: don't require the colons
|
|
// N.B.: The standard requires the colons if the entity
|
|
// declarations contain initializers.
|
|
extension(construct<TypeDeclarationStmt>{}(declarationTypeSpec,
|
|
defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
|
|
"," >> nonemptyList(entityDecl))))
|
|
|
|
// R802 attr-spec ->
|
|
// access-spec | ALLOCATABLE | ASYNCHRONOUS |
|
|
// CODIMENSION lbracket coarray-spec rbracket | CONTIGUOUS |
|
|
// DIMENSION ( array-spec ) | EXTERNAL | INTENT ( intent-spec ) |
|
|
// INTRINSIC | language-binding-spec | OPTIONAL | PARAMETER | POINTER |
|
|
// PROTECTED | SAVE | TARGET | VALUE | VOLATILE
|
|
constexpr auto optional = "OPTIONAL" >> construct<Optional>{};
|
|
constexpr auto protectedAttr = "PROTECTED" >> construct<Protected>{};
|
|
constexpr auto save = "SAVE" >> construct<Save>{};
|
|
TYPE_PARSER(construct<AttrSpec>{}(accessSpec) ||
|
|
construct<AttrSpec>{}(allocatable) ||
|
|
construct<AttrSpec>{}("ASYNCHRONOUS" >> construct<Asynchronous>{}) ||
|
|
construct<AttrSpec>{}("CODIMENSION" >> coarraySpec) ||
|
|
construct<AttrSpec>{}(contiguous) ||
|
|
construct<AttrSpec>{}("DIMENSION" >> arraySpec) ||
|
|
construct<AttrSpec>{}("EXTERNAL" >> construct<External>{}) ||
|
|
construct<AttrSpec>{}("INTENT" >> parenthesized(intentSpec)) ||
|
|
construct<AttrSpec>{}("INTRINSIC" >> construct<Intrinsic>{}) ||
|
|
construct<AttrSpec>{}(languageBindingSpec) ||
|
|
construct<AttrSpec>{}(optional) ||
|
|
construct<AttrSpec>{}("PARAMETER" >> construct<Parameter>{}) ||
|
|
construct<AttrSpec>{}(pointer) || construct<AttrSpec>{}(protectedAttr) ||
|
|
construct<AttrSpec>{}(save) ||
|
|
construct<AttrSpec>{}("TARGET" >> construct<Target>{}) ||
|
|
construct<AttrSpec>{}("VALUE" >> construct<Value>{}) ||
|
|
construct<AttrSpec>{}("VOLATILE" >> construct<Volatile>{}))
|
|
|
|
// R804 object-name -> name
|
|
constexpr auto objectName = name;
|
|
|
|
// R803 entity-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
// [* char-length] [initialization] |
|
|
// function-name [* char-length]
|
|
TYPE_PARSER(construct<EntityDecl>{}(objectName, maybe(arraySpec),
|
|
maybe(coarraySpec), maybe("*" >> charLength), maybe(initialization)))
|
|
|
|
// R806 null-init -> function-reference
|
|
// TODO: confirm in semantics that NULL still intrinsic in this scope
|
|
TYPE_PARSER("NULL ( )" >> construct<NullInit>{} / !"("_tok)
|
|
|
|
// R807 access-spec -> PUBLIC | PRIVATE
|
|
TYPE_PARSER(
|
|
"PUBLIC" >> construct<AccessSpec>{}(pure(AccessSpec::Kind::Public)) ||
|
|
"PRIVATE" >> construct<AccessSpec>{}(pure(AccessSpec::Kind::Private)))
|
|
|
|
// R808 language-binding-spec ->
|
|
// BIND ( C [, NAME = scalar-default-char-constant-expr] )
|
|
// R1528 proc-language-binding-spec -> language-binding-spec
|
|
TYPE_PARSER(construct<LanguageBindingSpec>{}(
|
|
"BIND ( C" >> maybe(", NAME =" >> scalarDefaultCharConstantExpr) / ")"))
|
|
|
|
// R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
|
|
// N.B. Bracketed here rather than around references, for consistency with
|
|
// array-spec.
|
|
TYPE_PARSER(
|
|
construct<CoarraySpec>{}(bracketed(Parser<DeferredCoshapeSpecList>{})) ||
|
|
construct<CoarraySpec>{}(bracketed(Parser<ExplicitCoshapeSpec>{})))
|
|
|
|
// R810 deferred-coshape-spec -> :
|
|
// deferred-coshape-spec-list - just a list of colons
|
|
int listLength(std::list<Success> &&xs) { return xs.size(); }
|
|
|
|
TYPE_PARSER(construct<DeferredCoshapeSpecList>{}(
|
|
applyFunction(listLength, nonemptyList(":"_tok))))
|
|
|
|
// R811 explicit-coshape-spec ->
|
|
// [[lower-cobound :] upper-cobound ,]... [lower-cobound :] *
|
|
// R812 lower-cobound -> specification-expr
|
|
// R813 upper-cobound -> specification-expr
|
|
TYPE_PARSER(construct<ExplicitCoshapeSpec>{}(
|
|
many(explicitShapeSpec / ","), maybe(specificationExpr / ":") / "*"))
|
|
|
|
// R815 array-spec ->
|
|
// explicit-shape-spec-list | assumed-shape-spec-list |
|
|
// deferred-shape-spec-list | assumed-size-spec | implied-shape-spec |
|
|
// implied-shape-or-assumed-size-spec | assumed-rank-spec
|
|
// N.B. Parenthesized here rather than around references to avoid
|
|
// a need for forced look-ahead.
|
|
TYPE_PARSER(
|
|
construct<ArraySpec>{}(parenthesized(nonemptyList(explicitShapeSpec))) ||
|
|
construct<ArraySpec>{}(
|
|
parenthesized(nonemptyList(Parser<AssumedShapeSpec>{}))) ||
|
|
construct<ArraySpec>{}(parenthesized(deferredShapeSpecList)) ||
|
|
construct<ArraySpec>{}(parenthesized(Parser<AssumedSizeSpec>{})) ||
|
|
construct<ArraySpec>{}(parenthesized(Parser<ImpliedShapeSpec>{})) ||
|
|
construct<ArraySpec>{}(parenthesized(Parser<AssumedRankSpec>{})))
|
|
|
|
// R816 explicit-shape-spec -> [lower-bound :] upper-bound
|
|
// R817 lower-bound -> specification-expr
|
|
// R818 upper-bound -> specification-expr
|
|
TYPE_PARSER(construct<ExplicitShapeSpec>{}(
|
|
maybe(specificationExpr / ":"), specificationExpr))
|
|
|
|
// R819 assumed-shape-spec -> [lower-bound] :
|
|
TYPE_PARSER(construct<AssumedShapeSpec>{}(maybe(specificationExpr) / ":"))
|
|
|
|
// R820 deferred-shape-spec -> :
|
|
// deferred-shape-spec-list - just a list of colons
|
|
TYPE_PARSER(construct<DeferredShapeSpecList>{}(
|
|
applyFunction(listLength, nonemptyList(":"_tok))))
|
|
|
|
// R821 assumed-implied-spec -> [lower-bound :] *
|
|
TYPE_PARSER(
|
|
construct<AssumedImpliedSpec>{}(maybe(specificationExpr / ":") / "*"))
|
|
|
|
// R822 assumed-size-spec -> explicit-shape-spec-list , assumed-implied-spec
|
|
TYPE_PARSER(construct<AssumedSizeSpec>{}(
|
|
nonemptyList(explicitShapeSpec) / ",", assumedImpliedSpec))
|
|
|
|
// R823 implied-shape-or-assumed-size-spec -> assumed-implied-spec
|
|
// R824 implied-shape-spec -> assumed-implied-spec , assumed-implied-spec-list
|
|
// I.e., when the assumed-implied-spec-list has a single item, it constitutes an
|
|
// implied-shape-or-assumed-size-spec; otherwise, an implied-shape-spec.
|
|
TYPE_PARSER(construct<ImpliedShapeSpec>{}(nonemptyList(assumedImpliedSpec)))
|
|
|
|
// R825 assumed-rank-spec -> ..
|
|
TYPE_PARSER(".." >> construct<AssumedRankSpec>{})
|
|
|
|
// R826 intent-spec -> IN | OUT | INOUT
|
|
TYPE_PARSER(
|
|
construct<IntentSpec>{}("IN OUT" >> pure(IntentSpec::Intent::InOut) ||
|
|
"IN" >> pure(IntentSpec::Intent::In) ||
|
|
"OUT" >> pure(IntentSpec::Intent::Out)))
|
|
|
|
// R827 access-stmt -> access-spec [[::] access-id-list]
|
|
TYPE_PARSER(construct<AccessStmt>{}(
|
|
accessSpec, defaulted(maybe("::"_tok) >> nonemptyList(Parser<AccessId>{}))))
|
|
|
|
// R828 access-id -> access-name | generic-spec
|
|
TYPE_PARSER(construct<AccessId>{}(indirect(genericSpec)) ||
|
|
construct<AccessId>{}(name)) // initially ambiguous with genericSpec
|
|
|
|
// R829 allocatable-stmt -> ALLOCATABLE [::] allocatable-decl-list
|
|
TYPE_PARSER("ALLOCATABLE" >> maybe("::"_tok) >>
|
|
construct<AllocatableStmt>{}(nonemptyList(Parser<ObjectDecl>{})))
|
|
|
|
// R830 allocatable-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
// R860 target-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
TYPE_PARSER(
|
|
construct<ObjectDecl>{}(objectName, maybe(arraySpec), maybe(coarraySpec)))
|
|
|
|
// R831 asynchronous-stmt -> ASYNCHRONOUS [::] object-name-list
|
|
TYPE_PARSER("ASYNCHRONOUS" >> maybe("::"_tok) >>
|
|
construct<AsynchronousStmt>{}(nonemptyList(objectName)))
|
|
|
|
// R832 bind-stmt -> language-binding-spec [::] bind-entity-list
|
|
TYPE_PARSER(construct<BindStmt>{}(
|
|
languageBindingSpec / maybe("::"_tok), nonemptyList(Parser<BindEntity>{})))
|
|
|
|
// R833 bind-entity -> entity-name | / common-block-name /
|
|
TYPE_PARSER(construct<BindEntity>{}(pure(BindEntity::Kind::Object), name) ||
|
|
"/" >> construct<BindEntity>{}(pure(BindEntity::Kind::Common), name) / "/")
|
|
|
|
// R834 codimension-stmt -> CODIMENSION [::] codimension-decl-list
|
|
TYPE_PARSER("CODIMENSION" >> maybe("::"_tok) >>
|
|
construct<CodimensionStmt>{}(nonemptyList(Parser<CodimensionDecl>{})))
|
|
|
|
// R835 codimension-decl -> coarray-name lbracket coarray-spec rbracket
|
|
TYPE_PARSER(construct<CodimensionDecl>{}(name, coarraySpec))
|
|
|
|
// R836 contiguous-stmt -> CONTIGUOUS [::] object-name-list
|
|
TYPE_PARSER("CONTIGUOUS" >> maybe("::"_tok) >>
|
|
construct<ContiguousStmt>{}(nonemptyList(objectName)))
|
|
|
|
// R837 data-stmt -> DATA data-stmt-set [[,] data-stmt-set]...
|
|
TYPE_CONTEXT_PARSER("DATA statement"_en_US,
|
|
"DATA" >> construct<DataStmt>{}(
|
|
nonemptySeparated(Parser<DataStmtSet>{}, maybe(","_tok))))
|
|
|
|
// R838 data-stmt-set -> data-stmt-object-list / data-stmt-value-list /
|
|
TYPE_PARSER(construct<DataStmtSet>{}(nonemptyList(Parser<DataStmtObject>{}),
|
|
"/"_tok >> nonemptyList(Parser<DataStmtValue>{}) / "/"))
|
|
|
|
// R839 data-stmt-object -> variable | data-implied-do
|
|
TYPE_PARSER(construct<DataStmtObject>{}(indirect(variable)) ||
|
|
construct<DataStmtObject>{}(dataImpliedDo))
|
|
|
|
// R840 data-implied-do ->
|
|
// ( data-i-do-object-list , [integer-type-spec ::] data-i-do-variable
|
|
// = scalar-int-constant-expr , scalar-int-constant-expr
|
|
// [, scalar-int-constant-expr] )
|
|
// R842 data-i-do-variable -> do-variable
|
|
TYPE_PARSER(parenthesized(construct<DataImpliedDo>{}(
|
|
nonemptyList(Parser<DataIDoObject>{} / lookAhead(","_tok)) / ",",
|
|
maybe(integerTypeSpec / "::"), loopBounds(scalarIntConstantExpr))))
|
|
|
|
// R841 data-i-do-object ->
|
|
// array-element | scalar-structure-component | data-implied-do
|
|
TYPE_PARSER(construct<DataIDoObject>{}(scalar(indirect(designator))) ||
|
|
construct<DataIDoObject>{}(indirect(dataImpliedDo)))
|
|
|
|
// R843 data-stmt-value -> [data-stmt-repeat *] data-stmt-constant
|
|
TYPE_PARSER(construct<DataStmtValue>{}(
|
|
maybe(Parser<DataStmtRepeat>{} / "*"), Parser<DataStmtConstant>{}))
|
|
|
|
// R847 constant-subobject -> designator
|
|
// R846 int-constant-subobject -> constant-subobject
|
|
constexpr auto constantSubobject = constant(indirect(designator));
|
|
|
|
// R844 data-stmt-repeat -> scalar-int-constant | scalar-int-constant-subobject
|
|
// R607 int-constant -> constant
|
|
// Factored into:
|
|
// constant -> literal-constant -> int-literal-constant and
|
|
// constant -> named-constant
|
|
TYPE_PARSER(construct<DataStmtRepeat>{}(intLiteralConstant) ||
|
|
construct<DataStmtRepeat>{}(scalar(integer(constantSubobject))) ||
|
|
construct<DataStmtRepeat>{}(scalar(integer(namedConstant))))
|
|
|
|
// R845 data-stmt-constant ->
|
|
// scalar-constant | scalar-constant-subobject |
|
|
// signed-int-literal-constant | signed-real-literal-constant |
|
|
// null-init | initial-data-target | structure-constructor
|
|
// TODO: Some structure constructors can be misrecognized as array
|
|
// references into constant subobjects.
|
|
TYPE_PARSER(construct<DataStmtConstant>{}(scalar(Parser<ConstantValue>{})) ||
|
|
construct<DataStmtConstant>{}(nullInit) ||
|
|
construct<DataStmtConstant>{}(Parser<StructureConstructor>{}) ||
|
|
construct<DataStmtConstant>{}(scalar(constantSubobject)) ||
|
|
construct<DataStmtConstant>{}(signedRealLiteralConstant) ||
|
|
construct<DataStmtConstant>{}(signedIntLiteralConstant) ||
|
|
extension(construct<DataStmtConstant>{}(
|
|
Parser<SignedComplexLiteralConstant>{})) ||
|
|
construct<DataStmtConstant>{}(initialDataTarget))
|
|
|
|
// R848 dimension-stmt ->
|
|
// DIMENSION [::] array-name ( array-spec )
|
|
// [, array-name ( array-spec )]...
|
|
TYPE_CONTEXT_PARSER("DIMENSION statement"_en_US,
|
|
"DIMENSION" >> maybe("::"_tok) >>
|
|
construct<DimensionStmt>{}(nonemptyList(
|
|
construct<DimensionStmt::Declaration>{}(name, arraySpec))))
|
|
|
|
// R849 intent-stmt -> INTENT ( intent-spec ) [::] dummy-arg-name-list
|
|
TYPE_CONTEXT_PARSER("INTENT statement"_en_US,
|
|
"INTENT" >>
|
|
construct<IntentStmt>{}(
|
|
parenthesized(intentSpec) / maybe("::"_tok), nonemptyList(name)))
|
|
|
|
// R850 optional-stmt -> OPTIONAL [::] dummy-arg-name-list
|
|
TYPE_PARSER("OPTIONAL" >> maybe("::"_tok) >>
|
|
construct<OptionalStmt>{}(nonemptyList(name)))
|
|
|
|
// R851 parameter-stmt -> PARAMETER ( named-constant-def-list )
|
|
// Legacy extension: omitted parentheses, no implicit typing from names
|
|
TYPE_CONTEXT_PARSER("PARAMETER statement"_en_US,
|
|
construct<ParameterStmt>{}(
|
|
"PARAMETER" >> parenthesized(nonemptyList(Parser<NamedConstantDef>{}))))
|
|
TYPE_CONTEXT_PARSER("old style PARAMETER statement"_en_US,
|
|
extension(construct<OldParameterStmt>{}(
|
|
"PARAMETER" >> nonemptyList(Parser<NamedConstantDef>{}))))
|
|
|
|
// R852 named-constant-def -> named-constant = constant-expr
|
|
TYPE_PARSER(construct<NamedConstantDef>{}(namedConstant, "=" >> constantExpr))
|
|
|
|
// R853 pointer-stmt -> POINTER [::] pointer-decl-list
|
|
TYPE_PARSER("POINTER" >> maybe("::"_tok) >>
|
|
construct<PointerStmt>{}(nonemptyList(Parser<PointerDecl>{})))
|
|
|
|
// R854 pointer-decl ->
|
|
// object-name [( deferred-shape-spec-list )] | proc-entity-name
|
|
TYPE_PARSER(
|
|
construct<PointerDecl>{}(name, maybe(parenthesized(deferredShapeSpecList))))
|
|
|
|
// R855 protected-stmt -> PROTECTED [::] entity-name-list
|
|
TYPE_PARSER("PROTECTED" >> maybe("::"_tok) >>
|
|
construct<ProtectedStmt>{}(nonemptyList(name)))
|
|
|
|
// R856 save-stmt -> SAVE [[::] saved-entity-list]
|
|
TYPE_PARSER("SAVE" >> construct<SaveStmt>{}(defaulted(maybe("::"_tok) >>
|
|
nonemptyList(Parser<SavedEntity>{}))))
|
|
|
|
// R857 saved-entity -> object-name | proc-pointer-name | / common-block-name /
|
|
// R858 proc-pointer-name -> name
|
|
// TODO: Distinguish Kind::ProcPointer and Kind::Object
|
|
TYPE_PARSER(construct<SavedEntity>{}(pure(SavedEntity::Kind::Object), name) ||
|
|
"/" >>
|
|
construct<SavedEntity>{}(pure(SavedEntity::Kind::Common), name) / "/")
|
|
|
|
// R859 target-stmt -> TARGET [::] target-decl-list
|
|
TYPE_PARSER("TARGET" >> maybe("::"_tok) >>
|
|
construct<TargetStmt>{}(nonemptyList(Parser<ObjectDecl>{})))
|
|
|
|
// R861 value-stmt -> VALUE [::] dummy-arg-name-list
|
|
TYPE_PARSER(
|
|
"VALUE" >> maybe("::"_tok) >> construct<ValueStmt>{}(nonemptyList(name)))
|
|
|
|
// R862 volatile-stmt -> VOLATILE [::] object-name-list
|
|
TYPE_PARSER("VOLATILE" >> maybe("::"_tok) >>
|
|
construct<VolatileStmt>{}(nonemptyList(objectName)))
|
|
|
|
// R866 implicit-name-spec -> EXTERNAL | TYPE
|
|
constexpr auto implicitNameSpec = "EXTERNAL" >>
|
|
pure(ImplicitStmt::ImplicitNoneNameSpec::External) ||
|
|
"TYPE" >> pure(ImplicitStmt::ImplicitNoneNameSpec::Type);
|
|
|
|
// R863 implicit-stmt ->
|
|
// IMPLICIT implicit-spec-list |
|
|
// IMPLICIT NONE [( [implicit-name-spec-list] )]
|
|
TYPE_CONTEXT_PARSER("IMPLICIT statement"_en_US,
|
|
"IMPLICIT" >>
|
|
(construct<ImplicitStmt>{}(nonemptyList(Parser<ImplicitSpec>{})) ||
|
|
construct<ImplicitStmt>{}("NONE" >>
|
|
defaulted(parenthesized(optionalList(implicitNameSpec))))))
|
|
|
|
// R864 implicit-spec -> declaration-type-spec ( letter-spec-list )
|
|
// The variant form of declarationTypeSpec is meant to avoid misrecognition
|
|
// of a letter-spec as a simple parenthesized expression for kind or character
|
|
// length, e.g., PARAMETER(I=5,N=1); IMPLICIT REAL(I-N)(O-Z) vs.
|
|
// IMPLICIT REAL(I-N). The variant form needs to attempt to reparse only
|
|
// types with optional parenthesized kind/length expressions, so derived
|
|
// type specs, DOUBLE PRECISION, and DOUBLE COMPLEX need not be considered.
|
|
constexpr auto noKindSelector = construct<std::optional<KindSelector>>{};
|
|
constexpr auto implicitSpecDeclarationTypeSpecRetry =
|
|
construct<DeclarationTypeSpec>{}(
|
|
"INTEGER" >> construct<IntrinsicTypeSpec>{}(
|
|
construct<IntegerTypeSpec>{}(noKindSelector)) ||
|
|
"REAL" >> construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Real>{}(noKindSelector)) ||
|
|
"COMPLEX" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Complex>{}(noKindSelector)) ||
|
|
"CHARACTER" >> construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Character>{}(
|
|
construct<std::optional<CharSelector>>{})) ||
|
|
"LOGICAL" >>
|
|
construct<IntrinsicTypeSpec>{}(
|
|
construct<IntrinsicTypeSpec::Logical>{}(noKindSelector)));
|
|
|
|
TYPE_PARSER(construct<ImplicitSpec>{}(declarationTypeSpec,
|
|
parenthesized(nonemptyList(Parser<LetterSpec>{}))) ||
|
|
construct<ImplicitSpec>{}(implicitSpecDeclarationTypeSpecRetry,
|
|
parenthesized(nonemptyList(Parser<LetterSpec>{}))))
|
|
|
|
// R865 letter-spec -> letter [- letter]
|
|
TYPE_PARSER(space >> (construct<LetterSpec>{}(letter, maybe("-" >> letter)) ||
|
|
construct<LetterSpec>{}(otherIdChar,
|
|
construct<std::optional<const char *>>{})))
|
|
|
|
// R867 import-stmt ->
|
|
// IMPORT [[::] import-name-list] |
|
|
// IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
|
|
TYPE_CONTEXT_PARSER("IMPORT statement"_en_US,
|
|
"IMPORT" >>
|
|
(construct<ImportStmt>{}(
|
|
", ONLY :" >> pure(ImportStmt::Kind::Only), nonemptyList(name)) ||
|
|
construct<ImportStmt>{}(", NONE" >> pure(ImportStmt::Kind::None)) ||
|
|
construct<ImportStmt>{}(", ALL" >> pure(ImportStmt::Kind::All)) ||
|
|
construct<ImportStmt>{}(maybe("::"_tok) >> optionalList(name))))
|
|
|
|
// R868 namelist-stmt ->
|
|
// NAMELIST / namelist-group-name / namelist-group-object-list
|
|
// [[,] / namelist-group-name / namelist-group-object-list]...
|
|
// R869 namelist-group-object -> variable-name
|
|
TYPE_PARSER("NAMELIST" >>
|
|
construct<NamelistStmt>{}(nonemptySeparated(
|
|
construct<NamelistStmt::Group>{}("/" >> name / "/", nonemptyList(name)),
|
|
maybe(","_tok))))
|
|
|
|
// R870 equivalence-stmt -> EQUIVALENCE equivalence-set-list
|
|
// R871 equivalence-set -> ( equivalence-object , equivalence-object-list )
|
|
TYPE_PARSER("EQUIVALENCE" >>
|
|
construct<EquivalenceStmt>{}(
|
|
nonemptyList(parenthesized(nonemptyList(Parser<EquivalenceObject>{})))))
|
|
|
|
// R872 equivalence-object -> variable-name | array-element | substring
|
|
TYPE_PARSER(construct<EquivalenceObject>{}(indirect(designator)))
|
|
|
|
// R873 common-stmt ->
|
|
// COMMON [/ [common-block-name] /] common-block-object-list
|
|
// [[,] / [common-block-name] / common-block-object-list]...
|
|
TYPE_PARSER(
|
|
"COMMON" >> construct<CommonStmt>{}(maybe("/" >> maybe(name) / "/"),
|
|
nonemptyList(Parser<CommonBlockObject>{}),
|
|
many(maybe(","_tok) >>
|
|
construct<CommonStmt::Block>{}("/" >> maybe(name) / "/",
|
|
nonemptyList(Parser<CommonBlockObject>{})))))
|
|
|
|
// R874 common-block-object -> variable-name [( array-spec )]
|
|
TYPE_PARSER(construct<CommonBlockObject>{}(name, maybe(arraySpec)))
|
|
|
|
// R901 designator -> object-name | array-element | array-section |
|
|
// coindexed-named-object | complex-part-designator |
|
|
// structure-component | substring
|
|
// The Standard's productions for designator and its alternatives are
|
|
// ambiguous without recourse to a symbol table. Many of the alternatives
|
|
// for designator (viz., array-element, coindexed-named-object,
|
|
// and structure-component) are all syntactically just data-ref.
|
|
// What designator boils down to is this:
|
|
// It starts with either a name or a character literal.
|
|
// If it starts with a character literal, it must be a substring.
|
|
// If it starts with a name, it's a sequence of %-separated parts;
|
|
// each part is a name, maybe a (section-subscript-list), and
|
|
// maybe an [image-selector].
|
|
// If it's a substring, it ends with (substring-range).
|
|
TYPE_PARSER(
|
|
construct<Designator>{}(substring) || construct<Designator>{}(dataRef))
|
|
|
|
constexpr struct OldStructureComponentName {
|
|
using resultType = Name;
|
|
static std::optional<Name> Parse(ParseState *state) {
|
|
if (std::optional<Name> n{name.Parse(state)}) {
|
|
if (const auto *user = state->userState()) {
|
|
if (user->IsOldStructureComponent(n->source)) {
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
} oldStructureComponentName;
|
|
|
|
constexpr auto percentOrDot = "%"_tok ||
|
|
// legacy VAX extension for RECORD field access
|
|
extension("."_tok / lookAhead(oldStructureComponentName));
|
|
|
|
// R902 variable -> designator | function-reference
|
|
// This production appears to be left-recursive in the grammar via
|
|
// function-reference -> procedure-designator -> proc-component-ref ->
|
|
// scalar-variable
|
|
// and would be so if we were to allow functions to be called via procedure
|
|
// pointer components within derived type results of other function references
|
|
// (a reasonable extension, esp. in the case of procedure pointer components
|
|
// that are NOPASS). However, Fortran constrains the use of a variable in a
|
|
// proc-component-ref to be a data-ref without coindices (C1027).
|
|
// Some array element references will be misrecognized as function references.
|
|
TYPE_PARSER(construct<Variable>{}(
|
|
indirect(functionReference / !"("_ch) / !percentOrDot) ||
|
|
construct<Variable>{}(indirect(designator)))
|
|
|
|
// R904 logical-variable -> variable
|
|
// Appears only as part of scalar-logical-variable.
|
|
constexpr auto scalarLogicalVariable = scalar(logical(variable));
|
|
|
|
// R905 char-variable -> variable
|
|
constexpr auto charVariable = construct<CharVariable>{}(variable);
|
|
|
|
// R906 default-char-variable -> variable
|
|
// Appears only as part of scalar-default-char-variable.
|
|
constexpr auto scalarDefaultCharVariable = scalar(defaultChar(variable));
|
|
|
|
// R907 int-variable -> variable
|
|
// Appears only as part of scalar-int-variable.
|
|
constexpr auto scalarIntVariable = scalar(integer(variable));
|
|
|
|
// R908 substring -> parent-string ( substring-range )
|
|
// R909 parent-string ->
|
|
// scalar-variable-name | array-element | coindexed-named-object |
|
|
// scalar-structure-component | scalar-char-literal-constant |
|
|
// scalar-named-constant
|
|
TYPE_PARSER(
|
|
construct<Substring>{}(dataRef, parenthesized(Parser<SubstringRange>{})))
|
|
|
|
TYPE_PARSER(construct<CharLiteralConstantSubstring>{}(
|
|
charLiteralConstant, parenthesized(Parser<SubstringRange>{})))
|
|
|
|
// R910 substring-range -> [scalar-int-expr] : [scalar-int-expr]
|
|
TYPE_PARSER(construct<SubstringRange>{}(
|
|
maybe(scalarIntExpr), ":" >> maybe(scalarIntExpr)))
|
|
|
|
// R1003 defined-unary-op -> . letter [letter]... .
|
|
// R1023 defined-binary-op -> . letter [letter]... .
|
|
// R1414 local-defined-operator -> defined-unary-op | defined-binary-op
|
|
// R1415 use-defined-operator -> defined-unary-op | defined-binary-op
|
|
// N.B. The name of the operator is captured without the periods around it.
|
|
TYPE_PARSER(space >> "."_ch >>
|
|
construct<DefinedOpName>{}(sourced(some(letter) >> construct<Name>{})) /
|
|
"."_ch)
|
|
|
|
// R911 data-ref -> part-ref [% part-ref]...
|
|
// R914 coindexed-named-object -> data-ref
|
|
// R917 array-element -> data-ref
|
|
TYPE_PARSER(
|
|
construct<DataRef>{}(nonemptySeparated(Parser<PartRef>{}, percentOrDot)))
|
|
|
|
// R912 part-ref -> part-name [( section-subscript-list )] [image-selector]
|
|
TYPE_PARSER(construct<PartRef>{}(name,
|
|
defaulted(
|
|
parenthesized(nonemptyList(Parser<SectionSubscript>{})) / !"=>"_tok),
|
|
maybe(Parser<ImageSelector>{})))
|
|
|
|
// R913 structure-component -> data-ref
|
|
TYPE_PARSER(construct<StructureComponent>{}(
|
|
construct<DataRef>{}(some(Parser<PartRef>{} / percentOrDot)), name))
|
|
|
|
// R915 complex-part-designator -> designator % RE | designator % IM
|
|
// %RE and %IM are initially recognized as structure components.
|
|
constexpr auto complexPartDesignator =
|
|
construct<ComplexPartDesignator>{}(dataRef);
|
|
|
|
// R916 type-param-inquiry -> designator % type-param-name
|
|
// Type parameter inquiries are initially recognized as structure components.
|
|
TYPE_PARSER(construct<TypeParamInquiry>{}(structureComponent))
|
|
|
|
// R918 array-section ->
|
|
// data-ref [( substring-range )] | complex-part-designator
|
|
constexpr auto arraySection = construct<ArraySection>{}(designator);
|
|
|
|
// R919 subscript -> scalar-int-expr
|
|
constexpr auto subscript = scalarIntExpr;
|
|
|
|
// R923 vector-subscript -> int-expr
|
|
constexpr auto vectorSubscript = intExpr;
|
|
|
|
// R920 section-subscript -> subscript | subscript-triplet | vector-subscript
|
|
// N.B. The distinction that needs to be made between "subscript" and
|
|
// "vector-subscript" is deferred to semantic analysis.
|
|
TYPE_PARSER(construct<SectionSubscript>{}(Parser<SubscriptTriplet>{}) ||
|
|
construct<SectionSubscript>{}(vectorSubscript) ||
|
|
construct<SectionSubscript>{}(subscript))
|
|
|
|
// R921 subscript-triplet -> [subscript] : [subscript] [: stride]
|
|
TYPE_PARSER(construct<SubscriptTriplet>{}(
|
|
maybe(subscript), ":" >> maybe(subscript), maybe(":" >> subscript)))
|
|
|
|
// R925 cosubscript -> scalar-int-expr
|
|
constexpr auto cosubscript = scalarIntExpr;
|
|
|
|
// R924 image-selector ->
|
|
// lbracket cosubscript-list [, image-selector-spec-list] rbracket
|
|
TYPE_PARSER(bracketed(construct<ImageSelector>{}(nonemptyList(cosubscript),
|
|
defaulted("," >> nonemptyList(Parser<ImageSelectorSpec>{})))))
|
|
|
|
// R1115 team-variable -> scalar-variable
|
|
constexpr auto teamVariable = scalar(indirect(variable));
|
|
|
|
// R926 image-selector-spec ->
|
|
// STAT = stat-variable | TEAM = team-variable |
|
|
// TEAM_NUMBER = scalar-int-expr
|
|
TYPE_PARSER("STAT =" >>
|
|
construct<ImageSelectorSpec>{}(construct<ImageSelectorSpec::Stat>{}(
|
|
scalar(integer(indirect(variable))))) ||
|
|
"TEAM =" >> construct<ImageSelectorSpec>{}(
|
|
construct<ImageSelectorSpec::Team>{}(teamVariable)) ||
|
|
"TEAM_NUMBER =" >>
|
|
construct<ImageSelectorSpec>{}(
|
|
construct<ImageSelectorSpec::Team_Number>{}(scalarIntExpr)))
|
|
|
|
// R927 allocate-stmt ->
|
|
// ALLOCATE ( [type-spec ::] allocation-list [, alloc-opt-list] )
|
|
TYPE_CONTEXT_PARSER("ALLOCATE statement"_en_US,
|
|
"ALLOCATE" >>
|
|
parenthesized(construct<AllocateStmt>{}(maybe(typeSpec / "::"),
|
|
nonemptyList(Parser<Allocation>{}),
|
|
defaulted("," >> nonemptyList(Parser<AllocOpt>{})))))
|
|
|
|
// R928 alloc-opt ->
|
|
// ERRMSG = errmsg-variable | MOLD = source-expr |
|
|
// SOURCE = source-expr | STAT = stat-variable
|
|
// R931 source-expr -> expr
|
|
TYPE_PARSER("MOLD =" >>
|
|
construct<AllocOpt>{}(construct<AllocOpt::Mold>{}(indirect(expr))) ||
|
|
"SOURCE =" >>
|
|
construct<AllocOpt>{}(construct<AllocOpt::Source>{}(indirect(expr))) ||
|
|
construct<AllocOpt>{}(statOrErrmsg))
|
|
|
|
// R929 stat-variable -> scalar-int-variable
|
|
TYPE_PARSER(construct<StatVariable>{}(scalar(integer(variable))))
|
|
|
|
// R930 errmsg-variable -> scalar-default-char-variable
|
|
// R1207 iomsg-variable -> scalar-default-char-variable
|
|
constexpr auto msgVariable =
|
|
construct<MsgVariable>{}(scalarDefaultCharVariable);
|
|
|
|
// R932 allocation ->
|
|
// allocate-object [( allocate-shape-spec-list )]
|
|
// [lbracket allocate-coarray-spec rbracket]
|
|
// TODO: allocate-shape-spec-list might be misrecognized as
|
|
// the final list of subscripts in allocate-object.
|
|
TYPE_PARSER(construct<Allocation>{}(Parser<AllocateObject>{},
|
|
defaulted(parenthesized(nonemptyList(Parser<AllocateShapeSpec>{}))),
|
|
maybe(bracketed(Parser<AllocateCoarraySpec>{}))))
|
|
|
|
// R933 allocate-object -> variable-name | structure-component
|
|
TYPE_PARSER(construct<AllocateObject>{}(structureComponent) ||
|
|
construct<AllocateObject>{}(name / !"="_tok))
|
|
|
|
// R935 lower-bound-expr -> scalar-int-expr
|
|
// R936 upper-bound-expr -> scalar-int-expr
|
|
constexpr auto boundExpr = scalarIntExpr;
|
|
|
|
// R934 allocate-shape-spec -> [lower-bound-expr :] upper-bound-expr
|
|
// R938 allocate-coshape-spec -> [lower-bound-expr :] upper-bound-expr
|
|
TYPE_PARSER(construct<AllocateShapeSpec>{}(maybe(boundExpr / ":"), boundExpr))
|
|
|
|
// R937 allocate-coarray-spec ->
|
|
// [allocate-coshape-spec-list ,] [lower-bound-expr :] *
|
|
TYPE_PARSER(construct<AllocateCoarraySpec>{}(
|
|
defaulted(nonemptyList(Parser<AllocateShapeSpec>{}) / ","),
|
|
maybe(boundExpr / ":") / "*"))
|
|
|
|
// R939 nullify-stmt -> NULLIFY ( pointer-object-list )
|
|
TYPE_CONTEXT_PARSER("NULLIFY statement"_en_US,
|
|
"NULLIFY" >> parenthesized(construct<NullifyStmt>{}(
|
|
nonemptyList(Parser<PointerObject>{}))))
|
|
|
|
// R940 pointer-object ->
|
|
// variable-name | structure-component | proc-pointer-name
|
|
TYPE_PARSER(construct<PointerObject>{}(structureComponent) ||
|
|
construct<PointerObject>{}(name))
|
|
|
|
// R941 deallocate-stmt ->
|
|
// DEALLOCATE ( allocate-object-list [, dealloc-opt-list] )
|
|
TYPE_CONTEXT_PARSER("DEALLOCATE statement"_en_US,
|
|
"DEALLOCATE" >> parenthesized(construct<DeallocateStmt>{}(
|
|
nonemptyList(Parser<AllocateObject>{}),
|
|
defaulted("," >> nonemptyList(statOrErrmsg)))))
|
|
|
|
// R942 dealloc-opt -> STAT = stat-variable | ERRMSG = errmsg-variable
|
|
// R1165 sync-stat -> STAT = stat-variable | ERRMSG = errmsg-variable
|
|
TYPE_PARSER("STAT =" >> construct<StatOrErrmsg>{}(statVariable) ||
|
|
"ERRMSG =" >> construct<StatOrErrmsg>{}(msgVariable))
|
|
|
|
// R1001 primary ->
|
|
// literal-constant | designator | array-constructor |
|
|
// structure-constructor | function-reference | type-param-inquiry |
|
|
// type-param-name | ( expr )
|
|
constexpr auto primary =
|
|
construct<Expr>{}(indirect(Parser<CharLiteralConstantSubstring>{})) ||
|
|
construct<Expr>{}(literalConstant) ||
|
|
construct<Expr>{}(construct<Expr::Parentheses>{}(parenthesized(expr))) ||
|
|
construct<Expr>{}(indirect(functionReference) / !"("_tok) ||
|
|
construct<Expr>{}(designator / !"("_tok) ||
|
|
construct<Expr>{}(Parser<StructureConstructor>{}) ||
|
|
construct<Expr>{}(Parser<ArrayConstructor>{}) ||
|
|
construct<Expr>{}(indirect(Parser<TypeParamInquiry>{})) || // occulted
|
|
// PGI/XLF extension: COMPLEX constructor (x,y)
|
|
extension(construct<Expr>{}(parenthesized(
|
|
construct<Expr::ComplexConstructor>{}(expr, "," >> expr)))) ||
|
|
extension(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
|
|
constexpr auto level1Expr = construct<Expr>{}(construct<Expr::DefinedUnary>{}(
|
|
definedOpName, primary)) ||
|
|
primary ||
|
|
extension(
|
|
"+" >> construct<Expr>{}(construct<Expr::UnaryPlus>{}(primary))) ||
|
|
extension("-" >> construct<Expr>{}(construct<Expr::Negate>{}(primary)));
|
|
|
|
// R1004 mult-operand -> level-1-expr [power-op mult-operand]
|
|
// R1007 power-op -> **
|
|
// Exponentiation (**) is Fortran's only right-associative binary operation.
|
|
constexpr struct MultOperand {
|
|
using resultType = Expr;
|
|
constexpr MultOperand() {}
|
|
static std::optional<Expr> Parse(ParseState *);
|
|
} multOperand;
|
|
|
|
std::optional<Expr> MultOperand::Parse(ParseState *state) {
|
|
std::optional<Expr> result{level1Expr.Parse(state)};
|
|
if (result) {
|
|
static constexpr auto op = attempt("**"_tok);
|
|
if (op.Parse(state)) {
|
|
std::function<Expr(Expr &&)> power{[&result](Expr &&right) {
|
|
return Expr{Expr::Power(std::move(result).value(), std::move(right))};
|
|
}};
|
|
return applyLambda(power, multOperand).Parse(state); // right-recursive
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// R1005 add-operand -> [add-operand mult-op] mult-operand
|
|
// R1008 mult-op -> * | /
|
|
// The left recursion in the grammar is implemented iteratively.
|
|
constexpr struct AddOperand {
|
|
using resultType = Expr;
|
|
constexpr AddOperand() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{multOperand.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> multiply{[&result](Expr &&right) {
|
|
return Expr{
|
|
Expr::Multiply(std::move(result).value(), std::move(right))};
|
|
}},
|
|
divide{[&result](Expr &&right) {
|
|
return Expr{
|
|
Expr::Divide(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = "*" >> applyLambda(multiply, multOperand) ||
|
|
"/" >> applyLambda(divide, multOperand);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} addOperand;
|
|
|
|
// R1006 level-2-expr -> [[level-2-expr] add-op] add-operand
|
|
// R1009 add-op -> + | -
|
|
// These are left-recursive productions, implemented iteratively.
|
|
// Note that standard Fortran admits a unary + or - to appear only here,
|
|
// by means of a missing first operand; e.g., 2*-3 is valid in C but not
|
|
// standard Fortran. We accept unary + and - to appear before any primary
|
|
// as an extension.
|
|
constexpr struct Level2Expr {
|
|
using resultType = Expr;
|
|
constexpr Level2Expr() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
static constexpr auto unary =
|
|
"+" >> construct<Expr>{}(construct<Expr::UnaryPlus>{}(addOperand)) ||
|
|
"-" >> construct<Expr>{}(construct<Expr::Negate>{}(addOperand)) ||
|
|
addOperand;
|
|
std::optional<Expr> result{unary.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> add{[&result](Expr &&right) {
|
|
return Expr{Expr::Add(std::move(result).value(), std::move(right))};
|
|
}},
|
|
subtract{[&result](Expr &&right) {
|
|
return Expr{
|
|
Expr::Subtract(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = "+" >> applyLambda(add, addOperand) ||
|
|
"-" >> applyLambda(subtract, addOperand);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} level2Expr;
|
|
|
|
// R1010 level-3-expr -> [level-3-expr concat-op] level-2-expr
|
|
// R1011 concat-op -> //
|
|
// Concatenation (//) is left-associative for parsing performance, although
|
|
// one would never notice if it were right-associated.
|
|
constexpr struct Level3Expr {
|
|
using resultType = Expr;
|
|
constexpr Level3Expr() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{level2Expr.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> concat{[&result](Expr &&right) {
|
|
return Expr{Expr::Concat(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = "//" >> applyLambda(concat, level2Expr);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} level3Expr;
|
|
|
|
// R1012 level-4-expr -> [level-3-expr rel-op] level-3-expr
|
|
// R1013 rel-op ->
|
|
// .EQ. | .NE. | .LT. | .LE. | .GT. | .GE. |
|
|
// == | /= | < | <= | > | >= @ | <>
|
|
// N.B. relations are not recursive (i.e., LOGICAL is not ordered)
|
|
constexpr struct Level4Expr {
|
|
using resultType = Expr;
|
|
constexpr Level4Expr() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{level3Expr.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> lt{[&result](Expr &&right) {
|
|
return Expr{Expr::LT(std::move(result).value(), std::move(right))};
|
|
}},
|
|
le{[&result](Expr &&right) {
|
|
return Expr{Expr::LE(std::move(result).value(), std::move(right))};
|
|
}},
|
|
eq{[&result](Expr &&right) {
|
|
return Expr{Expr::EQ(std::move(result).value(), std::move(right))};
|
|
}},
|
|
ne{[&result](Expr &&right) {
|
|
return Expr{Expr::NE(std::move(result).value(), std::move(right))};
|
|
}},
|
|
ge{[&result](Expr &&right) {
|
|
return Expr{Expr::GE(std::move(result).value(), std::move(right))};
|
|
}},
|
|
gt{[&result](Expr &&right) {
|
|
return Expr{Expr::GT(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = (".LT."_tok || "<"_tok) >> applyLambda(lt, level3Expr) ||
|
|
(".LE."_tok || "<="_tok) >> applyLambda(le, level3Expr) ||
|
|
(".EQ."_tok || "=="_tok) >> applyLambda(eq, level3Expr) ||
|
|
(".NE."_tok || "/="_tok ||
|
|
extension(
|
|
"<>"_tok /* PGI/Cray extension; Cray also has .LG. */)) >>
|
|
applyLambda(ne, level3Expr) ||
|
|
(".GE."_tok || ">="_tok) >> applyLambda(ge, level3Expr) ||
|
|
(".GT."_tok || ">"_tok) >> applyLambda(gt, level3Expr);
|
|
if (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
return next;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} level4Expr;
|
|
|
|
// R1014 and-operand -> [not-op] level-4-expr
|
|
// R1018 not-op -> .NOT.
|
|
// N.B. Fortran's .NOT. binds less tightly than its comparison operators do.
|
|
// PGI/Intel extension: accept multiple .NOT. operators
|
|
constexpr struct AndOperand {
|
|
using resultType = Expr;
|
|
constexpr AndOperand() {}
|
|
static std::optional<Expr> Parse(ParseState *);
|
|
} andOperand;
|
|
|
|
std::optional<Expr> AndOperand::Parse(ParseState *state) {
|
|
static constexpr auto op = attempt(".NOT."_tok);
|
|
int complements{0};
|
|
while (op.Parse(state)) {
|
|
++complements;
|
|
}
|
|
std::optional<Expr> result{level4Expr.Parse(state)};
|
|
if (result.has_value()) {
|
|
while (complements-- > 0) {
|
|
result = Expr{Expr::NOT{std::move(*result)}};
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// R1015 or-operand -> [or-operand and-op] and-operand
|
|
// R1019 and-op -> .AND.
|
|
// .AND. is left-associative
|
|
constexpr struct OrOperand {
|
|
using resultType = Expr;
|
|
constexpr OrOperand() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{andOperand.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> logicalAnd{[&result](Expr &&right) {
|
|
return Expr{Expr::AND(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = ".AND." >> applyLambda(logicalAnd, andOperand);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} orOperand;
|
|
|
|
// R1016 equiv-operand -> [equiv-operand or-op] or-operand
|
|
// R1020 or-op -> .OR.
|
|
// .OR. is left-associative
|
|
static constexpr struct EquivOperand {
|
|
using resultType = Expr;
|
|
constexpr EquivOperand() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{orOperand.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> logicalOr{[&result](Expr &&right) {
|
|
return Expr{Expr::OR(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = ".OR." >> applyLambda(logicalOr, orOperand);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} equivOperand;
|
|
|
|
// R1017 level-5-expr -> [level-5-expr equiv-op] equiv-operand
|
|
// R1021 equiv-op -> .EQV. | .NEQV.
|
|
// Logical equivalence is left-associative.
|
|
// Extension: .XOR. as synonym for .NEQV.
|
|
constexpr struct Level5Expr {
|
|
using resultType = Expr;
|
|
constexpr Level5Expr() {}
|
|
static std::optional<Expr> Parse(ParseState *state) {
|
|
std::optional<Expr> result{equivOperand.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(Expr &&)> eqv{[&result](Expr &&right) {
|
|
return Expr{Expr::EQV(std::move(result).value(), std::move(right))};
|
|
}},
|
|
neqv{[&result](Expr &&right) {
|
|
return Expr{
|
|
Expr::NEQV(std::move(result).value(), std::move(right))};
|
|
}},
|
|
logicalXor{[&result](Expr &&right) {
|
|
return Expr{Expr::XOR(std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = ".EQV." >> applyLambda(eqv, equivOperand) ||
|
|
".NEQV." >> applyLambda(neqv, equivOperand) ||
|
|
extension(".XOR." >> applyLambda(logicalXor, equivOperand));
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} level5Expr;
|
|
|
|
// R1022 expr -> [expr defined-binary-op] level-5-expr
|
|
// Defined binary operators associate leftwards.
|
|
template<> std::optional<Expr> Parser<Expr>::Parse(ParseState *state) {
|
|
std::optional<Expr> result{level5Expr.Parse(state)};
|
|
if (result) {
|
|
std::function<Expr(DefinedOpName &&, Expr &&)> defBinOp{
|
|
[&result](DefinedOpName &&op, Expr &&right) {
|
|
return Expr{Expr::DefinedBinary(
|
|
std::move(op), std::move(result).value(), std::move(right))};
|
|
}};
|
|
auto more = applyLambda(defBinOp, definedOpName, level5Expr);
|
|
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
|
|
result = std::move(next);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// R1028 specification-expr -> scalar-int-expr
|
|
TYPE_PARSER(construct<SpecificationExpr>{}(scalarIntExpr))
|
|
|
|
// R1032 assignment-stmt -> variable = expr
|
|
TYPE_CONTEXT_PARSER("assignment statement"_en_US,
|
|
construct<AssignmentStmt>{}(variable / "=", expr))
|
|
|
|
// R1033 pointer-assignment-stmt ->
|
|
// data-pointer-object [( bounds-spec-list )] => data-target |
|
|
// data-pointer-object ( bounds-remapping-list ) => data-target |
|
|
// proc-pointer-object => proc-target
|
|
// R1034 data-pointer-object ->
|
|
// variable-name | scalar-variable % data-pointer-component-name
|
|
// C1022 a scalar-variable shall be a data-ref
|
|
// C1024 a data-pointer-object shall not be a coindexed object
|
|
// R1038 proc-pointer-object -> proc-pointer-name | proc-component-ref
|
|
//
|
|
// A distinction can't be made at the time of the initial parse between
|
|
// data-pointer-object and proc-pointer-object, or between data-target
|
|
// and proc-target.
|
|
TYPE_CONTEXT_PARSER("pointer assignment statement"_en_US,
|
|
construct<PointerAssignmentStmt>{}(dataRef,
|
|
parenthesized(nonemptyList(Parser<BoundsRemapping>{})), "=>" >> expr) ||
|
|
construct<PointerAssignmentStmt>{}(dataRef,
|
|
defaulted(parenthesized(nonemptyList(Parser<BoundsSpec>{}))),
|
|
"=>" >> expr))
|
|
|
|
// R1035 bounds-spec -> lower-bound-expr :
|
|
TYPE_PARSER(construct<BoundsSpec>{}(boundExpr / ":"))
|
|
|
|
// R1036 bounds-remapping -> lower-bound-expr : upper-bound-expr
|
|
TYPE_PARSER(construct<BoundsRemapping>{}(boundExpr / ":", boundExpr))
|
|
|
|
// R1039 proc-component-ref -> scalar-variable % procedure-component-name
|
|
// C1027 the scalar-variable must be a data-ref without coindices.
|
|
TYPE_PARSER(construct<ProcComponentRef>{}(structureComponent))
|
|
|
|
// R1041 where-stmt -> WHERE ( mask-expr ) where-assignment-stmt
|
|
// R1045 where-assignment-stmt -> assignment-stmt
|
|
// R1046 mask-expr -> logical-expr
|
|
TYPE_CONTEXT_PARSER("WHERE statement"_en_US,
|
|
"WHERE" >>
|
|
construct<WhereStmt>{}(parenthesized(logicalExpr), assignmentStmt))
|
|
|
|
// R1042 where-construct ->
|
|
// where-construct-stmt [where-body-construct]...
|
|
// [masked-elsewhere-stmt [where-body-construct]...]...
|
|
// [elsewhere-stmt [where-body-construct]...] end-where-stmt
|
|
TYPE_CONTEXT_PARSER("WHERE construct"_en_US,
|
|
construct<WhereConstruct>{}(statement(Parser<WhereConstructStmt>{}),
|
|
many(whereBodyConstruct),
|
|
many(construct<WhereConstruct::MaskedElsewhere>{}(
|
|
statement(Parser<MaskedElsewhereStmt>{}),
|
|
many(whereBodyConstruct))),
|
|
maybe(construct<WhereConstruct::Elsewhere>{}(
|
|
statement(Parser<ElsewhereStmt>{}), many(whereBodyConstruct))),
|
|
statement(Parser<EndWhereStmt>{})))
|
|
|
|
// R1043 where-construct-stmt -> [where-construct-name :] WHERE ( mask-expr )
|
|
TYPE_CONTEXT_PARSER("WHERE construct statement"_en_US,
|
|
construct<WhereConstructStmt>{}(
|
|
maybe(name / ":"), "WHERE" >> parenthesized(logicalExpr)))
|
|
|
|
// R1044 where-body-construct ->
|
|
// where-assignment-stmt | where-stmt | where-construct
|
|
TYPE_PARSER(construct<WhereBodyConstruct>{}(statement(assignmentStmt)) ||
|
|
construct<WhereBodyConstruct>{}(statement(whereStmt)) ||
|
|
construct<WhereBodyConstruct>{}(indirect(whereConstruct)))
|
|
|
|
// R1047 masked-elsewhere-stmt ->
|
|
// ELSEWHERE ( mask-expr ) [where-construct-name]
|
|
TYPE_CONTEXT_PARSER("masked ELSEWHERE statement"_en_US,
|
|
"ELSE WHERE" >> construct<MaskedElsewhereStmt>{}(
|
|
parenthesized(logicalExpr), maybe(name)))
|
|
|
|
// R1048 elsewhere-stmt -> ELSEWHERE [where-construct-name]
|
|
TYPE_CONTEXT_PARSER("ELSEWHERE statement"_en_US,
|
|
"ELSE WHERE" >> construct<ElsewhereStmt>{}(maybe(name)))
|
|
|
|
// R1049 end-where-stmt -> ENDWHERE [where-construct-name]
|
|
TYPE_CONTEXT_PARSER("END WHERE statement"_en_US,
|
|
"END WHERE" >> construct<EndWhereStmt>{}(maybe(name)))
|
|
|
|
// R1050 forall-construct ->
|
|
// forall-construct-stmt [forall-body-construct]... end-forall-stmt
|
|
TYPE_CONTEXT_PARSER("FORALL construct"_en_US,
|
|
construct<ForallConstruct>{}(statement(Parser<ForallConstructStmt>{}),
|
|
many(Parser<ForallBodyConstruct>{}),
|
|
statement(Parser<EndForallStmt>{})))
|
|
|
|
// R1051 forall-construct-stmt ->
|
|
// [forall-construct-name :] FORALL concurrent-header
|
|
TYPE_CONTEXT_PARSER("FORALL construct statement"_en_US,
|
|
construct<ForallConstructStmt>{}(
|
|
maybe(name / ":"), "FORALL" >> indirect(concurrentHeader)))
|
|
|
|
// R1052 forall-body-construct ->
|
|
// forall-assignment-stmt | where-stmt | where-construct |
|
|
// forall-construct | forall-stmt
|
|
TYPE_PARSER(construct<ForallBodyConstruct>{}(statement(forallAssignmentStmt)) ||
|
|
construct<ForallBodyConstruct>{}(statement(whereStmt)) ||
|
|
construct<ForallBodyConstruct>{}(whereConstruct) ||
|
|
construct<ForallBodyConstruct>{}(indirect(forallConstruct)) ||
|
|
construct<ForallBodyConstruct>{}(statement(forallStmt)))
|
|
|
|
// R1053 forall-assignment-stmt -> assignment-stmt | pointer-assignment-stmt
|
|
TYPE_PARSER(construct<ForallAssignmentStmt>{}(assignmentStmt) ||
|
|
construct<ForallAssignmentStmt>{}(pointerAssignmentStmt))
|
|
|
|
// R1054 end-forall-stmt -> END FORALL [forall-construct-name]
|
|
TYPE_CONTEXT_PARSER("END FORALL statement"_en_US,
|
|
"END FORALL" >> construct<EndForallStmt>{}(maybe(name)))
|
|
|
|
// R1055 forall-stmt -> FORALL concurrent-header forall-assignment-stmt
|
|
TYPE_CONTEXT_PARSER("FORALL statement"_en_US,
|
|
"FORALL" >> construct<ForallStmt>{}(
|
|
indirect(concurrentHeader), forallAssignmentStmt))
|
|
|
|
// R1101 block -> [execution-part-construct]...
|
|
constexpr auto block = many(executionPartConstruct);
|
|
|
|
// R1102 associate-construct -> associate-stmt block end-associate-stmt
|
|
TYPE_CONTEXT_PARSER("ASSOCIATE construct"_en_US,
|
|
construct<AssociateConstruct>{}(statement(Parser<AssociateStmt>{}), block,
|
|
statement(Parser<EndAssociateStmt>{})))
|
|
|
|
// R1103 associate-stmt ->
|
|
// [associate-construct-name :] ASSOCIATE ( association-list )
|
|
TYPE_CONTEXT_PARSER("ASSOCIATE statement"_en_US,
|
|
construct<AssociateStmt>{}(maybe(name / ":"),
|
|
"ASSOCIATE" >> parenthesized(nonemptyList(Parser<Association>{}))))
|
|
|
|
// R1104 association -> associate-name => selector
|
|
TYPE_PARSER(construct<Association>{}(name, "=>" >> selector))
|
|
|
|
// R1105 selector -> expr | variable
|
|
TYPE_PARSER(construct<Selector>{}(variable) / lookAhead(","_tok || ")"_tok) ||
|
|
construct<Selector>{}(expr))
|
|
|
|
// R1106 end-associate-stmt -> END ASSOCIATE [associate-construct-name]
|
|
TYPE_PARSER("END ASSOCIATE" >> construct<EndAssociateStmt>{}(maybe(name)))
|
|
|
|
// R1107 block-construct ->
|
|
// block-stmt [block-specification-part] block end-block-stmt
|
|
TYPE_CONTEXT_PARSER("BLOCK construct"_en_US,
|
|
construct<BlockConstruct>{}(statement(Parser<BlockStmt>{}),
|
|
Parser<BlockSpecificationPart>{}, // can be empty
|
|
block, statement(Parser<EndBlockStmt>{})))
|
|
|
|
// R1108 block-stmt -> [block-construct-name :] BLOCK
|
|
TYPE_PARSER(construct<BlockStmt>{}(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<BlockSpecificationPart>{}(specificationPart))
|
|
|
|
// R1110 end-block-stmt -> END BLOCK [block-construct-name]
|
|
TYPE_PARSER(construct<EndBlockStmt>{}("END BLOCK" >> maybe(name)))
|
|
|
|
// R1111 change-team-construct -> change-team-stmt block end-change-team-stmt
|
|
TYPE_CONTEXT_PARSER("CHANGE TEAM construct"_en_US,
|
|
construct<ChangeTeamConstruct>{}(statement(Parser<ChangeTeamStmt>{}), block,
|
|
statement(Parser<EndChangeTeamStmt>{})))
|
|
|
|
// R1112 change-team-stmt ->
|
|
// [team-construct-name :] CHANGE TEAM
|
|
// ( team-variable [, coarray-association-list] [, sync-stat-list] )
|
|
TYPE_CONTEXT_PARSER("CHANGE TEAM statement"_en_US,
|
|
construct<ChangeTeamStmt>{}(maybe(name / ":"),
|
|
"CHANGE TEAM"_sptok >> "("_tok >> teamVariable,
|
|
defaulted("," >> nonemptyList(Parser<CoarrayAssociation>{})),
|
|
defaulted("," >> nonemptyList(statOrErrmsg))) /
|
|
")")
|
|
|
|
// R1113 coarray-association -> codimension-decl => selector
|
|
TYPE_PARSER(construct<CoarrayAssociation>{}(
|
|
Parser<CodimensionDecl>{}, "=>" >> selector))
|
|
|
|
// R1114 end-change-team-stmt ->
|
|
// END TEAM [( [sync-stat-list] )] [team-construct-name]
|
|
TYPE_CONTEXT_PARSER("END TEAM statement"_en_US,
|
|
"END TEAM" >>
|
|
construct<EndChangeTeamStmt>{}(
|
|
defaulted(parenthesized(optionalList(statOrErrmsg))), maybe(name)))
|
|
|
|
// R1117 critical-stmt ->
|
|
// [critical-construct-name :] CRITICAL [( [sync-stat-list] )]
|
|
TYPE_CONTEXT_PARSER("CRITICAL statement"_en_US,
|
|
construct<CriticalStmt>{}(maybe(name / ":"),
|
|
"CRITICAL" >> defaulted(parenthesized(optionalList(statOrErrmsg)))))
|
|
|
|
// R1116 critical-construct -> critical-stmt block end-critical-stmt
|
|
TYPE_CONTEXT_PARSER("CRITICAL construct"_en_US,
|
|
construct<CriticalConstruct>{}(statement(Parser<CriticalStmt>{}), block,
|
|
statement(Parser<EndCriticalStmt>{})))
|
|
|
|
// R1118 end-critical-stmt -> END CRITICAL [critical-construct-name]
|
|
TYPE_PARSER("END CRITICAL" >> construct<EndCriticalStmt>{}(maybe(name)))
|
|
|
|
// R1119 do-construct -> do-stmt block end-do
|
|
// R1120 do-stmt -> nonlabel-do-stmt | label-do-stmt
|
|
constexpr struct EnterNonlabelDoConstruct {
|
|
using resultType = Success;
|
|
static std::optional<Success> Parse(ParseState *state) {
|
|
if (auto ustate = state->userState()) {
|
|
ustate->EnterNonlabelDoConstruct();
|
|
}
|
|
return {Success{}};
|
|
}
|
|
} enterNonlabelDoConstruct;
|
|
|
|
constexpr struct LeaveDoConstruct {
|
|
using resultType = Success;
|
|
static std::optional<Success> Parse(ParseState *state) {
|
|
if (auto ustate = state->userState()) {
|
|
ustate->LeaveDoConstruct();
|
|
}
|
|
return {Success{}};
|
|
}
|
|
} leaveDoConstruct;
|
|
|
|
TYPE_CONTEXT_PARSER("DO construct"_en_US,
|
|
construct<DoConstruct>{}(
|
|
statement(Parser<NonLabelDoStmt>{}) / enterNonlabelDoConstruct, block,
|
|
statement(endDoStmt) / leaveDoConstruct))
|
|
|
|
// R1125 concurrent-header ->
|
|
// ( [integer-type-spec ::] concurrent-control-list
|
|
// [, scalar-mask-expr] )
|
|
TYPE_PARSER(parenthesized(construct<ConcurrentHeader>{}(
|
|
maybe(integerTypeSpec / "::"), nonemptyList(Parser<ConcurrentControl>{}),
|
|
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<ConcurrentControl>{}(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(
|
|
"LOCAL" >> construct<LocalitySpec>{}(construct<LocalitySpec::Local>{}(
|
|
parenthesized(nonemptyList(name)))) ||
|
|
"LOCAL INIT"_sptok >>
|
|
construct<LocalitySpec>{}(construct<LocalitySpec::LocalInit>{}(
|
|
parenthesized(nonemptyList(name)))) ||
|
|
"SHARED" >> construct<LocalitySpec>{}(construct<LocalitySpec::Shared>{}(
|
|
parenthesized(nonemptyList(name)))) ||
|
|
"DEFAULT ( NONE )" >>
|
|
construct<LocalitySpec>{}(construct<LocalitySpec::DefaultNone>{}))
|
|
|
|
// 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<LoopControl>{}(loopBounds(scalarIntExpr)) ||
|
|
"WHILE" >>
|
|
construct<LoopControl>{}(parenthesized(scalarLogicalExpr)) ||
|
|
"CONCURRENT" >>
|
|
construct<LoopControl>{}(construct<LoopControl::Concurrent>{}(
|
|
concurrentHeader, many(Parser<LocalitySpec>{})))))
|
|
|
|
// R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
|
|
TYPE_CONTEXT_PARSER("label DO statement"_en_US,
|
|
construct<LabelDoStmt>{}(
|
|
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<NonLabelDoStmt>{}(maybe(name / ":"), "DO" >> maybe(loopControl)))
|
|
|
|
// R1132 end-do-stmt -> END DO [do-construct-name]
|
|
TYPE_CONTEXT_PARSER(
|
|
"END DO statement"_en_US, "END DO" >> construct<EndDoStmt>{}(maybe(name)))
|
|
|
|
// R1133 cycle-stmt -> CYCLE [do-construct-name]
|
|
TYPE_CONTEXT_PARSER(
|
|
"CYCLE statement"_en_US, "CYCLE" >> construct<CycleStmt>{}(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<IfConstruct>{}(
|
|
statement(construct<IfThenStmt>{}(maybe(name / ":"),
|
|
"IF" >> parenthesized(scalarLogicalExpr) / "THEN")),
|
|
block,
|
|
many(construct<IfConstruct::ElseIfBlock>{}(
|
|
statement(construct<ElseIfStmt>{}(
|
|
"ELSE IF" >> parenthesized(scalarLogicalExpr),
|
|
"THEN" >> maybe(name))),
|
|
block)),
|
|
maybe(construct<IfConstruct::ElseBlock>{}(
|
|
statement(construct<ElseStmt>{}("ELSE" >> maybe(name))), block)),
|
|
statement(construct<EndIfStmt>{}("END IF" >> maybe(name)))))
|
|
|
|
// R1139 if-stmt -> IF ( scalar-logical-expr ) action-stmt
|
|
TYPE_CONTEXT_PARSER("IF statement"_en_US,
|
|
"IF" >> construct<IfStmt>{}(parenthesized(scalarLogicalExpr), actionStmt))
|
|
|
|
// R1140 case-construct ->
|
|
// select-case-stmt [case-stmt block]... end-select-stmt
|
|
TYPE_CONTEXT_PARSER("SELECT CASE construct"_en_US,
|
|
construct<CaseConstruct>{}(statement(Parser<SelectCaseStmt>{}),
|
|
many(construct<CaseConstruct::Case>{}(
|
|
statement(Parser<CaseStmt>{}), 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<SelectCaseStmt>{}(
|
|
maybe(name / ":"), "SELECT CASE" >> parenthesized(scalar(expr))))
|
|
|
|
// R1142 case-stmt -> CASE case-selector [case-construct-name]
|
|
TYPE_CONTEXT_PARSER("CASE statement"_en_US,
|
|
"CASE" >> construct<CaseStmt>{}(Parser<CaseSelector>{}, 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("END SELECT" >> construct<EndSelectStmt>{}(maybe(name)))
|
|
|
|
// R1145 case-selector -> ( case-value-range-list ) | DEFAULT
|
|
constexpr auto defaultKeyword = "DEFAULT" >> construct<Default>{};
|
|
TYPE_PARSER(parenthesized(construct<CaseSelector>{}(
|
|
nonemptyList(Parser<CaseValueRange>{}))) ||
|
|
construct<CaseSelector>{}(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<CaseValueRange>{}(construct<CaseValueRange::Range>{}(
|
|
construct<std::optional<CaseValue>>{}(caseValue),
|
|
":" >> maybe(caseValue))) ||
|
|
construct<CaseValueRange>{}(construct<CaseValueRange::Range>{}(
|
|
construct<std::optional<CaseValue>>{},
|
|
":" >> construct<std::optional<CaseValue>>{}(caseValue))) ||
|
|
construct<CaseValueRange>{}(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<SelectRankConstruct>{}(statement(Parser<SelectRankStmt>{}),
|
|
many(construct<SelectRankConstruct::RankCase>{}(
|
|
statement(Parser<SelectRankCaseStmt>{}), block)),
|
|
statement(endSelectStmt)))
|
|
|
|
// R1149 select-rank-stmt ->
|
|
// [select-construct-name :] SELECT RANK
|
|
// ( [associate-name =>] selector )
|
|
TYPE_CONTEXT_PARSER("SELECT RANK statement"_en_US,
|
|
construct<SelectRankStmt>{}(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<SelectRankCaseStmt>{}(
|
|
parenthesized(construct<SelectRankCaseStmt::Rank>{}(
|
|
scalarIntConstantExpr) ||
|
|
construct<SelectRankCaseStmt::Rank>{}(star)) ||
|
|
construct<SelectRankCaseStmt::Rank>{}(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<SelectTypeConstruct>{}(statement(Parser<SelectTypeStmt>{}),
|
|
many(construct<SelectTypeConstruct::TypeCase>{}(
|
|
statement(Parser<TypeGuardStmt>{}), block)),
|
|
statement(endSelectStmt)))
|
|
|
|
// R1153 select-type-stmt ->
|
|
// [select-construct-name :] SELECT TYPE
|
|
// ( [associate-name =>] selector )
|
|
TYPE_CONTEXT_PARSER("SELECT TYPE statement"_en_US,
|
|
construct<SelectTypeStmt>{}(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<TypeGuardStmt>{}("TYPE IS"_sptok >>
|
|
parenthesized(construct<TypeGuardStmt::Guard>{}(typeSpec)) ||
|
|
"CLASS IS"_sptok >> parenthesized(construct<TypeGuardStmt::Guard>{}(
|
|
derivedTypeSpec)) ||
|
|
"CLASS" >> construct<TypeGuardStmt::Guard>{}(defaultKeyword),
|
|
maybe(name)))
|
|
|
|
// R1156 exit-stmt -> EXIT [construct-name]
|
|
TYPE_CONTEXT_PARSER(
|
|
"EXIT statement"_en_US, "EXIT" >> construct<ExitStmt>{}(maybe(name)))
|
|
|
|
// R1157 goto-stmt -> GO TO label
|
|
TYPE_CONTEXT_PARSER(
|
|
"GOTO statement"_en_US, "GO TO" >> construct<GotoStmt>{}(label))
|
|
|
|
// R1158 computed-goto-stmt -> GO TO ( label-list ) [,] scalar-int-expr
|
|
TYPE_CONTEXT_PARSER("computed GOTO statement"_en_US,
|
|
"GO TO" >> construct<ComputedGotoStmt>{}(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<StopStmt>{}("STOP" >> pure(StopStmt::Kind::Stop) ||
|
|
"ERROR STOP"_sptok >> pure(StopStmt::Kind::ErrorStop),
|
|
maybe(Parser<StopCode>{}), maybe(", QUIET =" >> scalarLogicalExpr)))
|
|
|
|
// R1162 stop-code -> scalar-default-char-expr | scalar-int-expr
|
|
TYPE_PARSER(construct<StopCode>{}(scalarDefaultCharExpr) ||
|
|
construct<StopCode>{}(scalarIntExpr))
|
|
|
|
// R1164 sync-all-stmt -> SYNC ALL [( [sync-stat-list] )]
|
|
TYPE_CONTEXT_PARSER("SYNC ALL statement"_en_US,
|
|
"SYNC ALL"_sptok >> construct<SyncAllStmt>{}(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<SyncImagesStmt>{}(
|
|
construct<SyncImagesStmt::ImageSet>{}(intExpr) ||
|
|
construct<SyncImagesStmt::ImageSet>{}(star),
|
|
defaulted("," >> nonemptyList(statOrErrmsg)))))
|
|
|
|
// R1168 sync-memory-stmt -> SYNC MEMORY [( [sync-stat-list] )]
|
|
TYPE_CONTEXT_PARSER("SYNC MEMORY statement"_en_US,
|
|
"SYNC MEMORY"_sptok >> construct<SyncMemoryStmt>{}(defaulted(
|
|
parenthesized(optionalList(statOrErrmsg)))))
|
|
|
|
// R1169 sync-team-stmt -> SYNC TEAM ( team-variable [, sync-stat-list] )
|
|
TYPE_CONTEXT_PARSER("SYNC TEAM statement"_en_US,
|
|
"SYNC TEAM"_sptok >> parenthesized(construct<SyncTeamStmt>{}(teamVariable,
|
|
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,
|
|
"EVENT POST"_sptok >>
|
|
parenthesized(construct<EventPostStmt>{}(
|
|
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,
|
|
"EVENT WAIT"_sptok >>
|
|
parenthesized(construct<EventWaitStmt>{}(scalar(variable),
|
|
defaulted(
|
|
"," >> nonemptyList(Parser<EventWaitStmt::EventWaitSpec>{})))))
|
|
|
|
// 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<EventWaitStmt::EventWaitSpec>{}(untilSpec) ||
|
|
construct<EventWaitStmt::EventWaitSpec>{}(statOrErrmsg))
|
|
|
|
// 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,
|
|
"FORM TEAM"_sptok >>
|
|
parenthesized(construct<FormTeamStmt>{}(scalarIntExpr,
|
|
"," >> teamVariable,
|
|
defaulted(
|
|
"," >> nonemptyList(Parser<FormTeamStmt::FormTeamSpec>{})))))
|
|
|
|
// R1177 form-team-spec -> NEW_INDEX = scalar-int-expr | sync-stat
|
|
TYPE_PARSER(
|
|
"NEW_INDEX =" >> construct<FormTeamStmt::FormTeamSpec>{}(scalarIntExpr) ||
|
|
construct<FormTeamStmt::FormTeamSpec>{}(statOrErrmsg))
|
|
|
|
// R1181 lock-variable -> scalar-variable
|
|
constexpr auto lockVariable = scalar(variable);
|
|
|
|
// R1178 lock-stmt -> LOCK ( lock-variable [, lock-stat-list] )
|
|
TYPE_CONTEXT_PARSER("LOCK statement"_en_US,
|
|
"LOCK" >>
|
|
parenthesized(construct<LockStmt>{}(lockVariable,
|
|
defaulted("," >> nonemptyList(Parser<LockStmt::LockStat>{})))))
|
|
|
|
// R1179 lock-stat -> ACQUIRED_LOCK = scalar-logical-variable | sync-stat
|
|
TYPE_PARSER("ACQUIRED_LOCK =" >>
|
|
construct<LockStmt::LockStat>{}(scalarLogicalVariable) ||
|
|
construct<LockStmt::LockStat>{}(statOrErrmsg))
|
|
|
|
// R1180 unlock-stmt -> UNLOCK ( lock-variable [, sync-stat-list] )
|
|
TYPE_CONTEXT_PARSER("UNLOCK statement"_en_US,
|
|
"UNLOCK" >> parenthesized(construct<UnlockStmt>{}(lockVariable,
|
|
defaulted("," >> nonemptyList(statOrErrmsg)))))
|
|
|
|
// R1201 io-unit -> file-unit-number | * | internal-file-variable
|
|
// R1203 internal-file-variable -> char-variable
|
|
TYPE_PARSER(construct<IoUnit>{}(fileUnitNumber) || construct<IoUnit>{}(star) ||
|
|
construct<IoUnit>{}(charVariable / !"="_tok))
|
|
|
|
// R1202 file-unit-number -> scalar-int-expr
|
|
TYPE_PARSER(construct<FileUnitNumber>{}(scalarIntExpr / !"="_tok))
|
|
|
|
// R1204 open-stmt -> OPEN ( connect-spec-list )
|
|
TYPE_CONTEXT_PARSER("OPEN statement"_en_US,
|
|
"OPEN" >> parenthesized(
|
|
construct<OpenStmt>{}(nonemptyList(Parser<ConnectSpec>{}))))
|
|
|
|
// R1206 file-name-expr -> scalar-default-char-expr
|
|
constexpr auto fileNameExpr = scalarDefaultCharExpr;
|
|
|
|
// R1205 connect-spec ->
|
|
// [UNIT =] file-unit-number | ACCESS = scalar-default-char-expr |
|
|
// ACTION = scalar-default-char-expr |
|
|
// ASYNCHRONOUS = scalar-default-char-expr |
|
|
// BLANK = scalar-default-char-expr |
|
|
// DECIMAL = scalar-default-char-expr |
|
|
// DELIM = scalar-default-char-expr |
|
|
// ENCODING = scalar-default-char-expr | ERR = label |
|
|
// FILE = file-name-expr | FORM = scalar-default-char-expr |
|
|
// IOMSG = iomsg-variable | IOSTAT = scalar-int-variable |
|
|
// NEWUNIT = scalar-int-variable | PAD = scalar-default-char-expr |
|
|
// POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
|
|
// ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
|
|
// STATUS = scalar-default-char-expr
|
|
constexpr auto statusExpr = construct<StatusExpr>{}(scalarDefaultCharExpr);
|
|
constexpr auto errLabel = construct<ErrLabel>{}(label);
|
|
|
|
TYPE_PARSER(maybe("UNIT ="_tok) >> construct<ConnectSpec>{}(fileUnitNumber) ||
|
|
"ACCESS =" >> construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Access),
|
|
scalarDefaultCharExpr)) ||
|
|
"ACTION =" >> construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Action),
|
|
scalarDefaultCharExpr)) ||
|
|
"ASYNCHRONOUS =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Asynchronous),
|
|
scalarDefaultCharExpr)) ||
|
|
"BLANK =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Blank), scalarDefaultCharExpr)) ||
|
|
"DECIMAL =" >> construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Decimal),
|
|
scalarDefaultCharExpr)) ||
|
|
"DELIM =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Delim), scalarDefaultCharExpr)) ||
|
|
"ENCODING =" >> construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Encoding),
|
|
scalarDefaultCharExpr)) ||
|
|
"ERR =" >> construct<ConnectSpec>{}(errLabel) ||
|
|
"FILE =" >> construct<ConnectSpec>{}(fileNameExpr) ||
|
|
extension("NAME =" >> construct<ConnectSpec>{}(fileNameExpr)) ||
|
|
"FORM =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Form), scalarDefaultCharExpr)) ||
|
|
"IOMSG =" >> construct<ConnectSpec>{}(msgVariable) ||
|
|
"IOSTAT =" >> construct<ConnectSpec>{}(statVariable) ||
|
|
"NEWUNIT =" >> construct<ConnectSpec>{}(construct<ConnectSpec::Newunit>{}(
|
|
scalar(integer(variable)))) ||
|
|
"PAD =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Pad), scalarDefaultCharExpr)) ||
|
|
"POSITION =" >> construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Position),
|
|
scalarDefaultCharExpr)) ||
|
|
"RECL =" >> construct<ConnectSpec>{}(
|
|
construct<ConnectSpec::Recl>{}(scalarIntExpr)) ||
|
|
"ROUND =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Round), scalarDefaultCharExpr)) ||
|
|
"SIGN =" >>
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
pure(ConnectSpec::CharExpr::Kind::Sign), scalarDefaultCharExpr)) ||
|
|
"STATUS =" >> construct<ConnectSpec>{}(statusExpr) ||
|
|
extension(construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
"CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert),
|
|
scalarDefaultCharExpr)) ||
|
|
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
|
|
"DISPOSE =" >> pure(ConnectSpec::CharExpr::Kind::Dispose),
|
|
scalarDefaultCharExpr))))
|
|
|
|
// R1209 close-spec ->
|
|
// [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
|
|
// IOMSG = iomsg-variable | ERR = label |
|
|
// STATUS = scalar-default-char-expr
|
|
constexpr auto closeSpec = maybe("UNIT ="_tok) >>
|
|
construct<CloseStmt::CloseSpec>{}(fileUnitNumber) ||
|
|
"IOSTAT =" >> construct<CloseStmt::CloseSpec>{}(statVariable) ||
|
|
"IOMSG =" >> construct<CloseStmt::CloseSpec>{}(msgVariable) ||
|
|
"ERR =" >> construct<CloseStmt::CloseSpec>{}(errLabel) ||
|
|
"STATUS =" >> construct<CloseStmt::CloseSpec>{}(statusExpr);
|
|
|
|
// R1208 close-stmt -> CLOSE ( close-spec-list )
|
|
TYPE_CONTEXT_PARSER("CLOSE statement"_en_US,
|
|
"CLOSE" >> construct<CloseStmt>{}(parenthesized(nonemptyList(closeSpec))))
|
|
|
|
// R1210 read-stmt ->
|
|
// READ ( io-control-spec-list ) [input-item-list] |
|
|
// READ format [, input-item-list]
|
|
constexpr auto inputItemList =
|
|
extension(some("," >> inputItem)) || // legacy extension: leading comma
|
|
optionalList(inputItem);
|
|
|
|
TYPE_CONTEXT_PARSER("READ statement"_en_US,
|
|
"READ" >>
|
|
("(" >> construct<ReadStmt>{}(construct<std::optional<IoUnit>>{}(
|
|
maybe("UNIT ="_tok) >> ioUnit),
|
|
"," >> construct<std::optional<Format>>{}(format),
|
|
defaulted("," >> nonemptyList(ioControlSpec)) / ")",
|
|
inputItemList) ||
|
|
"(" >> construct<ReadStmt>{}(
|
|
construct<std::optional<IoUnit>>{}(ioUnit),
|
|
construct<std::optional<Format>>{},
|
|
defaulted("," >> nonemptyList(ioControlSpec)) / ")",
|
|
inputItemList) ||
|
|
construct<ReadStmt>{}(construct<std::optional<IoUnit>>{},
|
|
construct<std::optional<Format>>{},
|
|
parenthesized(nonemptyList(ioControlSpec)), inputItemList) ||
|
|
construct<ReadStmt>{}(construct<std::optional<IoUnit>>{},
|
|
construct<std::optional<Format>>{}(format),
|
|
construct<std::list<IoControlSpec>>{}, many("," >> inputItem))))
|
|
|
|
// R1214 id-variable -> scalar-int-variable
|
|
constexpr auto idVariable = construct<IdVariable>{}(scalarIntVariable);
|
|
|
|
// R1213 io-control-spec ->
|
|
// [UNIT =] io-unit | [FMT =] format | [NML =] namelist-group-name |
|
|
// ADVANCE = scalar-default-char-expr |
|
|
// ASYNCHRONOUS = scalar-default-char-constant-expr |
|
|
// BLANK = scalar-default-char-expr |
|
|
// DECIMAL = scalar-default-char-expr |
|
|
// DELIM = scalar-default-char-expr | END = label | EOR = label |
|
|
// ERR = label | ID = id-variable | IOMSG = iomsg-variable |
|
|
// IOSTAT = scalar-int-variable | PAD = scalar-default-char-expr |
|
|
// POS = scalar-int-expr | REC = scalar-int-expr |
|
|
// ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
|
|
// SIZE = scalar-int-variable
|
|
constexpr auto endLabel = construct<EndLabel>{}(label);
|
|
constexpr auto eorLabel = construct<EorLabel>{}(label);
|
|
TYPE_PARSER("UNIT =" >> construct<IoControlSpec>{}(ioUnit) ||
|
|
"FMT =" >> construct<IoControlSpec>{}(format) ||
|
|
"NML =" >> construct<IoControlSpec>{}(name) ||
|
|
"ADVANCE =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Advance),
|
|
scalarDefaultCharExpr)) ||
|
|
"ASYNCHRONOUS =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::Asynchronous>{}(
|
|
scalarDefaultCharConstantExpr)) ||
|
|
"BLANK =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Blank),
|
|
scalarDefaultCharExpr)) ||
|
|
"DECIMAL =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Decimal),
|
|
scalarDefaultCharExpr)) ||
|
|
"DELIM =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Delim),
|
|
scalarDefaultCharExpr)) ||
|
|
"END =" >> construct<IoControlSpec>{}(endLabel) ||
|
|
"EOR =" >> construct<IoControlSpec>{}(eorLabel) ||
|
|
"ERR =" >> construct<IoControlSpec>{}(errLabel) ||
|
|
"ID =" >> construct<IoControlSpec>{}(idVariable) ||
|
|
"IOMSG = " >> construct<IoControlSpec>{}(msgVariable) ||
|
|
"IOSTAT = " >> construct<IoControlSpec>{}(statVariable) ||
|
|
"PAD =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Pad), scalarDefaultCharExpr)) ||
|
|
"POS =" >> construct<IoControlSpec>{}(
|
|
construct<IoControlSpec::Pos>{}(scalarIntExpr)) ||
|
|
"REC =" >> construct<IoControlSpec>{}(
|
|
construct<IoControlSpec::Rec>{}(scalarIntExpr)) ||
|
|
"ROUND =" >>
|
|
construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Round),
|
|
scalarDefaultCharExpr)) ||
|
|
"SIGN =" >> construct<IoControlSpec>{}(construct<IoControlSpec::CharExpr>{}(
|
|
pure(IoControlSpec::CharExpr::Kind::Sign),
|
|
scalarDefaultCharExpr)) ||
|
|
"SIZE =" >> construct<IoControlSpec>{}(
|
|
construct<IoControlSpec::Size>{}(scalarIntVariable)))
|
|
|
|
// R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
|
|
constexpr auto outputItemList =
|
|
extension(some("," >> outputItem)) || // legacy: allow leading comma
|
|
optionalList(outputItem);
|
|
|
|
TYPE_CONTEXT_PARSER("WRITE statement"_en_US,
|
|
"WRITE" >>
|
|
(construct<WriteStmt>{}("(" >> construct<std::optional<IoUnit>>{}(
|
|
maybe("UNIT ="_tok) >> ioUnit),
|
|
"," >> construct<std::optional<Format>>{}(format),
|
|
defaulted("," >> nonemptyList(ioControlSpec)) / ")",
|
|
outputItemList) ||
|
|
construct<WriteStmt>{}(
|
|
"(" >> construct<std::optional<IoUnit>>{}(ioUnit),
|
|
construct<std::optional<Format>>{},
|
|
defaulted("," >> nonemptyList(ioControlSpec)) / ")",
|
|
outputItemList) ||
|
|
construct<WriteStmt>{}(construct<std::optional<IoUnit>>{},
|
|
construct<std::optional<Format>>{},
|
|
parenthesized(nonemptyList(ioControlSpec)), outputItemList)))
|
|
|
|
// R1212 print-stmt PRINT format [, output-item-list]
|
|
TYPE_CONTEXT_PARSER("PRINT statement"_en_US,
|
|
"PRINT" >> construct<PrintStmt>{}(
|
|
format, defaulted("," >> nonemptyList(outputItem))))
|
|
|
|
// R1215 format -> default-char-expr | label | *
|
|
TYPE_PARSER(construct<Format>{}(defaultCharExpr / !"="_tok) ||
|
|
construct<Format>{}(label) || construct<Format>{}(star))
|
|
|
|
// R1216 input-item -> variable | io-implied-do
|
|
TYPE_PARSER(construct<InputItem>{}(variable) ||
|
|
construct<InputItem>{}(indirect(inputImpliedDo)))
|
|
|
|
// R1217 output-item -> expr | io-implied-do
|
|
TYPE_PARSER(construct<OutputItem>{}(expr) ||
|
|
construct<OutputItem>{}(indirect(outputImpliedDo)))
|
|
|
|
// R1220 io-implied-do-control ->
|
|
// do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr]
|
|
constexpr auto ioImpliedDoControl = loopBounds(scalarIntExpr);
|
|
|
|
// R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control )
|
|
// R1219 io-implied-do-object -> input-item | output-item
|
|
TYPE_CONTEXT_PARSER("input implied DO"_en_US,
|
|
parenthesized(construct<InputImpliedDo>{}(
|
|
nonemptyList(inputItem / lookAhead(","_tok)),
|
|
"," >> ioImpliedDoControl)))
|
|
TYPE_CONTEXT_PARSER("output implied DO"_en_US,
|
|
parenthesized(construct<OutputImpliedDo>{}(
|
|
nonemptyList(outputItem / lookAhead(","_tok)),
|
|
"," >> ioImpliedDoControl)))
|
|
|
|
// R1222 wait-stmt -> WAIT ( wait-spec-list )
|
|
TYPE_CONTEXT_PARSER("WAIT statement"_en_US,
|
|
"WAIT" >>
|
|
parenthesized(construct<WaitStmt>{}(nonemptyList(Parser<WaitSpec>{}))))
|
|
|
|
// R1223 wait-spec ->
|
|
// [UNIT =] file-unit-number | END = label | EOR = label | ERR = label |
|
|
// ID = scalar-int-expr | IOMSG = iomsg-variable |
|
|
// IOSTAT = scalar-int-variable
|
|
constexpr auto idExpr = construct<IdExpr>{}(scalarIntExpr);
|
|
|
|
TYPE_PARSER(maybe("UNIT ="_tok) >> construct<WaitSpec>{}(fileUnitNumber) ||
|
|
"END =" >> construct<WaitSpec>{}(endLabel) ||
|
|
"EOR =" >> construct<WaitSpec>{}(eorLabel) ||
|
|
"ERR =" >> construct<WaitSpec>{}(errLabel) ||
|
|
"ID =" >> construct<WaitSpec>{}(idExpr) ||
|
|
"IOMSG =" >> construct<WaitSpec>{}(msgVariable) ||
|
|
"IOSTAT =" >> construct<WaitSpec>{}(statVariable))
|
|
|
|
template<typename A> std::list<A> singletonList(A &&x) {
|
|
std::list<A> result;
|
|
result.push_front(std::move(x));
|
|
return result;
|
|
}
|
|
constexpr auto bareUnitNumberAsList =
|
|
applyFunction(singletonList<PositionOrFlushSpec>,
|
|
construct<PositionOrFlushSpec>{}(fileUnitNumber));
|
|
constexpr auto positionOrFlushSpecList =
|
|
parenthesized(nonemptyList(positionOrFlushSpec)) || bareUnitNumberAsList;
|
|
|
|
// R1224 backspace-stmt ->
|
|
// BACKSPACE file-unit-number | BACKSPACE ( position-spec-list )
|
|
TYPE_CONTEXT_PARSER("BACKSPACE statement"_en_US,
|
|
construct<BackspaceStmt>{}("BACKSPACE" >> positionOrFlushSpecList))
|
|
|
|
// R1225 endfile-stmt ->
|
|
// ENDFILE file-unit-number | ENDFILE ( position-spec-list )
|
|
TYPE_CONTEXT_PARSER("ENDFILE statement"_en_US,
|
|
construct<EndfileStmt>{}("ENDFILE" >> positionOrFlushSpecList))
|
|
|
|
// R1226 rewind-stmt -> REWIND file-unit-number | REWIND ( position-spec-list )
|
|
TYPE_CONTEXT_PARSER("REWIND statement"_en_US,
|
|
construct<RewindStmt>{}("REWIND" >> positionOrFlushSpecList))
|
|
|
|
// R1227 position-spec ->
|
|
// [UNIT =] file-unit-number | IOMSG = iomsg-variable |
|
|
// IOSTAT = scalar-int-variable | ERR = label
|
|
// R1229 flush-spec ->
|
|
// [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
|
|
// IOMSG = iomsg-variable | ERR = label
|
|
TYPE_PARSER(
|
|
maybe("UNIT ="_tok) >> construct<PositionOrFlushSpec>{}(fileUnitNumber) ||
|
|
"IOMSG =" >> construct<PositionOrFlushSpec>{}(msgVariable) ||
|
|
"IOSTAT =" >> construct<PositionOrFlushSpec>{}(statVariable) ||
|
|
"ERR =" >> construct<PositionOrFlushSpec>{}(errLabel))
|
|
|
|
// R1228 flush-stmt -> FLUSH file-unit-number | FLUSH ( flush-spec-list )
|
|
TYPE_CONTEXT_PARSER("FLUSH statement"_en_US,
|
|
construct<FlushStmt>{}("FLUSH" >> positionOrFlushSpecList))
|
|
|
|
// R1231 inquire-spec ->
|
|
// [UNIT =] file-unit-number | FILE = file-name-expr |
|
|
// ACCESS = scalar-default-char-variable |
|
|
// ACTION = scalar-default-char-variable |
|
|
// ASYNCHRONOUS = scalar-default-char-variable |
|
|
// BLANK = scalar-default-char-variable |
|
|
// DECIMAL = scalar-default-char-variable |
|
|
// DELIM = scalar-default-char-variable |
|
|
// ENCODING = scalar-default-char-variable |
|
|
// ERR = label | EXIST = scalar-logical-variable |
|
|
// FORM = scalar-default-char-variable |
|
|
// FORMATTED = scalar-default-char-variable |
|
|
// ID = scalar-int-expr | IOMSG = iomsg-variable |
|
|
// IOSTAT = scalar-int-variable |
|
|
// NAME = scalar-default-char-variable |
|
|
// NAMED = scalar-logical-variable |
|
|
// NEXTREC = scalar-int-variable | NUMBER = scalar-int-variable |
|
|
// OPENED = scalar-logical-variable |
|
|
// PAD = scalar-default-char-variable |
|
|
// PENDING = scalar-logical-variable | POS = scalar-int-variable |
|
|
// POSITION = scalar-default-char-variable |
|
|
// READ = scalar-default-char-variable |
|
|
// READWRITE = scalar-default-char-variable |
|
|
// RECL = scalar-int-variable | ROUND = scalar-default-char-variable |
|
|
// SEQUENTIAL = scalar-default-char-variable |
|
|
// SIGN = scalar-default-char-variable |
|
|
// SIZE = scalar-int-variable |
|
|
// STREAM = scalar-default-char-variable |
|
|
// STATUS = scalar-default-char-variable |
|
|
// WRITE = scalar-default-char-variable
|
|
TYPE_PARSER(maybe("UNIT ="_tok) >> construct<InquireSpec>{}(fileUnitNumber) ||
|
|
"FILE =" >> construct<InquireSpec>{}(fileNameExpr) ||
|
|
"ACCESS =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Access),
|
|
scalarDefaultCharVariable)) ||
|
|
"ACTION =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Action),
|
|
scalarDefaultCharVariable)) ||
|
|
"ASYNCHRONOUS =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Asynchronous),
|
|
scalarDefaultCharVariable)) ||
|
|
"BLANK =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Blank),
|
|
scalarDefaultCharVariable)) ||
|
|
"DECIMAL =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Decimal),
|
|
scalarDefaultCharVariable)) ||
|
|
"DELIM =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Delim),
|
|
scalarDefaultCharVariable)) ||
|
|
"DIRECT =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Direct),
|
|
scalarDefaultCharVariable)) ||
|
|
"ENCODING =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Encoding),
|
|
scalarDefaultCharVariable)) ||
|
|
"ERR =" >> construct<InquireSpec>{}(errLabel) ||
|
|
"EXIST =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::LogVar>{}(
|
|
pure(InquireSpec::LogVar::Kind::Exist), scalarLogicalVariable)) ||
|
|
"FORM =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Form),
|
|
scalarDefaultCharVariable)) ||
|
|
"FORMATTED =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Formatted),
|
|
scalarDefaultCharVariable)) ||
|
|
"ID =" >> construct<InquireSpec>{}(idExpr) ||
|
|
"IOMSG =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Iomsg),
|
|
scalarDefaultCharVariable)) ||
|
|
"IOSTAT =" >> construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Iostat),
|
|
scalar(integer(variable)))) ||
|
|
"NAME =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Name),
|
|
scalarDefaultCharVariable)) ||
|
|
"NAMED =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::LogVar>{}(
|
|
pure(InquireSpec::LogVar::Kind::Named), scalarLogicalVariable)) ||
|
|
"NEXTREC =" >> construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Nextrec),
|
|
scalar(integer(variable)))) ||
|
|
"NUMBER =" >> construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Number),
|
|
scalar(integer(variable)))) ||
|
|
"OPENED =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::LogVar>{}(
|
|
pure(InquireSpec::LogVar::Kind::Opened), scalarLogicalVariable)) ||
|
|
"PAD =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Pad),
|
|
scalarDefaultCharVariable)) ||
|
|
"PENDING =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::LogVar>{}(
|
|
pure(InquireSpec::LogVar::Kind::Pending), scalarLogicalVariable)) ||
|
|
"POS =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Pos), scalar(integer(variable)))) ||
|
|
"POSITION =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Position),
|
|
scalarDefaultCharVariable)) ||
|
|
"READ =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Read),
|
|
scalarDefaultCharVariable)) ||
|
|
"READWRITE =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Readwrite),
|
|
scalarDefaultCharVariable)) ||
|
|
"RECL =" >> construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Recl),
|
|
scalar(integer(variable)))) ||
|
|
"ROUND =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Round),
|
|
scalarDefaultCharVariable)) ||
|
|
"SEQUENTIAL =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Sequential),
|
|
scalarDefaultCharVariable)) ||
|
|
"SIGN =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Sign),
|
|
scalarDefaultCharVariable)) ||
|
|
"SIZE =" >> construct<InquireSpec>{}(construct<InquireSpec::IntVar>{}(
|
|
pure(InquireSpec::IntVar::Kind::Size),
|
|
scalar(integer(variable)))) ||
|
|
"STREAM =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Stream),
|
|
scalarDefaultCharVariable)) ||
|
|
"STATUS =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Status),
|
|
scalarDefaultCharVariable)) ||
|
|
"UNFORMATTED =" >>
|
|
construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Unformatted),
|
|
scalarDefaultCharVariable)) ||
|
|
"WRITE =" >> construct<InquireSpec>{}(construct<InquireSpec::CharVar>{}(
|
|
pure(InquireSpec::CharVar::Kind::Write),
|
|
scalarDefaultCharVariable)))
|
|
|
|
// R1230 inquire-stmt ->
|
|
// INQUIRE ( inquire-spec-list ) |
|
|
// INQUIRE ( IOLENGTH = scalar-int-variable ) output-item-list
|
|
TYPE_CONTEXT_PARSER("INQUIRE statement"_en_US,
|
|
"INQUIRE" >>
|
|
(construct<InquireStmt>{}(
|
|
parenthesized(nonemptyList(Parser<InquireSpec>{}))) ||
|
|
construct<InquireStmt>{}(construct<InquireStmt::Iolength>{}(
|
|
parenthesized("IOLENGTH =" >> scalar(integer(variable))),
|
|
nonemptyList(outputItem)))))
|
|
|
|
// R1301 format-stmt -> FORMAT format-specification
|
|
TYPE_CONTEXT_PARSER("FORMAT statement"_en_US,
|
|
"FORMAT" >> construct<FormatStmt>{}(Parser<format::FormatSpecification>{}))
|
|
|
|
// R1321 char-string-edit-desc
|
|
// N.B. C1313 disallows any kind parameter on the character literal.
|
|
constexpr auto charStringEditDesc = space >>
|
|
(charLiteralConstantWithoutKind || rawHollerithLiteral);
|
|
|
|
// R1303 format-items -> format-item [[,] format-item]...
|
|
constexpr auto formatItems =
|
|
nonemptySeparated(space >> Parser<format::FormatItem>{}, maybe(","_tok));
|
|
|
|
// R1306 r -> digit-string
|
|
constexpr auto repeat = space >> digitString;
|
|
|
|
// R1304 format-item ->
|
|
// [r] data-edit-desc | control-edit-desc | char-string-edit-desc |
|
|
// [r] ( format-items )
|
|
TYPE_PARSER(construct<format::FormatItem>{}(
|
|
maybe(repeat), Parser<format::IntrinsicTypeDataEditDesc>{}) ||
|
|
construct<format::FormatItem>{}(
|
|
maybe(repeat), Parser<format::DerivedTypeDataEditDesc>{}) ||
|
|
construct<format::FormatItem>{}(Parser<format::ControlEditDesc>{}) ||
|
|
construct<format::FormatItem>{}(charStringEditDesc) ||
|
|
construct<format::FormatItem>{}(maybe(repeat), parenthesized(formatItems)))
|
|
|
|
// R1302 format-specification ->
|
|
// ( [format-items] ) | ( [format-items ,] unlimited-format-item )
|
|
// R1305 unlimited-format-item -> * ( format-items )
|
|
TYPE_PARSER(parenthesized(
|
|
construct<format::FormatSpecification>{}(
|
|
defaulted(formatItems / ","), "*" >> parenthesized(formatItems)) ||
|
|
construct<format::FormatSpecification>{}(defaulted(formatItems))))
|
|
// R1308 w -> digit-string
|
|
// R1309 m -> digit-string
|
|
// R1310 d -> digit-string
|
|
// R1311 e -> digit-string
|
|
constexpr auto width = repeat;
|
|
constexpr auto mandatoryWidth = construct<std::optional<int>>{}(width);
|
|
constexpr auto digits = repeat;
|
|
constexpr auto noInt = construct<std::optional<int>>{};
|
|
constexpr auto mandatoryDigits = "." >> construct<std::optional<int>>{}(width);
|
|
|
|
// R1307 data-edit-desc ->
|
|
// I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d |
|
|
// E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] |
|
|
// G w [. d [E e]] | L w | A [w] | D w . d |
|
|
// DT [char-literal-constant] [( v-list )]
|
|
// (part 1 of 2)
|
|
TYPE_PARSER(
|
|
construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"I"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
|
|
"B"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) ||
|
|
"O"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) ||
|
|
"Z"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z),
|
|
mandatoryWidth, maybe("." >> digits), noInt) ||
|
|
construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"F"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) ||
|
|
"D"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::D),
|
|
mandatoryWidth, mandatoryDigits, noInt) ||
|
|
construct<format::IntrinsicTypeDataEditDesc>{}("E"_ch >>
|
|
("N"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) ||
|
|
"S"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) ||
|
|
"X"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) ||
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::E)),
|
|
mandatoryWidth, mandatoryDigits, maybe("E"_ch >> digits)) ||
|
|
construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"G"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::G),
|
|
mandatoryWidth, mandatoryDigits, maybe("E"_ch >> digits)) ||
|
|
construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"G"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) ||
|
|
"L"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::L),
|
|
mandatoryWidth, noInt, noInt) ||
|
|
construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"A"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::A),
|
|
maybe(width), noInt, noInt) ||
|
|
// PGI/Intel extension: omitting width (and all else that follows)
|
|
extension(construct<format::IntrinsicTypeDataEditDesc>{}(
|
|
"I"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) ||
|
|
("B"_ch / !letter /* don't occlude BN & BZ */) >>
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::B) ||
|
|
"O"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) ||
|
|
"Z"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z) ||
|
|
"F"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) ||
|
|
("D"_ch / !letter /* don't occlude DC & DP */) >>
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::D) ||
|
|
"E"_ch >>
|
|
("N"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) ||
|
|
"S"_ch >>
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::ES) ||
|
|
"X"_ch >>
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::EX) ||
|
|
pure(format::IntrinsicTypeDataEditDesc::Kind::E)) ||
|
|
"G"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) ||
|
|
"L"_ch >> pure(format::IntrinsicTypeDataEditDesc::Kind::L),
|
|
noInt, noInt, noInt)))
|
|
|
|
// R1307 data-edit-desc (part 2 of 2)
|
|
// R1312 v -> [sign] digit-string
|
|
TYPE_PARSER("D"_ch >> "T"_ch >>
|
|
construct<format::DerivedTypeDataEditDesc>{}(
|
|
space >> defaulted(charLiteralConstantWithoutKind),
|
|
defaulted(parenthesized(nonemptyList(space >> signedDigitString)))))
|
|
|
|
// R1314 k -> [sign] digit-string
|
|
constexpr auto count = space >> DigitStringAsPositive{};
|
|
constexpr auto scaleFactor = space >> signedDigitString;
|
|
|
|
// R1313 control-edit-desc ->
|
|
// position-edit-desc | [r] / | : | sign-edit-desc | k P |
|
|
// blank-interp-edit-desc | round-edit-desc | decimal-edit-desc
|
|
// R1315 position-edit-desc -> T n | TL n | TR n | n X
|
|
// R1316 n -> digit-string
|
|
// R1317 sign-edit-desc -> SS | SP | S
|
|
// R1318 blank-interp-edit-desc -> BN | BZ
|
|
// R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP
|
|
// R1320 decimal-edit-desc -> DC | DP
|
|
TYPE_PARSER(construct<format::ControlEditDesc>{}("T"_ch >>
|
|
("L"_ch >> pure(format::ControlEditDesc::Kind::TL) ||
|
|
"R"_ch >> pure(format::ControlEditDesc::Kind::TR) ||
|
|
pure(format::ControlEditDesc::Kind::T)),
|
|
count) ||
|
|
construct<format::ControlEditDesc>{}(count,
|
|
"X"_ch >> pure(format::ControlEditDesc::Kind::X) ||
|
|
"/"_ch >> pure(format::ControlEditDesc::Kind::Slash)) ||
|
|
construct<format::ControlEditDesc>{}(
|
|
"X"_ch >> pure(format::ControlEditDesc::Kind::X) ||
|
|
"/"_ch >> pure(format::ControlEditDesc::Kind::Slash)) ||
|
|
construct<format::ControlEditDesc>{}(
|
|
scaleFactor, "P"_ch >> pure(format::ControlEditDesc::Kind::P)) ||
|
|
":"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::Colon)) ||
|
|
"S"_ch >> ("S"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::SS)) ||
|
|
"P"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::SP)) ||
|
|
construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::S))) ||
|
|
"B"_ch >> ("N"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::BN)) ||
|
|
"Z"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::BZ))) ||
|
|
"R"_ch >> ("U"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RU)) ||
|
|
"D"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RD)) ||
|
|
"Z"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RZ)) ||
|
|
"N"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RN)) ||
|
|
"C"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RC)) ||
|
|
"P"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::RP))) ||
|
|
"D"_ch >> ("C"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::DC)) ||
|
|
"P"_ch >> construct<format::ControlEditDesc>{}(
|
|
pure(format::ControlEditDesc::Kind::DP))))
|
|
|
|
// R1401 main-program ->
|
|
// [program-stmt] [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-program-stmt
|
|
TYPE_CONTEXT_PARSER("main program"_en_US,
|
|
construct<MainProgram>{}(maybe(statement(Parser<ProgramStmt>{})),
|
|
specificationPart, executionPart, maybe(internalSubprogramPart),
|
|
unterminatedStatement(Parser<EndProgramStmt>{})))
|
|
|
|
// R1402 program-stmt -> PROGRAM program-name
|
|
// PGI allows empty parentheses after the name.
|
|
TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
|
|
construct<ProgramStmt>{}(
|
|
"PROGRAM" >> name / maybe(extension(parenthesized(ok)))))
|
|
|
|
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
|
|
TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
|
|
construct<EndProgramStmt>{}(recovery(
|
|
"END PROGRAM" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1404 module ->
|
|
// module-stmt [specification-part] [module-subprogram-part]
|
|
// end-module-stmt
|
|
TYPE_CONTEXT_PARSER("module"_en_US,
|
|
construct<Module>{}(statement(Parser<ModuleStmt>{}), specificationPart,
|
|
maybe(Parser<ModuleSubprogramPart>{}),
|
|
unterminatedStatement(Parser<EndModuleStmt>{})))
|
|
|
|
// R1405 module-stmt -> MODULE module-name
|
|
TYPE_CONTEXT_PARSER(
|
|
"MODULE statement"_en_US, "MODULE" >> construct<ModuleStmt>{}(name))
|
|
|
|
// R1406 end-module-stmt -> END [MODULE [module-name]]
|
|
TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
|
|
construct<EndModuleStmt>{}(
|
|
recovery("END MODULE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
|
|
TYPE_CONTEXT_PARSER("module subprogram part"_en_US,
|
|
construct<ModuleSubprogramPart>{}(statement(containsStmt),
|
|
many(startNewSubprogram >> Parser<ModuleSubprogram>{})))
|
|
|
|
// R1408 module-subprogram ->
|
|
// function-subprogram | subroutine-subprogram |
|
|
// separate-module-subprogram
|
|
TYPE_PARSER(construct<ModuleSubprogram>{}(indirect(functionSubprogram)) ||
|
|
construct<ModuleSubprogram>{}(indirect(subroutineSubprogram)) ||
|
|
construct<ModuleSubprogram>{}(indirect(Parser<SeparateModuleSubprogram>{})))
|
|
|
|
// R1410 module-nature -> INTRINSIC | NON_INTRINSIC
|
|
constexpr auto moduleNature = "INTRINSIC" >>
|
|
pure(UseStmt::ModuleNature::Intrinsic) ||
|
|
"NON_INTRINSIC" >> pure(UseStmt::ModuleNature::Non_Intrinsic);
|
|
|
|
// R1409 use-stmt ->
|
|
// USE [[, module-nature] ::] module-name [, rename-list] |
|
|
// USE [[, module-nature] ::] module-name , ONLY : [only-list]
|
|
TYPE_PARSER(construct<UseStmt>{}("USE" >> optionalBeforeColons(moduleNature),
|
|
name, ", ONLY :" >> optionalList(Parser<Only>{})) ||
|
|
construct<UseStmt>{}("USE" >> optionalBeforeColons(moduleNature), name,
|
|
defaulted("," >> nonemptyList(Parser<Rename>{}))))
|
|
|
|
// R1411 rename ->
|
|
// local-name => use-name |
|
|
// OPERATOR ( local-defined-operator ) =>
|
|
// OPERATOR ( use-defined-operator )
|
|
TYPE_PARSER(construct<Rename>{}("OPERATOR (" >>
|
|
construct<Rename::Operators>{}(
|
|
definedOpName / ") => OPERATOR (", definedOpName / ")")) ||
|
|
construct<Rename>{}(construct<Rename::Names>{}(name, "=>" >> name)))
|
|
|
|
// R1412 only -> generic-spec | only-use-name | rename
|
|
// R1413 only-use-name -> use-name
|
|
TYPE_PARSER(construct<Only>{}(Parser<Rename>{}) ||
|
|
construct<Only>{}(indirect(genericSpec)) ||
|
|
construct<Only>{}(name)) // TODO: ambiguous, accepted by genericSpec
|
|
|
|
// R1416 submodule ->
|
|
// submodule-stmt [specification-part] [module-subprogram-part]
|
|
// end-submodule-stmt
|
|
TYPE_CONTEXT_PARSER("submodule"_en_US,
|
|
construct<Submodule>{}(statement(Parser<SubmoduleStmt>{}),
|
|
specificationPart, maybe(Parser<ModuleSubprogramPart>{}),
|
|
unterminatedStatement(Parser<EndSubmoduleStmt>{})))
|
|
|
|
// R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name
|
|
TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US,
|
|
construct<SubmoduleStmt>{}(
|
|
"SUBMODULE" >> parenthesized(Parser<ParentIdentifier>{}), name))
|
|
|
|
// R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name]
|
|
TYPE_PARSER(construct<ParentIdentifier>{}(name, maybe(":" >> name)))
|
|
|
|
// R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
|
|
TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
|
|
construct<EndSubmoduleStmt>{}(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,
|
|
construct<BlockData>{}(statement(Parser<BlockDataStmt>{}),
|
|
specificationPart, unterminatedStatement(Parser<EndBlockDataStmt>{})))
|
|
|
|
// R1421 block-data-stmt -> BLOCK DATA [block-data-name]
|
|
TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
|
|
"BLOCK DATA" >> construct<BlockDataStmt>{}(maybe(name)))
|
|
|
|
// R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
|
|
TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
|
|
construct<EndBlockDataStmt>{}(recovery(
|
|
"END BLOCK DATA" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1501 interface-block ->
|
|
// interface-stmt [interface-specification]... end-interface-stmt
|
|
TYPE_PARSER(construct<InterfaceBlock>{}(statement(Parser<InterfaceStmt>{}),
|
|
many(Parser<InterfaceSpecification>{}),
|
|
statement(Parser<EndInterfaceStmt>{})))
|
|
|
|
// R1502 interface-specification -> interface-body | procedure-stmt
|
|
TYPE_PARSER(construct<InterfaceSpecification>{}(Parser<InterfaceBody>{}) ||
|
|
construct<InterfaceSpecification>{}(statement(Parser<ProcedureStmt>{})))
|
|
|
|
// R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE
|
|
TYPE_PARSER("INTERFACE" >> construct<InterfaceStmt>{}(maybe(genericSpec)) ||
|
|
"ABSTRACT INTERFACE"_sptok >>
|
|
construct<InterfaceStmt>{}(construct<Abstract>{}))
|
|
|
|
// R1504 end-interface-stmt -> END INTERFACE [generic-spec]
|
|
TYPE_PARSER(
|
|
"END INTERFACE" >> construct<EndInterfaceStmt>{}(maybe(genericSpec)))
|
|
|
|
// R1505 interface-body ->
|
|
// function-stmt [specification-part] end-function-stmt |
|
|
// subroutine-stmt [specification-part] end-subroutine-stmt
|
|
TYPE_CONTEXT_PARSER("interface body"_en_US,
|
|
construct<InterfaceBody>{}(
|
|
construct<InterfaceBody::Function>{}(statement(functionStmt),
|
|
indirect(specificationPart), statement(endFunctionStmt))) ||
|
|
construct<InterfaceBody>{}(
|
|
construct<InterfaceBody::Subroutine>{}(statement(subroutineStmt),
|
|
indirect(specificationPart), statement(endSubroutineStmt))))
|
|
|
|
// R1507 specific-procedure -> procedure-name
|
|
constexpr auto specificProcedure = name;
|
|
|
|
// R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
|
|
TYPE_PARSER(construct<ProcedureStmt>{}("MODULE PROCEDURE"_sptok >>
|
|
pure(ProcedureStmt::Kind::ModuleProcedure),
|
|
maybe("::"_tok) >> nonemptyList(specificProcedure)) ||
|
|
construct<ProcedureStmt>{}(
|
|
"PROCEDURE" >> pure(ProcedureStmt::Kind::Procedure),
|
|
maybe("::"_tok) >> nonemptyList(specificProcedure)))
|
|
|
|
// R1508 generic-spec ->
|
|
// generic-name | OPERATOR ( defined-operator ) |
|
|
// ASSIGNMENT ( = ) | defined-io-generic-spec
|
|
// R1509 defined-io-generic-spec ->
|
|
// READ ( FORMATTED ) | READ ( UNFORMATTED ) |
|
|
// WRITE ( FORMATTED ) | WRITE ( UNFORMATTED )
|
|
TYPE_PARSER(construct<GenericSpec>{}(
|
|
"OPERATOR" >> parenthesized(Parser<DefinedOperator>{})) ||
|
|
construct<GenericSpec>{}(
|
|
"ASSIGNMENT ( = )" >> construct<GenericSpec::Assignment>{}) ||
|
|
construct<GenericSpec>{}(
|
|
"READ ( FORMATTED )" >> construct<GenericSpec::ReadFormatted>{}) ||
|
|
construct<GenericSpec>{}(
|
|
"READ ( UNFORMATTED )" >> construct<GenericSpec::ReadUnformatted>{}) ||
|
|
construct<GenericSpec>{}(
|
|
"WRITE ( FORMATTED )" >> construct<GenericSpec::WriteFormatted>{}) ||
|
|
construct<GenericSpec>{}("WRITE ( UNFORMATTED )" >>
|
|
construct<GenericSpec::WriteUnformatted>{}) ||
|
|
construct<GenericSpec>{}(name))
|
|
|
|
// R1510 generic-stmt ->
|
|
// GENERIC [, access-spec] :: generic-spec => specific-procedure-list
|
|
TYPE_PARSER("GENERIC" >> construct<GenericStmt>{}(maybe("," >> accessSpec),
|
|
"::" >> genericSpec,
|
|
"=>" >> nonemptyList(specificProcedure)))
|
|
|
|
// R1511 external-stmt -> EXTERNAL [::] external-name-list
|
|
TYPE_PARSER("EXTERNAL" >> maybe("::"_tok) >>
|
|
construct<ExternalStmt>{}(nonemptyList(name)))
|
|
|
|
// R1512 procedure-declaration-stmt ->
|
|
// PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::]
|
|
// proc-decl-list
|
|
TYPE_PARSER("PROCEDURE" >>
|
|
construct<ProcedureDeclarationStmt>{}(parenthesized(maybe(procInterface)),
|
|
optionalListBeforeColons(Parser<ProcAttrSpec>{}),
|
|
nonemptyList(procDecl)))
|
|
|
|
// R1513 proc-interface -> interface-name | declaration-type-spec
|
|
// R1516 interface-name -> name
|
|
TYPE_PARSER(construct<ProcInterface>{}(declarationTypeSpec) ||
|
|
construct<ProcInterface>{}(name))
|
|
|
|
// R1514 proc-attr-spec ->
|
|
// access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |
|
|
// OPTIONAL | POINTER | PROTECTED | SAVE
|
|
TYPE_PARSER(construct<ProcAttrSpec>{}(accessSpec) ||
|
|
construct<ProcAttrSpec>{}(languageBindingSpec) ||
|
|
construct<ProcAttrSpec>{}("INTENT" >> parenthesized(intentSpec)) ||
|
|
construct<ProcAttrSpec>{}(optional) || construct<ProcAttrSpec>{}(pointer) ||
|
|
construct<ProcAttrSpec>{}(protectedAttr) || construct<ProcAttrSpec>{}(save))
|
|
|
|
// R1515 proc-decl -> procedure-entity-name [=> proc-pointer-init]
|
|
TYPE_PARSER(
|
|
construct<ProcDecl>{}(name, maybe("=>" >> Parser<ProcPointerInit>{})))
|
|
|
|
// R1517 proc-pointer-init -> null-init | initial-proc-target
|
|
// R1518 initial-proc-target -> procedure-name
|
|
TYPE_PARSER(construct<ProcPointerInit>{}(nullInit) ||
|
|
construct<ProcPointerInit>{}(name))
|
|
|
|
// R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list
|
|
TYPE_PARSER("INTRINSIC" >> maybe("::"_tok) >>
|
|
construct<IntrinsicStmt>{}(nonemptyList(name)))
|
|
|
|
// R1520 function-reference -> procedure-designator ( [actual-arg-spec-list] )
|
|
TYPE_PARSER(construct<FunctionReference>{}(construct<Call>{}(
|
|
Parser<ProcedureDesignator>{}, parenthesized(optionalList(actualArgSpec)))))
|
|
|
|
// R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )]
|
|
TYPE_PARSER(construct<CallStmt>{}(
|
|
construct<Call>{}("CALL" >> Parser<ProcedureDesignator>{},
|
|
defaulted(parenthesized(optionalList(actualArgSpec))))))
|
|
|
|
// R1522 procedure-designator ->
|
|
// procedure-name | proc-component-ref | data-ref % binding-name
|
|
TYPE_PARSER(construct<ProcedureDesignator>{}(Parser<ProcComponentRef>{}) ||
|
|
construct<ProcedureDesignator>{}(name))
|
|
|
|
// R1523 actual-arg-spec -> [keyword =] actual-arg
|
|
TYPE_PARSER(construct<ActualArgSpec>{}(
|
|
maybe(keyword / "=" / !"="_ch), Parser<ActualArg>{}))
|
|
|
|
// R1524 actual-arg ->
|
|
// expr | variable | procedure-name | proc-component-ref |
|
|
// alt-return-spec
|
|
// N.B. the "procedure-name" and "proc-component-ref" alternatives can't
|
|
// yet be distinguished from "variable".
|
|
TYPE_PARSER(construct<ActualArg>{}(variable) / lookAhead(","_tok || ")"_tok) ||
|
|
construct<ActualArg>{}(expr) ||
|
|
construct<ActualArg>{}(Parser<AltReturnSpec>{}) ||
|
|
extension("%REF" >>
|
|
construct<ActualArg>{}(
|
|
construct<ActualArg::PercentRef>{}(parenthesized(variable)))) ||
|
|
extension(
|
|
"%VAL" >> construct<ActualArg>{}(
|
|
construct<ActualArg::PercentVal>{}(parenthesized(expr)))))
|
|
|
|
// R1525 alt-return-spec -> * label
|
|
TYPE_PARSER(star >> construct<AltReturnSpec>{}(label))
|
|
|
|
// R1527 prefix-spec ->
|
|
// declaration-type-spec | ELEMENTAL | IMPURE | MODULE |
|
|
// NON_RECURSIVE | PURE | RECURSIVE
|
|
TYPE_PARSER(construct<PrefixSpec>{}(declarationTypeSpec) ||
|
|
"ELEMENTAL" >>
|
|
construct<PrefixSpec>{}(construct<PrefixSpec::Elemental>{}) ||
|
|
"IMPURE" >> construct<PrefixSpec>{}(construct<PrefixSpec::Impure>{}) ||
|
|
"MODULE" >> construct<PrefixSpec>{}(construct<PrefixSpec::Module>{}) ||
|
|
"NON_RECURSIVE" >>
|
|
construct<PrefixSpec>{}(construct<PrefixSpec::Non_Recursive>{}) ||
|
|
"PURE" >> construct<PrefixSpec>{}(construct<PrefixSpec::Pure>{}) ||
|
|
"RECURSIVE" >> construct<PrefixSpec>{}(construct<PrefixSpec::Recursive>{}))
|
|
|
|
// R1529 function-subprogram ->
|
|
// function-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-function-stmt
|
|
TYPE_CONTEXT_PARSER("FUNCTION subprogram"_en_US,
|
|
construct<FunctionSubprogram>{}(statement(functionStmt), specificationPart,
|
|
executionPart, maybe(internalSubprogramPart),
|
|
unterminatedStatement(endFunctionStmt)))
|
|
|
|
// R1530 function-stmt ->
|
|
// [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix]
|
|
// R1526 prefix -> prefix-spec [prefix-spec]...
|
|
// R1531 dummy-arg-name -> name
|
|
TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US,
|
|
construct<FunctionStmt>{}(many(prefixSpec), "FUNCTION" >> name,
|
|
parenthesized(optionalList(name)), maybe(suffix)) ||
|
|
extension(construct<FunctionStmt>{}( // PGI & Intel accept "FUNCTION F"
|
|
many(prefixSpec), "FUNCTION" >> name, construct<std::list<Name>>{},
|
|
construct<std::optional<Suffix>>{})))
|
|
|
|
// R1532 suffix ->
|
|
// proc-language-binding-spec [RESULT ( result-name )] |
|
|
// RESULT ( result-name ) [proc-language-binding-spec]
|
|
TYPE_PARSER(construct<Suffix>{}(
|
|
languageBindingSpec, maybe("RESULT" >> parenthesized(name))) ||
|
|
construct<Suffix>{}(
|
|
"RESULT" >> parenthesized(name), maybe(languageBindingSpec)))
|
|
|
|
// R1533 end-function-stmt -> END [FUNCTION [function-name]]
|
|
TYPE_PARSER(construct<EndFunctionStmt>{}(
|
|
recovery("END FUNCTION" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1534 subroutine-subprogram ->
|
|
// subroutine-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-subroutine-stmt
|
|
TYPE_CONTEXT_PARSER("SUBROUTINE subprogram"_en_US,
|
|
construct<SubroutineSubprogram>{}(statement(subroutineStmt),
|
|
specificationPart, executionPart, maybe(internalSubprogramPart),
|
|
unterminatedStatement(endSubroutineStmt)))
|
|
|
|
// R1535 subroutine-stmt ->
|
|
// [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] )
|
|
// [proc-language-binding-spec]]
|
|
TYPE_PARSER(
|
|
construct<SubroutineStmt>{}(many(prefixSpec), "SUBROUTINE" >> name,
|
|
parenthesized(optionalList(dummyArg)), maybe(languageBindingSpec)) ||
|
|
construct<SubroutineStmt>{}(many(prefixSpec), "SUBROUTINE" >> name,
|
|
defaulted(cut >> many(dummyArg)),
|
|
defaulted(cut >> maybe(languageBindingSpec))))
|
|
|
|
// R1536 dummy-arg -> dummy-arg-name | *
|
|
TYPE_PARSER(construct<DummyArg>{}(name) || construct<DummyArg>{}(star))
|
|
|
|
// R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
|
|
TYPE_PARSER(construct<EndSubroutineStmt>{}(
|
|
recovery("END SUBROUTINE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1538 separate-module-subprogram ->
|
|
// mp-subprogram-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-mp-subprogram-stmt
|
|
TYPE_CONTEXT_PARSER("separate module subprogram"_en_US,
|
|
construct<SeparateModuleSubprogram>{}(statement(Parser<MpSubprogramStmt>{}),
|
|
specificationPart, executionPart, maybe(internalSubprogramPart),
|
|
statement(Parser<EndMpSubprogramStmt>{})))
|
|
|
|
// R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name
|
|
TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
|
|
construct<MpSubprogramStmt>{}("MODULE PROCEDURE"_sptok >> name))
|
|
|
|
// R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
|
|
TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
|
|
construct<EndMpSubprogramStmt>{}(recovery(
|
|
"END PROCEDURE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
|
|
|
|
// R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
|
|
TYPE_PARSER("ENTRY" >>
|
|
(construct<EntryStmt>{}(
|
|
name, parenthesized(optionalList(dummyArg)), maybe(suffix)) ||
|
|
construct<EntryStmt>{}(name, construct<std::list<DummyArg>>{},
|
|
construct<std::optional<Suffix>>{})))
|
|
|
|
// R1542 return-stmt -> RETURN [scalar-int-expr]
|
|
TYPE_CONTEXT_PARSER("RETURN statement"_en_US,
|
|
"RETURN" >> construct<ReturnStmt>{}(maybe(scalarIntExpr)))
|
|
|
|
// R1543 contains-stmt -> CONTAINS
|
|
TYPE_PARSER("CONTAINS" >> construct<ContainsStmt>{})
|
|
|
|
// R1544 stmt-function-stmt ->
|
|
// function-name ( [dummy-arg-name-list] ) = scalar-expr
|
|
TYPE_CONTEXT_PARSER("statement function definition"_en_US,
|
|
construct<StmtFunctionStmt>{}(
|
|
name, parenthesized(optionalList(name)), "=" >> scalar(expr)))
|
|
|
|
// Directives, extensions, and deprecated statements
|
|
// !DIR$ IVDEP
|
|
// !DIR$ IGNORE_TKR [ [(tkr...)] name ]...
|
|
constexpr auto beginDirective = skipEmptyLines >> space >> "!"_ch;
|
|
constexpr auto endDirective = space >> endOfLine;
|
|
constexpr auto ivdep = "DIR$ IVDEP" >> construct<CompilerDirective::IVDEP>{};
|
|
constexpr auto ignore_tkr = "DIR$ IGNORE_TKR" >>
|
|
optionalList(construct<CompilerDirective::IgnoreTKR>{}(
|
|
defaulted(parenthesized(some("tkr"_ch))), name));
|
|
TYPE_PARSER(beginDirective >> sourced(construct<CompilerDirective>{}(ivdep) ||
|
|
construct<CompilerDirective>{}(ignore_tkr)) /
|
|
endDirective)
|
|
|
|
TYPE_PARSER(
|
|
extension(construct<BasedPointerStmt>{}("POINTER (" >> objectName / ",",
|
|
objectName, maybe(Parser<ArraySpec>{}) / ")")))
|
|
|
|
TYPE_PARSER(construct<StructureStmt>{}("STRUCTURE /" >> name / "/", pure(true),
|
|
optionalList(entityDecl)) ||
|
|
construct<StructureStmt>{}(
|
|
"STRUCTURE" >> name, pure(false), defaulted(cut >> many(entityDecl))))
|
|
|
|
constexpr struct StructureComponents {
|
|
using resultType = DataComponentDefStmt;
|
|
static std::optional<DataComponentDefStmt> Parse(ParseState *state) {
|
|
static constexpr auto stmt = Parser<DataComponentDefStmt>{};
|
|
std::optional<DataComponentDefStmt> defs{stmt.Parse(state)};
|
|
if (defs.has_value()) {
|
|
if (auto ustate = state->userState()) {
|
|
for (const auto &decl : std::get<std::list<ComponentDecl>>(defs->t)) {
|
|
ustate->NoteOldStructureComponent(std::get<Name>(decl.t).source);
|
|
}
|
|
}
|
|
}
|
|
return defs;
|
|
}
|
|
} structureComponents;
|
|
|
|
TYPE_PARSER(construct<StructureField>{}(statement(structureComponents)) ||
|
|
construct<StructureField>{}(indirect(Parser<Union>{})) ||
|
|
construct<StructureField>{}(indirect(Parser<StructureDef>{})))
|
|
|
|
TYPE_CONTEXT_PARSER("STRUCTURE definition"_en_US,
|
|
extension(construct<StructureDef>{}(statement(Parser<StructureStmt>{}),
|
|
many(Parser<StructureField>{}),
|
|
statement(
|
|
"END STRUCTURE" >> construct<StructureDef::EndStructureStmt>{}))))
|
|
|
|
TYPE_CONTEXT_PARSER("UNION definition"_en_US,
|
|
construct<Union>{}(statement("UNION" >> construct<Union::UnionStmt>{}),
|
|
many(Parser<Map>{}),
|
|
statement("END UNION" >> construct<Union::EndUnionStmt>{})))
|
|
|
|
TYPE_CONTEXT_PARSER("MAP definition"_en_US,
|
|
construct<Map>{}(statement("MAP" >> construct<Map::MapStmt>{}),
|
|
many(Parser<StructureField>{}),
|
|
statement("END MAP" >> construct<Map::EndMapStmt>{})))
|
|
|
|
TYPE_CONTEXT_PARSER("arithmetic IF statement"_en_US,
|
|
deprecated("IF" >> construct<ArithmeticIfStmt>{}(parenthesized(expr),
|
|
label / ",", label / ",", label)))
|
|
|
|
TYPE_CONTEXT_PARSER("ASSIGN statement"_en_US,
|
|
deprecated("ASSIGN" >> construct<AssignStmt>{}(label, "TO" >> name)))
|
|
|
|
TYPE_CONTEXT_PARSER("assigned GOTO statement"_en_US,
|
|
deprecated("GO TO" >>
|
|
construct<AssignedGotoStmt>{}(name,
|
|
defaulted(maybe(","_tok) >> parenthesized(nonemptyList(label))))))
|
|
|
|
TYPE_CONTEXT_PARSER("PAUSE statement"_en_US,
|
|
deprecated("PAUSE" >> construct<PauseStmt>{}(maybe(Parser<StopCode>{}))))
|
|
|
|
// These requirement productions are defined by the Fortran standard but never
|
|
// used directly by the grammar:
|
|
// R620 delimiter -> ( | ) | / | [ | ] | (/ | /)
|
|
// R1027 numeric-expr -> expr
|
|
// R1031 int-constant-expr -> int-expr
|
|
// R1221 dtv-type-spec -> TYPE ( derived-type-spec ) |
|
|
// CLASS ( derived-type-spec )
|
|
//
|
|
// These requirement productions are defined and used, but need not be
|
|
// defined independently here in this file:
|
|
// R771 lbracket -> [
|
|
// R772 rbracket -> ]
|
|
//
|
|
// Further note that:
|
|
// R607 int-constant -> constant
|
|
// is used only once via R844 scalar-int-constant
|
|
// R904 logical-variable -> variable
|
|
// is used only via scalar-logical-variable
|
|
// R906 default-char-variable -> variable
|
|
// is used only via scalar-default-char-variable
|
|
// R907 int-variable -> variable
|
|
// is used only via scalar-int-variable
|
|
// R1030 default-char-constant-expr -> default-char-expr
|
|
// is only used via scalar-default-char-constant-expr
|
|
} // namespace parser
|
|
} // namespace Fortran
|
|
#endif // FORTRAN_PARSER_GRAMMAR_H_
|