[flang-commits] [flang] c26e752 - [flang] Support -D for function-like macros (#139812)

via flang-commits flang-commits at lists.llvm.org
Thu May 15 11:26:07 PDT 2025


Author: Peter Klausler
Date: 2025-05-15T11:26:03-07:00
New Revision: c26e7520a939556bd23f7db3b7e0f4530b9d94a8

URL: https://github.com/llvm/llvm-project/commit/c26e7520a939556bd23f7db3b7e0f4530b9d94a8
DIFF: https://github.com/llvm/llvm-project/commit/c26e7520a939556bd23f7db3b7e0f4530b9d94a8.diff

LOG: [flang] Support -D for function-like macros (#139812)

Handle a command-line function-like macro definition like
"-Dfoo(a)=...".

TODO: error reporting for badly formed argument lists.

Added: 
    flang/test/Preprocessing/func-on-command-line.F90

Modified: 
    flang/include/flang/Parser/preprocessor.h
    flang/lib/Parser/preprocessor.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h
index 86528a7e68def..15810a34ee6a5 100644
--- a/flang/include/flang/Parser/preprocessor.h
+++ b/flang/include/flang/Parser/preprocessor.h
@@ -116,6 +116,7 @@ class Preprocessor {
   bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first,
       std::size_t exprTokens, Prescanner &);
   void LineDirective(const TokenSequence &, std::size_t, Prescanner &);
+  TokenSequence TokenizeMacroBody(const std::string &);
 
   AllSources &allSources_;
   std::list<std::string> names_;

diff  --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 6e8e3aee19b09..a5de14d864762 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -301,8 +301,82 @@ void Preprocessor::DefineStandardMacros() {
   Define("__TIMESTAMP__"s, "__TIMESTAMP__"s);
 }
 
+static const std::string idChars{
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"s};
+
+static std::optional<std::vector<std::string>> TokenizeMacroNameAndArgs(
+    const std::string &str) {
+  // TODO: variadic macros on the command line (?)
+  std::vector<std::string> names;
+  for (std::string::size_type at{0};;) {
+    auto nameStart{str.find_first_not_of(" "s, at)};
+    if (nameStart == str.npos) {
+      return std::nullopt;
+    }
+    auto nameEnd{str.find_first_not_of(idChars, nameStart)};
+    if (nameEnd == str.npos) {
+      return std::nullopt;
+    }
+    auto punc{str.find_first_not_of(" "s, nameEnd)};
+    if (punc == str.npos) {
+      return std::nullopt;
+    }
+    if ((at == 0 && str[punc] != '(') ||
+        (at > 0 && str[punc] != ',' && str[punc] != ')')) {
+      return std::nullopt;
+    }
+    names.push_back(str.substr(nameStart, nameEnd - nameStart));
+    at = punc + 1;
+    if (str[punc] == ')') {
+      if (str.find_first_not_of(" "s, at) != str.npos) {
+        return std::nullopt;
+      } else {
+        return names;
+      }
+    }
+  }
+}
+
+TokenSequence Preprocessor::TokenizeMacroBody(const std::string &str) {
+  TokenSequence tokens;
+  Provenance provenance{allSources_.AddCompilerInsertion(str).start()};
+  auto end{str.size()};
+  for (std::string::size_type at{0}; at < end;) {
+    // Alternate between tokens that are identifiers (and therefore subject
+    // to argument replacement) and those that are not.
+    auto start{str.find_first_of(idChars, at)};
+    if (start == str.npos) {
+      tokens.Put(str.substr(at), provenance + at);
+      break;
+    } else if (start > at) {
+      tokens.Put(str.substr(at, start - at), provenance + at);
+    }
+    at = str.find_first_not_of(idChars, start + 1);
+    if (at == str.npos) {
+      tokens.Put(str.substr(start), provenance + start);
+      break;
+    } else {
+      tokens.Put(str.substr(start, at - start), provenance + start);
+    }
+  }
+  return tokens;
+}
+
 void Preprocessor::Define(const std::string &macro, const std::string &value) {
-  definitions_.emplace(SaveTokenAsName(macro), Definition{value, allSources_});
+  if (auto lhs{TokenizeMacroNameAndArgs(macro)}) {
+    // function-like macro
+    CharBlock macroName{SaveTokenAsName(lhs->front())};
+    auto iter{lhs->begin()};
+    ++iter;
+    std::vector<std::string> argNames{iter, lhs->end()};
+    auto rhs{TokenizeMacroBody(value)};
+    definitions_.emplace(std::make_pair(macroName,
+        Definition{
+            argNames, rhs, 0, rhs.SizeInTokens(), /*isVariadic=*/false}));
+  } else { // keyword macro
+    definitions_.emplace(
+        SaveTokenAsName(macro), Definition{value, allSources_});
+  }
 }
 
 void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); }

diff  --git a/flang/test/Preprocessing/func-on-command-line.F90 b/flang/test/Preprocessing/func-on-command-line.F90
new file mode 100644
index 0000000000000..cf844e021b371
--- /dev/null
+++ b/flang/test/Preprocessing/func-on-command-line.F90
@@ -0,0 +1,4 @@
+! RUN: %flang_fc1 -fdebug-unparse "-Dfoo(a,b)=bar(a+b)" %s | FileCheck %s
+! CHECK: CALL bar(3_4)
+call foo(1,2)
+end


        


More information about the flang-commits mailing list