aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Parser/token-sequence.cpp
diff options
context:
space:
mode:
authorpeter klausler <pklausler@nvidia.com>2021-09-30 15:33:19 -0700
committerpeter klausler <pklausler@nvidia.com>2021-10-06 14:00:15 -0700
commit094b380c210ac508a1ad5a7c47a760773b0cc6ea (patch)
tree69fda1360bf3a030978abf8dfe3c9ac1cc4d603f /flang/lib/Parser/token-sequence.cpp
parentc52d60ec3b9202eaa9e109be539f1d2a03fbad70 (diff)
downloadllvm-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.cpp49
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