[flang] Resolve some TODOs in the grammar.
authorpeter klausler <pklausler@nvidia.com>
Tue, 3 Apr 2018 21:14:39 +0000 (14:14 -0700)
committerpeter klausler <pklausler@nvidia.com>
Tue, 3 Apr 2018 21:14:39 +0000 (14:14 -0700)
Original-commit: flang-compiler/f18@6ef9e2388bfc7f9b7ac5966196d9e1918220d797
Reviewed-on: https://github.com/flang-compiler/f18/pull/39

flang/documentation/C++style.md
flang/documentation/parsing.md
flang/lib/parser/format-specification.h
flang/lib/parser/grammar.h
flang/lib/parser/token-parsers.h

index 73ac75e..ab96709 100755 (executable)
@@ -124,7 +124,7 @@ last (_pace_ the standard C library conventions for `memcpy()` & al.).
 explicitly, it should contains either a `default:;` at its end or a
 `default:` label that obviously crashes.
 #### Classes
-1. Define only POD structures with `struct`.
+1. Define POD structures with `struct`.
 1. Don't use `this->` in (non-static) member functions.
 1. Define accessor and mutator member functions (implicitly) inline in the
 class, after constructors and assignments.  Don't needlessly define
index f10ff76..f4757e9 100644 (file)
@@ -178,13 +178,15 @@ as function calls.  The semantic analysis phase of the compiler performs
 local rewrites of the parse tree once it can be disambiguated by symbols
 and types.
 
-Formally speaking, this parser is based on recursive descent with localized
-backtracking.  It is not generated as a table or code from a specification
-of the Fortran grammar; rather, it _is_ the grammar, as declaratively
-respecified in C++ constant expressions using a small collection of basic
-token recognition objects and a library of "parser combinator" template
-functions that compose them to form more complicated recognizers and
-their correspondences to the construction of parse tree values.
+Formally speaking, this parser is based on recursive descent with
+localized backtracking (specifically, it will not backtrack into a
+successful reduction to try its other alternatives).  It is not generated
+as a table or code from a specification of the Fortran grammar; rather, it
+_is_ the grammar, as declaratively respecified in C++ constant expressions
+using a small collection of basic token recognition objects and a library
+of "parser combinator" template functions that compose them to form more
+complicated recognizers and their correspondences to the construction
+of parse tree values.
 
 Unparsing
 ---------
index ea40df7..3d76cf0 100644 (file)
@@ -91,10 +91,10 @@ struct ControlEditDesc {
   ControlEditDesc(ControlEditDesc &&) = default;
   ControlEditDesc &operator=(ControlEditDesc &&) = default;
   explicit ControlEditDesc(Kind k) : kind{k} {}
-  ControlEditDesc(Kind k, int ct) : kind{k}, count{ct} {}
-  ControlEditDesc(int ct, Kind k) : kind{k}, count{ct} {}
+  ControlEditDesc(Kind k, std::int64_t ct) : kind{k}, count{ct} {}
+  ControlEditDesc(std::int64_t ct, Kind k) : kind{k}, count{ct} {}
   Kind kind;
-  int count{1};  // r, k, or n
+  std::int64_t count{1};  // r, k, or n
 };
 
 // R1304 format-item ->
@@ -107,10 +107,10 @@ struct FormatItem {
   FormatItem(FormatItem &&) = default;
   FormatItem &operator=(FormatItem &&) = default;
   template<typename A>
-  FormatItem(std::optional<int> &&r, A &&x)
+  FormatItem(std::optional<std::uint64_t> &&r, A &&x)
     : repeatCount{std::move(r)}, u{std::move(x)} {}
   template<typename A> explicit FormatItem(A &&x) : u{std::move(x)} {}
-  std::optional<int> repeatCount;
+  std::optional<std::uint64_t> repeatCount;
   std::variant<IntrinsicTypeDataEditDesc, DerivedTypeDataEditDesc,
       ControlEditDesc, std::string, std::list<FormatItem>>
       u;
index 5b221cd..f02fa0c 100644 (file)
@@ -159,7 +159,7 @@ template<typename PA> inline constexpr auto indirect(const PA &p) {
 
 // R711 digit-string -> digit [digit]...
 // N.B. not a token -- no space is skipped
-constexpr auto digitString = DigitString{};
+constexpr DigitString digitString;
 
 // statement(p) parses Statement<P> for some statement type P that is the
 // result type of the argument parser p, while also handling labels and
@@ -707,17 +707,7 @@ TYPE_PARSER(construct<KindSelector>{}(
 
 // R710 signed-digit-string -> [sign] digit-string
 // N.B. Not a complete token -- no space is skipped.
-static inline std::int64_t negate(std::uint64_t &&n) {
-  return -n;  // TODO: check for overflow
-}
-
-static inline std::int64_t castToSigned(std::uint64_t &&n) {
-  return n;  // TODO: check for overflow
-}
-
-constexpr auto signedDigitString = "-"_ch >>
-        applyFunction(negate, digitString) ||
-    maybe("+"_ch) >> applyFunction(castToSigned, digitString);
+constexpr SignedDigitString signedDigitString;
 
 // R707 signed-int-literal-constant -> [sign] int-literal-constant
 TYPE_PARSER(space >> sourced(construct<SignedIntLiteralConstant>{}(
@@ -3081,11 +3071,7 @@ constexpr auto formatItems =
     nonemptySeparated(space >> Parser<format::FormatItem>{}, maybe(","_tok));
 
 // R1306 r -> digit-string
-static inline int castU64ToInt(std::uint64_t &&n) {
-  return n;  // TODO: check for overflow
-}
-
-constexpr auto repeat = space >> applyFunction(castU64ToInt, digitString);
+constexpr auto repeat = space >> digitString;
 
 // R1304 format-item ->
 //         [r] data-edit-desc | control-edit-desc | char-string-edit-desc |
@@ -3177,11 +3163,8 @@ TYPE_PARSER("D"_ch >> "T"_ch >>
         defaulted(parenthesized(nonemptyList(space >> signedDigitString)))))
 
 // R1314 k -> [sign] digit-string
-static inline int castS64ToInt(std::int64_t &&n) {
-  return n;  // TODO: check for overflow
-}
-constexpr auto scaleFactor = space >>
-    applyFunction(castS64ToInt, signedDigitString);
+constexpr auto count = space >> DigitStringAsPositive{};
+constexpr auto scaleFactor = count;
 
 // R1313 control-edit-desc ->
 //         position-edit-desc | [r] / | : | sign-edit-desc | k P |
@@ -3196,8 +3179,8 @@ TYPE_PARSER(construct<format::ControlEditDesc>{}("T"_ch >>
                     ("L"_ch >> pure(format::ControlEditDesc::Kind::TL) ||
                         "R"_ch >> pure(format::ControlEditDesc::Kind::TR) ||
                         pure(format::ControlEditDesc::Kind::T)),
-                repeat) ||
-    construct<format::ControlEditDesc>{}(repeat,
+                count) ||
+    construct<format::ControlEditDesc>{}(count,
         "X"_ch >> pure(format::ControlEditDesc::Kind::X) ||
             "/"_ch >> pure(format::ControlEditDesc::Kind::Slash)) ||
     construct<format::ControlEditDesc>{}(
index 2e2094a..c88fd54 100644 (file)
@@ -457,6 +457,49 @@ constexpr struct SkipDigitString {
   }
 } skipDigitString;
 
+struct DigitStringAsPositive {
+  using resultType = std::int64_t;
+  static std::optional<std::int64_t> Parse(ParseState *state) {
+    Location at{state->GetLocation()};
+    std::optional<std::uint64_t> x{DigitString{}.Parse(state)};
+    if (!x.has_value()) {
+      return {};
+    }
+    if (*x > std::numeric_limits<std::int64_t>::max()) {
+      state->Say(at, "overflow in positive decimal literal"_err_en_US);
+    }
+    std::int64_t value = *x;
+    return {value};
+  }
+};
+
+struct SignedDigitString {
+  using resultType = std::int64_t;
+  static std::optional<std::int64_t> Parse(ParseState *state) {
+    std::optional<const char *> sign{state->PeekAtNextChar()};
+    if (!sign.has_value()) {
+      return {};
+    }
+    bool negate{**sign == '-'};
+    if (negate || **sign == '+') {
+      state->UncheckedAdvance();
+    }
+    std::optional<std::uint64_t> x{DigitString{}.Parse(state)};
+    if (!x.has_value()) {
+      return {};
+    }
+    std::uint64_t limit{std::numeric_limits<std::int64_t>::max()};
+    if (negate) {
+      limit = -(limit + 1);
+    }
+    if (*x > limit) {
+      state->Say(*sign, "overflow in signed decimal literal"_err_en_US);
+    }
+    std::int64_t value = *x;
+    return {negate ? -value : value};
+  }
+};
+
 // Legacy feature: Hollerith literal constants
 struct HollerithLiteral {
   using resultType = std::string;