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 | |
35 | using Poco::Token; |
36 | using Poco::WhitespaceToken; |
37 | using Poco::Path; |
38 | using Poco::NumberFormatter; |
39 | using Poco::SyntaxException; |
40 | using Poco::icompare; |
41 | using Poco::trimInPlace; |
42 | |
43 | |
44 | namespace Poco { |
45 | namespace CppParser { |
46 | |
47 | |
48 | Parser::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 | |
66 | Parser::~Parser() |
67 | { |
68 | } |
69 | |
70 | |
71 | inline bool Parser::isIdentifier(const Token* pToken) |
72 | { |
73 | return pToken->is(Token::IDENTIFIER_TOKEN) || isOperator(pToken, OperatorToken::OP_DBL_COLON); |
74 | } |
75 | |
76 | |
77 | inline bool Parser::isOperator(const Token* pToken, int kind) |
78 | { |
79 | return pToken->is(Token::OPERATOR_TOKEN) && pToken->asInteger() == kind; |
80 | } |
81 | |
82 | |
83 | inline bool Parser::isKeyword(const Token* pToken, int kind) |
84 | { |
85 | return pToken->is(Token::KEYWORD_TOKEN) && pToken->asInteger() == kind; |
86 | } |
87 | |
88 | |
89 | inline bool Parser::isEOF(const Token* pToken) |
90 | { |
91 | return pToken->is(Token::EOF_TOKEN); |
92 | } |
93 | |
94 | |
95 | void 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 | |
102 | void Parser::syntaxError(const std::string& msg) |
103 | { |
104 | throw SyntaxException("Expected" , msg); |
105 | } |
106 | |
107 | |
108 | inline void Parser::(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 | |
143 | inline void Parser::(std::string& decl, const Token* pToken) |
144 | { |
145 | poco_check_ptr (pToken); |
146 | append(decl, pToken->tokenString()); |
147 | } |
148 | |
149 | |
150 | void 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 | |
171 | const 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 | |
205 | const 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 | |
263 | const Token* Parser::parseClass(const Token* pNext) |
264 | { |
265 | std::string decl; |
266 | return parseClass(pNext, decl); |
267 | } |
268 | |
269 | |
270 | const Token* Parser::(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 | |
337 | const 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 | |
376 | const 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 | |
416 | const 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 | |
436 | const 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 | |
452 | const Token* Parser::(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 | |
472 | const 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 | |
492 | const 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 | |
524 | const 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 | |
539 | const Token* Parser::parseVarFunc(const Token* pNext) |
540 | { |
541 | std::string decl; |
542 | return parseVarFunc(pNext, decl); |
543 | } |
544 | |
545 | |
546 | const Token* Parser::(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 | |
593 | const 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 | |
615 | const Token* Parser::(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 | |
723 | const 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 | |
755 | const 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 | |
773 | const 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 | |
803 | const 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 | |
830 | const Token* Parser::(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 | |
853 | void 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 | |
878 | void Parser::pushNameSpace(NameSpace* pNameSpace, int lineNumber, bool addGST) |
879 | { |
880 | addSymbol(pNameSpace, lineNumber, addGST); |
881 | _nsStack.push_back(pNameSpace); |
882 | } |
883 | |
884 | |
885 | void Parser::popNameSpace() |
886 | { |
887 | _nsStack.pop_back(); |
888 | } |
889 | |
890 | |
891 | NameSpace* Parser::currentNameSpace() const |
892 | { |
893 | return _nsStack.back(); |
894 | } |
895 | |
896 | |
897 | const Token* Parser::next() |
898 | { |
899 | const Token* pNext = nextPreprocessed(); |
900 | while (!_inFile && !isEOF(pNext)) |
901 | pNext = nextPreprocessed(); |
902 | return pNext; |
903 | } |
904 | |
905 | |
906 | const 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 | |
937 | const 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& = 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 | |