Update macro expansion logic to accept parameters over multiple lines

This commit is contained in:
Jan 2023-12-24 00:05:27 +01:00
parent b1d4176b6e
commit 9c80332147
No known key found for this signature in database
GPG Key ID: 44B581F78FF5C57C
2 changed files with 170 additions and 101 deletions

View File

@ -124,7 +124,9 @@ DefinesStreamProxy::DefinesStreamProxy(IParserLineStream* stream, const bool ski
m_skip_directive_lines(skipDirectiveLines), m_skip_directive_lines(skipDirectiveLines),
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_macro_parameter_state(ParameterState::NOT_IN_PARAMETERS)
{ {
} }
@ -278,8 +280,7 @@ bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, const unsig
return true; return true;
} }
std::unique_ptr<ISimpleExpression> std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString)
DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString) const
{ {
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString)); ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
ExpandDefinedExpressions(pseudoLine); ExpandDefinedExpressions(pseudoLine);
@ -474,9 +475,9 @@ bool DefinesStreamProxy::MatchDirectives(ParserLine& line)
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos); || MatchEndifDirective(line, directiveStartPos, directiveEndPos);
} }
bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigned wordStart, const unsigned wordEnd, const Define*& value) const bool DefinesStreamProxy::FindDefineForWord(const std::string& line, const unsigned wordStart, const unsigned wordEnd, const Define*& value) const
{ {
const std::string word(line.m_line, wordStart, wordEnd - wordStart); const std::string word(line, wordStart, wordEnd - wordStart);
const auto foundEntry = m_defines.find(word); const auto foundEntry = m_defines.find(word);
if (foundEntry != m_defines.end()) if (foundEntry != m_defines.end())
{ {
@ -487,71 +488,107 @@ bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigne
return false; return false;
} }
void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line, void DefinesStreamProxy::ContinueMacroParameters(const ParserLine& line, unsigned& pos)
const unsigned parameterStart,
unsigned& parameterEnd,
std::vector<std::string>& parameterValues)
{ {
if (line.m_line[parameterStart] != '(') const auto lineLength = line.m_line.size();
return; while (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS && pos < lineLength)
std::ostringstream currentValue;
auto pos = parameterStart + 1;
auto valueHasStarted = false;
auto parenthesisDepth = 0;
while (true)
{ {
if (pos >= line.m_line.size())
throw ParsingException(CreatePos(line, pos), "Invalid use of define");
const auto c = line.m_line[pos]; const auto c = line.m_line[pos];
if (c == ',') if (c == ',')
{ {
if (parenthesisDepth > 0) if (!m_macro_bracket_depth.empty())
{ {
valueHasStarted = true; m_macro_parameter_state = ParameterState::AFTER_PARAM;
currentValue << c; m_current_macro_parameter << c;
} }
else else
{ {
parameterValues.emplace_back(currentValue.str()); m_macro_parameters.emplace_back(m_current_macro_parameter.str());
currentValue.clear(); m_current_macro_parameter.clear();
currentValue.str(std::string()); m_current_macro_parameter.str(std::string());
valueHasStarted = false; m_macro_parameter_state = ParameterState::AFTER_COMMA;
} }
} }
else if (c == '(') else if (c == '(')
{ {
valueHasStarted = true; m_macro_parameter_state = ParameterState::AFTER_PARAM;
parenthesisDepth++; m_macro_bracket_depth.push('(');
currentValue << c; m_current_macro_parameter << c;
} }
else if (c == ')') else if (c == ')')
{ {
if (parenthesisDepth > 0) if (!m_macro_bracket_depth.empty())
{ {
valueHasStarted = true; if (m_macro_bracket_depth.top() != '(')
parenthesisDepth--; throw ParsingException(CreatePos(line, pos), "Unbalanced brackets in macro parameters");
currentValue << c;
m_macro_parameter_state = ParameterState::AFTER_PARAM;
m_macro_bracket_depth.pop();
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 else
{ {
parameterValues.emplace_back(currentValue.str()); m_macro_parameters.emplace_back(m_current_macro_parameter.str());
parameterEnd = pos + 1; m_macro_parameter_state = ParameterState::NOT_IN_PARAMETERS;
break;
} }
} }
else if (valueHasStarted || !isspace(c)) else if (m_macro_parameter_state == ParameterState::AFTER_PARAM || !isspace(c))
{ {
valueHasStarted = true; m_macro_parameter_state = ParameterState::AFTER_PARAM;
currentValue << c; m_current_macro_parameter << c;
} }
pos++; 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;
m_macro_parameters = std::vector<std::string>();
m_macro_bracket_depth = std::stack<char>();
m_macro_parameter_state = ParameterState::AFTER_OPEN;
parameterEnd = parameterStart + 1;
ContinueMacroParameters(line, parameterEnd);
}
bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName) bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName)
{ {
unsigned currentPos = pos; unsigned currentPos = pos;
@ -603,86 +640,103 @@ void DefinesStreamProxy::ExpandDefinedExpressions(ParserLine& line) const
} }
} }
void DefinesStreamProxy::ExpandDefines(ParserLine& line) const void DefinesStreamProxy::ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out)
{
ExtractParametersFromDefineUsage(line, pos, pos);
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 lastWordEnd = 0u;
auto inWord = false;
for (; pos < lineSize; pos++)
{
const auto c = line[pos];
if (!inWord)
{
if (isalpha(c) || c == '_')
{
wordStart = pos;
inWord = true;
}
}
else
{
if (!isalnum(c) && c != '_')
{
if (FindDefineForWord(line, wordStart, pos, define))
{
defineStart = wordStart;
return true;
}
inWord = false;
}
}
}
if (inWord)
{
if (FindDefineForWord(line, wordStart, pos, define))
{
defineStart = wordStart;
return true;
}
}
return false;
}
void DefinesStreamProxy::ExpandDefines(ParserLine& line)
{ {
bool usesDefines;
auto defineIterations = 0u; auto defineIterations = 0u;
bool usesDefines;
do do
{ {
if (defineIterations > MAX_DEFINE_ITERATIONS) if (defineIterations > MAX_DEFINE_ITERATIONS)
{
throw ParsingException(CreatePos(line, 1), throw ParsingException(CreatePos(line, 1),
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations."); "Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
}
usesDefines = false; usesDefines = false;
auto pos = 0u;
auto wordStart = 0u; auto defineStart = 0u;
auto lastWordEnd = 0u; auto lastDefineEnd = 0u;
auto inWord = false; const Define* define;
const Define* value;
std::ostringstream str; std::ostringstream str;
for (auto i = 0u; i < line.m_line.size(); i++) while (FindNextDefine(line.m_line, pos, defineStart, m_current_macro))
{ {
const auto c = line.m_line[i]; if (!usesDefines)
if (!inWord)
{ {
if (isalpha(c) || c == '_') usesDefines = true;
{ str << std::string(line.m_line, 0, defineStart);
wordStart = i;
inWord = true;
}
} }
else else
{ {
if (!isalnum(c) && c != '_') str << std::string(line.m_line, lastDefineEnd, defineStart - (lastDefineEnd));
{
if (FindDefineForWord(line, wordStart, i, value))
{
std::vector<std::string> parameterValues;
ExtractParametersFromDefineUsage(line, i, i, 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 = i;
}
inWord = false;
}
} }
}
if (inWord) ProcessDefine(line, pos, str);
{
if (FindDefineForWord(line, wordStart, line.m_line.size(), value))
{
const std::vector<std::string> parameterValues;
const auto defineValue = value->Render(parameterValues);
if (!usesDefines) lastDefineEnd = pos;
{
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 (usesDefines)
{ {
if (lastWordEnd < line.m_line.size()) if (lastDefineEnd < line.m_line.size())
str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd); str << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
line.m_line = str.str(); line.m_line = str.str();
} }
@ -728,6 +782,11 @@ ParserLine DefinesStreamProxy::NextLine()
line = m_stream->NextLine(); line = m_stream->NextLine();
} }
else if (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS)
{
ContinueMacro(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)
{ {
if (!m_skip_directive_lines) if (!m_skip_directive_lines)

View File

@ -74,6 +74,12 @@ private:
std::ostringstream m_current_define_value; std::ostringstream m_current_define_value;
std::vector<std::string> m_current_define_parameters; std::vector<std::string> m_current_define_parameters;
const Define* m_current_macro;
ParameterState m_macro_parameter_state;
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);
void ContinueDefine(const ParserLine& line, unsigned currentPos); void ContinueDefine(const ParserLine& line, unsigned currentPos);
@ -87,22 +93,26 @@ 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);
static void void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd);
ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues); bool FindDefineForWord(const std::string& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
bool FindDefineForWord(const ParserLine& line, 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);
void ContinueMacro(ParserLine& line);
void ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out);
bool FindNextDefine(const std::string& line, unsigned& pos, unsigned& defineStart, const DefinesStreamProxy::Define*& define);
public: public:
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false); explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
void AddDefine(Define define); void AddDefine(Define define);
void Undefine(const std::string& name); void Undefine(const std::string& name);
void ExpandDefines(ParserLine& line) const; void ExpandDefines(ParserLine& line);
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString) const; _NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString);
ParserLine NextLine() override; ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override; bool IncludeFile(const std::string& filename) override;