[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 ¯o, 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