1 // Copyright (c) 2018-2019, NVIDIA CORPORATION.  All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef FORTRAN_PARSER_FORMAT_SPECIFICATION_H_
16 #define FORTRAN_PARSER_FORMAT_SPECIFICATION_H_
17 
18 // Represent parses of Fortran format specifications from FORMAT statements
19 // and character literals in formatted I/O statements at compilation time
20 // as well as from character variables and expressions at run time.
21 // From requirement productions R1302-R1321 of the Fortran 2018 draft
22 // standard (q.v.), extended with Hollerith.  These structures have been
23 // isolated so that they may be used in the run-time without introducing
24 // dependences on other parts of the compiler's source code.
25 // TODO: support Q formatting extension?
26 
27 #include <cinttypes>
28 #include <list>
29 #include <optional>
30 #include <string>
31 #include <variant>
32 
33 namespace Fortran::format {
34 
35 // R1307 data-edit-desc (part 1 of 2) ->
36 //         I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d |
37 //         E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] |
38 //         G w [. d [E e]] | L w | A [w] | D w . d
39 // R1308 w -> digit-string
40 // R1309 m -> digit-string
41 // R1310 d -> digit-string
42 // R1311 e -> digit-string
43 struct IntrinsicTypeDataEditDesc {
44   enum class Kind { I, B, O, Z, F, E, EN, ES, EX, G, L, A, D };
45   IntrinsicTypeDataEditDesc() = delete;
46   IntrinsicTypeDataEditDesc(IntrinsicTypeDataEditDesc &&) = default;
47   IntrinsicTypeDataEditDesc &operator=(IntrinsicTypeDataEditDesc &&) = default;
IntrinsicTypeDataEditDescIntrinsicTypeDataEditDesc48   IntrinsicTypeDataEditDesc(Kind &&k, std::optional<int> &&w,
49       std::optional<int> &&d, std::optional<int> &&e)
50     : kind{k}, width{std::move(w)}, digits{std::move(d)}, exponentWidth{
51                                                               std::move(e)} {}
52   Kind kind;
53   std::optional<int> width;  // w
54   std::optional<int> digits;  // m or d
55   std::optional<int> exponentWidth;  // e
56 };
57 
58 // R1307 data-edit-desc (part 2 of 2) ->
59 //         DT [char-literal-constant] [( v-list )]
60 // R1312 v -> [sign] digit-string
61 struct DerivedTypeDataEditDesc {
62   DerivedTypeDataEditDesc() = delete;
63   DerivedTypeDataEditDesc(DerivedTypeDataEditDesc &&) = default;
64   DerivedTypeDataEditDesc &operator=(DerivedTypeDataEditDesc &&) = default;
DerivedTypeDataEditDescDerivedTypeDataEditDesc65   DerivedTypeDataEditDesc(std::string &&t, std::list<std::int64_t> &&p)
66     : type{std::move(t)}, parameters{std::move(p)} {}
67   std::string type;
68   std::list<std::int64_t> parameters;
69 };
70 
71 // R1313 control-edit-desc ->
72 //         position-edit-desc | [r] / | : | sign-edit-desc | k P |
73 //         blank-interp-edit-desc | round-edit-desc | decimal-edit-desc |
74 //         @ \ | $
75 // R1315 position-edit-desc -> T n | TL n | TR n | n X
76 // R1316 n -> digit-string
77 // R1317 sign-edit-desc -> SS | SP | S
78 // R1318 blank-interp-edit-desc -> BN | BZ
79 // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP
80 // R1320 decimal-edit-desc -> DC | DP
81 struct ControlEditDesc {
82   enum class Kind {
83     T,
84     TL,
85     TR,
86     X,
87     Slash,
88     Colon,
89     SS,
90     SP,
91     S,
92     P,
93     BN,
94     BZ,
95     RU,
96     RD,
97     RZ,
98     RN,
99     RC,
100     RP,
101     DC,
102     DP,
103     Dollar,  // extension: inhibit newline on output
104     Backslash,  // ditto, but only on terminals
105   };
106   ControlEditDesc() = delete;
107   ControlEditDesc(ControlEditDesc &&) = default;
108   ControlEditDesc &operator=(ControlEditDesc &&) = default;
ControlEditDescControlEditDesc109   explicit ControlEditDesc(Kind k) : kind{k} {}
ControlEditDescControlEditDesc110   ControlEditDesc(Kind k, std::int64_t ct) : kind{k}, count{ct} {}
ControlEditDescControlEditDesc111   ControlEditDesc(std::int64_t ct, Kind k) : kind{k}, count{ct} {}
112   Kind kind;
113   std::int64_t count{1};  // r, k, or n
114 };
115 
116 // R1304 format-item ->
117 //         [r] data-edit-desc | control-edit-desc | char-string-edit-desc |
118 //         [r] ( format-items )
119 // R1306 r -> digit-string
120 // R1321 char-string-edit-desc
121 struct FormatItem {
122   FormatItem() = delete;
123   FormatItem(FormatItem &&) = default;
124   FormatItem &operator=(FormatItem &&) = default;
125   template<typename A, typename = common::NoLvalue<A>>
FormatItemFormatItem126   FormatItem(std::optional<std::uint64_t> &&r, A &&x)
127     : repeatCount{std::move(r)}, u{std::move(x)} {}
128   template<typename A, typename = common::NoLvalue<A>>
FormatItemFormatItem129   explicit FormatItem(A &&x) : u{std::move(x)} {}
130   std::optional<std::uint64_t> repeatCount;
131   std::variant<IntrinsicTypeDataEditDesc, DerivedTypeDataEditDesc,
132       ControlEditDesc, std::string, std::list<FormatItem>>
133       u;
134 };
135 
136 // R1302 format-specification ->
137 //         ( [format-items] ) | ( [format-items ,] unlimited-format-item )
138 // R1303 format-items -> format-item [[,] format-item]...
139 // R1305 unlimited-format-item -> * ( format-items )
140 struct FormatSpecification {
141   FormatSpecification() = delete;
142   FormatSpecification(FormatSpecification &&) = default;
143   FormatSpecification &operator=(FormatSpecification &&) = default;
FormatSpecificationFormatSpecification144   explicit FormatSpecification(std::list<FormatItem> &&is)
145     : items(std::move(is)) {}
FormatSpecificationFormatSpecification146   FormatSpecification(std::list<FormatItem> &&is, std::list<FormatItem> &&us)
147     : items(std::move(is)), unlimitedItems(std::move(us)) {}
148   std::list<FormatItem> items, unlimitedItems;
149 };
150 }
151 #endif  // FORTRAN_PARSER_FORMAT_SPECIFICATION_H_
152