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
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
---------
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 ->
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;
// 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
// 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>{}(
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 |
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 |
("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>{}(
}
} 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;