1 //===-- include/flang/Parser/format-specification.h -------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef FORTRAN_PARSER_FORMAT_SPECIFICATION_H_ 10 #define FORTRAN_PARSER_FORMAT_SPECIFICATION_H_ 11 12 // Represent parses of Fortran format specifications from FORMAT statements 13 // and character literals in formatted I/O statements at compilation time 14 // as well as from character variables and expressions at run time. 15 // From requirement productions R1302-R1321 of the Fortran 2018 draft 16 // standard (q.v.), extended with Hollerith. These structures have been 17 // isolated so that they may be used in the run-time without introducing 18 // dependences on other parts of the compiler's source code. 19 // TODO: support Q formatting extension? 20 21 #include <cinttypes> 22 #include <list> 23 #include <optional> 24 #include <string> 25 #include <variant> 26 27 namespace Fortran::format { 28 29 // R1307 data-edit-desc (part 1 of 2) -> 30 // I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d | 31 // E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] | 32 // G w [. d [E e]] | L w | A [w] | D w . d 33 // R1308 w -> digit-string 34 // R1309 m -> digit-string 35 // R1310 d -> digit-string 36 // R1311 e -> digit-string 37 struct IntrinsicTypeDataEditDesc { 38 enum class Kind { I, B, O, Z, F, E, EN, ES, EX, G, L, A, D }; 39 IntrinsicTypeDataEditDesc() = delete; 40 IntrinsicTypeDataEditDesc(IntrinsicTypeDataEditDesc &&) = default; 41 IntrinsicTypeDataEditDesc &operator=(IntrinsicTypeDataEditDesc &&) = default; IntrinsicTypeDataEditDescIntrinsicTypeDataEditDesc42 IntrinsicTypeDataEditDesc(Kind &&k, std::optional<int> &&w, 43 std::optional<int> &&d, std::optional<int> &&e) 44 : kind{k}, width{std::move(w)}, digits{std::move(d)}, exponentWidth{ 45 std::move(e)} {} 46 Kind kind; 47 std::optional<int> width; // w 48 std::optional<int> digits; // m or d 49 std::optional<int> exponentWidth; // e 50 }; 51 52 // R1307 data-edit-desc (part 2 of 2) -> 53 // DT [char-literal-constant] [( v-list )] 54 // R1312 v -> [sign] digit-string 55 struct DerivedTypeDataEditDesc { 56 DerivedTypeDataEditDesc() = delete; 57 DerivedTypeDataEditDesc(DerivedTypeDataEditDesc &&) = default; 58 DerivedTypeDataEditDesc &operator=(DerivedTypeDataEditDesc &&) = default; DerivedTypeDataEditDescDerivedTypeDataEditDesc59 DerivedTypeDataEditDesc(std::string &&t, std::list<std::int64_t> &&p) 60 : type{std::move(t)}, parameters{std::move(p)} {} 61 std::string type; 62 std::list<std::int64_t> parameters; 63 }; 64 65 // R1313 control-edit-desc -> 66 // position-edit-desc | [r] / | : | sign-edit-desc | k P | 67 // blank-interp-edit-desc | round-edit-desc | decimal-edit-desc | 68 // @ \ | $ 69 // R1315 position-edit-desc -> T n | TL n | TR n | n X 70 // R1316 n -> digit-string 71 // R1317 sign-edit-desc -> SS | SP | S 72 // R1318 blank-interp-edit-desc -> BN | BZ 73 // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP 74 // R1320 decimal-edit-desc -> DC | DP 75 struct ControlEditDesc { 76 enum class Kind { 77 T, 78 TL, 79 TR, 80 X, 81 Slash, 82 Colon, 83 SS, 84 SP, 85 S, 86 P, 87 BN, 88 BZ, 89 RU, 90 RD, 91 RZ, 92 RN, 93 RC, 94 RP, 95 DC, 96 DP, 97 Dollar, // extension: inhibit newline on output 98 Backslash, // ditto, but only on terminals 99 }; 100 ControlEditDesc() = delete; 101 ControlEditDesc(ControlEditDesc &&) = default; 102 ControlEditDesc &operator=(ControlEditDesc &&) = default; ControlEditDescControlEditDesc103 explicit ControlEditDesc(Kind k) : kind{k} {} ControlEditDescControlEditDesc104 ControlEditDesc(Kind k, std::int64_t ct) : kind{k}, count{ct} {} ControlEditDescControlEditDesc105 ControlEditDesc(std::int64_t ct, Kind k) : kind{k}, count{ct} {} 106 Kind kind; 107 std::int64_t count{1}; // r, k, or n 108 }; 109 110 // R1304 format-item -> 111 // [r] data-edit-desc | control-edit-desc | char-string-edit-desc | 112 // [r] ( format-items ) 113 // R1306 r -> digit-string 114 // R1321 char-string-edit-desc 115 struct FormatItem { 116 FormatItem() = delete; 117 FormatItem(FormatItem &&) = default; 118 FormatItem &operator=(FormatItem &&) = default; 119 template <typename A, typename = common::NoLvalue<A>> FormatItemFormatItem120 FormatItem(std::optional<std::uint64_t> &&r, A &&x) 121 : repeatCount{std::move(r)}, u{std::move(x)} {} 122 template <typename A, typename = common::NoLvalue<A>> FormatItemFormatItem123 explicit FormatItem(A &&x) : u{std::move(x)} {} 124 std::optional<std::uint64_t> repeatCount; 125 std::variant<IntrinsicTypeDataEditDesc, DerivedTypeDataEditDesc, 126 ControlEditDesc, std::string, std::list<FormatItem>> 127 u; 128 }; 129 130 // R1302 format-specification -> 131 // ( [format-items] ) | ( [format-items ,] unlimited-format-item ) 132 // R1303 format-items -> format-item [[,] format-item]... 133 // R1305 unlimited-format-item -> * ( format-items ) 134 struct FormatSpecification { 135 FormatSpecification() = delete; 136 FormatSpecification(FormatSpecification &&) = default; 137 FormatSpecification &operator=(FormatSpecification &&) = default; FormatSpecificationFormatSpecification138 explicit FormatSpecification(std::list<FormatItem> &&is) 139 : items(std::move(is)) {} FormatSpecificationFormatSpecification140 FormatSpecification(std::list<FormatItem> &&is, std::list<FormatItem> &&us) 141 : items(std::move(is)), unlimitedItems(std::move(us)) {} 142 std::list<FormatItem> items, unlimitedItems; 143 }; 144 } // namespace Fortran::format 145 #endif // FORTRAN_PARSER_FORMAT_SPECIFICATION_H_ 146