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