[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / flang / runtime / format.h
blobb9f8f73a48dec7a54d75dd5df9b7cbf9d24a0009
1 //===-- runtime/format.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 //===----------------------------------------------------------------------===//
9 // FORMAT string processing
11 #ifndef FORTRAN_RUNTIME_FORMAT_H_
12 #define FORTRAN_RUNTIME_FORMAT_H_
14 #include "environment.h"
15 #include "io-error.h"
16 #include "flang/Common/Fortran.h"
17 #include "flang/Decimal/decimal.h"
18 #include <cinttypes>
19 #include <optional>
21 namespace Fortran::runtime {
22 class Descriptor;
23 } // namespace Fortran::runtime
25 namespace Fortran::runtime::io {
27 class IoStatementState;
29 enum EditingFlags {
30 blankZero = 1, // BLANK=ZERO or BZ edit
31 decimalComma = 2, // DECIMAL=COMMA or DC edit
32 signPlus = 4, // SIGN=PLUS or SP edit
35 struct MutableModes {
36 std::uint8_t editingFlags{0}; // BN, DP, SS
37 enum decimal::FortranRounding round{
38 executionEnvironment
39 .defaultOutputRoundingMode}; // RP/ROUND='PROCESSOR_DEFAULT'
40 bool pad{true}; // PAD= mode on READ
41 char delim{'\0'}; // DELIM=
42 short scale{0}; // kP
43 bool inNamelist{false}; // skip ! comments
44 bool nonAdvancing{false}; // ADVANCE='NO', or $ or \ in FORMAT
47 // A single edit descriptor extracted from a FORMAT
48 struct DataEdit {
49 char descriptor; // capitalized: one of A, I, B, O, Z, F, E(N/S/X), D, G
51 // Special internal data edit descriptors for list-directed & NAMELIST I/O
52 static constexpr char ListDirected{'g'}; // non-COMPLEX list-directed
53 static constexpr char ListDirectedRealPart{'r'}; // emit "(r," or "(r;"
54 static constexpr char ListDirectedImaginaryPart{'z'}; // emit "z)"
55 static constexpr char ListDirectedNullValue{'n'}; // see 13.10.3.2
56 constexpr bool IsListDirected() const {
57 return descriptor == ListDirected || descriptor == ListDirectedRealPart ||
58 descriptor == ListDirectedImaginaryPart;
60 constexpr bool IsNamelist() const {
61 return IsListDirected() && modes.inNamelist;
64 static constexpr char DefinedDerivedType{'d'}; // DT defined I/O
66 char variation{'\0'}; // N, S, or X for EN, ES, EX
67 std::optional<int> width; // the 'w' field; optional for A
68 std::optional<int> digits; // the 'm' or 'd' field
69 std::optional<int> expoDigits; // 'Ee' field
70 MutableModes modes;
71 int repeat{1};
73 // "iotype" &/or "v_list" values for a DT'iotype'(v_list)
74 // defined I/O data edit descriptor
75 static constexpr std::size_t maxIoTypeChars{32};
76 static constexpr std::size_t maxVListEntries{4};
77 std::uint8_t ioTypeChars{0};
78 std::uint8_t vListEntries{0};
79 char ioType[maxIoTypeChars];
80 int vList[maxVListEntries];
83 // Generates a sequence of DataEdits from a FORMAT statement or
84 // default-CHARACTER string. Driven by I/O item list processing.
85 // Errors are fatal. See subclause 13.4 in Fortran 2018 for background.
86 template <typename CONTEXT> class FormatControl {
87 public:
88 using Context = CONTEXT;
89 using CharType = char; // formats are always default kind CHARACTER
91 FormatControl() {}
92 FormatControl(const Terminator &, const CharType *format,
93 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr,
94 int maxHeight = maxMaxHeight);
96 // For attempting to allocate in a user-supplied stack area
97 static std::size_t GetNeededSize(int maxHeight) {
98 return sizeof(FormatControl) -
99 sizeof(Iteration) * (maxMaxHeight - maxHeight);
102 // Extracts the next data edit descriptor, handling control edit descriptors
103 // along the way. If maxRepeat==0, this is a peek at the next data edit
104 // descriptor.
105 std::optional<DataEdit> GetNextDataEdit(Context &, int maxRepeat = 1);
107 // Emit any remaining character literals after the last data item (on output)
108 // and perform remaining record positioning actions.
109 void Finish(Context &);
111 private:
112 static constexpr std::uint8_t maxMaxHeight{100};
114 struct Iteration {
115 static constexpr int unlimited{-1};
116 int start{0}; // offset in format_ of '(' or a repeated edit descriptor
117 int remaining{0}; // while >0, decrement and iterate
120 void SkipBlanks() {
121 while (offset_ < formatLength_ &&
122 (format_[offset_] == ' ' || format_[offset_] == '\t' ||
123 format_[offset_] == '\v')) {
124 ++offset_;
127 CharType PeekNext() {
128 SkipBlanks();
129 return offset_ < formatLength_ ? format_[offset_] : '\0';
131 CharType GetNextChar(IoErrorHandler &handler) {
132 SkipBlanks();
133 if (offset_ >= formatLength_) {
134 if (formatLength_ == 0) {
135 handler.SignalError(
136 IostatErrorInFormat, "Empty or badly assigned FORMAT");
137 } else {
138 handler.SignalError(
139 IostatErrorInFormat, "FORMAT missing at least one ')'");
141 return '\n';
143 return format_[offset_++];
145 int GetIntField(
146 IoErrorHandler &, CharType firstCh = '\0', bool *hadError = nullptr);
148 // Advances through the FORMAT until the next data edit
149 // descriptor has been found; handles control edit descriptors
150 // along the way. Returns the repeat count that appeared
151 // before the descriptor (defaulting to 1) and leaves offset_
152 // pointing to the data edit.
153 int CueUpNextDataEdit(Context &, bool stop = false);
155 static constexpr CharType Capitalize(CharType ch) {
156 return ch >= 'a' && ch <= 'z' ? ch + 'A' - 'a' : ch;
159 void ReportBadFormat(Context &context, const char *msg, int offset) const {
160 if constexpr (std::is_same_v<CharType, char>) {
161 // Echo the bad format in the error message, but trim any leading or
162 // trailing spaces.
163 int firstNonBlank{0};
164 while (firstNonBlank < formatLength_ && format_[firstNonBlank] == ' ') {
165 ++firstNonBlank;
167 int lastNonBlank{formatLength_ - 1};
168 while (lastNonBlank > firstNonBlank && format_[lastNonBlank] == ' ') {
169 --lastNonBlank;
171 if (firstNonBlank <= lastNonBlank) {
172 context.SignalError(IostatErrorInFormat,
173 "%s; at offset %d in format '%.*s'", msg, offset,
174 lastNonBlank - firstNonBlank + 1, format_ + firstNonBlank);
175 return;
178 context.SignalError(IostatErrorInFormat, "%s; at offset %d", msg, offset);
181 // Data members are arranged and typed so as to reduce size.
182 // This structure may be allocated in stack space loaned by the
183 // user program for internal I/O.
184 const std::uint8_t maxHeight_{maxMaxHeight};
185 std::uint8_t height_{0};
186 bool freeFormat_{false};
187 const CharType *format_{nullptr};
188 int formatLength_{0}; // in units of characters
189 int offset_{0}; // next item is at format_[offset_]
191 // must be last, may be incomplete
192 Iteration stack_[maxMaxHeight];
194 } // namespace Fortran::runtime::io
195 #endif // FORTRAN_RUNTIME_FORMAT_H_