164ab3302SCarolineConcatto //===-- lib/Parser/token-sequence.cpp -------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto
964ab3302SCarolineConcatto #include "token-sequence.h"
1064ab3302SCarolineConcatto #include "flang/Parser/characters.h"
11a0a1a4e5Speter klausler #include "flang/Parser/message.h"
128670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1364ab3302SCarolineConcatto
1464ab3302SCarolineConcatto namespace Fortran::parser {
1564ab3302SCarolineConcatto
operator =(TokenSequence && that)1664ab3302SCarolineConcatto TokenSequence &TokenSequence::operator=(TokenSequence &&that) {
1764ab3302SCarolineConcatto clear();
1864ab3302SCarolineConcatto swap(that);
1964ab3302SCarolineConcatto return *this;
2064ab3302SCarolineConcatto }
2164ab3302SCarolineConcatto
clear()2264ab3302SCarolineConcatto void TokenSequence::clear() {
2364ab3302SCarolineConcatto start_.clear();
2464ab3302SCarolineConcatto nextStart_ = 0;
2564ab3302SCarolineConcatto char_.clear();
2664ab3302SCarolineConcatto provenances_.clear();
2764ab3302SCarolineConcatto }
2864ab3302SCarolineConcatto
pop_back()2964ab3302SCarolineConcatto void TokenSequence::pop_back() {
30*094b380cSpeter klausler CHECK(!start_.empty());
31*094b380cSpeter klausler CHECK(nextStart_ > start_.back());
3264ab3302SCarolineConcatto std::size_t bytes{nextStart_ - start_.back()};
3364ab3302SCarolineConcatto nextStart_ = start_.back();
3464ab3302SCarolineConcatto start_.pop_back();
3564ab3302SCarolineConcatto char_.resize(nextStart_);
3664ab3302SCarolineConcatto provenances_.RemoveLastBytes(bytes);
3764ab3302SCarolineConcatto }
3864ab3302SCarolineConcatto
shrink_to_fit()3964ab3302SCarolineConcatto void TokenSequence::shrink_to_fit() {
4064ab3302SCarolineConcatto start_.shrink_to_fit();
4164ab3302SCarolineConcatto char_.shrink_to_fit();
4264ab3302SCarolineConcatto provenances_.shrink_to_fit();
4364ab3302SCarolineConcatto }
4464ab3302SCarolineConcatto
swap(TokenSequence & that)4564ab3302SCarolineConcatto void TokenSequence::swap(TokenSequence &that) {
4664ab3302SCarolineConcatto start_.swap(that.start_);
4764ab3302SCarolineConcatto std::swap(nextStart_, that.nextStart_);
4864ab3302SCarolineConcatto char_.swap(that.char_);
4964ab3302SCarolineConcatto provenances_.swap(that.provenances_);
5064ab3302SCarolineConcatto }
5164ab3302SCarolineConcatto
SkipBlanks(std::size_t at) const5264ab3302SCarolineConcatto std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
5364ab3302SCarolineConcatto std::size_t tokens{start_.size()};
5464ab3302SCarolineConcatto for (; at < tokens; ++at) {
5564ab3302SCarolineConcatto if (!TokenAt(at).IsBlank()) {
5664ab3302SCarolineConcatto return at;
5764ab3302SCarolineConcatto }
5864ab3302SCarolineConcatto }
5964ab3302SCarolineConcatto return tokens; // even if at > tokens
6064ab3302SCarolineConcatto }
6164ab3302SCarolineConcatto
62cf2274b7Speter klausler // C-style /*comments*/ are removed from preprocessing directive
63cf2274b7Speter klausler // token sequences by the prescanner, but not C++ or Fortran
64cf2274b7Speter klausler // free-form line-ending comments (//... and !...) because
65cf2274b7Speter klausler // ignoring them is directive-specific.
IsAnythingLeft(std::size_t at) const66cf2274b7Speter klausler bool TokenSequence::IsAnythingLeft(std::size_t at) const {
67cf2274b7Speter klausler std::size_t tokens{start_.size()};
68cf2274b7Speter klausler for (; at < tokens; ++at) {
69cf2274b7Speter klausler auto tok{TokenAt(at)};
70cf2274b7Speter klausler const char *end{tok.end()};
71cf2274b7Speter klausler for (const char *p{tok.begin()}; p < end; ++p) {
72cf2274b7Speter klausler switch (*p) {
73cf2274b7Speter klausler case '/':
74cf2274b7Speter klausler return p + 1 >= end || p[1] != '/';
75cf2274b7Speter klausler case '!':
76cf2274b7Speter klausler return false;
77cf2274b7Speter klausler case ' ':
78cf2274b7Speter klausler break;
79cf2274b7Speter klausler default:
80cf2274b7Speter klausler return true;
81cf2274b7Speter klausler }
82cf2274b7Speter klausler }
83cf2274b7Speter klausler }
84cf2274b7Speter klausler return false;
85cf2274b7Speter klausler }
86cf2274b7Speter klausler
Put(const TokenSequence & that)8764ab3302SCarolineConcatto void TokenSequence::Put(const TokenSequence &that) {
8864ab3302SCarolineConcatto if (nextStart_ < char_.size()) {
8964ab3302SCarolineConcatto start_.push_back(nextStart_);
9064ab3302SCarolineConcatto }
9164ab3302SCarolineConcatto int offset = char_.size();
9264ab3302SCarolineConcatto for (int st : that.start_) {
9364ab3302SCarolineConcatto start_.push_back(st + offset);
9464ab3302SCarolineConcatto }
9564ab3302SCarolineConcatto char_.insert(char_.end(), that.char_.begin(), that.char_.end());
9664ab3302SCarolineConcatto nextStart_ = char_.size();
9764ab3302SCarolineConcatto provenances_.Put(that.provenances_);
9864ab3302SCarolineConcatto }
9964ab3302SCarolineConcatto
Put(const TokenSequence & that,ProvenanceRange range)10064ab3302SCarolineConcatto void TokenSequence::Put(const TokenSequence &that, ProvenanceRange range) {
10164ab3302SCarolineConcatto std::size_t offset{0};
10264ab3302SCarolineConcatto std::size_t tokens{that.SizeInTokens()};
10364ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
10464ab3302SCarolineConcatto CharBlock tok{that.TokenAt(j)};
10564ab3302SCarolineConcatto Put(tok, range.OffsetMember(offset));
10664ab3302SCarolineConcatto offset += tok.size();
10764ab3302SCarolineConcatto }
10864ab3302SCarolineConcatto CHECK(offset == range.size());
10964ab3302SCarolineConcatto }
11064ab3302SCarolineConcatto
Put(const TokenSequence & that,std::size_t at,std::size_t tokens)11164ab3302SCarolineConcatto void TokenSequence::Put(
11264ab3302SCarolineConcatto const TokenSequence &that, std::size_t at, std::size_t tokens) {
11364ab3302SCarolineConcatto ProvenanceRange provenance;
11464ab3302SCarolineConcatto std::size_t offset{0};
11564ab3302SCarolineConcatto for (; tokens-- > 0; ++at) {
11664ab3302SCarolineConcatto CharBlock tok{that.TokenAt(at)};
11764ab3302SCarolineConcatto std::size_t tokBytes{tok.size()};
11864ab3302SCarolineConcatto for (std::size_t j{0}; j < tokBytes; ++j) {
11964ab3302SCarolineConcatto if (offset == provenance.size()) {
12064ab3302SCarolineConcatto provenance = that.provenances_.Map(that.start_[at] + j);
12164ab3302SCarolineConcatto offset = 0;
12264ab3302SCarolineConcatto }
12364ab3302SCarolineConcatto PutNextTokenChar(tok[j], provenance.OffsetMember(offset++));
12464ab3302SCarolineConcatto }
12564ab3302SCarolineConcatto CloseToken();
12664ab3302SCarolineConcatto }
12764ab3302SCarolineConcatto }
12864ab3302SCarolineConcatto
Put(const char * s,std::size_t bytes,Provenance provenance)12964ab3302SCarolineConcatto void TokenSequence::Put(
13064ab3302SCarolineConcatto const char *s, std::size_t bytes, Provenance provenance) {
13164ab3302SCarolineConcatto for (std::size_t j{0}; j < bytes; ++j) {
13264ab3302SCarolineConcatto PutNextTokenChar(s[j], provenance + j);
13364ab3302SCarolineConcatto }
13464ab3302SCarolineConcatto CloseToken();
13564ab3302SCarolineConcatto }
13664ab3302SCarolineConcatto
Put(const CharBlock & t,Provenance provenance)13764ab3302SCarolineConcatto void TokenSequence::Put(const CharBlock &t, Provenance provenance) {
13864ab3302SCarolineConcatto Put(&t[0], t.size(), provenance);
13964ab3302SCarolineConcatto }
14064ab3302SCarolineConcatto
Put(const std::string & s,Provenance provenance)14164ab3302SCarolineConcatto void TokenSequence::Put(const std::string &s, Provenance provenance) {
14264ab3302SCarolineConcatto Put(s.data(), s.size(), provenance);
14364ab3302SCarolineConcatto }
14464ab3302SCarolineConcatto
Put(llvm::raw_string_ostream & ss,Provenance provenance)1458670e499SCaroline Concatto void TokenSequence::Put(llvm::raw_string_ostream &ss, Provenance provenance) {
14664ab3302SCarolineConcatto Put(ss.str(), provenance);
14764ab3302SCarolineConcatto }
14864ab3302SCarolineConcatto
ToLowerCase()14964ab3302SCarolineConcatto TokenSequence &TokenSequence::ToLowerCase() {
15064ab3302SCarolineConcatto std::size_t tokens{start_.size()};
15164ab3302SCarolineConcatto std::size_t chars{char_.size()};
15264ab3302SCarolineConcatto std::size_t atToken{0};
15364ab3302SCarolineConcatto for (std::size_t j{0}; j < chars;) {
15464ab3302SCarolineConcatto std::size_t nextStart{atToken + 1 < tokens ? start_[++atToken] : chars};
1552a774411Sserge-sans-paille char *p{&char_[j]};
1562a774411Sserge-sans-paille char const *limit{char_.data() + nextStart};
15764ab3302SCarolineConcatto j = nextStart;
15864ab3302SCarolineConcatto if (IsDecimalDigit(*p)) {
15964ab3302SCarolineConcatto while (p < limit && IsDecimalDigit(*p)) {
16064ab3302SCarolineConcatto ++p;
16164ab3302SCarolineConcatto }
16264ab3302SCarolineConcatto if (p >= limit) {
16364ab3302SCarolineConcatto } else if (*p == 'h' || *p == 'H') {
16464ab3302SCarolineConcatto // Hollerith
16564ab3302SCarolineConcatto *p = 'h';
16664ab3302SCarolineConcatto } else if (*p == '_') {
16764ab3302SCarolineConcatto // kind-prefixed character literal (e.g., 1_"ABC")
16864ab3302SCarolineConcatto } else {
16964ab3302SCarolineConcatto // exponent
17064ab3302SCarolineConcatto for (; p < limit; ++p) {
17164ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p);
17264ab3302SCarolineConcatto }
17364ab3302SCarolineConcatto }
17464ab3302SCarolineConcatto } else if (limit[-1] == '\'' || limit[-1] == '"') {
17564ab3302SCarolineConcatto if (*p == limit[-1]) {
17664ab3302SCarolineConcatto // Character literal without prefix
17764ab3302SCarolineConcatto } else if (p[1] == limit[-1]) {
17864ab3302SCarolineConcatto // BOZX-prefixed constant
17964ab3302SCarolineConcatto for (; p < limit; ++p) {
18064ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p);
18164ab3302SCarolineConcatto }
18264ab3302SCarolineConcatto } else {
18364ab3302SCarolineConcatto // Literal with kind-param prefix name (e.g., K_"ABC").
18464ab3302SCarolineConcatto for (; *p != limit[-1]; ++p) {
18564ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p);
18664ab3302SCarolineConcatto }
18764ab3302SCarolineConcatto }
18864ab3302SCarolineConcatto } else {
18964ab3302SCarolineConcatto for (; p < limit; ++p) {
19064ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p);
19164ab3302SCarolineConcatto }
19264ab3302SCarolineConcatto }
19364ab3302SCarolineConcatto }
19464ab3302SCarolineConcatto return *this;
19564ab3302SCarolineConcatto }
19664ab3302SCarolineConcatto
HasBlanks(std::size_t firstChar) const19764ab3302SCarolineConcatto bool TokenSequence::HasBlanks(std::size_t firstChar) const {
19864ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()};
19964ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
20064ab3302SCarolineConcatto if (start_[j] >= firstChar && TokenAt(j).IsBlank()) {
20164ab3302SCarolineConcatto return true;
20264ab3302SCarolineConcatto }
20364ab3302SCarolineConcatto }
20464ab3302SCarolineConcatto return false;
20564ab3302SCarolineConcatto }
20664ab3302SCarolineConcatto
HasRedundantBlanks(std::size_t firstChar) const20764ab3302SCarolineConcatto bool TokenSequence::HasRedundantBlanks(std::size_t firstChar) const {
20864ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()};
20964ab3302SCarolineConcatto bool lastWasBlank{false};
21064ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
21164ab3302SCarolineConcatto bool isBlank{TokenAt(j).IsBlank()};
21264ab3302SCarolineConcatto if (isBlank && lastWasBlank && start_[j] >= firstChar) {
21364ab3302SCarolineConcatto return true;
21464ab3302SCarolineConcatto }
21564ab3302SCarolineConcatto lastWasBlank = isBlank;
21664ab3302SCarolineConcatto }
21764ab3302SCarolineConcatto return false;
21864ab3302SCarolineConcatto }
21964ab3302SCarolineConcatto
RemoveBlanks(std::size_t firstChar)22064ab3302SCarolineConcatto TokenSequence &TokenSequence::RemoveBlanks(std::size_t firstChar) {
22164ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()};
22264ab3302SCarolineConcatto TokenSequence result;
22364ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
22464ab3302SCarolineConcatto if (!TokenAt(j).IsBlank() || start_[j] < firstChar) {
22564ab3302SCarolineConcatto result.Put(*this, j);
22664ab3302SCarolineConcatto }
22764ab3302SCarolineConcatto }
22864ab3302SCarolineConcatto swap(result);
22964ab3302SCarolineConcatto return *this;
23064ab3302SCarolineConcatto }
23164ab3302SCarolineConcatto
RemoveRedundantBlanks(std::size_t firstChar)23264ab3302SCarolineConcatto TokenSequence &TokenSequence::RemoveRedundantBlanks(std::size_t firstChar) {
23364ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()};
23464ab3302SCarolineConcatto TokenSequence result;
23564ab3302SCarolineConcatto bool lastWasBlank{false};
23664ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
23764ab3302SCarolineConcatto bool isBlank{TokenAt(j).IsBlank()};
23864ab3302SCarolineConcatto if (!isBlank || !lastWasBlank || start_[j] < firstChar) {
23964ab3302SCarolineConcatto result.Put(*this, j);
24064ab3302SCarolineConcatto }
24164ab3302SCarolineConcatto lastWasBlank = isBlank;
24264ab3302SCarolineConcatto }
24364ab3302SCarolineConcatto swap(result);
24464ab3302SCarolineConcatto return *this;
24564ab3302SCarolineConcatto }
24664ab3302SCarolineConcatto
ClipComment(bool skipFirst)24764ab3302SCarolineConcatto TokenSequence &TokenSequence::ClipComment(bool skipFirst) {
24864ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()};
24964ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) {
25064ab3302SCarolineConcatto if (TokenAt(j).FirstNonBlank() == '!') {
25164ab3302SCarolineConcatto if (skipFirst) {
25264ab3302SCarolineConcatto skipFirst = false;
25364ab3302SCarolineConcatto } else {
25464ab3302SCarolineConcatto TokenSequence result;
25564ab3302SCarolineConcatto if (j > 0) {
25664ab3302SCarolineConcatto result.Put(*this, 0, j - 1);
25764ab3302SCarolineConcatto }
25864ab3302SCarolineConcatto swap(result);
25964ab3302SCarolineConcatto return *this;
26064ab3302SCarolineConcatto }
26164ab3302SCarolineConcatto }
26264ab3302SCarolineConcatto }
26364ab3302SCarolineConcatto return *this;
26464ab3302SCarolineConcatto }
26564ab3302SCarolineConcatto
Emit(CookedSource & cooked) const26664ab3302SCarolineConcatto void TokenSequence::Emit(CookedSource &cooked) const {
26764ab3302SCarolineConcatto cooked.Put(&char_[0], char_.size());
26864ab3302SCarolineConcatto cooked.PutProvenanceMappings(provenances_);
26964ab3302SCarolineConcatto }
27064ab3302SCarolineConcatto
Dump(llvm::raw_ostream & o) const2713338ef93Speter klausler llvm::raw_ostream &TokenSequence::Dump(llvm::raw_ostream &o) const {
27264ab3302SCarolineConcatto o << "TokenSequence has " << char_.size() << " chars; nextStart_ "
27364ab3302SCarolineConcatto << nextStart_ << '\n';
27464ab3302SCarolineConcatto for (std::size_t j{0}; j < start_.size(); ++j) {
27564ab3302SCarolineConcatto o << '[' << j << "] @ " << start_[j] << " '" << TokenAt(j).ToString()
27664ab3302SCarolineConcatto << "'\n";
27764ab3302SCarolineConcatto }
2783338ef93Speter klausler return o;
27964ab3302SCarolineConcatto }
28064ab3302SCarolineConcatto
GetCharProvenance(std::size_t offset) const281f6ddfac4Speter klausler Provenance TokenSequence::GetCharProvenance(std::size_t offset) const {
282f6ddfac4Speter klausler ProvenanceRange range{provenances_.Map(offset)};
283f6ddfac4Speter klausler return range.start();
284f6ddfac4Speter klausler }
285f6ddfac4Speter klausler
GetTokenProvenance(std::size_t token,std::size_t offset) const28664ab3302SCarolineConcatto Provenance TokenSequence::GetTokenProvenance(
28764ab3302SCarolineConcatto std::size_t token, std::size_t offset) const {
288f6ddfac4Speter klausler return GetCharProvenance(start_[token] + offset);
28964ab3302SCarolineConcatto }
29064ab3302SCarolineConcatto
GetTokenProvenanceRange(std::size_t token,std::size_t offset) const29164ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetTokenProvenanceRange(
29264ab3302SCarolineConcatto std::size_t token, std::size_t offset) const {
29364ab3302SCarolineConcatto ProvenanceRange range{provenances_.Map(start_[token] + offset)};
29464ab3302SCarolineConcatto return range.Prefix(TokenBytes(token) - offset);
29564ab3302SCarolineConcatto }
29664ab3302SCarolineConcatto
GetIntervalProvenanceRange(std::size_t token,std::size_t tokens) const29764ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetIntervalProvenanceRange(
29864ab3302SCarolineConcatto std::size_t token, std::size_t tokens) const {
29964ab3302SCarolineConcatto if (tokens == 0) {
30064ab3302SCarolineConcatto return {};
30164ab3302SCarolineConcatto }
30264ab3302SCarolineConcatto ProvenanceRange range{provenances_.Map(start_[token])};
30364ab3302SCarolineConcatto while (--tokens > 0 &&
30464ab3302SCarolineConcatto range.AnnexIfPredecessor(provenances_.Map(start_[++token]))) {
30564ab3302SCarolineConcatto }
30664ab3302SCarolineConcatto return range;
30764ab3302SCarolineConcatto }
30864ab3302SCarolineConcatto
GetProvenanceRange() const30964ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetProvenanceRange() const {
31064ab3302SCarolineConcatto return GetIntervalProvenanceRange(0, start_.size());
31164ab3302SCarolineConcatto }
312a0a1a4e5Speter klausler
CheckBadFortranCharacters(Messages & messages) const313a0a1a4e5Speter klausler const TokenSequence &TokenSequence::CheckBadFortranCharacters(
314a0a1a4e5Speter klausler Messages &messages) const {
315a0a1a4e5Speter klausler std::size_t tokens{SizeInTokens()};
316a0a1a4e5Speter klausler for (std::size_t j{0}; j < tokens; ++j) {
317a0a1a4e5Speter klausler CharBlock token{TokenAt(j)};
318a0a1a4e5Speter klausler char ch{token.FirstNonBlank()};
319a0a1a4e5Speter klausler if (ch != ' ' && !IsValidFortranTokenCharacter(ch)) {
320a0a1a4e5Speter klausler if (ch == '!' && j == 0) {
321a0a1a4e5Speter klausler // allow in !dir$
322a0a1a4e5Speter klausler } else if (ch < ' ' || ch >= '\x7f') {
323a0a1a4e5Speter klausler messages.Say(GetTokenProvenanceRange(j),
324a0a1a4e5Speter klausler "bad character (0x%02x) in Fortran token"_err_en_US, ch & 0xff);
325a0a1a4e5Speter klausler } else {
326a0a1a4e5Speter klausler messages.Say(GetTokenProvenanceRange(j),
327a0a1a4e5Speter klausler "bad character ('%c') in Fortran token"_err_en_US, ch);
328a0a1a4e5Speter klausler }
329a0a1a4e5Speter klausler }
330a0a1a4e5Speter klausler }
331a0a1a4e5Speter klausler return *this;
332a0a1a4e5Speter klausler }
333*094b380cSpeter klausler
CheckBadParentheses(Messages & messages) const334*094b380cSpeter klausler const TokenSequence &TokenSequence::CheckBadParentheses(
335*094b380cSpeter klausler Messages &messages) const {
336*094b380cSpeter klausler // First, a quick pass with no allocation for the common case
337*094b380cSpeter klausler int nesting{0};
338*094b380cSpeter klausler std::size_t tokens{SizeInTokens()};
339*094b380cSpeter klausler for (std::size_t j{0}; j < tokens; ++j) {
340*094b380cSpeter klausler CharBlock token{TokenAt(j)};
341*094b380cSpeter klausler char ch{token.FirstNonBlank()};
342*094b380cSpeter klausler if (ch == '(') {
343*094b380cSpeter klausler ++nesting;
344*094b380cSpeter klausler } else if (ch == ')') {
345*094b380cSpeter klausler --nesting;
346*094b380cSpeter klausler }
347*094b380cSpeter klausler }
348*094b380cSpeter klausler if (nesting != 0) {
349*094b380cSpeter klausler // There's an error; diagnose it
350*094b380cSpeter klausler std::vector<std::size_t> stack;
351*094b380cSpeter klausler for (std::size_t j{0}; j < tokens; ++j) {
352*094b380cSpeter klausler CharBlock token{TokenAt(j)};
353*094b380cSpeter klausler char ch{token.FirstNonBlank()};
354*094b380cSpeter klausler if (ch == '(') {
355*094b380cSpeter klausler stack.push_back(j);
356*094b380cSpeter klausler } else if (ch == ')') {
357*094b380cSpeter klausler if (stack.empty()) {
358*094b380cSpeter klausler messages.Say(GetTokenProvenanceRange(j), "Unmatched ')'"_err_en_US);
359*094b380cSpeter klausler return *this;
360*094b380cSpeter klausler }
361*094b380cSpeter klausler stack.pop_back();
362*094b380cSpeter klausler }
363*094b380cSpeter klausler }
364*094b380cSpeter klausler CHECK(!stack.empty());
365*094b380cSpeter klausler messages.Say(
366*094b380cSpeter klausler GetTokenProvenanceRange(stack.back()), "Unmatched '('"_err_en_US);
367*094b380cSpeter klausler }
368*094b380cSpeter klausler return *this;
369*094b380cSpeter klausler }
3701f879005STim Keith } // namespace Fortran::parser
371