FLANG

token-parsers.h
1 //===-- lib/Parser/token-parsers.h ------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef FORTRAN_PARSER_TOKEN_PARSERS_H_
10 #define FORTRAN_PARSER_TOKEN_PARSERS_H_
11
12 // These parsers are driven by the parsers of the Fortran grammar to consume
13 // the prescanned character stream and recognize context-sensitive tokens.
14
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"
22 #include <cctype>
23 #include <cstddef>
24 #include <cstring>
25 #include <functional>
26 #include <limits>
27 #include <list>
28 #include <optional>
29 #include <string>
30
31 namespace Fortran::parser {
32
33 // "xyz"_ch matches one instance of the characters x, y, or z without skipping
34 // any spaces before or after. The parser returns the location of the character
35 // on success.
36 class AnyOfChars {
37 public:
38 using resultType = const char *;
39 constexpr AnyOfChars(const AnyOfChars &) = default;
40 constexpr AnyOfChars(SetOfChars set) : set_{set} {}
41 std::optional<const char *> Parse(ParseState &state) const {
42 if (std::optional<const char *> at{state.PeekAtNextChar()}) {
43 if (set_.Has(**at)) {
44 state.UncheckedAdvance();
45 state.set_anyTokenMatched();
46 return at;
47 }
48 }
49 state.Say(MessageExpectedText{set_});
50 return std::nullopt;
51 }
52
53 private:
54 const SetOfChars set_;
55 };
56
57 constexpr AnyOfChars operator""_ch(const char str[], std::size_t n) {
58 return AnyOfChars{SetOfChars(str, n)};
59 }
60
61 constexpr auto letter{"abcdefghijklmnopqrstuvwxyz"_ch};
62 constexpr auto digit{"0123456789"_ch};
63
64 // Skips over optional spaces. Always succeeds.
65 constexpr struct Space {
66 using resultType = Success;
67 constexpr Space() {}
68 static std::optional<Success> Parse(ParseState &state) {
69 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
70 if (**p != ' ') {
71 break;
72 }
73 state.UncheckedAdvance();
74 }
75 return {Success{}};
76 }
77 } space;
78
79 // Skips a space that in free form requires a warning if it precedes a
80 // character that could begin an identifier or keyword. Always succeeds.
81 inline void MissingSpace(ParseState &state) {
82 if (!state.inFixedForm()) {
83 state.Nonstandard(
84 LanguageFeature::OptionalFreeFormSpace, "missing space"_en_US);
85 }
86 }
87
88 constexpr struct SpaceCheck {
89 using resultType = Success;
90 constexpr SpaceCheck() {}
91 static std::optional<Success> Parse(ParseState &state) {
92 if (std::optional<const char *> p{state.PeekAtNextChar()}) {
93 char ch{**p};
94 if (ch == ' ') {
95 state.UncheckedAdvance();
96 return space.Parse(state);
97 }
98 if (IsLegalInIdentifier(ch)) {
99 MissingSpace(state);
100 }
101 }
102 return {Success{}};
103 }
104 } spaceCheck;
105
106 // Matches a token string. Spaces in the token string denote where
107 // spaces may appear in the source; they can be made mandatory for
108 // some free form keyword sequences. Missing mandatory spaces in free
109 // form elicit a warning; they are not necessary for recognition.
110 // Spaces before and after the token are also skipped.
111 //
112 // Token strings appear in the grammar as C++ user-defined literals
113 // like "BIND ( C )"_tok and "SYNC ALL"_sptok. The _tok suffix is implied
114 // when a string literal appears before the sequencing operator >> or
115 // after the sequencing operator /. The literal "..."_id parses a
116 // token that cannot be a prefix of a longer identifier.
117 template <bool MandatoryFreeFormSpace = false, bool MustBeComplete = false>
118 class TokenStringMatch {
119 public:
120 using resultType = Success;
121 constexpr TokenStringMatch(const TokenStringMatch &) = default;
122 constexpr TokenStringMatch(const char *str, std::size_t n)
123 : str_{str}, bytes_{n} {}
124 explicit constexpr TokenStringMatch(const char *str) : str_{str} {}
125 std::optional<Success> Parse(ParseState &state) const {
126 space.Parse(state);
127 const char *start{state.GetLocation()};
128 const char *p{str_};
129 std::optional<const char *> at; // initially empty
130 for (std::size_t j{0}; j < bytes_ && *p != '\0'; ++j, ++p) {
131 bool spaceSkipping{*p == ' '};
132 if (spaceSkipping) {
133 if (j + 1 == bytes_ || p[1] == ' ' || p[1] == '\0') {
134 continue; // redundant; ignore
135 }
136 }
137 if (!at) {
138 at = nextCh.Parse(state);
139 if (!at) {
140 return std::nullopt;
141 }
142 }
143 if (spaceSkipping) {
144 if (**at == ' ') {
145 at = nextCh.Parse(state);
146 if (!at) {
147 return std::nullopt;
148 }
149 } else if constexpr (MandatoryFreeFormSpace) {
150 MissingSpace(state);
151 }
152 // 'at' remains full for next iteration
153 } else if (**at == ToLowerCaseLetter(*p)) {
154 at.reset();
155 } else {
156 state.Say(start, MessageExpectedText{str_, bytes_});
157 return std::nullopt;
158 }
159 }
160 if constexpr (MustBeComplete) {
161 if (auto after{state.PeekAtNextChar()}) {
162 if (IsLegalInIdentifier(**after)) {
163 state.Say(start, MessageExpectedText{str_, bytes_});
164 return std::nullopt;
165 }
166 }
167 }
168 state.set_anyTokenMatched();
169 if (IsLegalInIdentifier(p[-1])) {
170 return spaceCheck.Parse(state);
171 } else {
172 return space.Parse(state);
173 }
174 }
175
176 private:
177 const char *const str_;
178 const std::size_t bytes_{std::string::npos};
179 };
180
181 constexpr TokenStringMatch<> operator""_tok(const char str[], std::size_t n) {
182 return {str, n};
183 }
184
185 constexpr TokenStringMatch<true> operator""_sptok(
186 const char str[], std::size_t n) {
187 return {str, n};
188 }
189
190 constexpr TokenStringMatch<false, true> operator""_id(
191 const char str[], std::size_t n) {
192 return {str, n};
193 }
194
195 template <class PA>
196 inline constexpr std::enable_if_t<std::is_class_v<PA>,
197 SequenceParser<TokenStringMatch<>, PA>>
198 operator>>(const char *str, const PA &p) {
199 return SequenceParser<TokenStringMatch<>, PA>{TokenStringMatch<>{str}, p};
200 }
201
202 template <class PA>
203 inline constexpr std::enable_if_t<std::is_class_v<PA>,
204 FollowParser<PA, TokenStringMatch<>>>
205 operator/(const PA &p, const char *str) {
206 return FollowParser<PA, TokenStringMatch<>>{p, TokenStringMatch<>{str}};
207 }
208
209 template <class PA> inline constexpr auto parenthesized(const PA &p) {
210 return "(" >> p / ")";
211 }
212
213 template <class PA> inline constexpr auto bracketed(const PA &p) {
214 return "[" >> p / "]";
215 }
216
217 // Quoted character literal constants.
218 struct CharLiteralChar {
219 using resultType = std::pair<char, bool /* was escaped */>;
220 static std::optional<resultType> Parse(ParseState &state) {
221 auto at{state.GetLocation()};
222 if (std::optional<const char *> cp{nextCh.Parse(state)}) {
223 char ch{**cp};
224 if (ch == '\n') {
225 state.Say(CharBlock{at, state.GetLocation()},
226 "Unclosed character constant"_err_en_US);
227 return std::nullopt;
228 }
229 if (ch == '\\') {
230 // Most escape sequences in character literals are processed later,
231 // but we have to look for quotes here so that doubled quotes work.
232 if (std::optional<const char *> next{state.PeekAtNextChar()}) {
233 char escaped{**next};
234 if (escaped == '\'' || escaped == '"' || escaped == '\\') {
235 state.UncheckedAdvance();
236 return std::make_pair(escaped, true);
237 }
238 }
239 }
240 return std::make_pair(ch, false);
241 }
242 return std::nullopt;
243 }
244 };
245
246 template <char quote> struct CharLiteral {
247 using resultType = std::string;
248 static std::optional<std::string> Parse(ParseState &state) {
249 std::string str;
250 static constexpr auto nextch{attempt(CharLiteralChar{})};
251 while (auto ch{nextch.Parse(state)}) {
252 if (ch->second) {
253 str += '\\';
254 } else if (ch->first == quote) {
255 static constexpr auto doubled{attempt(AnyOfChars{SetOfChars{quote}})};
256 if (!doubled.Parse(state)) {
257 return str;
258 }
259 }
260 str += ch->first;
261 }
262 return std::nullopt;
263 }
264 };
265
266 // Parse "BOZ" binary literal quoted constants.
267 // As extensions, support X as an alternate hexadecimal marker, and allow
268 // BOZX markers to appear as suffixes.
269 struct BOZLiteral {
270 using resultType = std::string;
271 static std::optional<resultType> Parse(ParseState &state) {
272 char base{'\0'};
273 auto baseChar{[&base](char ch) -> bool {
274 switch (ch) {
275 case 'b':
276 case 'o':
277 case 'z':
278 base = ch;
279 return true;
280 case 'x':
281 base = 'z';
282 return true;
283 default:
284 return false;
285 }
286 }};
287
288 space.Parse(state);
289 const char *start{state.GetLocation()};
290 std::optional<const char *> at{nextCh.Parse(state)};
291 if (!at) {
292 return std::nullopt;
293 }
294 if (**at == 'x' &&
295 !state.IsNonstandardOk(
296 LanguageFeature::BOZExtensions, "nonstandard BOZ literal"_en_US)) {
297 return std::nullopt;
298 }
299 if (baseChar(**at)) {
300 at = nextCh.Parse(state);
301 if (!at) {
302 return std::nullopt;
303 }
304 }
305
306 char quote = **at;
307 if (quote != '\'' && quote != '"') {
308 return std::nullopt;
309 }
310
311 std::string content;
312 while (true) {
313 at = nextCh.Parse(state);
314 if (!at) {
315 return std::nullopt;
316 }
317 if (**at == quote) {
318 break;
319 }
320 if (**at == ' ') {
321 continue;
322 }
323 if (!IsHexadecimalDigit(**at)) {
324 return std::nullopt;
325 }
326 content += ToLowerCaseLetter(**at);
327 }
328
329 if (!base) {
330 // extension: base allowed to appear as suffix, too
331 if (!(at = nextCh.Parse(state)) || !baseChar(**at) ||
332 !state.IsNonstandardOk(LanguageFeature::BOZExtensions,
333 "nonstandard BOZ literal"_en_US)) {
334 return std::nullopt;
335 }
336 spaceCheck.Parse(state);
337 }
338
339 if (content.empty()) {
340 state.Say(start, "no digit in BOZ literal"_err_en_US);
341 return std::nullopt;
342 }
343 return {std::string{base} + '"' + content + '"'};
344 }
345 };
346
347 // R711 digit-string -> digit [digit]...
348 // N.B. not a token -- no space is skipped
349 constexpr struct DigitString {
350 using resultType = CharBlock;
351 static std::optional<resultType> Parse(ParseState &state) {
352 if (std::optional<const char *> ch1{state.PeekAtNextChar()}) {
353 if (IsDecimalDigit(**ch1)) {
354 state.UncheckedAdvance();
355 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
356 if (!IsDecimalDigit(**p)) {
357 break;
358 }
359 state.UncheckedAdvance();
360 }
361 return CharBlock{*ch1, state.GetLocation()};
362 }
363 }
364 return std::nullopt;
365 }
366 } digitString;
367
368 struct SignedIntLiteralConstantWithoutKind {
369 using resultType = CharBlock;
370 static std::optional<resultType> Parse(ParseState &state) {
371 resultType result{state.GetLocation()};
372 static constexpr auto sign{maybe("+-"_ch / space)};
373 if (sign.Parse(state)) {
374 if (auto digits{digitString.Parse(state)}) {
375 result.ExtendToCover(*digits);
376 return result;
377 }
378 }
379 return std::nullopt;
380 }
381 };
382
383 constexpr struct DigitString64 {
384 using resultType = std::uint64_t;
385 static std::optional<std::uint64_t> Parse(ParseState &state) {
386 std::optional<const char *> firstDigit{digit.Parse(state)};
387 if (!firstDigit) {
388 return std::nullopt;
389 }
390 std::uint64_t value = **firstDigit - '0';
391 bool overflow{false};
392 static constexpr auto getDigit{attempt(digit)};
393 while (auto nextDigit{getDigit.Parse(state)}) {
394 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
395 overflow = true;
396 }
397 value *= 10;
398 int digitValue = **nextDigit - '0';
399 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
400 overflow = true;
401 }
402 value += digitValue;
403 }
404 if (overflow) {
405 state.Say(*firstDigit, "overflow in decimal literal"_err_en_US);
406 }
407 return {value};
408 }
409 } digitString64;
410
411 // R707 signed-int-literal-constant -> [sign] int-literal-constant
412 // N.B. Spaces are consumed before and after the sign, since the sign
413 // and the int-literal-constant are distinct tokens. Does not
414 // handle a trailing kind parameter.
415 static std::optional<std::int64_t> SignedInteger(
416 const std::optional<std::uint64_t> &x, Location at, bool negate,
417 ParseState &state) {
418 if (!x) {
419 return std::nullopt;
420 }
421 std::uint64_t limit{std::numeric_limits<std::int64_t>::max()};
422 if (negate) {
423 limit = -(limit + 1);
424 }
425 if (*x > limit) {
426 state.Say(at, "overflow in signed decimal literal"_err_en_US);
427 }
428 std::int64_t value = *x;
429 return std::make_optional<std::int64_t>(negate ? -value : value);
430 }
431
432 // R710 signed-digit-string -> [sign] digit-string
433 // N.B. Not a complete token -- no space is skipped.
434 // Used only in the exponent parts of real literal constants.
435 struct SignedDigitString {
436 using resultType = std::int64_t;
437 static std::optional<std::int64_t> Parse(ParseState &state) {
438 std::optional<const char *> sign{state.PeekAtNextChar()};
439 if (!sign) {
440 return std::nullopt;
441 }
442 bool negate{**sign == '-'};
443 if (negate || **sign == '+') {
444 state.UncheckedAdvance();
445 }
446 return SignedInteger(digitString64.Parse(state), *sign, negate, state);
447 }
448 };
449
450 // Variants of the above for use in FORMAT specifications, where spaces
451 // must be ignored.
452 struct DigitStringIgnoreSpaces {
453 using resultType = std::uint64_t;
454 static std::optional<std::uint64_t> Parse(ParseState &state) {
455 static constexpr auto getFirstDigit{space >> digit};
456 std::optional<const char *> firstDigit{getFirstDigit.Parse(state)};
457 if (!firstDigit) {
458 return std::nullopt;
459 }
460 std::uint64_t value = **firstDigit - '0';
461 bool overflow{false};
462 static constexpr auto getDigit{space >> attempt(digit)};
463 while (auto nextDigit{getDigit.Parse(state)}) {
464 if (value > std::numeric_limits<std::uint64_t>::max() / 10) {
465 overflow = true;
466 }
467 value *= 10;
468 int digitValue = **nextDigit - '0';
469 if (value > std::numeric_limits<std::uint64_t>::max() - digitValue) {
470 overflow = true;
471 }
472 value += digitValue;
473 }
474 if (overflow) {
475 state.Say(*firstDigit, "overflow in decimal literal"_err_en_US);
476 }
477 return value;
478 }
479 };
480
481 struct PositiveDigitStringIgnoreSpaces {
482 using resultType = std::int64_t;
483 static std::optional<std::int64_t> Parse(ParseState &state) {
484 Location at{state.GetLocation()};
485 return SignedInteger(
486 DigitStringIgnoreSpaces{}.Parse(state), at, false /*positive*/, state);
487 }
488 };
489
490 struct SignedDigitStringIgnoreSpaces {
491 using resultType = std::int64_t;
492 static std::optional<std::int64_t> Parse(ParseState &state) {
493 static constexpr auto getSign{space >> attempt("+-"_ch)};
494 bool negate{false};
495 if (std::optional<const char *> sign{getSign.Parse(state)}) {
496 negate = **sign == '-';
497 }
498 Location at{state.GetLocation()};
499 return SignedInteger(
500 DigitStringIgnoreSpaces{}.Parse(state), at, negate, state);
501 }
502 };
503
504 // Legacy feature: Hollerith literal constants
505 struct HollerithLiteral {
506 using resultType = std::string;
507 static std::optional<std::string> Parse(ParseState &state) {
508 space.Parse(state);
509 const char *start{state.GetLocation()};
510 std::optional<std::uint64_t> charCount{
511 DigitStringIgnoreSpaces{}.Parse(state)};
512 if (!charCount || *charCount < 1) {
513 return std::nullopt;
514 }
515 static constexpr auto letterH{"h"_ch};
516 std::optional<const char *> h{letterH.Parse(state)};
517 if (!h) {
518 return std::nullopt;
519 }
520 std::string content;
521 for (auto j{*charCount}; j-- > 0;) {
522 int chBytes{UTF_8CharacterBytes(state.GetLocation())};
523 for (int bytes{chBytes}; bytes > 0; --bytes) {
524 if (std::optional<const char *> at{nextCh.Parse(state)}) {
525 if (chBytes == 1 && !std::isprint(**at)) {
526 state.Say(start, "Bad character in Hollerith"_err_en_US);
527 return std::nullopt;
528 }
529 content += **at;
530 } else {
531 state.Say(start, "Insufficient characters in Hollerith"_err_en_US);
532 return std::nullopt;
533 }
534 }
535 }
536 return content;
537 }
538 };
539
540 constexpr struct ConsumedAllInputParser {
541 using resultType = Success;
542 constexpr ConsumedAllInputParser() {}
543 static inline std::optional<Success> Parse(ParseState &state) {
544 if (state.IsAtEnd()) {
545 return {Success{}};
546 }
547 return std::nullopt;
548 }
549 } consumedAllInput;
550
551 template <char goal> struct SkipPast {
552 using resultType = Success;
553 constexpr SkipPast() {}
554 constexpr SkipPast(const SkipPast &) {}
555 static std::optional<Success> Parse(ParseState &state) {
556 while (std::optional<const char *> p{state.GetNextChar()}) {
557 if (**p == goal) {
558 return {Success{}};
559 }
560 }
561 return std::nullopt;
562 }
563 };
564
565 template <char goal> struct SkipTo {
566 using resultType = Success;
567 constexpr SkipTo() {}
568 constexpr SkipTo(const SkipTo &) {}
569 static std::optional<Success> Parse(ParseState &state) {
570 while (std::optional<const char *> p{state.PeekAtNextChar()}) {
571 if (**p == goal) {
572 return {Success{}};
573 }
574 state.UncheckedAdvance();
575 }
576 return std::nullopt;
577 }
578 };
579
580 // A common idiom in the Fortran grammar is an optional item (usually
581 // a nonempty comma-separated list) that, if present, must follow a comma
582 // and precede a doubled colon. When the item is absent, the comma must
583 // not appear, and the doubled colons are optional.
584 // [[, xyz] ::] is optionalBeforeColons(xyz)
585 // [[, xyz]... ::] is optionalBeforeColons(nonemptyList(xyz))
586 template <typename PA> inline constexpr auto optionalBeforeColons(const PA &p) {
587 using resultType = std::optional<typename PA::resultType>;
588 return "," >> construct<resultType>(p) / "::" ||
589 ("::"_tok || !","_tok) >> pure<resultType>();
590 }
591 template <typename PA>
592 inline constexpr auto optionalListBeforeColons(const PA &p) {
593 using resultType = std::list<typename PA::resultType>;
594 return "," >> nonemptyList(p) / "::" ||
595 ("::"_tok || !","_tok) >> pure<resultType>();
596 }
597
598 // Skip over empty lines, leading spaces, and some compiler directives (viz.,
599 // the ones that specify the source form) that might appear before the
600 // next statement. Skip over empty statements (bare semicolons) when
601 // not in strict standard conformance mode. Always succeeds.
602 constexpr struct SkipStuffBeforeStatement {
603 using resultType = Success;
604 static std::optional<Success> Parse(ParseState &state) {
605 if (UserState * ustate{state.userState()}) {
606 if (ParsingLog * log{ustate->log()}) {
607 // Save memory: vacate the parsing log before each statement unless
608 // we're logging the whole parse for debugging.
609 if (!ustate->instrumentedParse()) {
610 log->clear();
611 }
612 }
613 }
614 while (std::optional<const char *> at{state.PeekAtNextChar()}) {
615 if (**at == '\n' || **at == ' ') {
616 state.UncheckedAdvance();
617 } else if (**at == '!') {
618 static const char fixed[] = "!dir$ fixed\n", free[] = "!dir$ free\n";
619 static constexpr std::size_t fixedBytes{sizeof fixed - 1};
620 static constexpr std::size_t freeBytes{sizeof free - 1};
621 std::size_t remain{state.BytesRemaining()};
622 if (remain >= fixedBytes && std::memcmp(*at, fixed, fixedBytes) == 0) {
623 state.set_inFixedForm(true).UncheckedAdvance(fixedBytes);
624 } else if (remain >= freeBytes &&
625 std::memcmp(*at, free, freeBytes) == 0) {
626 state.set_inFixedForm(false).UncheckedAdvance(freeBytes);
627 } else {
628 break;
629 }
630 } else if (**at == ';' &&
631 state.IsNonstandardOk(
632 LanguageFeature::EmptyStatement, "empty statement"_en_US)) {
633 state.UncheckedAdvance();
634 } else {
635 break;
636 }
637 }
638 return {Success{}};
639 }
640 } skipStuffBeforeStatement;
641
642 // R602 underscore -> _
643 constexpr auto underscore{"_"_ch};
644
645 // Characters besides letters and digits that may appear in names.
646 // N.B. Don't accept an underscore if it is immediately followed by a
647 // quotation mark, so that kindParam_"character literal" is parsed properly.
648 // PGI and ifort accept '$' in identifiers, even as the initial character.
649 // Cray and gfortran accept '$', but not as the first character.
650 // Cray accepts '@' as well.
651 constexpr auto otherIdChar{underscore / !"'\""_ch ||
652 extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
653
654 constexpr auto logicalTRUE{
655 (".TRUE."_tok ||
656 extension<LanguageFeature::LogicalAbbreviations>(".T."_tok)) >>
657 pure(true)};
658 constexpr auto logicalFALSE{
659 (".FALSE."_tok ||
660 extension<LanguageFeature::LogicalAbbreviations>(".F."_tok)) >>
661 pure(false)};
662
663 // deprecated: Hollerith literals
664 constexpr auto rawHollerithLiteral{
665 deprecated<LanguageFeature::Hollerith>(HollerithLiteral{})};
666
667 template <typename A> constexpr decltype(auto) verbatim(A x) {
668 return sourced(construct<Verbatim>(x));
669 }
670
671 } // namespace Fortran::parser
672 #endif // FORTRAN_PARSER_TOKEN_PARSERS_H_
Fortran::parser::SkipPast
Definition: token-parsers.h:551
Fortran::parser::Success
Definition: user-state.h:33
Fortran::parser::SetOfChars
Definition: char-set.h:23
Fortran::parser::SignedIntLiteralConstantWithoutKind
Definition: token-parsers.h:368
Fortran::parser::DigitString64
Definition: token-parsers.h:383
Fortran::parser::MessageExpectedText
Definition: message.h:113
Fortran::parser::HollerithLiteral
Definition: token-parsers.h:505
Fortran::parser::SkipTo
Definition: token-parsers.h:565
Fortran::parser::Space
Definition: token-parsers.h:65
Fortran::parser::BOZLiteral
Definition: token-parsers.h:269
Fortran::parser::DigitString
Definition: token-parsers.h:349
Fortran::parser::ConsumedAllInputParser
Definition: token-parsers.h:540
Fortran::parser::CharLiteral
Definition: token-parsers.h:246
Fortran::parser::PositiveDigitStringIgnoreSpaces
Definition: token-parsers.h:481
Fortran::parser::SignedDigitString
Definition: token-parsers.h:435
Fortran::parser::SkipStuffBeforeStatement
Definition: token-parsers.h:602
Fortran::parser::SpaceCheck
Definition: token-parsers.h:88
Fortran::parser::CharLiteralChar
Definition: token-parsers.h:218
Fortran::parser::TokenStringMatch
Definition: token-parsers.h:118
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::parser::ParsingLog
Definition: instrumented-parser.h:25
Fortran::parser::DigitStringIgnoreSpaces
Definition: token-parsers.h:452
Fortran::parser::ParseState
Definition: parse-state.h:35
Fortran::parser::SignedDigitStringIgnoreSpaces
Definition: token-parsers.h:490
Fortran::parser
Definition: check-expression.h:19
Fortran::parser::AnyOfChars
Definition: token-parsers.h:36
Fortran::parser::UserState
Definition: user-state.h:35