diff options
author | peter klausler <pklausler@nvidia.com> | 2021-09-30 15:33:19 -0700 |
---|---|---|
committer | peter klausler <pklausler@nvidia.com> | 2021-10-06 14:00:15 -0700 |
commit | 094b380c210ac508a1ad5a7c47a760773b0cc6ea (patch) | |
tree | 69fda1360bf3a030978abf8dfe3c9ac1cc4d603f /flang/lib/Parser/token-sequence.cpp | |
parent | c52d60ec3b9202eaa9e109be539f1d2a03fbad70 (diff) | |
download | llvm-094b380c210ac508a1ad5a7c47a760773b0cc6ea.zip llvm-094b380c210ac508a1ad5a7c47a760773b0cc6ea.tar.gz llvm-094b380c210ac508a1ad5a7c47a760773b0cc6ea.tar.bz2 |
[flang] Catch mismatched parentheses in prescanner
Source lines with mismatched parentheses are hard cases for error
recovery in parsing, and the best error message (viz.,
"here's an unmatched parenthesis") can be emitted from the
prescanner.
Differential Revision: https://reviews.llvm.org/D111254#3046173
Diffstat (limited to 'flang/lib/Parser/token-sequence.cpp')
-rw-r--r-- | flang/lib/Parser/token-sequence.cpp | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp index 3ed9d05..55217a9 100644 --- a/flang/lib/Parser/token-sequence.cpp +++ b/flang/lib/Parser/token-sequence.cpp @@ -27,6 +27,8 @@ void TokenSequence::clear() { } void TokenSequence::pop_back() { + CHECK(!start_.empty()); + CHECK(nextStart_ > start_.back()); std::size_t bytes{nextStart_ - start_.back()}; nextStart_ = start_.back(); start_.pop_back(); @@ -82,16 +84,6 @@ bool TokenSequence::IsAnythingLeft(std::size_t at) const { return false; } -void TokenSequence::RemoveLastToken() { - CHECK(!start_.empty()); - CHECK(nextStart_ > start_.back()); - std::size_t bytes{nextStart_ - start_.back()}; - nextStart_ = start_.back(); - start_.pop_back(); - char_.erase(char_.begin() + nextStart_, char_.end()); - provenances_.RemoveLastBytes(bytes); -} - void TokenSequence::Put(const TokenSequence &that) { if (nextStart_ < char_.size()) { start_.push_back(nextStart_); @@ -338,4 +330,41 @@ const TokenSequence &TokenSequence::CheckBadFortranCharacters( } return *this; } + +const TokenSequence &TokenSequence::CheckBadParentheses( + Messages &messages) const { + // First, a quick pass with no allocation for the common case + int nesting{0}; + std::size_t tokens{SizeInTokens()}; + for (std::size_t j{0}; j < tokens; ++j) { + CharBlock token{TokenAt(j)}; + char ch{token.FirstNonBlank()}; + if (ch == '(') { + ++nesting; + } else if (ch == ')') { + --nesting; + } + } + if (nesting != 0) { + // There's an error; diagnose it + std::vector<std::size_t> stack; + for (std::size_t j{0}; j < tokens; ++j) { + CharBlock token{TokenAt(j)}; + char ch{token.FirstNonBlank()}; + if (ch == '(') { + stack.push_back(j); + } else if (ch == ')') { + if (stack.empty()) { + messages.Say(GetTokenProvenanceRange(j), "Unmatched ')'"_err_en_US); + return *this; + } + stack.pop_back(); + } + } + CHECK(!stack.empty()); + messages.Say( + GetTokenProvenanceRange(stack.back()), "Unmatched '('"_err_en_US); + } + return *this; +} } // namespace Fortran::parser |