[flang-commits] [flang] cf2274b - [flang] Allow ! and // comments after some preprocessing directives
peter klausler via flang-commits
flang-commits at lists.llvm.org
Fri Jul 17 15:29:02 PDT 2020
Author: peter klausler
Date: 2020-07-17T15:28:22-07:00
New Revision: cf2274b779f5ffee476cfe40994e6963a51c6428
URL: https://github.com/llvm/llvm-project/commit/cf2274b779f5ffee476cfe40994e6963a51c6428
DIFF: https://github.com/llvm/llvm-project/commit/cf2274b779f5ffee476cfe40994e6963a51c6428.diff
LOG: [flang] Allow ! and // comments after some preprocessing directives
Old-style C /*comments*/ are omitted from preprocessor directive
token sequences by the prescanner, but line-ending C++ and Fortran
free-form comments are not since their handling might depend on
the directive. Add code to skip these line-ending comments as
appropriate in place of existing code that just skipped blanks.
Reviewed By: sscalpone
Differential Revision: https://reviews.llvm.org/D84061
Added:
flang/test/Parser/pp-dir-comments.f90
Modified:
flang/lib/Parser/preprocessor.cpp
flang/lib/Parser/token-sequence.cpp
flang/lib/Parser/token-sequence.h
Removed:
################################################################################
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 3b09597ddeb7..a1f07967d9b0 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -453,10 +453,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"# missing or invalid name"_err_en_US);
} else {
- j = dir.SkipBlanks(j + 1);
- if (j != tokens) {
+ if (dir.IsAnythingLeft(++j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
- "#undef: excess tokens at end of directive"_err_en_US);
+ "#undef: excess tokens at end of directive"_en_US);
} else {
definitions_.erase(nameToken);
}
@@ -468,8 +467,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"#%s: missing name"_err_en_US, dirName);
} else {
- j = dir.SkipBlanks(j + 1);
- if (j != tokens) {
+ if (dir.IsAnythingLeft(++j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#%s: excess tokens at end of directive"_en_US, dirName);
}
@@ -489,9 +487,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetTokenProvenanceRange(dirOffset));
}
} else if (dirName == "else") {
- if (j != tokens) {
+ if (dir.IsAnythingLeft(j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
- "#else: excess tokens at end of directive"_err_en_US);
+ "#else: excess tokens at end of directive"_en_US);
} else if (ifStack_.empty()) {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#else: not nested within #if, #ifdef, or #ifndef"_err_en_US);
@@ -516,9 +514,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
dir.GetTokenProvenanceRange(dirOffset));
}
} else if (dirName == "endif") {
- if (j != tokens) {
+ if (dir.IsAnythingLeft(j)) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
- "#endif: excess tokens at end of directive"_err_en_US);
+ "#endif: excess tokens at end of directive"_en_US);
} else if (ifStack_.empty()) {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#endif: no #if, #ifdef, or #ifndef"_err_en_US);
diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp
index ce94f2623501..07c5b12e5f75 100644
--- a/flang/lib/Parser/token-sequence.cpp
+++ b/flang/lib/Parser/token-sequence.cpp
@@ -56,6 +56,31 @@ std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
return tokens; // even if at > tokens
}
+// C-style /*comments*/ are removed from preprocessing directive
+// token sequences by the prescanner, but not C++ or Fortran
+// free-form line-ending comments (//... and !...) because
+// ignoring them is directive-specific.
+bool TokenSequence::IsAnythingLeft(std::size_t at) const {
+ std::size_t tokens{start_.size()};
+ for (; at < tokens; ++at) {
+ auto tok{TokenAt(at)};
+ const char *end{tok.end()};
+ for (const char *p{tok.begin()}; p < end; ++p) {
+ switch (*p) {
+ case '/':
+ return p + 1 >= end || p[1] != '/';
+ case '!':
+ return false;
+ case ' ':
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void TokenSequence::RemoveLastToken() {
CHECK(!start_.empty());
CHECK(nextStart_ > start_.back());
diff --git a/flang/lib/Parser/token-sequence.h b/flang/lib/Parser/token-sequence.h
index d73b3c20be6f..d98c0b955c5e 100644
--- a/flang/lib/Parser/token-sequence.h
+++ b/flang/lib/Parser/token-sequence.h
@@ -71,6 +71,10 @@ class TokenSequence {
std::size_t SkipBlanks(std::size_t) const;
+ // True if anything remains in the sequence at & after the given offset
+ // except blanks and line-ending C++ and Fortran free-form comments.
+ bool IsAnythingLeft(std::size_t) const;
+
void PutNextTokenChar(char ch, Provenance provenance) {
char_.emplace_back(ch);
provenances_.Put({provenance, 1});
diff --git a/flang/test/Parser/pp-dir-comments.f90 b/flang/test/Parser/pp-dir-comments.f90
new file mode 100644
index 000000000000..f5fe4ca5c71e
--- /dev/null
+++ b/flang/test/Parser/pp-dir-comments.f90
@@ -0,0 +1,19 @@
+! RUN: %f18 -funparse %s 2>&1 | FileCheck %s
+
+#define pmk
+#ifdef pmk // comment
+! CHECK: t1
+real t1
+#endif // comment
+#undef pmk ! comment
+#ifndef pmk ! comment
+! CHECK: t2
+real t2
+#endif // comment
+#if 0 /* C comment */ + 0
+! CHECK-NOT: misinterpreted
+# error misinterpreted #if
+#else // comment
+! CHECK: END PROGRAM
+end
+#endif ! comment
More information about the flang-commits
mailing list