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 97d60232bSKrzysztof Parzyszek #include "flang/Parser/token-sequence.h" 107d60232bSKrzysztof Parzyszek 11cbc5d42fSPeter Klausler #include "prescan.h" 1264ab3302SCarolineConcatto #include "flang/Parser/characters.h" 13a0a1a4e5Speter klausler #include "flang/Parser/message.h" 148670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 1564ab3302SCarolineConcatto 1664ab3302SCarolineConcatto namespace Fortran::parser { 1764ab3302SCarolineConcatto 1864ab3302SCarolineConcatto TokenSequence &TokenSequence::operator=(TokenSequence &&that) { 1964ab3302SCarolineConcatto clear(); 2064ab3302SCarolineConcatto swap(that); 2164ab3302SCarolineConcatto return *this; 2264ab3302SCarolineConcatto } 2364ab3302SCarolineConcatto 2464ab3302SCarolineConcatto void TokenSequence::clear() { 2564ab3302SCarolineConcatto start_.clear(); 2664ab3302SCarolineConcatto nextStart_ = 0; 2764ab3302SCarolineConcatto char_.clear(); 2864ab3302SCarolineConcatto provenances_.clear(); 2964ab3302SCarolineConcatto } 3064ab3302SCarolineConcatto 3164ab3302SCarolineConcatto void TokenSequence::pop_back() { 32094b380cSpeter klausler CHECK(!start_.empty()); 33094b380cSpeter klausler CHECK(nextStart_ > start_.back()); 3464ab3302SCarolineConcatto std::size_t bytes{nextStart_ - start_.back()}; 3564ab3302SCarolineConcatto nextStart_ = start_.back(); 3664ab3302SCarolineConcatto start_.pop_back(); 3764ab3302SCarolineConcatto char_.resize(nextStart_); 3864ab3302SCarolineConcatto provenances_.RemoveLastBytes(bytes); 3964ab3302SCarolineConcatto } 4064ab3302SCarolineConcatto 4164ab3302SCarolineConcatto void TokenSequence::shrink_to_fit() { 4264ab3302SCarolineConcatto start_.shrink_to_fit(); 4364ab3302SCarolineConcatto char_.shrink_to_fit(); 4464ab3302SCarolineConcatto provenances_.shrink_to_fit(); 4564ab3302SCarolineConcatto } 4664ab3302SCarolineConcatto 4764ab3302SCarolineConcatto void TokenSequence::swap(TokenSequence &that) { 4864ab3302SCarolineConcatto start_.swap(that.start_); 4964ab3302SCarolineConcatto std::swap(nextStart_, that.nextStart_); 5064ab3302SCarolineConcatto char_.swap(that.char_); 5164ab3302SCarolineConcatto provenances_.swap(that.provenances_); 5264ab3302SCarolineConcatto } 5364ab3302SCarolineConcatto 5464ab3302SCarolineConcatto std::size_t TokenSequence::SkipBlanks(std::size_t at) const { 5564ab3302SCarolineConcatto std::size_t tokens{start_.size()}; 5664ab3302SCarolineConcatto for (; at < tokens; ++at) { 5764ab3302SCarolineConcatto if (!TokenAt(at).IsBlank()) { 5864ab3302SCarolineConcatto return at; 5964ab3302SCarolineConcatto } 6064ab3302SCarolineConcatto } 6164ab3302SCarolineConcatto return tokens; // even if at > tokens 6264ab3302SCarolineConcatto } 6364ab3302SCarolineConcatto 64*850d42fbSPeter Klausler std::optional<std::size_t> TokenSequence::SkipBlanksBackwards( 65*850d42fbSPeter Klausler std::size_t at) const { 66*850d42fbSPeter Klausler while (at-- > 0) { 67*850d42fbSPeter Klausler if (!TokenAt(at).IsBlank()) { 68*850d42fbSPeter Klausler return at; 69*850d42fbSPeter Klausler } 70*850d42fbSPeter Klausler } 71*850d42fbSPeter Klausler return std::nullopt; 72*850d42fbSPeter Klausler } 73*850d42fbSPeter Klausler 74cf2274b7Speter klausler // C-style /*comments*/ are removed from preprocessing directive 75cf2274b7Speter klausler // token sequences by the prescanner, but not C++ or Fortran 76cf2274b7Speter klausler // free-form line-ending comments (//... and !...) because 77cf2274b7Speter klausler // ignoring them is directive-specific. 78cf2274b7Speter klausler bool TokenSequence::IsAnythingLeft(std::size_t at) const { 79cf2274b7Speter klausler std::size_t tokens{start_.size()}; 80cf2274b7Speter klausler for (; at < tokens; ++at) { 81cf2274b7Speter klausler auto tok{TokenAt(at)}; 82cf2274b7Speter klausler const char *end{tok.end()}; 83cf2274b7Speter klausler for (const char *p{tok.begin()}; p < end; ++p) { 84cf2274b7Speter klausler switch (*p) { 85cf2274b7Speter klausler case '/': 86cf2274b7Speter klausler return p + 1 >= end || p[1] != '/'; 87cf2274b7Speter klausler case '!': 88cf2274b7Speter klausler return false; 89cf2274b7Speter klausler case ' ': 90cf2274b7Speter klausler break; 91cf2274b7Speter klausler default: 92cf2274b7Speter klausler return true; 93cf2274b7Speter klausler } 94cf2274b7Speter klausler } 95cf2274b7Speter klausler } 96cf2274b7Speter klausler return false; 97cf2274b7Speter klausler } 98cf2274b7Speter klausler 9964ab3302SCarolineConcatto void TokenSequence::Put(const TokenSequence &that) { 10064ab3302SCarolineConcatto if (nextStart_ < char_.size()) { 10164ab3302SCarolineConcatto start_.push_back(nextStart_); 10264ab3302SCarolineConcatto } 10364ab3302SCarolineConcatto int offset = char_.size(); 10464ab3302SCarolineConcatto for (int st : that.start_) { 10564ab3302SCarolineConcatto start_.push_back(st + offset); 10664ab3302SCarolineConcatto } 10764ab3302SCarolineConcatto char_.insert(char_.end(), that.char_.begin(), that.char_.end()); 10864ab3302SCarolineConcatto nextStart_ = char_.size(); 10964ab3302SCarolineConcatto provenances_.Put(that.provenances_); 11064ab3302SCarolineConcatto } 11164ab3302SCarolineConcatto 11264ab3302SCarolineConcatto void TokenSequence::Put(const TokenSequence &that, ProvenanceRange range) { 11364ab3302SCarolineConcatto std::size_t offset{0}; 11464ab3302SCarolineConcatto std::size_t tokens{that.SizeInTokens()}; 11564ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 11664ab3302SCarolineConcatto CharBlock tok{that.TokenAt(j)}; 11764ab3302SCarolineConcatto Put(tok, range.OffsetMember(offset)); 11864ab3302SCarolineConcatto offset += tok.size(); 11964ab3302SCarolineConcatto } 12064ab3302SCarolineConcatto CHECK(offset == range.size()); 12164ab3302SCarolineConcatto } 12264ab3302SCarolineConcatto 12364ab3302SCarolineConcatto void TokenSequence::Put( 12464ab3302SCarolineConcatto const TokenSequence &that, std::size_t at, std::size_t tokens) { 12564ab3302SCarolineConcatto ProvenanceRange provenance; 12664ab3302SCarolineConcatto std::size_t offset{0}; 12764ab3302SCarolineConcatto for (; tokens-- > 0; ++at) { 12864ab3302SCarolineConcatto CharBlock tok{that.TokenAt(at)}; 12964ab3302SCarolineConcatto std::size_t tokBytes{tok.size()}; 13064ab3302SCarolineConcatto for (std::size_t j{0}; j < tokBytes; ++j) { 13164ab3302SCarolineConcatto if (offset == provenance.size()) { 13264ab3302SCarolineConcatto provenance = that.provenances_.Map(that.start_[at] + j); 13364ab3302SCarolineConcatto offset = 0; 13464ab3302SCarolineConcatto } 13564ab3302SCarolineConcatto PutNextTokenChar(tok[j], provenance.OffsetMember(offset++)); 13664ab3302SCarolineConcatto } 13764ab3302SCarolineConcatto CloseToken(); 13864ab3302SCarolineConcatto } 13964ab3302SCarolineConcatto } 14064ab3302SCarolineConcatto 14164ab3302SCarolineConcatto void TokenSequence::Put( 14264ab3302SCarolineConcatto const char *s, std::size_t bytes, Provenance provenance) { 14364ab3302SCarolineConcatto for (std::size_t j{0}; j < bytes; ++j) { 14464ab3302SCarolineConcatto PutNextTokenChar(s[j], provenance + j); 14564ab3302SCarolineConcatto } 14664ab3302SCarolineConcatto CloseToken(); 14764ab3302SCarolineConcatto } 14864ab3302SCarolineConcatto 14964ab3302SCarolineConcatto void TokenSequence::Put(const CharBlock &t, Provenance provenance) { 1501def98d9SKrzysztof Parzyszek // Avoid t[0] if t is empty: it would create a reference to nullptr, 1511def98d9SKrzysztof Parzyszek // which is UB. 1521def98d9SKrzysztof Parzyszek const char *addr{t.size() ? &t[0] : nullptr}; 1531def98d9SKrzysztof Parzyszek Put(addr, t.size(), provenance); 15464ab3302SCarolineConcatto } 15564ab3302SCarolineConcatto 15664ab3302SCarolineConcatto void TokenSequence::Put(const std::string &s, Provenance provenance) { 15764ab3302SCarolineConcatto Put(s.data(), s.size(), provenance); 15864ab3302SCarolineConcatto } 15964ab3302SCarolineConcatto 1608670e499SCaroline Concatto void TokenSequence::Put(llvm::raw_string_ostream &ss, Provenance provenance) { 16164ab3302SCarolineConcatto Put(ss.str(), provenance); 16264ab3302SCarolineConcatto } 16364ab3302SCarolineConcatto 16464ab3302SCarolineConcatto TokenSequence &TokenSequence::ToLowerCase() { 16564ab3302SCarolineConcatto std::size_t tokens{start_.size()}; 16664ab3302SCarolineConcatto std::size_t chars{char_.size()}; 16764ab3302SCarolineConcatto std::size_t atToken{0}; 16864ab3302SCarolineConcatto for (std::size_t j{0}; j < chars;) { 16964ab3302SCarolineConcatto std::size_t nextStart{atToken + 1 < tokens ? start_[++atToken] : chars}; 1702a774411Sserge-sans-paille char *p{&char_[j]}; 1712a774411Sserge-sans-paille char const *limit{char_.data() + nextStart}; 1720e1fa917SLeandro Lupori const char *lastChar{limit - 1}; 17364ab3302SCarolineConcatto j = nextStart; 1740e1fa917SLeandro Lupori // Skip leading whitespaces 1750e1fa917SLeandro Lupori while (p < limit - 1 && *p == ' ') { 1760e1fa917SLeandro Lupori ++p; 1770e1fa917SLeandro Lupori } 1780e1fa917SLeandro Lupori // Find last non-whitespace char 1790e1fa917SLeandro Lupori while (lastChar > p + 1 && *lastChar == ' ') { 1800e1fa917SLeandro Lupori --lastChar; 1810e1fa917SLeandro Lupori } 18264ab3302SCarolineConcatto if (IsDecimalDigit(*p)) { 18364ab3302SCarolineConcatto while (p < limit && IsDecimalDigit(*p)) { 18464ab3302SCarolineConcatto ++p; 18564ab3302SCarolineConcatto } 18664ab3302SCarolineConcatto if (p >= limit) { 18764ab3302SCarolineConcatto } else if (*p == 'h' || *p == 'H') { 18864ab3302SCarolineConcatto // Hollerith 18964ab3302SCarolineConcatto *p = 'h'; 19064ab3302SCarolineConcatto } else if (*p == '_') { 19164ab3302SCarolineConcatto // kind-prefixed character literal (e.g., 1_"ABC") 19264ab3302SCarolineConcatto } else { 19364ab3302SCarolineConcatto // exponent 19464ab3302SCarolineConcatto for (; p < limit; ++p) { 19564ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p); 19664ab3302SCarolineConcatto } 19764ab3302SCarolineConcatto } 1980e1fa917SLeandro Lupori } else if (*lastChar == '\'' || *lastChar == '"') { 1990e1fa917SLeandro Lupori if (*p == *lastChar) { 20064ab3302SCarolineConcatto // Character literal without prefix 2010e1fa917SLeandro Lupori } else if (p[1] == *lastChar) { 20264ab3302SCarolineConcatto // BOZX-prefixed constant 20364ab3302SCarolineConcatto for (; p < limit; ++p) { 20464ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p); 20564ab3302SCarolineConcatto } 20664ab3302SCarolineConcatto } else { 20764ab3302SCarolineConcatto // Literal with kind-param prefix name (e.g., K_"ABC"). 2080e1fa917SLeandro Lupori for (; *p != *lastChar; ++p) { 20964ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p); 21064ab3302SCarolineConcatto } 21164ab3302SCarolineConcatto } 21264ab3302SCarolineConcatto } else { 21364ab3302SCarolineConcatto for (; p < limit; ++p) { 21464ab3302SCarolineConcatto *p = ToLowerCaseLetter(*p); 21564ab3302SCarolineConcatto } 21664ab3302SCarolineConcatto } 21764ab3302SCarolineConcatto } 21864ab3302SCarolineConcatto return *this; 21964ab3302SCarolineConcatto } 22064ab3302SCarolineConcatto 22164ab3302SCarolineConcatto bool TokenSequence::HasBlanks(std::size_t firstChar) const { 22264ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()}; 22364ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 22464ab3302SCarolineConcatto if (start_[j] >= firstChar && TokenAt(j).IsBlank()) { 22564ab3302SCarolineConcatto return true; 22664ab3302SCarolineConcatto } 22764ab3302SCarolineConcatto } 22864ab3302SCarolineConcatto return false; 22964ab3302SCarolineConcatto } 23064ab3302SCarolineConcatto 23164ab3302SCarolineConcatto bool TokenSequence::HasRedundantBlanks(std::size_t firstChar) const { 23264ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()}; 23364ab3302SCarolineConcatto bool lastWasBlank{false}; 23464ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 23564ab3302SCarolineConcatto bool isBlank{TokenAt(j).IsBlank()}; 23664ab3302SCarolineConcatto if (isBlank && lastWasBlank && start_[j] >= firstChar) { 23764ab3302SCarolineConcatto return true; 23864ab3302SCarolineConcatto } 23964ab3302SCarolineConcatto lastWasBlank = isBlank; 24064ab3302SCarolineConcatto } 24164ab3302SCarolineConcatto return false; 24264ab3302SCarolineConcatto } 24364ab3302SCarolineConcatto 24464ab3302SCarolineConcatto TokenSequence &TokenSequence::RemoveBlanks(std::size_t firstChar) { 24564ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()}; 24664ab3302SCarolineConcatto TokenSequence result; 24764ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 24864ab3302SCarolineConcatto if (!TokenAt(j).IsBlank() || start_[j] < firstChar) { 24964ab3302SCarolineConcatto result.Put(*this, j); 25064ab3302SCarolineConcatto } 25164ab3302SCarolineConcatto } 25264ab3302SCarolineConcatto swap(result); 25364ab3302SCarolineConcatto return *this; 25464ab3302SCarolineConcatto } 25564ab3302SCarolineConcatto 25664ab3302SCarolineConcatto TokenSequence &TokenSequence::RemoveRedundantBlanks(std::size_t firstChar) { 25764ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()}; 25864ab3302SCarolineConcatto TokenSequence result; 25964ab3302SCarolineConcatto bool lastWasBlank{false}; 26064ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 26164ab3302SCarolineConcatto bool isBlank{TokenAt(j).IsBlank()}; 26264ab3302SCarolineConcatto if (!isBlank || !lastWasBlank || start_[j] < firstChar) { 26364ab3302SCarolineConcatto result.Put(*this, j); 26464ab3302SCarolineConcatto } 26564ab3302SCarolineConcatto lastWasBlank = isBlank; 26664ab3302SCarolineConcatto } 26764ab3302SCarolineConcatto swap(result); 26864ab3302SCarolineConcatto return *this; 26964ab3302SCarolineConcatto } 27064ab3302SCarolineConcatto 271cbc5d42fSPeter Klausler TokenSequence &TokenSequence::ClipComment( 272cbc5d42fSPeter Klausler const Prescanner &prescanner, bool skipFirst) { 27364ab3302SCarolineConcatto std::size_t tokens{SizeInTokens()}; 27464ab3302SCarolineConcatto for (std::size_t j{0}; j < tokens; ++j) { 275cbc5d42fSPeter Klausler CharBlock tok{TokenAt(j)}; 276cbc5d42fSPeter Klausler if (std::size_t blanks{tok.CountLeadingBlanks()}; 277cbc5d42fSPeter Klausler blanks < tok.size() && tok[blanks] == '!') { 278cbc5d42fSPeter Klausler // Retain active compiler directive sentinels (e.g. "!dir$") 279259ce119SPeter Klausler for (std::size_t k{j + 1}; k < tokens && tok.size() <= blanks + 5; ++k) { 280cbc5d42fSPeter Klausler if (tok.begin() + tok.size() == TokenAt(k).begin()) { 281cbc5d42fSPeter Klausler tok.ExtendToCover(TokenAt(k)); 282cbc5d42fSPeter Klausler } else { 283cbc5d42fSPeter Klausler break; 284cbc5d42fSPeter Klausler } 285cbc5d42fSPeter Klausler } 286cbc5d42fSPeter Klausler bool isSentinel{false}; 287259ce119SPeter Klausler if (tok.size() > blanks + 5) { 288259ce119SPeter Klausler isSentinel = prescanner.IsCompilerDirectiveSentinel(&tok[blanks + 1]) 289259ce119SPeter Klausler .has_value(); 290cbc5d42fSPeter Klausler } 291cbc5d42fSPeter Klausler if (isSentinel) { 292cbc5d42fSPeter Klausler } else if (skipFirst) { 29364ab3302SCarolineConcatto skipFirst = false; 29464ab3302SCarolineConcatto } else { 29564ab3302SCarolineConcatto TokenSequence result; 29664ab3302SCarolineConcatto if (j > 0) { 29764ab3302SCarolineConcatto result.Put(*this, 0, j - 1); 29864ab3302SCarolineConcatto } 29964ab3302SCarolineConcatto swap(result); 30064ab3302SCarolineConcatto return *this; 30164ab3302SCarolineConcatto } 30264ab3302SCarolineConcatto } 30364ab3302SCarolineConcatto } 30464ab3302SCarolineConcatto return *this; 30564ab3302SCarolineConcatto } 30664ab3302SCarolineConcatto 30764ab3302SCarolineConcatto void TokenSequence::Emit(CookedSource &cooked) const { 30895526930SPeter Klausler if (auto n{char_.size()}) { 30995526930SPeter Klausler cooked.Put(&char_[0], n); 31064ab3302SCarolineConcatto cooked.PutProvenanceMappings(provenances_); 31164ab3302SCarolineConcatto } 31295526930SPeter Klausler } 31364ab3302SCarolineConcatto 3143338ef93Speter klausler llvm::raw_ostream &TokenSequence::Dump(llvm::raw_ostream &o) const { 31564ab3302SCarolineConcatto o << "TokenSequence has " << char_.size() << " chars; nextStart_ " 31664ab3302SCarolineConcatto << nextStart_ << '\n'; 31764ab3302SCarolineConcatto for (std::size_t j{0}; j < start_.size(); ++j) { 31864ab3302SCarolineConcatto o << '[' << j << "] @ " << start_[j] << " '" << TokenAt(j).ToString() 31964ab3302SCarolineConcatto << "'\n"; 32064ab3302SCarolineConcatto } 3213338ef93Speter klausler return o; 32264ab3302SCarolineConcatto } 32364ab3302SCarolineConcatto 324f6ddfac4Speter klausler Provenance TokenSequence::GetCharProvenance(std::size_t offset) const { 325f6ddfac4Speter klausler ProvenanceRange range{provenances_.Map(offset)}; 326f6ddfac4Speter klausler return range.start(); 327f6ddfac4Speter klausler } 328f6ddfac4Speter klausler 32964ab3302SCarolineConcatto Provenance TokenSequence::GetTokenProvenance( 33064ab3302SCarolineConcatto std::size_t token, std::size_t offset) const { 331f6ddfac4Speter klausler return GetCharProvenance(start_[token] + offset); 33264ab3302SCarolineConcatto } 33364ab3302SCarolineConcatto 33464ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetTokenProvenanceRange( 33564ab3302SCarolineConcatto std::size_t token, std::size_t offset) const { 33664ab3302SCarolineConcatto ProvenanceRange range{provenances_.Map(start_[token] + offset)}; 33764ab3302SCarolineConcatto return range.Prefix(TokenBytes(token) - offset); 33864ab3302SCarolineConcatto } 33964ab3302SCarolineConcatto 34064ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetIntervalProvenanceRange( 34164ab3302SCarolineConcatto std::size_t token, std::size_t tokens) const { 34264ab3302SCarolineConcatto if (tokens == 0) { 34364ab3302SCarolineConcatto return {}; 34464ab3302SCarolineConcatto } 34564ab3302SCarolineConcatto ProvenanceRange range{provenances_.Map(start_[token])}; 34664ab3302SCarolineConcatto while (--tokens > 0 && 34764ab3302SCarolineConcatto range.AnnexIfPredecessor(provenances_.Map(start_[++token]))) { 34864ab3302SCarolineConcatto } 34964ab3302SCarolineConcatto return range; 35064ab3302SCarolineConcatto } 35164ab3302SCarolineConcatto 35264ab3302SCarolineConcatto ProvenanceRange TokenSequence::GetProvenanceRange() const { 35364ab3302SCarolineConcatto return GetIntervalProvenanceRange(0, start_.size()); 35464ab3302SCarolineConcatto } 355a0a1a4e5Speter klausler 356a0a1a4e5Speter klausler const TokenSequence &TokenSequence::CheckBadFortranCharacters( 357e286ecfeSPeter Klausler Messages &messages, const Prescanner &prescanner, 358e286ecfeSPeter Klausler bool allowAmpersand) const { 359a0a1a4e5Speter klausler std::size_t tokens{SizeInTokens()}; 360a0a1a4e5Speter klausler for (std::size_t j{0}; j < tokens; ++j) { 361a0a1a4e5Speter klausler CharBlock token{TokenAt(j)}; 362a0a1a4e5Speter klausler char ch{token.FirstNonBlank()}; 363a0a1a4e5Speter klausler if (ch != ' ' && !IsValidFortranTokenCharacter(ch)) { 364297230acSPeter Klausler if (ch == '!') { 365297230acSPeter Klausler if (prescanner.IsCompilerDirectiveSentinel(token)) { 366297230acSPeter Klausler continue; 367297230acSPeter Klausler } else if (j + 1 < tokens && 368297230acSPeter Klausler prescanner.IsCompilerDirectiveSentinel( 369297230acSPeter Klausler TokenAt(j + 1))) { // !dir$, &c. 370297230acSPeter Klausler ++j; 371297230acSPeter Klausler continue; 372297230acSPeter Klausler } 373e286ecfeSPeter Klausler } else if (ch == '&' && allowAmpersand) { 374e286ecfeSPeter Klausler continue; 375297230acSPeter Klausler } 376297230acSPeter Klausler if (ch < ' ' || ch >= '\x7f') { 377a0a1a4e5Speter klausler messages.Say(GetTokenProvenanceRange(j), 378a0a1a4e5Speter klausler "bad character (0x%02x) in Fortran token"_err_en_US, ch & 0xff); 379a0a1a4e5Speter klausler } else { 380a0a1a4e5Speter klausler messages.Say(GetTokenProvenanceRange(j), 381a0a1a4e5Speter klausler "bad character ('%c') in Fortran token"_err_en_US, ch); 382a0a1a4e5Speter klausler } 383a0a1a4e5Speter klausler } 384a0a1a4e5Speter klausler } 385a0a1a4e5Speter klausler return *this; 386a0a1a4e5Speter klausler } 387094b380cSpeter klausler 38886bee819SPeter Klausler bool TokenSequence::BadlyNestedParentheses() const { 389094b380cSpeter klausler int nesting{0}; 390094b380cSpeter klausler std::size_t tokens{SizeInTokens()}; 391094b380cSpeter klausler for (std::size_t j{0}; j < tokens; ++j) { 392094b380cSpeter klausler CharBlock token{TokenAt(j)}; 3936fac3f7bSPeter Klausler char ch{token.OnlyNonBlank()}; 394094b380cSpeter klausler if (ch == '(') { 395094b380cSpeter klausler ++nesting; 396094b380cSpeter klausler } else if (ch == ')') { 3976fac3f7bSPeter Klausler if (nesting-- == 0) { 3986fac3f7bSPeter Klausler break; 3996fac3f7bSPeter Klausler } 400094b380cSpeter klausler } 401094b380cSpeter klausler } 40286bee819SPeter Klausler return nesting != 0; 40386bee819SPeter Klausler } 40486bee819SPeter Klausler 40586bee819SPeter Klausler const TokenSequence &TokenSequence::CheckBadParentheses( 40686bee819SPeter Klausler Messages &messages) const { 40786bee819SPeter Klausler if (BadlyNestedParentheses()) { 408094b380cSpeter klausler // There's an error; diagnose it 40986bee819SPeter Klausler std::size_t tokens{SizeInTokens()}; 410094b380cSpeter klausler std::vector<std::size_t> stack; 411094b380cSpeter klausler for (std::size_t j{0}; j < tokens; ++j) { 412094b380cSpeter klausler CharBlock token{TokenAt(j)}; 4136fac3f7bSPeter Klausler char ch{token.OnlyNonBlank()}; 414094b380cSpeter klausler if (ch == '(') { 415094b380cSpeter klausler stack.push_back(j); 416094b380cSpeter klausler } else if (ch == ')') { 417094b380cSpeter klausler if (stack.empty()) { 418094b380cSpeter klausler messages.Say(GetTokenProvenanceRange(j), "Unmatched ')'"_err_en_US); 419094b380cSpeter klausler return *this; 420094b380cSpeter klausler } 421094b380cSpeter klausler stack.pop_back(); 422094b380cSpeter klausler } 423094b380cSpeter klausler } 424094b380cSpeter klausler CHECK(!stack.empty()); 425094b380cSpeter klausler messages.Say( 426094b380cSpeter klausler GetTokenProvenanceRange(stack.back()), "Unmatched '('"_err_en_US); 427094b380cSpeter klausler } 428094b380cSpeter klausler return *this; 429094b380cSpeter klausler } 4301f879005STim Keith } // namespace Fortran::parser 431