• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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