[flang] Fix tokenization of signed-int-literal-constant, allow internal space.

Original-commit: flang-compiler/f18@afa6425b48
Reviewed-on: https://github.com/flang-compiler/f18/pull/90
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-05-15 16:37:47 -07:00
parent 51e63799fd
commit 454f909cbc
2 changed files with 54 additions and 44 deletions

View file

@ -481,8 +481,8 @@ TYPE_PARSER(construct<KindSelector>(
construct<KindSelector::StarSize>("*" >> digitString / spaceCheck))))
// R707 signed-int-literal-constant -> [sign] int-literal-constant
TYPE_PARSER(space >> sourced(construct<SignedIntLiteralConstant>(
signedDigitString, maybe(underscore >> kindParam))))
TYPE_PARSER(sourced(construct<SignedIntLiteralConstant>(
SignedIntLiteralConstantWithoutKind{}, maybe(underscore >> kindParam))))
// R708 int-literal-constant -> digit-string [_ kind-param]
// The negated look-ahead for a trailing underscore prevents misrecognition
@ -495,9 +495,11 @@ TYPE_PARSER(construct<KindParam>(digitString) ||
construct<KindParam>(scalar(integer(constant(name)))))
// R712 sign -> + | -
// Not a complete token.
constexpr auto sign = "+"_ch >> pure(Sign::Positive) ||
"-"_ch >> pure(Sign::Negative);
// N.B. A sign constitutes a whole token, so a space is allowed in free form
// after the sign and before a real-literal-constant or
// complex-literal-constant. A sign is not a unary operator in these contexts.
constexpr auto sign = "+"_tok >> pure(Sign::Positive) ||
"-"_tok >> pure(Sign::Negative);
// R713 signed-real-literal-constant -> [sign] real-literal-constant
constexpr auto signedRealLiteralConstant = space >>
@ -512,7 +514,7 @@ constexpr auto signedRealLiteralConstant = space >>
// R717 exponent -> signed-digit-string
// N.B. Preceding space is not skipped.
constexpr auto exponentPart =
("ed"_ch || extension("q"_ch)) >> signedDigitString;
("ed"_ch || extension("q"_ch)) >> SignedDigitString{};
TYPE_CONTEXT_PARSER("REAL literal constant"_en_US,
construct<RealLiteralConstant>(
@ -532,7 +534,7 @@ TYPE_CONTEXT_PARSER("COMPLEX literal constant"_en_US,
// PGI/Intel extension: signed complex literal constant
TYPE_PARSER(construct<SignedComplexLiteralConstant>(
space >> sign, Parser<ComplexLiteralConstant>{}))
sign, Parser<ComplexLiteralConstant>{}))
// R719 real-part ->
// signed-int-literal-constant | signed-real-literal-constant |

View file

@ -446,9 +446,47 @@ constexpr struct SkipDigitString {
}
} skipDigitString;
// R707 signed-int-literal-constant -> [sign] int-literal-constant
// N.B. Spaces are consumed before and after the sign, since the sign
// and the int-literal-constant are distinct tokens. Does not
// handle a trailing kind parameter.
static inline constexpr std::optional<std::int64_t> SignedInteger(
const std::optional<std::uint64_t> &x, Location at, bool negate,
ParseState &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(at, "overflow in signed decimal literal"_err_en_US);
}
std::int64_t value = *x;
return {negate ? -value : value};
}
struct SignedIntLiteralConstantWithoutKind {
using resultType = std::int64_t;
static std::optional<std::int64_t> Parse(ParseState &state) {
Location at{state.GetLocation()};
static constexpr auto minus = attempt("-"_tok);
static constexpr auto plus = maybe("+"_tok);
bool negate{false};
if (minus.Parse(state)) {
negate = true;
} else if (!plus.Parse(state)) {
return {};
}
return SignedInteger(digitString.Parse(state), at, negate, state);
}
};
// R710 signed-digit-string -> [sign] digit-string
// N.B. Not a complete token -- no space is skipped.
constexpr struct SignedDigitString {
// Used only in the exponent parts of real literal constants.
struct SignedDigitString {
using resultType = std::int64_t;
static std::optional<std::int64_t> Parse(ParseState &state) {
std::optional<const char *> sign{state.PeekAtNextChar()};
@ -459,21 +497,9 @@ constexpr struct SignedDigitString {
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};
return SignedInteger(digitString.Parse(state), *sign, negate, state);
}
} signedDigitString;
};
// Variants of the above for use in FORMAT specifications, where spaces
// must be ignored.
@ -510,15 +536,8 @@ struct PositiveDigitStringIgnoreSpaces {
using resultType = std::int64_t;
static std::optional<std::int64_t> Parse(ParseState &state) {
Location at{state.GetLocation()};
std::optional<std::uint64_t> x{DigitStringIgnoreSpaces{}.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};
return SignedInteger(
DigitStringIgnoreSpaces{}.Parse(state), at, false /*positive*/, state);
}
};
@ -531,19 +550,8 @@ struct SignedDigitStringIgnoreSpaces {
negate = **sign == '-';
}
Location at{state.GetLocation()};
std::optional<std::uint64_t> x{DigitStringIgnoreSpaces{}.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(at, "overflow in signed decimal literal"_err_en_US);
}
std::int64_t value = *x;
return {negate ? -value : value};
return SignedInteger(
DigitStringIgnoreSpaces{}.Parse(state), at, negate, state);
}
};