mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Make DefinesProxy expand nested macros independently to avoid recursion
This commit is contained in:
parent
37b1f7fe87
commit
3901ea2d3c
@ -34,34 +34,9 @@ DefinesStreamProxy::Define::Define(std::string name, std::string value)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DefinesStreamProxy::Define::Render(const std::vector<std::string>& parameterValues) const
|
DefinesStreamProxy::MacroParameterState::MacroParameterState()
|
||||||
|
: m_parameter_state(ParameterState::NOT_IN_PARAMETERS)
|
||||||
{
|
{
|
||||||
if (parameterValues.empty() || m_parameter_positions.empty())
|
|
||||||
return m_value;
|
|
||||||
|
|
||||||
std::ostringstream str;
|
|
||||||
auto lastPos = 0u;
|
|
||||||
for (const auto& parameterPosition : m_parameter_positions)
|
|
||||||
{
|
|
||||||
const auto stringizeSkipLastChar = parameterPosition.m_stringize ? 1 : 0;
|
|
||||||
if (lastPos < parameterPosition.m_parameter_position)
|
|
||||||
str << std::string(m_value, lastPos, parameterPosition.m_parameter_position - lastPos - stringizeSkipLastChar);
|
|
||||||
|
|
||||||
if (parameterPosition.m_parameter_index < parameterValues.size())
|
|
||||||
{
|
|
||||||
if (parameterPosition.m_stringize)
|
|
||||||
str << '"' << utils::EscapeStringForQuotationMarks(parameterValues[parameterPosition.m_parameter_index]) << '"';
|
|
||||||
else
|
|
||||||
str << parameterValues[parameterPosition.m_parameter_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPos = parameterPosition.m_parameter_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastPos < m_value.size())
|
|
||||||
str << std::string(m_value, lastPos, m_value.size() - lastPos);
|
|
||||||
|
|
||||||
return str.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::Define::IdentifyParameters(const std::vector<std::string>& parameterNames)
|
void DefinesStreamProxy::Define::IdentifyParameters(const std::vector<std::string>& parameterNames)
|
||||||
@ -144,8 +119,7 @@ DefinesStreamProxy::DefinesStreamProxy(IParserLineStream* stream, const bool ski
|
|||||||
m_ignore_depth(0),
|
m_ignore_depth(0),
|
||||||
m_in_define(false),
|
m_in_define(false),
|
||||||
m_parameter_state(ParameterState::NOT_IN_PARAMETERS),
|
m_parameter_state(ParameterState::NOT_IN_PARAMETERS),
|
||||||
m_current_macro(nullptr),
|
m_current_macro(nullptr)
|
||||||
m_macro_parameter_state(ParameterState::NOT_IN_PARAMETERS)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +277,7 @@ std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(std::shar
|
|||||||
{
|
{
|
||||||
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
|
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
|
||||||
ExpandDefinedExpressions(pseudoLine);
|
ExpandDefinedExpressions(pseudoLine);
|
||||||
ExpandDefines(pseudoLine);
|
ProcessMacrosMultiLine(pseudoLine);
|
||||||
|
|
||||||
std::istringstream ss(pseudoLine.m_line);
|
std::istringstream ss(pseudoLine.m_line);
|
||||||
ParserSingleInputStream inputStream(ss, "defines directive expression");
|
ParserSingleInputStream inputStream(ss, "defines directive expression");
|
||||||
@ -494,10 +468,13 @@ bool DefinesStreamProxy::MatchDirectives(ParserLine& line)
|
|||||||
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos);
|
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::FindDefineForWord(const std::string& line, const unsigned wordStart, const unsigned wordEnd, const Define*& value) const
|
bool DefinesStreamProxy::FindMacroForIdentifier(const std::string& input,
|
||||||
|
const unsigned identifierStart,
|
||||||
|
const unsigned identifierEnd,
|
||||||
|
const Define*& value) const
|
||||||
{
|
{
|
||||||
const std::string word(line, wordStart, wordEnd - wordStart);
|
const std::string identifier(input, identifierStart, identifierEnd - identifierStart);
|
||||||
const auto foundEntry = m_defines.find(word);
|
const auto foundEntry = m_defines.find(identifier);
|
||||||
if (foundEntry != m_defines.end())
|
if (foundEntry != m_defines.end())
|
||||||
{
|
{
|
||||||
value = &foundEntry->second;
|
value = &foundEntry->second;
|
||||||
@ -507,120 +484,20 @@ bool DefinesStreamProxy::FindDefineForWord(const std::string& line, const unsign
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ContinueMacroParameters(const ParserLine& line, unsigned& pos)
|
void DefinesStreamProxy::ExtractParametersFromMacroUsage(
|
||||||
|
const ParserLine& line, unsigned& linePos, MacroParameterState& state, const std::string& input, unsigned& inputPos)
|
||||||
{
|
{
|
||||||
const auto lineLength = line.m_line.size();
|
if (input[inputPos] != '(')
|
||||||
while (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS && pos < lineLength)
|
|
||||||
{
|
|
||||||
const auto c = line.m_line[pos];
|
|
||||||
|
|
||||||
if (c == ',')
|
|
||||||
{
|
|
||||||
if (!m_macro_bracket_depth.empty())
|
|
||||||
{
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
|
||||||
m_current_macro_parameter << c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
|
||||||
m_current_macro_parameter.clear();
|
|
||||||
m_current_macro_parameter.str(std::string());
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_COMMA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (c == '(' || c == '[' || c == '{')
|
|
||||||
{
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
|
||||||
m_macro_bracket_depth.push(c);
|
|
||||||
m_current_macro_parameter << c;
|
|
||||||
}
|
|
||||||
else if (c == ')')
|
|
||||||
{
|
|
||||||
if (!m_macro_bracket_depth.empty())
|
|
||||||
{
|
|
||||||
if (m_macro_bracket_depth.top() != '(')
|
|
||||||
throw ParsingException(CreatePos(line, pos), "Unbalanced brackets in macro parameters");
|
|
||||||
|
|
||||||
m_macro_bracket_depth.pop();
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
|
||||||
m_current_macro_parameter << c;
|
|
||||||
}
|
|
||||||
else if (m_macro_parameter_state == ParameterState::AFTER_COMMA)
|
|
||||||
{
|
|
||||||
throw ParsingException(CreatePos(line, pos), "Cannot close macro parameters after comma");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
|
||||||
m_macro_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (c == ']' || c == '}')
|
|
||||||
{
|
|
||||||
if (!m_macro_bracket_depth.empty())
|
|
||||||
{
|
|
||||||
const auto otherBracket = c == ']' ? '[' : '{';
|
|
||||||
if (m_macro_bracket_depth.top() != otherBracket)
|
|
||||||
throw ParsingException(CreatePos(line, pos), "Unbalanced brackets in macro parameters");
|
|
||||||
m_macro_bracket_depth.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
|
||||||
m_current_macro_parameter << c;
|
|
||||||
}
|
|
||||||
else if (m_macro_parameter_state == ParameterState::AFTER_PARAM || !isspace(c))
|
|
||||||
{
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
|
||||||
m_current_macro_parameter << c;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DefinesStreamProxy::ContinueMacro(ParserLine& line)
|
|
||||||
{
|
|
||||||
auto pos = 0u;
|
|
||||||
ContinueMacroParameters(line, pos);
|
|
||||||
|
|
||||||
if (m_macro_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
|
||||||
{
|
|
||||||
const auto defineValue = m_current_macro->Render(m_macro_parameters);
|
|
||||||
|
|
||||||
if (pos < line.m_line.size())
|
|
||||||
{
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << defineValue;
|
|
||||||
ss << std::string(line.m_line, pos, line.m_line.size() - pos);
|
|
||||||
line.m_line = ss.str();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line.m_line = defineValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpandDefines(line);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line.m_line = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line, const unsigned parameterStart, unsigned& parameterEnd)
|
|
||||||
{
|
|
||||||
if (line.m_line[parameterStart] != '(')
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_macro_parameter_state = ParameterState::AFTER_OPEN;
|
inputPos++;
|
||||||
m_macro_parameters = std::vector<std::string>();
|
state.m_parameter_state = ParameterState::AFTER_OPEN;
|
||||||
m_current_macro_parameter.clear();
|
state.m_parameters = std::vector<std::string>();
|
||||||
m_current_macro_parameter.str(std::string());
|
state.m_current_parameter.clear();
|
||||||
m_macro_bracket_depth = std::stack<char>();
|
state.m_current_parameter.str(std::string());
|
||||||
parameterEnd = parameterStart + 1;
|
state.m_bracket_depth = std::stack<char>();
|
||||||
|
|
||||||
ContinueMacroParameters(line, parameterEnd);
|
ContinueMacroParameters(line, linePos, state, input, inputPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName)
|
bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName)
|
||||||
@ -674,32 +551,21 @@ void DefinesStreamProxy::ExpandDefinedExpressions(ParserLine& line) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out)
|
bool DefinesStreamProxy::FindNextMacro(const std::string& input, unsigned& inputPos, unsigned& defineStart, const DefinesStreamProxy::Define*& define)
|
||||||
{
|
{
|
||||||
ExtractParametersFromDefineUsage(line, pos, pos);
|
const auto inputSize = input.size();
|
||||||
|
|
||||||
if (m_macro_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
|
||||||
{
|
|
||||||
const auto defineValue = m_current_macro->Render(m_macro_parameters);
|
|
||||||
out << defineValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DefinesStreamProxy::FindNextDefine(const std::string& line, unsigned& pos, unsigned& defineStart, const DefinesStreamProxy::Define*& define)
|
|
||||||
{
|
|
||||||
const auto lineSize = line.size();
|
|
||||||
auto wordStart = 0u;
|
auto wordStart = 0u;
|
||||||
auto lastWordEnd = 0u;
|
auto lastWordEnd = 0u;
|
||||||
auto inWord = false;
|
auto inWord = false;
|
||||||
|
|
||||||
for (; pos < lineSize; pos++)
|
for (; inputPos < inputSize; inputPos++)
|
||||||
{
|
{
|
||||||
const auto c = line[pos];
|
const auto c = input[inputPos];
|
||||||
if (!inWord)
|
if (!inWord)
|
||||||
{
|
{
|
||||||
if (isalpha(c) || c == '_')
|
if (isalpha(c) || c == '_')
|
||||||
{
|
{
|
||||||
wordStart = pos;
|
wordStart = inputPos;
|
||||||
inWord = true;
|
inWord = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -707,7 +573,7 @@ bool DefinesStreamProxy::FindNextDefine(const std::string& line, unsigned& pos,
|
|||||||
{
|
{
|
||||||
if (!isalnum(c) && c != '_')
|
if (!isalnum(c) && c != '_')
|
||||||
{
|
{
|
||||||
if (FindDefineForWord(line, wordStart, pos, define))
|
if (FindMacroForIdentifier(input, wordStart, inputPos, define))
|
||||||
{
|
{
|
||||||
defineStart = wordStart;
|
defineStart = wordStart;
|
||||||
return true;
|
return true;
|
||||||
@ -720,7 +586,7 @@ bool DefinesStreamProxy::FindNextDefine(const std::string& line, unsigned& pos,
|
|||||||
|
|
||||||
if (inWord)
|
if (inWord)
|
||||||
{
|
{
|
||||||
if (FindDefineForWord(line, wordStart, pos, define))
|
if (FindMacroForIdentifier(input, wordStart, inputPos, define))
|
||||||
{
|
{
|
||||||
defineStart = wordStart;
|
defineStart = wordStart;
|
||||||
return true;
|
return true;
|
||||||
@ -730,51 +596,253 @@ bool DefinesStreamProxy::FindNextDefine(const std::string& line, unsigned& pos,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ExpandDefines(ParserLine& line)
|
void DefinesStreamProxy::InsertMacroParameters(std::ostringstream& out, const DefinesStreamProxy::Define* macro, std::vector<std::string>& parameterValues)
|
||||||
{
|
{
|
||||||
auto defineIterations = 0u;
|
if (parameterValues.empty() || macro->m_parameter_positions.empty())
|
||||||
bool usesDefines;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (defineIterations > MAX_DEFINE_ITERATIONS)
|
out << macro->m_value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lastPos = 0u;
|
||||||
|
for (const auto& parameterPosition : macro->m_parameter_positions)
|
||||||
|
{
|
||||||
|
const auto stringizeSkipLastChar = parameterPosition.m_stringize ? 1 : 0;
|
||||||
|
if (lastPos < parameterPosition.m_parameter_position)
|
||||||
|
out << std::string(macro->m_value, lastPos, parameterPosition.m_parameter_position - lastPos - stringizeSkipLastChar);
|
||||||
|
|
||||||
|
if (parameterPosition.m_parameter_index < parameterValues.size())
|
||||||
{
|
{
|
||||||
throw ParsingException(CreatePos(line, 1),
|
if (!parameterPosition.m_stringize)
|
||||||
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
|
{
|
||||||
|
out << parameterValues[parameterPosition.m_parameter_index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out << '"' << utils::EscapeStringForQuotationMarks(parameterValues[parameterPosition.m_parameter_index]) << '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
usesDefines = false;
|
lastPos = parameterPosition.m_parameter_position;
|
||||||
auto pos = 0u;
|
}
|
||||||
auto defineStart = 0u;
|
|
||||||
auto lastDefineEnd = 0u;
|
|
||||||
std::ostringstream str;
|
|
||||||
|
|
||||||
while (FindNextDefine(line.m_line, pos, defineStart, m_current_macro))
|
if (lastPos < macro->m_value.size())
|
||||||
|
out << std::string(macro->m_value, lastPos, macro->m_value.size() - lastPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ExpandMacro(ParserLine& line,
|
||||||
|
unsigned& linePos,
|
||||||
|
std::ostringstream& out,
|
||||||
|
std::vector<const Define*>& callstack,
|
||||||
|
const DefinesStreamProxy::Define* macro,
|
||||||
|
std::vector<std::string>& parameterValues)
|
||||||
|
{
|
||||||
|
std::ostringstream rawOutput;
|
||||||
|
InsertMacroParameters(rawOutput, macro, parameterValues);
|
||||||
|
|
||||||
|
std::string str = rawOutput.str();
|
||||||
|
unsigned nestedPos = 0;
|
||||||
|
ProcessNestedMacros(line, linePos, callstack, str, nestedPos);
|
||||||
|
out << str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ContinueMacroParameters(
|
||||||
|
const ParserLine& line, unsigned& linePos, MacroParameterState& state, const std::string& input, unsigned& inputPos)
|
||||||
|
{
|
||||||
|
const auto lineLength = line.m_line.size();
|
||||||
|
while (state.m_parameter_state != ParameterState::NOT_IN_PARAMETERS && inputPos < lineLength)
|
||||||
|
{
|
||||||
|
const auto c = input[inputPos];
|
||||||
|
|
||||||
|
if (c == ',')
|
||||||
{
|
{
|
||||||
if (!usesDefines)
|
if (!state.m_bracket_depth.empty())
|
||||||
{
|
{
|
||||||
usesDefines = true;
|
state.m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
str << std::string(line.m_line, 0, defineStart);
|
state.m_current_parameter << c;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str << std::string(line.m_line, lastDefineEnd, defineStart - (lastDefineEnd));
|
state.m_parameters.emplace_back(state.m_current_parameter.str());
|
||||||
|
state.m_current_parameter.clear();
|
||||||
|
state.m_current_parameter.str(std::string());
|
||||||
|
m_parameter_state = ParameterState::AFTER_COMMA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '(' || c == '[' || c == '{')
|
||||||
|
{
|
||||||
|
state.m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
state.m_bracket_depth.push(c);
|
||||||
|
state.m_current_parameter << c;
|
||||||
|
}
|
||||||
|
else if (c == ')')
|
||||||
|
{
|
||||||
|
if (!state.m_bracket_depth.empty())
|
||||||
|
{
|
||||||
|
if (state.m_bracket_depth.top() != '(')
|
||||||
|
throw ParsingException(CreatePos(line, linePos), "Unbalanced brackets in macro parameters");
|
||||||
|
|
||||||
|
state.m_bracket_depth.pop();
|
||||||
|
state.m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
state.m_current_parameter << c;
|
||||||
|
}
|
||||||
|
else if (state.m_parameter_state == ParameterState::AFTER_COMMA)
|
||||||
|
{
|
||||||
|
throw ParsingException(CreatePos(line, linePos), "Cannot close macro parameters after comma");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.m_parameters.emplace_back(state.m_current_parameter.str());
|
||||||
|
state.m_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == ']' || c == '}')
|
||||||
|
{
|
||||||
|
if (!state.m_bracket_depth.empty())
|
||||||
|
{
|
||||||
|
const auto otherBracket = c == ']' ? '[' : '{';
|
||||||
|
if (state.m_bracket_depth.top() != otherBracket)
|
||||||
|
throw ParsingException(CreatePos(line, linePos), "Unbalanced brackets in macro parameters");
|
||||||
|
state.m_bracket_depth.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessDefine(line, pos, str);
|
state.m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
state.m_current_parameter << c;
|
||||||
lastDefineEnd = pos;
|
|
||||||
}
|
}
|
||||||
|
else if (state.m_parameter_state == ParameterState::AFTER_PARAM || !isspace(c))
|
||||||
if (usesDefines)
|
|
||||||
{
|
{
|
||||||
if (lastDefineEnd < line.m_line.size())
|
state.m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
str << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
|
state.m_current_parameter << c;
|
||||||
line.m_line = str.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defineIterations++;
|
inputPos++;
|
||||||
} while (usesDefines);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ContinueMultiLineMacro(ParserLine& line)
|
||||||
|
{
|
||||||
|
auto pos = 0u;
|
||||||
|
ContinueMacroParameters(line, pos, m_multi_line_macro_parameters, line.m_line, pos);
|
||||||
|
|
||||||
|
if (m_multi_line_macro_parameters.m_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
std::vector<const Define*> callstack;
|
||||||
|
ExpandMacro(line, pos, ss, callstack, m_current_macro, m_multi_line_macro_parameters.m_parameters);
|
||||||
|
|
||||||
|
if (pos < line.m_line.size())
|
||||||
|
ss << std::string(line.m_line, pos, line.m_line.size() - pos);
|
||||||
|
|
||||||
|
line.m_line = ss.str();
|
||||||
|
|
||||||
|
ProcessMacrosMultiLine(line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line.m_line = std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ProcessNestedMacros(ParserLine& line, unsigned& linePos, std::vector<const Define*>& callstack, std::string& input, unsigned& inputPos)
|
||||||
|
{
|
||||||
|
bool usesDefines = false;
|
||||||
|
|
||||||
|
auto pos = 0u;
|
||||||
|
auto defineStart = 0u;
|
||||||
|
auto lastDefineEnd = 0u;
|
||||||
|
std::ostringstream ss;
|
||||||
|
|
||||||
|
const Define* nestedMacro = nullptr;
|
||||||
|
while (FindNextMacro(input, pos, defineStart, nestedMacro))
|
||||||
|
{
|
||||||
|
if (std::find(callstack.cbegin(), callstack.cend(), nestedMacro) != callstack.cend())
|
||||||
|
{
|
||||||
|
// Do not expand recursively
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we account for all text between the last macro (or beginning) and now
|
||||||
|
if (!usesDefines)
|
||||||
|
{
|
||||||
|
usesDefines = true;
|
||||||
|
ss << std::string(input, 0, defineStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss << std::string(input, lastDefineEnd, defineStart - (lastDefineEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
callstack.push_back(nestedMacro);
|
||||||
|
|
||||||
|
MacroParameterState nestedMacroState;
|
||||||
|
ExtractParametersFromMacroUsage(line, pos, nestedMacroState, input, inputPos);
|
||||||
|
if (nestedMacroState.m_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
throw ParsingException(CreatePos(line, linePos), "Unbalanced brackets in macro parameters");
|
||||||
|
ExpandMacro(line, linePos, ss, callstack, nestedMacro, nestedMacroState.m_parameters);
|
||||||
|
|
||||||
|
callstack.pop_back();
|
||||||
|
|
||||||
|
lastDefineEnd = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usesDefines)
|
||||||
|
{
|
||||||
|
// Make sure we account for all text between the last macro and the end
|
||||||
|
if (lastDefineEnd < line.m_line.size())
|
||||||
|
ss << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
|
||||||
|
input = ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ProcessMacrosSingleLine(ParserLine& line)
|
||||||
|
{
|
||||||
|
unsigned pos = 0;
|
||||||
|
std::vector<const Define*> callstack;
|
||||||
|
ProcessNestedMacros(line, pos, callstack, line.m_line, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ProcessMacrosMultiLine(ParserLine& line)
|
||||||
|
{
|
||||||
|
bool usesDefines = false;
|
||||||
|
|
||||||
|
auto pos = 0u;
|
||||||
|
auto defineStart = 0u;
|
||||||
|
auto lastDefineEnd = 0u;
|
||||||
|
std::ostringstream str;
|
||||||
|
std::vector<const Define*> callstack;
|
||||||
|
while (FindNextMacro(line.m_line, pos, defineStart, m_current_macro))
|
||||||
|
{
|
||||||
|
// Make sure we account for all text between the last macro (or beginning) and now
|
||||||
|
if (!usesDefines)
|
||||||
|
{
|
||||||
|
usesDefines = true;
|
||||||
|
str << std::string(line.m_line, 0, defineStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str << std::string(line.m_line, lastDefineEnd, defineStart - (lastDefineEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
callstack.push_back(m_current_macro);
|
||||||
|
|
||||||
|
ExtractParametersFromMacroUsage(line, pos, m_multi_line_macro_parameters, line.m_line, pos);
|
||||||
|
|
||||||
|
// If still in parameters they continue on the next line
|
||||||
|
if (m_multi_line_macro_parameters.m_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
ExpandMacro(line, pos, str, callstack, m_current_macro, m_multi_line_macro_parameters.m_parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
callstack.pop_back();
|
||||||
|
|
||||||
|
lastDefineEnd = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usesDefines)
|
||||||
|
{
|
||||||
|
// Make sure we account for all text between the last macro and the end
|
||||||
|
if (lastDefineEnd < line.m_line.size())
|
||||||
|
str << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
|
||||||
|
line.m_line = str.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::AddDefine(Define define)
|
void DefinesStreamProxy::AddDefine(Define define)
|
||||||
@ -815,9 +883,9 @@ ParserLine DefinesStreamProxy::NextLine()
|
|||||||
|
|
||||||
line = m_stream->NextLine();
|
line = m_stream->NextLine();
|
||||||
}
|
}
|
||||||
else if (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
else if (m_multi_line_macro_parameters.m_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
||||||
{
|
{
|
||||||
ContinueMacro(line);
|
ContinueMultiLineMacro(line);
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
else if (MatchDirectives(line) || !m_modes.empty() && m_modes.top() != BlockMode::IN_BLOCK)
|
else if (MatchDirectives(line) || !m_modes.empty() && m_modes.top() != BlockMode::IN_BLOCK)
|
||||||
@ -832,7 +900,7 @@ ParserLine DefinesStreamProxy::NextLine()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExpandDefines(line);
|
ProcessMacrosMultiLine(line);
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
#include "Parsing/Simple/Expression/ISimpleExpression.h"
|
#include "Parsing/Simple/Expression/ISimpleExpression.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class DefinesStreamProxy final : public AbstractDirectiveStreamProxy
|
class DefinesStreamProxy final : public AbstractDirectiveStreamProxy
|
||||||
{
|
{
|
||||||
@ -44,15 +46,6 @@ public:
|
|||||||
Define();
|
Define();
|
||||||
Define(std::string name, std::string value);
|
Define(std::string name, std::string value);
|
||||||
void IdentifyParameters(const std::vector<std::string>& parameterNames);
|
void IdentifyParameters(const std::vector<std::string>& parameterNames);
|
||||||
_NODISCARD std::string Render(const std::vector<std::string>& parameterValues) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class BlockMode : uint8_t
|
|
||||||
{
|
|
||||||
NOT_IN_BLOCK,
|
|
||||||
IN_BLOCK,
|
|
||||||
BLOCK_BLOCKED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ParameterState : uint8_t
|
enum class ParameterState : uint8_t
|
||||||
@ -63,6 +56,26 @@ private:
|
|||||||
AFTER_COMMA
|
AFTER_COMMA
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MacroParameterState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParameterState m_parameter_state;
|
||||||
|
std::ostringstream m_current_parameter;
|
||||||
|
std::vector<std::string> m_parameters;
|
||||||
|
std::stack<char> m_bracket_depth;
|
||||||
|
|
||||||
|
MacroParameterState();
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class BlockMode : uint8_t
|
||||||
|
|
||||||
|
{
|
||||||
|
NOT_IN_BLOCK,
|
||||||
|
IN_BLOCK,
|
||||||
|
BLOCK_BLOCKED
|
||||||
|
};
|
||||||
|
|
||||||
IParserLineStream* const m_stream;
|
IParserLineStream* const m_stream;
|
||||||
const bool m_skip_directive_lines;
|
const bool m_skip_directive_lines;
|
||||||
std::map<std::string, Define> m_defines;
|
std::map<std::string, Define> m_defines;
|
||||||
@ -76,10 +89,7 @@ private:
|
|||||||
std::vector<std::string> m_current_define_parameters;
|
std::vector<std::string> m_current_define_parameters;
|
||||||
|
|
||||||
const Define* m_current_macro;
|
const Define* m_current_macro;
|
||||||
ParameterState m_macro_parameter_state;
|
MacroParameterState m_multi_line_macro_parameters;
|
||||||
std::vector<std::string> m_macro_parameters;
|
|
||||||
std::ostringstream m_current_macro_parameter;
|
|
||||||
std::stack<char> m_macro_bracket_depth;
|
|
||||||
|
|
||||||
static int GetLineEndEscapePos(const ParserLine& line);
|
static int GetLineEndEscapePos(const ParserLine& line);
|
||||||
void MatchDefineParameters(const ParserLine& line, unsigned& currentPos);
|
void MatchDefineParameters(const ParserLine& line, unsigned& currentPos);
|
||||||
@ -94,16 +104,28 @@ private:
|
|||||||
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchDirectives(ParserLine& line);
|
_NODISCARD bool MatchDirectives(ParserLine& line);
|
||||||
|
|
||||||
void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd);
|
void ExtractParametersFromMacroUsage(const ParserLine& line, unsigned& linePos, MacroParameterState& state, const std::string& input, unsigned& inputPos);
|
||||||
bool FindDefineForWord(const std::string& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
bool FindMacroForIdentifier(const std::string& input, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
||||||
|
|
||||||
static bool MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName);
|
static bool MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName);
|
||||||
void ExpandDefinedExpressions(ParserLine& line) const;
|
void ExpandDefinedExpressions(ParserLine& line) const;
|
||||||
|
|
||||||
void ContinueMacroParameters(const ParserLine& line, unsigned& pos);
|
bool FindNextMacro(const std::string& input, unsigned& inputPos, unsigned& defineStart, const DefinesStreamProxy::Define*& define);
|
||||||
void ContinueMacro(ParserLine& line);
|
|
||||||
void ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out);
|
void InsertMacroParameters(std::ostringstream& out, const DefinesStreamProxy::Define* macro, std::vector<std::string>& parameterValues);
|
||||||
bool FindNextDefine(const std::string& line, unsigned& pos, unsigned& defineStart, const DefinesStreamProxy::Define*& define);
|
void ExpandMacro(ParserLine& line,
|
||||||
|
unsigned& linePos,
|
||||||
|
std::ostringstream& out,
|
||||||
|
std::vector<const Define*>& callstack,
|
||||||
|
const DefinesStreamProxy::Define* macro,
|
||||||
|
std::vector<std::string>& parameterValues);
|
||||||
|
|
||||||
|
void ContinueMacroParameters(const ParserLine& line, unsigned& linePos, MacroParameterState& state, const std::string& input, unsigned& inputPos);
|
||||||
|
void ContinueMultiLineMacro(ParserLine& line);
|
||||||
|
|
||||||
|
void ProcessNestedMacros(ParserLine& line, unsigned& linePos, std::vector<const Define*>& callstack, std::string& input, unsigned& inputPos);
|
||||||
|
void ProcessMacrosSingleLine(ParserLine& line);
|
||||||
|
void ProcessMacrosMultiLine(ParserLine& line);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
|
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
|
||||||
@ -111,8 +133,6 @@ public:
|
|||||||
void AddDefine(Define define);
|
void AddDefine(Define define);
|
||||||
void Undefine(const std::string& name);
|
void Undefine(const std::string& name);
|
||||||
|
|
||||||
void ExpandDefines(ParserLine& line);
|
|
||||||
|
|
||||||
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString);
|
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString);
|
||||||
|
|
||||||
ParserLine NextLine() override;
|
ParserLine NextLine() override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user