@@ -353,6 +353,7 @@ namespace tcpp
353353 void _removeMacroDefinition (const std::string& macroName) TCPP_NOEXCEPT;
354354
355355 std::vector<TToken> _expandMacroDefinition (const TMacroDesc& macroDesc, const TToken& idToken, const std::function<TToken()>& getNextTokenCallback) const TCPP_NOEXCEPT;
356+ std::vector<TToken> _expandArg (const std::function<TToken()>& getNextTokenCallback) const TCPP_NOEXCEPT;
356357
357358 void _expect (const E_TOKEN_TYPE& expectedType, const E_TOKEN_TYPE& actualType) const TCPP_NOEXCEPT;
358359
@@ -385,6 +386,8 @@ namespace tcpp
385386 // /< implementation of the library is placed below
386387#if defined(TCPP_IMPLEMENTATION)
387388
389+ static const std::string EMPTY_STR_VALUE = " " ;
390+
388391
389392 std::string ErrorTypeToString (const E_ERROR_TYPE& errorType) TCPP_NOEXCEPT
390393 {
@@ -418,7 +421,7 @@ namespace tcpp
418421 return " Incorrect usage of stringification operation" ;
419422 }
420423
421- return " " ;
424+ return EMPTY_STR_VALUE ;
422425 }
423426
424427
@@ -684,7 +687,7 @@ namespace tcpp
684687
685688 static const std::string separators = " ,()[]<>\" +-*/&|!=;" ;
686689
687- std::string currStr = " " ;
690+ std::string currStr = EMPTY_STR_VALUE ;
688691
689692 while (!inputLine.empty ())
690693 {
@@ -782,7 +785,7 @@ namespace tcpp
782785 inputLine.erase (0 , currDirectiveStr.length ());
783786 mCurrPos += currDirectiveStr.length ();
784787
785- return { std::get<E_TOKEN_TYPE>(currDirective), " " , mCurrLineIndex , mCurrPos };
788+ return { std::get<E_TOKEN_TYPE>(currDirective), EMPTY_STR_VALUE , mCurrLineIndex , mCurrPos };
786789 }
787790 }
788791
@@ -807,11 +810,11 @@ namespace tcpp
807810 case ' #' : // \note concatenation operator
808811 inputLine.erase (0 , 1 );
809812 ++mCurrPos ;
810- return { E_TOKEN_TYPE::CONCAT_OP, " " , mCurrLineIndex , mCurrPos };
813+ return { E_TOKEN_TYPE::CONCAT_OP, EMPTY_STR_VALUE , mCurrLineIndex , mCurrPos };
811814 default :
812815 if (nextCh != ' ' ) // \note stringification operator
813816 {
814- return { E_TOKEN_TYPE::STRINGIZE_OP, " " , mCurrLineIndex , mCurrPos };
817+ return { E_TOKEN_TYPE::STRINGIZE_OP, EMPTY_STR_VALUE , mCurrLineIndex , mCurrPos };
815818 }
816819
817820 return { E_TOKEN_TYPE::BLOB, " #" , mCurrLineIndex , mCurrPos };
@@ -973,7 +976,7 @@ namespace tcpp
973976
974977 if (!pCurrInputStream->HasNextLine ())
975978 {
976- return " " ;
979+ return EMPTY_STR_VALUE ;
977980 }
978981
979982 std::string sourceLine = pCurrInputStream->ReadLine ();
@@ -1557,6 +1560,11 @@ namespace tcpp
15571560
15581561 std::string replacementValue;
15591562
1563+ std::unordered_map<std::string, std::vector<TToken>> cachedArgsSequences
1564+ {
1565+ { EMPTY_STR_VALUE, {} }
1566+ };
1567+
15601568 for (size_t currArgIndex = 0 ; currArgIndex < processingTokens.size (); ++currArgIndex)
15611569 {
15621570 const bool variadics = macroDesc.mVariadic && currArgIndex == macroDesc.mArgsNames .size () - 1 ;
@@ -1581,14 +1589,50 @@ namespace tcpp
15811589 }
15821590 }
15831591
1584- for (auto & currToken : replacementList)
1592+ for (size_t currTokenIndex = 0 ; currTokenIndex < replacementList. size (); ++currTokenIndex )
15851593 {
1594+ TToken& currToken = replacementList[currTokenIndex];
1595+
15861596 if ((currToken.mType != E_TOKEN_TYPE::IDENTIFIER) || (currToken.mRawView != currArgName))
15871597 {
15881598 continue ;
15891599 }
1600+
1601+ // \note Check whether argument is used as an operand of token-pasting or stringification operators
1602+ auto nextNonSpaceToken = std::find_if (replacementList.cbegin () + currTokenIndex + 1 , replacementList.cend (), [](const TToken& token) { return token.mType != E_TOKEN_TYPE::SPACE; });
1603+ auto prevNonSpaceToken = std::find_if (replacementList.rbegin () + (replacementList.size () - currTokenIndex), replacementList.rend (), [](const TToken& token) { return token.mType != E_TOKEN_TYPE::SPACE; });
1604+
1605+ const bool isTokenPastingOperand =
1606+ (nextNonSpaceToken != replacementList.cend () && nextNonSpaceToken->mType == E_TOKEN_TYPE::CONCAT_OP) ||
1607+ (prevNonSpaceToken != replacementList.rend () && prevNonSpaceToken->mType == E_TOKEN_TYPE::CONCAT_OP);
1608+ const bool isStringifyOperand = currTokenIndex > 0 && replacementList[currTokenIndex - 1 ].mType == E_TOKEN_TYPE::STRINGIZE_OP;
1609+
1610+ if (isTokenPastingOperand || isStringifyOperand)
1611+ {
1612+ currToken.mRawView = replacementValue;
1613+ continue ;
1614+ }
15901615
1591- currToken.mRawView = replacementValue;
1616+ std::vector<TToken>& currExpandedArgTokens = cachedArgsSequences[EMPTY_STR_VALUE];
1617+
1618+ auto prevComputationIt = cachedArgsSequences.find (replacementValue);
1619+ if (prevComputationIt == cachedArgsSequences.cend ())
1620+ {
1621+ auto it = processingTokens[currArgIndex].begin ();
1622+ currExpandedArgTokens = _expandArg ([&processingTokens, &it, currArgIndex] { if (it == processingTokens[currArgIndex].end ()) return TToken{ E_TOKEN_TYPE::END }; return *it++; });
1623+ }
1624+ else
1625+ {
1626+ currExpandedArgTokens = prevComputationIt->second ;
1627+ }
1628+
1629+ currToken = *currExpandedArgTokens.cbegin ();
1630+
1631+ if (currExpandedArgTokens.size () > 1 )
1632+ {
1633+ replacementList.insert (replacementList.cbegin () + currTokenIndex + 1 , currExpandedArgTokens.cbegin () + 1 , currExpandedArgTokens.cend ());
1634+ currTokenIndex += currExpandedArgTokens.size () - 1 ;
1635+ }
15921636 }
15931637
15941638 if (variadics)
@@ -1601,9 +1645,86 @@ namespace tcpp
16011645 return replacementList;
16021646 }
16031647
1604- /* std::vector<TToken> Preprocessor::_expandMacroArg(const TMacroDesc& macroDesc, const TToken& idToken, const std::function<TToken()>& getNextTokenCallback) const TCPP_NOEXCEPT
1648+ std::vector<TToken> Preprocessor::_expandArg ( const std::function<TToken()>& getNextTokenCallback) const TCPP_NOEXCEPT
16051649 {
1606- }*/
1650+ std::vector<TToken> outputSequence{};
1651+
1652+ TToken currToken;
1653+
1654+ while ((currToken = getNextTokenCallback ()).mType != E_TOKEN_TYPE::END)
1655+ {
1656+ switch (currToken.mType )
1657+ {
1658+ case E_TOKEN_TYPE::IDENTIFIER: // \note try to expand some macro here
1659+ {
1660+ auto iter = std::find_if (mSymTable .cbegin (), mSymTable .cend (), [&currToken](auto && item)
1661+ {
1662+ return item.mName == currToken.mRawView ;
1663+ });
1664+
1665+ auto contextIter = std::find_if (mContextStack .cbegin (), mContextStack .cend (), [&currToken](auto && item)
1666+ {
1667+ return item == currToken.mRawView ;
1668+ });
1669+
1670+ if (iter != mSymTable .cend () && contextIter == mContextStack .cend ())
1671+ {
1672+ auto expandedMacroTokens = _expandMacroDefinition (*iter, currToken, getNextTokenCallback);
1673+ outputSequence.insert (outputSequence.cbegin (), expandedMacroTokens.cbegin (), expandedMacroTokens.cend ());
1674+ }
1675+ else
1676+ {
1677+ outputSequence.emplace_back (currToken);
1678+ }
1679+ }
1680+ break ;
1681+ case E_TOKEN_TYPE::REJECT_MACRO:
1682+ mContextStack .erase (std::remove_if (mContextStack .begin (), mContextStack .end (), [&currToken](auto && item)
1683+ {
1684+ return item == currToken.mRawView ;
1685+ }), mContextStack .end ());
1686+ break ;
1687+ case E_TOKEN_TYPE::CONCAT_OP:
1688+ #if 0
1689+ while (processedStr.back() == ' ') // \note Remove last character in the processed source if it was a whitespace
1690+ {
1691+ processedStr.erase(processedStr.length() - 1);
1692+ }
1693+
1694+ currToken = TrySkipWhitespaceTokensSequence(getNextTokenCallback(), getNextTokenCallback());
1695+ appendString(currToken.mRawView);
1696+ #endif
1697+ break ;
1698+ case E_TOKEN_TYPE::STRINGIZE_OP:
1699+ {
1700+ if (mContextStack .empty ())
1701+ {
1702+ mOnErrorCallback ({ E_ERROR_TYPE::INCORRECT_OPERATION_USAGE, mpLexer->GetCurrLineIndex () });
1703+ continue ;
1704+ }
1705+
1706+ TToken stringLiteralToken = currToken;
1707+ stringLiteralToken.mType = E_TOKEN_TYPE::BLOB;
1708+ stringLiteralToken.mRawView = " \" " + (currToken = mpLexer->GetNextToken ()).mRawView + " \" " ;
1709+
1710+ outputSequence.emplace_back (stringLiteralToken);
1711+ }
1712+ break ;
1713+ default :
1714+ if (E_TOKEN_TYPE::COMMENTARY == currToken.mType && mSkipCommentsTokens )
1715+ {
1716+ break ;
1717+ }
1718+
1719+ outputSequence.emplace_back (currToken);
1720+ break ;
1721+ }
1722+ }
1723+
1724+ TCPP_ASSERT (!outputSequence.empty ());
1725+
1726+ return outputSequence;
1727+ }
16071728
16081729 void Preprocessor::_expect (const E_TOKEN_TYPE& expectedType, const E_TOKEN_TYPE& actualType) const TCPP_NOEXCEPT
16091730 {
0 commit comments