
The cancellable construct names on CANCEL or CANCELLATION POINT directives are actually clauses (with the same names as the corresponding constructs). Instead of parsing them into a custom structure, parse them as a clause, which will make CANCEL/CANCELLATION POINT follow the same uniform scheme as other constructs (<directive> [(<arguments>)] [clauses]).
5334 lines
179 KiB
C++
5334 lines
179 KiB
C++
//===-- include/flang/Parser/parse-tree.h -----------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef FORTRAN_PARSER_PARSE_TREE_H_
|
|
#define FORTRAN_PARSER_PARSE_TREE_H_
|
|
|
|
// Defines the classes used to represent successful reductions of productions
|
|
// in the Fortran grammar. The names and content of these definitions
|
|
// adhere closely to the syntax specifications in the language standard (q.v.)
|
|
// that are transcribed here and referenced via their requirement numbers.
|
|
// The representations of some productions that may also be of use in the
|
|
// run-time I/O support library have been isolated into a distinct header file
|
|
// (viz., format-specification.h).
|
|
|
|
#include "char-block.h"
|
|
#include "characters.h"
|
|
#include "format-specification.h"
|
|
#include "message.h"
|
|
#include "provenance.h"
|
|
#include "flang/Common/idioms.h"
|
|
#include "flang/Common/indirection.h"
|
|
#include "flang/Support/Fortran.h"
|
|
#include "llvm/Frontend/OpenACC/ACC.h.inc"
|
|
#include "llvm/Frontend/OpenMP/OMP.h"
|
|
#include "llvm/Frontend/OpenMP/OMPConstants.h"
|
|
#include <cinttypes>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <variant>
|
|
|
|
// Parse tree node class types do not have default constructors. They
|
|
// explicitly declare "T() {} = delete;" to make this clear. This restriction
|
|
// prevents the introduction of what would be a viral requirement to include
|
|
// std::monostate among most std::variant<> discriminated union members.
|
|
|
|
// Parse tree node class types do not have copy constructors or copy assignment
|
|
// operators. They are explicitly declared "= delete;" to make this clear,
|
|
// although a C++ compiler wouldn't default them anyway due to the presence
|
|
// of explicitly defaulted move constructors and move assignments.
|
|
|
|
CLASS_TRAIT(EmptyTrait)
|
|
CLASS_TRAIT(WrapperTrait)
|
|
CLASS_TRAIT(UnionTrait)
|
|
CLASS_TRAIT(TupleTrait)
|
|
CLASS_TRAIT(ConstraintTrait)
|
|
|
|
// Some parse tree nodes have fields in them to cache the results of a
|
|
// successful semantic analysis later. Their types are forward declared
|
|
// here.
|
|
namespace Fortran::semantics {
|
|
class Symbol;
|
|
class DeclTypeSpec;
|
|
class DerivedTypeSpec;
|
|
} // namespace Fortran::semantics
|
|
|
|
// Expressions in the parse tree have owning pointers that can be set to
|
|
// type-checked generic expression representations by semantic analysis.
|
|
namespace Fortran::evaluate {
|
|
struct GenericExprWrapper; // forward definition, wraps Expr<SomeType>
|
|
struct GenericAssignmentWrapper; // forward definition, represent assignment
|
|
class ProcedureRef; // forward definition, represents a CALL or function ref
|
|
} // namespace Fortran::evaluate
|
|
|
|
// Most non-template classes in this file use these default definitions
|
|
// for their move constructor and move assignment operator=, and disable
|
|
// their copy constructor and copy assignment operator=.
|
|
#define COPY_AND_ASSIGN_BOILERPLATE(classname) \
|
|
classname(classname &&) = default; \
|
|
classname &operator=(classname &&) = default; \
|
|
classname(const classname &) = delete; \
|
|
classname &operator=(const classname &) = delete
|
|
|
|
// Almost all classes in this file have no default constructor.
|
|
#define BOILERPLATE(classname) \
|
|
COPY_AND_ASSIGN_BOILERPLATE(classname); \
|
|
classname() = delete
|
|
|
|
// Empty classes are often used below as alternatives in std::variant<>
|
|
// discriminated unions.
|
|
#define EMPTY_CLASS(classname) \
|
|
struct classname { \
|
|
classname() {} \
|
|
classname(const classname &) {} \
|
|
classname(classname &&) {} \
|
|
classname &operator=(const classname &) { return *this; }; \
|
|
classname &operator=(classname &&) { return *this; }; \
|
|
using EmptyTrait = std::true_type; \
|
|
}
|
|
|
|
// Many classes below simply wrap a std::variant<> discriminated union,
|
|
// which is conventionally named "u".
|
|
#define UNION_CLASS_BOILERPLATE(classname) \
|
|
template <typename A, typename = common::NoLvalue<A>> \
|
|
classname(A &&x) : u(std::move(x)) {} \
|
|
using UnionTrait = std::true_type; \
|
|
BOILERPLATE(classname)
|
|
|
|
// Many other classes below simply wrap a std::tuple<> structure, which
|
|
// is conventionally named "t".
|
|
#define TUPLE_CLASS_BOILERPLATE(classname) \
|
|
template <typename... Ts, typename = common::NoLvalue<Ts...>> \
|
|
classname(Ts &&...args) : t(std::move(args)...) {} \
|
|
using TupleTrait = std::true_type; \
|
|
BOILERPLATE(classname)
|
|
|
|
// Many other classes below simply wrap a single data member, which is
|
|
// conventionally named "v".
|
|
#define WRAPPER_CLASS_BOILERPLATE(classname, type) \
|
|
BOILERPLATE(classname); \
|
|
classname(type &&x) : v(std::move(x)) {} \
|
|
using WrapperTrait = std::true_type; \
|
|
type v
|
|
|
|
#define WRAPPER_CLASS(classname, type) \
|
|
struct classname { \
|
|
WRAPPER_CLASS_BOILERPLATE(classname, type); \
|
|
}
|
|
|
|
namespace Fortran::parser {
|
|
|
|
// These are the unavoidable recursively-defined productions of Fortran.
|
|
// Some references to the representations of their parses require
|
|
// indirection. The Indirect<> pointer wrapper class is used to
|
|
// enforce ownership semantics and non-nullability.
|
|
struct SpecificationPart; // R504
|
|
struct ExecutableConstruct; // R514
|
|
struct ActionStmt; // R515
|
|
struct AcImpliedDo; // R774
|
|
struct DataImpliedDo; // R840
|
|
struct Designator; // R901
|
|
struct Variable; // R902
|
|
struct Expr; // R1001
|
|
struct WhereConstruct; // R1042
|
|
struct ForallConstruct; // R1050
|
|
struct InputImpliedDo; // R1218
|
|
struct OutputImpliedDo; // R1218
|
|
struct FunctionReference; // R1520
|
|
struct FunctionSubprogram; // R1529
|
|
struct SubroutineSubprogram; // R1534
|
|
|
|
// These additional forward references are declared so that the order of
|
|
// class definitions in this header file can remain reasonably consistent
|
|
// with order of the the requirement productions in the grammar.
|
|
struct DerivedTypeDef; // R726
|
|
struct EnumDef; // R759
|
|
struct TypeDeclarationStmt; // R801
|
|
struct AccessStmt; // R827
|
|
struct AllocatableStmt; // R829
|
|
struct AsynchronousStmt; // R831
|
|
struct BindStmt; // R832
|
|
struct CodimensionStmt; // R834
|
|
struct ContiguousStmt; // R836
|
|
struct DataStmt; // R837
|
|
struct DataStmtValue; // R843
|
|
struct DimensionStmt; // R848
|
|
struct IntentStmt; // R849
|
|
struct OptionalStmt; // R850
|
|
struct ParameterStmt; // R851
|
|
struct OldParameterStmt;
|
|
struct PointerStmt; // R853
|
|
struct ProtectedStmt; // R855
|
|
struct SaveStmt; // R856
|
|
struct TargetStmt; // R859
|
|
struct ValueStmt; // R861
|
|
struct VolatileStmt; // R862
|
|
struct ImplicitStmt; // R863
|
|
struct ImportStmt; // R867
|
|
struct NamelistStmt; // R868
|
|
struct EquivalenceStmt; // R870
|
|
struct CommonStmt; // R873
|
|
struct Substring; // R908
|
|
struct CharLiteralConstantSubstring;
|
|
struct SubstringInquiry;
|
|
struct DataRef; // R911
|
|
struct StructureComponent; // R913
|
|
struct CoindexedNamedObject; // R914
|
|
struct ArrayElement; // R917
|
|
struct AllocateStmt; // R927
|
|
struct NullifyStmt; // R939
|
|
struct DeallocateStmt; // R941
|
|
struct AssignmentStmt; // R1032
|
|
struct PointerAssignmentStmt; // R1033
|
|
struct WhereStmt; // R1041, R1045, R1046
|
|
struct ForallStmt; // R1055
|
|
struct AssociateConstruct; // R1102
|
|
struct BlockConstruct; // R1107
|
|
struct ChangeTeamConstruct; // R1111
|
|
struct CriticalConstruct; // R1116
|
|
struct DoConstruct; // R1119
|
|
struct LabelDoStmt; // R1121
|
|
struct ConcurrentHeader; // R1125
|
|
struct EndDoStmt; // R1132
|
|
struct CycleStmt; // R1133
|
|
struct IfConstruct; // R1134
|
|
struct IfStmt; // R1139
|
|
struct CaseConstruct; // R1140
|
|
struct SelectRankConstruct; // R1148
|
|
struct SelectTypeConstruct; // R1152
|
|
struct ExitStmt; // R1156
|
|
struct GotoStmt; // R1157
|
|
struct ComputedGotoStmt; // R1158
|
|
struct StopStmt; // R1160, R1161
|
|
struct NotifyWaitStmt; // F2023: R1166
|
|
struct SyncAllStmt; // R1164
|
|
struct SyncImagesStmt; // R1166
|
|
struct SyncMemoryStmt; // R1168
|
|
struct SyncTeamStmt; // R1169
|
|
struct EventPostStmt; // R1170, R1171
|
|
struct EventWaitSpec; // F2023: R1177
|
|
struct EventWaitStmt; // R1172, R1173, R1174
|
|
struct FormTeamStmt; // R1175, R1176, R1177
|
|
struct LockStmt; // R1178
|
|
struct UnlockStmt; // R1180
|
|
struct OpenStmt; // R1204
|
|
struct CloseStmt; // R1208
|
|
struct ReadStmt; // R1210
|
|
struct WriteStmt; // R1211
|
|
struct PrintStmt; // R1212
|
|
struct WaitStmt; // R1222
|
|
struct BackspaceStmt; // R1224
|
|
struct EndfileStmt; // R1225
|
|
struct RewindStmt; // R1226
|
|
struct FlushStmt; // R1228
|
|
struct InquireStmt; // R1230
|
|
struct FormatStmt; // R1301
|
|
struct MainProgram; // R1401
|
|
struct Module; // R1404
|
|
struct UseStmt; // R1409
|
|
struct Submodule; // R1416
|
|
struct BlockData; // R1420
|
|
struct InterfaceBlock; // R1501
|
|
struct GenericSpec; // R1508
|
|
struct GenericStmt; // R1510
|
|
struct ExternalStmt; // R1511
|
|
struct ProcedureDeclarationStmt; // R1512
|
|
struct IntrinsicStmt; // R1519
|
|
struct Call; // R1520 & R1521
|
|
struct CallStmt; // R1521
|
|
struct ProcedureDesignator; // R1522
|
|
struct ActualArg; // R1524
|
|
struct SeparateModuleSubprogram; // R1538
|
|
struct EntryStmt; // R1541
|
|
struct ReturnStmt; // R1542
|
|
struct StmtFunctionStmt; // R1544
|
|
|
|
// Directives, extensions, and deprecated statements
|
|
struct CompilerDirective;
|
|
struct BasedPointerStmt;
|
|
struct CUDAAttributesStmt;
|
|
struct StructureDef;
|
|
struct ArithmeticIfStmt;
|
|
struct AssignStmt;
|
|
struct AssignedGotoStmt;
|
|
struct PauseStmt;
|
|
struct OpenACCConstruct;
|
|
struct AccEndCombinedDirective;
|
|
struct OpenACCDeclarativeConstruct;
|
|
struct OpenACCRoutineConstruct;
|
|
struct OpenMPConstruct;
|
|
struct OpenMPDeclarativeConstruct;
|
|
struct OmpEndLoopDirective;
|
|
struct OmpMemoryOrderClause;
|
|
struct CUFKernelDoConstruct;
|
|
|
|
// Cooked character stream locations
|
|
using Location = const char *;
|
|
|
|
// A parse tree node with provenance only
|
|
struct Verbatim {
|
|
// Allow a no-arg constructor for Verbatim so parsers can return `RESULT{}`.
|
|
constexpr Verbatim() {}
|
|
COPY_AND_ASSIGN_BOILERPLATE(Verbatim);
|
|
using EmptyTrait = std::true_type;
|
|
CharBlock source;
|
|
};
|
|
|
|
// Implicit definitions of the Standard
|
|
|
|
// R403 scalar-xyz -> xyz
|
|
// These template class wrappers correspond to the Standard's modifiers
|
|
// scalar-xyz, constant-xzy, int-xzy, default-char-xyz, & logical-xyz.
|
|
template <typename A> struct Scalar {
|
|
using ConstraintTrait = std::true_type;
|
|
Scalar(Scalar &&that) = default;
|
|
Scalar(A &&that) : thing(std::move(that)) {}
|
|
Scalar &operator=(Scalar &&) = default;
|
|
A thing;
|
|
};
|
|
|
|
template <typename A> struct Constant {
|
|
using ConstraintTrait = std::true_type;
|
|
Constant(Constant &&that) = default;
|
|
Constant(A &&that) : thing(std::move(that)) {}
|
|
Constant &operator=(Constant &&) = default;
|
|
A thing;
|
|
};
|
|
|
|
template <typename A> struct Integer {
|
|
using ConstraintTrait = std::true_type;
|
|
Integer(Integer &&that) = default;
|
|
Integer(A &&that) : thing(std::move(that)) {}
|
|
Integer &operator=(Integer &&) = default;
|
|
A thing;
|
|
};
|
|
|
|
template <typename A> struct Logical {
|
|
using ConstraintTrait = std::true_type;
|
|
Logical(Logical &&that) = default;
|
|
Logical(A &&that) : thing(std::move(that)) {}
|
|
Logical &operator=(Logical &&) = default;
|
|
A thing;
|
|
};
|
|
|
|
template <typename A> struct DefaultChar {
|
|
using ConstraintTrait = std::true_type;
|
|
DefaultChar(DefaultChar &&that) = default;
|
|
DefaultChar(A &&that) : thing(std::move(that)) {}
|
|
DefaultChar &operator=(DefaultChar &&) = default;
|
|
A thing;
|
|
};
|
|
|
|
using LogicalExpr = Logical<common::Indirection<Expr>>; // R1024
|
|
using DefaultCharExpr = DefaultChar<common::Indirection<Expr>>; // R1025
|
|
using IntExpr = Integer<common::Indirection<Expr>>; // R1026
|
|
using ConstantExpr = Constant<common::Indirection<Expr>>; // R1029
|
|
using IntConstantExpr = Integer<ConstantExpr>; // R1031
|
|
using ScalarLogicalExpr = Scalar<LogicalExpr>;
|
|
using ScalarIntExpr = Scalar<IntExpr>;
|
|
using ScalarIntConstantExpr = Scalar<IntConstantExpr>;
|
|
using ScalarDefaultCharExpr = Scalar<DefaultCharExpr>;
|
|
// R1030 default-char-constant-expr is used in the Standard only as part of
|
|
// scalar-default-char-constant-expr.
|
|
using ScalarDefaultCharConstantExpr = Scalar<DefaultChar<ConstantExpr>>;
|
|
|
|
// R611 label -> digit [digit]...
|
|
using Label = common::Label; // validated later, must be in [1..99999]
|
|
|
|
// A wrapper for xzy-stmt productions that are statements, so that
|
|
// source provenances and labels have a uniform representation.
|
|
template <typename A> struct UnlabeledStatement {
|
|
explicit UnlabeledStatement(A &&s) : statement(std::move(s)) {}
|
|
CharBlock source;
|
|
A statement;
|
|
};
|
|
template <typename A> struct Statement : public UnlabeledStatement<A> {
|
|
Statement(std::optional<long> &&lab, A &&s)
|
|
: UnlabeledStatement<A>{std::move(s)}, label(std::move(lab)) {}
|
|
std::optional<Label> label;
|
|
};
|
|
|
|
// Error recovery marker
|
|
EMPTY_CLASS(ErrorRecovery);
|
|
|
|
// 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
|
|
// Extension: (Cray) based POINTER statement
|
|
// Extension: CUDA data attribute statement
|
|
struct OtherSpecificationStmt {
|
|
UNION_CLASS_BOILERPLATE(OtherSpecificationStmt);
|
|
std::variant<common::Indirection<AccessStmt>,
|
|
common::Indirection<AllocatableStmt>,
|
|
common::Indirection<AsynchronousStmt>, common::Indirection<BindStmt>,
|
|
common::Indirection<CodimensionStmt>, common::Indirection<ContiguousStmt>,
|
|
common::Indirection<DimensionStmt>, common::Indirection<ExternalStmt>,
|
|
common::Indirection<IntentStmt>, common::Indirection<IntrinsicStmt>,
|
|
common::Indirection<NamelistStmt>, common::Indirection<OptionalStmt>,
|
|
common::Indirection<PointerStmt>, common::Indirection<ProtectedStmt>,
|
|
common::Indirection<SaveStmt>, common::Indirection<TargetStmt>,
|
|
common::Indirection<ValueStmt>, common::Indirection<VolatileStmt>,
|
|
common::Indirection<CommonStmt>, common::Indirection<EquivalenceStmt>,
|
|
common::Indirection<BasedPointerStmt>,
|
|
common::Indirection<CUDAAttributesStmt>>
|
|
u;
|
|
};
|
|
|
|
// R508 specification-construct ->
|
|
// derived-type-def | enum-def | generic-stmt | interface-block |
|
|
// parameter-stmt | procedure-declaration-stmt |
|
|
// other-specification-stmt | type-declaration-stmt
|
|
struct SpecificationConstruct {
|
|
UNION_CLASS_BOILERPLATE(SpecificationConstruct);
|
|
std::variant<common::Indirection<DerivedTypeDef>,
|
|
common::Indirection<EnumDef>, Statement<common::Indirection<GenericStmt>>,
|
|
common::Indirection<InterfaceBlock>,
|
|
Statement<common::Indirection<ParameterStmt>>,
|
|
Statement<common::Indirection<OldParameterStmt>>,
|
|
Statement<common::Indirection<ProcedureDeclarationStmt>>,
|
|
Statement<OtherSpecificationStmt>,
|
|
Statement<common::Indirection<TypeDeclarationStmt>>,
|
|
common::Indirection<StructureDef>,
|
|
common::Indirection<OpenACCDeclarativeConstruct>,
|
|
common::Indirection<OpenMPDeclarativeConstruct>,
|
|
common::Indirection<CompilerDirective>>
|
|
u;
|
|
};
|
|
|
|
// R506 implicit-part-stmt ->
|
|
// implicit-stmt | parameter-stmt | format-stmt | entry-stmt
|
|
struct ImplicitPartStmt {
|
|
UNION_CLASS_BOILERPLATE(ImplicitPartStmt);
|
|
std::variant<Statement<common::Indirection<ImplicitStmt>>,
|
|
Statement<common::Indirection<ParameterStmt>>,
|
|
Statement<common::Indirection<OldParameterStmt>>,
|
|
Statement<common::Indirection<FormatStmt>>,
|
|
Statement<common::Indirection<EntryStmt>>,
|
|
common::Indirection<CompilerDirective>,
|
|
common::Indirection<OpenACCDeclarativeConstruct>>
|
|
u;
|
|
};
|
|
|
|
// R505 implicit-part -> [implicit-part-stmt]... implicit-stmt
|
|
WRAPPER_CLASS(ImplicitPart, std::list<ImplicitPartStmt>);
|
|
|
|
// R507 declaration-construct ->
|
|
// specification-construct | data-stmt | format-stmt |
|
|
// entry-stmt | stmt-function-stmt
|
|
struct DeclarationConstruct {
|
|
UNION_CLASS_BOILERPLATE(DeclarationConstruct);
|
|
std::variant<SpecificationConstruct, Statement<common::Indirection<DataStmt>>,
|
|
Statement<common::Indirection<FormatStmt>>,
|
|
Statement<common::Indirection<EntryStmt>>,
|
|
Statement<common::Indirection<StmtFunctionStmt>>, ErrorRecovery>
|
|
u;
|
|
};
|
|
|
|
// R504 specification-part -> [use-stmt]... [import-stmt]... [implicit-part]
|
|
// [declaration-construct]...
|
|
// PARAMETER, FORMAT, and ENTRY statements that appear before any other
|
|
// kind of declaration-construct will be parsed into the implicit-part,
|
|
// even if there are no IMPLICIT statements.
|
|
struct SpecificationPart {
|
|
TUPLE_CLASS_BOILERPLATE(SpecificationPart);
|
|
std::tuple<std::list<OpenACCDeclarativeConstruct>,
|
|
std::list<OpenMPDeclarativeConstruct>,
|
|
std::list<common::Indirection<CompilerDirective>>,
|
|
std::list<Statement<common::Indirection<UseStmt>>>,
|
|
std::list<Statement<common::Indirection<ImportStmt>>>, ImplicitPart,
|
|
std::list<DeclarationConstruct>>
|
|
t;
|
|
};
|
|
|
|
// R512 internal-subprogram -> function-subprogram | subroutine-subprogram
|
|
struct InternalSubprogram {
|
|
UNION_CLASS_BOILERPLATE(InternalSubprogram);
|
|
std::variant<common::Indirection<FunctionSubprogram>,
|
|
common::Indirection<SubroutineSubprogram>,
|
|
common::Indirection<CompilerDirective>>
|
|
u;
|
|
};
|
|
|
|
// R1543 contains-stmt -> CONTAINS
|
|
EMPTY_CLASS(ContainsStmt);
|
|
|
|
// R511 internal-subprogram-part -> contains-stmt [internal-subprogram]...
|
|
struct InternalSubprogramPart {
|
|
TUPLE_CLASS_BOILERPLATE(InternalSubprogramPart);
|
|
std::tuple<Statement<ContainsStmt>, std::list<InternalSubprogram>> t;
|
|
};
|
|
|
|
// R1159 continue-stmt -> CONTINUE
|
|
EMPTY_CLASS(ContinueStmt);
|
|
|
|
// R1163 fail-image-stmt -> FAIL IMAGE
|
|
EMPTY_CLASS(FailImageStmt);
|
|
|
|
// 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 | notify-wait-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
|
|
struct ActionStmt {
|
|
UNION_CLASS_BOILERPLATE(ActionStmt);
|
|
std::variant<common::Indirection<AllocateStmt>,
|
|
common::Indirection<AssignmentStmt>, common::Indirection<BackspaceStmt>,
|
|
common::Indirection<CallStmt>, common::Indirection<CloseStmt>,
|
|
ContinueStmt, common::Indirection<CycleStmt>,
|
|
common::Indirection<DeallocateStmt>, common::Indirection<EndfileStmt>,
|
|
common::Indirection<EventPostStmt>, common::Indirection<EventWaitStmt>,
|
|
common::Indirection<ExitStmt>, FailImageStmt,
|
|
common::Indirection<FlushStmt>, common::Indirection<FormTeamStmt>,
|
|
common::Indirection<GotoStmt>, common::Indirection<IfStmt>,
|
|
common::Indirection<InquireStmt>, common::Indirection<LockStmt>,
|
|
common::Indirection<NotifyWaitStmt>, common::Indirection<NullifyStmt>,
|
|
common::Indirection<OpenStmt>, common::Indirection<PointerAssignmentStmt>,
|
|
common::Indirection<PrintStmt>, common::Indirection<ReadStmt>,
|
|
common::Indirection<ReturnStmt>, common::Indirection<RewindStmt>,
|
|
common::Indirection<StopStmt>, common::Indirection<SyncAllStmt>,
|
|
common::Indirection<SyncImagesStmt>, common::Indirection<SyncMemoryStmt>,
|
|
common::Indirection<SyncTeamStmt>, common::Indirection<UnlockStmt>,
|
|
common::Indirection<WaitStmt>, common::Indirection<WhereStmt>,
|
|
common::Indirection<WriteStmt>, common::Indirection<ComputedGotoStmt>,
|
|
common::Indirection<ForallStmt>, common::Indirection<ArithmeticIfStmt>,
|
|
common::Indirection<AssignStmt>, common::Indirection<AssignedGotoStmt>,
|
|
common::Indirection<PauseStmt>>
|
|
u;
|
|
};
|
|
|
|
// 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 |
|
|
// (CUDA) CUF-kernel-do-construct
|
|
struct ExecutableConstruct {
|
|
UNION_CLASS_BOILERPLATE(ExecutableConstruct);
|
|
std::variant<Statement<ActionStmt>, common::Indirection<AssociateConstruct>,
|
|
common::Indirection<BlockConstruct>, common::Indirection<CaseConstruct>,
|
|
common::Indirection<ChangeTeamConstruct>,
|
|
common::Indirection<CriticalConstruct>,
|
|
Statement<common::Indirection<LabelDoStmt>>,
|
|
Statement<common::Indirection<EndDoStmt>>,
|
|
common::Indirection<DoConstruct>, common::Indirection<IfConstruct>,
|
|
common::Indirection<SelectRankConstruct>,
|
|
common::Indirection<SelectTypeConstruct>,
|
|
common::Indirection<WhereConstruct>, common::Indirection<ForallConstruct>,
|
|
common::Indirection<CompilerDirective>,
|
|
common::Indirection<OpenACCConstruct>,
|
|
common::Indirection<AccEndCombinedDirective>,
|
|
common::Indirection<OpenMPConstruct>,
|
|
common::Indirection<OmpEndLoopDirective>,
|
|
common::Indirection<CUFKernelDoConstruct>>
|
|
u;
|
|
};
|
|
|
|
// R510 execution-part-construct ->
|
|
// executable-construct | format-stmt | entry-stmt | data-stmt
|
|
// Extension (PGI/Intel): also accept NAMELIST in execution part
|
|
struct ExecutionPartConstruct {
|
|
UNION_CLASS_BOILERPLATE(ExecutionPartConstruct);
|
|
std::variant<ExecutableConstruct, Statement<common::Indirection<FormatStmt>>,
|
|
Statement<common::Indirection<EntryStmt>>,
|
|
Statement<common::Indirection<DataStmt>>,
|
|
Statement<common::Indirection<NamelistStmt>>, ErrorRecovery>
|
|
u;
|
|
};
|
|
|
|
// R509 execution-part -> executable-construct [execution-part-construct]...
|
|
// R1101 block -> [execution-part-construct]...
|
|
using Block = std::list<ExecutionPartConstruct>;
|
|
WRAPPER_CLASS(ExecutionPart, Block);
|
|
|
|
// R502 program-unit ->
|
|
// main-program | external-subprogram | module | submodule | block-data
|
|
// R503 external-subprogram -> function-subprogram | subroutine-subprogram
|
|
struct ProgramUnit {
|
|
UNION_CLASS_BOILERPLATE(ProgramUnit);
|
|
std::variant<common::Indirection<MainProgram>,
|
|
common::Indirection<FunctionSubprogram>,
|
|
common::Indirection<SubroutineSubprogram>, common::Indirection<Module>,
|
|
common::Indirection<Submodule>, common::Indirection<BlockData>,
|
|
common::Indirection<CompilerDirective>,
|
|
common::Indirection<OpenACCRoutineConstruct>>
|
|
u;
|
|
};
|
|
|
|
// R501 program -> program-unit [program-unit]...
|
|
// This is the top-level production.
|
|
WRAPPER_CLASS(Program, std::list<ProgramUnit>);
|
|
|
|
// R603 name -> letter [alphanumeric-character]...
|
|
struct Name {
|
|
std::string ToString() const { return source.ToString(); }
|
|
CharBlock source;
|
|
mutable semantics::Symbol *symbol{nullptr}; // filled in during semantics
|
|
};
|
|
|
|
// R516 keyword -> name
|
|
WRAPPER_CLASS(Keyword, Name);
|
|
|
|
// R606 named-constant -> name
|
|
WRAPPER_CLASS(NamedConstant, Name);
|
|
|
|
// 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
|
|
// The Name here is stored with the dots; e.g., .FOO.
|
|
WRAPPER_CLASS(DefinedOpName, Name);
|
|
|
|
// R608 intrinsic-operator ->
|
|
// ** | * | / | + | - | // | .LT. | .LE. | .EQ. | .NE. | .GE. | .GT. |
|
|
// .NOT. | .AND. | .OR. | .EQV. | .NEQV.
|
|
// R609 defined-operator ->
|
|
// defined-unary-op | defined-binary-op | extended-intrinsic-op
|
|
// R610 extended-intrinsic-op -> intrinsic-operator
|
|
struct DefinedOperator {
|
|
UNION_CLASS_BOILERPLATE(DefinedOperator);
|
|
ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat,
|
|
LT, LE, EQ, NE, GE, GT, NOT, AND, OR, EQV, NEQV)
|
|
std::variant<DefinedOpName, IntrinsicOperator> u;
|
|
};
|
|
|
|
// R804 object-name -> name
|
|
using ObjectName = Name;
|
|
|
|
// R867 import-stmt ->
|
|
// IMPORT [[::] import-name-list] |
|
|
// IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
|
|
struct ImportStmt {
|
|
BOILERPLATE(ImportStmt);
|
|
ImportStmt(common::ImportKind &&k) : kind{k} {}
|
|
ImportStmt(std::list<Name> &&n) : names(std::move(n)) {}
|
|
ImportStmt(common::ImportKind &&, std::list<Name> &&);
|
|
common::ImportKind kind{common::ImportKind::Default};
|
|
std::list<Name> names;
|
|
};
|
|
|
|
// R868 namelist-stmt ->
|
|
// NAMELIST / namelist-group-name / namelist-group-object-list
|
|
// [[,] / namelist-group-name / namelist-group-object-list]...
|
|
// R869 namelist-group-object -> variable-name
|
|
struct NamelistStmt {
|
|
struct Group {
|
|
TUPLE_CLASS_BOILERPLATE(Group);
|
|
std::tuple<Name, std::list<Name>> t;
|
|
};
|
|
WRAPPER_CLASS_BOILERPLATE(NamelistStmt, std::list<Group>);
|
|
};
|
|
|
|
// R701 type-param-value -> scalar-int-expr | * | :
|
|
EMPTY_CLASS(Star);
|
|
|
|
struct TypeParamValue {
|
|
UNION_CLASS_BOILERPLATE(TypeParamValue);
|
|
EMPTY_CLASS(Deferred); // :
|
|
std::variant<ScalarIntExpr, Star, Deferred> u;
|
|
};
|
|
|
|
// R706 kind-selector -> ( [KIND =] scalar-int-constant-expr )
|
|
// Legacy extension: kind-selector -> * digit-string
|
|
// N.B. These are not semantically identical in the case of COMPLEX.
|
|
struct KindSelector {
|
|
UNION_CLASS_BOILERPLATE(KindSelector);
|
|
WRAPPER_CLASS(StarSize, std::uint64_t);
|
|
std::variant<ScalarIntConstantExpr, StarSize> u;
|
|
};
|
|
|
|
// R705 integer-type-spec -> INTEGER [kind-selector]
|
|
WRAPPER_CLASS(IntegerTypeSpec, std::optional<KindSelector>);
|
|
|
|
WRAPPER_CLASS(UnsignedTypeSpec, std::optional<KindSelector>);
|
|
|
|
// R723 char-length -> ( type-param-value ) | digit-string
|
|
struct CharLength {
|
|
UNION_CLASS_BOILERPLATE(CharLength);
|
|
std::variant<TypeParamValue, std::uint64_t> u;
|
|
};
|
|
|
|
// R722 length-selector -> ( [LEN =] type-param-value ) | * char-length [,]
|
|
struct LengthSelector {
|
|
UNION_CLASS_BOILERPLATE(LengthSelector);
|
|
std::variant<TypeParamValue, CharLength> u;
|
|
};
|
|
|
|
// 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] )
|
|
struct CharSelector {
|
|
UNION_CLASS_BOILERPLATE(CharSelector);
|
|
struct LengthAndKind {
|
|
BOILERPLATE(LengthAndKind);
|
|
LengthAndKind(std::optional<TypeParamValue> &&l, ScalarIntConstantExpr &&k)
|
|
: length(std::move(l)), kind(std::move(k)) {}
|
|
std::optional<TypeParamValue> length;
|
|
ScalarIntConstantExpr kind;
|
|
};
|
|
CharSelector(TypeParamValue &&l, ScalarIntConstantExpr &&k)
|
|
: u{LengthAndKind{std::make_optional(std::move(l)), std::move(k)}} {}
|
|
CharSelector(ScalarIntConstantExpr &&k, std::optional<TypeParamValue> &&l)
|
|
: u{LengthAndKind{std::move(l), std::move(k)}} {}
|
|
std::variant<LengthSelector, LengthAndKind> u;
|
|
};
|
|
|
|
// R704 intrinsic-type-spec ->
|
|
// integer-type-spec | REAL [kind-selector] | DOUBLE PRECISION |
|
|
// COMPLEX [kind-selector] | CHARACTER [char-selector] |
|
|
// LOGICAL [kind-selector]
|
|
// Extensions: DOUBLE COMPLEX & UNSIGNED [kind-selector]
|
|
struct IntrinsicTypeSpec {
|
|
UNION_CLASS_BOILERPLATE(IntrinsicTypeSpec);
|
|
struct Real {
|
|
BOILERPLATE(Real);
|
|
Real(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
|
|
std::optional<KindSelector> kind;
|
|
};
|
|
EMPTY_CLASS(DoublePrecision);
|
|
struct Complex {
|
|
BOILERPLATE(Complex);
|
|
Complex(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
|
|
std::optional<KindSelector> kind;
|
|
};
|
|
struct Character {
|
|
BOILERPLATE(Character);
|
|
Character(std::optional<CharSelector> &&s) : selector{std::move(s)} {}
|
|
std::optional<CharSelector> selector;
|
|
};
|
|
struct Logical {
|
|
BOILERPLATE(Logical);
|
|
Logical(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
|
|
std::optional<KindSelector> kind;
|
|
};
|
|
EMPTY_CLASS(DoubleComplex);
|
|
std::variant<IntegerTypeSpec, UnsignedTypeSpec, Real, DoublePrecision,
|
|
Complex, Character, Logical, DoubleComplex>
|
|
u;
|
|
};
|
|
|
|
// Extension: Vector type
|
|
struct VectorElementType {
|
|
UNION_CLASS_BOILERPLATE(VectorElementType);
|
|
std::variant<IntegerTypeSpec, IntrinsicTypeSpec::Real, UnsignedTypeSpec> u;
|
|
};
|
|
WRAPPER_CLASS(IntrinsicVectorTypeSpec, VectorElementType);
|
|
struct VectorTypeSpec {
|
|
UNION_CLASS_BOILERPLATE(VectorTypeSpec);
|
|
EMPTY_CLASS(PairVectorTypeSpec);
|
|
EMPTY_CLASS(QuadVectorTypeSpec);
|
|
std::variant<IntrinsicVectorTypeSpec, PairVectorTypeSpec, QuadVectorTypeSpec>
|
|
u;
|
|
};
|
|
|
|
// R755 type-param-spec -> [keyword =] type-param-value
|
|
struct TypeParamSpec {
|
|
TUPLE_CLASS_BOILERPLATE(TypeParamSpec);
|
|
std::tuple<std::optional<Keyword>, TypeParamValue> t;
|
|
};
|
|
|
|
// R754 derived-type-spec -> type-name [(type-param-spec-list)]
|
|
struct DerivedTypeSpec {
|
|
TUPLE_CLASS_BOILERPLATE(DerivedTypeSpec);
|
|
mutable const semantics::DerivedTypeSpec *derivedTypeSpec{nullptr};
|
|
std::tuple<Name, std::list<TypeParamSpec>> t;
|
|
};
|
|
|
|
// R702 type-spec -> intrinsic-type-spec | derived-type-spec
|
|
struct TypeSpec {
|
|
UNION_CLASS_BOILERPLATE(TypeSpec);
|
|
mutable const semantics::DeclTypeSpec *declTypeSpec{nullptr};
|
|
std::variant<IntrinsicTypeSpec, DerivedTypeSpec> u;
|
|
};
|
|
|
|
// R703 declaration-type-spec ->
|
|
// intrinsic-type-spec | TYPE ( intrinsic-type-spec ) |
|
|
// TYPE ( derived-type-spec ) | CLASS ( derived-type-spec ) |
|
|
// CLASS ( * ) | TYPE ( * )
|
|
// Legacy extension: RECORD /struct/
|
|
struct DeclarationTypeSpec {
|
|
UNION_CLASS_BOILERPLATE(DeclarationTypeSpec);
|
|
struct Type {
|
|
BOILERPLATE(Type);
|
|
Type(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
|
|
DerivedTypeSpec derived;
|
|
};
|
|
struct Class {
|
|
BOILERPLATE(Class);
|
|
Class(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
|
|
DerivedTypeSpec derived;
|
|
};
|
|
EMPTY_CLASS(ClassStar);
|
|
EMPTY_CLASS(TypeStar);
|
|
WRAPPER_CLASS(Record, Name);
|
|
std::variant<IntrinsicTypeSpec, Type, Class, ClassStar, TypeStar, Record,
|
|
VectorTypeSpec>
|
|
u;
|
|
};
|
|
|
|
// R709 kind-param -> digit-string | scalar-int-constant-name
|
|
struct KindParam {
|
|
UNION_CLASS_BOILERPLATE(KindParam);
|
|
std::variant<std::uint64_t, Scalar<Integer<Constant<Name>>>> u;
|
|
};
|
|
|
|
// R707 signed-int-literal-constant -> [sign] int-literal-constant
|
|
struct SignedIntLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(SignedIntLiteralConstant);
|
|
CharBlock source;
|
|
std::tuple<CharBlock, std::optional<KindParam>> t;
|
|
};
|
|
|
|
// R708 int-literal-constant -> digit-string [_ kind-param]
|
|
struct IntLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(IntLiteralConstant);
|
|
std::tuple<CharBlock, std::optional<KindParam>> t;
|
|
};
|
|
|
|
// extension: unsigned-literal-constant -> digit-string U [_ kind-param]
|
|
struct UnsignedLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(UnsignedLiteralConstant);
|
|
std::tuple<CharBlock, std::optional<KindParam>> t;
|
|
};
|
|
|
|
// R712 sign -> + | -
|
|
enum class Sign { Positive, Negative };
|
|
|
|
// 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
|
|
// R717 exponent -> signed-digit-string
|
|
struct RealLiteralConstant {
|
|
BOILERPLATE(RealLiteralConstant);
|
|
struct Real {
|
|
COPY_AND_ASSIGN_BOILERPLATE(Real);
|
|
Real() {}
|
|
CharBlock source;
|
|
};
|
|
RealLiteralConstant(Real &&r, std::optional<KindParam> &&k)
|
|
: real{std::move(r)}, kind{std::move(k)} {}
|
|
Real real;
|
|
std::optional<KindParam> kind;
|
|
};
|
|
|
|
// R713 signed-real-literal-constant -> [sign] real-literal-constant
|
|
struct SignedRealLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(SignedRealLiteralConstant);
|
|
std::tuple<std::optional<Sign>, RealLiteralConstant> t;
|
|
};
|
|
|
|
// 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
|
|
struct ComplexPart {
|
|
UNION_CLASS_BOILERPLATE(ComplexPart);
|
|
std::variant<SignedIntLiteralConstant, SignedRealLiteralConstant,
|
|
NamedConstant>
|
|
u;
|
|
};
|
|
|
|
// R718 complex-literal-constant -> ( real-part , imag-part )
|
|
struct ComplexLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(ComplexLiteralConstant);
|
|
std::tuple<ComplexPart, ComplexPart> t; // real, imaginary
|
|
};
|
|
|
|
// Extension: signed COMPLEX constant
|
|
struct SignedComplexLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(SignedComplexLiteralConstant);
|
|
std::tuple<Sign, ComplexLiteralConstant> t;
|
|
};
|
|
|
|
// R724 char-literal-constant ->
|
|
// [kind-param _] ' [rep-char]... ' |
|
|
// [kind-param _] " [rep-char]... "
|
|
struct CharLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(CharLiteralConstant);
|
|
std::tuple<std::optional<KindParam>, std::string> t;
|
|
std::string GetString() const { return std::get<std::string>(t); }
|
|
};
|
|
|
|
// legacy extension
|
|
struct HollerithLiteralConstant {
|
|
WRAPPER_CLASS_BOILERPLATE(HollerithLiteralConstant, std::string);
|
|
std::string GetString() const { return v; }
|
|
};
|
|
|
|
// R725 logical-literal-constant ->
|
|
// .TRUE. [_ kind-param] | .FALSE. [_ kind-param]
|
|
struct LogicalLiteralConstant {
|
|
TUPLE_CLASS_BOILERPLATE(LogicalLiteralConstant);
|
|
std::tuple<bool, std::optional<KindParam>> t;
|
|
};
|
|
|
|
// 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]... "
|
|
// The constant must be large enough to hold any real or integer scalar
|
|
// of any supported kind (F'2018 7.7).
|
|
WRAPPER_CLASS(BOZLiteralConstant, std::string);
|
|
|
|
// R605 literal-constant ->
|
|
// int-literal-constant | real-literal-constant |
|
|
// complex-literal-constant | logical-literal-constant |
|
|
// char-literal-constant | boz-literal-constant
|
|
struct LiteralConstant {
|
|
UNION_CLASS_BOILERPLATE(LiteralConstant);
|
|
std::variant<HollerithLiteralConstant, IntLiteralConstant,
|
|
RealLiteralConstant, ComplexLiteralConstant, BOZLiteralConstant,
|
|
CharLiteralConstant, LogicalLiteralConstant, UnsignedLiteralConstant>
|
|
u;
|
|
};
|
|
|
|
// R807 access-spec -> PUBLIC | PRIVATE
|
|
struct AccessSpec {
|
|
ENUM_CLASS(Kind, Public, Private)
|
|
WRAPPER_CLASS_BOILERPLATE(AccessSpec, Kind);
|
|
};
|
|
|
|
// R728 type-attr-spec ->
|
|
// ABSTRACT | access-spec | BIND(C) | EXTENDS ( parent-type-name )
|
|
EMPTY_CLASS(Abstract);
|
|
struct TypeAttrSpec {
|
|
UNION_CLASS_BOILERPLATE(TypeAttrSpec);
|
|
EMPTY_CLASS(BindC);
|
|
WRAPPER_CLASS(Extends, Name);
|
|
std::variant<Abstract, AccessSpec, BindC, Extends> u;
|
|
};
|
|
|
|
// R727 derived-type-stmt ->
|
|
// TYPE [[, type-attr-spec-list] ::] type-name [( type-param-name-list )]
|
|
struct DerivedTypeStmt {
|
|
TUPLE_CLASS_BOILERPLATE(DerivedTypeStmt);
|
|
std::tuple<std::list<TypeAttrSpec>, Name, std::list<Name>> t;
|
|
};
|
|
|
|
// R731 sequence-stmt -> SEQUENCE
|
|
EMPTY_CLASS(SequenceStmt);
|
|
|
|
// R745 private-components-stmt -> PRIVATE
|
|
// R747 binding-private-stmt -> PRIVATE
|
|
EMPTY_CLASS(PrivateStmt);
|
|
|
|
// R729 private-or-sequence -> private-components-stmt | sequence-stmt
|
|
struct PrivateOrSequence {
|
|
UNION_CLASS_BOILERPLATE(PrivateOrSequence);
|
|
std::variant<PrivateStmt, SequenceStmt> u;
|
|
};
|
|
|
|
// R733 type-param-decl -> type-param-name [= scalar-int-constant-expr]
|
|
struct TypeParamDecl {
|
|
TUPLE_CLASS_BOILERPLATE(TypeParamDecl);
|
|
std::tuple<Name, std::optional<ScalarIntConstantExpr>> t;
|
|
};
|
|
|
|
// R732 type-param-def-stmt ->
|
|
// integer-type-spec , type-param-attr-spec :: type-param-decl-list
|
|
// R734 type-param-attr-spec -> KIND | LEN
|
|
struct TypeParamDefStmt {
|
|
TUPLE_CLASS_BOILERPLATE(TypeParamDefStmt);
|
|
std::tuple<IntegerTypeSpec, common::TypeParamAttr, std::list<TypeParamDecl>>
|
|
t;
|
|
};
|
|
|
|
// R1028 specification-expr -> scalar-int-expr
|
|
WRAPPER_CLASS(SpecificationExpr, ScalarIntExpr);
|
|
|
|
// R816 explicit-shape-spec -> [lower-bound :] upper-bound
|
|
// R817 lower-bound -> specification-expr
|
|
// R818 upper-bound -> specification-expr
|
|
struct ExplicitShapeSpec {
|
|
TUPLE_CLASS_BOILERPLATE(ExplicitShapeSpec);
|
|
std::tuple<std::optional<SpecificationExpr>, SpecificationExpr> t;
|
|
};
|
|
|
|
// R810 deferred-coshape-spec -> :
|
|
// deferred-coshape-spec-list is just a count of the colons (i.e., the rank).
|
|
WRAPPER_CLASS(DeferredCoshapeSpecList, int);
|
|
|
|
// R811 explicit-coshape-spec ->
|
|
// [[lower-cobound :] upper-cobound ,]... [lower-cobound :] *
|
|
// R812 lower-cobound -> specification-expr
|
|
// R813 upper-cobound -> specification-expr
|
|
struct ExplicitCoshapeSpec {
|
|
TUPLE_CLASS_BOILERPLATE(ExplicitCoshapeSpec);
|
|
std::tuple<std::list<ExplicitShapeSpec>, std::optional<SpecificationExpr>> t;
|
|
};
|
|
|
|
// R809 coarray-spec -> deferred-coshape-spec-list | explicit-coshape-spec
|
|
struct CoarraySpec {
|
|
UNION_CLASS_BOILERPLATE(CoarraySpec);
|
|
std::variant<DeferredCoshapeSpecList, ExplicitCoshapeSpec> u;
|
|
};
|
|
|
|
// R820 deferred-shape-spec -> :
|
|
// deferred-shape-spec-list is just a count of the colons (i.e., the rank).
|
|
WRAPPER_CLASS(DeferredShapeSpecList, int);
|
|
|
|
// R740 component-array-spec ->
|
|
// explicit-shape-spec-list | deferred-shape-spec-list
|
|
struct ComponentArraySpec {
|
|
UNION_CLASS_BOILERPLATE(ComponentArraySpec);
|
|
std::variant<std::list<ExplicitShapeSpec>, DeferredShapeSpecList> u;
|
|
};
|
|
|
|
// R738 component-attr-spec ->
|
|
// access-spec | ALLOCATABLE |
|
|
// CODIMENSION lbracket coarray-spec rbracket |
|
|
// CONTIGUOUS | DIMENSION ( component-array-spec ) | POINTER |
|
|
// (CUDA) CONSTANT | DEVICE | MANAGED | PINNED | SHARED | TEXTURE | UNIFIED
|
|
EMPTY_CLASS(Allocatable);
|
|
EMPTY_CLASS(Pointer);
|
|
EMPTY_CLASS(Contiguous);
|
|
struct ComponentAttrSpec {
|
|
UNION_CLASS_BOILERPLATE(ComponentAttrSpec);
|
|
std::variant<AccessSpec, Allocatable, CoarraySpec, Contiguous,
|
|
ComponentArraySpec, Pointer, common::CUDADataAttr, ErrorRecovery>
|
|
u;
|
|
};
|
|
|
|
// R806 null-init -> function-reference ... which must be NULL()
|
|
WRAPPER_CLASS(NullInit, common::Indirection<Expr>);
|
|
|
|
// R744 initial-data-target -> designator
|
|
using InitialDataTarget = common::Indirection<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 /
|
|
struct Initialization {
|
|
UNION_CLASS_BOILERPLATE(Initialization);
|
|
std::variant<ConstantExpr, NullInit, InitialDataTarget,
|
|
std::list<common::Indirection<DataStmtValue>>>
|
|
u;
|
|
};
|
|
|
|
// R739 component-decl ->
|
|
// component-name [( component-array-spec )]
|
|
// [lbracket coarray-spec rbracket] [* char-length]
|
|
// [component-initialization] |
|
|
// component-name *char-length [( component-array-spec )]
|
|
// [lbracket coarray-spec rbracket] [component-initialization]
|
|
struct ComponentDecl {
|
|
TUPLE_CLASS_BOILERPLATE(ComponentDecl);
|
|
ComponentDecl(Name &&name, CharLength &&length,
|
|
std::optional<ComponentArraySpec> &&aSpec,
|
|
std::optional<CoarraySpec> &&coaSpec,
|
|
std::optional<Initialization> &&init)
|
|
: t{std::move(name), std::move(aSpec), std::move(coaSpec),
|
|
std::move(length), std::move(init)} {}
|
|
std::tuple<Name, std::optional<ComponentArraySpec>,
|
|
std::optional<CoarraySpec>, std::optional<CharLength>,
|
|
std::optional<Initialization>>
|
|
t;
|
|
};
|
|
|
|
// A %FILL component for a DEC STRUCTURE. The name will be replaced
|
|
// with a distinct compiler-generated name.
|
|
struct FillDecl {
|
|
TUPLE_CLASS_BOILERPLATE(FillDecl);
|
|
std::tuple<Name, std::optional<ComponentArraySpec>, std::optional<CharLength>>
|
|
t;
|
|
};
|
|
|
|
struct ComponentOrFill {
|
|
UNION_CLASS_BOILERPLATE(ComponentOrFill);
|
|
std::variant<ComponentDecl, FillDecl> u;
|
|
};
|
|
|
|
// R737 data-component-def-stmt ->
|
|
// declaration-type-spec [[, component-attr-spec-list] ::]
|
|
// component-decl-list
|
|
struct DataComponentDefStmt {
|
|
TUPLE_CLASS_BOILERPLATE(DataComponentDefStmt);
|
|
std::tuple<DeclarationTypeSpec, std::list<ComponentAttrSpec>,
|
|
std::list<ComponentOrFill>>
|
|
t;
|
|
};
|
|
|
|
// R742 proc-component-attr-spec ->
|
|
// access-spec | NOPASS | PASS [(arg-name)] | POINTER
|
|
EMPTY_CLASS(NoPass);
|
|
WRAPPER_CLASS(Pass, std::optional<Name>);
|
|
struct ProcComponentAttrSpec {
|
|
UNION_CLASS_BOILERPLATE(ProcComponentAttrSpec);
|
|
std::variant<AccessSpec, NoPass, Pass, Pointer> u;
|
|
};
|
|
|
|
// R1517 proc-pointer-init -> null-init | initial-proc-target
|
|
// R1518 initial-proc-target -> procedure-name
|
|
struct ProcPointerInit {
|
|
UNION_CLASS_BOILERPLATE(ProcPointerInit);
|
|
std::variant<NullInit, Name> u;
|
|
};
|
|
|
|
// R1513 proc-interface -> interface-name | declaration-type-spec
|
|
// R1516 interface-name -> name
|
|
struct ProcInterface {
|
|
UNION_CLASS_BOILERPLATE(ProcInterface);
|
|
std::variant<Name, DeclarationTypeSpec> u;
|
|
};
|
|
|
|
// R1515 proc-decl -> procedure-entity-name [=> proc-pointer-init]
|
|
struct ProcDecl {
|
|
TUPLE_CLASS_BOILERPLATE(ProcDecl);
|
|
std::tuple<Name, std::optional<ProcPointerInit>> t;
|
|
};
|
|
|
|
// R741 proc-component-def-stmt ->
|
|
// PROCEDURE ( [proc-interface] ) , proc-component-attr-spec-list
|
|
// :: proc-decl-list
|
|
struct ProcComponentDefStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ProcComponentDefStmt);
|
|
std::tuple<std::optional<ProcInterface>, std::list<ProcComponentAttrSpec>,
|
|
std::list<ProcDecl>>
|
|
t;
|
|
};
|
|
|
|
// R736 component-def-stmt -> data-component-def-stmt | proc-component-def-stmt
|
|
struct ComponentDefStmt {
|
|
UNION_CLASS_BOILERPLATE(ComponentDefStmt);
|
|
std::variant<DataComponentDefStmt, ProcComponentDefStmt,
|
|
common::Indirection<CompilerDirective>, ErrorRecovery
|
|
// , TypeParamDefStmt -- PGI accidental extension, not enabled
|
|
>
|
|
u;
|
|
};
|
|
|
|
// R752 bind-attr ->
|
|
// access-spec | DEFERRED | NON_OVERRIDABLE | NOPASS | PASS [(arg-name)]
|
|
struct BindAttr {
|
|
UNION_CLASS_BOILERPLATE(BindAttr);
|
|
EMPTY_CLASS(Deferred);
|
|
EMPTY_CLASS(Non_Overridable);
|
|
std::variant<AccessSpec, Deferred, Non_Overridable, NoPass, Pass> u;
|
|
};
|
|
|
|
// R750 type-bound-proc-decl -> binding-name [=> procedure-name]
|
|
struct TypeBoundProcDecl {
|
|
TUPLE_CLASS_BOILERPLATE(TypeBoundProcDecl);
|
|
std::tuple<Name, std::optional<Name>> t;
|
|
};
|
|
|
|
// R749 type-bound-procedure-stmt ->
|
|
// PROCEDURE [[, bind-attr-list] ::] type-bound-proc-decl-list |
|
|
// PROCEDURE ( interface-name ) , bind-attr-list :: binding-name-list
|
|
// The second form, with interface-name, requires DEFERRED in bind-attr-list,
|
|
// and thus can appear only in an abstract type.
|
|
struct TypeBoundProcedureStmt {
|
|
UNION_CLASS_BOILERPLATE(TypeBoundProcedureStmt);
|
|
struct WithoutInterface {
|
|
BOILERPLATE(WithoutInterface);
|
|
WithoutInterface(
|
|
std::list<BindAttr> &&as, std::list<TypeBoundProcDecl> &&ds)
|
|
: attributes(std::move(as)), declarations(std::move(ds)) {}
|
|
std::list<BindAttr> attributes;
|
|
std::list<TypeBoundProcDecl> declarations;
|
|
};
|
|
struct WithInterface {
|
|
BOILERPLATE(WithInterface);
|
|
WithInterface(Name &&n, std::list<BindAttr> &&as, std::list<Name> &&bs)
|
|
: interfaceName(std::move(n)), attributes(std::move(as)),
|
|
bindingNames(std::move(bs)) {}
|
|
Name interfaceName;
|
|
std::list<BindAttr> attributes;
|
|
std::list<Name> bindingNames;
|
|
};
|
|
std::variant<WithoutInterface, WithInterface> u;
|
|
};
|
|
|
|
// R751 type-bound-generic-stmt ->
|
|
// GENERIC [, access-spec] :: generic-spec => binding-name-list
|
|
struct TypeBoundGenericStmt {
|
|
TUPLE_CLASS_BOILERPLATE(TypeBoundGenericStmt);
|
|
std::tuple<std::optional<AccessSpec>, common::Indirection<GenericSpec>,
|
|
std::list<Name>>
|
|
t;
|
|
};
|
|
|
|
// R753 final-procedure-stmt -> FINAL [::] final-subroutine-name-list
|
|
WRAPPER_CLASS(FinalProcedureStmt, std::list<Name>);
|
|
|
|
// R748 type-bound-proc-binding ->
|
|
// type-bound-procedure-stmt | type-bound-generic-stmt |
|
|
// final-procedure-stmt
|
|
struct TypeBoundProcBinding {
|
|
UNION_CLASS_BOILERPLATE(TypeBoundProcBinding);
|
|
std::variant<TypeBoundProcedureStmt, TypeBoundGenericStmt, FinalProcedureStmt,
|
|
ErrorRecovery>
|
|
u;
|
|
};
|
|
|
|
// R746 type-bound-procedure-part ->
|
|
// contains-stmt [binding-private-stmt] [type-bound-proc-binding]...
|
|
struct TypeBoundProcedurePart {
|
|
TUPLE_CLASS_BOILERPLATE(TypeBoundProcedurePart);
|
|
std::tuple<Statement<ContainsStmt>, std::optional<Statement<PrivateStmt>>,
|
|
std::list<Statement<TypeBoundProcBinding>>>
|
|
t;
|
|
};
|
|
|
|
// R730 end-type-stmt -> END TYPE [type-name]
|
|
WRAPPER_CLASS(EndTypeStmt, std::optional<Name>);
|
|
|
|
// 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]...
|
|
struct DerivedTypeDef {
|
|
TUPLE_CLASS_BOILERPLATE(DerivedTypeDef);
|
|
std::tuple<Statement<DerivedTypeStmt>, std::list<Statement<TypeParamDefStmt>>,
|
|
std::list<Statement<PrivateOrSequence>>,
|
|
std::list<Statement<ComponentDefStmt>>,
|
|
std::optional<TypeBoundProcedurePart>, Statement<EndTypeStmt>>
|
|
t;
|
|
};
|
|
|
|
// R758 component-data-source -> expr | data-target | proc-target
|
|
// R1037 data-target -> expr
|
|
// R1040 proc-target -> expr | procedure-name | proc-component-ref
|
|
WRAPPER_CLASS(ComponentDataSource, common::Indirection<Expr>);
|
|
|
|
// R757 component-spec -> [keyword =] component-data-source
|
|
struct ComponentSpec {
|
|
TUPLE_CLASS_BOILERPLATE(ComponentSpec);
|
|
std::tuple<std::optional<Keyword>, ComponentDataSource> t;
|
|
};
|
|
|
|
// R756 structure-constructor -> derived-type-spec ( [component-spec-list] )
|
|
struct StructureConstructor {
|
|
TUPLE_CLASS_BOILERPLATE(StructureConstructor);
|
|
std::tuple<DerivedTypeSpec, std::list<ComponentSpec>> t;
|
|
};
|
|
|
|
// R760 enum-def-stmt -> ENUM, BIND(C)
|
|
EMPTY_CLASS(EnumDefStmt);
|
|
|
|
// R762 enumerator -> named-constant [= scalar-int-constant-expr]
|
|
struct Enumerator {
|
|
TUPLE_CLASS_BOILERPLATE(Enumerator);
|
|
std::tuple<NamedConstant, std::optional<ScalarIntConstantExpr>> t;
|
|
};
|
|
|
|
// R761 enumerator-def-stmt -> ENUMERATOR [::] enumerator-list
|
|
WRAPPER_CLASS(EnumeratorDefStmt, std::list<Enumerator>);
|
|
|
|
// R763 end-enum-stmt -> END ENUM
|
|
EMPTY_CLASS(EndEnumStmt);
|
|
|
|
// R759 enum-def ->
|
|
// enum-def-stmt enumerator-def-stmt [enumerator-def-stmt]...
|
|
// end-enum-stmt
|
|
struct EnumDef {
|
|
TUPLE_CLASS_BOILERPLATE(EnumDef);
|
|
std::tuple<Statement<EnumDefStmt>, std::list<Statement<EnumeratorDefStmt>>,
|
|
Statement<EndEnumStmt>>
|
|
t;
|
|
};
|
|
|
|
// R773 ac-value -> expr | ac-implied-do
|
|
struct AcValue {
|
|
struct Triplet { // PGI/Intel extension
|
|
TUPLE_CLASS_BOILERPLATE(Triplet);
|
|
std::tuple<ScalarIntExpr, ScalarIntExpr, std::optional<ScalarIntExpr>> t;
|
|
};
|
|
UNION_CLASS_BOILERPLATE(AcValue);
|
|
std::variant<Triplet, common::Indirection<Expr>,
|
|
common::Indirection<AcImpliedDo>>
|
|
u;
|
|
};
|
|
|
|
// R770 ac-spec -> type-spec :: | [type-spec ::] ac-value-list
|
|
struct AcSpec {
|
|
BOILERPLATE(AcSpec);
|
|
AcSpec(std::optional<TypeSpec> &&ts, std::list<AcValue> &&xs)
|
|
: type(std::move(ts)), values(std::move(xs)) {}
|
|
explicit AcSpec(TypeSpec &&ts) : type{std::move(ts)} {}
|
|
std::optional<TypeSpec> type;
|
|
std::list<AcValue> values;
|
|
};
|
|
|
|
// R769 array-constructor -> (/ ac-spec /) | lbracket ac-spec rbracket
|
|
WRAPPER_CLASS(ArrayConstructor, AcSpec);
|
|
|
|
// R1124 do-variable -> scalar-int-variable-name
|
|
using DoVariable = Scalar<Integer<Name>>;
|
|
|
|
template <typename VAR, typename BOUND> struct LoopBounds {
|
|
LoopBounds(LoopBounds &&that) = default;
|
|
LoopBounds(
|
|
VAR &&name, BOUND &&lower, BOUND &&upper, std::optional<BOUND> &&step)
|
|
: name{std::move(name)}, lower{std::move(lower)}, upper{std::move(upper)},
|
|
step{std::move(step)} {}
|
|
LoopBounds &operator=(LoopBounds &&) = default;
|
|
VAR name;
|
|
BOUND lower, upper;
|
|
std::optional<BOUND> step;
|
|
};
|
|
|
|
using ScalarName = Scalar<Name>;
|
|
using ScalarExpr = Scalar<common::Indirection<Expr>>;
|
|
|
|
// 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
|
|
struct AcImpliedDoControl {
|
|
TUPLE_CLASS_BOILERPLATE(AcImpliedDoControl);
|
|
using Bounds = LoopBounds<DoVariable, ScalarIntExpr>;
|
|
std::tuple<std::optional<IntegerTypeSpec>, Bounds> t;
|
|
};
|
|
|
|
// R774 ac-implied-do -> ( ac-value-list , ac-implied-do-control )
|
|
struct AcImpliedDo {
|
|
TUPLE_CLASS_BOILERPLATE(AcImpliedDo);
|
|
std::tuple<std::list<AcValue>, AcImpliedDoControl> t;
|
|
};
|
|
|
|
// R808 language-binding-spec ->
|
|
// BIND ( C [, NAME = scalar-default-char-constant-expr ]
|
|
// [, CDEFINED ] )
|
|
// R1528 proc-language-binding-spec -> language-binding-spec
|
|
struct LanguageBindingSpec {
|
|
TUPLE_CLASS_BOILERPLATE(LanguageBindingSpec);
|
|
std::tuple<std::optional<ScalarDefaultCharConstantExpr>, bool> t;
|
|
};
|
|
|
|
// R852 named-constant-def -> named-constant = constant-expr
|
|
struct NamedConstantDef {
|
|
TUPLE_CLASS_BOILERPLATE(NamedConstantDef);
|
|
std::tuple<NamedConstant, ConstantExpr> t;
|
|
};
|
|
|
|
// R851 parameter-stmt -> PARAMETER ( named-constant-def-list )
|
|
WRAPPER_CLASS(ParameterStmt, std::list<NamedConstantDef>);
|
|
|
|
// R819 assumed-shape-spec -> [lower-bound] :
|
|
WRAPPER_CLASS(AssumedShapeSpec, std::optional<SpecificationExpr>);
|
|
|
|
// R821 assumed-implied-spec -> [lower-bound :] *
|
|
WRAPPER_CLASS(AssumedImpliedSpec, std::optional<SpecificationExpr>);
|
|
|
|
// R822 assumed-size-spec -> explicit-shape-spec-list , assumed-implied-spec
|
|
struct AssumedSizeSpec {
|
|
TUPLE_CLASS_BOILERPLATE(AssumedSizeSpec);
|
|
std::tuple<std::list<ExplicitShapeSpec>, AssumedImpliedSpec> t;
|
|
};
|
|
|
|
// 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.
|
|
WRAPPER_CLASS(ImpliedShapeSpec, std::list<AssumedImpliedSpec>);
|
|
|
|
// R825 assumed-rank-spec -> ..
|
|
EMPTY_CLASS(AssumedRankSpec);
|
|
|
|
// 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
|
|
struct ArraySpec {
|
|
UNION_CLASS_BOILERPLATE(ArraySpec);
|
|
std::variant<std::list<ExplicitShapeSpec>, std::list<AssumedShapeSpec>,
|
|
DeferredShapeSpecList, AssumedSizeSpec, ImpliedShapeSpec, AssumedRankSpec>
|
|
u;
|
|
};
|
|
|
|
// R826 intent-spec -> IN | OUT | INOUT
|
|
struct IntentSpec {
|
|
ENUM_CLASS(Intent, In, Out, InOut)
|
|
WRAPPER_CLASS_BOILERPLATE(IntentSpec, Intent);
|
|
};
|
|
|
|
// 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 |
|
|
// (CUDA) CONSTANT | DEVICE | MANAGED | PINNED | SHARED | TEXTURE
|
|
EMPTY_CLASS(Asynchronous);
|
|
EMPTY_CLASS(External);
|
|
EMPTY_CLASS(Intrinsic);
|
|
EMPTY_CLASS(Optional);
|
|
EMPTY_CLASS(Parameter);
|
|
EMPTY_CLASS(Protected);
|
|
EMPTY_CLASS(Save);
|
|
EMPTY_CLASS(Target);
|
|
EMPTY_CLASS(Value);
|
|
EMPTY_CLASS(Volatile);
|
|
struct AttrSpec {
|
|
UNION_CLASS_BOILERPLATE(AttrSpec);
|
|
std::variant<AccessSpec, Allocatable, Asynchronous, CoarraySpec, Contiguous,
|
|
ArraySpec, External, IntentSpec, Intrinsic, LanguageBindingSpec, Optional,
|
|
Parameter, Pointer, Protected, Save, Target, Value, Volatile,
|
|
common::CUDADataAttr>
|
|
u;
|
|
};
|
|
|
|
// R803 entity-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
// [* char-length] [initialization] |
|
|
// function-name [* char-length] |
|
|
// (ext.) object-name *char-length [( array-spec )]
|
|
// [lbracket coarray-spec rbracket] [initialization]
|
|
struct EntityDecl {
|
|
TUPLE_CLASS_BOILERPLATE(EntityDecl);
|
|
EntityDecl(ObjectName &&name, CharLength &&length,
|
|
std::optional<ArraySpec> &&aSpec, std::optional<CoarraySpec> &&coaSpec,
|
|
std::optional<Initialization> &&init)
|
|
: t{std::move(name), std::move(aSpec), std::move(coaSpec),
|
|
std::move(length), std::move(init)} {}
|
|
std::tuple<ObjectName, std::optional<ArraySpec>, std::optional<CoarraySpec>,
|
|
std::optional<CharLength>, std::optional<Initialization>>
|
|
t;
|
|
};
|
|
|
|
// R801 type-declaration-stmt ->
|
|
// declaration-type-spec [[, attr-spec]... ::] entity-decl-list
|
|
struct TypeDeclarationStmt {
|
|
TUPLE_CLASS_BOILERPLATE(TypeDeclarationStmt);
|
|
std::tuple<DeclarationTypeSpec, std::list<AttrSpec>, std::list<EntityDecl>> t;
|
|
};
|
|
|
|
// R828 access-id -> access-name | generic-spec
|
|
// "access-name" is ambiguous with "generic-spec", so that's what's parsed
|
|
WRAPPER_CLASS(AccessId, common::Indirection<GenericSpec>);
|
|
|
|
// R827 access-stmt -> access-spec [[::] access-id-list]
|
|
struct AccessStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AccessStmt);
|
|
std::tuple<AccessSpec, std::list<AccessId>> t;
|
|
};
|
|
|
|
// R830 allocatable-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
// R860 target-decl ->
|
|
// object-name [( array-spec )] [lbracket coarray-spec rbracket]
|
|
struct ObjectDecl {
|
|
TUPLE_CLASS_BOILERPLATE(ObjectDecl);
|
|
std::tuple<ObjectName, std::optional<ArraySpec>, std::optional<CoarraySpec>>
|
|
t;
|
|
};
|
|
|
|
// R829 allocatable-stmt -> ALLOCATABLE [::] allocatable-decl-list
|
|
WRAPPER_CLASS(AllocatableStmt, std::list<ObjectDecl>);
|
|
|
|
// R831 asynchronous-stmt -> ASYNCHRONOUS [::] object-name-list
|
|
WRAPPER_CLASS(AsynchronousStmt, std::list<ObjectName>);
|
|
|
|
// R833 bind-entity -> entity-name | / common-block-name /
|
|
struct BindEntity {
|
|
TUPLE_CLASS_BOILERPLATE(BindEntity);
|
|
ENUM_CLASS(Kind, Object, Common)
|
|
std::tuple<Kind, Name> t;
|
|
};
|
|
|
|
// R832 bind-stmt -> language-binding-spec [::] bind-entity-list
|
|
struct BindStmt {
|
|
TUPLE_CLASS_BOILERPLATE(BindStmt);
|
|
std::tuple<LanguageBindingSpec, std::list<BindEntity>> t;
|
|
};
|
|
|
|
// R835 codimension-decl -> coarray-name lbracket coarray-spec rbracket
|
|
struct CodimensionDecl {
|
|
TUPLE_CLASS_BOILERPLATE(CodimensionDecl);
|
|
std::tuple<Name, CoarraySpec> t;
|
|
};
|
|
|
|
// R834 codimension-stmt -> CODIMENSION [::] codimension-decl-list
|
|
WRAPPER_CLASS(CodimensionStmt, std::list<CodimensionDecl>);
|
|
|
|
// R836 contiguous-stmt -> CONTIGUOUS [::] object-name-list
|
|
WRAPPER_CLASS(ContiguousStmt, std::list<ObjectName>);
|
|
|
|
// R847 constant-subobject -> designator
|
|
// R846 int-constant-subobject -> constant-subobject
|
|
using ConstantSubobject = Constant<common::Indirection<Designator>>;
|
|
|
|
// Represents an analyzed expression
|
|
using TypedExpr = common::ForwardOwningPointer<evaluate::GenericExprWrapper>;
|
|
|
|
// R845 data-stmt-constant ->
|
|
// scalar-constant | scalar-constant-subobject |
|
|
// signed-int-literal-constant | signed-real-literal-constant |
|
|
// null-init | initial-data-target |
|
|
// structure-constructor
|
|
// N.B. Parsing ambiguities abound here without recourse to symbols
|
|
// (see comments on R845's parser).
|
|
struct DataStmtConstant {
|
|
UNION_CLASS_BOILERPLATE(DataStmtConstant);
|
|
CharBlock source;
|
|
mutable TypedExpr typedExpr;
|
|
std::variant<common::Indirection<CharLiteralConstantSubstring>,
|
|
LiteralConstant, SignedIntLiteralConstant, SignedRealLiteralConstant,
|
|
SignedComplexLiteralConstant, NullInit, common::Indirection<Designator>,
|
|
StructureConstructor, UnsignedLiteralConstant>
|
|
u;
|
|
};
|
|
|
|
// R844 data-stmt-repeat -> scalar-int-constant | scalar-int-constant-subobject
|
|
// R607 int-constant -> constant
|
|
// R604 constant -> literal-constant | named-constant
|
|
// (only literal-constant -> int-literal-constant applies)
|
|
struct DataStmtRepeat {
|
|
UNION_CLASS_BOILERPLATE(DataStmtRepeat);
|
|
std::variant<IntLiteralConstant, Scalar<Integer<ConstantSubobject>>> u;
|
|
};
|
|
|
|
// R843 data-stmt-value -> [data-stmt-repeat *] data-stmt-constant
|
|
struct DataStmtValue {
|
|
TUPLE_CLASS_BOILERPLATE(DataStmtValue);
|
|
mutable std::int64_t repetitions{1}; // replaced during semantics
|
|
std::tuple<std::optional<DataStmtRepeat>, DataStmtConstant> t;
|
|
};
|
|
|
|
// R841 data-i-do-object ->
|
|
// array-element | scalar-structure-component | data-implied-do
|
|
struct DataIDoObject {
|
|
UNION_CLASS_BOILERPLATE(DataIDoObject);
|
|
std::variant<Scalar<common::Indirection<Designator>>,
|
|
common::Indirection<DataImpliedDo>>
|
|
u;
|
|
};
|
|
|
|
// 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
|
|
struct DataImpliedDo {
|
|
TUPLE_CLASS_BOILERPLATE(DataImpliedDo);
|
|
using Bounds = LoopBounds<DoVariable, ScalarIntConstantExpr>;
|
|
std::tuple<std::list<DataIDoObject>, std::optional<IntegerTypeSpec>, Bounds>
|
|
t;
|
|
};
|
|
|
|
// R839 data-stmt-object -> variable | data-implied-do
|
|
struct DataStmtObject {
|
|
UNION_CLASS_BOILERPLATE(DataStmtObject);
|
|
std::variant<common::Indirection<Variable>, DataImpliedDo> u;
|
|
};
|
|
|
|
// R838 data-stmt-set -> data-stmt-object-list / data-stmt-value-list /
|
|
struct DataStmtSet {
|
|
TUPLE_CLASS_BOILERPLATE(DataStmtSet);
|
|
std::tuple<std::list<DataStmtObject>, std::list<DataStmtValue>> t;
|
|
};
|
|
|
|
// R837 data-stmt -> DATA data-stmt-set [[,] data-stmt-set]...
|
|
WRAPPER_CLASS(DataStmt, std::list<DataStmtSet>);
|
|
|
|
// R848 dimension-stmt ->
|
|
// DIMENSION [::] array-name ( array-spec )
|
|
// [, array-name ( array-spec )]...
|
|
struct DimensionStmt {
|
|
struct Declaration {
|
|
TUPLE_CLASS_BOILERPLATE(Declaration);
|
|
std::tuple<Name, ArraySpec> t;
|
|
};
|
|
WRAPPER_CLASS_BOILERPLATE(DimensionStmt, std::list<Declaration>);
|
|
};
|
|
|
|
// R849 intent-stmt -> INTENT ( intent-spec ) [::] dummy-arg-name-list
|
|
struct IntentStmt {
|
|
TUPLE_CLASS_BOILERPLATE(IntentStmt);
|
|
std::tuple<IntentSpec, std::list<Name>> t;
|
|
};
|
|
|
|
// R850 optional-stmt -> OPTIONAL [::] dummy-arg-name-list
|
|
WRAPPER_CLASS(OptionalStmt, std::list<Name>);
|
|
|
|
// R854 pointer-decl ->
|
|
// object-name [( deferred-shape-spec-list )] | proc-entity-name
|
|
struct PointerDecl {
|
|
TUPLE_CLASS_BOILERPLATE(PointerDecl);
|
|
std::tuple<Name, std::optional<DeferredShapeSpecList>> t;
|
|
};
|
|
|
|
// R853 pointer-stmt -> POINTER [::] pointer-decl-list
|
|
WRAPPER_CLASS(PointerStmt, std::list<PointerDecl>);
|
|
|
|
// R855 protected-stmt -> PROTECTED [::] entity-name-list
|
|
WRAPPER_CLASS(ProtectedStmt, std::list<Name>);
|
|
|
|
// R857 saved-entity -> object-name | proc-pointer-name | / common-block-name /
|
|
// R858 proc-pointer-name -> name
|
|
struct SavedEntity {
|
|
TUPLE_CLASS_BOILERPLATE(SavedEntity);
|
|
ENUM_CLASS(Kind, Entity, Common)
|
|
std::tuple<Kind, Name> t;
|
|
};
|
|
|
|
// R856 save-stmt -> SAVE [[::] saved-entity-list]
|
|
WRAPPER_CLASS(SaveStmt, std::list<SavedEntity>);
|
|
|
|
// R859 target-stmt -> TARGET [::] target-decl-list
|
|
WRAPPER_CLASS(TargetStmt, std::list<ObjectDecl>);
|
|
|
|
// R861 value-stmt -> VALUE [::] dummy-arg-name-list
|
|
WRAPPER_CLASS(ValueStmt, std::list<Name>);
|
|
|
|
// R862 volatile-stmt -> VOLATILE [::] object-name-list
|
|
WRAPPER_CLASS(VolatileStmt, std::list<ObjectName>);
|
|
|
|
// R865 letter-spec -> letter [- letter]
|
|
struct LetterSpec {
|
|
TUPLE_CLASS_BOILERPLATE(LetterSpec);
|
|
std::tuple<Location, std::optional<Location>> t;
|
|
};
|
|
|
|
// R864 implicit-spec -> declaration-type-spec ( letter-spec-list )
|
|
struct ImplicitSpec {
|
|
TUPLE_CLASS_BOILERPLATE(ImplicitSpec);
|
|
std::tuple<DeclarationTypeSpec, std::list<LetterSpec>> t;
|
|
};
|
|
|
|
// R863 implicit-stmt ->
|
|
// IMPLICIT implicit-spec-list |
|
|
// IMPLICIT NONE [( [implicit-name-spec-list] )]
|
|
// R866 implicit-name-spec -> EXTERNAL | TYPE
|
|
struct ImplicitStmt {
|
|
UNION_CLASS_BOILERPLATE(ImplicitStmt);
|
|
ENUM_CLASS(ImplicitNoneNameSpec, External, Type) // R866
|
|
std::variant<std::list<ImplicitSpec>, std::list<ImplicitNoneNameSpec>> u;
|
|
};
|
|
|
|
// R874 common-block-object -> variable-name [( array-spec )]
|
|
struct CommonBlockObject {
|
|
TUPLE_CLASS_BOILERPLATE(CommonBlockObject);
|
|
std::tuple<Name, std::optional<ArraySpec>> t;
|
|
};
|
|
|
|
// R873 common-stmt ->
|
|
// COMMON [/ [common-block-name] /] common-block-object-list
|
|
// [[,] / [common-block-name] / common-block-object-list]...
|
|
struct CommonStmt {
|
|
struct Block {
|
|
TUPLE_CLASS_BOILERPLATE(Block);
|
|
std::tuple<std::optional<Name>, std::list<CommonBlockObject>> t;
|
|
};
|
|
BOILERPLATE(CommonStmt);
|
|
CommonStmt(std::optional<Name> &&, std::list<CommonBlockObject> &&,
|
|
std::list<Block> &&);
|
|
std::list<Block> blocks;
|
|
};
|
|
|
|
// R872 equivalence-object -> variable-name | array-element | substring
|
|
WRAPPER_CLASS(EquivalenceObject, common::Indirection<Designator>);
|
|
|
|
// R870 equivalence-stmt -> EQUIVALENCE equivalence-set-list
|
|
// R871 equivalence-set -> ( equivalence-object , equivalence-object-list )
|
|
WRAPPER_CLASS(EquivalenceStmt, std::list<std::list<EquivalenceObject>>);
|
|
|
|
// R910 substring-range -> [scalar-int-expr] : [scalar-int-expr]
|
|
struct SubstringRange {
|
|
TUPLE_CLASS_BOILERPLATE(SubstringRange);
|
|
std::tuple<std::optional<ScalarIntExpr>, std::optional<ScalarIntExpr>> t;
|
|
};
|
|
|
|
// R919 subscript -> scalar-int-expr
|
|
using Subscript = ScalarIntExpr;
|
|
|
|
// R921 subscript-triplet -> [subscript] : [subscript] [: stride]
|
|
struct SubscriptTriplet {
|
|
TUPLE_CLASS_BOILERPLATE(SubscriptTriplet);
|
|
std::tuple<std::optional<Subscript>, std::optional<Subscript>,
|
|
std::optional<Subscript>>
|
|
t;
|
|
};
|
|
|
|
// R920 section-subscript -> subscript | subscript-triplet | vector-subscript
|
|
// R923 vector-subscript -> int-expr
|
|
struct SectionSubscript {
|
|
UNION_CLASS_BOILERPLATE(SectionSubscript);
|
|
std::variant<IntExpr, SubscriptTriplet> u;
|
|
};
|
|
|
|
// R925 cosubscript -> scalar-int-expr
|
|
using Cosubscript = ScalarIntExpr;
|
|
|
|
// R1115 team-value -> scalar-expr
|
|
WRAPPER_CLASS(TeamValue, Scalar<common::Indirection<Expr>>);
|
|
|
|
// R926 image-selector-spec ->
|
|
// STAT = stat-variable | TEAM = team-value |
|
|
// TEAM_NUMBER = scalar-int-expr
|
|
struct ImageSelectorSpec {
|
|
WRAPPER_CLASS(Stat, Scalar<Integer<common::Indirection<Variable>>>);
|
|
WRAPPER_CLASS(Team_Number, ScalarIntExpr);
|
|
UNION_CLASS_BOILERPLATE(ImageSelectorSpec);
|
|
std::variant<Stat, TeamValue, Team_Number> u;
|
|
};
|
|
|
|
// R924 image-selector ->
|
|
// lbracket cosubscript-list [, image-selector-spec-list] rbracket
|
|
struct ImageSelector {
|
|
TUPLE_CLASS_BOILERPLATE(ImageSelector);
|
|
std::tuple<std::list<Cosubscript>, std::list<ImageSelectorSpec>> t;
|
|
};
|
|
|
|
// R1001 - R1022 expressions
|
|
struct Expr {
|
|
UNION_CLASS_BOILERPLATE(Expr);
|
|
|
|
WRAPPER_CLASS(IntrinsicUnary, common::Indirection<Expr>);
|
|
struct Parentheses : public IntrinsicUnary {
|
|
using IntrinsicUnary::IntrinsicUnary;
|
|
};
|
|
struct UnaryPlus : public IntrinsicUnary {
|
|
using IntrinsicUnary::IntrinsicUnary;
|
|
};
|
|
struct Negate : public IntrinsicUnary {
|
|
using IntrinsicUnary::IntrinsicUnary;
|
|
};
|
|
struct NOT : public IntrinsicUnary {
|
|
using IntrinsicUnary::IntrinsicUnary;
|
|
};
|
|
|
|
WRAPPER_CLASS(PercentLoc, common::Indirection<Variable>); // %LOC(v) extension
|
|
|
|
struct DefinedUnary {
|
|
TUPLE_CLASS_BOILERPLATE(DefinedUnary);
|
|
std::tuple<DefinedOpName, common::Indirection<Expr>> t;
|
|
};
|
|
|
|
struct IntrinsicBinary {
|
|
TUPLE_CLASS_BOILERPLATE(IntrinsicBinary);
|
|
std::tuple<common::Indirection<Expr>, common::Indirection<Expr>> t;
|
|
};
|
|
struct Power : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct Multiply : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct Divide : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct Add : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct Subtract : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct Concat : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct LT : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct LE : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct EQ : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct NE : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct GE : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct GT : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct AND : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct OR : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct EQV : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
struct NEQV : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
|
|
// PGI/XLF extension: (x,y), not both constant
|
|
struct ComplexConstructor : public IntrinsicBinary {
|
|
using IntrinsicBinary::IntrinsicBinary;
|
|
};
|
|
|
|
struct DefinedBinary {
|
|
TUPLE_CLASS_BOILERPLATE(DefinedBinary);
|
|
std::tuple<DefinedOpName, common::Indirection<Expr>,
|
|
common::Indirection<Expr>>
|
|
t;
|
|
};
|
|
|
|
explicit Expr(Designator &&);
|
|
explicit Expr(FunctionReference &&);
|
|
|
|
mutable TypedExpr typedExpr;
|
|
|
|
CharBlock source;
|
|
|
|
std::variant<common::Indirection<CharLiteralConstantSubstring>,
|
|
LiteralConstant, common::Indirection<Designator>, ArrayConstructor,
|
|
StructureConstructor, common::Indirection<FunctionReference>, Parentheses,
|
|
UnaryPlus, Negate, NOT, PercentLoc, DefinedUnary, Power, Multiply, Divide,
|
|
Add, Subtract, Concat, LT, LE, EQ, NE, GE, GT, AND, OR, EQV, NEQV,
|
|
DefinedBinary, ComplexConstructor, common::Indirection<SubstringInquiry>>
|
|
u;
|
|
};
|
|
|
|
// R912 part-ref -> part-name [( section-subscript-list )] [image-selector]
|
|
struct PartRef {
|
|
BOILERPLATE(PartRef);
|
|
PartRef(Name &&n, std::list<SectionSubscript> &&ss,
|
|
std::optional<ImageSelector> &&is)
|
|
: name{std::move(n)}, subscripts(std::move(ss)),
|
|
imageSelector{std::move(is)} {}
|
|
Name name;
|
|
std::list<SectionSubscript> subscripts;
|
|
std::optional<ImageSelector> imageSelector;
|
|
};
|
|
|
|
// R911 data-ref -> part-ref [% part-ref]...
|
|
struct DataRef {
|
|
UNION_CLASS_BOILERPLATE(DataRef);
|
|
explicit DataRef(std::list<PartRef> &&);
|
|
std::variant<Name, common::Indirection<StructureComponent>,
|
|
common::Indirection<ArrayElement>,
|
|
common::Indirection<CoindexedNamedObject>>
|
|
u;
|
|
};
|
|
|
|
// 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
|
|
// Substrings of character literals have been factored out into their
|
|
// own productions so that they can't appear as designators in any context
|
|
// other than a primary expression.
|
|
struct Substring {
|
|
TUPLE_CLASS_BOILERPLATE(Substring);
|
|
std::tuple<DataRef, SubstringRange> t;
|
|
};
|
|
|
|
struct CharLiteralConstantSubstring {
|
|
TUPLE_CLASS_BOILERPLATE(CharLiteralConstantSubstring);
|
|
std::tuple<CharLiteralConstant, SubstringRange> t;
|
|
};
|
|
|
|
// substring%KIND/LEN type parameter inquiry for cases that could not be
|
|
// parsed as part-refs and fixed up afterwards. N.B. we only have to
|
|
// handle inquiries into designator-based substrings, not those based on
|
|
// char-literal-constants.
|
|
struct SubstringInquiry {
|
|
CharBlock source;
|
|
WRAPPER_CLASS_BOILERPLATE(SubstringInquiry, Substring);
|
|
};
|
|
|
|
// R901 designator -> object-name | array-element | array-section |
|
|
// coindexed-named-object | complex-part-designator |
|
|
// structure-component | substring
|
|
struct Designator {
|
|
UNION_CLASS_BOILERPLATE(Designator);
|
|
bool EndsInBareName() const;
|
|
CharBlock source;
|
|
std::variant<DataRef, Substring> u;
|
|
};
|
|
|
|
// R902 variable -> designator | function-reference
|
|
struct Variable {
|
|
UNION_CLASS_BOILERPLATE(Variable);
|
|
mutable TypedExpr typedExpr;
|
|
CharBlock GetSource() const;
|
|
std::variant<common::Indirection<Designator>,
|
|
common::Indirection<FunctionReference>>
|
|
u;
|
|
};
|
|
|
|
// R904 logical-variable -> variable
|
|
// Appears only as part of scalar-logical-variable.
|
|
using ScalarLogicalVariable = Scalar<Logical<Variable>>;
|
|
|
|
// R906 default-char-variable -> variable
|
|
// Appears only as part of scalar-default-char-variable.
|
|
using ScalarDefaultCharVariable = Scalar<DefaultChar<Variable>>;
|
|
|
|
// R907 int-variable -> variable
|
|
// Appears only as part of scalar-int-variable.
|
|
using ScalarIntVariable = Scalar<Integer<Variable>>;
|
|
|
|
// R913 structure-component -> data-ref
|
|
struct StructureComponent {
|
|
BOILERPLATE(StructureComponent);
|
|
StructureComponent(DataRef &&dr, Name &&n)
|
|
: base{std::move(dr)}, component(std::move(n)) {}
|
|
DataRef base;
|
|
Name component;
|
|
};
|
|
|
|
// R1039 proc-component-ref -> scalar-variable % procedure-component-name
|
|
// C1027 constrains the scalar-variable to be a data-ref without coindices.
|
|
struct ProcComponentRef {
|
|
WRAPPER_CLASS_BOILERPLATE(ProcComponentRef, Scalar<StructureComponent>);
|
|
};
|
|
|
|
// R914 coindexed-named-object -> data-ref
|
|
struct CoindexedNamedObject {
|
|
BOILERPLATE(CoindexedNamedObject);
|
|
CoindexedNamedObject(DataRef &&dr, ImageSelector &&is)
|
|
: base{std::move(dr)}, imageSelector{std::move(is)} {}
|
|
DataRef base;
|
|
ImageSelector imageSelector;
|
|
};
|
|
|
|
// R917 array-element -> data-ref
|
|
struct ArrayElement {
|
|
BOILERPLATE(ArrayElement);
|
|
ArrayElement(DataRef &&dr, std::list<SectionSubscript> &&ss)
|
|
: base{std::move(dr)}, subscripts(std::move(ss)) {}
|
|
Substring ConvertToSubstring();
|
|
StructureConstructor ConvertToStructureConstructor(
|
|
const semantics::DerivedTypeSpec &);
|
|
DataRef base;
|
|
std::list<SectionSubscript> subscripts;
|
|
};
|
|
|
|
// R933 allocate-object -> variable-name | structure-component
|
|
struct AllocateObject {
|
|
UNION_CLASS_BOILERPLATE(AllocateObject);
|
|
mutable TypedExpr typedExpr;
|
|
std::variant<Name, StructureComponent> u;
|
|
};
|
|
|
|
// R935 lower-bound-expr -> scalar-int-expr
|
|
// R936 upper-bound-expr -> scalar-int-expr
|
|
using BoundExpr = ScalarIntExpr;
|
|
|
|
// R934 allocate-shape-spec -> [lower-bound-expr :] upper-bound-expr
|
|
// R938 allocate-coshape-spec -> [lower-bound-expr :] upper-bound-expr
|
|
struct AllocateShapeSpec {
|
|
TUPLE_CLASS_BOILERPLATE(AllocateShapeSpec);
|
|
std::tuple<std::optional<BoundExpr>, BoundExpr> t;
|
|
};
|
|
|
|
using AllocateCoshapeSpec = AllocateShapeSpec;
|
|
|
|
// R937 allocate-coarray-spec ->
|
|
// [allocate-coshape-spec-list ,] [lower-bound-expr :] *
|
|
struct AllocateCoarraySpec {
|
|
TUPLE_CLASS_BOILERPLATE(AllocateCoarraySpec);
|
|
std::tuple<std::list<AllocateCoshapeSpec>, std::optional<BoundExpr>> t;
|
|
};
|
|
|
|
// R932 allocation ->
|
|
// allocate-object [( allocate-shape-spec-list )]
|
|
// [lbracket allocate-coarray-spec rbracket]
|
|
struct Allocation {
|
|
TUPLE_CLASS_BOILERPLATE(Allocation);
|
|
std::tuple<AllocateObject, std::list<AllocateShapeSpec>,
|
|
std::optional<AllocateCoarraySpec>>
|
|
t;
|
|
};
|
|
|
|
// R929 stat-variable -> scalar-int-variable
|
|
WRAPPER_CLASS(StatVariable, ScalarIntVariable);
|
|
|
|
// R930 errmsg-variable -> scalar-default-char-variable
|
|
// R1207 iomsg-variable -> scalar-default-char-variable
|
|
WRAPPER_CLASS(MsgVariable, ScalarDefaultCharVariable);
|
|
|
|
// R942 dealloc-opt -> STAT = stat-variable | ERRMSG = errmsg-variable
|
|
// R1165 sync-stat -> STAT = stat-variable | ERRMSG = errmsg-variable
|
|
struct StatOrErrmsg {
|
|
UNION_CLASS_BOILERPLATE(StatOrErrmsg);
|
|
std::variant<StatVariable, MsgVariable> u;
|
|
};
|
|
|
|
// R928 alloc-opt ->
|
|
// ERRMSG = errmsg-variable | MOLD = source-expr |
|
|
// SOURCE = source-expr | STAT = stat-variable |
|
|
// (CUDA) STREAM = scalar-int-expr
|
|
// PINNED = scalar-logical-variable
|
|
// R931 source-expr -> expr
|
|
struct AllocOpt {
|
|
UNION_CLASS_BOILERPLATE(AllocOpt);
|
|
WRAPPER_CLASS(Mold, common::Indirection<Expr>);
|
|
WRAPPER_CLASS(Source, common::Indirection<Expr>);
|
|
WRAPPER_CLASS(Stream, common::Indirection<ScalarIntExpr>);
|
|
WRAPPER_CLASS(Pinned, common::Indirection<ScalarLogicalVariable>);
|
|
std::variant<Mold, Source, StatOrErrmsg, Stream, Pinned> u;
|
|
};
|
|
|
|
// R927 allocate-stmt ->
|
|
// ALLOCATE ( [type-spec ::] allocation-list [, alloc-opt-list] )
|
|
struct AllocateStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AllocateStmt);
|
|
std::tuple<std::optional<TypeSpec>, std::list<Allocation>,
|
|
std::list<AllocOpt>>
|
|
t;
|
|
};
|
|
|
|
// R940 pointer-object ->
|
|
// variable-name | structure-component | proc-pointer-name
|
|
struct PointerObject {
|
|
UNION_CLASS_BOILERPLATE(PointerObject);
|
|
mutable TypedExpr typedExpr;
|
|
std::variant<Name, StructureComponent> u;
|
|
};
|
|
|
|
// R939 nullify-stmt -> NULLIFY ( pointer-object-list )
|
|
WRAPPER_CLASS(NullifyStmt, std::list<PointerObject>);
|
|
|
|
// R941 deallocate-stmt ->
|
|
// DEALLOCATE ( allocate-object-list [, dealloc-opt-list] )
|
|
struct DeallocateStmt {
|
|
TUPLE_CLASS_BOILERPLATE(DeallocateStmt);
|
|
std::tuple<std::list<AllocateObject>, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1032 assignment-stmt -> variable = expr
|
|
struct AssignmentStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AssignmentStmt);
|
|
using TypedAssignment =
|
|
common::ForwardOwningPointer<evaluate::GenericAssignmentWrapper>;
|
|
mutable TypedAssignment typedAssignment;
|
|
std::tuple<Variable, Expr> t;
|
|
};
|
|
|
|
// R1035 bounds-spec -> lower-bound-expr :
|
|
WRAPPER_CLASS(BoundsSpec, BoundExpr);
|
|
|
|
// R1036 bounds-remapping -> lower-bound-expr : upper-bound-expr
|
|
struct BoundsRemapping {
|
|
TUPLE_CLASS_BOILERPLATE(BoundsRemapping);
|
|
std::tuple<BoundExpr, BoundExpr> t;
|
|
};
|
|
|
|
// 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
|
|
// R1038 proc-pointer-object -> proc-pointer-name | proc-component-ref
|
|
struct PointerAssignmentStmt {
|
|
struct Bounds {
|
|
UNION_CLASS_BOILERPLATE(Bounds);
|
|
std::variant<std::list<BoundsRemapping>, std::list<BoundsSpec>> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(PointerAssignmentStmt);
|
|
mutable AssignmentStmt::TypedAssignment typedAssignment;
|
|
std::tuple<DataRef, Bounds, Expr> t;
|
|
};
|
|
|
|
// R1041 where-stmt -> WHERE ( mask-expr ) where-assignment-stmt
|
|
// R1045 where-assignment-stmt -> assignment-stmt
|
|
// R1046 mask-expr -> logical-expr
|
|
struct WhereStmt {
|
|
TUPLE_CLASS_BOILERPLATE(WhereStmt);
|
|
std::tuple<LogicalExpr, AssignmentStmt> t;
|
|
};
|
|
|
|
// R1043 where-construct-stmt -> [where-construct-name :] WHERE ( mask-expr )
|
|
struct WhereConstructStmt {
|
|
TUPLE_CLASS_BOILERPLATE(WhereConstructStmt);
|
|
std::tuple<std::optional<Name>, LogicalExpr> t;
|
|
};
|
|
|
|
// R1044 where-body-construct ->
|
|
// where-assignment-stmt | where-stmt | where-construct
|
|
struct WhereBodyConstruct {
|
|
UNION_CLASS_BOILERPLATE(WhereBodyConstruct);
|
|
std::variant<Statement<AssignmentStmt>, Statement<WhereStmt>,
|
|
common::Indirection<WhereConstruct>>
|
|
u;
|
|
};
|
|
|
|
// R1047 masked-elsewhere-stmt ->
|
|
// ELSEWHERE ( mask-expr ) [where-construct-name]
|
|
struct MaskedElsewhereStmt {
|
|
TUPLE_CLASS_BOILERPLATE(MaskedElsewhereStmt);
|
|
std::tuple<LogicalExpr, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1048 elsewhere-stmt -> ELSEWHERE [where-construct-name]
|
|
WRAPPER_CLASS(ElsewhereStmt, std::optional<Name>);
|
|
|
|
// R1049 end-where-stmt -> END WHERE [where-construct-name]
|
|
WRAPPER_CLASS(EndWhereStmt, std::optional<Name>);
|
|
|
|
// R1042 where-construct ->
|
|
// where-construct-stmt [where-body-construct]...
|
|
// [masked-elsewhere-stmt [where-body-construct]...]...
|
|
// [elsewhere-stmt [where-body-construct]...] end-where-stmt
|
|
struct WhereConstruct {
|
|
struct MaskedElsewhere {
|
|
TUPLE_CLASS_BOILERPLATE(MaskedElsewhere);
|
|
std::tuple<Statement<MaskedElsewhereStmt>, std::list<WhereBodyConstruct>> t;
|
|
};
|
|
struct Elsewhere {
|
|
TUPLE_CLASS_BOILERPLATE(Elsewhere);
|
|
std::tuple<Statement<ElsewhereStmt>, std::list<WhereBodyConstruct>> t;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(WhereConstruct);
|
|
std::tuple<Statement<WhereConstructStmt>, std::list<WhereBodyConstruct>,
|
|
std::list<MaskedElsewhere>, std::optional<Elsewhere>,
|
|
Statement<EndWhereStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1051 forall-construct-stmt ->
|
|
// [forall-construct-name :] FORALL concurrent-header
|
|
struct ForallConstructStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ForallConstructStmt);
|
|
std::tuple<std::optional<Name>, common::Indirection<ConcurrentHeader>> t;
|
|
};
|
|
|
|
// R1053 forall-assignment-stmt -> assignment-stmt | pointer-assignment-stmt
|
|
struct ForallAssignmentStmt {
|
|
UNION_CLASS_BOILERPLATE(ForallAssignmentStmt);
|
|
std::variant<AssignmentStmt, PointerAssignmentStmt> u;
|
|
};
|
|
|
|
// R1055 forall-stmt -> FORALL concurrent-header forall-assignment-stmt
|
|
struct ForallStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ForallStmt);
|
|
std::tuple<common::Indirection<ConcurrentHeader>,
|
|
UnlabeledStatement<ForallAssignmentStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1052 forall-body-construct ->
|
|
// forall-assignment-stmt | where-stmt | where-construct |
|
|
// forall-construct | forall-stmt
|
|
struct ForallBodyConstruct {
|
|
UNION_CLASS_BOILERPLATE(ForallBodyConstruct);
|
|
std::variant<Statement<ForallAssignmentStmt>, Statement<WhereStmt>,
|
|
WhereConstruct, common::Indirection<ForallConstruct>,
|
|
Statement<ForallStmt>>
|
|
u;
|
|
};
|
|
|
|
// R1054 end-forall-stmt -> END FORALL [forall-construct-name]
|
|
WRAPPER_CLASS(EndForallStmt, std::optional<Name>);
|
|
|
|
// R1050 forall-construct ->
|
|
// forall-construct-stmt [forall-body-construct]... end-forall-stmt
|
|
struct ForallConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(ForallConstruct);
|
|
std::tuple<Statement<ForallConstructStmt>, std::list<ForallBodyConstruct>,
|
|
Statement<EndForallStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1105 selector -> expr | variable
|
|
struct Selector {
|
|
UNION_CLASS_BOILERPLATE(Selector);
|
|
std::variant<Expr, Variable> u;
|
|
};
|
|
|
|
// R1104 association -> associate-name => selector
|
|
struct Association {
|
|
TUPLE_CLASS_BOILERPLATE(Association);
|
|
std::tuple<Name, Selector> t;
|
|
};
|
|
|
|
// R1103 associate-stmt ->
|
|
// [associate-construct-name :] ASSOCIATE ( association-list )
|
|
struct AssociateStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AssociateStmt);
|
|
std::tuple<std::optional<Name>, std::list<Association>> t;
|
|
};
|
|
|
|
// R1106 end-associate-stmt -> END ASSOCIATE [associate-construct-name]
|
|
WRAPPER_CLASS(EndAssociateStmt, std::optional<Name>);
|
|
|
|
// R1102 associate-construct -> associate-stmt block end-associate-stmt
|
|
struct AssociateConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(AssociateConstruct);
|
|
std::tuple<Statement<AssociateStmt>, Block, Statement<EndAssociateStmt>> t;
|
|
};
|
|
|
|
// R1108 block-stmt -> [block-construct-name :] BLOCK
|
|
WRAPPER_CLASS(BlockStmt, std::optional<Name>);
|
|
|
|
// R1110 end-block-stmt -> END BLOCK [block-construct-name]
|
|
WRAPPER_CLASS(EndBlockStmt, std::optional<Name>);
|
|
|
|
// R1109 block-specification-part ->
|
|
// [use-stmt]... [import-stmt]...
|
|
// [[declaration-construct]... specification-construct]
|
|
// N.B. Because BlockSpecificationPart just wraps the more general
|
|
// SpecificationPart, it can misrecognize an ImplicitPart as part of
|
|
// the BlockSpecificationPart during parsing, and we have to detect and
|
|
// flag such usage in semantics.
|
|
WRAPPER_CLASS(BlockSpecificationPart, SpecificationPart);
|
|
|
|
// R1107 block-construct ->
|
|
// block-stmt [block-specification-part] block end-block-stmt
|
|
struct BlockConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(BlockConstruct);
|
|
std::tuple<Statement<BlockStmt>, BlockSpecificationPart, Block,
|
|
Statement<EndBlockStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1113 coarray-association -> codimension-decl => selector
|
|
struct CoarrayAssociation {
|
|
TUPLE_CLASS_BOILERPLATE(CoarrayAssociation);
|
|
std::tuple<CodimensionDecl, Selector> t;
|
|
};
|
|
|
|
// R1112 change-team-stmt ->
|
|
// [team-construct-name :] CHANGE TEAM
|
|
// ( team-value [, coarray-association-list] [, sync-stat-list] )
|
|
struct ChangeTeamStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ChangeTeamStmt);
|
|
std::tuple<std::optional<Name>, TeamValue, std::list<CoarrayAssociation>,
|
|
std::list<StatOrErrmsg>>
|
|
t;
|
|
};
|
|
|
|
// R1114 end-change-team-stmt ->
|
|
// END TEAM [( [sync-stat-list] )] [team-construct-name]
|
|
struct EndChangeTeamStmt {
|
|
TUPLE_CLASS_BOILERPLATE(EndChangeTeamStmt);
|
|
std::tuple<std::list<StatOrErrmsg>, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1111 change-team-construct -> change-team-stmt block end-change-team-stmt
|
|
struct ChangeTeamConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(ChangeTeamConstruct);
|
|
std::tuple<Statement<ChangeTeamStmt>, Block, Statement<EndChangeTeamStmt>> t;
|
|
};
|
|
|
|
// R1117 critical-stmt ->
|
|
// [critical-construct-name :] CRITICAL [( [sync-stat-list] )]
|
|
struct CriticalStmt {
|
|
TUPLE_CLASS_BOILERPLATE(CriticalStmt);
|
|
std::tuple<std::optional<Name>, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1118 end-critical-stmt -> END CRITICAL [critical-construct-name]
|
|
WRAPPER_CLASS(EndCriticalStmt, std::optional<Name>);
|
|
|
|
// R1116 critical-construct -> critical-stmt block end-critical-stmt
|
|
struct CriticalConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(CriticalConstruct);
|
|
std::tuple<Statement<CriticalStmt>, Block, Statement<EndCriticalStmt>> t;
|
|
};
|
|
|
|
// R1126 concurrent-control ->
|
|
// index-name = concurrent-limit : concurrent-limit [: concurrent-step]
|
|
// R1127 concurrent-limit -> scalar-int-expr
|
|
// R1128 concurrent-step -> scalar-int-expr
|
|
struct ConcurrentControl {
|
|
TUPLE_CLASS_BOILERPLATE(ConcurrentControl);
|
|
std::tuple<Name, ScalarIntExpr, ScalarIntExpr, std::optional<ScalarIntExpr>>
|
|
t;
|
|
};
|
|
|
|
// R1125 concurrent-header ->
|
|
// ( [integer-type-spec ::] concurrent-control-list
|
|
// [, scalar-mask-expr] )
|
|
struct ConcurrentHeader {
|
|
TUPLE_CLASS_BOILERPLATE(ConcurrentHeader);
|
|
std::tuple<std::optional<IntegerTypeSpec>, std::list<ConcurrentControl>,
|
|
std::optional<ScalarLogicalExpr>>
|
|
t;
|
|
};
|
|
|
|
// F'2023 R1131 reduce-operation -> reduction-operator
|
|
// CUF reduction-op -> reduction-operator
|
|
// OpenACC 3.3 2.5.15 reduction-operator ->
|
|
// + | * | .AND. | .OR. | .EQV. | .NEQV. |
|
|
// MAX | MIN | IAND | IOR | IEOR
|
|
struct ReductionOperator {
|
|
ENUM_CLASS(
|
|
Operator, Plus, Multiply, Max, Min, Iand, Ior, Ieor, And, Or, Eqv, Neqv)
|
|
WRAPPER_CLASS_BOILERPLATE(ReductionOperator, Operator);
|
|
CharBlock source;
|
|
};
|
|
|
|
// R1130 locality-spec ->
|
|
// LOCAL ( variable-name-list ) | LOCAL_INIT ( variable-name-list ) |
|
|
// REDUCE ( reduce-operation : variable-name-list ) |
|
|
// SHARED ( variable-name-list ) | DEFAULT ( NONE )
|
|
struct LocalitySpec {
|
|
UNION_CLASS_BOILERPLATE(LocalitySpec);
|
|
WRAPPER_CLASS(Local, std::list<Name>);
|
|
WRAPPER_CLASS(LocalInit, std::list<Name>);
|
|
struct Reduce {
|
|
TUPLE_CLASS_BOILERPLATE(Reduce);
|
|
using Operator = ReductionOperator;
|
|
std::tuple<Operator, std::list<Name>> t;
|
|
};
|
|
WRAPPER_CLASS(Shared, std::list<Name>);
|
|
EMPTY_CLASS(DefaultNone);
|
|
std::variant<Local, LocalInit, Reduce, Shared, DefaultNone> u;
|
|
};
|
|
|
|
// 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]...
|
|
struct LoopControl {
|
|
UNION_CLASS_BOILERPLATE(LoopControl);
|
|
struct Concurrent {
|
|
TUPLE_CLASS_BOILERPLATE(Concurrent);
|
|
std::tuple<ConcurrentHeader, std::list<LocalitySpec>> t;
|
|
};
|
|
using Bounds = LoopBounds<ScalarName, ScalarExpr>;
|
|
std::variant<Bounds, ScalarLogicalExpr, Concurrent> u;
|
|
};
|
|
|
|
// R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
|
|
// A label-do-stmt with a do-construct-name is parsed as a non-label-do-stmt.
|
|
struct LabelDoStmt {
|
|
TUPLE_CLASS_BOILERPLATE(LabelDoStmt);
|
|
std::tuple<Label, std::optional<LoopControl>> t;
|
|
};
|
|
|
|
// R1122 nonlabel-do-stmt -> [do-construct-name :] DO [loop-control]
|
|
struct NonLabelDoStmt {
|
|
TUPLE_CLASS_BOILERPLATE(NonLabelDoStmt);
|
|
std::tuple<std::optional<Name>, std::optional<Label>,
|
|
std::optional<LoopControl>>
|
|
t;
|
|
};
|
|
|
|
// R1132 end-do-stmt -> END DO [do-construct-name]
|
|
WRAPPER_CLASS(EndDoStmt, std::optional<Name>);
|
|
|
|
// R1131 end-do -> end-do-stmt | continue-stmt
|
|
|
|
// R1119 do-construct -> do-stmt block end-do
|
|
// R1120 do-stmt -> nonlabel-do-stmt | label-do-stmt
|
|
// Deprecated, but supported: "label DO" loops ending on statements other
|
|
// than END DO and CONTINUE, and multiple "label DO" loops ending on the
|
|
// same label.
|
|
struct DoConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(DoConstruct);
|
|
const std::optional<LoopControl> &GetLoopControl() const;
|
|
bool IsDoNormal() const;
|
|
bool IsDoWhile() const;
|
|
bool IsDoConcurrent() const;
|
|
std::tuple<Statement<NonLabelDoStmt>, Block, Statement<EndDoStmt>> t;
|
|
};
|
|
|
|
// R1133 cycle-stmt -> CYCLE [do-construct-name]
|
|
WRAPPER_CLASS(CycleStmt, std::optional<Name>);
|
|
|
|
// R1135 if-then-stmt -> [if-construct-name :] IF ( scalar-logical-expr ) THEN
|
|
struct IfThenStmt {
|
|
TUPLE_CLASS_BOILERPLATE(IfThenStmt);
|
|
std::tuple<std::optional<Name>, ScalarLogicalExpr> t;
|
|
};
|
|
|
|
// R1136 else-if-stmt ->
|
|
// ELSE IF ( scalar-logical-expr ) THEN [if-construct-name]
|
|
struct ElseIfStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ElseIfStmt);
|
|
std::tuple<ScalarLogicalExpr, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1137 else-stmt -> ELSE [if-construct-name]
|
|
WRAPPER_CLASS(ElseStmt, std::optional<Name>);
|
|
|
|
// R1138 end-if-stmt -> END IF [if-construct-name]
|
|
WRAPPER_CLASS(EndIfStmt, std::optional<Name>);
|
|
|
|
// R1134 if-construct ->
|
|
// if-then-stmt block [else-if-stmt block]...
|
|
// [else-stmt block] end-if-stmt
|
|
struct IfConstruct {
|
|
struct ElseIfBlock {
|
|
TUPLE_CLASS_BOILERPLATE(ElseIfBlock);
|
|
std::tuple<Statement<ElseIfStmt>, Block> t;
|
|
};
|
|
struct ElseBlock {
|
|
TUPLE_CLASS_BOILERPLATE(ElseBlock);
|
|
std::tuple<Statement<ElseStmt>, Block> t;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(IfConstruct);
|
|
std::tuple<Statement<IfThenStmt>, Block, std::list<ElseIfBlock>,
|
|
std::optional<ElseBlock>, Statement<EndIfStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1139 if-stmt -> IF ( scalar-logical-expr ) action-stmt
|
|
struct IfStmt {
|
|
TUPLE_CLASS_BOILERPLATE(IfStmt);
|
|
std::tuple<ScalarLogicalExpr, UnlabeledStatement<ActionStmt>> t;
|
|
};
|
|
|
|
// R1141 select-case-stmt -> [case-construct-name :] SELECT CASE ( case-expr )
|
|
// R1144 case-expr -> scalar-expr
|
|
struct SelectCaseStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SelectCaseStmt);
|
|
std::tuple<std::optional<Name>, Scalar<Expr>> t;
|
|
};
|
|
|
|
// R1147 case-value -> scalar-constant-expr
|
|
using CaseValue = Scalar<ConstantExpr>;
|
|
|
|
// R1146 case-value-range ->
|
|
// case-value | case-value : | : case-value | case-value : case-value
|
|
struct CaseValueRange {
|
|
UNION_CLASS_BOILERPLATE(CaseValueRange);
|
|
struct Range {
|
|
BOILERPLATE(Range);
|
|
Range(std::optional<CaseValue> &&l, std::optional<CaseValue> &&u)
|
|
: lower{std::move(l)}, upper{std::move(u)} {}
|
|
std::optional<CaseValue> lower, upper; // not both missing
|
|
};
|
|
std::variant<CaseValue, Range> u;
|
|
};
|
|
|
|
// R1145 case-selector -> ( case-value-range-list ) | DEFAULT
|
|
EMPTY_CLASS(Default);
|
|
|
|
struct CaseSelector {
|
|
UNION_CLASS_BOILERPLATE(CaseSelector);
|
|
std::variant<std::list<CaseValueRange>, Default> u;
|
|
};
|
|
|
|
// R1142 case-stmt -> CASE case-selector [case-construct-name]
|
|
struct CaseStmt {
|
|
TUPLE_CLASS_BOILERPLATE(CaseStmt);
|
|
std::tuple<CaseSelector, std::optional<Name>> t;
|
|
};
|
|
|
|
// 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]
|
|
WRAPPER_CLASS(EndSelectStmt, std::optional<Name>);
|
|
|
|
// R1140 case-construct ->
|
|
// select-case-stmt [case-stmt block]... end-select-stmt
|
|
struct CaseConstruct {
|
|
struct Case {
|
|
TUPLE_CLASS_BOILERPLATE(Case);
|
|
std::tuple<Statement<CaseStmt>, Block> t;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(CaseConstruct);
|
|
std::tuple<Statement<SelectCaseStmt>, std::list<Case>,
|
|
Statement<EndSelectStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1149 select-rank-stmt ->
|
|
// [select-construct-name :] SELECT RANK
|
|
// ( [associate-name =>] selector )
|
|
struct SelectRankStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SelectRankStmt);
|
|
std::tuple<std::optional<Name>, std::optional<Name>, Selector> t;
|
|
};
|
|
|
|
// R1150 select-rank-case-stmt ->
|
|
// RANK ( scalar-int-constant-expr ) [select-construct-name] |
|
|
// RANK ( * ) [select-construct-name] |
|
|
// RANK DEFAULT [select-construct-name]
|
|
struct SelectRankCaseStmt {
|
|
struct Rank {
|
|
UNION_CLASS_BOILERPLATE(Rank);
|
|
std::variant<ScalarIntConstantExpr, Star, Default> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(SelectRankCaseStmt);
|
|
std::tuple<Rank, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1148 select-rank-construct ->
|
|
// select-rank-stmt [select-rank-case-stmt block]...
|
|
// end-select-rank-stmt
|
|
struct SelectRankConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(SelectRankConstruct);
|
|
struct RankCase {
|
|
TUPLE_CLASS_BOILERPLATE(RankCase);
|
|
std::tuple<Statement<SelectRankCaseStmt>, Block> t;
|
|
};
|
|
std::tuple<Statement<SelectRankStmt>, std::list<RankCase>,
|
|
Statement<EndSelectStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1153 select-type-stmt ->
|
|
// [select-construct-name :] SELECT TYPE
|
|
// ( [associate-name =>] selector )
|
|
struct SelectTypeStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SelectTypeStmt);
|
|
std::tuple<std::optional<Name>, std::optional<Name>, Selector> t;
|
|
};
|
|
|
|
// R1154 type-guard-stmt ->
|
|
// TYPE IS ( type-spec ) [select-construct-name] |
|
|
// CLASS IS ( derived-type-spec ) [select-construct-name] |
|
|
// CLASS DEFAULT [select-construct-name]
|
|
struct TypeGuardStmt {
|
|
struct Guard {
|
|
UNION_CLASS_BOILERPLATE(Guard);
|
|
std::variant<TypeSpec, DerivedTypeSpec, Default> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(TypeGuardStmt);
|
|
std::tuple<Guard, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1152 select-type-construct ->
|
|
// select-type-stmt [type-guard-stmt block]... end-select-type-stmt
|
|
struct SelectTypeConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(SelectTypeConstruct);
|
|
struct TypeCase {
|
|
TUPLE_CLASS_BOILERPLATE(TypeCase);
|
|
std::tuple<Statement<TypeGuardStmt>, Block> t;
|
|
};
|
|
std::tuple<Statement<SelectTypeStmt>, std::list<TypeCase>,
|
|
Statement<EndSelectStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1156 exit-stmt -> EXIT [construct-name]
|
|
WRAPPER_CLASS(ExitStmt, std::optional<Name>);
|
|
|
|
// R1157 goto-stmt -> GO TO label
|
|
WRAPPER_CLASS(GotoStmt, Label);
|
|
|
|
// R1158 computed-goto-stmt -> GO TO ( label-list ) [,] scalar-int-expr
|
|
struct ComputedGotoStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ComputedGotoStmt);
|
|
std::tuple<std::list<Label>, ScalarIntExpr> t;
|
|
};
|
|
|
|
// R1162 stop-code -> scalar-default-char-expr | scalar-int-expr
|
|
// We can't distinguish character expressions from integer
|
|
// expressions during parsing, so we just parse an expr and
|
|
// check its type later.
|
|
WRAPPER_CLASS(StopCode, Scalar<Expr>);
|
|
|
|
// R1160 stop-stmt -> STOP [stop-code] [, QUIET = scalar-logical-expr]
|
|
// R1161 error-stop-stmt ->
|
|
// ERROR STOP [stop-code] [, QUIET = scalar-logical-expr]
|
|
struct StopStmt {
|
|
ENUM_CLASS(Kind, Stop, ErrorStop)
|
|
TUPLE_CLASS_BOILERPLATE(StopStmt);
|
|
std::tuple<Kind, std::optional<StopCode>, std::optional<ScalarLogicalExpr>> t;
|
|
};
|
|
|
|
// F2023: R1166 notify-wait-stmt -> NOTIFY WAIT ( notify-variable [,
|
|
// event-wait-spec-list] )
|
|
struct NotifyWaitStmt {
|
|
TUPLE_CLASS_BOILERPLATE(NotifyWaitStmt);
|
|
std::tuple<Scalar<Variable>, std::list<EventWaitSpec>> t;
|
|
};
|
|
|
|
// R1164 sync-all-stmt -> SYNC ALL [( [sync-stat-list] )]
|
|
WRAPPER_CLASS(SyncAllStmt, std::list<StatOrErrmsg>);
|
|
|
|
// R1166 sync-images-stmt -> SYNC IMAGES ( image-set [, sync-stat-list] )
|
|
// R1167 image-set -> int-expr | *
|
|
struct SyncImagesStmt {
|
|
struct ImageSet {
|
|
UNION_CLASS_BOILERPLATE(ImageSet);
|
|
std::variant<IntExpr, Star> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(SyncImagesStmt);
|
|
std::tuple<ImageSet, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1168 sync-memory-stmt -> SYNC MEMORY [( [sync-stat-list] )]
|
|
WRAPPER_CLASS(SyncMemoryStmt, std::list<StatOrErrmsg>);
|
|
|
|
// R1169 sync-team-stmt -> SYNC TEAM ( team-value [, sync-stat-list] )
|
|
struct SyncTeamStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SyncTeamStmt);
|
|
std::tuple<TeamValue, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1171 event-variable -> scalar-variable
|
|
using EventVariable = Scalar<Variable>;
|
|
|
|
// R1170 event-post-stmt -> EVENT POST ( event-variable [, sync-stat-list] )
|
|
struct EventPostStmt {
|
|
TUPLE_CLASS_BOILERPLATE(EventPostStmt);
|
|
std::tuple<EventVariable, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1173 event-wait-spec -> until-spec | sync-stat
|
|
struct EventWaitSpec {
|
|
UNION_CLASS_BOILERPLATE(EventWaitSpec);
|
|
std::variant<ScalarIntExpr, StatOrErrmsg> u;
|
|
};
|
|
|
|
// R1172 event-wait-stmt ->
|
|
// EVENT WAIT ( event-variable [, event-wait-spec-list] )
|
|
// R1174 until-spec -> UNTIL_COUNT = scalar-int-expr
|
|
struct EventWaitStmt {
|
|
TUPLE_CLASS_BOILERPLATE(EventWaitStmt);
|
|
std::tuple<EventVariable, std::list<EventWaitSpec>> t;
|
|
};
|
|
|
|
// R1177 team-variable -> scalar-variable
|
|
using TeamVariable = Scalar<Variable>;
|
|
|
|
// R1175 form-team-stmt ->
|
|
// FORM TEAM ( team-number , team-variable [, form-team-spec-list] )
|
|
// R1176 team-number -> scalar-int-expr
|
|
// R1178 form-team-spec -> NEW_INDEX = scalar-int-expr | sync-stat
|
|
struct FormTeamStmt {
|
|
struct FormTeamSpec {
|
|
UNION_CLASS_BOILERPLATE(FormTeamSpec);
|
|
std::variant<ScalarIntExpr, StatOrErrmsg> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(FormTeamStmt);
|
|
std::tuple<ScalarIntExpr, TeamVariable, std::list<FormTeamSpec>> t;
|
|
};
|
|
|
|
// R1182 lock-variable -> scalar-variable
|
|
using LockVariable = Scalar<Variable>;
|
|
|
|
// R1179 lock-stmt -> LOCK ( lock-variable [, lock-stat-list] )
|
|
// R1180 lock-stat -> ACQUIRED_LOCK = scalar-logical-variable | sync-stat
|
|
struct LockStmt {
|
|
struct LockStat {
|
|
UNION_CLASS_BOILERPLATE(LockStat);
|
|
std::variant<Scalar<Logical<Variable>>, StatOrErrmsg> u;
|
|
};
|
|
TUPLE_CLASS_BOILERPLATE(LockStmt);
|
|
std::tuple<LockVariable, std::list<LockStat>> t;
|
|
};
|
|
|
|
// R1181 unlock-stmt -> UNLOCK ( lock-variable [, sync-stat-list] )
|
|
struct UnlockStmt {
|
|
TUPLE_CLASS_BOILERPLATE(UnlockStmt);
|
|
std::tuple<LockVariable, std::list<StatOrErrmsg>> t;
|
|
};
|
|
|
|
// R1202 file-unit-number -> scalar-int-expr
|
|
WRAPPER_CLASS(FileUnitNumber, ScalarIntExpr);
|
|
|
|
// R1201 io-unit -> file-unit-number | * | internal-file-variable
|
|
// R1203 internal-file-variable -> char-variable
|
|
// R905 char-variable -> variable
|
|
// When Variable appears as an IoUnit, it must be character of a default,
|
|
// ASCII, or Unicode kind; this constraint is not automatically checked.
|
|
// The parse is ambiguous and is repaired if necessary once the types of
|
|
// symbols are known.
|
|
struct IoUnit {
|
|
UNION_CLASS_BOILERPLATE(IoUnit);
|
|
std::variant<Variable, common::Indirection<Expr>, Star> u;
|
|
};
|
|
|
|
// R1206 file-name-expr -> scalar-default-char-expr
|
|
using 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
|
|
// @ | CARRIAGECONTROL = scalar-default-char-variable
|
|
// | CONVERT = scalar-default-char-variable
|
|
// | DISPOSE = scalar-default-char-variable
|
|
WRAPPER_CLASS(StatusExpr, ScalarDefaultCharExpr);
|
|
WRAPPER_CLASS(ErrLabel, Label);
|
|
|
|
struct ConnectSpec {
|
|
UNION_CLASS_BOILERPLATE(ConnectSpec);
|
|
struct CharExpr {
|
|
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
|
|
Encoding, Form, Pad, Position, Round, Sign,
|
|
/* extensions: */ Carriagecontrol, Convert, Dispose)
|
|
TUPLE_CLASS_BOILERPLATE(CharExpr);
|
|
std::tuple<Kind, ScalarDefaultCharExpr> t;
|
|
};
|
|
WRAPPER_CLASS(Recl, ScalarIntExpr);
|
|
WRAPPER_CLASS(Newunit, ScalarIntVariable);
|
|
std::variant<FileUnitNumber, FileNameExpr, CharExpr, MsgVariable,
|
|
StatVariable, Recl, Newunit, ErrLabel, StatusExpr>
|
|
u;
|
|
};
|
|
|
|
// R1204 open-stmt -> OPEN ( connect-spec-list )
|
|
WRAPPER_CLASS(OpenStmt, std::list<ConnectSpec>);
|
|
|
|
// R1208 close-stmt -> CLOSE ( close-spec-list )
|
|
// R1209 close-spec ->
|
|
// [UNIT =] file-unit-number | IOSTAT = scalar-int-variable |
|
|
// IOMSG = iomsg-variable | ERR = label |
|
|
// STATUS = scalar-default-char-expr
|
|
struct CloseStmt {
|
|
struct CloseSpec {
|
|
UNION_CLASS_BOILERPLATE(CloseSpec);
|
|
std::variant<FileUnitNumber, StatVariable, MsgVariable, ErrLabel,
|
|
StatusExpr>
|
|
u;
|
|
};
|
|
WRAPPER_CLASS_BOILERPLATE(CloseStmt, std::list<CloseSpec>);
|
|
};
|
|
|
|
// R1215 format -> default-char-expr | label | *
|
|
// deprecated(ASSIGN): | scalar-int-name
|
|
struct Format {
|
|
UNION_CLASS_BOILERPLATE(Format);
|
|
std::variant<Expr, Label, Star> u;
|
|
};
|
|
|
|
// R1214 id-variable -> scalar-int-variable
|
|
WRAPPER_CLASS(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
|
|
WRAPPER_CLASS(EndLabel, Label);
|
|
WRAPPER_CLASS(EorLabel, Label);
|
|
struct IoControlSpec {
|
|
UNION_CLASS_BOILERPLATE(IoControlSpec);
|
|
struct CharExpr {
|
|
ENUM_CLASS(Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign)
|
|
TUPLE_CLASS_BOILERPLATE(CharExpr);
|
|
std::tuple<Kind, ScalarDefaultCharExpr> t;
|
|
};
|
|
WRAPPER_CLASS(Asynchronous, ScalarDefaultCharConstantExpr);
|
|
WRAPPER_CLASS(Pos, ScalarIntExpr);
|
|
WRAPPER_CLASS(Rec, ScalarIntExpr);
|
|
WRAPPER_CLASS(Size, ScalarIntVariable);
|
|
std::variant<IoUnit, Format, Name, CharExpr, Asynchronous, EndLabel, EorLabel,
|
|
ErrLabel, IdVariable, MsgVariable, StatVariable, Pos, Rec, Size>
|
|
u;
|
|
};
|
|
|
|
// R1216 input-item -> variable | io-implied-do
|
|
struct InputItem {
|
|
UNION_CLASS_BOILERPLATE(InputItem);
|
|
std::variant<Variable, common::Indirection<InputImpliedDo>> u;
|
|
};
|
|
|
|
// R1210 read-stmt ->
|
|
// READ ( io-control-spec-list ) [input-item-list] |
|
|
// READ format [, input-item-list]
|
|
struct ReadStmt {
|
|
BOILERPLATE(ReadStmt);
|
|
ReadStmt(std::optional<IoUnit> &&i, std::optional<Format> &&f,
|
|
std::list<IoControlSpec> &&cs, std::list<InputItem> &&its)
|
|
: iounit{std::move(i)}, format{std::move(f)}, controls(std::move(cs)),
|
|
items(std::move(its)) {}
|
|
std::optional<IoUnit> iounit; // if first in controls without UNIT= &/or
|
|
// followed by untagged format/namelist
|
|
std::optional<Format> format; // if second in controls without FMT=/NML=, or
|
|
// no (io-control-spec-list); might be
|
|
// an untagged namelist group name
|
|
std::list<IoControlSpec> controls;
|
|
std::list<InputItem> items;
|
|
};
|
|
|
|
// R1217 output-item -> expr | io-implied-do
|
|
struct OutputItem {
|
|
UNION_CLASS_BOILERPLATE(OutputItem);
|
|
std::variant<Expr, common::Indirection<OutputImpliedDo>> u;
|
|
};
|
|
|
|
// R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list]
|
|
struct WriteStmt {
|
|
BOILERPLATE(WriteStmt);
|
|
WriteStmt(std::optional<IoUnit> &&i, std::optional<Format> &&f,
|
|
std::list<IoControlSpec> &&cs, std::list<OutputItem> &&its)
|
|
: iounit{std::move(i)}, format{std::move(f)}, controls(std::move(cs)),
|
|
items(std::move(its)) {}
|
|
std::optional<IoUnit> iounit; // if first in controls without UNIT= &/or
|
|
// followed by untagged format/namelist
|
|
std::optional<Format> format; // if second in controls without FMT=/NML=;
|
|
// might be an untagged namelist group, too
|
|
std::list<IoControlSpec> controls;
|
|
std::list<OutputItem> items;
|
|
};
|
|
|
|
// R1212 print-stmt PRINT format [, output-item-list]
|
|
struct PrintStmt {
|
|
TUPLE_CLASS_BOILERPLATE(PrintStmt);
|
|
std::tuple<Format, std::list<OutputItem>> t;
|
|
};
|
|
|
|
// R1220 io-implied-do-control ->
|
|
// do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr]
|
|
using IoImpliedDoControl = LoopBounds<DoVariable, ScalarIntExpr>;
|
|
|
|
// R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control )
|
|
// R1219 io-implied-do-object -> input-item | output-item
|
|
struct InputImpliedDo {
|
|
TUPLE_CLASS_BOILERPLATE(InputImpliedDo);
|
|
std::tuple<std::list<InputItem>, IoImpliedDoControl> t;
|
|
};
|
|
|
|
struct OutputImpliedDo {
|
|
TUPLE_CLASS_BOILERPLATE(OutputImpliedDo);
|
|
std::tuple<std::list<OutputItem>, IoImpliedDoControl> t;
|
|
};
|
|
|
|
// R1223 wait-spec ->
|
|
// [UNIT =] file-unit-number | END = label | EOR = label | ERR = label |
|
|
// ID = scalar-int-expr | IOMSG = iomsg-variable |
|
|
// IOSTAT = scalar-int-variable
|
|
WRAPPER_CLASS(IdExpr, ScalarIntExpr);
|
|
struct WaitSpec {
|
|
UNION_CLASS_BOILERPLATE(WaitSpec);
|
|
std::variant<FileUnitNumber, EndLabel, EorLabel, ErrLabel, IdExpr,
|
|
MsgVariable, StatVariable>
|
|
u;
|
|
};
|
|
|
|
// R1222 wait-stmt -> WAIT ( wait-spec-list )
|
|
WRAPPER_CLASS(WaitStmt, std::list<WaitSpec>);
|
|
|
|
// 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
|
|
struct PositionOrFlushSpec {
|
|
UNION_CLASS_BOILERPLATE(PositionOrFlushSpec);
|
|
std::variant<FileUnitNumber, MsgVariable, StatVariable, ErrLabel> u;
|
|
};
|
|
|
|
// R1224 backspace-stmt ->
|
|
// BACKSPACE file-unit-number | BACKSPACE ( position-spec-list )
|
|
WRAPPER_CLASS(BackspaceStmt, std::list<PositionOrFlushSpec>);
|
|
|
|
// R1225 endfile-stmt ->
|
|
// ENDFILE file-unit-number | ENDFILE ( position-spec-list )
|
|
WRAPPER_CLASS(EndfileStmt, std::list<PositionOrFlushSpec>);
|
|
|
|
// R1226 rewind-stmt -> REWIND file-unit-number | REWIND ( position-spec-list )
|
|
WRAPPER_CLASS(RewindStmt, std::list<PositionOrFlushSpec>);
|
|
|
|
// R1228 flush-stmt -> FLUSH file-unit-number | FLUSH ( flush-spec-list )
|
|
WRAPPER_CLASS(FlushStmt, std::list<PositionOrFlushSpec>);
|
|
|
|
// 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 |
|
|
// DIRECT = 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 |
|
|
// UNFORMATTED = scalar-default-char-variable |
|
|
// WRITE = scalar-default-char-variable
|
|
// @ | CARRIAGECONTROL = scalar-default-char-variable
|
|
// | CONVERT = scalar-default-char-variable
|
|
// | DISPOSE = scalar-default-char-variable
|
|
struct InquireSpec {
|
|
UNION_CLASS_BOILERPLATE(InquireSpec);
|
|
struct CharVar {
|
|
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
|
|
Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read,
|
|
Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, Write,
|
|
/* extensions: */ Carriagecontrol, Convert, Dispose)
|
|
TUPLE_CLASS_BOILERPLATE(CharVar);
|
|
std::tuple<Kind, ScalarDefaultCharVariable> t;
|
|
};
|
|
struct IntVar {
|
|
ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size)
|
|
TUPLE_CLASS_BOILERPLATE(IntVar);
|
|
std::tuple<Kind, ScalarIntVariable> t;
|
|
};
|
|
struct LogVar {
|
|
ENUM_CLASS(Kind, Exist, Named, Opened, Pending)
|
|
TUPLE_CLASS_BOILERPLATE(LogVar);
|
|
std::tuple<Kind, Scalar<Logical<Variable>>> t;
|
|
};
|
|
std::variant<FileUnitNumber, FileNameExpr, CharVar, IntVar, LogVar, IdExpr,
|
|
ErrLabel>
|
|
u;
|
|
};
|
|
|
|
// R1230 inquire-stmt ->
|
|
// INQUIRE ( inquire-spec-list ) |
|
|
// INQUIRE ( IOLENGTH = scalar-int-variable ) output-item-list
|
|
struct InquireStmt {
|
|
UNION_CLASS_BOILERPLATE(InquireStmt);
|
|
struct Iolength {
|
|
TUPLE_CLASS_BOILERPLATE(Iolength);
|
|
std::tuple<ScalarIntVariable, std::list<OutputItem>> t;
|
|
};
|
|
std::variant<std::list<InquireSpec>, Iolength> u;
|
|
};
|
|
|
|
// R1301 format-stmt -> FORMAT format-specification
|
|
WRAPPER_CLASS(FormatStmt, format::FormatSpecification);
|
|
|
|
// R1402 program-stmt -> PROGRAM program-name
|
|
WRAPPER_CLASS(ProgramStmt, Name);
|
|
|
|
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
|
|
WRAPPER_CLASS(EndProgramStmt, std::optional<Name>);
|
|
|
|
// R1401 main-program ->
|
|
// [program-stmt] [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-program-stmt
|
|
struct MainProgram {
|
|
TUPLE_CLASS_BOILERPLATE(MainProgram);
|
|
std::tuple<std::optional<Statement<ProgramStmt>>, SpecificationPart,
|
|
ExecutionPart, std::optional<InternalSubprogramPart>,
|
|
Statement<EndProgramStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1405 module-stmt -> MODULE module-name
|
|
WRAPPER_CLASS(ModuleStmt, Name);
|
|
|
|
// R1408 module-subprogram ->
|
|
// function-subprogram | subroutine-subprogram |
|
|
// separate-module-subprogram
|
|
struct ModuleSubprogram {
|
|
UNION_CLASS_BOILERPLATE(ModuleSubprogram);
|
|
std::variant<common::Indirection<FunctionSubprogram>,
|
|
common::Indirection<SubroutineSubprogram>,
|
|
common::Indirection<SeparateModuleSubprogram>,
|
|
common::Indirection<CompilerDirective>>
|
|
u;
|
|
};
|
|
|
|
// R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
|
|
struct ModuleSubprogramPart {
|
|
TUPLE_CLASS_BOILERPLATE(ModuleSubprogramPart);
|
|
std::tuple<Statement<ContainsStmt>, std::list<ModuleSubprogram>> t;
|
|
};
|
|
|
|
// R1406 end-module-stmt -> END [MODULE [module-name]]
|
|
WRAPPER_CLASS(EndModuleStmt, std::optional<Name>);
|
|
|
|
// R1404 module ->
|
|
// module-stmt [specification-part] [module-subprogram-part]
|
|
// end-module-stmt
|
|
struct Module {
|
|
TUPLE_CLASS_BOILERPLATE(Module);
|
|
std::tuple<Statement<ModuleStmt>, SpecificationPart,
|
|
std::optional<ModuleSubprogramPart>, Statement<EndModuleStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1411 rename ->
|
|
// local-name => use-name |
|
|
// OPERATOR ( local-defined-operator ) =>
|
|
// OPERATOR ( use-defined-operator )
|
|
struct Rename {
|
|
UNION_CLASS_BOILERPLATE(Rename);
|
|
struct Names {
|
|
TUPLE_CLASS_BOILERPLATE(Names);
|
|
std::tuple<Name, Name> t;
|
|
};
|
|
struct Operators {
|
|
TUPLE_CLASS_BOILERPLATE(Operators);
|
|
std::tuple<DefinedOpName, DefinedOpName> t;
|
|
};
|
|
std::variant<Names, Operators> u;
|
|
};
|
|
|
|
// R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name]
|
|
struct ParentIdentifier {
|
|
TUPLE_CLASS_BOILERPLATE(ParentIdentifier);
|
|
std::tuple<Name, std::optional<Name>> t;
|
|
};
|
|
|
|
// R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name
|
|
struct SubmoduleStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SubmoduleStmt);
|
|
std::tuple<ParentIdentifier, Name> t;
|
|
};
|
|
|
|
// R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
|
|
WRAPPER_CLASS(EndSubmoduleStmt, std::optional<Name>);
|
|
|
|
// R1416 submodule ->
|
|
// submodule-stmt [specification-part] [module-subprogram-part]
|
|
// end-submodule-stmt
|
|
struct Submodule {
|
|
TUPLE_CLASS_BOILERPLATE(Submodule);
|
|
std::tuple<Statement<SubmoduleStmt>, SpecificationPart,
|
|
std::optional<ModuleSubprogramPart>, Statement<EndSubmoduleStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1421 block-data-stmt -> BLOCK DATA [block-data-name]
|
|
WRAPPER_CLASS(BlockDataStmt, std::optional<Name>);
|
|
|
|
// R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
|
|
WRAPPER_CLASS(EndBlockDataStmt, std::optional<Name>);
|
|
|
|
// R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
|
|
struct BlockData {
|
|
TUPLE_CLASS_BOILERPLATE(BlockData);
|
|
std::tuple<Statement<BlockDataStmt>, SpecificationPart,
|
|
Statement<EndBlockDataStmt>>
|
|
t;
|
|
};
|
|
|
|
// 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 )
|
|
struct GenericSpec {
|
|
UNION_CLASS_BOILERPLATE(GenericSpec);
|
|
EMPTY_CLASS(Assignment);
|
|
EMPTY_CLASS(ReadFormatted);
|
|
EMPTY_CLASS(ReadUnformatted);
|
|
EMPTY_CLASS(WriteFormatted);
|
|
EMPTY_CLASS(WriteUnformatted);
|
|
CharBlock source;
|
|
std::variant<Name, DefinedOperator, Assignment, ReadFormatted,
|
|
ReadUnformatted, WriteFormatted, WriteUnformatted>
|
|
u;
|
|
};
|
|
|
|
// R1510 generic-stmt ->
|
|
// GENERIC [, access-spec] :: generic-spec => specific-procedure-list
|
|
struct GenericStmt {
|
|
TUPLE_CLASS_BOILERPLATE(GenericStmt);
|
|
std::tuple<std::optional<AccessSpec>, GenericSpec, std::list<Name>> t;
|
|
};
|
|
|
|
// R1503 interface-stmt -> INTERFACE [generic-spec] | ABSTRACT INTERFACE
|
|
struct InterfaceStmt {
|
|
UNION_CLASS_BOILERPLATE(InterfaceStmt);
|
|
// Workaround for clang with libstc++10 bug
|
|
InterfaceStmt(Abstract x) : u{x} {}
|
|
|
|
std::variant<std::optional<GenericSpec>, Abstract> u;
|
|
};
|
|
|
|
// R1412 only -> generic-spec | only-use-name | rename
|
|
// R1413 only-use-name -> use-name
|
|
struct Only {
|
|
UNION_CLASS_BOILERPLATE(Only);
|
|
std::variant<common::Indirection<GenericSpec>, Name, Rename> u;
|
|
};
|
|
|
|
// R1409 use-stmt ->
|
|
// USE [[, module-nature] ::] module-name [, rename-list] |
|
|
// USE [[, module-nature] ::] module-name , ONLY : [only-list]
|
|
// R1410 module-nature -> INTRINSIC | NON_INTRINSIC
|
|
struct UseStmt {
|
|
BOILERPLATE(UseStmt);
|
|
ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic) // R1410
|
|
template <typename A>
|
|
UseStmt(std::optional<ModuleNature> &&nat, Name &&n, std::list<A> &&x)
|
|
: nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {}
|
|
std::optional<ModuleNature> nature;
|
|
Name moduleName;
|
|
std::variant<std::list<Rename>, std::list<Only>> u;
|
|
};
|
|
|
|
// R1514 proc-attr-spec ->
|
|
// access-spec | proc-language-binding-spec | INTENT ( intent-spec ) |
|
|
// OPTIONAL | POINTER | PROTECTED | SAVE
|
|
struct ProcAttrSpec {
|
|
UNION_CLASS_BOILERPLATE(ProcAttrSpec);
|
|
std::variant<AccessSpec, LanguageBindingSpec, IntentSpec, Optional, Pointer,
|
|
Protected, Save>
|
|
u;
|
|
};
|
|
|
|
// R1512 procedure-declaration-stmt ->
|
|
// PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::]
|
|
// proc-decl-list
|
|
struct ProcedureDeclarationStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ProcedureDeclarationStmt);
|
|
std::tuple<std::optional<ProcInterface>, std::list<ProcAttrSpec>,
|
|
std::list<ProcDecl>>
|
|
t;
|
|
};
|
|
|
|
// R1527 prefix-spec ->
|
|
// declaration-type-spec | ELEMENTAL | IMPURE | MODULE |
|
|
// NON_RECURSIVE | PURE | RECURSIVE |
|
|
// (CUDA) ATTRIBUTES ( (DEVICE | GLOBAL | GRID_GLOBAL | HOST)... )
|
|
// LAUNCH_BOUNDS(expr-list) | CLUSTER_DIMS(expr-list)
|
|
struct PrefixSpec {
|
|
UNION_CLASS_BOILERPLATE(PrefixSpec);
|
|
EMPTY_CLASS(Elemental);
|
|
EMPTY_CLASS(Impure);
|
|
EMPTY_CLASS(Module);
|
|
EMPTY_CLASS(Non_Recursive);
|
|
EMPTY_CLASS(Pure);
|
|
EMPTY_CLASS(Recursive);
|
|
WRAPPER_CLASS(Attributes, std::list<common::CUDASubprogramAttrs>);
|
|
WRAPPER_CLASS(Launch_Bounds, std::list<ScalarIntConstantExpr>);
|
|
WRAPPER_CLASS(Cluster_Dims, std::list<ScalarIntConstantExpr>);
|
|
std::variant<DeclarationTypeSpec, Elemental, Impure, Module, Non_Recursive,
|
|
Pure, Recursive, Attributes, Launch_Bounds, Cluster_Dims>
|
|
u;
|
|
};
|
|
|
|
// R1532 suffix ->
|
|
// proc-language-binding-spec [RESULT ( result-name )] |
|
|
// RESULT ( result-name ) [proc-language-binding-spec]
|
|
struct Suffix {
|
|
BOILERPLATE(Suffix);
|
|
Suffix(LanguageBindingSpec &&lbs, std::optional<Name> &&rn)
|
|
: binding(std::move(lbs)), resultName(std::move(rn)) {}
|
|
Suffix(Name &&rn, std::optional<LanguageBindingSpec> &&lbs)
|
|
: binding(std::move(lbs)), resultName(std::move(rn)) {}
|
|
std::optional<LanguageBindingSpec> binding;
|
|
std::optional<Name> resultName;
|
|
};
|
|
|
|
// R1530 function-stmt ->
|
|
// [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix]
|
|
// R1526 prefix -> prefix-spec [prefix-spec]...
|
|
// R1531 dummy-arg-name -> name
|
|
struct FunctionStmt {
|
|
TUPLE_CLASS_BOILERPLATE(FunctionStmt);
|
|
std::tuple<std::list<PrefixSpec>, Name, std::list<Name>,
|
|
std::optional<Suffix>>
|
|
t;
|
|
};
|
|
|
|
// R1533 end-function-stmt -> END [FUNCTION [function-name]]
|
|
WRAPPER_CLASS(EndFunctionStmt, std::optional<Name>);
|
|
|
|
// R1536 dummy-arg -> dummy-arg-name | *
|
|
struct DummyArg {
|
|
UNION_CLASS_BOILERPLATE(DummyArg);
|
|
std::variant<Name, Star> u;
|
|
};
|
|
|
|
// R1535 subroutine-stmt ->
|
|
// [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] )
|
|
// [proc-language-binding-spec]]
|
|
struct SubroutineStmt {
|
|
TUPLE_CLASS_BOILERPLATE(SubroutineStmt);
|
|
std::tuple<std::list<PrefixSpec>, Name, std::list<DummyArg>,
|
|
std::optional<LanguageBindingSpec>>
|
|
t;
|
|
};
|
|
|
|
// R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
|
|
WRAPPER_CLASS(EndSubroutineStmt, std::optional<Name>);
|
|
|
|
// R1505 interface-body ->
|
|
// function-stmt [specification-part] end-function-stmt |
|
|
// subroutine-stmt [specification-part] end-subroutine-stmt
|
|
struct InterfaceBody {
|
|
UNION_CLASS_BOILERPLATE(InterfaceBody);
|
|
struct Function {
|
|
TUPLE_CLASS_BOILERPLATE(Function);
|
|
std::tuple<Statement<FunctionStmt>, common::Indirection<SpecificationPart>,
|
|
Statement<EndFunctionStmt>>
|
|
t;
|
|
};
|
|
struct Subroutine {
|
|
TUPLE_CLASS_BOILERPLATE(Subroutine);
|
|
std::tuple<Statement<SubroutineStmt>,
|
|
common::Indirection<SpecificationPart>, Statement<EndSubroutineStmt>>
|
|
t;
|
|
};
|
|
std::variant<Function, Subroutine> u;
|
|
};
|
|
|
|
// R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
|
|
struct ProcedureStmt {
|
|
ENUM_CLASS(Kind, ModuleProcedure, Procedure)
|
|
TUPLE_CLASS_BOILERPLATE(ProcedureStmt);
|
|
std::tuple<Kind, std::list<Name>> t;
|
|
};
|
|
|
|
// R1502 interface-specification -> interface-body | procedure-stmt
|
|
struct InterfaceSpecification {
|
|
UNION_CLASS_BOILERPLATE(InterfaceSpecification);
|
|
std::variant<InterfaceBody, Statement<ProcedureStmt>> u;
|
|
};
|
|
|
|
// R1504 end-interface-stmt -> END INTERFACE [generic-spec]
|
|
WRAPPER_CLASS(EndInterfaceStmt, std::optional<GenericSpec>);
|
|
|
|
// R1501 interface-block ->
|
|
// interface-stmt [interface-specification]... end-interface-stmt
|
|
struct InterfaceBlock {
|
|
TUPLE_CLASS_BOILERPLATE(InterfaceBlock);
|
|
std::tuple<Statement<InterfaceStmt>, std::list<InterfaceSpecification>,
|
|
Statement<EndInterfaceStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1511 external-stmt -> EXTERNAL [::] external-name-list
|
|
WRAPPER_CLASS(ExternalStmt, std::list<Name>);
|
|
|
|
// R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list
|
|
WRAPPER_CLASS(IntrinsicStmt, std::list<Name>);
|
|
|
|
// R1522 procedure-designator ->
|
|
// procedure-name | proc-component-ref | data-ref % binding-name
|
|
struct ProcedureDesignator {
|
|
UNION_CLASS_BOILERPLATE(ProcedureDesignator);
|
|
std::variant<Name, ProcComponentRef> u;
|
|
};
|
|
|
|
// R1525 alt-return-spec -> * label
|
|
WRAPPER_CLASS(AltReturnSpec, Label);
|
|
|
|
// R1524 actual-arg ->
|
|
// expr | variable | procedure-name | proc-component-ref |
|
|
// alt-return-spec
|
|
struct ActualArg {
|
|
WRAPPER_CLASS(PercentRef, Expr); // %REF(x) extension
|
|
WRAPPER_CLASS(PercentVal, Expr); // %VAL(x) extension
|
|
UNION_CLASS_BOILERPLATE(ActualArg);
|
|
ActualArg(Expr &&x) : u{common::Indirection<Expr>(std::move(x))} {}
|
|
std::variant<common::Indirection<Expr>, AltReturnSpec, PercentRef, PercentVal>
|
|
u;
|
|
};
|
|
|
|
// R1523 actual-arg-spec -> [keyword =] actual-arg
|
|
struct ActualArgSpec {
|
|
TUPLE_CLASS_BOILERPLATE(ActualArgSpec);
|
|
std::tuple<std::optional<Keyword>, ActualArg> t;
|
|
};
|
|
|
|
// R1520 function-reference -> procedure-designator
|
|
// ( [actual-arg-spec-list] )
|
|
struct Call {
|
|
TUPLE_CLASS_BOILERPLATE(Call);
|
|
std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
|
|
};
|
|
|
|
struct FunctionReference {
|
|
WRAPPER_CLASS_BOILERPLATE(FunctionReference, Call);
|
|
CharBlock source;
|
|
Designator ConvertToArrayElementRef();
|
|
StructureConstructor ConvertToStructureConstructor(
|
|
const semantics::DerivedTypeSpec &);
|
|
};
|
|
|
|
// R1521 call-stmt -> CALL procedure-designator [ chevrons ]
|
|
// [( [actual-arg-spec-list] )]
|
|
// (CUDA) chevrons -> <<< * | scalar-expr, scalar-expr [,
|
|
// scalar-int-expr [, scalar-int-expr ] ] >>>
|
|
struct CallStmt {
|
|
BOILERPLATE(CallStmt);
|
|
WRAPPER_CLASS(StarOrExpr, std::optional<ScalarExpr>);
|
|
struct Chevrons {
|
|
TUPLE_CLASS_BOILERPLATE(Chevrons);
|
|
std::tuple<StarOrExpr, ScalarExpr, std::optional<ScalarIntExpr>,
|
|
std::optional<ScalarIntExpr>>
|
|
t;
|
|
};
|
|
explicit CallStmt(ProcedureDesignator &&pd, std::optional<Chevrons> &&ch,
|
|
std::list<ActualArgSpec> &&args)
|
|
: call{std::move(pd), std::move(args)}, chevrons{std::move(ch)} {}
|
|
Call call;
|
|
std::optional<Chevrons> chevrons;
|
|
CharBlock source;
|
|
mutable common::ForwardOwningPointer<evaluate::ProcedureRef>
|
|
typedCall; // filled by semantics
|
|
};
|
|
|
|
// R1529 function-subprogram ->
|
|
// function-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-function-stmt
|
|
struct FunctionSubprogram {
|
|
TUPLE_CLASS_BOILERPLATE(FunctionSubprogram);
|
|
std::tuple<Statement<FunctionStmt>, SpecificationPart, ExecutionPart,
|
|
std::optional<InternalSubprogramPart>, Statement<EndFunctionStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1534 subroutine-subprogram ->
|
|
// subroutine-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-subroutine-stmt
|
|
struct SubroutineSubprogram {
|
|
TUPLE_CLASS_BOILERPLATE(SubroutineSubprogram);
|
|
std::tuple<Statement<SubroutineStmt>, SpecificationPart, ExecutionPart,
|
|
std::optional<InternalSubprogramPart>, Statement<EndSubroutineStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name
|
|
WRAPPER_CLASS(MpSubprogramStmt, Name);
|
|
|
|
// R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
|
|
WRAPPER_CLASS(EndMpSubprogramStmt, std::optional<Name>);
|
|
|
|
// R1538 separate-module-subprogram ->
|
|
// mp-subprogram-stmt [specification-part] [execution-part]
|
|
// [internal-subprogram-part] end-mp-subprogram-stmt
|
|
struct SeparateModuleSubprogram {
|
|
TUPLE_CLASS_BOILERPLATE(SeparateModuleSubprogram);
|
|
std::tuple<Statement<MpSubprogramStmt>, SpecificationPart, ExecutionPart,
|
|
std::optional<InternalSubprogramPart>, Statement<EndMpSubprogramStmt>>
|
|
t;
|
|
};
|
|
|
|
// R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
|
|
struct EntryStmt {
|
|
TUPLE_CLASS_BOILERPLATE(EntryStmt);
|
|
std::tuple<Name, std::list<DummyArg>, std::optional<Suffix>> t;
|
|
};
|
|
|
|
// R1542 return-stmt -> RETURN [scalar-int-expr]
|
|
WRAPPER_CLASS(ReturnStmt, std::optional<ScalarIntExpr>);
|
|
|
|
// R1544 stmt-function-stmt ->
|
|
// function-name ( [dummy-arg-name-list] ) = scalar-expr
|
|
struct StmtFunctionStmt {
|
|
TUPLE_CLASS_BOILERPLATE(StmtFunctionStmt);
|
|
std::tuple<Name, std::list<Name>, Scalar<Expr>> t;
|
|
Statement<ActionStmt> ConvertToAssignment();
|
|
};
|
|
|
|
// Compiler directives
|
|
// !DIR$ IGNORE_TKR [ [(tkrdmac...)] name ]...
|
|
// !DIR$ LOOP COUNT (n1[, n2]...)
|
|
// !DIR$ name[=value] [, name[=value]]... = can be :
|
|
// !DIR$ UNROLL [N]
|
|
// !DIR$ UNROLL_AND_JAM [N]
|
|
// !DIR$ <anything else>
|
|
struct CompilerDirective {
|
|
UNION_CLASS_BOILERPLATE(CompilerDirective);
|
|
struct IgnoreTKR {
|
|
TUPLE_CLASS_BOILERPLATE(IgnoreTKR);
|
|
std::tuple<std::optional<std::list<const char *>>, Name> t;
|
|
};
|
|
struct LoopCount {
|
|
WRAPPER_CLASS_BOILERPLATE(LoopCount, std::list<std::uint64_t>);
|
|
};
|
|
struct AssumeAligned {
|
|
TUPLE_CLASS_BOILERPLATE(AssumeAligned);
|
|
std::tuple<common::Indirection<Designator>, uint64_t> t;
|
|
};
|
|
EMPTY_CLASS(VectorAlways);
|
|
struct NameValue {
|
|
TUPLE_CLASS_BOILERPLATE(NameValue);
|
|
std::tuple<Name, std::optional<std::uint64_t>> t;
|
|
};
|
|
struct Unroll {
|
|
WRAPPER_CLASS_BOILERPLATE(Unroll, std::optional<std::uint64_t>);
|
|
};
|
|
struct UnrollAndJam {
|
|
WRAPPER_CLASS_BOILERPLATE(UnrollAndJam, std::optional<std::uint64_t>);
|
|
};
|
|
EMPTY_CLASS(Unrecognized);
|
|
CharBlock source;
|
|
std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
|
|
VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized>
|
|
u;
|
|
};
|
|
|
|
// (CUDA) ATTRIBUTE(attribute) [::] name-list
|
|
struct CUDAAttributesStmt {
|
|
TUPLE_CLASS_BOILERPLATE(CUDAAttributesStmt);
|
|
std::tuple<common::CUDADataAttr, std::list<Name>> t;
|
|
};
|
|
|
|
// Legacy extensions
|
|
struct BasedPointer {
|
|
TUPLE_CLASS_BOILERPLATE(BasedPointer);
|
|
std::tuple<ObjectName, ObjectName, std::optional<ArraySpec>> t;
|
|
};
|
|
WRAPPER_CLASS(BasedPointerStmt, std::list<BasedPointer>);
|
|
|
|
struct Union;
|
|
struct StructureDef;
|
|
|
|
struct StructureField {
|
|
UNION_CLASS_BOILERPLATE(StructureField);
|
|
std::variant<Statement<DataComponentDefStmt>,
|
|
common::Indirection<StructureDef>, common::Indirection<Union>>
|
|
u;
|
|
};
|
|
|
|
struct Map {
|
|
EMPTY_CLASS(MapStmt);
|
|
EMPTY_CLASS(EndMapStmt);
|
|
TUPLE_CLASS_BOILERPLATE(Map);
|
|
std::tuple<Statement<MapStmt>, std::list<StructureField>,
|
|
Statement<EndMapStmt>>
|
|
t;
|
|
};
|
|
|
|
struct Union {
|
|
EMPTY_CLASS(UnionStmt);
|
|
EMPTY_CLASS(EndUnionStmt);
|
|
TUPLE_CLASS_BOILERPLATE(Union);
|
|
std::tuple<Statement<UnionStmt>, std::list<Map>, Statement<EndUnionStmt>> t;
|
|
};
|
|
|
|
struct StructureStmt {
|
|
TUPLE_CLASS_BOILERPLATE(StructureStmt);
|
|
std::tuple<std::optional<Name>, std::list<EntityDecl>> t;
|
|
};
|
|
|
|
struct StructureDef {
|
|
EMPTY_CLASS(EndStructureStmt);
|
|
TUPLE_CLASS_BOILERPLATE(StructureDef);
|
|
std::tuple<Statement<StructureStmt>, std::list<StructureField>,
|
|
Statement<EndStructureStmt>>
|
|
t;
|
|
};
|
|
|
|
// Old style PARAMETER statement without parentheses.
|
|
// Types are determined entirely from the right-hand sides, not the names.
|
|
WRAPPER_CLASS(OldParameterStmt, std::list<NamedConstantDef>);
|
|
|
|
// Deprecations
|
|
struct ArithmeticIfStmt {
|
|
TUPLE_CLASS_BOILERPLATE(ArithmeticIfStmt);
|
|
std::tuple<Expr, Label, Label, Label> t;
|
|
};
|
|
|
|
struct AssignStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AssignStmt);
|
|
std::tuple<Label, Name> t;
|
|
};
|
|
|
|
struct AssignedGotoStmt {
|
|
TUPLE_CLASS_BOILERPLATE(AssignedGotoStmt);
|
|
std::tuple<Name, std::list<Label>> t;
|
|
};
|
|
|
|
WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
|
|
|
|
// Parse tree nodes for OpenMP directives and clauses
|
|
|
|
// --- Common definitions
|
|
|
|
struct OmpClause;
|
|
struct OmpDirectiveSpecification;
|
|
|
|
struct OmpDirectiveName {
|
|
// No boilerplates: this class should be copyable, movable, etc.
|
|
constexpr OmpDirectiveName() = default;
|
|
constexpr OmpDirectiveName(const OmpDirectiveName &) = default;
|
|
// Construct from an already parsed text. Use Verbatim for this because
|
|
// Verbatim's source corresponds to an actual source location.
|
|
// This allows "construct<OmpDirectiveName>(Verbatim("<name>"))".
|
|
OmpDirectiveName(const Verbatim &name);
|
|
using WrapperTrait = std::true_type;
|
|
CharBlock source;
|
|
llvm::omp::Directive v{llvm::omp::Directive::OMPD_unknown};
|
|
};
|
|
|
|
// 2.1 Directives or clauses may accept a list or extended-list.
|
|
// A list item is a variable, array section or common block name (enclosed
|
|
// in slashes). An extended list item is a list item or a procedure Name.
|
|
// variable-name | / common-block / | array-sections
|
|
struct OmpObject {
|
|
UNION_CLASS_BOILERPLATE(OmpObject);
|
|
std::variant<Designator, /*common block*/ Name> u;
|
|
};
|
|
|
|
WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
|
|
|
|
// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
|
|
//
|
|
// reduction-identifier ->
|
|
// base-language-identifier | // since 4.5
|
|
// - | // since 4.5, until 5.2
|
|
// + | * | .AND. | .OR. | .EQV. | .NEQV. | // since 4.5
|
|
// MIN | MAX | IAND | IOR | IEOR // since 4.5
|
|
struct OmpReductionIdentifier {
|
|
UNION_CLASS_BOILERPLATE(OmpReductionIdentifier);
|
|
std::variant<DefinedOperator, ProcedureDesignator> u;
|
|
};
|
|
|
|
// Ref: [4.5:222:6], [5.0:305:27], [5.1:337:19], [5.2:126:3-4], [6.0:240:27-28]
|
|
//
|
|
// combiner-expression -> // since 4.5
|
|
// assignment-statement |
|
|
// function-reference
|
|
struct OmpReductionCombiner {
|
|
UNION_CLASS_BOILERPLATE(OmpReductionCombiner);
|
|
std::variant<AssignmentStmt, FunctionReference> u;
|
|
};
|
|
|
|
inline namespace arguments {
|
|
struct OmpTypeSpecifier {
|
|
UNION_CLASS_BOILERPLATE(OmpTypeSpecifier);
|
|
std::variant<TypeSpec, DeclarationTypeSpec> u;
|
|
};
|
|
|
|
WRAPPER_CLASS(OmpTypeNameList, std::list<OmpTypeSpecifier>);
|
|
|
|
struct OmpLocator {
|
|
UNION_CLASS_BOILERPLATE(OmpLocator);
|
|
std::variant<OmpObject, FunctionReference> u;
|
|
};
|
|
|
|
WRAPPER_CLASS(OmpLocatorList, std::list<OmpLocator>);
|
|
|
|
// Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21]
|
|
//
|
|
// mapper-specifier ->
|
|
// [mapper-identifier :] type :: var | // since 5.0
|
|
// DEFAULT type :: var
|
|
struct OmpMapperSpecifier {
|
|
// Absent mapper-identifier is equivalent to DEFAULT.
|
|
TUPLE_CLASS_BOILERPLATE(OmpMapperSpecifier);
|
|
std::tuple<std::optional<Name>, TypeSpec, Name> t;
|
|
};
|
|
|
|
// Ref: [4.5:222:1-5], [5.0:305:20-27], [5.1:337:11-19], [5.2:139:18-23],
|
|
// [6.0:260:16-20]
|
|
//
|
|
// reduction-specifier ->
|
|
// reduction-identifier : typename-list
|
|
// : combiner-expression // since 4.5, until 5.2
|
|
// reduction-identifier : typename-list // since 6.0
|
|
struct OmpReductionSpecifier {
|
|
TUPLE_CLASS_BOILERPLATE(OmpReductionSpecifier);
|
|
std::tuple<OmpReductionIdentifier, OmpTypeNameList,
|
|
std::optional<OmpReductionCombiner>>
|
|
t;
|
|
};
|
|
|
|
struct OmpArgument {
|
|
CharBlock source;
|
|
UNION_CLASS_BOILERPLATE(OmpArgument);
|
|
std::variant<OmpLocator, // {variable, extended, locator}-list-item
|
|
OmpMapperSpecifier, OmpReductionSpecifier>
|
|
u;
|
|
};
|
|
} // namespace arguments
|
|
|
|
inline namespace traits {
|
|
// trait-property-name ->
|
|
// identifier | string-literal
|
|
//
|
|
// This is a bit of a problematic case. The spec says that a word in quotes,
|
|
// and the same word without quotes are equivalent. We currently parse both
|
|
// as a string, but it's likely just a temporary solution.
|
|
//
|
|
// The problem is that trait-property can be (among other things) a
|
|
// trait-property-name or a trait-property-expression. A simple identifier
|
|
// can be either, there is no reasonably simple way of telling them apart
|
|
// in the parser. There is a similar issue with extensions. Some of that
|
|
// disambiguation may need to be done in the "canonicalization" pass and
|
|
// then some of those AST nodes would be rewritten into different ones.
|
|
//
|
|
struct OmpTraitPropertyName {
|
|
CharBlock source;
|
|
WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string);
|
|
};
|
|
|
|
// trait-score ->
|
|
// SCORE(non-negative-const-integer-expression)
|
|
struct OmpTraitScore {
|
|
CharBlock source;
|
|
WRAPPER_CLASS_BOILERPLATE(OmpTraitScore, ScalarIntExpr);
|
|
};
|
|
|
|
// trait-property-extension ->
|
|
// trait-property-name |
|
|
// scalar-expr |
|
|
// trait-property-name (trait-property-extension, ...)
|
|
//
|
|
struct OmpTraitPropertyExtension {
|
|
CharBlock source;
|
|
UNION_CLASS_BOILERPLATE(OmpTraitPropertyExtension);
|
|
struct Complex { // name (prop-ext, prop-ext, ...)
|
|
CharBlock source;
|
|
TUPLE_CLASS_BOILERPLATE(Complex);
|
|
std::tuple<OmpTraitPropertyName,
|
|
std::list<common::Indirection<OmpTraitPropertyExtension>>>
|
|
t;
|
|
};
|
|
|
|
std::variant<OmpTraitPropertyName, ScalarExpr, Complex> u;
|
|
};
|
|
|
|
// trait-property ->
|
|
// trait-property-name | OmpClause |
|
|
// trait-property-expression | trait-property-extension
|
|
// trait-property-expression ->
|
|
// scalar-logical-expression | scalar-integer-expression
|
|
//
|
|
// The parser for a logical expression will accept an integer expression,
|
|
// and if it's not logical, it will flag an error later. The same thing
|
|
// will happen if the scalar integer expression sees a logical expresion.
|
|
// To avoid this, parse all expressions as scalar expressions.
|
|
struct OmpTraitProperty {
|
|
CharBlock source;
|
|
UNION_CLASS_BOILERPLATE(OmpTraitProperty);
|
|
std::variant<OmpTraitPropertyName, common::Indirection<OmpClause>,
|
|
ScalarExpr, // trait-property-expresion
|
|
OmpTraitPropertyExtension>
|
|
u;
|
|
};
|
|
|
|
// trait-selector-name ->
|
|
// KIND | DT // name-list (host, nohost, +/add-def-doc)
|
|
// ISA | DT // name-list (isa_name, ... /impl-defined)
|
|
// ARCH | DT // name-list (arch_name, ... /impl-defined)
|
|
// directive-name | C // no properties
|
|
// SIMD | C // clause-list (from declare_simd)
|
|
// // (at least simdlen, inbranch/notinbranch)
|
|
// DEVICE_NUM | T // device-number
|
|
// UID | T // unique-string-id /impl-defined
|
|
// VENDOR | I // name-list (vendor-id /add-def-doc)
|
|
// EXTENSION | I // name-list (ext_name /impl-defined)
|
|
// ATOMIC_DEFAULT_MEM_ORDER I | // clause-list (value of admo)
|
|
// REQUIRES | I // clause-list (from requires)
|
|
// CONDITION U // logical-expr
|
|
// <other name> I // treated as extension
|
|
//
|
|
// Trait-set-selectors:
|
|
// [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser.
|
|
struct OmpTraitSelectorName {
|
|
std::string ToString() const;
|
|
CharBlock source;
|
|
UNION_CLASS_BOILERPLATE(OmpTraitSelectorName);
|
|
ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num,
|
|
Extension, Isa, Kind, Requires, Simd, Uid, Vendor)
|
|
std::variant<Value, llvm::omp::Directive, std::string> u;
|
|
};
|
|
|
|
// trait-selector ->
|
|
// trait-selector-name |
|
|
// trait-selector-name ([trait-score:] trait-property, ...)
|
|
struct OmpTraitSelector {
|
|
CharBlock source;
|
|
TUPLE_CLASS_BOILERPLATE(OmpTraitSelector);
|
|
struct Properties {
|
|
TUPLE_CLASS_BOILERPLATE(Properties);
|
|
std::tuple<std::optional<OmpTraitScore>, std::list<OmpTraitProperty>> t;
|
|
};
|
|
std::tuple<OmpTraitSelectorName, std::optional<Properties>> t;
|
|
};
|
|
|
|
// trait-set-selector-name ->
|
|
// CONSTRUCT | DEVICE | IMPLEMENTATION | USER | // since 5.0
|
|
// TARGET_DEVICE // since 5.1
|
|
struct OmpTraitSetSelectorName {
|
|
std::string ToString() const;
|
|
CharBlock source;
|
|
ENUM_CLASS(Value, Construct, Device, Implementation, Target_Device, User)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpTraitSetSelectorName, Value);
|
|
};
|
|
|
|
// trait-set-selector ->
|
|
// trait-set-selector-name = {trait-selector, ...}
|
|
struct OmpTraitSetSelector {
|
|
CharBlock source;
|
|
TUPLE_CLASS_BOILERPLATE(OmpTraitSetSelector);
|
|
std::tuple<OmpTraitSetSelectorName, std::list<OmpTraitSelector>> t;
|
|
};
|
|
|
|
// context-selector-specification ->
|
|
// trait-set-selector, ...
|
|
struct OmpContextSelectorSpecification { // Modifier
|
|
CharBlock source;
|
|
WRAPPER_CLASS_BOILERPLATE(
|
|
OmpContextSelectorSpecification, std::list<OmpTraitSetSelector>);
|
|
};
|
|
} // namespace traits
|
|
|
|
#define MODIFIER_BOILERPLATE(...) \
|
|
struct Modifier { \
|
|
using Variant = std::variant<__VA_ARGS__>; \
|
|
UNION_CLASS_BOILERPLATE(Modifier); \
|
|
CharBlock source; \
|
|
Variant u; \
|
|
}
|
|
|
|
#define MODIFIERS() std::optional<std::list<Modifier>>
|
|
|
|
inline namespace modifier {
|
|
// For uniformity, in all keyword modifiers the name of the type defined
|
|
// by ENUM_CLASS is "Value", e.g.
|
|
// struct Foo {
|
|
// ENUM_CLASS(Value, Keyword1, Keyword2);
|
|
// };
|
|
|
|
// Ref: [4.5:72-81], [5.0:110-119], [5.1:134-143], [5.2:169-170]
|
|
//
|
|
// alignment ->
|
|
// scalar-integer-expression // since 4.5
|
|
struct OmpAlignment {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAlignment, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [5.1:184-185], [5.2:178-179]
|
|
//
|
|
// align-modifier ->
|
|
// ALIGN(alignment) // since 5.1
|
|
struct OmpAlignModifier {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAlignModifier, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [5.0:158-159], [5.1:184-185], [5.2:178-179]
|
|
//
|
|
// allocator-simple-modifier ->
|
|
// allocator // since 5.0
|
|
struct OmpAllocatorSimpleModifier {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAllocatorSimpleModifier, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [5.1:184-185], [5.2:178-179]
|
|
//
|
|
// allocator-complex-modifier ->
|
|
// ALLOCATOR(allocator) // since 5.1
|
|
struct OmpAllocatorComplexModifier {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAllocatorComplexModifier, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [5.2:252-254]
|
|
//
|
|
// chunk-modifier ->
|
|
// SIMD // since 5.2
|
|
//
|
|
// Prior to 5.2 "chunk-modifier" was a part of "modifier" on SCHEDULE clause.
|
|
struct OmpChunkModifier {
|
|
ENUM_CLASS(Value, Simd)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpChunkModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69]
|
|
//
|
|
// iterator-specifier ->
|
|
// [iterator-type] iterator-identifier
|
|
// = range-specification | // since 5.0
|
|
// [iterator-type ::] iterator-identifier
|
|
// = range-specification // since 5.2
|
|
struct OmpIteratorSpecifier {
|
|
TUPLE_CLASS_BOILERPLATE(OmpIteratorSpecifier);
|
|
CharBlock source;
|
|
std::tuple<TypeDeclarationStmt, SubscriptTriplet> t;
|
|
};
|
|
|
|
// Ref: [4.5:169-170], [5.0:255-256], [5.1:288-289]
|
|
//
|
|
// dependence-type ->
|
|
// SINK | SOURCE | // since 4.5
|
|
// IN | OUT | INOUT | // since 4.5, until 5.1
|
|
// MUTEXINOUTSET | DEPOBJ | // since 5.0, until 5.1
|
|
// INOUTSET // since 5.1, until 5.1
|
|
//
|
|
// All of these, except SINK and SOURCE became task-dependence-type in 5.2.
|
|
//
|
|
// Keeping these two as separate types, since having them all together
|
|
// creates conflicts when parsing the DEPEND clause. For DEPEND(SINK: ...),
|
|
// the SINK may be parsed as 'task-dependence-type', and the list after
|
|
// the ':' would then be parsed as OmpObjectList (instead of the iteration
|
|
// vector). This would accept the vector "i, j, k" (although interpreted
|
|
// incorrectly), while flagging a syntax error for "i+1, j, k".
|
|
struct OmpDependenceType {
|
|
ENUM_CLASS(Value, Sink, Source);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Value);
|
|
};
|
|
|
|
// Ref: [5.0:170-176], [5.1:197-205], [5.2:276-277]
|
|
//
|
|
// device-modifier ->
|
|
// ANCESTOR | DEVICE_NUM // since 5.0
|
|
struct OmpDeviceModifier {
|
|
ENUM_CLASS(Value, Ancestor, Device_Num)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDeviceModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.2:72-73,230-323], in 4.5-5.1 it's scattered over individual
|
|
// directives that allow the IF clause.
|
|
//
|
|
// directive-name-modifier ->
|
|
// PARALLEL | TARGET | TARGET DATA |
|
|
// TARGET ENTER DATA | TARGET EXIT DATA |
|
|
// TARGET UPDATE | TASK | TASKLOOP | // since 4.5
|
|
// CANCEL[*] | SIMD | // since 5.0
|
|
// TEAMS // since 5.2
|
|
//
|
|
// [*] The IF clause is allowed on CANCEL in OpenMP 4.5, but only without
|
|
// the directive-name-modifier. For the sake of uniformity CANCEL can be
|
|
// considered a valid value in 4.5 as well.
|
|
using OmpDirectiveNameModifier = OmpDirectiveName;
|
|
|
|
// Ref: [5.1:205-209], [5.2:166-168]
|
|
//
|
|
// motion-modifier ->
|
|
// PRESENT | // since 5.0, until 5.0
|
|
// mapper | iterator
|
|
// expectation ->
|
|
// PRESENT // since 5.1
|
|
//
|
|
// The PRESENT value was a part of motion-modifier in 5.1, and became a
|
|
// value of expectation in 5.2.
|
|
struct OmpExpectation {
|
|
ENUM_CLASS(Value, Present);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpExpectation, Value);
|
|
};
|
|
|
|
// Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69]
|
|
//
|
|
// iterator-modifier ->
|
|
// ITERATOR(iterator-specifier [, ...]) // since 5.0
|
|
struct OmpIterator {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpIterator, std::list<OmpIteratorSpecifier>);
|
|
};
|
|
|
|
// Ref: [5.0:288-290], [5.1:321-322], [5.2:115-117]
|
|
//
|
|
// lastprivate-modifier ->
|
|
// CONDITIONAL // since 5.0
|
|
struct OmpLastprivateModifier {
|
|
ENUM_CLASS(Value, Conditional)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpLastprivateModifier, Value);
|
|
};
|
|
|
|
// Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
|
|
//
|
|
// linear-modifier ->
|
|
// REF | UVAL | VAL // since 4.5
|
|
struct OmpLinearModifier {
|
|
ENUM_CLASS(Value, Ref, Uval, Val);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpLinearModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.0:176-180], [5.1:205-210], [5.2:149-150]
|
|
//
|
|
// mapper ->
|
|
// identifier // since 4.5
|
|
struct OmpMapper {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpMapper, Name);
|
|
};
|
|
|
|
// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
|
|
//
|
|
// map-type ->
|
|
// ALLOC | DELETE | FROM | RELEASE | TO | TOFROM // since 4.5
|
|
struct OmpMapType {
|
|
ENUM_CLASS(Value, Alloc, Delete, From, Release, To, Tofrom);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpMapType, Value);
|
|
};
|
|
|
|
// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
|
|
//
|
|
// map-type-modifier ->
|
|
// ALWAYS | // since 4.5
|
|
// CLOSE | // since 5.0
|
|
// PRESENT // since 5.1
|
|
struct OmpMapTypeModifier {
|
|
ENUM_CLASS(Value, Always, Close, Present, Ompx_Hold)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpMapTypeModifier, Value);
|
|
};
|
|
|
|
// Ref: [4.5:56-63], [5.0:101-109], [5.1:126-133], [5.2:252-254]
|
|
//
|
|
// modifier ->
|
|
// MONOTONIC | NONMONOTONIC | SIMD // since 4.5, until 5.1
|
|
// ordering-modifier ->
|
|
// MONOTONIC | NONMONOTONIC // since 5.2
|
|
//
|
|
// Until 5.1, the SCHEDULE clause accepted up to two instances of "modifier".
|
|
// Since 5.2 "modifier" was replaced with "ordering-modifier" and "chunk-
|
|
// modifier".
|
|
struct OmpOrderingModifier {
|
|
ENUM_CLASS(Value, Monotonic, Nonmonotonic, Simd)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpOrderingModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.1:125-126], [5.2:233-234]
|
|
//
|
|
// order-modifier ->
|
|
// REPRODUCIBLE | UNCONSTRAINED // since 5.1
|
|
struct OmpOrderModifier {
|
|
ENUM_CLASS(Value, Reproducible, Unconstrained)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpOrderModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.1:166-171], [5.2:269-270]
|
|
//
|
|
// prescriptiveness ->
|
|
// STRICT // since 5.1
|
|
struct OmpPrescriptiveness {
|
|
ENUM_CLASS(Value, Strict)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpPrescriptiveness, Value);
|
|
};
|
|
|
|
// Ref: [5.0:300-302], [5.1:332-334], [5.2:134-137]
|
|
//
|
|
// reduction-modifier ->
|
|
// DEFAULT | INSCAN | TASK // since 5.0
|
|
struct OmpReductionModifier {
|
|
ENUM_CLASS(Value, Default, Inscan, Task);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpReductionModifier, Value);
|
|
};
|
|
|
|
// Ref: [5.2:117-120]
|
|
//
|
|
// step-complex-modifier ->
|
|
// STEP(integer-expression) // since 5.2
|
|
struct OmpStepComplexModifier {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpStepComplexModifier, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
|
|
//
|
|
// step-simple-modifier ->
|
|
// integer-expresion // since 4.5
|
|
struct OmpStepSimpleModifier {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpStepSimpleModifier, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [4.5:169-170], [5.0:254-256], [5.1:287-289], [5.2:321]
|
|
//
|
|
// task-dependence-type -> // "dependence-type" in 5.1 and before
|
|
// IN | OUT | INOUT | // since 4.5
|
|
// MUTEXINOUTSET | DEPOBJ | // since 5.0
|
|
// INOUTSET // since 5.2
|
|
struct OmpTaskDependenceType {
|
|
ENUM_CLASS(Value, In, Out, Inout, Inoutset, Mutexinoutset, Depobj)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Value);
|
|
};
|
|
|
|
// Ref: [4.5:229-230], [5.0:324-325], [5.1:357-358], [5.2:161-162]
|
|
//
|
|
// variable-category ->
|
|
// SCALAR | // since 4.5
|
|
// AGGREGATE | ALLOCATABLE | POINTER | // since 5.0
|
|
// ALL // since 5.2
|
|
struct OmpVariableCategory {
|
|
ENUM_CLASS(Value, Aggregate, All, Allocatable, Pointer, Scalar)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpVariableCategory, Value);
|
|
};
|
|
|
|
// context-selector
|
|
using OmpContextSelector = traits::OmpContextSelectorSpecification;
|
|
} // namespace modifier
|
|
|
|
// --- Clauses
|
|
|
|
using OmpDirectiveList = std::list<llvm::omp::Directive>;
|
|
|
|
// Ref: [5.2:214]
|
|
//
|
|
// absent-clause ->
|
|
// ABSENT(directive-name[, directive-name])
|
|
struct OmpAbsentClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAbsentClause, OmpDirectiveList);
|
|
};
|
|
|
|
// Ref: [5.0:135-140], [5.1:161-166], [5.2:264-265]
|
|
//
|
|
// affinity-clause ->
|
|
// AFFINITY([aff-modifier:] locator-list) // since 5.0
|
|
// aff-modifier ->
|
|
// interator-modifier // since 5.0
|
|
struct OmpAffinityClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAffinityClause);
|
|
MODIFIER_BOILERPLATE(OmpIterator);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// Ref: 5.2: [174]
|
|
struct OmpAlignClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAlignClause, ScalarIntExpr);
|
|
};
|
|
|
|
// Ref: [4.5:72-81], [5.0:110-119], [5.1:134-143], [5.2:169-170]
|
|
//
|
|
// aligned-clause ->
|
|
// ALIGNED(list [: alignment]) // since 4.5
|
|
struct OmpAlignedClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAlignedClause);
|
|
MODIFIER_BOILERPLATE(OmpAlignment);
|
|
std::tuple<OmpObjectList, MODIFIERS()> t;
|
|
};
|
|
|
|
// Ref: [5.0:158-159], [5.1:184-185], [5.2:178-179]
|
|
//
|
|
// allocate-clause ->
|
|
// ALLOCATE(
|
|
// [allocator-simple-modifier:] list) | // since 5.0
|
|
// ALLOCATE([modifier...:] list) // since 5.1
|
|
// modifier ->
|
|
// allocator-simple-modifier |
|
|
// allocator-complex-modifier | align-modifier // since 5.1
|
|
struct OmpAllocateClause {
|
|
MODIFIER_BOILERPLATE(OmpAlignModifier, OmpAllocatorSimpleModifier,
|
|
OmpAllocatorComplexModifier);
|
|
TUPLE_CLASS_BOILERPLATE(OmpAllocateClause);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// Ref: [5.2:216-217 (sort of, as it's only mentioned in passing)
|
|
// AT(compilation|execution)
|
|
struct OmpAtClause {
|
|
ENUM_CLASS(ActionTime, Compilation, Execution);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAtClause, ActionTime);
|
|
};
|
|
|
|
// Ref: [5.0:60-63], [5.1:83-86], [5.2:210-213]
|
|
//
|
|
// atomic-default-mem-order-clause ->
|
|
// ATOMIC_DEFAULT_MEM_ORDER(memory-order) // since 5.0
|
|
// memory-order ->
|
|
// SEQ_CST | ACQ_REL | RELAXED | // since 5.0
|
|
// ACQUIRE | RELEASE // since 5.2
|
|
struct OmpAtomicDefaultMemOrderClause {
|
|
using MemoryOrder = common::OmpAtomicDefaultMemOrderType;
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAtomicDefaultMemOrderClause, MemoryOrder);
|
|
};
|
|
|
|
// Ref: [5.0:128-131], [5.1:151-154], [5.2:258-259]
|
|
//
|
|
// bind-clause ->
|
|
// BIND(binding) // since 5.0
|
|
// binding ->
|
|
// TEAMS | PARALLEL | THREAD // since 5.0
|
|
struct OmpBindClause {
|
|
ENUM_CLASS(Binding, Parallel, Teams, Thread)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpBindClause, Binding);
|
|
};
|
|
|
|
// Artificial clause to represent a cancellable construct.
|
|
struct OmpCancellationConstructTypeClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpCancellationConstructTypeClause);
|
|
std::tuple<OmpDirectiveName, std::optional<ScalarLogicalExpr>> t;
|
|
};
|
|
|
|
// Ref: [5.2:214]
|
|
//
|
|
// contains-clause ->
|
|
// CONTAINS(directive-name[, directive-name])
|
|
struct OmpContainsClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpContainsClause, OmpDirectiveList);
|
|
};
|
|
|
|
// Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:109]
|
|
//
|
|
// When used as a data-sharing clause:
|
|
// default-clause ->
|
|
// DEFAULT(data-sharing-attribute) // since 4.5
|
|
// data-sharing-attribute ->
|
|
// SHARED | NONE | // since 4.5
|
|
// PRIVATE | FIRSTPRIVATE // since 5.0
|
|
//
|
|
// When used in METADIRECTIVE:
|
|
// default-clause ->
|
|
// DEFAULT(directive-specification) // since 5.0, until 5.1
|
|
// See also otherwise-clause.
|
|
struct OmpDefaultClause {
|
|
ENUM_CLASS(DataSharingAttribute, Private, Firstprivate, Shared, None)
|
|
UNION_CLASS_BOILERPLATE(OmpDefaultClause);
|
|
std::variant<DataSharingAttribute,
|
|
common::Indirection<OmpDirectiveSpecification>>
|
|
u;
|
|
};
|
|
|
|
// Ref: [4.5:103-107], [5.0:324-325], [5.1:357-358], [5.2:161-162]
|
|
//
|
|
// defaultmap-clause ->
|
|
// DEFAULTMAP(implicit-behavior
|
|
// [: variable-category]) // since 5.0
|
|
// implicit-behavior ->
|
|
// TOFROM | // since 4.5
|
|
// ALLOC | TO | FROM | FIRSTPRIVATE | NONE |
|
|
// DEFAULT | // since 5.0
|
|
// PRESENT // since 5.1
|
|
struct OmpDefaultmapClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpDefaultmapClause);
|
|
ENUM_CLASS(
|
|
ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None, Default)
|
|
MODIFIER_BOILERPLATE(OmpVariableCategory);
|
|
std::tuple<ImplicitBehavior, MODIFIERS()> t;
|
|
};
|
|
|
|
// Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
|
|
//
|
|
// iteration-offset ->
|
|
// +|- non-negative-constant // since 4.5
|
|
struct OmpIterationOffset {
|
|
TUPLE_CLASS_BOILERPLATE(OmpIterationOffset);
|
|
std::tuple<DefinedOperator, ScalarIntConstantExpr> t;
|
|
};
|
|
|
|
// Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
|
|
//
|
|
// iteration ->
|
|
// induction-variable [iteration-offset] // since 4.5
|
|
struct OmpIteration {
|
|
TUPLE_CLASS_BOILERPLATE(OmpIteration);
|
|
std::tuple<Name, std::optional<OmpIterationOffset>> t;
|
|
};
|
|
|
|
// Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:91-93]
|
|
//
|
|
// iteration-vector ->
|
|
// [iteration...] // since 4.5
|
|
WRAPPER_CLASS(OmpIterationVector, std::list<OmpIteration>);
|
|
|
|
// Extract this into a separate structure (instead of having it directly in
|
|
// OmpDoacrossClause), so that the context in TYPE_CONTEXT_PARSER can be set
|
|
// separately for OmpDependClause and OmpDoacrossClause.
|
|
//
|
|
// See: depend-clause, doacross-clause
|
|
struct OmpDoacross {
|
|
OmpDependenceType::Value GetDepType() const;
|
|
|
|
WRAPPER_CLASS(Sink, OmpIterationVector);
|
|
EMPTY_CLASS(Source);
|
|
UNION_CLASS_BOILERPLATE(OmpDoacross);
|
|
std::variant<Sink, Source> u;
|
|
};
|
|
|
|
// Ref: [4.5:169-172], [5.0:255-259], [5.1:288-292], [5.2:323-326]
|
|
//
|
|
// depend-clause ->
|
|
// DEPEND(SOURCE) | // since 4.5, until 5.1
|
|
// DEPEND(SINK: iteration-vector) | // since 4.5, until 5.1
|
|
// DEPEND([depend-modifier,]
|
|
// task-dependence-type: locator-list) // since 4.5
|
|
//
|
|
// depend-modifier -> iterator-modifier // since 5.0
|
|
struct OmpDependClause {
|
|
UNION_CLASS_BOILERPLATE(OmpDependClause);
|
|
struct TaskDep {
|
|
OmpTaskDependenceType::Value GetTaskDepType() const;
|
|
TUPLE_CLASS_BOILERPLATE(TaskDep);
|
|
MODIFIER_BOILERPLATE(OmpIterator, OmpTaskDependenceType);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
std::variant<TaskDep, OmpDoacross> u;
|
|
};
|
|
|
|
// Ref: [5.2:326-328]
|
|
//
|
|
// doacross-clause ->
|
|
// DOACROSS(dependence-type: iteration-vector) // since 5.2
|
|
WRAPPER_CLASS(OmpDoacrossClause, OmpDoacross);
|
|
|
|
// Ref: [5.0:254-255], [5.1:287-288], [5.2:73]
|
|
//
|
|
// destroy-clause ->
|
|
// DESTROY | // since 5.0, until 5.1
|
|
// DESTROY(variable) // since 5.2
|
|
WRAPPER_CLASS(OmpDestroyClause, OmpObject);
|
|
|
|
// Ref: [5.0:135-140], [5.1:161-166], [5.2:265-266]
|
|
//
|
|
// detach-clause ->
|
|
// DETACH(event-handle) // since 5.0
|
|
struct OmpDetachClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDetachClause, OmpObject);
|
|
};
|
|
|
|
// Ref: [4.5:103-107], [5.0:170-176], [5.1:197-205], [5.2:276-277]
|
|
//
|
|
// device-clause ->
|
|
// DEVICE(scalar-integer-expression) | // since 4.5
|
|
// DEVICE([device-modifier:]
|
|
// scalar-integer-expression) // since 5.0
|
|
struct OmpDeviceClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpDeviceClause);
|
|
MODIFIER_BOILERPLATE(OmpDeviceModifier);
|
|
std::tuple<MODIFIERS(), ScalarIntExpr> t;
|
|
};
|
|
|
|
// Ref: [5.0:180-185], [5.1:210-216], [5.2:275]
|
|
//
|
|
// device-type-clause ->
|
|
// DEVICE_TYPE(ANY | HOST | NOHOST) // since 5.0
|
|
struct OmpDeviceTypeClause {
|
|
ENUM_CLASS(DeviceTypeDescription, Any, Host, Nohost)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, DeviceTypeDescription);
|
|
};
|
|
|
|
// OMP 5.2 15.8.3 extended-atomic, fail-clause ->
|
|
// FAIL(memory-order)
|
|
struct OmpFailClause {
|
|
WRAPPER_CLASS_BOILERPLATE(
|
|
OmpFailClause, common::Indirection<OmpMemoryOrderClause>);
|
|
CharBlock source;
|
|
};
|
|
|
|
// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
|
|
//
|
|
// from-clause ->
|
|
// FROM(locator-list) |
|
|
// FROM(mapper-modifier: locator-list) | // since 5.0
|
|
// FROM(motion-modifier[,] ...: locator-list) // since 5.1
|
|
// motion-modifier ->
|
|
// PRESENT | mapper-modifier | iterator-modifier
|
|
struct OmpFromClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpFromClause);
|
|
MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
|
|
std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
|
|
};
|
|
|
|
// Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:269]
|
|
//
|
|
// grainsize-clause ->
|
|
// GRAINSIZE(grain-size) | // since 4.5
|
|
// GRAINSIZE([prescriptiveness:] grain-size) // since 5.1
|
|
struct OmpGrainsizeClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
|
|
MODIFIER_BOILERPLATE(OmpPrescriptiveness);
|
|
std::tuple<MODIFIERS(), ScalarIntExpr> t;
|
|
};
|
|
|
|
// Ref: [5.2: 214]
|
|
//
|
|
// holds-clause ->
|
|
// HOLDS(expr)
|
|
struct OmpHoldsClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpHoldsClause, common::Indirection<Expr>);
|
|
};
|
|
|
|
// Ref: [5.2:72-73], in 4.5-5.1 it's scattered over individual directives
|
|
// that allow the IF clause.
|
|
//
|
|
// if-clause ->
|
|
// IF([directive-name-modifier:]
|
|
// scalar-logical-expression) // since 4.5
|
|
struct OmpIfClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpIfClause);
|
|
MODIFIER_BOILERPLATE(OmpDirectiveNameModifier);
|
|
std::tuple<MODIFIERS(), ScalarLogicalExpr> t;
|
|
};
|
|
|
|
// Ref: [5.0:170-176], [5.1:197-205], [5.2:138-139]
|
|
//
|
|
// in-reduction-clause ->
|
|
// IN_REDUCTION(reduction-identifier: list) // since 5.0
|
|
struct OmpInReductionClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpInReductionClause);
|
|
MODIFIER_BOILERPLATE(OmpReductionIdentifier);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// declare-reduction -> DECLARE REDUCTION (reduction-identifier : type-list
|
|
// : combiner) [initializer-clause]
|
|
struct OmpInitializerProc {
|
|
TUPLE_CLASS_BOILERPLATE(OmpInitializerProc);
|
|
std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
|
|
};
|
|
WRAPPER_CLASS(OmpInitializerExpr, Expr);
|
|
|
|
// Initialization for declare reduction construct
|
|
struct OmpInitializerClause {
|
|
UNION_CLASS_BOILERPLATE(OmpInitializerClause);
|
|
std::variant<OmpInitializerProc, OmpInitializerExpr> u;
|
|
};
|
|
|
|
// Ref: [4.5:199-201], [5.0:288-290], [5.1:321-322], [5.2:115-117]
|
|
//
|
|
// lastprivate-clause ->
|
|
// LASTPRIVATE(list) | // since 4.5
|
|
// LASTPRIVATE([lastprivate-modifier:] list) // since 5.0
|
|
struct OmpLastprivateClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause);
|
|
MODIFIER_BOILERPLATE(OmpLastprivateModifier);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
|
|
//
|
|
// linear-clause ->
|
|
// LINEAR(list [: step-simple-modifier]) | // since 4.5
|
|
// LINEAR(linear-modifier(list)
|
|
// [: step-simple-modifier]) | // since 4.5, until 5.2[*]
|
|
// LINEAR(list [: linear-modifier,
|
|
// step-complex-modifier]) // since 5.2
|
|
// [*] Still allowed in 5.2 when on DECLARE SIMD, but deprecated.
|
|
struct OmpLinearClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpLinearClause);
|
|
MODIFIER_BOILERPLATE(
|
|
OmpLinearModifier, OmpStepSimpleModifier, OmpStepComplexModifier);
|
|
std::tuple<OmpObjectList, MODIFIERS(), /*PostModified=*/bool> t;
|
|
};
|
|
|
|
// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
|
|
//
|
|
// map-clause ->
|
|
// MAP([modifier...:] locator-list) // since 4.5
|
|
// modifier ->
|
|
// map-type-modifier | // since 4.5
|
|
// mapper | // since 5.0
|
|
// iterator | // since 5.1
|
|
// map-type // since 4.5
|
|
struct OmpMapClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpMapClause);
|
|
MODIFIER_BOILERPLATE(OmpMapTypeModifier, OmpMapper, OmpIterator, OmpMapType);
|
|
std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
|
|
};
|
|
|
|
// Ref: [5.0:58-60], [5.1:63-68], [5.2:194-195]
|
|
//
|
|
// match-clause ->
|
|
// MATCH (context-selector-specification) // since 5.0
|
|
struct OmpMatchClause {
|
|
// The context-selector is an argument.
|
|
WRAPPER_CLASS_BOILERPLATE(
|
|
OmpMatchClause, traits::OmpContextSelectorSpecification);
|
|
};
|
|
|
|
// Ref: [5.2:217-218]
|
|
// message-clause ->
|
|
// MESSAGE("message-text")
|
|
struct OmpMessageClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpMessageClause, Expr);
|
|
};
|
|
|
|
// Ref: [5.2: 214]
|
|
//
|
|
// no_openmp_clause -> NO_OPENMP
|
|
EMPTY_CLASS(OmpNoOpenMPClause);
|
|
|
|
// Ref: [5.2: 214]
|
|
//
|
|
// no_openmp_routines_clause -> NO_OPENMP_ROUTINES
|
|
EMPTY_CLASS(OmpNoOpenMPRoutinesClause);
|
|
|
|
// Ref: [5.2: 214]
|
|
//
|
|
// no_parallelism_clause -> NO_PARALELISM
|
|
EMPTY_CLASS(OmpNoParallelismClause);
|
|
|
|
// Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:270]
|
|
//
|
|
// num-tasks-clause ->
|
|
// NUM_TASKS(num-tasks) | // since 4.5
|
|
// NUM_TASKS([prescriptiveness:] num-tasks) // since 5.1
|
|
struct OmpNumTasksClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause);
|
|
MODIFIER_BOILERPLATE(OmpPrescriptiveness);
|
|
std::tuple<MODIFIERS(), ScalarIntExpr> t;
|
|
};
|
|
|
|
// Ref: [5.0:101-109], [5.1:126-134], [5.2:233-234]
|
|
//
|
|
// order-clause ->
|
|
// ORDER(CONCURRENT) | // since 5.0
|
|
// ORDER([order-modifier:] CONCURRENT) // since 5.1
|
|
struct OmpOrderClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpOrderClause);
|
|
ENUM_CLASS(Ordering, Concurrent)
|
|
MODIFIER_BOILERPLATE(OmpOrderModifier);
|
|
std::tuple<MODIFIERS(), Ordering> t;
|
|
};
|
|
|
|
// Ref: [5.0:56-57], [5.1:60-62], [5.2:191]
|
|
//
|
|
// otherwise-clause ->
|
|
// DEFAULT ([directive-specification]) // since 5.0, until 5.1
|
|
// otherwise-clause ->
|
|
// OTHERWISE ([directive-specification])] // since 5.2
|
|
struct OmpOtherwiseClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpOtherwiseClause,
|
|
std::optional<common::Indirection<OmpDirectiveSpecification>>);
|
|
};
|
|
|
|
// Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:229-230]
|
|
//
|
|
// proc-bind-clause ->
|
|
// PROC_BIND(affinity-policy) // since 4.5
|
|
// affinity-policy ->
|
|
// CLOSE | PRIMARY | SPREAD | // since 4.5
|
|
// MASTER // since 4.5, until 5.2
|
|
struct OmpProcBindClause {
|
|
ENUM_CLASS(AffinityPolicy, Close, Master, Spread, Primary)
|
|
WRAPPER_CLASS_BOILERPLATE(OmpProcBindClause, AffinityPolicy);
|
|
};
|
|
|
|
// Ref: [4.5:201-207], [5.0:300-302], [5.1:332-334], [5.2:134-137]
|
|
//
|
|
// reduction-clause ->
|
|
// REDUCTION(reduction-identifier: list) | // since 4.5
|
|
// REDUCTION([reduction-modifier,]
|
|
// reduction-identifier: list) // since 5.0
|
|
struct OmpReductionClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpReductionClause);
|
|
MODIFIER_BOILERPLATE(OmpReductionModifier, OmpReductionIdentifier);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// Ref: [4.5:56-63], [5.0:101-109], [5.1:126-133], [5.2:252-254]
|
|
//
|
|
// schedule-clause ->
|
|
// SCHEDULE([modifier[, modifier]:]
|
|
// kind[, chunk-size]) // since 4.5, until 5.1
|
|
// schedule-clause ->
|
|
// SCHEDULE([ordering-modifier], chunk-modifier],
|
|
// kind[, chunk_size]) // since 5.2
|
|
struct OmpScheduleClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpScheduleClause);
|
|
ENUM_CLASS(Kind, Static, Dynamic, Guided, Auto, Runtime)
|
|
MODIFIER_BOILERPLATE(OmpOrderingModifier, OmpChunkModifier);
|
|
std::tuple<MODIFIERS(), Kind, std::optional<ScalarIntExpr>> t;
|
|
};
|
|
|
|
// REF: [5.2:217]
|
|
// severity-clause ->
|
|
// SEVERITY(warning|fatal)
|
|
struct OmpSeverityClause {
|
|
ENUM_CLASS(Severity, Fatal, Warning);
|
|
WRAPPER_CLASS_BOILERPLATE(OmpSeverityClause, Severity);
|
|
};
|
|
|
|
// Ref: [5.0:232-234], [5.1:264-266], [5.2:137]
|
|
//
|
|
// task-reduction-clause ->
|
|
// TASK_REDUCTION(reduction-identifier: list) // since 5.0
|
|
struct OmpTaskReductionClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpTaskReductionClause);
|
|
MODIFIER_BOILERPLATE(OmpReductionIdentifier);
|
|
std::tuple<MODIFIERS(), OmpObjectList> t;
|
|
};
|
|
|
|
// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
|
|
//
|
|
// to-clause (in DECLARE TARGET) ->
|
|
// TO(extended-list) | // until 5.1
|
|
// to-clause (in TARGET UPDATE) ->
|
|
// TO(locator-list) |
|
|
// TO(mapper-modifier: locator-list) | // since 5.0
|
|
// TO(motion-modifier[,] ...: locator-list) // since 5.1
|
|
// motion-modifier ->
|
|
// PRESENT | mapper-modifier | iterator-modifier
|
|
struct OmpToClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpToClause);
|
|
MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
|
|
std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
|
|
};
|
|
|
|
// Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322]
|
|
//
|
|
// update-clause ->
|
|
// UPDATE(dependence-type) // since 5.0, until 5.1
|
|
// update-clause ->
|
|
// UPDATE(task-dependence-type) // since 5.2
|
|
struct OmpUpdateClause {
|
|
UNION_CLASS_BOILERPLATE(OmpUpdateClause);
|
|
// The dependence type is an argument here, not a modifier.
|
|
std::variant<OmpDependenceType, OmpTaskDependenceType> u;
|
|
};
|
|
|
|
// Ref: [5.0:56-57], [5.1:60-62], [5.2:190-191]
|
|
//
|
|
// when-clause ->
|
|
// WHEN (context-selector :
|
|
// [directive-specification]) // since 5.0
|
|
struct OmpWhenClause {
|
|
TUPLE_CLASS_BOILERPLATE(OmpWhenClause);
|
|
MODIFIER_BOILERPLATE(OmpContextSelector);
|
|
std::tuple<MODIFIERS(),
|
|
std::optional<common::Indirection<OmpDirectiveSpecification>>>
|
|
t;
|
|
};
|
|
|
|
// OpenMP Clauses
|
|
struct OmpClause {
|
|
UNION_CLASS_BOILERPLATE(OmpClause);
|
|
llvm::omp::Clause Id() const;
|
|
|
|
#define GEN_FLANG_CLAUSE_PARSER_CLASSES
|
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
|
|
|
CharBlock source;
|
|
|
|
std::variant<
|
|
#define GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST
|
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
|
>
|
|
u;
|
|
};
|
|
|
|
struct OmpClauseList {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpClauseList, std::list<OmpClause>);
|
|
CharBlock source;
|
|
};
|
|
|
|
// --- Directives and constructs
|
|
|
|
struct OmpDirectiveSpecification {
|
|
ENUM_CLASS(Flags, None, DeprecatedSyntax);
|
|
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
|
|
llvm::omp::Directive DirId() const { //
|
|
return std::get<OmpDirectiveName>(t).v;
|
|
}
|
|
const OmpClauseList &Clauses() const;
|
|
|
|
CharBlock source;
|
|
std::tuple<OmpDirectiveName, std::optional<std::list<OmpArgument>>,
|
|
std::optional<OmpClauseList>, Flags>
|
|
t;
|
|
};
|
|
|
|
struct OmpMetadirectiveDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpMetadirectiveDirective);
|
|
std::tuple<OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
// Ref: [5.1:89-90], [5.2:216]
|
|
//
|
|
// nothing-directive ->
|
|
// NOTHING // since 5.1
|
|
struct OmpNothingDirective {
|
|
using EmptyTrait = std::true_type;
|
|
COPY_AND_ASSIGN_BOILERPLATE(OmpNothingDirective);
|
|
CharBlock source;
|
|
};
|
|
|
|
// Ref: OpenMP [5.2:216-218]
|
|
// ERROR AT(compilation|execution) SEVERITY(fatal|warning) MESSAGE("msg-str)
|
|
struct OmpErrorDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpErrorDirective);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
};
|
|
|
|
struct OpenMPUtilityConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenMPUtilityConstruct);
|
|
CharBlock source;
|
|
std::variant<OmpErrorDirective, OmpNothingDirective> u;
|
|
};
|
|
|
|
// Ref: [5.2: 213-216]
|
|
//
|
|
// assumes-construct ->
|
|
// ASSUMES absent-clause | contains-clause | holds-clause | no-openmp-clause |
|
|
// no-openmp-routines-clause | no-parallelism-clause
|
|
struct OpenMPDeclarativeAssumes {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclarativeAssumes);
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpAssumeDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAssumeDirective);
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpEndAssumeDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpEndAssumeDirective, Verbatim);
|
|
CharBlock source;
|
|
};
|
|
|
|
// Ref: [5.2: 213-216]
|
|
//
|
|
// assume-construct ->
|
|
// ASSUME absent-clause | contains-clause | holds_clause | no-openmp-clause
|
|
// no-openmp-routines-clause | no-parallelism-clause
|
|
// block
|
|
// [END ASSUME]
|
|
struct OpenMPAssumeConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPAssumeConstruct);
|
|
std::tuple<OmpAssumeDirective, Block, std::optional<OmpEndAssumeDirective>> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
// 2.7.2 SECTIONS
|
|
// 2.11.2 PARALLEL SECTIONS
|
|
struct OmpSectionsDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpSectionsDirective, llvm::omp::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpBeginSectionsDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpBeginSectionsDirective);
|
|
std::tuple<OmpSectionsDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
struct OmpEndSectionsDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpEndSectionsDirective);
|
|
std::tuple<OmpSectionsDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
// [!$omp section]
|
|
// structured-block
|
|
// [!$omp section
|
|
// structured-block]
|
|
// ...
|
|
struct OpenMPSectionConstruct {
|
|
WRAPPER_CLASS_BOILERPLATE(OpenMPSectionConstruct, Block);
|
|
CharBlock source;
|
|
};
|
|
|
|
// `OmpSectionBlocks` is a list of section constructs. The parser guarentees
|
|
// that the `OpenMPConstruct` here always encapsulates an
|
|
// `OpenMPSectionConstruct` and not any other OpenMP construct.
|
|
WRAPPER_CLASS(OmpSectionBlocks, std::list<OpenMPConstruct>);
|
|
|
|
struct OpenMPSectionsConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPSectionsConstruct);
|
|
std::tuple<OmpBeginSectionsDirective, OmpSectionBlocks,
|
|
OmpEndSectionsDirective>
|
|
t;
|
|
};
|
|
|
|
// OpenMP directive beginning or ending a block
|
|
struct OmpBlockDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpBlockDirective, llvm::omp::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
// 2.10.6 declare-target -> DECLARE TARGET (extended-list) |
|
|
// DECLARE TARGET [declare-target-clause[ [,]
|
|
// declare-target-clause]...]
|
|
struct OmpDeclareTargetWithList {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithList, OmpObjectList);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpDeclareTargetWithClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetWithClause, OmpClauseList);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpDeclareTargetSpecifier {
|
|
UNION_CLASS_BOILERPLATE(OmpDeclareTargetSpecifier);
|
|
std::variant<OmpDeclareTargetWithList, OmpDeclareTargetWithClause> u;
|
|
};
|
|
|
|
struct OpenMPDeclareTargetConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclareTargetConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpDeclareTargetSpecifier> t;
|
|
};
|
|
|
|
// OMP v5.2: 5.8.8
|
|
// declare-mapper -> DECLARE MAPPER ([mapper-name :] type :: var) map-clauses
|
|
struct OpenMPDeclareMapperConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclareMapperConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpMapperSpecifier, OmpClauseList> t;
|
|
};
|
|
|
|
// ref: 5.2: Section 5.5.11 139-141
|
|
// 2.16 declare-reduction -> DECLARE REDUCTION (reduction-identifier : type-list
|
|
// : combiner) [initializer-clause]
|
|
struct OpenMPDeclareReductionConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclareReductionConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, common::Indirection<OmpReductionSpecifier>,
|
|
std::optional<OmpClauseList>>
|
|
t;
|
|
};
|
|
|
|
// 2.8.2 declare-simd -> DECLARE SIMD [(proc-name)] [declare-simd-clause[ [,]
|
|
// declare-simd-clause]...]
|
|
struct OpenMPDeclareSimdConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclareSimdConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
|
|
};
|
|
|
|
// 2.4 requires -> REQUIRES requires-clause[ [ [,] requires-clause]...]
|
|
struct OpenMPRequiresConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPRequiresConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
};
|
|
|
|
// 2.15.2 threadprivate -> THREADPRIVATE (variable-name-list)
|
|
struct OpenMPThreadprivate {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPThreadprivate);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpObjectList> t;
|
|
};
|
|
|
|
// 2.11.3 allocate -> ALLOCATE (variable-name-list) [clause]
|
|
struct OpenMPDeclarativeAllocate {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDeclarativeAllocate);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpObjectList, OmpClauseList> t;
|
|
};
|
|
|
|
struct OpenMPDeclarativeConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenMPDeclarativeConstruct);
|
|
CharBlock source;
|
|
std::variant<OpenMPDeclarativeAllocate, OpenMPDeclarativeAssumes,
|
|
OpenMPDeclareMapperConstruct, OpenMPDeclareReductionConstruct,
|
|
OpenMPDeclareSimdConstruct, OpenMPDeclareTargetConstruct,
|
|
OpenMPThreadprivate, OpenMPRequiresConstruct, OpenMPUtilityConstruct,
|
|
OmpMetadirectiveDirective>
|
|
u;
|
|
};
|
|
|
|
// 2.13.2 CRITICAL [Name] <block> END CRITICAL [Name]
|
|
struct OmpCriticalDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpCriticalDirective);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
|
|
};
|
|
struct OmpEndCriticalDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpEndCriticalDirective);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<Name>> t;
|
|
};
|
|
struct OpenMPCriticalConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPCriticalConstruct);
|
|
std::tuple<OmpCriticalDirective, Block, OmpEndCriticalDirective> t;
|
|
};
|
|
|
|
// 2.11.3 allocate -> ALLOCATE [(variable-name-list)] [clause]
|
|
// [ALLOCATE (variable-name-list) [clause] [...]]
|
|
// allocate-statement
|
|
// clause -> allocator-clause
|
|
struct OpenMPExecutableAllocate {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPExecutableAllocate);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<OmpObjectList>, OmpClauseList,
|
|
std::optional<std::list<OpenMPDeclarativeAllocate>>,
|
|
Statement<AllocateStmt>>
|
|
t;
|
|
};
|
|
|
|
EMPTY_CLASS(OmpEndAllocators);
|
|
|
|
// 6.7 Allocators construct [OpenMP 5.2]
|
|
// allocators-construct -> ALLOCATORS [allocate-clause [,]]
|
|
// allocate-stmt
|
|
// [omp-end-allocators-construct]
|
|
struct OpenMPAllocatorsConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPAllocatorsConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList, Statement<AllocateStmt>,
|
|
std::optional<OmpEndAllocators>>
|
|
t;
|
|
};
|
|
|
|
// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0]
|
|
// memory-order-clause -> acq_rel
|
|
// release
|
|
// acquire
|
|
// seq_cst
|
|
// relaxed
|
|
struct OmpMemoryOrderClause {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause);
|
|
CharBlock source;
|
|
};
|
|
|
|
// 2.17.7 Atomic construct
|
|
// atomic-clause -> memory-order-clause | HINT(hint-expression) |
|
|
// FAIL(memory-order)
|
|
struct OmpAtomicClause {
|
|
UNION_CLASS_BOILERPLATE(OmpAtomicClause);
|
|
CharBlock source;
|
|
std::variant<OmpMemoryOrderClause, OmpFailClause, OmpClause> u;
|
|
};
|
|
|
|
// atomic-clause-list -> [atomic-clause, [atomic-clause], ...]
|
|
struct OmpAtomicClauseList {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list<OmpAtomicClause>);
|
|
CharBlock source;
|
|
};
|
|
|
|
// END ATOMIC
|
|
EMPTY_CLASS(OmpEndAtomic);
|
|
|
|
// ATOMIC READ
|
|
struct OmpAtomicRead {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomicRead);
|
|
CharBlock source;
|
|
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
|
|
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ATOMIC WRITE
|
|
struct OmpAtomicWrite {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite);
|
|
CharBlock source;
|
|
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
|
|
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ATOMIC UPDATE
|
|
struct OmpAtomicUpdate {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate);
|
|
CharBlock source;
|
|
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
|
|
Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ATOMIC CAPTURE
|
|
struct OmpAtomicCapture {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture);
|
|
CharBlock source;
|
|
WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
|
|
WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
|
|
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList, Stmt1, Stmt2,
|
|
OmpEndAtomic>
|
|
t;
|
|
};
|
|
|
|
struct OmpAtomicCompareIfStmt {
|
|
UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
|
|
std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
|
|
};
|
|
|
|
// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
|
|
struct OmpAtomicCompare {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
|
|
CharBlock source;
|
|
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
|
|
OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ATOMIC
|
|
struct OmpAtomic {
|
|
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpAtomicClauseList, Statement<AssignmentStmt>,
|
|
std::optional<OmpEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// 2.17.7 atomic ->
|
|
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
|
|
// ATOMIC [atomic-clause-list]
|
|
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
|
|
struct OpenMPAtomicConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
|
|
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
|
|
OmpAtomicCompare, OmpAtomic>
|
|
u;
|
|
};
|
|
|
|
// OpenMP directives that associate with loop(s)
|
|
struct OmpLoopDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpLoopDirective, llvm::omp::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
// 2.14.2 cancellation-point -> CANCELLATION POINT construct-type-clause
|
|
struct OpenMPCancellationPointConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPCancellationPointConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
};
|
|
|
|
// 2.14.1 cancel -> CANCEL construct-type-clause [ [,] if-clause]
|
|
struct OpenMPCancelConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
};
|
|
|
|
// Ref: [5.0:254-255], [5.1:287-288], [5.2:322-323]
|
|
//
|
|
// depobj-construct -> DEPOBJ(depend-object) depobj-clause // since 5.0
|
|
// depobj-clause -> depend-clause | // until 5.2
|
|
// destroy-clause |
|
|
// update-clause
|
|
struct OpenMPDepobjConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDepobjConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpObject, OmpClause> t;
|
|
};
|
|
|
|
// Ref: [5.2: 200-201]
|
|
//
|
|
// dispatch-construct -> DISPATCH dispatch-clause
|
|
// dispatch-clause -> depend-clause |
|
|
// device-clause |
|
|
// is_device_ptr-clause |
|
|
// nocontext-clause |
|
|
// novariants-clause |
|
|
// nowait-clause
|
|
struct OmpDispatchDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpDispatchDirective);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, OmpClauseList> t;
|
|
};
|
|
|
|
EMPTY_CLASS(OmpEndDispatchDirective);
|
|
|
|
struct OpenMPDispatchConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPDispatchConstruct);
|
|
CharBlock source;
|
|
std::tuple<OmpDispatchDirective, Block,
|
|
std::optional<OmpEndDispatchDirective>>
|
|
t;
|
|
};
|
|
|
|
// [4.5:162-165], [5.0:242-246], [5.1:275-279], [5.2:315-316], [6.0:498-500]
|
|
//
|
|
// flush-construct ->
|
|
// FLUSH [(list)] // since 4.5, until 4.5
|
|
// flush-construct ->
|
|
// FLUSH [memory-order-clause] [(list)] // since 5.0, until 5.1
|
|
// flush-construct ->
|
|
// FLUSH [(list)] [clause-list] // since 5.2
|
|
//
|
|
// memory-order-clause -> // since 5.0, until 5.1
|
|
// ACQ_REL | RELEASE | ACQUIRE | // since 5.0
|
|
// SEQ_CST // since 5.1
|
|
struct OpenMPFlushConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<OmpObjectList>,
|
|
std::optional<OmpClauseList>, /*TrailingClauses=*/bool>
|
|
t;
|
|
};
|
|
|
|
struct OmpSimpleStandaloneDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(OmpSimpleStandaloneDirective, llvm::omp::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenMPSimpleStandaloneConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPSimpleStandaloneConstruct);
|
|
CharBlock source;
|
|
std::tuple<OmpSimpleStandaloneDirective, OmpClauseList> t;
|
|
};
|
|
|
|
struct OpenMPStandaloneConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenMPStandaloneConstruct);
|
|
CharBlock source;
|
|
std::variant<OpenMPSimpleStandaloneConstruct, OpenMPFlushConstruct,
|
|
OpenMPCancelConstruct, OpenMPCancellationPointConstruct,
|
|
OpenMPDepobjConstruct, OmpMetadirectiveDirective>
|
|
u;
|
|
};
|
|
|
|
struct OmpBeginLoopDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpBeginLoopDirective);
|
|
std::tuple<OmpLoopDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpEndLoopDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpEndLoopDirective);
|
|
std::tuple<OmpLoopDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpBeginBlockDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpBeginBlockDirective);
|
|
std::tuple<OmpBlockDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OmpEndBlockDirective {
|
|
TUPLE_CLASS_BOILERPLATE(OmpEndBlockDirective);
|
|
std::tuple<OmpBlockDirective, OmpClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenMPBlockConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPBlockConstruct);
|
|
std::tuple<OmpBeginBlockDirective, Block, OmpEndBlockDirective> t;
|
|
};
|
|
|
|
// OpenMP directives enclosing do loop
|
|
struct OpenMPLoopConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenMPLoopConstruct);
|
|
OpenMPLoopConstruct(OmpBeginLoopDirective &&a)
|
|
: t({std::move(a), std::nullopt, std::nullopt}) {}
|
|
std::tuple<OmpBeginLoopDirective, std::optional<DoConstruct>,
|
|
std::optional<OmpEndLoopDirective>>
|
|
t;
|
|
};
|
|
|
|
struct OpenMPConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenMPConstruct);
|
|
std::variant<OpenMPStandaloneConstruct, OpenMPSectionsConstruct,
|
|
OpenMPSectionConstruct, OpenMPLoopConstruct, OpenMPBlockConstruct,
|
|
OpenMPAtomicConstruct, OpenMPDeclarativeAllocate, OpenMPDispatchConstruct,
|
|
OpenMPUtilityConstruct, OpenMPExecutableAllocate,
|
|
OpenMPAllocatorsConstruct, OpenMPAssumeConstruct, OpenMPCriticalConstruct>
|
|
u;
|
|
};
|
|
|
|
// Parse tree nodes for OpenACC 3.3 directives and clauses
|
|
|
|
struct AccObject {
|
|
UNION_CLASS_BOILERPLATE(AccObject);
|
|
std::variant<Designator, /*common block*/ Name> u;
|
|
};
|
|
|
|
WRAPPER_CLASS(AccObjectList, std::list<AccObject>);
|
|
|
|
// OpenACC directive beginning or ending a block
|
|
struct AccBlockDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccBlockDirective, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccLoopDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccLoopDirective, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccStandaloneDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccStandaloneDirective, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
// 2.11 Combined constructs
|
|
struct AccCombinedDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccCombinedDirective, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccDeclarativeDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccDeclarativeDirective, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
// OpenACC Clauses
|
|
struct AccBindClause {
|
|
UNION_CLASS_BOILERPLATE(AccBindClause);
|
|
std::variant<Name, ScalarDefaultCharExpr> u;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccDefaultClause {
|
|
WRAPPER_CLASS_BOILERPLATE(AccDefaultClause, llvm::acc::DefaultValue);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccDataModifier {
|
|
ENUM_CLASS(Modifier, ReadOnly, Zero)
|
|
WRAPPER_CLASS_BOILERPLATE(AccDataModifier, Modifier);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccObjectListWithModifier {
|
|
TUPLE_CLASS_BOILERPLATE(AccObjectListWithModifier);
|
|
std::tuple<std::optional<AccDataModifier>, AccObjectList> t;
|
|
};
|
|
|
|
struct AccObjectListWithReduction {
|
|
TUPLE_CLASS_BOILERPLATE(AccObjectListWithReduction);
|
|
std::tuple<ReductionOperator, AccObjectList> t;
|
|
};
|
|
|
|
struct AccWaitArgument {
|
|
TUPLE_CLASS_BOILERPLATE(AccWaitArgument);
|
|
std::tuple<std::optional<ScalarIntExpr>, std::list<ScalarIntExpr>> t;
|
|
};
|
|
|
|
struct AccDeviceTypeExpr {
|
|
WRAPPER_CLASS_BOILERPLATE(
|
|
AccDeviceTypeExpr, Fortran::common::OpenACCDeviceType);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccDeviceTypeExprList {
|
|
WRAPPER_CLASS_BOILERPLATE(
|
|
AccDeviceTypeExprList, std::list<AccDeviceTypeExpr>);
|
|
};
|
|
|
|
struct AccTileExpr {
|
|
TUPLE_CLASS_BOILERPLATE(AccTileExpr);
|
|
CharBlock source;
|
|
std::tuple<std::optional<ScalarIntConstantExpr>> t; // if null then *
|
|
};
|
|
|
|
struct AccTileExprList {
|
|
WRAPPER_CLASS_BOILERPLATE(AccTileExprList, std::list<AccTileExpr>);
|
|
};
|
|
|
|
struct AccSizeExpr {
|
|
WRAPPER_CLASS_BOILERPLATE(AccSizeExpr, std::optional<ScalarIntExpr>);
|
|
};
|
|
|
|
struct AccSizeExprList {
|
|
WRAPPER_CLASS_BOILERPLATE(AccSizeExprList, std::list<AccSizeExpr>);
|
|
};
|
|
|
|
struct AccSelfClause {
|
|
UNION_CLASS_BOILERPLATE(AccSelfClause);
|
|
std::variant<std::optional<ScalarLogicalExpr>, AccObjectList> u;
|
|
CharBlock source;
|
|
};
|
|
|
|
// num, dim, static
|
|
struct AccGangArg {
|
|
UNION_CLASS_BOILERPLATE(AccGangArg);
|
|
WRAPPER_CLASS(Num, ScalarIntExpr);
|
|
WRAPPER_CLASS(Dim, ScalarIntExpr);
|
|
WRAPPER_CLASS(Static, AccSizeExpr);
|
|
std::variant<Num, Dim, Static> u;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccGangArgList {
|
|
WRAPPER_CLASS_BOILERPLATE(AccGangArgList, std::list<AccGangArg>);
|
|
};
|
|
|
|
struct AccCollapseArg {
|
|
TUPLE_CLASS_BOILERPLATE(AccCollapseArg);
|
|
std::tuple<bool, ScalarIntConstantExpr> t;
|
|
};
|
|
|
|
struct AccClause {
|
|
UNION_CLASS_BOILERPLATE(AccClause);
|
|
|
|
#define GEN_FLANG_CLAUSE_PARSER_CLASSES
|
|
#include "llvm/Frontend/OpenACC/ACC.inc"
|
|
|
|
CharBlock source;
|
|
|
|
std::variant<
|
|
#define GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST
|
|
#include "llvm/Frontend/OpenACC/ACC.inc"
|
|
>
|
|
u;
|
|
};
|
|
|
|
struct AccClauseList {
|
|
WRAPPER_CLASS_BOILERPLATE(AccClauseList, std::list<AccClause>);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenACCRoutineConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCRoutineConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<Name>, AccClauseList> t;
|
|
};
|
|
|
|
struct OpenACCCacheConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCCacheConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, AccObjectListWithModifier> t;
|
|
};
|
|
|
|
struct OpenACCWaitConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCWaitConstruct);
|
|
CharBlock source;
|
|
std::tuple<Verbatim, std::optional<AccWaitArgument>, AccClauseList> t;
|
|
};
|
|
|
|
struct AccBeginLoopDirective {
|
|
TUPLE_CLASS_BOILERPLATE(AccBeginLoopDirective);
|
|
std::tuple<AccLoopDirective, AccClauseList> t;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct AccBeginBlockDirective {
|
|
TUPLE_CLASS_BOILERPLATE(AccBeginBlockDirective);
|
|
CharBlock source;
|
|
std::tuple<AccBlockDirective, AccClauseList> t;
|
|
};
|
|
|
|
struct AccEndBlockDirective {
|
|
CharBlock source;
|
|
WRAPPER_CLASS_BOILERPLATE(AccEndBlockDirective, AccBlockDirective);
|
|
};
|
|
|
|
// ACC END ATOMIC
|
|
EMPTY_CLASS(AccEndAtomic);
|
|
|
|
// ACC ATOMIC READ
|
|
struct AccAtomicRead {
|
|
TUPLE_CLASS_BOILERPLATE(AccAtomicRead);
|
|
std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ACC ATOMIC WRITE
|
|
struct AccAtomicWrite {
|
|
TUPLE_CLASS_BOILERPLATE(AccAtomicWrite);
|
|
std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ACC ATOMIC UPDATE
|
|
struct AccAtomicUpdate {
|
|
TUPLE_CLASS_BOILERPLATE(AccAtomicUpdate);
|
|
std::tuple<std::optional<Verbatim>, Statement<AssignmentStmt>,
|
|
std::optional<AccEndAtomic>>
|
|
t;
|
|
};
|
|
|
|
// ACC ATOMIC CAPTURE
|
|
struct AccAtomicCapture {
|
|
TUPLE_CLASS_BOILERPLATE(AccAtomicCapture);
|
|
WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
|
|
WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
|
|
std::tuple<Verbatim, Stmt1, Stmt2, AccEndAtomic> t;
|
|
};
|
|
|
|
struct OpenACCAtomicConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenACCAtomicConstruct);
|
|
std::variant<AccAtomicRead, AccAtomicWrite, AccAtomicCapture, AccAtomicUpdate>
|
|
u;
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenACCBlockConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCBlockConstruct);
|
|
std::tuple<AccBeginBlockDirective, Block, AccEndBlockDirective> t;
|
|
};
|
|
|
|
struct OpenACCStandaloneDeclarativeConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneDeclarativeConstruct);
|
|
CharBlock source;
|
|
std::tuple<AccDeclarativeDirective, AccClauseList> t;
|
|
};
|
|
|
|
struct AccBeginCombinedDirective {
|
|
TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective);
|
|
CharBlock source;
|
|
std::tuple<AccCombinedDirective, AccClauseList> t;
|
|
};
|
|
|
|
struct AccEndCombinedDirective {
|
|
WRAPPER_CLASS_BOILERPLATE(AccEndCombinedDirective, AccCombinedDirective);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenACCCombinedConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct);
|
|
CharBlock source;
|
|
OpenACCCombinedConstruct(AccBeginCombinedDirective &&a)
|
|
: t({std::move(a), std::nullopt, std::nullopt}) {}
|
|
std::tuple<AccBeginCombinedDirective, std::optional<DoConstruct>,
|
|
std::optional<AccEndCombinedDirective>>
|
|
t;
|
|
};
|
|
|
|
struct OpenACCDeclarativeConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenACCDeclarativeConstruct);
|
|
CharBlock source;
|
|
std::variant<OpenACCStandaloneDeclarativeConstruct, OpenACCRoutineConstruct>
|
|
u;
|
|
};
|
|
|
|
// OpenACC directives enclosing do loop
|
|
EMPTY_CLASS(AccEndLoop);
|
|
struct OpenACCLoopConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct);
|
|
OpenACCLoopConstruct(AccBeginLoopDirective &&a)
|
|
: t({std::move(a), std::nullopt, std::nullopt}) {}
|
|
std::tuple<AccBeginLoopDirective, std::optional<DoConstruct>,
|
|
std::optional<AccEndLoop>>
|
|
t;
|
|
};
|
|
|
|
struct OpenACCEndConstruct {
|
|
WRAPPER_CLASS_BOILERPLATE(OpenACCEndConstruct, llvm::acc::Directive);
|
|
CharBlock source;
|
|
};
|
|
|
|
struct OpenACCStandaloneConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneConstruct);
|
|
CharBlock source;
|
|
std::tuple<AccStandaloneDirective, AccClauseList> t;
|
|
};
|
|
|
|
struct OpenACCConstruct {
|
|
UNION_CLASS_BOILERPLATE(OpenACCConstruct);
|
|
std::variant<OpenACCBlockConstruct, OpenACCCombinedConstruct,
|
|
OpenACCLoopConstruct, OpenACCStandaloneConstruct, OpenACCCacheConstruct,
|
|
OpenACCWaitConstruct, OpenACCAtomicConstruct, OpenACCEndConstruct>
|
|
u;
|
|
};
|
|
|
|
// CUF-kernel-do-construct ->
|
|
// !$CUF KERNEL DO [ (scalar-int-constant-expr) ]
|
|
// <<< grid, block [, stream] >>>
|
|
// [ cuf-reduction... ]
|
|
// do-construct
|
|
// star-or-expr -> * | scalar-int-expr
|
|
// grid -> * | scalar-int-expr | ( star-or-expr-list )
|
|
// block -> * | scalar-int-expr | ( star-or-expr-list )
|
|
// stream -> 0, scalar-int-expr | STREAM = scalar-int-expr
|
|
// cuf-reduction -> [ REDUCE | REDUCTION ] (
|
|
// reduction-op : scalar-variable-list )
|
|
|
|
struct CUFReduction {
|
|
TUPLE_CLASS_BOILERPLATE(CUFReduction);
|
|
using Operator = ReductionOperator;
|
|
std::tuple<Operator, std::list<Scalar<Variable>>> t;
|
|
};
|
|
|
|
struct CUFKernelDoConstruct {
|
|
TUPLE_CLASS_BOILERPLATE(CUFKernelDoConstruct);
|
|
WRAPPER_CLASS(StarOrExpr, std::optional<ScalarIntExpr>);
|
|
struct LaunchConfiguration {
|
|
TUPLE_CLASS_BOILERPLATE(LaunchConfiguration);
|
|
std::tuple<std::list<StarOrExpr>, std::list<StarOrExpr>,
|
|
std::optional<ScalarIntExpr>>
|
|
t;
|
|
};
|
|
struct Directive {
|
|
TUPLE_CLASS_BOILERPLATE(Directive);
|
|
CharBlock source;
|
|
std::tuple<std::optional<ScalarIntConstantExpr>,
|
|
std::optional<LaunchConfiguration>, std::list<CUFReduction>>
|
|
t;
|
|
};
|
|
std::tuple<Directive, std::optional<DoConstruct>> t;
|
|
};
|
|
|
|
} // namespace Fortran::parser
|
|
#endif // FORTRAN_PARSER_PARSE_TREE_H_
|