--- /dev/null
+#ifndef FORTRAN_FORMAT_SPECIFICATION_H_
+#define FORTRAN_FORMAT_SPECIFICATION_H_
+
+// Represent parses of Fortran format specifications from FORMAT statements
+// and character literals in formatted I/O statements at compilation time
+// as well as from character variables and expressions at run time.
+// From requirement productions R1302-R1321 of the Fortran 2018 draft
+// standard (q.v.), extended with Hollerith. These structures have been
+// isolated so that they may be used in the run-time without introducing
+// dependences on other parts of the compiler's source code.
+// TODO: support Q formatting extension?
+
+#include <cinttypes>
+#include <list>
+#include <optional>
+#include <string>
+#include <variant>
+
+namespace Fortran {
+
+// R1307 data-edit-desc (part 1 of 2) ->
+// I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d |
+// E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] |
+// G w [. d [E e]] | L w | A [w] | D w . d
+// R1308 w -> digit-string
+// R1309 m -> digit-string
+// R1310 d -> digit-string
+// R1311 e -> digit-string
+struct IntrinsicTypeDataEditDesc {
+ enum class Kind { I, B, O, Z, F, E, EN, ES, EX, G, L, A, D };
+ IntrinsicTypeDataEditDesc() = delete;
+ IntrinsicTypeDataEditDesc(IntrinsicTypeDataEditDesc &&) = default;
+ IntrinsicTypeDataEditDesc &operator=(IntrinsicTypeDataEditDesc &&) = default;
+ IntrinsicTypeDataEditDesc(Kind &&k, std::optional<int> &&w,
+ std::optional<int> &&d, std::optional<int> &&e)
+ : kind{k}, width{std::move(w)}, digits{std::move(d)},
+ exponentWidth{std::move(e)} {}
+ Kind kind;
+ std::optional<int> width; // w
+ std::optional<int> digits; // m or d
+ std::optional<int> exponentWidth; // e
+};
+
+// R1307 data-edit-desc (part 2 of 2) ->
+// DT [char-literal-constant] [( v-list )]
+// R1312 v -> [sign] digit-string
+struct DerivedTypeDataEditDesc {
+ DerivedTypeDataEditDesc() = delete;
+ DerivedTypeDataEditDesc(DerivedTypeDataEditDesc &&) = default;
+ DerivedTypeDataEditDesc &operator=(DerivedTypeDataEditDesc &&) = default;
+ DerivedTypeDataEditDesc(std::string &&t, std::list<std::int64_t> &&p)
+ : type{std::move(t)}, parameters{std::move(p)} {}
+ std::string type;
+ std::list<std::int64_t> parameters;
+};
+
+// R1313 control-edit-desc ->
+// position-edit-desc | [r] / | : | sign-edit-desc | k P |
+// blank-interp-edit-desc | round-edit-desc | decimal-edit-desc
+// R1315 position-edit-desc -> T n | TL n | TR n | n X
+// R1316 n -> digit-string
+// R1317 sign-edit-desc -> SS | SP | S
+// R1318 blank-interp-edit-desc -> BN | BZ
+// R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP
+// R1320 decimal-edit-desc -> DC | DP
+struct ControlEditDesc {
+ enum class Kind { T, TL, TR, X, Slash, Colon, SS, SP, S, P, BN, BZ,
+ RU, RD, RZ, RN, RC, RP, DC, DP };
+ ControlEditDesc() = delete;
+ ControlEditDesc(ControlEditDesc &&) = default;
+ ControlEditDesc &operator=(ControlEditDesc &&) = default;
+ explicit ControlEditDesc(Kind k) : kind{k} {}
+ ControlEditDesc(Kind k, int ct) : kind{k}, count{ct} {}
+ ControlEditDesc(int ct, Kind k) : kind{k}, count{ct} {}
+ Kind kind;
+ int count{1}; // r, k, or n
+};
+
+// R1304 format-item ->
+// [r] data-edit-desc | control-edit-desc | char-string-edit-desc |
+// [r] ( format-items )
+// R1306 r -> digit-string
+// R1321 char-string-edit-desc
+struct FormatItem {
+ FormatItem() = delete;
+ FormatItem(FormatItem &&) = default;
+ FormatItem &operator=(FormatItem &&) = default;
+ template<typename A> FormatItem(std::optional<int> &&r, A &&x)
+ : repeatCount{std::move(r)}, u{std::move(x)} {}
+ template<typename A> explicit FormatItem(A &&x) : u{std::move(x)} {}
+ std::optional<int> repeatCount;
+ std::variant<IntrinsicTypeDataEditDesc, DerivedTypeDataEditDesc,
+ ControlEditDesc, std::string, std::list<FormatItem>> u;
+};
+
+// R1302 format-specification ->
+// ( [format-items] ) | ( [format-items ,] unlimited-format-item )
+// R1303 format-items -> format-item [[,] format-item]...
+// R1305 unlimited-format-item -> * ( format-items )
+struct FormatSpecification {
+ FormatSpecification() = delete;
+ FormatSpecification(FormatSpecification &&) = default;
+ FormatSpecification &operator=(FormatSpecification &&) = default;
+ explicit FormatSpecification(std::list<FormatItem> &&is)
+ : items(std::move(is)) {}
+ FormatSpecification(std::list<FormatItem> &&is, std::list<FormatItem> &&us)
+ : items(std::move(is)), unlimitedItems(std::move(us)) {}
+ std::list<FormatItem> items, unlimitedItems;
+};
+} // namespace Fortran
+#endif // FORTRAN_FORMAT_SPECIFICATION_H_