9#ifndef FORTRAN_PARSER_TOKEN_PARSERS_H_
10#define FORTRAN_PARSER_TOKEN_PARSERS_H_
15#include "basic-parsers.h"
16#include "type-parsers.h"
17#include "flang/Parser/char-set.h"
18#include "flang/Parser/characters.h"
19#include "flang/Parser/instrumented-parser.h"
34 using resultType =
const char *;
35 constexpr AnyOfChars(
const AnyOfChars &) =
default;
36 constexpr AnyOfChars(
SetOfChars set) : set_{set} {}
37 std::optional<const char *> Parse(
ParseState &state)
const {
38 if (std::optional<const char *> at{state.PeekAtNextChar()}) {
40 state.UncheckedAdvance();
41 state.set_anyTokenMatched();
53constexpr AnyOfChars operator""_ch(
const char str[], std::size_t n) {
57constexpr auto letter{
"abcdefghijklmnopqrstuvwxyz"_ch};
58constexpr auto digit{
"0123456789"_ch};
64 static std::optional<Success> Parse(
ParseState &state) {
65 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
69 state.UncheckedAdvance();
79 if (!state.inFixedForm()) {
81 LanguageFeature::OptionalFreeFormSpace,
"missing space"_port_en_US);
87 constexpr SpaceCheck() {}
88 static std::optional<Success> Parse(
ParseState &state) {
89 if (std::optional<const char *> p{state.PeekAtNextChar()}) {
92 state.UncheckedAdvance();
93 return space.Parse(state);
95 if (IsLegalInIdentifier(ch)) {
115template <
bool MandatoryFreeFormSpace = false,
bool MustBeComplete = false>
116class TokenStringMatch {
119 constexpr TokenStringMatch(
const TokenStringMatch &) =
default;
120 constexpr TokenStringMatch(
const char *str, std::size_t n)
121 : str_{str}, bytes_{n} {}
122 explicit constexpr TokenStringMatch(
const char *str) : str_{str} {}
123 std::optional<Success> Parse(
ParseState &state)
const {
125 const char *start{state.GetLocation()};
127 std::optional<const char *> at;
128 for (std::size_t j{0}; j < bytes_ && *p !=
'\0'; ++j, ++p) {
129 bool spaceSkipping{*p ==
' '};
131 if (j + 1 == bytes_ || p[1] ==
' ' || p[1] ==
'\0') {
136 at = nextCh.Parse(state);
143 at = nextCh.Parse(state);
147 }
else if constexpr (MandatoryFreeFormSpace) {
151 }
else if (**at == ToLowerCaseLetter(*p)) {
158 if constexpr (MustBeComplete) {
159 if (
auto after{state.PeekAtNextChar()}) {
160 if (IsLegalInIdentifier(**after)) {
166 state.set_anyTokenMatched();
167 if (IsLegalInIdentifier(p[-1])) {
168 return spaceCheck.Parse(state);
170 return space.Parse(state);
175 const char *
const str_;
176 const std::size_t bytes_{std::string::npos};
183constexpr TokenStringMatch<true>
operator""_sptok(
184 const char str[], std::size_t n) {
189 const char str[], std::size_t n) {
194inline constexpr std::enable_if_t<std::is_class_v<PA>,
196operator>>(
const char *str,
const PA &p) {
201inline constexpr std::enable_if_t<std::is_class_v<PA>,
203operator/(
const PA &p,
const char *str) {
207template <
class PA>
inline constexpr auto parenthesized(
const PA &p) {
208 return "(" >> p /
")";
211template <
class PA>
inline constexpr auto bracketed(
const PA &p) {
212 return "[" >> p /
"]";
215template <
class PA>
inline constexpr auto braced(
const PA &p) {
216 return "{" >> p /
"}";
221 using resultType = std::pair<char,
bool >;
222 static std::optional<resultType> Parse(
ParseState &state) {
223 auto at{state.GetLocation()};
224 if (std::optional<const char *> cp{nextCh.Parse(state)}) {
227 state.Say(
CharBlock{at, state.GetLocation()},
228 "Unclosed character constant"_err_en_US);
234 if (std::optional<const char *> next{state.PeekAtNextChar()}) {
235 char escaped{**next};
236 if (escaped ==
'\'' || escaped ==
'"' || escaped ==
'\\') {
237 state.UncheckedAdvance();
238 return std::make_pair(escaped,
true);
242 return std::make_pair(ch,
false);
249 using resultType = std::string;
250 static std::optional<std::string> Parse(
ParseState &state) {
253 while (
auto ch{nextch.Parse(state)}) {
256 }
else if (ch->first == quote) {
258 if (!doubled.Parse(state)) {
272 using resultType = std::string;
273 static std::optional<resultType> Parse(
ParseState &state) {
275 auto baseChar{[&base](
char ch) ->
bool {
291 const char *start{state.GetLocation()};
292 std::optional<const char *> at{nextCh.Parse(state)};
297 !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
298 "nonstandard BOZ literal"_port_en_US)) {
301 if (baseChar(**at)) {
302 at = nextCh.Parse(state);
309 if (quote !=
'\'' && quote !=
'"') {
315 at = nextCh.Parse(state);
325 if (!IsHexadecimalDigit(**at)) {
328 content += ToLowerCaseLetter(**at);
333 if (!(at = nextCh.Parse(state)) || !baseChar(**at) ||
334 !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
335 "nonstandard BOZ literal"_port_en_US)) {
338 spaceCheck.Parse(state);
341 if (content.empty()) {
342 state.Say(start,
"no digit in BOZ literal"_err_en_US);
345 return {std::string{base} +
'"' + content +
'"'};
353 static std::optional<resultType> Parse(
ParseState &state) {
354 if (std::optional<const char *> ch1{state.PeekAtNextChar()}) {
355 if (IsDecimalDigit(**ch1)) {
356 state.UncheckedAdvance();
357 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
358 if (!IsDecimalDigit(**p)) {
361 state.UncheckedAdvance();
363 return CharBlock{*ch1, state.GetLocation()};
373 static std::optional<resultType> Parse(
ParseState &state) {
374 resultType result{state.GetLocation()};
375 static constexpr auto sign{maybe(
"+-"_ch / space)};
376 if (sign.Parse(state)) {
377 if (
auto digits{digitString.Parse(state)}) {
378 result.ExtendToCover(*digits);
387 using resultType = std::uint64_t;
388 static std::optional<std::uint64_t> Parse(
ParseState &state) {
389 std::optional<const char *> firstDigit{digit.Parse(state)};
393 std::uint64_t value = **firstDigit -
'0';
394 bool overflow{
false};
395 static constexpr auto getDigit{attempt(digit)};
396 while (
auto nextDigit{getDigit.Parse(state)}) {
397 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
401 int digitValue = **nextDigit -
'0';
402 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
408 state.Say(*firstDigit,
"overflow in decimal literal"_err_en_US);
419static std::optional<std::int64_t> SignedInteger(
420 const std::optional<std::uint64_t> &x, Location at,
bool negate,
425 std::uint64_t limit{std::numeric_limits<std::int64_t>::max()};
427 limit = -(limit + 1);
430 state.Say(at,
"overflow in signed decimal literal"_err_en_US);
432 std::int64_t value = *x;
433 return std::make_optional<std::int64_t>(negate ? -value : value);
440 using resultType = std::int64_t;
441 static std::optional<std::int64_t> Parse(
ParseState &state) {
442 std::optional<const char *> sign{state.PeekAtNextChar()};
446 bool negate{**sign ==
'-'};
447 if (negate || **sign ==
'+') {
448 state.UncheckedAdvance();
450 return SignedInteger(digitString64.Parse(state), *sign, negate, state);
457 using resultType = std::uint64_t;
458 static std::optional<std::uint64_t> Parse(
ParseState &state) {
459 static constexpr auto getFirstDigit{space >> digit};
460 std::optional<const char *> firstDigit{getFirstDigit.Parse(state)};
464 std::uint64_t value = **firstDigit -
'0';
465 bool overflow{
false};
466 static constexpr auto getDigit{space >> attempt(digit)};
467 while (
auto nextDigit{getDigit.Parse(state)}) {
468 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
472 int digitValue = **nextDigit -
'0';
473 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
479 state.Say(*firstDigit,
"overflow in decimal literal"_err_en_US);
486 using resultType = std::int64_t;
487 static std::optional<std::int64_t> Parse(
ParseState &state) {
488 Location at{state.GetLocation()};
489 return SignedInteger(
495 using resultType = std::int64_t;
496 static std::optional<std::int64_t> Parse(
ParseState &state) {
497 static constexpr auto getSign{space >> attempt(
"+-"_ch)};
499 if (std::optional<const char *> sign{getSign.Parse(state)}) {
500 negate = **sign ==
'-';
502 Location at{state.GetLocation()};
503 return SignedInteger(
510 using resultType = std::string;
511 static std::optional<std::string> Parse(
ParseState &state) {
513 const char *start{state.GetLocation()};
514 std::optional<std::uint64_t> charCount{
516 if (!charCount || *charCount < 1) {
519 static constexpr auto letterH{
"h"_ch};
520 std::optional<const char *> h{letterH.Parse(state)};
525 for (
auto j{*charCount}; j-- > 0;) {
526 int chBytes{UTF_8CharacterBytes(state.GetLocation())};
527 for (
int bytes{chBytes}; bytes > 0; --bytes) {
528 if (std::optional<const char *> at{nextCh.Parse(state)}) {
529 if (chBytes == 1 && !IsPrintable(**at)) {
530 state.Say(start,
"Bad character in Hollerith"_err_en_US);
535 state.Say(start,
"Insufficient characters in Hollerith"_err_en_US);
544struct ConsumedAllInputParser {
546 constexpr ConsumedAllInputParser() {}
547 static inline std::optional<Success> Parse(
ParseState &state) {
548 if (state.IsAtEnd()) {
556template <
char goal>
struct SkipPast {
558 constexpr SkipPast() {}
559 constexpr SkipPast(
const SkipPast &) {}
560 static std::optional<Success> Parse(
ParseState &state) {
561 while (std::optional<const char *> p{state.GetNextChar()}) {
564 }
else if (**p ==
'\n') {
572template <
char goal>
struct SkipTo {
574 constexpr SkipTo() {}
575 constexpr SkipTo(
const SkipTo &) {}
576 static std::optional<Success> Parse(
ParseState &state) {
577 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
580 }
else if (**p ==
'\n') {
583 state.UncheckedAdvance();
590template <
char left,
char right>
struct SkipPastNested {
592 constexpr SkipPastNested() {}
593 constexpr SkipPastNested(
const SkipPastNested &) {}
594 static std::optional<Success> Parse(
ParseState &state) {
596 while (std::optional<const char *> p{state.GetNextChar()}) {
601 }
else if (**p == left) {
603 }
else if (**p ==
'\n') {
617template <
typename PA>
inline constexpr auto optionalBeforeColons(
const PA &p) {
618 using resultType = std::optional<typename PA::resultType>;
619 return "," >> construct<resultType>(p) /
"::" ||
620 (
"::"_tok || !
","_tok) >> pure<resultType>();
622template <
typename PA>
623inline constexpr auto optionalListBeforeColons(
const PA &p) {
624 using resultType = std::list<typename PA::resultType>;
625 return "," >> nonemptyList(p) /
"::" ||
626 (
"::"_tok || !
","_tok) >> pure<resultType>();
635 static std::optional<Success> Parse(
ParseState &state) {
636 if (
UserState * ustate{state.userState()}) {
640 if (!ustate->instrumentedParse()) {
645 while (std::optional<const char *> at{state.PeekAtNextChar()}) {
646 if (**at ==
'\n' || **at ==
' ') {
647 state.UncheckedAdvance();
648 }
else if (**at ==
'!') {
649 static const char fixed[] =
"!dir$ fixed\n", free[] =
"!dir$ free\n";
650 static constexpr std::size_t fixedBytes{
sizeof fixed - 1};
651 static constexpr std::size_t freeBytes{
sizeof free - 1};
652 std::size_t remain{state.BytesRemaining()};
653 if (remain >= fixedBytes && std::memcmp(*at, fixed, fixedBytes) == 0) {
654 state.set_inFixedForm(
true).UncheckedAdvance(fixedBytes);
655 }
else if (remain >= freeBytes &&
656 std::memcmp(*at, free, freeBytes) == 0) {
657 state.set_inFixedForm(
false).UncheckedAdvance(freeBytes);
661 }
else if (**at ==
';' &&
662 state.IsNonstandardOk(
663 LanguageFeature::EmptyStatement,
"empty statement"_port_en_US)) {
664 state.UncheckedAdvance();
675constexpr auto underscore{
"_"_ch};
683constexpr auto otherIdChar{underscore / !
"'\""_ch ||
684 extension<LanguageFeature::PunctuationInNames>(
685 "nonstandard usage: punctuation in name"_port_en_US,
"$@"_ch)};
687constexpr auto logicalTRUE{
689 extension<LanguageFeature::LogicalAbbreviations>(
690 "nonstandard usage: .T. spelling of .TRUE."_port_en_US,
693constexpr auto logicalFALSE{
695 extension<LanguageFeature::LogicalAbbreviations>(
696 "nonstandard usage: .F. spelling of .FALSE."_port_en_US,
701constexpr auto rawHollerithLiteral{
704template <
typename A>
constexpr decltype(
auto) verbatim(A x) {
705 return sourced(construct<Verbatim>(x));
Definition token-parsers.h:32
Definition char-block.h:26
Definition basic-parsers.h:279
Definition parse-state.h:31
Definition instrumented-parser.h:25
Definition basic-parsers.h:256
Definition user-state.h:32
Definition token-parsers.h:116
Definition user-state.h:34
Definition check-expression.h:19
Definition token-parsers.h:271
Definition token-parsers.h:220
Definition token-parsers.h:248
Definition token-parsers.h:386
Definition token-parsers.h:456
Definition token-parsers.h:351
Definition token-parsers.h:509
Definition token-parsers.h:485
Definition token-parsers.h:494
Definition token-parsers.h:439
Definition token-parsers.h:371
Definition token-parsers.h:633
Definition token-parsers.h:85
Definition token-parsers.h:61