#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 "idioms.h" #include "indirection.h" #include "message.h" #include "provenance.h" #include #include #include #include #include #include #include #include // 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 move constructors and move assignments. CLASS_TRAIT(EmptyTrait); CLASS_TRAIT(WrapperTrait); CLASS_TRAIT(UnionTrait); CLASS_TRAIT(TupleTrait); // // An empty class to attach semantic information to each class in // the parse-tree. In practice, each parser-tree 'classname' shall // implement a member: // // Semantic * s = nullptr; // // The actual implementation of each Sema will be provided // later thus allowing the parser to be build without an dependency // with the Sema library // namespace Fortran { namespace semantics { class Symbol; template struct Semantic { Semantic(T *) {} }; } // namespace semantics } // namespace Fortran // 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; \ Fortran::semantics::Semantic *s = nullptr // 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; \ Fortran::semantics::Semantic *s = nullptr; \ } // Many classes below simply wrap a std::variant<> discriminated union, // which is conventionally named "u". #define UNION_CLASS_BOILERPLATE(classname) \ template 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 \ classname(Ts &&... args) : t(std::forward(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 { namespace 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 DataRef; // R911 struct StructureComponent; // R913 struct CoindexedNamedObject; // R914 struct TypeParamInquiry; // R916 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 SyncAllStmt; // R1164 struct SyncImagesStmt; // R1166 struct SyncMemoryStmt; // R1168 struct SyncTeamStmt; // R1169 struct EventPostStmt; // R1170, R1171 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 StructureDef; struct ArithmeticIfStmt; struct AssignStmt; struct AssignedGotoStmt; struct PauseStmt; // Cooked character stream locations using Location = const char *; // 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. // TODO: Implement as wrappers instead, or maybe remove. template struct Scalar { Scalar(Scalar &&that) = default; Scalar(A &&that) : thing(std::move(that)) {} Scalar &operator=(Scalar &&) = default; A thing; }; template struct Constant { Constant(Constant &&that) = default; Constant(A &&that) : thing(std::move(that)) {} Constant &operator=(Constant &&) = default; A thing; }; template struct Integer { Integer(Integer &&that) = default; Integer(A &&that) : thing(std::move(that)) {} Integer &operator=(Integer &&) = default; A thing; }; template struct Logical { Logical(Logical &&that) = default; Logical(A &&that) : thing(std::move(that)) {} Logical &operator=(Logical &&) = default; A thing; }; template struct DefaultChar { DefaultChar(DefaultChar &&that) = default; DefaultChar(A &&that) : thing(std::move(that)) {} DefaultChar &operator=(DefaultChar &&) = default; A thing; }; using LogicalExpr = Logical>; // R1024 using DefaultCharExpr = DefaultChar>; // R1025 using IntExpr = Integer>; // R1026 using ConstantExpr = Constant>; // R1029 using IntConstantExpr = Integer; // R1031 using ScalarLogicalExpr = Scalar; using ScalarIntExpr = Scalar; using ScalarIntConstantExpr = Scalar; using ScalarDefaultCharExpr = Scalar; // R1030 default-char-constant-expr is used in the Standard only as part of // scalar-default-char-constant-expr. using ScalarDefaultCharConstantExpr = Scalar>; // R611 label -> digit [digit]... using Label = std::uint64_t; // 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 struct Statement { Statement(std::optional &&lab, A &&s) : label(std::move(lab)), statement(std::move(s)) {} CharBlock source; std::optional