diff options
Diffstat (limited to 'flang/lib/Parser/preprocessor.cpp')
-rw-r--r-- | flang/lib/Parser/preprocessor.cpp | 76 |
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 ¯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); } |