[flang-commits] [flang] 7c5630f - [flang] Handle spaces (more) correctly in REAL input

peter klausler via flang-commits flang-commits at lists.llvm.org
Mon Aug 3 16:13:11 PDT 2020


Author: peter klausler
Date: 2020-08-03T16:12:30-07:00
New Revision: 7c5630fe9908a8bf10be2e9d26054406fac8de87

URL: https://github.com/llvm/llvm-project/commit/7c5630fe9908a8bf10be2e9d26054406fac8de87
DIFF: https://github.com/llvm/llvm-project/commit/7c5630fe9908a8bf10be2e9d26054406fac8de87.diff

LOG: [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

Added: 
    

Modified: 
    flang/runtime/edit-input.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index ebbe41b49b2c..998edc954ba7 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -13,6 +13,8 @@
 
 namespace Fortran::runtime::io {
 
+// For fixed-width fields, initialize the number of remaining characters.
+// Skip over leading blanks, then return the first non-blank character (if any).
 static std::optional<char32_t> PrepareInput(
     IoStatementState &io, const DataEdit &edit, std::optional<int> &remaining) {
   remaining.reset();
@@ -61,7 +63,8 @@ static bool EditBOZInput(IoStatementState &io, const DataEdit &edit, void *n,
   return true;
 }
 
-// Returns false if there's a '-' sign
+// Prepares input from a field, and consumes the sign, if any.
+// Returns true if there's a '-' sign.
 static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
     std::optional<char32_t> &next, std::optional<int> &remaining) {
   next = PrepareInput(io, edit, remaining);
@@ -69,6 +72,7 @@ static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
   if (next) {
     negative = *next == '-';
     if (negative || *next == '+') {
+      io.SkipSpaces(remaining);
       next = io.NextInField(remaining);
     }
   }
@@ -126,39 +130,44 @@ bool EditIntegerInput(
   return true;
 }
 
+// Parses a REAL input number from the input source as a normalized
+// fraction into a supplied buffer -- there's an optional '-', a
+// decimal point, and at least one digit.  The adjusted exponent value
+// is returned in a reference argument.  The returned value is the number
+// of characters that (should) have been written to the buffer -- this can
+// be larger than the buffer size and can indicate overflow.  Replaces
+// blanks with zeroes if appropriate.
 static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     const DataEdit &edit, int &exponent) {
   std::optional<int> remaining;
   std::optional<char32_t> next;
   int got{0};
   std::optional<int> decimalPoint;
-  if (ScanNumericPrefix(io, edit, next, remaining) && next) {
+  auto Put{[&](char ch) -> void {
     if (got < bufferSize) {
-      buffer[got++] = '-';
+      buffer[got] = ch;
     }
+    ++got;
+  }};
+  if (ScanNumericPrefix(io, edit, next, remaining)) {
+    Put('-');
   }
   if (!next) { // empty field means zero
-    if (got < bufferSize) {
-      buffer[got++] = '0';
-    }
+    Put('0');
     return got;
   }
-  if (got < bufferSize) {
-    buffer[got++] = '.'; // input field is normalized to a fraction
-  }
   char32_t decimal = edit.modes.editingFlags & decimalComma ? ',' : '.';
-  auto start{got};
-  if ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z')) {
+  char32_t first{*next >= 'a' && *next <= 'z' ? *next + 'A' - 'a' : *next};
+  if (first == 'N' || first == 'I') {
     // NaN or infinity - convert to upper case
+    // Subtle: a blank field of digits could be followed by 'E' or 'D',
     for (; next &&
          ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z'));
          next = io.NextInField(remaining)) {
-      if (got < bufferSize) {
-        if (*next >= 'a' && *next <= 'z') {
-          buffer[got++] = *next - 'a' + 'A';
-        } else {
-          buffer[got++] = *next;
-        }
+      if (*next >= 'a' && *next <= 'z') {
+        Put(*next - 'a' + 'A');
+      } else {
+        Put(*next);
       }
     }
     if (next && *next == '(') { // NaN(...)
@@ -167,7 +176,10 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
       }
     }
     exponent = 0;
-  } else if (*next == decimal || (*next >= '0' && *next <= '9')) {
+  } else if (first == decimal || (first >= '0' && first <= '9') ||
+      first == 'E' || first == 'D' || first == 'Q') {
+    Put('.'); // input field is normalized to a fraction
+    auto start{got};
     for (; next; next = io.NextInField(remaining)) {
       char32_t ch{*next};
       if (ch == ' ' || ch == '\t') {
@@ -180,9 +192,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
       if (ch == '0' && got == start && !decimalPoint) {
         // omit leading zeroes before the decimal
       } else if (ch >= '0' && ch <= '9') {
-        if (got < bufferSize) {
-          buffer[got++] = ch;
-        }
+        Put(ch);
       } else if (ch == decimal && !decimalPoint) {
         // the decimal point is *not* copied to the buffer
         decimalPoint = got - start; // # of digits before the decimal point
@@ -190,8 +200,8 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
         break;
       }
     }
-    if (got == start && got < bufferSize) {
-      buffer[got++] = '0'; // all digits were zeroes
+    if (got == start) {
+      Put('0'); // emit at least one digit
     }
     if (next &&
         (*next == 'e' || *next == 'E' || *next == 'd' || *next == 'D' ||


        


More information about the flang-commits mailing list