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{true}; // 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 IsListDirectedDataEdit48 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, std::size_t elementBytes = 0); 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 FormatControl()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 GetNeededSize(int maxHeight)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 SkipBlanks()116 void SkipBlanks() { 117 while (offset_ < formatLength_ && format_[offset_] == ' ') { 118 ++offset_; 119 } 120 } PeekNext()121 CharType PeekNext() { 122 SkipBlanks(); 123 return offset_ < formatLength_ ? format_[offset_] : '\0'; 124 } GetNextChar(IoErrorHandler & handler)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 Capitalize(CharType ch)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_ 161