Skip to content

Commit 7c5630f

Browse files
committed
[flang] Handle spaces (more) correctly in REAL input
Fixes problems in FCVS test fm110.f. Add more comments, too. Differential Revision: https://reviews.llvm.org/D85163
1 parent 509f5c4 commit 7c5630f

File tree

1 file changed

+33
-23
lines changed

1 file changed

+33
-23
lines changed

flang/runtime/edit-input.cpp

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace Fortran::runtime::io {
1515

16+
// For fixed-width fields, initialize the number of remaining characters.
17+
// Skip over leading blanks, then return the first non-blank character (if any).
1618
static std::optional<char32_t> PrepareInput(
1719
IoStatementState &io, const DataEdit &edit, std::optional<int> &remaining) {
1820
remaining.reset();
@@ -61,14 +63,16 @@ static bool EditBOZInput(IoStatementState &io, const DataEdit &edit, void *n,
6163
return true;
6264
}
6365

64-
// Returns false if there's a '-' sign
66+
// Prepares input from a field, and consumes the sign, if any.
67+
// Returns true if there's a '-' sign.
6568
static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
6669
std::optional<char32_t> &next, std::optional<int> &remaining) {
6770
next = PrepareInput(io, edit, remaining);
6871
bool negative{false};
6972
if (next) {
7073
negative = *next == '-';
7174
if (negative || *next == '+') {
75+
io.SkipSpaces(remaining);
7276
next = io.NextInField(remaining);
7377
}
7478
}
@@ -126,39 +130,44 @@ bool EditIntegerInput(
126130
return true;
127131
}
128132

133+
// Parses a REAL input number from the input source as a normalized
134+
// fraction into a supplied buffer -- there's an optional '-', a
135+
// decimal point, and at least one digit. The adjusted exponent value
136+
// is returned in a reference argument. The returned value is the number
137+
// of characters that (should) have been written to the buffer -- this can
138+
// be larger than the buffer size and can indicate overflow. Replaces
139+
// blanks with zeroes if appropriate.
129140
static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
130141
const DataEdit &edit, int &exponent) {
131142
std::optional<int> remaining;
132143
std::optional<char32_t> next;
133144
int got{0};
134145
std::optional<int> decimalPoint;
135-
if (ScanNumericPrefix(io, edit, next, remaining) && next) {
146+
auto Put{[&](char ch) -> void {
136147
if (got < bufferSize) {
137-
buffer[got++] = '-';
148+
buffer[got] = ch;
138149
}
150+
++got;
151+
}};
152+
if (ScanNumericPrefix(io, edit, next, remaining)) {
153+
Put('-');
139154
}
140155
if (!next) { // empty field means zero
141-
if (got < bufferSize) {
142-
buffer[got++] = '0';
143-
}
156+
Put('0');
144157
return got;
145158
}
146-
if (got < bufferSize) {
147-
buffer[got++] = '.'; // input field is normalized to a fraction
148-
}
149159
char32_t decimal = edit.modes.editingFlags & decimalComma ? ',' : '.';
150-
auto start{got};
151-
if ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z')) {
160+
char32_t first{*next >= 'a' && *next <= 'z' ? *next + 'A' - 'a' : *next};
161+
if (first == 'N' || first == 'I') {
152162
// NaN or infinity - convert to upper case
163+
// Subtle: a blank field of digits could be followed by 'E' or 'D',
153164
for (; next &&
154165
((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z'));
155166
next = io.NextInField(remaining)) {
156-
if (got < bufferSize) {
157-
if (*next >= 'a' && *next <= 'z') {
158-
buffer[got++] = *next - 'a' + 'A';
159-
} else {
160-
buffer[got++] = *next;
161-
}
167+
if (*next >= 'a' && *next <= 'z') {
168+
Put(*next - 'a' + 'A');
169+
} else {
170+
Put(*next);
162171
}
163172
}
164173
if (next && *next == '(') { // NaN(...)
@@ -167,7 +176,10 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
167176
}
168177
}
169178
exponent = 0;
170-
} else if (*next == decimal || (*next >= '0' && *next <= '9')) {
179+
} else if (first == decimal || (first >= '0' && first <= '9') ||
180+
first == 'E' || first == 'D' || first == 'Q') {
181+
Put('.'); // input field is normalized to a fraction
182+
auto start{got};
171183
for (; next; next = io.NextInField(remaining)) {
172184
char32_t ch{*next};
173185
if (ch == ' ' || ch == '\t') {
@@ -180,18 +192,16 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
180192
if (ch == '0' && got == start && !decimalPoint) {
181193
// omit leading zeroes before the decimal
182194
} else if (ch >= '0' && ch <= '9') {
183-
if (got < bufferSize) {
184-
buffer[got++] = ch;
185-
}
195+
Put(ch);
186196
} else if (ch == decimal && !decimalPoint) {
187197
// the decimal point is *not* copied to the buffer
188198
decimalPoint = got - start; // # of digits before the decimal point
189199
} else {
190200
break;
191201
}
192202
}
193-
if (got == start && got < bufferSize) {
194-
buffer[got++] = '0'; // all digits were zeroes
203+
if (got == start) {
204+
Put('0'); // emit at least one digit
195205
}
196206
if (next &&
197207
(*next == 'e' || *next == 'E' || *next == 'd' || *next == 'D' ||

0 commit comments

Comments
 (0)