Make DefinesProxy go over a line with defines substitution multiple times until no further substitution has been done

This commit is contained in:
Jan 2021-10-31 16:21:04 +01:00
parent bba55706bf
commit 9816d01ac2
2 changed files with 83 additions and 70 deletions

View File

@ -26,7 +26,7 @@ DefinesStreamProxy::Define::Define(std::string name, std::string value)
{ {
} }
std::string DefinesStreamProxy::Define::Render(std::vector<std::string>& parameterValues) std::string DefinesStreamProxy::Define::Render(const std::vector<std::string>& parameterValues)
{ {
if (parameterValues.empty() || m_parameter_positions.empty()) if (parameterValues.empty() || m_parameter_positions.empty())
return m_value; return m_value;
@ -52,7 +52,7 @@ std::string DefinesStreamProxy::Define::Render(std::vector<std::string>& paramet
return str.str(); return str.str();
} }
void DefinesStreamProxy::Define::IdentifyParameters(std::vector<std::string>& parameterNames) void DefinesStreamProxy::Define::IdentifyParameters(const std::vector<std::string>& parameterNames)
{ {
if (parameterNames.empty()) if (parameterNames.empty())
return; return;
@ -168,7 +168,7 @@ bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, unsigned d
const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos); const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos);
auto parameters = MatchDefineParameters(line, directivePosition); const auto parameters = MatchDefineParameters(line, directivePosition);
std::string value; std::string value;
if (directivePosition < line.m_line.size()) if (directivePosition < line.m_line.size())
@ -346,77 +346,88 @@ void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line
void DefinesStreamProxy::ExpandDefines(ParserLine& line) void DefinesStreamProxy::ExpandDefines(ParserLine& line)
{ {
auto wordStart = 0u; bool usesDefines;
auto lastWordEnd = 0u; auto defineIterations = 0u;
auto inWord = false;
Define* value;
std::ostringstream str; do
auto usesDefines = false;
for (auto i = 0u; i < line.m_line.size(); i++)
{ {
const auto c = line.m_line[i]; if (defineIterations > MAX_DEFINE_ITERATIONS)
if (!inWord) throw ParsingException(CreatePos(line, 1), "Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
usesDefines = false;
auto wordStart = 0u;
auto lastWordEnd = 0u;
auto inWord = false;
Define* value;
std::ostringstream str;
for (auto i = 0u; i < line.m_line.size(); i++)
{ {
if (isalpha(c) || c == '_') const auto c = line.m_line[i];
if (!inWord)
{ {
wordStart = i; if (isalpha(c) || c == '_')
inWord = true;
}
}
else
{
if (!isalnum(c) && c != '_')
{
if (FindDefineForWord(line, wordStart, i, value))
{ {
std::vector<std::string> parameterValues; wordStart = i;
ExtractParametersFromDefineUsage(line, i, i, parameterValues); inWord = true;
const auto defineValue = value->Render(parameterValues);
if (!usesDefines)
{
str << std::string(line.m_line, 0, wordStart) << defineValue;
usesDefines = true;
}
else
{
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
}
lastWordEnd = i;
} }
inWord = false;
}
}
}
if (inWord)
{
if (FindDefineForWord(line, wordStart, line.m_line.size(), value))
{
std::vector<std::string> parameterValues;
const auto defineValue = value->Render(parameterValues);
if (!usesDefines)
{
str << std::string(line.m_line, 0, wordStart) << defineValue;
usesDefines = true;
} }
else else
{ {
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue; if (!isalnum(c) && c != '_')
} {
lastWordEnd = line.m_line.size(); if (FindDefineForWord(line, wordStart, i, value))
} {
} std::vector<std::string> parameterValues;
ExtractParametersFromDefineUsage(line, i, i, parameterValues);
const auto defineValue = value->Render(parameterValues);
if (usesDefines) if (!usesDefines)
{ {
if (lastWordEnd < line.m_line.size()) str << std::string(line.m_line, 0, wordStart) << defineValue;
str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd); usesDefines = true;
line.m_line = str.str(); }
} else
{
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
}
lastWordEnd = i;
}
inWord = false;
}
}
}
if (inWord)
{
if (FindDefineForWord(line, wordStart, line.m_line.size(), value))
{
const std::vector<std::string> parameterValues;
const auto defineValue = value->Render(parameterValues);
if (!usesDefines)
{
str << std::string(line.m_line, 0, wordStart) << defineValue;
usesDefines = true;
}
else
{
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
}
lastWordEnd = line.m_line.size();
}
}
if (usesDefines)
{
if (lastWordEnd < line.m_line.size())
str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd);
line.m_line = str.str();
}
defineIterations++;
} while (usesDefines);
} }
void DefinesStreamProxy::AddDefine(Define define) void DefinesStreamProxy::AddDefine(Define define)

View File

@ -15,6 +15,8 @@ class DefinesStreamProxy final : public AbstractDirectiveStreamProxy
static constexpr const char* ELSE_DIRECTIVE = "else"; static constexpr const char* ELSE_DIRECTIVE = "else";
static constexpr const char* ENDIF_DIRECTIVE = "endif"; static constexpr const char* ENDIF_DIRECTIVE = "endif";
static constexpr auto MAX_DEFINE_ITERATIONS = 128u;
public: public:
class DefineParameterPosition class DefineParameterPosition
{ {
@ -35,8 +37,8 @@ public:
Define(); Define();
Define(std::string name, std::string value); Define(std::string name, std::string value);
void IdentifyParameters(std::vector<std::string>& parameterNames); void IdentifyParameters(const std::vector<std::string>& parameterNames);
std::string Render(std::vector<std::string>& parameterValues); std::string Render(const std::vector<std::string>& parameterValues);
}; };
private: private:
@ -44,16 +46,16 @@ private:
std::unordered_map<std::string, Define> m_defines; std::unordered_map<std::string, Define> m_defines;
std::stack<bool> m_modes; std::stack<bool> m_modes;
unsigned m_ignore_depth; unsigned m_ignore_depth;
std::vector<std::string> MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition); static std::vector<std::string> MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition);
_NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchDirectives(const ParserLine& line); _NODISCARD bool MatchDirectives(const ParserLine& line);
void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues); static void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);
bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, Define*& value); bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, Define*& value);
void ExpandDefines(ParserLine& line); void ExpandDefines(ParserLine& line);