FLANG

format.h
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 //===----------------------------------------------------------------------===//
8
9 // FORMAT string processing
10
11 #ifndef FORTRAN_RUNTIME_FORMAT_H_
12 #define FORTRAN_RUNTIME_FORMAT_H_
13
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>
20
21 namespace Fortran::runtime::io {
22
23 enum EditingFlags {
24 blankZero = 1, // BLANK=ZERO or BZ edit
25 decimalComma = 2, // DECIMAL=COMMA or DC edit
26 signPlus = 4, // SIGN=PLUS or SP edit
27 };
28
29 struct MutableModes {
30 std::uint8_t editingFlags{0}; // BN, DP, SS
31 enum decimal::FortranRounding round{
32 executionEnvironment
33 .defaultOutputRoundingMode}; // RP/ROUND='PROCESSOR_DEFAULT'
34 bool pad{false}; // PAD= mode on READ
35 char delim{'\0'}; // DELIM=
36 short scale{0}; // kP
37 };
38
39 // A single edit descriptor extracted from a FORMAT
40 struct DataEdit {
41 char descriptor; // capitalized: one of A, I, B, O, Z, F, E(N/S/X), D, G
42
43 // Special internal data edit descriptors for list-directed I/O
44 static constexpr char ListDirected{'g'}; // non-COMPLEX list-directed
45 static constexpr char ListDirectedRealPart{'r'}; // emit "(r," or "(r;"
46 static constexpr char ListDirectedImaginaryPart{'z'}; // emit "z)"
47 static constexpr char ListDirectedNullValue{'n'}; // see 13.10.3.2
48 constexpr bool IsListDirected() const {
49 return descriptor == ListDirected || descriptor == ListDirectedRealPart ||
50 descriptor == ListDirectedImaginaryPart;
51 }
52
53 char variation{'\0'}; // N, S, or X for EN, ES, EX
54 std::optional<int> width; // the 'w' field; optional for A
55 std::optional<int> digits; // the 'm' or 'd' field
56 std::optional<int> expoDigits; // 'Ee' field
57 MutableModes modes;
58 int repeat{1};
59 };
60
61 // FormatControl<A> requires that A have these member functions;
62 // these default implementations just crash if called.
63 struct DefaultFormatControlCallbacks : public IoErrorHandler {
64 using IoErrorHandler::IoErrorHandler;
65 DataEdit GetNextDataEdit(int = 1);
66 bool Emit(const char *, std::size_t);
67 bool Emit(const char16_t *, std::size_t);
68 bool Emit(const char32_t *, std::size_t);
69 std::optional<char32_t> GetCurrentChar();
70 bool AdvanceRecord(int = 1);
71 void BackspaceRecord();
72 void HandleAbsolutePosition(std::int64_t);
73 void HandleRelativePosition(std::int64_t);
74 };
75
76 // Generates a sequence of DataEdits from a FORMAT statement or
77 // default-CHARACTER string. Driven by I/O item list processing.
78 // Errors are fatal. See clause 13.4 in Fortran 2018 for background.
79 template <typename CONTEXT> class FormatControl {
80 public:
81 using Context = CONTEXT;
82 using CharType = typename Context::CharType;
83
84 FormatControl() {}
85 FormatControl(const Terminator &, const CharType *format,
86 std::size_t formatLength, int maxHeight = maxMaxHeight);
87
88 // Determines the max parenthesis nesting level by scanning and validating
89 // the FORMAT string.
90 static int GetMaxParenthesisNesting(
91 IoErrorHandler &, const CharType *format, std::size_t formatLength);
92
93 // For attempting to allocate in a user-supplied stack area
94 static std::size_t GetNeededSize(int maxHeight) {
95 return sizeof(FormatControl) -
96 sizeof(Iteration) * (maxMaxHeight - maxHeight);
97 }
98
99 // Extracts the next data edit descriptor, handling control edit descriptors
100 // along the way.
101 DataEdit GetNextDataEdit(Context &, int maxRepeat = 1);
102
103 // Emit any remaining character literals after the last data item (on output)
104 // and perform remaining record positioning actions.
105 void Finish(Context &);
106
107 private:
108 static constexpr std::uint8_t maxMaxHeight{100};
109
110 struct Iteration {
111 static constexpr int unlimited{-1};
112 int start{0}; // offset in format_ of '(' or a repeated edit descriptor
113 int remaining{0}; // while >0, decrement and iterate
114 };
115
116 void SkipBlanks() {
117 while (offset_ < formatLength_ && format_[offset_] == ' ') {
118 ++offset_;
119 }
120 }
121 CharType PeekNext() {
122 SkipBlanks();
123 return offset_ < formatLength_ ? format_[offset_] : '\0';
124 }
125 CharType GetNextChar(IoErrorHandler &handler) {
126 SkipBlanks();
127 if (offset_ >= formatLength_) {
128 handler.SignalError(
129 IostatErrorInFormat, "FORMAT missing at least one ')'");
130 return '\n';
131 }
132 return format_[offset_++];
133 }
134 int GetIntField(IoErrorHandler &, CharType firstCh = '\0');
135
136 // Advances through the FORMAT until the next data edit
137 // descriptor has been found; handles control edit descriptors
138 // along the way. Returns the repeat count that appeared
139 // before the descriptor (defaulting to 1) and leaves offset_
140 // pointing to the data edit.
141 int CueUpNextDataEdit(Context &, bool stop = false);
142
143 static constexpr CharType Capitalize(CharType ch) {
144 return ch >= 'a' && ch <= 'z' ? ch + 'A' - 'a' : ch;
145 }
146
147 // Data members are arranged and typed so as to reduce size.
148 // This structure may be allocated in stack space loaned by the
149 // user program for internal I/O.
150 const std::uint8_t maxHeight_{maxMaxHeight};
151 std::uint8_t height_{0};
152 const CharType *format_{nullptr};
153 int formatLength_{0};
154 int offset_{0}; // next item is at format_[offset_]
155
156 // must be last, may be incomplete
157 Iteration stack_[maxMaxHeight];
158 };
159 } // namespace Fortran::runtime::io
160 #endif // FORTRAN_RUNTIME_FORMAT_H_
Fortran::runtime::Terminator
Definition: terminator.h:21
Fortran::runtime::io::IoErrorHandler
Definition: io-error.h:26
Fortran::runtime::io::MutableModes
Definition: format.h:29
Fortran::runtime::io::DataEdit
Definition: format.h:40
Fortran::runtime::io::DefaultFormatControlCallbacks
Definition: format.h:63
Fortran::runtime::io::FormatControl
Definition: format.h:79