aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Parser/preprocessor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Parser/preprocessor.cpp')
-rw-r--r--flang/lib/Parser/preprocessor.cpp76
1 files changed, 75 insertions, 1 deletions
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 6e8e3ae..a5de14d 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); }