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/Common/idioms.h"
18#include "flang/Parser/char-set.h"
19#include "flang/Parser/characters.h"
20#include "flang/Parser/instrumented-parser.h"
21#include "flang/Parser/provenance.h"
37 using resultType =
const char *;
40 std::optional<const char *> Parse(
ParseState &state)
const {
41 if (std::optional<const char *> at{state.PeekAtNextChar()}) {
43 state.UncheckedAdvance();
44 state.set_anyTokenMatched();
56constexpr AnyOfChars operator""_ch(
const char str[], std::size_t n) {
60constexpr auto letter{
"abcdefghijklmnopqrstuvwxyz"_ch};
61constexpr auto digit{
"0123456789"_ch};
67 static std::optional<Success> Parse(
ParseState &state) {
68 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
72 state.UncheckedAdvance();
82 if (!state.inFixedForm()) {
84 LanguageFeature::OptionalFreeFormSpace,
"missing space"_port_en_US);
91 static std::optional<Success> Parse(
ParseState &state) {
92 if (std::optional<const char *> p{state.PeekAtNextChar()}) {
95 state.UncheckedAdvance();
96 return space.Parse(state);
98 if (IsLegalInIdentifier(ch)) {
118template <
bool MandatoryFreeFormSpace = false,
bool MustBeComplete = false>
124 : str_{str}, bytes_{n} {}
126 std::optional<Success> Parse(
ParseState &state)
const {
128 const char *start{state.GetLocation()};
130 std::optional<const char *> at;
131 for (std::size_t j{0}; j < bytes_ && *p !=
'\0'; ++j, ++p) {
132 bool spaceSkipping{*p ==
' '};
134 if (j + 1 == bytes_ || p[1] ==
' ' || p[1] ==
'\0') {
139 at = nextCh.Parse(state);
146 at = nextCh.Parse(state);
150 }
else if constexpr (MandatoryFreeFormSpace) {
154 }
else if (**at == ToLowerCaseLetter(*p)) {
161 if constexpr (MustBeComplete) {
162 if (
auto after{state.PeekAtNextChar()}) {
163 if (IsLegalInIdentifier(**after)) {
169 state.set_anyTokenMatched();
170 if (IsLegalInIdentifier(p[-1])) {
171 return spaceCheck.Parse(state);
173 return space.Parse(state);
178 const char *
const str_;
179 const std::size_t bytes_{std::string::npos};
186constexpr TokenStringMatch<true>
operator""_sptok(
187 const char str[], std::size_t n) {
191constexpr TokenStringMatch<false, true>
operator""_id(
192 const char str[], std::size_t n) {
197inline constexpr std::enable_if_t<std::is_class_v<PA>,
198 SequenceParser<TokenStringMatch<>, PA>>
199operator>>(
const char *str,
const PA &p) {
200 return SequenceParser<TokenStringMatch<>, PA>{TokenStringMatch<>{str}, p};
204inline constexpr std::enable_if_t<std::is_class_v<PA>,
205 FollowParser<PA, TokenStringMatch<>>>
206operator/(
const PA &p,
const char *str) {
207 return FollowParser<PA, TokenStringMatch<>>{p, TokenStringMatch<>{str}};
210template <
class PA>
inline constexpr auto parenthesized(
const PA &p) {
211 return "(" >> p /
")";
214template <
class PA>
inline constexpr auto bracketed(
const PA &p) {
215 return "[" >> p /
"]";
218template <
class PA>
inline constexpr auto braced(
const PA &p) {
219 return "{" >> p /
"}";
224 using resultType = std::pair<char,
bool >;
225 static std::optional<resultType> Parse(
ParseState &state) {
226 auto at{state.GetLocation()};
227 if (std::optional<const char *> cp{nextCh.Parse(state)}) {
230 state.Say(
CharBlock{at, state.GetLocation()},
231 "Unclosed character constant"_err_en_US);
237 if (std::optional<const char *> next{state.PeekAtNextChar()}) {
238 char escaped{**next};
239 if (escaped ==
'\'' || escaped ==
'"' || escaped ==
'\\') {
240 state.UncheckedAdvance();
241 return std::make_pair(escaped,
true);
245 return std::make_pair(ch,
false);
252 using resultType = std::string;
253 static std::optional<std::string> Parse(
ParseState &state) {
256 while (
auto ch{nextch.Parse(state)}) {
259 }
else if (ch->first == quote) {
261 if (!doubled.Parse(state)) {
275 using resultType = std::string;
276 static std::optional<resultType> Parse(
ParseState &state) {
278 auto baseChar{[&base](
char ch) ->
bool {
294 const char *start{state.GetLocation()};
295 std::optional<const char *> at{nextCh.Parse(state)};
300 !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
301 "nonstandard BOZ literal"_port_en_US)) {
304 if (baseChar(**at)) {
305 at = nextCh.Parse(state);
312 if (quote !=
'\'' && quote !=
'"') {
318 at = nextCh.Parse(state);
328 if (!IsHexadecimalDigit(**at)) {
331 content += ToLowerCaseLetter(**at);
336 if (!(at = nextCh.Parse(state)) || !baseChar(**at) ||
337 !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
338 "nonstandard BOZ literal"_port_en_US)) {
341 spaceCheck.Parse(state);
344 if (content.empty()) {
345 state.Say(start,
"no digit in BOZ literal"_err_en_US);
348 return {std::string{base} +
'"' + content +
'"'};
356 static std::optional<resultType> Parse(
ParseState &state) {
357 if (std::optional<const char *> ch1{state.PeekAtNextChar()}) {
358 if (IsDecimalDigit(**ch1)) {
359 state.UncheckedAdvance();
360 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
361 if (!IsDecimalDigit(**p)) {
364 state.UncheckedAdvance();
366 return CharBlock{*ch1, state.GetLocation()};
376 static std::optional<resultType> Parse(
ParseState &state) {
378 static constexpr auto sign{maybe(
"+-"_ch / space)};
379 if (sign.Parse(state)) {
380 if (
auto digits{digitString.Parse(state)}) {
381 result.ExtendToCover(*digits);
390 using resultType = std::uint64_t;
391 static std::optional<std::uint64_t> Parse(
ParseState &state) {
392 std::optional<const char *> firstDigit{digit.Parse(state)};
396 std::uint64_t value = **firstDigit -
'0';
397 bool overflow{
false};
398 static constexpr auto getDigit{attempt(digit)};
399 while (
auto nextDigit{getDigit.Parse(state)}) {
400 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
404 int digitValue = **nextDigit -
'0';
405 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
411 state.Say(*firstDigit,
"overflow in decimal literal"_err_en_US);
422static std::optional<std::int64_t> SignedInteger(
423 const std::optional<std::uint64_t> &x, Location at,
bool negate,
428 std::uint64_t limit{std::numeric_limits<std::int64_t>::max()};
430 limit = -(limit + 1);
433 state.Say(at,
"overflow in signed decimal literal"_err_en_US);
435 std::int64_t value = *x;
436 return std::make_optional<std::int64_t>(negate ? -value : value);
443 using resultType = std::int64_t;
444 static std::optional<std::int64_t> Parse(
ParseState &state) {
445 std::optional<const char *> sign{state.PeekAtNextChar()};
449 bool negate{**sign ==
'-'};
450 if (negate || **sign ==
'+') {
451 state.UncheckedAdvance();
453 return SignedInteger(digitString64.Parse(state), *sign, negate, state);
460 using resultType = std::uint64_t;
461 static std::optional<std::uint64_t> Parse(
ParseState &state) {
462 static constexpr auto getFirstDigit{space >> digit};
463 std::optional<const char *> firstDigit{getFirstDigit.Parse(state)};
467 std::uint64_t value = **firstDigit -
'0';
468 bool overflow{
false};
469 static constexpr auto getDigit{space >> attempt(digit)};
470 while (
auto nextDigit{getDigit.Parse(state)}) {
471 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
475 int digitValue = **nextDigit -
'0';
476 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
482 state.Say(*firstDigit,
"overflow in decimal literal"_err_en_US);
489 using resultType = std::int64_t;
490 static std::optional<std::int64_t> Parse(
ParseState &state) {
491 Location at{state.GetLocation()};
492 return SignedInteger(
498 using resultType = std::int64_t;
499 static std::optional<std::int64_t> Parse(
ParseState &state) {
500 static constexpr auto getSign{space >> attempt(
"+-"_ch)};
502 if (std::optional<const char *> sign{getSign.Parse(state)}) {
503 negate = **sign ==
'-';
505 Location at{state.GetLocation()};
506 return SignedInteger(
513 using resultType = std::string;
514 static std::optional<std::string> Parse(
ParseState &state) {
516 const char *start{state.GetLocation()};
517 std::optional<std::uint64_t> charCount{
519 if (!charCount || *charCount < 1) {
522 static constexpr auto letterH{
"h"_ch};
523 std::optional<const char *> h{letterH.Parse(state)};
528 for (
auto j{*charCount}; j-- > 0;) {
529 int chBytes{UTF_8CharacterBytes(state.GetLocation())};
530 for (
int bytes{chBytes}; bytes > 0; --bytes) {
531 if (std::optional<const char *> at{nextCh.Parse(state)}) {
532 if (chBytes == 1 && !IsPrintable(**at)) {
533 state.Say(start,
"Bad character in Hollerith"_err_en_US);
538 state.Say(start,
"Insufficient characters in Hollerith"_err_en_US);
550 static inline std::optional<Success> Parse(
ParseState &state) {
551 if (state.IsAtEnd()) {
563 static std::optional<Success> Parse(
ParseState &state) {
564 while (std::optional<const char *> p{state.GetNextChar()}) {
567 }
else if (**p ==
'\n') {
579 static std::optional<Success> Parse(
ParseState &state) {
580 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
583 }
else if (**p ==
'\n') {
586 state.UncheckedAdvance();
597 static std::optional<Success> Parse(
ParseState &state) {
599 while (std::optional<const char *> p{state.GetNextChar()}) {
604 }
else if (**p == left) {
606 }
else if (**p ==
'\n') {
620template <
typename PA>
inline constexpr auto optionalBeforeColons(
const PA &p) {
621 using resultType = std::optional<typename PA::resultType>;
622 return "," >> construct<resultType>(p) /
"::" ||
623 (
"::"_tok || !
","_tok) >> pure<resultType>();
625template <
typename PA>
626inline constexpr auto optionalListBeforeColons(
const PA &p) {
627 using resultType = std::list<typename PA::resultType>;
628 return "," >> nonemptyList(p) /
"::" ||
629 (
"::"_tok || !
","_tok) >> pure<resultType>();
638 static std::optional<Success> Parse(
ParseState &state) {
639 if (
UserState * ustate{state.userState()}) {
643 if (!ustate->instrumentedParse()) {
648 while (std::optional<const char *> at{state.PeekAtNextChar()}) {
649 if (**at ==
'\n' || **at ==
' ') {
650 state.UncheckedAdvance();
651 }
else if (**at ==
'!') {
652 static const char fixed[] =
"!dir$ fixed\n", free[] =
"!dir$ free\n";
653 static constexpr std::size_t fixedBytes{
sizeof fixed - 1};
654 static constexpr std::size_t freeBytes{
sizeof free - 1};
655 std::size_t remain{state.BytesRemaining()};
656 if (remain >= fixedBytes && std::memcmp(*at, fixed, fixedBytes) == 0) {
657 state.set_inFixedForm(
true).UncheckedAdvance(fixedBytes);
658 }
else if (remain >= freeBytes &&
659 std::memcmp(*at, free, freeBytes) == 0) {
660 state.set_inFixedForm(
false).UncheckedAdvance(freeBytes);
664 }
else if (**at ==
';' &&
665 state.IsNonstandardOk(
666 LanguageFeature::EmptyStatement,
"empty statement"_port_en_US)) {
667 state.UncheckedAdvance();
678constexpr auto underscore{
"_"_ch};
686constexpr auto otherIdChar{underscore / !
"'\""_ch ||
687 extension<LanguageFeature::PunctuationInNames>(
688 "nonstandard usage: punctuation in name"_port_en_US,
"$@"_ch)};
690constexpr auto logicalTRUE{
692 extension<LanguageFeature::LogicalAbbreviations>(
693 "nonstandard usage: .T. spelling of .TRUE."_port_en_US,
696constexpr auto logicalFALSE{
698 extension<LanguageFeature::LogicalAbbreviations>(
699 "nonstandard usage: .F. spelling of .FALSE."_port_en_US,
704constexpr auto rawHollerithLiteral{
705 deprecated<LanguageFeature::Hollerith>(HollerithLiteral{})};
707template <
typename A>
constexpr decltype(
auto) verbatim(A x) {
708 return sourced(construct<Verbatim>(x));
Definition: token-parsers.h:35
Definition: char-block.h:28
Definition: message.h:160
Definition: parse-state.h:35
Definition: instrumented-parser.h:25
Definition: user-state.h:33
Definition: token-parsers.h:119
Definition: user-state.h:35
Definition: check-expression.h:19
Definition: token-parsers.h:274
Definition: token-parsers.h:223
Definition: token-parsers.h:251
Definition: token-parsers.h:389
Definition: token-parsers.h:459
Definition: token-parsers.h:354
Definition: token-parsers.h:512
Definition: token-parsers.h:488
Definition: char-set.h:23
Definition: token-parsers.h:497
Definition: token-parsers.h:442
Definition: token-parsers.h:374
Definition: token-parsers.h:593
Definition: token-parsers.h:559
Definition: token-parsers.h:636
Definition: token-parsers.h:575
Definition: token-parsers.h:88
Definition: token-parsers.h:64