Skip to content

Commit c26e752

Browse files
authored
[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.
1 parent 36ccfe2 commit c26e752

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

flang/include/flang/Parser/preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class Preprocessor {
116116
bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first,
117117
std::size_t exprTokens, Prescanner &);
118118
void LineDirective(const TokenSequence &, std::size_t, Prescanner &);
119+
TokenSequence TokenizeMacroBody(const std::string &);
119120

120121
AllSources &allSources_;
121122
std::list<std::string> names_;

flang/lib/Parser/preprocessor.cpp

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,82 @@ void Preprocessor::DefineStandardMacros() {
301301
Define("__TIMESTAMP__"s, "__TIMESTAMP__"s);
302302
}
303303

304+
static const std::string idChars{
305+
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"s};
306+
307+
static std::optional<std::vector<std::string>> TokenizeMacroNameAndArgs(
308+
const std::string &str) {
309+
// TODO: variadic macros on the command line (?)
310+
std::vector<std::string> names;
311+
for (std::string::size_type at{0};;) {
312+
auto nameStart{str.find_first_not_of(" "s, at)};
313+
if (nameStart == str.npos) {
314+
return std::nullopt;
315+
}
316+
auto nameEnd{str.find_first_not_of(idChars, nameStart)};
317+
if (nameEnd == str.npos) {
318+
return std::nullopt;
319+
}
320+
auto punc{str.find_first_not_of(" "s, nameEnd)};
321+
if (punc == str.npos) {
322+
return std::nullopt;
323+
}
324+
if ((at == 0 && str[punc] != '(') ||
325+
(at > 0 && str[punc] != ',' && str[punc] != ')')) {
326+
return std::nullopt;
327+
}
328+
names.push_back(str.substr(nameStart, nameEnd - nameStart));
329+
at = punc + 1;
330+
if (str[punc] == ')') {
331+
if (str.find_first_not_of(" "s, at) != str.npos) {
332+
return std::nullopt;
333+
} else {
334+
return names;
335+
}
336+
}
337+
}
338+
}
339+
340+
TokenSequence Preprocessor::TokenizeMacroBody(const std::string &str) {
341+
TokenSequence tokens;
342+
Provenance provenance{allSources_.AddCompilerInsertion(str).start()};
343+
auto end{str.size()};
344+
for (std::string::size_type at{0}; at < end;) {
345+
// Alternate between tokens that are identifiers (and therefore subject
346+
// to argument replacement) and those that are not.
347+
auto start{str.find_first_of(idChars, at)};
348+
if (start == str.npos) {
349+
tokens.Put(str.substr(at), provenance + at);
350+
break;
351+
} else if (start > at) {
352+
tokens.Put(str.substr(at, start - at), provenance + at);
353+
}
354+
at = str.find_first_not_of(idChars, start + 1);
355+
if (at == str.npos) {
356+
tokens.Put(str.substr(start), provenance + start);
357+
break;
358+
} else {
359+
tokens.Put(str.substr(start, at - start), provenance + start);
360+
}
361+
}
362+
return tokens;
363+
}
364+
304365
void Preprocessor::Define(const std::string &macro, const std::string &value) {
305-
definitions_.emplace(SaveTokenAsName(macro), Definition{value, allSources_});
366+
if (auto lhs{TokenizeMacroNameAndArgs(macro)}) {
367+
// function-like macro
368+
CharBlock macroName{SaveTokenAsName(lhs->front())};
369+
auto iter{lhs->begin()};
370+
++iter;
371+
std::vector<std::string> argNames{iter, lhs->end()};
372+
auto rhs{TokenizeMacroBody(value)};
373+
definitions_.emplace(std::make_pair(macroName,
374+
Definition{
375+
argNames, rhs, 0, rhs.SizeInTokens(), /*isVariadic=*/false}));
376+
} else { // keyword macro
377+
definitions_.emplace(
378+
SaveTokenAsName(macro), Definition{value, allSources_});
379+
}
306380
}
307381

308382
void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
! RUN: %flang_fc1 -fdebug-unparse "-Dfoo(a,b)=bar(a+b)" %s | FileCheck %s
2+
! CHECK: CALL bar(3_4)
3+
call foo(1,2)
4+
end

0 commit comments

Comments
 (0)