diff --git a/Parser.cpp b/Parser.cpp index 67f94233..e3ebd72b 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -11,6 +11,59 @@ namespace fs = std::filesystem; namespace commonItems { std::string getNextLexeme(std::istream& theStream); + + +RegisteredRegexBase::RegisteredRegexBase(const std::string& keyword): regex(std::regex(keyword)) {} + + +RegisteredRegex::RegisteredRegex(const std::string& keyword, const parsingFunction& function): RegisteredRegexBase(keyword), function(function) {} + +bool RegisteredRegex::match(const std::string& lexeme, std::istream& theStream) +{ + if (!std::regex_match(lexeme, regex)) + return false; + else + { + function(lexeme, theStream); + return true; + } +} + +bool RegisteredRegex::matchStripped(const std::string& lexeme, const std::string& strippedLexeme, std::istream& theStream) +{ + if (!std::regex_match(strippedLexeme, regex)) + return false; + else + { + function(lexeme, theStream); + return true; + } +} + + +RegisteredRegexStreamOnly::RegisteredRegexStreamOnly(const std::string& keyword, const parsingFunctionStreamOnly& function): RegisteredRegexBase(keyword), function(function) {} + +bool RegisteredRegexStreamOnly::match(const std::string& lexeme, std::istream& theStream) +{ + if (!std::regex_match(lexeme, regex)) + return false; + else + { + function(theStream); + return true; + } +} + +bool RegisteredRegexStreamOnly::matchStripped(const std::string& lexeme, const std::string& strippedLexeme, std::istream& theStream) +{ + if (!std::regex_match(strippedLexeme, regex)) + return false; + else + { + function(theStream); + return true; + } +} } // namespace commonItems @@ -27,19 +80,25 @@ void commonItems::absorbBOM(std::istream& theStream) void commonItems::parser::registerKeyword(const std::string& keyword, const parsingFunction& function) { - registeredKeywordStrings.insert(std::make_pair(keyword, function)); + registeredRegexes.emplace_back(std::make_unique(keyword, function)); } void commonItems::parser::registerKeyword(const std::string& keyword, const parsingFunctionStreamOnly& function) { - registeredKeywordStringsStreamOnly.insert(std::make_pair(keyword, function)); + registeredRegexes.emplace_back(std::make_unique(keyword, function)); } void commonItems::parser::registerRegex(const std::string& keyword, const parsingFunction& function) { - generatedRegexes.emplace_back(std::regex(keyword), function); + registeredRegexes.emplace_back(std::make_unique(keyword, function)); +} + + +void commonItems::parser::registerRegex(const std::string& keyword, const parsingFunctionStreamOnly& function) +{ + registeredRegexes.emplace_back(std::make_unique(keyword, function)); } @@ -115,9 +174,7 @@ void commonItems::parser::parseFile(std::string_view filename) void commonItems::parser::clearRegisteredKeywords() noexcept { - std::map().swap(registeredKeywordStrings); - std::map().swap(registeredKeywordStringsStreamOnly); - std::vector>().swap(generatedRegexes); + std::vector>().swap(registeredRegexes); } @@ -137,11 +194,27 @@ std::optional commonItems::parser::getNextToken(std::istream& theSt const auto strippedLexeme = remQuotes(toReturn); const auto isLexemeQuoted = (strippedLexeme.size() < toReturn.size()); - auto matched = tryToMatchAgainstKeywords(toReturn, strippedLexeme, isLexemeQuoted, theStream); + bool matched = false; + for (const auto& registered: registeredRegexes) + { + if (registered->match(toReturn, theStream)) + { + matched = true; + break; + } + } + if (!matched && isLexemeQuoted) + { + for (const auto& registered: registeredRegexes) + { + if (registered->matchStripped(toReturn, strippedLexeme, theStream)) + { + matched = true; + break; + } + } + } - if (!matched) - matched = tryToMatchAgainstRegexes(toReturn, strippedLexeme, isLexemeQuoted, theStream); - if (!matched) gotToken = true; } @@ -152,70 +225,6 @@ std::optional commonItems::parser::getNextToken(std::istream& theSt } -inline bool commonItems::parser::tryToMatchAgainstKeywords(const std::string& toReturn, - const std::string& strippedLexeme, - bool isLexemeQuoted, - std::istream& theStream) -{ - if (const auto& match = registeredKeywordStringsStreamOnly.find(toReturn); match != registeredKeywordStringsStreamOnly.end()) - { - match->second(theStream); - return true; - } - else if (const auto& match = registeredKeywordStrings.find(toReturn); match != registeredKeywordStrings.end()) - { - match->second(toReturn, theStream); - return true; - } - else if (isLexemeQuoted) - { - if (const auto& strippedMatch = registeredKeywordStringsStreamOnly.find(strippedLexeme); - strippedMatch != registeredKeywordStringsStreamOnly.end()) - { - strippedMatch->second(theStream); - return true; - } - else if (const auto& strippedMatch = registeredKeywordStrings.find(strippedLexeme); - strippedMatch != registeredKeywordStrings.end()) - { - strippedMatch->second(toReturn, theStream); - return true; - } - } - - return false; -} - -inline bool commonItems::parser::tryToMatchAgainstRegexes(const std::string& toReturn, - const std::string& strippedLexeme, - bool isLexemeQuoted, - std::istream& theStream) -{ - for (const auto& [regex, parsingFunction]: generatedRegexes) - { - std::smatch match; - if (std::regex_match(toReturn, match, regex)) - { - parsingFunction(toReturn, theStream); - return true; - } - } - if (isLexemeQuoted) - { - for (const auto& [regex, parsingFunction]: generatedRegexes) - { - std::smatch match; - if (std::regex_match(strippedLexeme, match, regex)) - { - parsingFunction(toReturn, theStream); - return true; - } - } - } - return false; -} - - std::optional commonItems::parser::getNextTokenWithoutMatching(std::istream& theStream) { theStream >> std::noskipws; diff --git a/Parser.h b/Parser.h index 7893b800..45c0ab4e 100644 --- a/Parser.h +++ b/Parser.h @@ -20,6 +20,39 @@ typedef std::function parsingFunctionStreamOnly; void absorbBOM(std::istream& theStream); +class RegisteredRegexBase +{ + protected: + std::regex regex; + public: + RegisteredRegexBase(const std::string& keyword); + virtual ~RegisteredRegexBase() = default; + virtual bool match(const std::string& lexeme, std::istream& theStream) = 0; + virtual bool matchStripped(const std::string& lexeme, const std::string& strippedLexeme, std::istream& theStream) = 0; +}; + + +class RegisteredRegex: public RegisteredRegexBase +{ + private: + parsingFunction function; + public: + RegisteredRegex(const std::string& keyword, const parsingFunction& function); + bool match(const std::string& lexeme, std::istream& theStream); + bool matchStripped(const std::string& lexeme, const std::string& strippedLexeme, std::istream& theStream); +}; + +class RegisteredRegexStreamOnly: public RegisteredRegexBase +{ + private: + parsingFunctionStreamOnly function; + public: + RegisteredRegexStreamOnly(const std::string& keyword, const parsingFunctionStreamOnly& function); + bool match(const std::string& lexeme, std::istream& theStream); + bool matchStripped(const std::string& lexeme, const std::string& strippedLexeme, std::istream& theStream); +}; + + class parser { public: @@ -32,6 +65,7 @@ class parser void registerKeyword(const std::string& keyword, const parsingFunctionStreamOnly& function); void registerKeyword(const std::string& keyword, const parsingFunction& function); // for the few keywords that need to be returned + void registerRegex(const std::string& keyword, const parsingFunctionStreamOnly& function); void registerRegex(const std::string& keyword, const parsingFunction& function); void clearRegisteredKeywords() noexcept; @@ -44,18 +78,7 @@ class parser private: - inline bool tryToMatchAgainstKeywords(const std::string& toReturn, - const std::string& strippedLexeme, - bool isLexemeQuoted, - std::istream& theStream); - inline bool tryToMatchAgainstRegexes(const std::string& toReturn, - const std::string& strippedLexeme, - bool isLexemeQuoted, - std::istream& theStream); - - std::map registeredKeywordStringsStreamOnly; - std::map registeredKeywordStrings; - std::vector> generatedRegexes; + std::vector> registeredRegexes; }; } // namespace commonItems diff --git a/ParserHelpers.cpp b/ParserHelpers.cpp index d6f6c47e..caacc033 100644 --- a/ParserHelpers.cpp +++ b/ParserHelpers.cpp @@ -13,7 +13,7 @@ namespace commonItems std::string getNextLexeme(std::istream& theStream); -void ignoreItem(const std::string& unused, std::istream& theStream) +void ignoreItem(std::istream& theStream) { auto next = getNextLexeme(theStream); if (next == "=") @@ -59,7 +59,7 @@ void ignoreItem(const std::string& unused, std::istream& theStream) } -void ignoreObject(const std::string& unused, std::istream& theStream) +void ignoreObject(std::istream& theStream) { auto braceDepth = 0; while (true) @@ -86,7 +86,7 @@ void ignoreObject(const std::string& unused, std::istream& theStream) } -void ignoreString(const std::string& unused, std::istream& theStream) +void ignoreString(std::istream& theStream) { singleString ignore(theStream); } @@ -519,7 +519,7 @@ stringsOfItems::stringsOfItems(std::istream& theStream) stringsOfItemNames::stringsOfItemNames(std::istream& theStream) { registerRegex(catchallRegex, [this](const std::string& itemName, std::istream& theStream) { - ignoreItem(itemName, theStream); + ignoreItem(theStream); theStrings.push_back(itemName); }); diff --git a/ParserHelpers.h b/ParserHelpers.h index 96d8749c..39717cc1 100644 --- a/ParserHelpers.h +++ b/ParserHelpers.h @@ -12,9 +12,9 @@ namespace commonItems { -void ignoreItem(const std::string& unused, std::istream& theStream); -void ignoreObject(const std::string& unused, std::istream& theStream); -void ignoreString(const std::string& unused, std::istream& theStream); +void ignoreItem(std::istream& theStream); +void ignoreObject(std::istream& theStream); +void ignoreString(std::istream& theStream); /*function template only enabled for integer types diff --git a/tests/CommonItemsTests.vcxproj.filters b/tests/CommonItemsTests.vcxproj.filters index 33bc7c87..3280ba54 100644 --- a/tests/CommonItemsTests.vcxproj.filters +++ b/tests/CommonItemsTests.vcxproj.filters @@ -142,6 +142,8 @@ TestFiles - + + TestFiles + \ No newline at end of file diff --git a/tests/ParserHelperTests.cpp b/tests/ParserHelperTests.cpp index 40c76572..cff9d205 100644 --- a/tests/ParserHelperTests.cpp +++ b/tests/ParserHelperTests.cpp @@ -8,7 +8,7 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresSimpleText) { std::stringstream input{"ignore_me More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -20,7 +20,7 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresAssignedText) { std::stringstream input{"= ignore_me More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -32,7 +32,7 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresBracedItem) { std::stringstream input{"{ { ignore_me } } More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -44,7 +44,7 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresAssignedBracedItem) { std::stringstream input{"= { { ignore_me } } More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -56,7 +56,7 @@ TEST(ParserHelper_Tests, IgnoreObjectIgnoresNextItem) { std::stringstream input{"ignore_me More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -68,7 +68,7 @@ TEST(ParserHelper_Tests, IgnoreObjectIgnoresWholeBracedItem) { std::stringstream input{"{ { ignore_me } } More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -80,7 +80,7 @@ TEST(ParserHelper_Tests, IgnoreStringIgnoresNextItem) { std::stringstream input{"ignore_me More text"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -92,7 +92,7 @@ TEST(ParserHelper_Tests, IgnoreStringIgnoresWholeQuoation) { std::stringstream input{R"("ignore_me More" text)"}; input >> std::noskipws; - commonItems::ignoreItem("unused", input); + commonItems::ignoreItem(input); char buffer[256]; input.getline(buffer, sizeof buffer); @@ -893,8 +893,8 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresSimpleColorWithColorSpace) std::stringstream input2{"hsv {0.1 1.0 0.6} More text"}; input >> std::noskipws; input2 >> std::noskipws; - commonItems::ignoreItem("unused", input); - commonItems::ignoreItem("unused", input2); + commonItems::ignoreItem(input); + commonItems::ignoreItem(input2); char buffer[256]; char buffer2[256]; @@ -911,8 +911,8 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresAssignedColorWithColorSpace) std::stringstream input2{"= hsv {0.1 1.0 0.6} More text"}; input >> std::noskipws; input2 >> std::noskipws; - commonItems::ignoreItem("unused", input); - commonItems::ignoreItem("unused", input2); + commonItems::ignoreItem(input); + commonItems::ignoreItem(input2); char buffer[256]; char buffer2[256]; @@ -929,8 +929,8 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresRgbAndHsvStringsWithoutBreakingParsing std::stringstream input2{"= hsv next_parameter = 420 More text"}; input >> std::noskipws; input2 >> std::noskipws; - commonItems::ignoreItem("unused", input); - commonItems::ignoreItem("unused", input2); + commonItems::ignoreItem(input); + commonItems::ignoreItem(input2); char buffer[256]; char buffer2[256]; @@ -947,8 +947,8 @@ TEST(ParserHelper_Tests, IgnoreItemIgnoresQuotedRgbAndHsvStringsWithoutBreakingP std::stringstream input2{"= \"hsv\" next_parameter = 420 More text"}; input >> std::noskipws; input2 >> std::noskipws; - commonItems::ignoreItem("unused", input); - commonItems::ignoreItem("unused", input2); + commonItems::ignoreItem(input); + commonItems::ignoreItem(input2); char buffer[256]; char buffer2[256];