Properly handle tabs in pragma directives and other precompiler statements

This commit is contained in:
Jan 2021-11-01 14:36:53 +01:00
parent be4e489118
commit e19f526d8b
8 changed files with 178 additions and 104 deletions

View File

@ -94,17 +94,29 @@ bool AbstractDirectiveStreamProxy::MatchNextString(const ParserLine& line, unsig
return SkipWhitespace(line, position) && MatchString(line, position, str, len);
}
bool AbstractDirectiveStreamProxy::FindDirective(const ParserLine& line, unsigned& directivePosition)
bool AbstractDirectiveStreamProxy::FindDirective(const ParserLine& line, unsigned& directiveStartPosition, unsigned& directiveEndPos)
{
directivePosition = 0;
for (; directivePosition < line.m_line.size(); directivePosition++)
directiveStartPosition = 0;
for (; directiveStartPosition < line.m_line.size(); directiveStartPosition++)
{
const auto c = line.m_line[directivePosition];
const auto c = line.m_line[directiveStartPosition];
if (isspace(c))
continue;
return c == '#';
if (c != '#')
continue;
directiveEndPos = directiveStartPosition + 1;
for(; directiveEndPos < line.m_line.size(); directiveEndPos++)
{
const auto c2 = line.m_line[directiveEndPos];
if (isspace(c2))
break;
}
return true;
}
return false;

View File

@ -18,5 +18,5 @@ protected:
static bool MatchString(const ParserLine& line, unsigned& position, const char* str, unsigned len);
static bool MatchNextString(const ParserLine& line, unsigned& position, const char* str, unsigned len);
static bool FindDirective(const ParserLine& line, unsigned& directivePosition);
static bool FindDirective(const ParserLine& line, unsigned& directiveStartPosition, unsigned& directiveEndPos);
};

View File

@ -157,22 +157,30 @@ std::vector<std::string> DefinesStreamProxy::MatchDefineParameters(const ParserL
return parameters;
}
bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, unsigned directivePosition)
bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
if (!MatchString(line, directivePosition, DEFINE_DIRECTIVE, std::char_traits<char>::length(DEFINE_DIRECTIVE)))
auto currentPos = directiveStartPosition;
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(DEFINE_DIRECTIVE)
|| !MatchString(line, currentPos, DEFINE_DIRECTIVE, std::char_traits<char>::length(DEFINE_DIRECTIVE)))
{
return false;
}
const auto nameStartPos = directivePosition;
if (!ExtractIdentifier(line, directivePosition))
throw ParsingException(CreatePos(line, directivePosition), "Cannot ifdef without a name.");
if (!SkipWhitespace(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot define without a name.");
const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos);
const auto nameStartPos = currentPos;
if (!ExtractIdentifier(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot define without a name.");
const auto parameters = MatchDefineParameters(line, directivePosition);
const auto name = line.m_line.substr(nameStartPos, currentPos - nameStartPos);
const auto parameters = MatchDefineParameters(line, currentPos);
std::string value;
if (directivePosition < line.m_line.size())
value = line.m_line.substr(directivePosition + 1);
if (currentPos < line.m_line.size())
value = line.m_line.substr(currentPos + 1);
Define define(name, value);
define.IdentifyParameters(parameters);
@ -181,19 +189,24 @@ bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, unsigned d
return true;
}
bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, unsigned directivePosition)
bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
if (!MatchString(line, directivePosition, UNDEF_DIRECTIVE, std::char_traits<char>::length(UNDEF_DIRECTIVE)))
auto currentPos = directiveStartPosition;
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(UNDEF_DIRECTIVE)
|| !MatchString(line, currentPos, UNDEF_DIRECTIVE, std::char_traits<char>::length(UNDEF_DIRECTIVE)))
{
return false;
}
if (!SkipWhitespace(line, directivePosition))
throw ParsingException(CreatePos(line, directivePosition), "Cannot undef without a name.");
if (!SkipWhitespace(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot undef without a name.");
const auto nameStartPos = directivePosition;
if (!ExtractIdentifier(line, directivePosition))
throw ParsingException(CreatePos(line, directivePosition), "Cannot ifdef without a name.");
const auto nameStartPos = currentPos;
if (!ExtractIdentifier(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot undef without a name.");
const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos);
const auto name = line.m_line.substr(nameStartPos, currentPos - nameStartPos);
const auto entry = m_defines.find(name);
if (entry != m_defines.end())
@ -202,13 +215,19 @@ bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, unsigned di
return true;
}
bool DefinesStreamProxy::MatchIfdefDirective(const ParserLine& line, unsigned directivePosition)
bool DefinesStreamProxy::MatchIfdefDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
auto currentPos = directiveStartPosition;
auto reverse = false;
if (!MatchString(line, directivePosition, IFDEF_DIRECTIVE, std::char_traits<char>::length(IFDEF_DIRECTIVE)))
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(IFDEF_DIRECTIVE)
|| !MatchString(line, currentPos, IFDEF_DIRECTIVE, std::char_traits<char>::length(IFDEF_DIRECTIVE)))
{
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(IFNDEF_DIRECTIVE)
|| !MatchString(line, currentPos, IFNDEF_DIRECTIVE, std::char_traits<char>::length(IFNDEF_DIRECTIVE)))
{
if (!MatchString(line, directivePosition, IFNDEF_DIRECTIVE, std::char_traits<char>::length(IFNDEF_DIRECTIVE)))
return false;
}
reverse = true;
}
@ -219,14 +238,14 @@ bool DefinesStreamProxy::MatchIfdefDirective(const ParserLine& line, unsigned di
return true;
}
if (!SkipWhitespace(line, directivePosition))
throw ParsingException(CreatePos(line, directivePosition), "Cannot ifdef without a name.");
if (!SkipWhitespace(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot ifdef without a name.");
const auto nameStartPos = directivePosition;
if (!ExtractIdentifier(line, directivePosition))
throw ParsingException(CreatePos(line, directivePosition), "Cannot ifdef without a name.");
const auto nameStartPos = currentPos;
if (!ExtractIdentifier(line, currentPos))
throw ParsingException(CreatePos(line, currentPos), "Cannot ifdef without a name.");
const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos);
const auto name = line.m_line.substr(nameStartPos, currentPos - nameStartPos);
const auto entry = m_defines.find(name);
if (entry != m_defines.end())
@ -237,10 +256,15 @@ bool DefinesStreamProxy::MatchIfdefDirective(const ParserLine& line, unsigned di
return true;
}
bool DefinesStreamProxy::MatchElseDirective(const ParserLine& line, unsigned directivePosition)
bool DefinesStreamProxy::MatchElseDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
if (!MatchString(line, directivePosition, ELSE_DIRECTIVE, std::char_traits<char>::length(ELSE_DIRECTIVE)))
auto currentPos = directiveStartPosition;
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(ELSE_DIRECTIVE)
|| !MatchString(line, currentPos, ELSE_DIRECTIVE, std::char_traits<char>::length(ELSE_DIRECTIVE)))
{
return false;
}
if (m_ignore_depth > 0)
return true;
@ -248,15 +272,20 @@ bool DefinesStreamProxy::MatchElseDirective(const ParserLine& line, unsigned dir
if (!m_modes.empty())
m_modes.top() = !m_modes.top();
else
throw ParsingException(CreatePos(line, directivePosition), "Cannot use else without ifdef");
throw ParsingException(CreatePos(line, currentPos), "Cannot use else without ifdef");
return true;
}
bool DefinesStreamProxy::MatchEndifDirective(const ParserLine& line, unsigned directivePosition)
bool DefinesStreamProxy::MatchEndifDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
if (!MatchString(line, directivePosition, ENDIF_DIRECTIVE, std::char_traits<char>::length(ENDIF_DIRECTIVE)))
auto currentPos = directiveStartPosition;
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(ENDIF_DIRECTIVE)
|| !MatchString(line, currentPos, ENDIF_DIRECTIVE, std::char_traits<char>::length(ENDIF_DIRECTIVE)))
{
return false;
}
if (m_ignore_depth > 0)
{
@ -267,30 +296,31 @@ bool DefinesStreamProxy::MatchEndifDirective(const ParserLine& line, unsigned di
if (!m_modes.empty())
m_modes.pop();
else
throw ParsingException(CreatePos(line, directivePosition), "Cannot use endif without ifdef");
throw ParsingException(CreatePos(line, currentPos), "Cannot use endif without ifdef");
return true;
}
bool DefinesStreamProxy::MatchDirectives(const ParserLine& line)
{
unsigned directivePos;
unsigned directiveStartPos;
unsigned directiveEndPos;
if (!FindDirective(line, directivePos))
if (!FindDirective(line, directiveStartPos, directiveEndPos))
return false;
directivePos++;
directiveStartPos++;
if (m_modes.empty() || m_modes.top() == true)
{
if (MatchDefineDirective(line, directivePos)
|| MatchUndefDirective(line, directivePos))
if (MatchDefineDirective(line, directiveStartPos, directiveEndPos)
|| MatchUndefDirective(line, directiveStartPos, directiveEndPos))
return true;
}
return MatchIfdefDirective(line, directivePos)
|| MatchElseDirective(line, directivePos)
|| MatchEndifDirective(line, directivePos);
return MatchIfdefDirective(line, directiveStartPos, directiveEndPos)
|| MatchElseDirective(line, directiveStartPos, directiveEndPos)
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos);
}
bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigned wordStart, const unsigned wordEnd, Define*& value)
@ -427,7 +457,8 @@ void DefinesStreamProxy::ExpandDefines(ParserLine& line)
}
defineIterations++;
} while (usesDefines);
}
while (usesDefines);
}
void DefinesStreamProxy::AddDefine(Define define)

View File

@ -8,10 +8,10 @@
class DefinesStreamProxy final : public AbstractDirectiveStreamProxy
{
static constexpr const char* DEFINE_DIRECTIVE = "define ";
static constexpr const char* UNDEF_DIRECTIVE = "undef ";
static constexpr const char* IFDEF_DIRECTIVE = "ifdef ";
static constexpr const char* IFNDEF_DIRECTIVE = "ifndef ";
static constexpr const char* DEFINE_DIRECTIVE = "define";
static constexpr const char* UNDEF_DIRECTIVE = "undef";
static constexpr const char* IFDEF_DIRECTIVE = "ifdef";
static constexpr const char* IFNDEF_DIRECTIVE = "ifndef";
static constexpr const char* ELSE_DIRECTIVE = "else";
static constexpr const char* ENDIF_DIRECTIVE = "endif";
@ -48,11 +48,11 @@ private:
unsigned m_ignore_depth;
static std::vector<std::string> MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition);
_NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchDirectives(const ParserLine& line);
static void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);

View File

@ -57,18 +57,23 @@ bool IncludingStreamProxy::ExtractIncludeFilename(const ParserLine& line, const
return false;
}
bool IncludingStreamProxy::MatchIncludeDirective(const ParserLine& line, unsigned directivePosition) const
bool IncludingStreamProxy::MatchIncludeDirective(const ParserLine& line, const unsigned directiveStartPos, const unsigned directiveEndPos) const
{
if (!MatchString(line, directivePosition, INCLUDE_DIRECTIVE, std::char_traits<char>::length(INCLUDE_DIRECTIVE)))
auto currentPos = directiveStartPos;
if (directiveEndPos - directiveStartPos != std::char_traits<char>::length(INCLUDE_DIRECTIVE)
|| !MatchString(line, currentPos, INCLUDE_DIRECTIVE, std::char_traits<char>::length(INCLUDE_DIRECTIVE)))
{
return false;
}
unsigned filenameStart, filenameEnd;
if (!ExtractIncludeFilename(line, directivePosition, filenameStart, filenameEnd))
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, static_cast<int>(directivePosition)), INCLUDE_QUOTES_ERROR);
if (!ExtractIncludeFilename(line, currentPos, filenameStart, filenameEnd))
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, static_cast<int>(currentPos)), INCLUDE_QUOTES_ERROR);
if (filenameEnd <= filenameStart)
throw ParsingException(CreatePos(line, directivePosition), "No filename specified");
throw ParsingException(CreatePos(line, currentPos), "No filename specified");
const auto filename = line.m_line.substr(filenameStart, filenameEnd - filenameStart);
@ -76,15 +81,26 @@ bool IncludingStreamProxy::MatchIncludeDirective(const ParserLine& line, unsigne
{
std::ostringstream errorStr;
errorStr << "Could not include file \"" << filename << "\"";
throw ParsingException(CreatePos(line, directivePosition), errorStr.str());
throw ParsingException(CreatePos(line, currentPos), errorStr.str());
}
return true;
}
bool IncludingStreamProxy::MatchPragmaOnceDirective(const ParserLine& line, unsigned directivePosition)
bool IncludingStreamProxy::MatchPragmaOnceDirective(const ParserLine& line, const unsigned directiveStartPos, const unsigned directiveEndPos)
{
if(!MatchString(line, directivePosition, PRAGMA_ONCE_DIRECTIVE, std::char_traits<char>::length(PRAGMA_ONCE_DIRECTIVE)))
auto currentPos = directiveStartPos;
if(directiveEndPos - directiveStartPos != std::char_traits<char>::length(PRAGMA_DIRECTIVE)
|| !MatchString(line, currentPos, PRAGMA_DIRECTIVE, std::char_traits<char>::length(PRAGMA_DIRECTIVE)))
{
return false;
}
if (!SkipWhitespace(line, currentPos))
return false;
if (!MatchString(line, currentPos, ONCE_PRAGMA_COMMAND, std::char_traits<char>::length(ONCE_PRAGMA_COMMAND)))
return false;
const auto absolutePath = absolute(fs::path(line.m_filename.get()));
@ -101,14 +117,14 @@ bool IncludingStreamProxy::MatchPragmaOnceDirective(const ParserLine& line, unsi
bool IncludingStreamProxy::MatchDirectives(const ParserLine& line)
{
unsigned directivePos;
unsigned directiveStartPos, directiveEndPos;
if (!FindDirective(line, directivePos))
if (!FindDirective(line, directiveStartPos, directiveEndPos))
return false;
directivePos++;
return MatchIncludeDirective(line, directivePos)
|| MatchPragmaOnceDirective(line, directivePos);
directiveStartPos++;
return MatchIncludeDirective(line, directiveStartPos, directiveEndPos)
|| MatchPragmaOnceDirective(line, directiveStartPos, directiveEndPos);
}
ParserLine IncludingStreamProxy::NextLine()

View File

@ -8,15 +8,16 @@
class IncludingStreamProxy final : public AbstractDirectiveStreamProxy
{
static constexpr const char* INCLUDE_QUOTES_ERROR = "Invalid include directive. Expected \"\" or <>";
static constexpr const char* INCLUDE_DIRECTIVE = "include ";
static constexpr const char* PRAGMA_ONCE_DIRECTIVE = "pragma once";
static constexpr const char* INCLUDE_DIRECTIVE = "include";
static constexpr const char* PRAGMA_DIRECTIVE = "pragma";
static constexpr const char* ONCE_PRAGMA_COMMAND = "once";
IParserLineStream* const m_stream;
std::set<std::string> m_included_files;
_NODISCARD static bool ExtractIncludeFilename(const ParserLine& line, unsigned includeDirectivePosition, unsigned& filenameStartPosition, unsigned& filenameEndPosition);
_NODISCARD bool MatchIncludeDirective(const ParserLine& line, unsigned directivePosition) const;
_NODISCARD bool MatchPragmaOnceDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD static bool ExtractIncludeFilename(const ParserLine& line, unsigned includeDirectivePosition, unsigned& directiveStartPos, unsigned& filenameEndPos);
_NODISCARD bool MatchIncludeDirective(const ParserLine& line, unsigned directiveStartPos, unsigned directiveEndPos) const;
_NODISCARD bool MatchPragmaOnceDirective(const ParserLine& line, unsigned directiveStartPos, unsigned directiveEndPos);
_NODISCARD bool MatchDirectives(const ParserLine& line);
public:

View File

@ -7,37 +7,50 @@ PackDefinitionStreamProxy::PackDefinitionStreamProxy(IParserLineStream* stream)
{
}
bool PackDefinitionStreamProxy::MatchPackDirective(const ParserLine& line, unsigned directivePosition)
bool PackDefinitionStreamProxy::MatchPackDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
{
auto packValue = 0;
auto currentPosition = directiveStartPosition;
if (!MatchString(line, directivePosition, PRAGMA_PACK_DIRECTIVE, std::char_traits<char>::length(PRAGMA_PACK_DIRECTIVE)))
return false;
if (!MatchNextCharacter(line, directivePosition, '('))
throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive.");
bool isPush;
if (MatchNextString(line, directivePosition, PUSH_KEYWORD, std::char_traits<char>::length(PUSH_KEYWORD)))
isPush = true;
else if (MatchNextString(line, directivePosition, POP_KEYWORD, std::char_traits<char>::length(POP_KEYWORD)))
isPush = false;
else
throw ParsingException(CreatePos(line, directivePosition), "Unknown pack directive command.");
if(isPush)
if (directiveEndPosition - directiveStartPosition != std::char_traits<char>::length(PRAGMA_DIRECTIVE)
|| !MatchString(line, currentPosition, PRAGMA_DIRECTIVE, std::char_traits<char>::length(PRAGMA_DIRECTIVE)))
{
if (!MatchNextCharacter(line, directivePosition, ','))
throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive.");
if (!ExtractInteger(line, directivePosition, packValue))
throw ParsingException(CreatePos(line, directivePosition), "Invalid pack value.");
return false;
}
if (!MatchNextCharacter(line, directivePosition, ')'))
throw ParsingException(CreatePos(line, directivePosition), "Invalid pack directive.");
if (!SkipWhitespace(line, currentPosition))
return false;
if(isPush)
if (!MatchString(line, currentPosition, PACK_PRAGMA_COMMAND, std::char_traits<char>::length(PACK_PRAGMA_COMMAND)))
return false;
if (!SkipWhitespace(line, currentPosition))
throw ParsingException(CreatePos(line, currentPosition), "Invalid pack directive.");
if (!MatchNextCharacter(line, currentPosition, '('))
throw ParsingException(CreatePos(line, currentPosition), "Invalid pack directive.");
bool isPush;
if (MatchNextString(line, currentPosition, PUSH_KEYWORD, std::char_traits<char>::length(PUSH_KEYWORD)))
isPush = true;
else if (MatchNextString(line, currentPosition, POP_KEYWORD, std::char_traits<char>::length(POP_KEYWORD)))
isPush = false;
else
throw ParsingException(CreatePos(line, currentPosition), "Unknown pack directive command.");
if (isPush)
{
if (!MatchNextCharacter(line, currentPosition, ','))
throw ParsingException(CreatePos(line, currentPosition), "Invalid pack directive.");
if (!ExtractInteger(line, currentPosition, packValue))
throw ParsingException(CreatePos(line, currentPosition), "Invalid pack value.");
}
if (!MatchNextCharacter(line, currentPosition, ')'))
throw ParsingException(CreatePos(line, currentPosition), "Invalid pack directive.");
if (isPush)
m_current_pack.push(packValue);
else if (!m_current_pack.empty())
m_current_pack.pop();
@ -47,13 +60,13 @@ bool PackDefinitionStreamProxy::MatchPackDirective(const ParserLine& line, unsig
bool PackDefinitionStreamProxy::MatchDirectives(const ParserLine& line)
{
unsigned directivePos;
unsigned directiveStartPos, directiveEndPos;
if (!FindDirective(line, directivePos))
if (!FindDirective(line, directiveStartPos, directiveEndPos))
return false;
directivePos++;
return MatchPackDirective(line, directivePos);
directiveStartPos++;
return MatchPackDirective(line, directiveStartPos, directiveEndPos);
}
ParserLine PackDefinitionStreamProxy::NextLine()

View File

@ -12,14 +12,15 @@ public:
static constexpr int DEFAULT_PACK = 8;
private:
static constexpr const char* PRAGMA_PACK_DIRECTIVE = "pragma pack";
static constexpr const char* PRAGMA_DIRECTIVE = "pragma";
static constexpr const char* PACK_PRAGMA_COMMAND = "pack";
static constexpr const char* PUSH_KEYWORD = "push";
static constexpr const char* POP_KEYWORD = "pop";
IParserLineStream* const m_stream;
std::stack<int> m_current_pack;
_NODISCARD bool MatchPackDirective(const ParserLine& line, unsigned directivePosition);
_NODISCARD bool MatchPackDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
_NODISCARD bool MatchDirectives(const ParserLine& line);
public: