@@ -46,6 +46,12 @@ namespace Poco {
4646namespace CppParser {
4747
4848
49+ // Context-sensitive identifiers (not reserved keywords in C++,
50+ // but have special meaning in certain contexts)
51+ static const std::string ID_OVERRIDE (" override" );
52+ static const std::string ID_FINAL (" final" );
53+
54+
4955Parser::Parser (NameSpace::SymbolTable& gst, const std::string& file, std::istream& istr):
5056 _gst (gst),
5157 _istr (istr),
@@ -198,6 +204,9 @@ const Token* Parser::parseFile(const Token* pNext)
198204 case IdentifierToken::KW_ENUM:
199205 pNext = parseEnum (pNext);
200206 break ;
207+ case IdentifierToken::KW_STATIC_ASSERT:
208+ pNext = parseStaticAssert (pNext);
209+ break ;
201210 default :
202211 pNext = parseVarFunc (pNext);
203212 }
@@ -263,13 +272,23 @@ const Token* Parser::parseNameSpace(const Token* pNext)
263272 case IdentifierToken::KW_ENUM:
264273 pNext = parseEnum (pNext);
265274 break ;
275+ case IdentifierToken::KW_STATIC_ASSERT:
276+ pNext = parseStaticAssert (pNext);
277+ break ;
266278 default :
267279 pNext = parseVarFunc (pNext);
268280 }
269281 }
270282 expectOperator (pNext, OperatorToken::OP_CLOSBRACE, " }" );
271283 pNext = next ();
272284 }
285+ else if (isOperator (pNext, OperatorToken::OP_OPENBRACE))
286+ {
287+ // Anonymous namespace (namespace { ... }) contains implementation
288+ // details not relevant for API documentation; skip the entire block.
289+ pNext = parseBlock (pNext);
290+ return pNext;
291+ }
273292 else syntaxError (" namespace name" );
274293 popNameSpace ();
275294 return pNext;
@@ -305,7 +324,7 @@ const Token* Parser::parseClass(const Token* pNext, std::string& decl)
305324 pNext = next ();
306325
307326 bool isFinal = false ;
308- if (isIdentifier (pNext) && pNext->asString () == " final " )
327+ if (isIdentifier (pNext) && pNext->asString () == ID_FINAL )
309328 {
310329 pNext = next ();
311330 isFinal = true ;
@@ -424,6 +443,9 @@ const Token* Parser::parseClassMembers(const Token* pNext, Struct* /*pClass*/)
424443 case IdentifierToken::KW_FRIEND:
425444 pNext = parseFriend (pNext);
426445 break ;
446+ case IdentifierToken::KW_STATIC_ASSERT:
447+ pNext = parseStaticAssert (pNext);
448+ break ;
427449 case OperatorToken::OP_COMPL:
428450 default :
429451 pNext = parseVarFunc (pNext);
@@ -569,12 +591,19 @@ const Token* Parser::parseFriend(const Token* pNext)
569591{
570592 poco_assert (isKeyword (pNext, IdentifierToken::KW_FRIEND));
571593
594+ // Friend declarations come in two forms:
595+ // friend class Foo; — ends with ;
596+ // friend bool operator==(A a, B b) { ... } — inline definition ends with }
597+ // Skip the entire declaration in both cases.
572598 pNext = next ();
573-
574- while (!isOperator (pNext, OperatorToken::OP_SEMICOLON) && !isEOF (pNext))
599+ while (!isOperator (pNext, OperatorToken::OP_SEMICOLON) &&
600+ !isOperator (pNext, OperatorToken::OP_OPENBRACE) &&
601+ !isEOF (pNext))
575602 pNext = next ();
576603
577- if (isOperator (pNext, OperatorToken::OP_SEMICOLON))
604+ if (isOperator (pNext, OperatorToken::OP_OPENBRACE))
605+ pNext = parseBlock (pNext);
606+ else if (isOperator (pNext, OperatorToken::OP_SEMICOLON))
578607 pNext = next ();
579608 return pNext;
580609}
@@ -601,6 +630,18 @@ const Token* Parser::parseVarFunc(const Token* pNext, std::string& decl)
601630 }
602631 else
603632 {
633+ while (isKeyword (pNext, IdentifierToken::KW_ALIGNAS) ||
634+ isKeyword (pNext, IdentifierToken::KW_DECLTYPE))
635+ {
636+ // These keywords take parenthesized arguments and are part
637+ // of the declaration, not function names
638+ append (decl, pNext);
639+ pNext = next ();
640+ if (isOperator (pNext, OperatorToken::OP_OPENPARENT))
641+ {
642+ pNext = parseParenthesized (pNext, decl);
643+ }
644+ }
604645 append (decl, pNext);
605646 pNext = next ();
606647 bool isOperatorKeyword = false ;
@@ -691,6 +732,7 @@ const Token* Parser::parseFunc(const Token* pNext, const std::string& attrs, std
691732 {
692733 if (pFunc) pFunc->makeConst ();
693734 pNext = next ();
735+ continue ;
694736 }
695737 if (isKeyword (pNext, IdentifierToken::KW_THROW))
696738 {
@@ -702,13 +744,18 @@ const Token* Parser::parseFunc(const Token* pNext, const std::string& attrs, std
702744 {
703745 if (pFunc) pFunc->makeNoexcept ();
704746 pNext = next ();
747+ if (isOperator (pNext, OperatorToken::OP_OPENPARENT))
748+ {
749+ std::string tmp;
750+ pNext = parseParenthesized (pNext, tmp);
751+ }
705752 }
706- else if (isIdentifier (pNext) && pNext->asString () == " override " )
753+ else if (isIdentifier (pNext) && pNext->asString () == ID_OVERRIDE )
707754 {
708755 if (pFunc) pFunc->makeOverride ();
709756 pNext = next ();
710757 }
711- else if (isIdentifier (pNext) && pNext->asString () == " final " )
758+ else if (isIdentifier (pNext) && pNext->asString () == ID_FINAL )
712759 {
713760 if (pFunc) pFunc->makeFinal ();
714761 pNext = next ();
@@ -717,18 +764,26 @@ const Token* Parser::parseFunc(const Token* pNext, const std::string& attrs, std
717764 {
718765 break ; // handled below
719766 }
767+ else break ;
720768 }
721769 if (isOperator (pNext, OperatorToken::OP_ASSIGN))
722770 {
723771 pNext = next ();
724772 if (!pNext->is (Token::INTEGER_LITERAL_TOKEN) && !isKeyword (pNext, IdentifierToken::KW_DEFAULT) && !isKeyword (pNext, IdentifierToken::KW_DELETE))
725773 syntaxError (" 0, default or delete" );
726774 if (isKeyword (pNext, IdentifierToken::KW_DEFAULT))
727- pFunc->makeDefault ();
775+ {
776+ if (pFunc) pFunc->makeDefault ();
777+ }
728778 else if (isKeyword (pNext, IdentifierToken::KW_DELETE))
729- pFunc->makeDelete ();
779+ {
780+ if (pFunc) pFunc->makeDelete ();
781+ }
782+ else
783+ {
784+ if (pFunc) pFunc->makePureVirtual ();
785+ }
730786 pNext = next ();
731- if (pFunc) pFunc->makePureVirtual ();
732787 expectOperator (pNext, OperatorToken::OP_SEMICOLON, " ;" );
733788 }
734789 else if (isOperator (pNext, OperatorToken::OP_OPENBRACE) || isOperator (pNext, OperatorToken::OP_COLON))
@@ -957,6 +1012,44 @@ const Poco::Token* Parser::parseAttributes(const Poco::Token* pNext, std::string
9571012}
9581013
9591014
1015+ const Token* Parser::parseParenthesized (const Token* pNext, std::string& decl)
1016+ {
1017+ poco_assert (isOperator (pNext, OperatorToken::OP_OPENPARENT));
1018+
1019+ append (decl, pNext);
1020+ pNext = next ();
1021+ int depth = 1 ;
1022+ while (depth > 0 && !isEOF (pNext))
1023+ {
1024+ if (isOperator (pNext, OperatorToken::OP_OPENPARENT))
1025+ ++depth;
1026+ else if (isOperator (pNext, OperatorToken::OP_CLOSPARENT))
1027+ --depth;
1028+ if (depth > 0 )
1029+ {
1030+ append (decl, pNext);
1031+ pNext = next ();
1032+ }
1033+ }
1034+ append (decl, pNext); // closing ')'
1035+ pNext = next ();
1036+ return pNext;
1037+ }
1038+
1039+
1040+ const Token* Parser::parseStaticAssert (const Token* pNext)
1041+ {
1042+ poco_assert (isKeyword (pNext, IdentifierToken::KW_STATIC_ASSERT));
1043+
1044+ // skip static_assert(...); — not a declaration
1045+ while (!isOperator (pNext, OperatorToken::OP_SEMICOLON) && !isEOF (pNext))
1046+ pNext = next ();
1047+ if (isOperator (pNext, OperatorToken::OP_SEMICOLON))
1048+ pNext = next ();
1049+ return pNext;
1050+ }
1051+
1052+
9601053void Parser::addSymbol (Symbol* pSymbol, int lineNumber, bool addGST)
9611054{
9621055 pSymbol->setLineNumber (lineNumber);
0 commit comments