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 "flang/Common/idioms.h" 22 #include <cinttypes> 23 #include <list> 24 #include <optional> 25 #include <string> 26 #include <variant> 27 28 namespace Fortran::format { 29 30 // R1307 data-edit-desc (part 1 of 2) -> 31 // I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d | 32 // E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] | 33 // G w [. d [E e]] | L w | A [w] | D w . d 34 // R1308 w -> digit-string 35 // R1309 m -> digit-string 36 // R1310 d -> digit-string 37 // R1311 e -> digit-string 38 struct IntrinsicTypeDataEditDesc { 39 enum class Kind { I, B, O, Z, F, E, EN, ES, EX, G, L, A, D }; 40 IntrinsicTypeDataEditDesc() = delete; 41 IntrinsicTypeDataEditDesc(IntrinsicTypeDataEditDesc &&) = default; 42 IntrinsicTypeDataEditDesc &operator=(IntrinsicTypeDataEditDesc &&) = default; IntrinsicTypeDataEditDescIntrinsicTypeDataEditDesc43 IntrinsicTypeDataEditDesc(Kind &&k, std::optional<int> &&w, 44 std::optional<int> &&d, std::optional<int> &&e) 45 : kind{k}, width{std::move(w)}, digits{std::move(d)}, exponentWidth{ 46 std::move(e)} {} 47 Kind kind; 48 std::optional<int> width; // w 49 std::optional<int> digits; // m or d 50 std::optional<int> exponentWidth; // e 51 }; 52 53 // R1307 data-edit-desc (part 2 of 2) -> 54 // DT [char-literal-constant] [( v-list )] 55 // R1312 v -> [sign] digit-string 56 struct DerivedTypeDataEditDesc { 57 DerivedTypeDataEditDesc() = delete; 58 DerivedTypeDataEditDesc(DerivedTypeDataEditDesc &&) = default; 59 DerivedTypeDataEditDesc &operator=(DerivedTypeDataEditDesc &&) = default; DerivedTypeDataEditDescDerivedTypeDataEditDesc60 DerivedTypeDataEditDesc(std::string &&t, std::list<std::int64_t> &&p) 61 : type{std::move(t)}, parameters{std::move(p)} {} 62 std::string type; 63 std::list<std::int64_t> parameters; 64 }; 65 66 // R1313 control-edit-desc -> 67 // position-edit-desc | [r] / | : | sign-edit-desc | k P | 68 // blank-interp-edit-desc | round-edit-desc | decimal-edit-desc | 69 // @ \ | $ 70 // R1315 position-edit-desc -> T n | TL n | TR n | n X 71 // R1316 n -> digit-string 72 // R1317 sign-edit-desc -> SS | SP | S 73 // R1318 blank-interp-edit-desc -> BN | BZ 74 // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP 75 // R1320 decimal-edit-desc -> DC | DP 76 struct ControlEditDesc { 77 enum class Kind { 78 T, 79 TL, 80 TR, 81 X, 82 Slash, 83 Colon, 84 SS, 85 SP, 86 S, 87 P, 88 BN, 89 BZ, 90 RU, 91 RD, 92 RZ, 93 RN, 94 RC, 95 RP, 96 DC, 97 DP, 98 Dollar, // extension: inhibit newline on output 99 Backslash, // ditto, but only on terminals 100 }; 101 ControlEditDesc() = delete; 102 ControlEditDesc(ControlEditDesc &&) = default; 103 ControlEditDesc &operator=(ControlEditDesc &&) = default; ControlEditDescControlEditDesc104 explicit ControlEditDesc(Kind k) : kind{k} {} ControlEditDescControlEditDesc105 ControlEditDesc(Kind k, std::int64_t ct) : kind{k}, count{ct} {} ControlEditDescControlEditDesc106 ControlEditDesc(std::int64_t ct, Kind k) : kind{k}, count{ct} {} 107 Kind kind; 108 std::int64_t count{1}; // r, k, or n 109 }; 110 111 // R1304 format-item -> 112 // [r] data-edit-desc | control-edit-desc | char-string-edit-desc | 113 // [r] ( format-items ) 114 // R1306 r -> digit-string 115 // R1321 char-string-edit-desc 116 struct FormatItem { 117 FormatItem() = delete; 118 FormatItem(FormatItem &&) = default; 119 FormatItem &operator=(FormatItem &&) = default; 120 template <typename A, typename = common::NoLvalue<A>> FormatItemFormatItem121 FormatItem(std::optional<std::uint64_t> &&r, A &&x) 122 : repeatCount{std::move(r)}, u{std::move(x)} {} 123 template <typename A, typename = common::NoLvalue<A>> FormatItemFormatItem124 explicit FormatItem(A &&x) : u{std::move(x)} {} 125 std::optional<std::uint64_t> repeatCount; 126 std::variant<IntrinsicTypeDataEditDesc, DerivedTypeDataEditDesc, 127 ControlEditDesc, std::string, std::list<FormatItem>> 128 u; 129 }; 130 131 // R1302 format-specification -> 132 // ( [format-items] ) | ( [format-items ,] unlimited-format-item ) 133 // R1303 format-items -> format-item [[,] format-item]... 134 // R1305 unlimited-format-item -> * ( format-items ) 135 struct FormatSpecification { 136 FormatSpecification() = delete; 137 FormatSpecification(FormatSpecification &&) = default; 138 FormatSpecification &operator=(FormatSpecification &&) = default; FormatSpecificationFormatSpecification139 explicit FormatSpecification(std::list<FormatItem> &&is) 140 : items(std::move(is)) {} FormatSpecificationFormatSpecification141 FormatSpecification(std::list<FormatItem> &&is, std::list<FormatItem> &&us) 142 : items(std::move(is)), unlimitedItems(std::move(us)) {} 143 std::list<FormatItem> items, unlimitedItems; 144 }; 145 } // namespace Fortran::format 146 #endif // FORTRAN_PARSER_FORMAT_SPECIFICATION_H_ 147