1//
2// Parser.cpp
3//
4// Library: CppParser
5// Package: CppParser
6// Module: Parser
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/CppParser/Parser.h"
16#include "Poco/CppParser/CppToken.h"
17#include "Poco/CppParser/Decl.h"
18#include "Poco/CppParser/Enum.h"
19#include "Poco/CppParser/EnumValue.h"
20#include "Poco/CppParser/Function.h"
21#include "Poco/CppParser/NameSpace.h"
22#include "Poco/CppParser/Parameter.h"
23#include "Poco/CppParser/Struct.h"
24#include "Poco/CppParser/TypeDef.h"
25#include "Poco/CppParser/Variable.h"
26#include "Poco/CppParser/AttributesParser.h"
27#include "Poco/Path.h"
28#include "Poco/String.h"
29#include "Poco/NumberFormatter.h"
30#include "Poco/Exception.h"
31#include <sstream>
32#include <cctype>
33
34
35using Poco::Token;
36using Poco::WhitespaceToken;
37using Poco::Path;
38using Poco::NumberFormatter;
39using Poco::SyntaxException;
40using Poco::icompare;
41using Poco::trimInPlace;
42
43
44namespace Poco {
45namespace CppParser {
46
47
48Parser::Parser(NameSpace::SymbolTable& gst, const std::string& file, std::istream& istr):
49 _gst(gst),
50 _istr(istr),
51 _tokenizer(_istr),
52 _file(file),
53 _inFile(false),
54 _pCurrentSymbol(0),
55 _access(Symbol::ACC_PUBLIC)
56{
57 Path p(file);
58 p.makeAbsolute();
59 _path = p.toString();
60 _currentPath = _path;
61
62 _nsStack.push_back(NameSpace::root());
63}
64
65
66Parser::~Parser()
67{
68}
69
70
71inline bool Parser::isIdentifier(const Token* pToken)
72{
73 return pToken->is(Token::IDENTIFIER_TOKEN) || isOperator(pToken, OperatorToken::OP_DBL_COLON);
74}
75
76
77inline bool Parser::isOperator(const Token* pToken, int kind)
78{
79 return pToken->is(Token::OPERATOR_TOKEN) && pToken->asInteger() == kind;
80}
81
82
83inline bool Parser::isKeyword(const Token* pToken, int kind)
84{
85 return pToken->is(Token::KEYWORD_TOKEN) && pToken->asInteger() == kind;
86}
87
88
89inline bool Parser::isEOF(const Token* pToken)
90{
91 return pToken->is(Token::EOF_TOKEN);
92}
93
94
95void Parser::expectOperator(const Token* pToken, int kind, const std::string& msg)
96{
97 if (!isOperator(pToken, kind))
98 syntaxError(msg + ", found " + pToken->tokenString());
99}
100
101
102void Parser::syntaxError(const std::string& msg)
103{
104 throw SyntaxException("Expected", msg);
105}
106
107
108inline void Parser::append(std::string& decl, const std::string& token)
109{
110 if (!decl.empty())
111 {
112 char last = decl[decl.length() - 1];
113 if (token != "::" &&
114 token != "." &&
115 token != ")" &&
116 token != "->" &&
117 token != "," &&
118 token != "[" &&
119 token != "]" &&
120 last != '~' &&
121 last != ':' &&
122 last != '(' &&
123 last != ')' &&
124 last != '[' &&
125 last != ']' &&
126 last != ' '
127 )
128 decl.append(" ");
129 }
130 decl.append(token);
131 if (token == "const"
132 || token == "constexpr"
133 || token == "static"
134 || token == "mutable"
135 || token == "inline"
136 || token == "volatile"
137 || token == "register"
138 || token == "thread_local")
139 decl.append(" ");
140}
141
142
143inline void Parser::append(std::string& decl, const Token* pToken)
144{
145 poco_check_ptr (pToken);
146 append(decl, pToken->tokenString());
147}
148
149
150void Parser::parse()
151{
152 try
153 {
154 const Token* pNext = next();
155 pNext = parseFile(pNext);
156 if (!isEOF(pNext))
157 syntaxError("Additional tokens behind supposed EOF");
158 }
159 catch (SyntaxException& exc)
160 {
161 std::string m(exc.message());
162 std::string where(_currentPath);
163 where.append("(");
164 where.append(NumberFormatter::format(static_cast<int>(_istr.getCurrentLineNumber())));
165 where.append(")");
166 throw SyntaxException(m, where);
167 }
168}
169
170
171const Token* Parser::parseFile(const Token* pNext)
172{
173 while (pNext->is(Token::IDENTIFIER_TOKEN) || pNext->is(Token::KEYWORD_TOKEN))
174 {
175 switch (pNext->asInteger())
176 {
177 case IdentifierToken::KW_NAMESPACE:
178 pNext = parseNameSpace(pNext);
179 break;
180 case IdentifierToken::KW_STRUCT:
181 case IdentifierToken::KW_CLASS:
182 case IdentifierToken::KW_UNION:
183 pNext = parseClass(pNext);
184 break;
185 case IdentifierToken::KW_TEMPLATE:
186 pNext = parseTemplate(pNext);
187 break;
188 case IdentifierToken::KW_TYPEDEF:
189 pNext = parseTypeDef(pNext);
190 break;
191 case IdentifierToken::KW_USING:
192 pNext = parseUsing(pNext);
193 break;
194 case IdentifierToken::KW_ENUM:
195 pNext = parseEnum(pNext);
196 break;
197 default:
198 pNext = parseVarFunc(pNext);
199 }
200 }
201 return pNext;
202}
203
204
205const Token* Parser::parseNameSpace(const Token* pNext)
206{
207 poco_assert (isKeyword(pNext, IdentifierToken::KW_NAMESPACE));
208
209 pNext = next();
210 if (pNext->is(Token::IDENTIFIER_TOKEN))
211 {
212 _access = Symbol::ACC_PUBLIC;
213 std::string name = pNext->tokenString();
214 pNext = next();
215 expectOperator(pNext, OperatorToken::OP_OPENBRACE, "{");
216
217 std::string fullName = currentNameSpace()->fullName();
218 if (!fullName.empty()) fullName += "::";
219 fullName += name;
220
221 NameSpace* pNS = dynamic_cast<NameSpace*>(currentNameSpace()->lookup(fullName));
222 bool undefined = (pNS == 0);
223 if (undefined) pNS = new NameSpace(name, currentNameSpace());
224 pushNameSpace(pNS, -1, undefined);
225 pNext = next();
226 while (pNext->is(Token::IDENTIFIER_TOKEN) || pNext->is(Token::KEYWORD_TOKEN))
227 {
228 switch (pNext->asInteger())
229 {
230 case IdentifierToken::KW_NAMESPACE:
231 pNext = parseNameSpace(pNext);
232 break;
233 case IdentifierToken::KW_STRUCT:
234 case IdentifierToken::KW_CLASS:
235 case IdentifierToken::KW_UNION:
236 pNext = parseClass(pNext);
237 break;
238 case IdentifierToken::KW_TEMPLATE:
239 pNext = parseTemplate(pNext);
240 break;
241 case IdentifierToken::KW_TYPEDEF:
242 pNext = parseTypeDef(pNext);
243 break;
244 case IdentifierToken::KW_USING:
245 pNext = parseUsing(pNext);
246 break;
247 case IdentifierToken::KW_ENUM:
248 pNext = parseEnum(pNext);
249 break;
250 default:
251 pNext = parseVarFunc(pNext);
252 }
253 }
254 expectOperator(pNext, OperatorToken::OP_CLOSBRACE, "}");
255 pNext = next();
256 }
257 else syntaxError("namespace name");
258 popNameSpace();
259 return pNext;
260}
261
262
263const Token* Parser::parseClass(const Token* pNext)
264{
265 std::string decl;
266 return parseClass(pNext, decl);
267}
268
269
270const Token* Parser::parseClass(const Token* pNext, std::string& decl)
271{
272 poco_assert (isKeyword(pNext, IdentifierToken::KW_CLASS) || isKeyword(pNext, IdentifierToken::KW_STRUCT) || isKeyword(pNext, IdentifierToken::KW_UNION));
273
274 _pCurrentSymbol = 0;
275 bool isClass = isKeyword(pNext, IdentifierToken::KW_CLASS);
276 int line = _istr.getCurrentLineNumber();
277 Symbol::Access prevAccess = _access;
278 append(decl, pNext);
279 Symbol::Access access;
280 if (isKeyword(pNext, IdentifierToken::KW_CLASS))
281 access = Symbol::ACC_PRIVATE;
282 else
283 access = Symbol::ACC_PUBLIC;
284 pNext = next();
285 if (pNext->is(Token::IDENTIFIER_TOKEN))
286 append(decl, pNext);
287 else
288 syntaxError("class/struct name");
289 pNext = next();
290 bool isFinal = false;
291 if (isIdentifier(pNext) && pNext->asString() == "final")
292 {
293 pNext = next();
294 isFinal = true;
295 }
296 if (!isOperator(pNext, OperatorToken::OP_SEMICOLON))
297 {
298 // if we have a template specialization the next token will be a <
299 if (isOperator(pNext, OperatorToken::OP_LT))
300 {
301 // skip all template specializations
302 // skip until at { bracket, then parseBlock to ignore it
303 while (!isOperator(pNext, OperatorToken::OP_OPENBRACE))
304 pNext = next();
305 pNext = parseBlock(pNext); // skip after }
306
307 expectOperator(pNext, OperatorToken::OP_SEMICOLON, ";");
308 pNext = next();
309 _access = prevAccess;
310 _pCurrentSymbol = 0;
311 return pNext;
312 }
313 if (isOperator(pNext, OperatorToken::OP_COLON) || isOperator(pNext, OperatorToken::OP_OPENBRACE))
314 {
315 Struct* pClass = new Struct(decl, isClass, currentNameSpace());
316 if (isFinal) pClass->makeFinal();
317 pushNameSpace(pClass, line);
318 _access = access;
319 if (isOperator(pNext, OperatorToken::OP_COLON))
320 pNext = parseBaseClassList(next(), pClass);
321 expectOperator(pNext, OperatorToken::OP_OPENBRACE, "{");
322 pNext = parseClassMembers(pNext, pClass);
323 expectOperator(pNext, OperatorToken::OP_CLOSBRACE, "}");
324 pNext = next();
325 expectOperator(pNext, OperatorToken::OP_SEMICOLON, ";");
326 popNameSpace();
327 }
328 else return parseVarFunc(pNext, decl);
329 }
330 pNext = next();
331 _access = prevAccess;
332 _pCurrentSymbol = 0;
333 return pNext;
334}
335
336
337const Token* Parser::parseBaseClassList(const Token* pNext, Struct* pClass)
338{
339 while (pNext->is(Token::IDENTIFIER_TOKEN) || pNext->is(Token::KEYWORD_TOKEN))
340 {
341 bool isVirtual = false;
342 Symbol::Access acc = _access;
343 while (pNext->is(Token::KEYWORD_TOKEN))
344 {
345 switch (pNext->asInteger())
346 {
347 case IdentifierToken::KW_PUBLIC:
348 acc = Symbol::ACC_PUBLIC;
349 break;
350 case IdentifierToken::KW_PROTECTED:
351 acc = Symbol::ACC_PROTECTED;
352 break;
353 case IdentifierToken::KW_PRIVATE:
354 acc = Symbol::ACC_PRIVATE;
355 break;
356 case IdentifierToken::KW_VIRTUAL:
357 isVirtual = true;
358 break;
359 default:
360 syntaxError("public, protected, private or virtual");
361 }
362 pNext = next();
363 }
364 std::string id;
365 pNext = parseIdentifier(pNext, id);
366 if (isOperator(pNext, OperatorToken::OP_LT))
367 pNext = parseTemplateArgs(pNext, id);
368 pClass->addBase(id, acc, isVirtual);
369 if (isOperator(pNext, OperatorToken::OP_COMMA))
370 pNext = next();
371 }
372 return pNext;
373}
374
375
376const Token* Parser::parseClassMembers(const Token* pNext, Struct* /*pClass*/)
377{
378 poco_assert (isOperator(pNext, OperatorToken::OP_OPENBRACE));
379
380 pNext = next();
381 while (pNext->is(Token::IDENTIFIER_TOKEN) || pNext->is(Token::KEYWORD_TOKEN) || isOperator(pNext, OperatorToken::OP_COMPL))
382 {
383 switch (pNext->asInteger())
384 {
385 case IdentifierToken::KW_PRIVATE:
386 case IdentifierToken::KW_PROTECTED:
387 case IdentifierToken::KW_PUBLIC:
388 pNext = parseAccess(pNext);
389 break;
390 case IdentifierToken::KW_STRUCT:
391 case IdentifierToken::KW_CLASS:
392 case IdentifierToken::KW_UNION:
393 pNext = parseClass(pNext);
394 break;
395 case IdentifierToken::KW_TEMPLATE:
396 pNext = parseTemplate(pNext);
397 break;
398 case IdentifierToken::KW_TYPEDEF:
399 pNext = parseTypeDef(pNext);
400 break;
401 case IdentifierToken::KW_ENUM:
402 pNext = parseEnum(pNext);
403 break;
404 case IdentifierToken::KW_FRIEND:
405 pNext = parseFriend(pNext);
406 break;
407 case OperatorToken::OP_COMPL:
408 default:
409 pNext = parseVarFunc(pNext);
410 }
411 }
412 return pNext;
413}
414
415
416const Token* Parser::parseAccess(const Token* pNext)
417{
418 switch (pNext->asInteger())
419 {
420 case IdentifierToken::KW_PRIVATE:
421 _access = Symbol::ACC_PRIVATE;
422 break;
423 case IdentifierToken::KW_PROTECTED:
424 _access = Symbol::ACC_PROTECTED;
425 break;
426 case IdentifierToken::KW_PUBLIC:
427 _access = Symbol::ACC_PUBLIC;
428 break;
429 }
430 pNext = next();
431 expectOperator(pNext, OperatorToken::OP_COLON, ":");
432 return next();
433}
434
435
436const Token* Parser::parseTemplate(const Token* pNext)
437{
438 poco_assert (isKeyword(pNext, IdentifierToken::KW_TEMPLATE));
439
440 std::string decl;
441 append(decl, pNext);
442 pNext = next();
443 expectOperator(pNext, OperatorToken::OP_LT, "<");
444 pNext = parseTemplateArgs(pNext, decl);
445 if (isKeyword(pNext, IdentifierToken::KW_CLASS) || isKeyword(pNext, IdentifierToken::KW_STRUCT) || isKeyword(pNext, IdentifierToken::KW_UNION))
446 return parseClass(pNext, decl);
447 else
448 return parseVarFunc(pNext, decl);
449}
450
451
452const Token* Parser::parseTemplateArgs(const Token* pNext, std::string& decl)
453{
454 poco_assert (isOperator(pNext, OperatorToken::OP_LT));
455
456 append(decl, pNext);
457 int depth = 1;
458 pNext = next();
459 while (depth > 0 && !isEOF(pNext))
460 {
461 append(decl, pNext);
462 if (isOperator(pNext, OperatorToken::OP_LT))
463 ++depth;
464 else if (isOperator(pNext, OperatorToken::OP_GT))
465 --depth;
466 pNext = next();
467 }
468 return pNext;
469}
470
471
472const Token* Parser::parseTypeDef(const Token* pNext)
473{
474 poco_assert (isKeyword(pNext, IdentifierToken::KW_TYPEDEF));
475
476 _pCurrentSymbol = 0;
477 int line = _istr.getCurrentLineNumber();
478 std::string decl;
479 while (!isOperator(pNext, OperatorToken::OP_SEMICOLON) && !isEOF(pNext))
480 {
481 append(decl, pNext);
482 pNext = next();
483 }
484 TypeDef* pTypeDef = new TypeDef(decl, currentNameSpace());
485 addSymbol(pTypeDef, line);
486 pNext = next();
487 _pCurrentSymbol = 0;
488 return pNext;
489}
490
491
492const Token* Parser::parseUsing(const Token* pNext)
493{
494 poco_assert (isKeyword(pNext, IdentifierToken::KW_USING));
495
496 pNext = next();
497 if (isKeyword(pNext, IdentifierToken::KW_NAMESPACE))
498 {
499 pNext = next();
500 if (isIdentifier(pNext))
501 {
502 std::string ns;
503 pNext = parseIdentifier(pNext, ns);
504 currentNameSpace()->importNameSpace(ns);
505 }
506 else syntaxError("identifier");
507 }
508 else
509 {
510 if (isIdentifier(pNext))
511 {
512 std::string id;
513 pNext = parseIdentifier(pNext, id);
514 currentNameSpace()->importSymbol(id);
515 }
516 }
517
518 if (!isOperator(pNext, OperatorToken::OP_SEMICOLON))
519 syntaxError("semicolon");
520 return next();
521}
522
523
524const Token* Parser::parseFriend(const Token* pNext)
525{
526 poco_assert (isKeyword(pNext, IdentifierToken::KW_FRIEND));
527
528 pNext = next();
529
530 while (!isOperator(pNext, OperatorToken::OP_SEMICOLON) && !isEOF(pNext))
531 pNext = next();
532
533 if (isOperator(pNext, OperatorToken::OP_SEMICOLON))
534 pNext = next();
535 return pNext;
536}
537
538
539const Token* Parser::parseVarFunc(const Token* pNext)
540{
541 std::string decl;
542 return parseVarFunc(pNext, decl);
543}
544
545
546const Token* Parser::parseVarFunc(const Token* pNext, std::string& decl)
547{
548 _pCurrentSymbol = 0;
549 if (isKeyword(pNext, IdentifierToken::KW_EXTERN))
550 {
551 pNext = parseExtern(pNext);
552 }
553 else
554 {
555 append(decl, pNext);
556 pNext = next();
557 bool isOp = false;
558 while (!isOperator(pNext, OperatorToken::OP_SEMICOLON) && !isOperator(pNext, OperatorToken::OP_OPENPARENT) && !isEOF(pNext))
559 {
560 append(decl, pNext);
561 isOp = isKeyword(pNext, IdentifierToken::KW_OPERATOR);
562 pNext = next();
563 }
564 if (isOperator(pNext, OperatorToken::OP_SEMICOLON))
565 {
566 std::string name = Symbol::extractName(decl);
567 if (!currentNameSpace()->lookup(name))
568 {
569 Variable* pVar = new Variable(decl, currentNameSpace());
570 addSymbol(pVar, _istr.getCurrentLineNumber());
571 }
572 pNext = next();
573 }
574 else if (isOperator(pNext, OperatorToken::OP_OPENPARENT))
575 {
576 if (isOp)
577 {
578 decl += " (";
579 pNext = next();
580 expectOperator(pNext, OperatorToken::OP_CLOSPARENT, ")");
581 append(decl, pNext);
582 pNext = next();
583 expectOperator(pNext, OperatorToken::OP_OPENPARENT, "(");
584 }
585 pNext = parseFunc(pNext, decl);
586 }
587 }
588 _pCurrentSymbol = 0;
589 return pNext;
590}
591
592
593const Token* Parser::parseExtern(const Token* pNext)
594{
595 poco_assert (isKeyword(pNext, IdentifierToken::KW_EXTERN));
596
597 pNext = next();
598 if (pNext->is(Token::STRING_LITERAL_TOKEN))
599 pNext = next();
600 if (isOperator(pNext, OperatorToken::OP_OPENBRACE))
601 {
602 pNext = parseBlock(pNext);
603 }
604 else
605 {
606 while (!isOperator(pNext, OperatorToken::OP_SEMICOLON) && !isEOF(pNext))
607 pNext = next();
608 }
609 if (isOperator(pNext, OperatorToken::OP_SEMICOLON))
610 pNext = next();
611 return pNext;
612}
613
614
615const Token* Parser::parseFunc(const Token* pNext, std::string& decl)
616{
617 poco_assert (isOperator(pNext, OperatorToken::OP_OPENPARENT));
618
619 int line = _istr.getCurrentLineNumber();
620 Function* pFunc = 0;
621 std::string name = Symbol::extractName(decl);
622 if (name.find(':') == std::string::npos)
623 {
624 pFunc = new Function(decl, currentNameSpace());
625 addSymbol(pFunc, line);
626 }
627 pNext = parseParameters(pNext, pFunc);
628 expectOperator(pNext, OperatorToken::OP_CLOSPARENT, ")");
629 pNext = next();
630 while (pNext->is(Poco::Token::IDENTIFIER_TOKEN) || pNext->is(Poco::Token::KEYWORD_TOKEN))
631 {
632 if (isKeyword(pNext, IdentifierToken::KW_CONST))
633 {
634 if (pFunc) pFunc->makeConst();
635 pNext = next();
636 }
637 if (isKeyword(pNext, IdentifierToken::KW_THROW))
638 {
639 while (!isOperator(pNext, OperatorToken::OP_ASSIGN) && !isOperator(pNext, OperatorToken::OP_SEMICOLON) &&
640 !isOperator(pNext, OperatorToken::OP_OPENBRACE) && !isEOF(pNext))
641 pNext = next();
642 }
643 else if (isKeyword(pNext, IdentifierToken::KW_NOEXCEPT))
644 {
645 if (pFunc) pFunc->makeNoexcept();
646 pNext = next();
647 }
648 else if (isIdentifier(pNext) && pNext->asString() == "override")
649 {
650 if (pFunc) pFunc->makeOverride();
651 pNext = next();
652 }
653 else if (isIdentifier(pNext) && pNext->asString() == "final")
654 {
655 if (pFunc) pFunc->makeFinal();
656 pNext = next();
657 }
658 else if (isKeyword(pNext, IdentifierToken::KW_TRY))
659 {
660 break; // handled below
661 }
662 }
663 if (isOperator(pNext, OperatorToken::OP_ASSIGN))
664 {
665 pNext = next();
666 if (!pNext->is(Token::INTEGER_LITERAL_TOKEN) && !isKeyword(pNext, IdentifierToken::KW_DEFAULT) && !isKeyword(pNext, IdentifierToken::KW_DELETE))
667 syntaxError("0, default or delete");
668 if (isKeyword(pNext, IdentifierToken::KW_DEFAULT))
669 pFunc->makeDefault();
670 else if (isKeyword(pNext, IdentifierToken::KW_DELETE))
671 pFunc->makeDelete();
672 pNext = next();
673 if (pFunc) pFunc->makePureVirtual();
674 expectOperator(pNext, OperatorToken::OP_SEMICOLON, ";");
675 }
676 else if (isOperator(pNext, OperatorToken::OP_OPENBRACE) || isOperator(pNext, OperatorToken::OP_COLON))
677 {
678 while (!isOperator(pNext, OperatorToken::OP_OPENBRACE) && !isEOF(pNext))
679 pNext = next();
680
681 pNext = parseBlock(pNext);
682 if (!pFunc)
683 pFunc = dynamic_cast<Function*>(currentNameSpace()->lookup(name));
684 if (pFunc)
685 pFunc->makeInline();
686 }
687 else if (isKeyword(pNext, IdentifierToken::KW_TRY))
688 {
689 pNext = next();
690 if (isOperator(pNext, OperatorToken::OP_OPENBRACE) || isOperator(pNext, OperatorToken::OP_COLON))
691 {
692 while (!isOperator(pNext, OperatorToken::OP_OPENBRACE) && !isEOF(pNext))
693 pNext = next();
694
695 pNext = parseBlock(pNext);
696
697 if (isKeyword(pNext, IdentifierToken::KW_CATCH))
698 {
699 while (!isOperator(pNext, OperatorToken::OP_OPENBRACE) && !isEOF(pNext))
700 pNext = next();
701
702 pNext = parseBlock(pNext);
703 }
704 else syntaxError("expected catch block");
705
706 if (!pFunc)
707 pFunc = dynamic_cast<Function*>(currentNameSpace()->lookup(name));
708 if (pFunc)
709 pFunc->makeInline();
710 }
711 else syntaxError("expected member initialization or block");
712 }
713 else
714 {
715 expectOperator(pNext, OperatorToken::OP_SEMICOLON, ";");
716 }
717 if (isOperator(pNext, OperatorToken::OP_SEMICOLON))
718 pNext = next();
719 return pNext;
720}
721
722
723const Token* Parser::parseParameters(const Token* pNext, Function* pFunc)
724{
725 poco_assert (isOperator(pNext, OperatorToken::OP_OPENPARENT));
726
727 pNext = next();
728 while (!isOperator(pNext, OperatorToken::OP_CLOSPARENT) && !isEOF(pNext))
729 {
730 std::string decl;
731 int depth = 0;
732 int tdepth = 0;
733 while ((depth > 0 || tdepth > 0 || (!isOperator(pNext, OperatorToken::OP_CLOSPARENT) && !isOperator(pNext, OperatorToken::OP_COMMA))) && !isEOF(pNext))
734 {
735 append(decl, pNext);
736 if (isOperator(pNext, OperatorToken::OP_OPENPARENT))
737 ++depth;
738 else if (isOperator(pNext, OperatorToken::OP_CLOSPARENT))
739 --depth;
740 else if (isOperator(pNext, OperatorToken::OP_LT))
741 ++tdepth;
742 else if (isOperator(pNext, OperatorToken::OP_GT))
743 --tdepth;
744 pNext = next();
745 }
746 if (isOperator(pNext, OperatorToken::OP_COMMA))
747 pNext = next();
748 if (pFunc && decl != "void") // don't add the void parameter, I simply check here to avoid throwing away void*
749 pFunc->addParameter(new Parameter(decl, pFunc));
750 }
751 return pNext;
752}
753
754
755const Token* Parser::parseBlock(const Token* pNext)
756{
757 poco_assert (isOperator(pNext, OperatorToken::OP_OPENBRACE));
758
759 pNext = next();
760 int depth = 1;
761 while (depth > 0 && !isEOF(pNext))
762 {
763 if (isOperator(pNext, OperatorToken::OP_OPENBRACE))
764 ++depth;
765 else if (isOperator(pNext, OperatorToken::OP_CLOSBRACE))
766 --depth;
767 pNext = next();
768 }
769 return pNext;
770}
771
772
773const Token* Parser::parseEnum(const Token* pNext)
774{
775 poco_assert (isKeyword(pNext, IdentifierToken::KW_ENUM));
776
777 _pCurrentSymbol = 0;
778 int line = _istr.getCurrentLineNumber();
779 pNext = next();
780 std::string name;
781 if (pNext->is(Token::IDENTIFIER_TOKEN))
782 {
783 name = pNext->tokenString();
784 pNext = next();
785 }
786 expectOperator(pNext, OperatorToken::OP_OPENBRACE, "{");
787 Enum* pEnum = new Enum(name, currentNameSpace());
788 addSymbol(pEnum, line);
789 pNext = next();
790 while (pNext->is(Token::IDENTIFIER_TOKEN))
791 {
792 pNext = parseEnumValue(pNext, pEnum);
793 }
794 expectOperator(pNext, OperatorToken::OP_CLOSBRACE, "}");
795 pNext = next();
796 expectOperator(pNext, OperatorToken::OP_SEMICOLON, ";");
797 pNext = next();
798 _pCurrentSymbol = 0;
799 return pNext;
800}
801
802
803const Token* Parser::parseEnumValue(const Token* pNext, Enum* pEnum)
804{
805 _pCurrentSymbol = 0;
806 _doc.clear();
807 int line = _istr.getCurrentLineNumber();
808 std::string name = pNext->tokenString();
809 std::string value;
810 pNext = next();
811 if (isOperator(pNext, OperatorToken::OP_ASSIGN))
812 {
813 pNext = next();
814 while (!isOperator(pNext, OperatorToken::OP_COMMA) && !isOperator(pNext, OperatorToken::OP_CLOSBRACE) && !isEOF(pNext))
815 {
816 append(value, pNext);
817 pNext = next();
818 }
819 }
820 EnumValue* pValue = new EnumValue(name, value, pEnum);
821 addSymbol(pValue, line, true);
822 if (isOperator(pNext, OperatorToken::OP_COMMA))
823 pNext = next();
824 else if (!isOperator(pNext, OperatorToken::OP_CLOSBRACE))
825 syntaxError(", or }");
826 return pNext;
827}
828
829
830const Token* Parser::parseIdentifier(const Token* pNext, std::string& id)
831{
832 poco_assert (pNext->is(Token::IDENTIFIER_TOKEN) || isOperator(pNext, OperatorToken::OP_DBL_COLON));
833 id.append(pNext->tokenString());
834 if (isOperator(pNext, OperatorToken::OP_DBL_COLON))
835 {
836 pNext = next();
837 if (!pNext->is(Token::IDENTIFIER_TOKEN)) syntaxError("identifier");
838 id.append(pNext->tokenString());
839 }
840 pNext = next();
841 while (isOperator(pNext, OperatorToken::OP_DBL_COLON))
842 {
843 id.append("::");
844 pNext = next();
845 if (!pNext->is(Token::IDENTIFIER_TOKEN)) syntaxError("identifier");
846 id.append(pNext->tokenString());
847 pNext = next();
848 }
849 return pNext;
850}
851
852
853void Parser::addSymbol(Symbol* pSymbol, int lineNumber, bool addGST)
854{
855 pSymbol->setLineNumber(lineNumber);
856 pSymbol->setFile(_currentPath);
857 pSymbol->setPackage(_package);
858 pSymbol->setLibrary(_library);
859 pSymbol->setAccess(_access);
860 _pCurrentSymbol = pSymbol;
861 if (addGST)
862 _gst.insert(NameSpace::SymbolTable::value_type(pSymbol->name(), pSymbol));
863 if (!_doc.empty())
864 pSymbol->addDocumentation(_doc);
865 if (!_attrs.empty())
866 {
867 Attributes attrs;
868 std::istringstream istr(_attrs);
869 AttributesParser parser(attrs, istr);
870 parser.parse();
871 pSymbol->setAttributes(attrs);
872 _attrs.clear();
873 }
874 _doc.clear();
875}
876
877
878void Parser::pushNameSpace(NameSpace* pNameSpace, int lineNumber, bool addGST)
879{
880 addSymbol(pNameSpace, lineNumber, addGST);
881 _nsStack.push_back(pNameSpace);
882}
883
884
885void Parser::popNameSpace()
886{
887 _nsStack.pop_back();
888}
889
890
891NameSpace* Parser::currentNameSpace() const
892{
893 return _nsStack.back();
894}
895
896
897const Token* Parser::next()
898{
899 const Token* pNext = nextPreprocessed();
900 while (!_inFile && !isEOF(pNext))
901 pNext = nextPreprocessed();
902 return pNext;
903}
904
905
906const Token* Parser::nextPreprocessed()
907{
908 const Token* pNext = nextToken();
909 while (pNext->is(Token::PREPROCESSOR_TOKEN))
910 {
911 std::istringstream pps(pNext->tokenString());
912 pps.get();
913 Tokenizer ppt(pps);
914 const Token* pPPT = ppt.next();
915 if (pPPT->tokenString() == "line" || pPPT->is(Token::INTEGER_LITERAL_TOKEN))
916 {
917 if (!pPPT->is(Token::INTEGER_LITERAL_TOKEN))
918 pPPT = ppt.next();
919 int line = pPPT->asInteger();
920 _istr.setCurrentLineNumber(line);
921 pPPT = ppt.next();
922 if (pPPT->is(Token::STRING_LITERAL_TOKEN))
923 {
924 std::string path = pPPT->asString();
925 Path p(path);
926 p.makeAbsolute();
927 _currentPath = p.toString();
928 _inFile = (icompare(_path, _currentPath) == 0);
929 }
930 }
931 pNext = nextToken();
932 }
933 return pNext;
934}
935
936
937const Token* Parser::nextToken()
938{
939 const Token* pNext = _tokenizer.next();
940 while (pNext->is(Token::COMMENT_TOKEN) || pNext->is(Token::SPECIAL_COMMENT_TOKEN))
941 {
942 if (pNext->is(Token::SPECIAL_COMMENT_TOKEN))
943 {
944 if (_pCurrentSymbol)
945 {
946 _pCurrentSymbol->addDocumentation(pNext->asString());
947 _doc.clear();
948 }
949 else if (_inFile)
950 {
951 if (!_doc.empty()) _doc += "\n";
952 _doc += pNext->asString();
953 }
954 }
955 else if (pNext->is(Token::COMMENT_TOKEN) && _inFile)
956 {
957 const std::string& comment = pNext->tokenString();
958 if (comment.compare(0, 3, "//@") == 0)
959 {
960 _attrs.append(comment.substr(3));
961 }
962 else if (comment.compare(0, 11, "// Package:") == 0)
963 {
964 _package = comment.substr(11);
965 trimInPlace(_package);
966 }
967 else if (comment.compare(0, 11, "// Library:") == 0)
968 {
969 _library = comment.substr(11);
970 trimInPlace(_library);
971 }
972 }
973 pNext = _tokenizer.next();
974 }
975 return pNext;
976}
977
978
979} } // namespace Poco::CppParser
980