[flang-commits] [flang] [flang][preprocessor] Support \ as line continuation (PR #89970)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Wed Apr 24 11:30:16 PDT 2024


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/89970

When prescanning a Fortran source file with preprocessing enabled in free source form, interpret a line-ending backslash as a source line continuation marker as a C preprocessor would.  This usage isn't completely portable, but it is supported by GNU Fortran and appears in the source for FPM package manager.

>From 04202d25fa78f6e8c1ad2062f39005e34ed5fd38 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Wed, 24 Apr 2024 11:25:24 -0700
Subject: [PATCH] [flang][preprocessor] Support \ as line continuation

When prescanning a Fortran source file with preprocessing enabled
in free source form, interpret a line-ending backslash as a source
line continuation marker as a C preprocessor would.  This usage
isn't completely portable, but it is supported by GNU Fortran and
appears in the source for FPM package manager.
---
 flang/docs/Preprocessing.md                   |  3 +++
 flang/include/flang/Parser/preprocessor.h     |  1 +
 flang/lib/Parser/prescan.cpp                  | 21 +++++++++++++++----
 flang/lib/Parser/prescan.h                    |  1 +
 .../test/Preprocessing/backslash-contin1.F90  |  8 +++++++
 5 files changed, 30 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Preprocessing/backslash-contin1.F90

diff --git a/flang/docs/Preprocessing.md b/flang/docs/Preprocessing.md
index 3c523472f39bd0..0b70d857833cef 100644
--- a/flang/docs/Preprocessing.md
+++ b/flang/docs/Preprocessing.md
@@ -93,6 +93,9 @@ local:
 * If a `#define` or `#undef` directive appears among continuation
   lines, it may or may not affect text in the continued statement that
   appeared before the directive.
+* A backslash at the end of a free form source line is a continuation
+  marker, with no space skipping or special handling of a leading `&`
+  on the next line.
 
 ## Behavior that few compilers properly support (or none), but should:
 
diff --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h
index 630d5273d427c6..c3076435be5f0b 100644
--- a/flang/include/flang/Parser/preprocessor.h
+++ b/flang/include/flang/Parser/preprocessor.h
@@ -81,6 +81,7 @@ class Preprocessor {
   void Undefine(std::string macro);
   bool IsNameDefined(const CharBlock &);
   bool IsFunctionLikeDefinition(const CharBlock &);
+  bool AnyDefinitions() const { return !definitions_.empty(); }
 
   // When called with partialFunctionLikeMacro not null, MacroReplacement()
   // and ReplaceMacros() handle an unclosed function-like macro reference
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 96db3955299f33..17c2701d6a393c 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -29,15 +29,18 @@ Prescanner::Prescanner(Messages &messages, CookedSource &cooked,
     Preprocessor &preprocessor, common::LanguageFeatureControl lfc)
     : messages_{messages}, cooked_{cooked}, preprocessor_{preprocessor},
       allSources_{preprocessor_.allSources()}, features_{lfc},
+      backslashFreeFormContinuation_{preprocessor.AnyDefinitions()},
       encoding_{allSources_.encoding()} {}
 
 Prescanner::Prescanner(const Prescanner &that)
     : messages_{that.messages_}, cooked_{that.cooked_},
       preprocessor_{that.preprocessor_}, allSources_{that.allSources_},
-      features_{that.features_}, inFixedForm_{that.inFixedForm_},
+      features_{that.features_},
+      backslashFreeFormContinuation_{that.backslashFreeFormContinuation_},
+      inFixedForm_{that.inFixedForm_},
       fixedFormColumnLimit_{that.fixedFormColumnLimit_},
-      encoding_{that.encoding_}, prescannerNesting_{that.prescannerNesting_ +
-                                     1},
+      encoding_{that.encoding_},
+      prescannerNesting_{that.prescannerNesting_ + 1},
       skipLeadingAmpersand_{that.skipLeadingAmpersand_},
       compilerDirectiveBloomFilter_{that.compilerDirectiveBloomFilter_},
       compilerDirectiveSentinels_{that.compilerDirectiveSentinels_} {}
@@ -1190,6 +1193,16 @@ bool Prescanner::FreeFormContinuation() {
   bool ampersand{*p == '&'};
   if (ampersand) {
     p = SkipWhiteSpace(p + 1);
+  } else if (*p == '\\' && p + 2 == nextLine_ &&
+      backslashFreeFormContinuation_) {
+    // cpp-like handling of \ at end of a source line
+    if (nextLine_ < limit_) {
+      BeginSourceLine(nextLine_);
+      NextLine();
+      return true;
+    } else {
+      return false;
+    }
   }
   if (*p != '\n') {
     if (inCharLiteral_) {
@@ -1220,7 +1233,7 @@ bool Prescanner::IsImplicitContinuation() const {
 }
 
 bool Prescanner::Continuation(bool mightNeedFixedFormSpace) {
-  if (*at_ == '\n' || *at_ == '&') {
+  if (*at_ == '\n' || *at_ == '&' || *at_ == '\\') {
     if (inFixedForm_) {
       return FixedFormContinuation(mightNeedFixedFormSpace);
     } else {
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 581980001bcc23..3ee4c5a2c69eaa 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -197,6 +197,7 @@ class Prescanner {
   Preprocessor &preprocessor_;
   AllSources &allSources_;
   common::LanguageFeatureControl features_;
+  bool backslashFreeFormContinuation_{false};
   bool inFixedForm_{false};
   int fixedFormColumnLimit_{72};
   Encoding encoding_{Encoding::UTF_8};
diff --git a/flang/test/Preprocessing/backslash-contin1.F90 b/flang/test/Preprocessing/backslash-contin1.F90
new file mode 100644
index 00000000000000..cf2ed36370dab3
--- /dev/null
+++ b/flang/test/Preprocessing/backslash-contin1.F90
@@ -0,0 +1,8 @@
+! RUN: %flang -E %s | FileCheck %s
+print *, \
+  "hello, \
+world"
+end
+!CHECK:      print *, "hello, world"
+!CHECK:      end
+



More information about the flang-commits mailing list