/* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2007-2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //krazy:excludeall=cpp // c++ support #include "parser.h" #include "tokens.h" #include "lexer.h" #include "control.h" #include "parsesession.h" #include "commentformatter.h" #include "memorypool.h" #include #include #include "rpp/chartools.h" #define ADVANCE(tk, descr) \ { \ if (session->token_stream->lookAhead() != tk) { \ tokenRequiredError(tk); \ return false; \ } \ advance(); \ } #define ADVANCE_NR(tk, descr) \ do { \ if (session->token_stream->lookAhead() != tk) { \ tokenRequiredError(tk); \ } \ else \ advance(); \ } while (0) #define CHECK(tk) \ do { \ if (session->token_stream->lookAhead() != tk) { \ return false; \ } \ advance(); \ } while (0) #define UPDATE_POS(_node, start, end) \ do { \ (_node)->start_token = start; \ (_node)->end_token = end; \ } while (0) template inline _Tp *CreateNode(MemoryPool *memory_pool) { _Tp *node = memory_pool->allocate<_Tp>(); node->kind = _Tp::__node_kind; return node; } void Parser::addComment( CommentAST* ast, const Comment& comment ) { if( comment ) { /* kDebug() << "Adding but leaving comment" << session->token_stream->token(comment.token()).symbol();*/ ast->comments = snoc(ast->comments, comment.token(), session->mempool); } } void Parser::moveComments( CommentAST* ast ) { while( m_commentStore.hasComment() ) { uint token = m_commentStore.takeFirstComment().token(); /* kDebug() << "Moving comment" << session->token_stream->token(token).symbol();*/ ast->comments = snoc(ast->comments, token, session->mempool); } } Parser::Parser(Control *c) : control(c), lexer(control) , _M_problem_count(0) , _M_max_problem_count(5) , session(0) , _M_hold_errors(false) , _M_last_valid_token(0) , _M_last_parsed_comment(0) , _M_hadMismatchingCompoundTokens(false) , m_primaryExpressionWithTemplateParamsNeedsFunctionCall(true) { } Parser::~Parser() { } void Parser::rewind(uint position) { session->token_stream->rewind(position); //Search the previous valid token _M_last_valid_token = position > 0 ? position-1 : position; while( _M_last_valid_token > 0 && session->token_stream->kind(_M_last_valid_token) == Token_comment ) --_M_last_valid_token; } void Parser::advance( bool skipComment ) { uint t = session->token_stream->lookAhead(); if( session->token_stream->cursor() > 0 && t == Token_EOF ) { return; } if( t != Token_comment ) _M_last_valid_token = session->token_stream->cursor(); session->token_stream->nextToken(); if( session->token_stream->lookAhead() == Token_comment ) { if( skipComment ) { processComment(); advance(); } } } Comment Parser::comment() { return m_commentStore.latestComment(); } void Parser::preparseLineComments( int tokenNumber ) { const Token& token( (*session->token_stream)[tokenNumber] ); KDevelop::CursorInRevision tokenPosition = KDevelop::CursorInRevision::invalid(); for( int a = 0; a < 40; a++ ) { if( !session->token_stream->lookAhead(a) ) break; if( session->token_stream->lookAhead(a) == Token_comment ) { //Make sure the token's line is before the searched token's line const Token& commentToken( (*session->token_stream)[session->token_stream->cursor() + a] ); if( !tokenPosition.isValid() ) //Get the token line. Only on-demand, because it's not cheap. tokenPosition = session->positionAt(token.position); KDevelop::CursorInRevision commentPosition = session->positionAt( commentToken.position ); if( commentPosition.line < tokenPosition.line ) { continue; } else if( commentPosition.line == tokenPosition.line ) { processComment( a ); } else { //Too far break; } } } } int Parser::lineFromTokenNumber( uint tokenNumber ) const { const Token& token( (*session->token_stream)[tokenNumber] ); return session->positionAt( token.position ).line; } void Parser::processComment( int offset, int line ) { uint tokenNumber = session->token_stream->cursor() + offset; if(_M_last_parsed_comment >= tokenNumber) return; //The comment was already parsed. May happen because of pre-parsing _M_last_parsed_comment = tokenNumber; const Token& commentToken( (*session->token_stream)[tokenNumber] ); Q_ASSERT(commentToken.kind == Token_comment); if( line == -1 ) { KDevelop::CursorInRevision position = session->positionAt( commentToken.position ); line = position.line; } session->m_commentFormatter.extractToDos( tokenNumber, session, control ); m_commentStore.addComment( Comment( session->token_stream->cursor() + offset, line ) ); } void Parser::clearComment( ) { m_commentStore.clear(); } TranslationUnitAST *Parser::parse(ParseSession* _session) { clear(); session = _session; if (!session->token_stream) session->token_stream = new TokenStream(session); lexer.tokenize(session); advance(); // skip the first token TranslationUnitAST *ast = 0; parseTranslationUnit(ast); return ast; } StatementAST *Parser::parseStatement(ParseSession* _session) { clear(); session = _session; if (!session->token_stream) session->token_stream = new TokenStream(session); lexer.tokenize(session); advance(); // skip the first token StatementAST *ast = 0; parseCompoundStatement(ast); return ast; } AST *Parser::parseTypeOrExpression(ParseSession* _session, bool forceExpression) { clear(); session = _session; if (!session->token_stream) session->token_stream = new TokenStream(session); lexer.tokenize(session); advance(); // skip the first token TypeIdAST *ast = 0; if (!forceExpression) parseTypeId(ast); if(!ast) { m_primaryExpressionWithTemplateParamsNeedsFunctionCall = false; ExpressionAST* ast = 0; parseExpression(ast); return ast; } return ast; } void Parser::fixupInitializerFromParameter(InitDeclaratorAST* node, ParseSession* _session) { clear(); session = _session; Q_ASSERT(session->token_stream); Q_ASSERT(!node->initializer); Q_ASSERT(node->declarator); Q_ASSERT(node->declarator->parameter_declaration_clause); // include the '(', which is not included in the parameter_declaration_clause, thus: -1 rewind(node->declarator->parameter_declaration_clause->start_token - 1); InitializerAST* initializer = 0; if (!parseInitializer(initializer)) { // note: this can happen when we encounter unresolved types, since then // DeclarationBuilder::checkParameterDeclarationClause will think this is an initializer // we handle this gracefully and just exit return; } // fixup AST node->initializer = initializer; // note: this is not leaking, as the AST is managed by a memory pool node->declarator->parameter_declaration_clause = 0; } void Parser::clear() { _M_hold_errors = false; _M_problem_count = 0; _M_hadMismatchingCompoundTokens = false; m_tokenMarkers.clear(); } void Parser::addTokenMarkers(uint tokenNumber, Parser::TokenMarkers markers) { QHash::iterator it = m_tokenMarkers.find(tokenNumber); if(it != m_tokenMarkers.end()) it.value() = (TokenMarkers)(it.value() | markers); else m_tokenMarkers.insert(tokenNumber, markers); } Parser::TokenMarkers Parser::tokenMarkers(uint tokenNumber) const { return m_tokenMarkers.value(tokenNumber, None); } bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node) { if (session->token_stream->lookAhead() != Token_identifier) return false; uint start = session->token_stream->cursor(); const uint tokenIndex = session->token_stream->symbolIndex(session->token_stream->cursor()); static const KDevelop::IndexedString declSpecString("__declspec"); if (declSpecString.index() != tokenIndex) return false; uint specifier = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() != '(') return false; advance(); if (session->token_stream->lookAhead() != Token_identifier) return false; uint modifier = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() != ')') return false; advance(); node = CreateNode(session->mempool); node->specifier = specifier; node->modifier = modifier; UPDATE_POS(node, start, _M_last_valid_token+1); return true; } void Parser::tokenRequiredError(int token) { QString err; err += "Expected token "; err += '\''; err += token_name(token); err += "\' after \'"; err += token_name(session->token_stream->lookAhead(-1)); err += "\' found \'"; err += token_name(session->token_stream->lookAhead()); err += '\''; if(token == '}' || token == '{') _M_hadMismatchingCompoundTokens = true; reportError(err); } void Parser::syntaxError() { uint cursor = session->token_stream->cursor(); uint kind = session->token_stream->lookAhead(); if (m_syntaxErrorTokens.contains(cursor)) return; // syntax error at this point has already been reported m_syntaxErrorTokens.insert(cursor); QString err; if (kind == Token_EOF) err += "Unexpected end of file"; else { err += "Unexpected token "; err += '\''; err += token_name(kind); err += '\''; } reportError(err); } void Parser::reportPendingErrors() { bool hold = holdErrors(false); uint start = session->token_stream->cursor(); while (m_pendingErrors.count() > 0) { PendingError error = m_pendingErrors.dequeue(); session->token_stream->rewind(error.cursor); reportError(error.message); } rewind(start); holdErrors(hold); } void Parser::reportError(const QString& msg, KDevelop::ProblemData::Severity severity) { if (!_M_hold_errors && _M_problem_count < _M_max_problem_count) { ++_M_problem_count; QString fileName; uint tok = session->token_stream->cursor(); KDevelop::CursorInRevision position = session->positionAt(session->token_stream->position(tok)); KDevelop::ProblemPointer p(new KDevelop::Problem); p->setFinalLocation(KDevelop::DocumentRange(session->url(), KDevelop::SimpleRange(position.castToSimpleCursor(), 0))); p->setDescription(msg); p->setSource(KDevelop::ProblemData::Parser); p->setSeverity(severity); control->reportProblem(p); } else if (_M_hold_errors) { PendingError pending; pending.message = msg; pending.cursor = session->token_stream->cursor(); m_pendingErrors.enqueue(pending); } } bool Parser::skipUntil(int token) { clearComment(); while (session->token_stream->lookAhead()) { if (session->token_stream->lookAhead() == token) return true; advance(); } return false; } bool Parser::skipUntilDeclaration() { while (session->token_stream->lookAhead()) { switch(session->token_stream->lookAhead()) { case ';': case '~': case Token_scope: case Token_identifier: case Token_inline: case Token_operator: case Token_char: case Token_char16_t: case Token_char32_t: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: case Token_auto: case Token_extern: case Token_namespace: case Token_using: case Token_typedef: case Token_asm: case Token_template: case Token_export: case Token_thread_local: case Token_static_assert: case Token_constexpr: case Token_const: // cv case Token_volatile: // cv case Token_public: case Token_protected: case Token_private: case Token___qt_signals__: // Qt case Token___qt_slots__: // Qt return true; case '}': return false; default: advance(); } } return false; } bool Parser::skipUntilStatement() { while (session->token_stream->lookAhead()) { switch(session->token_stream->lookAhead()) { case ';': case '{': case '}': case Token_const: case Token_volatile: case Token_identifier: case Token_case: case Token_default: case Token_if: case Token_switch: case Token_while: case Token_do: case Token_for: case Token_break: case Token_continue: case Token_return: case Token_goto: case Token_try: case Token_catch: case Token_throw: case Token_char: case Token_char16_t: case Token_char32_t: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: case Token_auto: case Token_class: case Token_struct: case Token_union: case Token_enum: case Token_scope: case Token_template: case Token_using: case Token_static_assert: case Token_constexpr: return true; default: advance(); } } return false; } bool Parser::skip(int l, int r) { int count = 0; while (session->token_stream->lookAhead()) { int tk = session->token_stream->lookAhead(); if (tk == l) ++count; else if (tk == r) --count; else if (l != '{' && (tk == '{' || tk == '}' || tk == ';')) return false; if (count == 0) return true; advance(); } return false; } bool Parser::parseName(NameAST*& node, ParseNameAcceptTemplate acceptTemplateId) { uint start = session->token_stream->cursor(); WinDeclSpecAST *winDeclSpec = 0; parseWinDeclSpec(winDeclSpec); NameAST *ast = 0; bool setGlobal = false; if (session->token_stream->lookAhead() == Token_scope) { setGlobal = true; advance(); } uint idx = session->token_stream->cursor(); while (true) { UnqualifiedNameAST *n = 0; if (!parseUnqualifiedName(n)) { return false; } if (!ast) ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_scope && //ptr-to-member session->token_stream->lookAhead(1) != '*') { advance(); ast->qualified_names = snoc(ast->qualified_names, n, session->mempool); if (session->token_stream->lookAhead() == Token_template) { /// skip optional template #### @todo CHECK advance(); } } else { Q_ASSERT(n != 0); if (acceptTemplateId == DontAcceptTemplate || //Eventually only accept template parameters as primary expression if the expression is followed by a function call //or by a braced init list (acceptTemplateId == EventuallyAcceptTemplate && n->template_arguments && session->token_stream->lookAhead() != '(' && session->token_stream->lookAhead() != '{' && m_primaryExpressionWithTemplateParamsNeedsFunctionCall)) { rewind(n->start_token); parseUnqualifiedName(n, false); } ast->unqualified_name = n; break; } } if (idx == session->token_stream->cursor()) return false; if (setGlobal) ast->global = true; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTranslationUnit(TranslationUnitAST *&node) { clear(); /* kDebug() << "tokens:"; for(uint a = 0; a < session->token_stream->size(); ++a) kDebug() << token_name(session->token_stream->token(a).kind) << session->token_stream->token(a).symbolString();*/ uint start = session->token_stream->cursor(); TranslationUnitAST *ast = CreateNode(session->mempool); session->topAstNode(ast); if( m_commentStore.hasComment() ) addComment(ast, m_commentStore.takeFirstComment()); while (session->token_stream->lookAhead()) { uint startDecl = session->token_stream->cursor(); DeclarationAST *declaration = 0; if (parseDeclaration(declaration)) { ast->declarations = snoc(ast->declarations, declaration, session->mempool); } else { // error recovery if (startDecl == session->token_stream->cursor()) { // skip at least one token advance(); } skipUntilDeclaration(); } } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; ast->hadMissingCompoundTokens = _M_hadMismatchingCompoundTokens; return true; } bool Parser::parseDeclaration(DeclarationAST *&node) { uint start = session->token_stream->cursor(); switch(session->token_stream->lookAhead()) { case ';': advance(); return true; case Token_extern: return parseLinkageSpecification(node); case Token_namespace: return parseNamespace(node); case Token_using: return parseUsing(node); case Token_typedef: return parseTypedef(node); case Token_asm: return parseAsmDefinition(node); case Token_template: case Token_export: return parseTemplateDeclaration(node); case Token_static_assert: return parseStaticAssert(node); case Token_inline: if (session->token_stream->lookAhead(+1) == Token_namespace) { return parseNamespace(node); } // else fallthrough default: { const ListNode *cv = 0; parseCvQualify(cv); const ListNode *storageSpec = 0; parseStorageClassSpecifier(storageSpec); parseCvQualify(cv); Comment mcomment = comment(); clearComment(); TypeSpecifierAST *spec = 0; if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { parseCvQualify(cv); spec->cv = cv; const ListNode *declarators = 0; parseInitDeclaratorList(declarators); ADVANCE(';', ";"); SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->type_specifier = spec; ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; if( mcomment ) addComment(ast, mcomment); preparseLineComments(ast->end_token-1); if( m_commentStore.hasComment() ) addComment( ast, m_commentStore.takeCommentInRange( lineFromTokenNumber( --ast->end_token ) ) ); return true; } else { rewind(start); if( parseDeclarationInternal(node) ) { //Add the comments to the declaration if( mcomment ) addComment(node, mcomment); preparseLineComments(node->end_token-1); if( m_commentStore.hasComment() ) addComment( node, m_commentStore.takeCommentInRange( lineFromTokenNumber( --node->end_token ) ) ); return true; } } } } // end switch return false; } bool Parser::parseLinkageSpecification(DeclarationAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_extern); LinkageSpecificationAST *ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_string_literal) { ast->extern_type = session->token_stream->cursor(); advance(); } if (session->token_stream->lookAhead() == '{') { parseLinkageBody(ast->linkage_body); } else if (!parseDeclaration(ast->declaration)) { reportError(("Declaration syntax error")); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseLinkageBody(LinkageBodyAST *&node) { uint start = session->token_stream->cursor(); CHECK('{'); LinkageBodyAST *ast = CreateNode(session->mempool); while (session->token_stream->lookAhead()) { int tk = session->token_stream->lookAhead(); if (tk == '}') break; uint startDecl = session->token_stream->cursor(); DeclarationAST *declaration = 0; if (parseDeclaration(declaration)) { ast->declarations = snoc(ast->declarations, declaration, session->mempool); } else { // error recovery if (startDecl == session->token_stream->cursor()) { // skip at least one token advance(); } skipUntilDeclaration(); } } clearComment(); if (session->token_stream->lookAhead() != '}') { reportError(("} expected")); _M_hadMismatchingCompoundTokens = true; } else advance(); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseNamespace(DeclarationAST *&node) { uint start = session->token_stream->cursor(); bool inlined = false; if (session->token_stream->lookAhead() == Token_inline) { inlined = true; advance(); } CHECK(Token_namespace); uint namespace_name = 0; if (session->token_stream->lookAhead() == Token_identifier) { namespace_name = session->token_stream->cursor(); advance(); } if (session->token_stream->lookAhead() == '=') { // namespace alias advance(); NameAST *name = 0; if (parseName(name)) { ADVANCE(';', ";"); NamespaceAliasDefinitionAST *ast = CreateNode(session->mempool); ast->namespace_name = namespace_name; ast->alias_name = name; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } else { reportError(("Namespace expected")); return false; } } else if (session->token_stream->lookAhead() != '{') { reportError(("{ expected")); _M_hadMismatchingCompoundTokens = true; return false; } NamespaceAST *ast = CreateNode(session->mempool); ast->namespace_name = namespace_name; ast->inlined = inlined; parseLinkageBody(ast->linkage_body); UPDATE_POS(ast, start, ast->linkage_body->end_token); node = ast; return true; } bool Parser::parseUsing(DeclarationAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_using); if (session->token_stream->lookAhead() == Token_namespace) return parseUsingDirective(node); uint type_name = 0; NameAST* name = 0; if (session->token_stream->lookAhead() == Token_typename) { type_name = session->token_stream->cursor(); advance(); } if (!parseName(name)) return false; DeclarationAST* ast = 0; if (type_name || session->token_stream->lookAhead() == ';') { ADVANCE(';', ";"); UsingAST *usingAst = CreateNode(session->mempool); usingAst->type_name = type_name; usingAst->name = name; ast = usingAst; } else { ADVANCE('=', "="); TypeIdAST* type_id = 0; if (!parseTypeId(type_id)) { return false; } ADVANCE(';', ";"); AliasDeclarationAST *aliasAST = CreateNode(session->mempool); aliasAST->name = name; aliasAST->type_id = type_id; ast = aliasAST; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseUsingDirective(DeclarationAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_namespace); NameAST *name = 0; if (!parseName(name)) { reportError(("Namespace name expected")); return false; } ADVANCE(';', ";"); UsingDirectiveAST *ast = CreateNode(session->mempool); ast->name = name; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseOperatorFunctionId(OperatorFunctionIdAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_operator); OperatorFunctionIdAST *ast = CreateNode(session->mempool); if (!parseOperator(ast->op)) { ast->op = 0; // parse cast operator const ListNode *cv = 0; parseCvQualify(cv); if (!parseSimpleTypeSpecifier(ast->type_specifier)) { syntaxError(); return false; } parseCvQualify(cv); ast->type_specifier->cv = cv; PtrOperatorAST *ptr_op = 0; while (parsePtrOperator(ptr_op)) ast->ptr_ops = snoc(ast->ptr_ops, ptr_op, session->mempool); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTemplateArgumentList(const ListNode *&node, bool reportError) { TemplateArgumentAST *templArg = 0; if (!parseTemplateArgument(templArg)) return false; node = snoc(node, templArg, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseTemplateArgument(templArg)) { if (reportError) { syntaxError(); break; } node = 0; return false; } node = snoc(node, templArg, session->mempool); } return true; } bool Parser::parseTypedef(DeclarationAST *&node) { uint start = session->token_stream->cursor(); Comment mcomment = comment(); CHECK(Token_typedef); TypeSpecifierAST *spec = 0; if (!parseTypeSpecifierOrClassSpec(spec)) { reportError(("Need a type specifier to declare")); return false; } const ListNode *declarators = 0; if (!parseInitDeclaratorList(declarators)) { //reportError(("Need an identifier to declare")); //return false; } clearComment(); TypedefAST *ast = CreateNode(session->mempool); if( mcomment ) addComment( ast, mcomment ); ADVANCE(';', ";"); ast->type_specifier = spec; ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; preparseLineComments( ast->end_token-1 ); if( m_commentStore.hasComment() ) addComment( ast, m_commentStore.takeCommentInRange( lineFromTokenNumber( --ast->end_token ) ) ); return true; } bool Parser::parseAsmDefinition(DeclarationAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_asm, "asm"); const ListNode *cv = 0; parseCvQualify(cv); skip('(', ')'); advance(); ADVANCE(';', ";"); AsmDefinitionAST *ast = CreateNode(session->mempool); ast->cv = cv; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTemplateDeclaration(DeclarationAST *&node) { uint start = session->token_stream->cursor(); uint exported = 0; if (session->token_stream->lookAhead() == Token_export) { exported = session->token_stream->cursor(); advance(); } CHECK(Token_template); const ListNode *params = 0; if (session->token_stream->lookAhead() == '<') { advance(); parseTemplateParameterList(params); ADVANCE('>', ">"); } DeclarationAST *declaration = 0; if (!parseDeclaration(declaration)) { reportError(("Expected a declaration")); } TemplateDeclarationAST *ast = CreateNode(session->mempool); ast->exported = exported; ast->template_parameters = params; ast->declaration = declaration; UPDATE_POS(ast, start, declaration ? declaration->end_token : _M_last_valid_token+1); node = ast; return true; } bool Parser::parseOperator(OperatorAST *&node) { uint start = session->token_stream->cursor(); OperatorAST *ast = CreateNode(session->mempool); switch(session->token_stream->lookAhead()) { case Token_new: case Token_delete: { ast->op = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() == '[' && session->token_stream->lookAhead(1) == ']') { ast->open = session->token_stream->cursor(); advance(); ast->close = session->token_stream->cursor(); advance(); } } break; case '+': case '-': case '*': case '/': case '%': case '^': case '&': case '|': case '~': case '!': case '=': case '<': case '>': case ',': case Token_leftshift: case Token_rightshift: case Token_eq: case Token_not: case Token_not_eq: case Token_and_eq: case Token_or_eq: case Token_xor_eq: case Token_leftshift_eq: case Token_rightshift_eq: case Token_div_eq: case Token_star_eq: case Token_plus_eq: case Token_minus_eq: case Token_remainder_eq: case Token_leq: case Token_geq: case Token_and: case Token_or: case Token_incr: case Token_decr: case Token_ptrmem: case Token_arrow: ast->op = session->token_stream->cursor(); advance(); break; default: if (session->token_stream->lookAhead() == '(' && session->token_stream->lookAhead(1) == ')') { ast->op = ast->open = session->token_stream->cursor(); advance(); ast->close = session->token_stream->cursor(); advance(); } else if (session->token_stream->lookAhead() == '[' && session->token_stream->lookAhead(1) == ']') { ast->op = ast->open = session->token_stream->cursor(); advance(); ast->close = session->token_stream->cursor(); advance(); } else { return false; } } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseCvQualify(const ListNode *&node) { uint start = session->token_stream->cursor(); quint16 tk; while (0 != (tk = session->token_stream->lookAhead()) && (tk == Token_const || tk == Token_volatile)) { node = snoc(node, session->token_stream->cursor(), session->mempool); advance(); } return start != session->token_stream->cursor(); } bool Parser::parseRefQualifier(uint& ref_qualifier) { const quint16 tk = session->token_stream->lookAhead(); if (tk == '&' || tk == Token_bitand || tk == Token_and) { advance(); ref_qualifier = session->token_stream->cursor(); return true; } return false; } bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, bool onlyIntegral) { uint start = session->token_stream->cursor(); bool isIntegral = false; bool done = false; const ListNode *integrals = 0; while (!done) { switch(session->token_stream->lookAhead()) { case Token_char: case Token_char16_t: case Token_char32_t: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: case Token_auto: integrals = snoc(integrals, session->token_stream->cursor(), session->mempool); isIntegral = true; advance(); break; default: done = true; } } SimpleTypeSpecifierAST *ast = 0; if (isIntegral) { ast = CreateNode(session->mempool); ast->integrals = integrals; } else if (session->token_stream->lookAhead() == Token___typeof) { ast = CreateNode(session->mempool); ast->isTypeof = true; advance(); if (session->token_stream->lookAhead() == '(') { advance(); uint saved = session->token_stream->cursor(); if (!parseTypeId(ast->type_id) || session->token_stream->lookAhead() != ')') { ast->type_id = 0; ast->integrals = 0; rewind(saved); parseCommaExpression(ast->expression); } ADVANCE(')', ")"); } else { parseUnaryExpression(ast->expression); } } else if (session->token_stream->lookAhead() == Token_decltype) { ast = CreateNode(session->mempool); ast->isDecltype = true; advance(); ADVANCE('(', "("); parseExpression(ast->expression); ADVANCE(')', ")"); } else if (onlyIntegral) { rewind(start); return false; } else { NameAST *name = 0; if (!parseName(name, AcceptTemplate)) { rewind(start); return false; } ast = CreateNode(session->mempool); ast->name = name; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parsePtrOperator(PtrOperatorAST *&node) { int tk = session->token_stream->lookAhead(); if (tk != '&' && tk != '*' && tk != Token_and && tk != Token_scope && tk != Token_identifier) { return false; } uint start = session->token_stream->cursor(); PtrOperatorAST *ast = CreateNode(session->mempool); switch (session->token_stream->lookAhead()) { case '&': case '*': case Token_and: ast->op = session->token_stream->cursor(); advance(); break; case Token_scope: case Token_identifier: { if (!parsePtrToMember(ast->mem_ptr)) { rewind(start); return false; } } break; default: Q_ASSERT(0); break; } parseCvQualify(ast->cv); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTemplateArgument(TemplateArgumentAST *&node) { uint start = session->token_stream->cursor(); TypeIdAST *typeId = 0; ExpressionAST *expr = 0; if (!parseTypeId(typeId) || (session->token_stream->lookAhead() != ',' && session->token_stream->lookAhead() != '>' && session->token_stream->lookAhead() != ')' && session->token_stream->lookAhead() != Token_rightshift && session->token_stream->lookAhead() != Token_ellipsis )) { rewind(start); if (!parsePrimaryExpression(expr) || (session->token_stream->lookAhead() != ',' && session->token_stream->lookAhead() != '>' && session->token_stream->lookAhead() != ')' && session->token_stream->lookAhead() != Token_rightshift && session->token_stream->lookAhead() != Token_ellipsis )) { rewind(start); if (!parseConditionalExpression(expr, true)) return false; } } bool isVariadic = false; if (session->token_stream->lookAhead() == Token_ellipsis) { isVariadic = true; advance(); } TemplateArgumentAST *ast = CreateNode(session->mempool); ast->type_id = typeId; ast->expression = expr; ast->isVariadic = isVariadic; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node) { ///TODO: Proper parsing of typename, this is some kind a hack, typename will be eaten, wrong typename-usages will be accepted, e.g. outside of templates. Please have a look at the C++-language-specification, if you want to fix it. if(session->token_stream->lookAhead() == Token_typename) session->token_stream->nextToken(); /// ;) uint start = session->token_stream->cursor(); const ListNode *cv = 0; parseCvQualify(cv); TypeSpecifierAST *ast = 0; if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast)) { rewind(start); return false; } parseCvQualify(cv); ast->cv = cv; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseDeclarator(DeclaratorAST*& node, bool allowBitfield) { uint start = session->token_stream->cursor(); DeclaratorAST *ast = CreateNode(session->mempool); DeclaratorAST *decl = 0; NameAST *declId = 0; PtrOperatorAST *ptrOp = 0; while (parsePtrOperator(ptrOp)) { ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, session->mempool); } if (session->token_stream->lookAhead() == '(') { advance(); if (!parseDeclarator(decl)) return false; ast->sub_declarator = decl; CHECK(')'); } else { // bitfield can be unnamed if (!allowBitfield || session->token_stream->lookAhead() != ':') { if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; } if (parseName(declId, AcceptTemplate)) { ast->id = declId; } else { rewind(start); return false; } } if (allowBitfield && session->token_stream->lookAhead() == ':') { advance(); if (!parseConstantExpression(ast->bit_expression)) { reportError(("Constant expression expected")); } goto update_pos; } } { bool isVector = false; while (session->token_stream->lookAhead() == '[') { advance(); ExpressionAST *expr = 0; parseCommaExpression(expr); ADVANCE(']', "]"); ast->array_dimensions = snoc(ast->array_dimensions, expr, session->mempool); isVector = true; } bool skipParen = false; if (session->token_stream->lookAhead() == Token_identifier && session->token_stream->lookAhead(1) == '(' && session->token_stream->lookAhead(2) == '(') { advance(); advance(); skipParen = true; } int tok = session->token_stream->lookAhead(); if (ast->sub_declarator && !(isVector || tok == '(' || tok == ',' || tok == ';' || tok == '=')) { rewind(start); return false; } uint index = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '(') { advance(); ///@todo Sometimes something like (test()) is parsed as a parameter declaration clause, although it cannot be one. ParameterDeclarationClauseAST *params = 0; if (!parseParameterDeclarationClause(params)) { rewind(index); goto update_pos; } ast->parameter_declaration_clause = params; if (session->token_stream->lookAhead() != ')') { rewind(index); goto update_pos; } advance(); // skip ')' parseCvQualify(ast->fun_cv); parseRefQualifier(ast->ref_qualifier); parseExceptionSpecification(ast->exception_spec); // trailing return type support if (session->token_stream->lookAhead() == Token_arrow) { parseTrailingReturnType(ast->trailing_return_type); } parseMemberVirtSpecifier(ast->virt_specifiers); } if (skipParen) { if (session->token_stream->lookAhead() != ')') { reportError(("')' expected")); } else advance(); } } update_pos: UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) { uint start = session->token_stream->cursor(); DeclaratorAST *ast = CreateNode(session->mempool); DeclaratorAST *decl = 0; PtrOperatorAST *ptrOp = 0; while (parsePtrOperator(ptrOp)) { ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, session->mempool); } int index = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '(') { advance(); if (!parseAbstractDeclarator(decl)) { rewind(index); goto label1; } ast->sub_declarator = decl; if (session->token_stream->lookAhead() != ')') { rewind(start); return false; } advance(); } else if (session->token_stream->lookAhead() == ':') { advance(); if (!parseConstantExpression(ast->bit_expression)) { ast->bit_expression = 0; reportError(("Constant expression expected")); } goto update_pos; } else if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; goto update_pos; } label1: { bool isVector = false; while (session->token_stream->lookAhead() == '[') { advance(); ExpressionAST *expr = 0; parseCommaExpression(expr); ADVANCE(']', "]"); ast->array_dimensions = snoc(ast->array_dimensions, expr, session->mempool); isVector = true; } int tok = session->token_stream->lookAhead(); if (ast->sub_declarator && !(isVector || tok == '(' || tok == ',' || tok == ';' || tok == '=')) { rewind(start); return false; } int index = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '(') { advance(); ParameterDeclarationClauseAST *params = 0; if (!parseParameterDeclarationClause(params)) { rewind(index); goto update_pos; } ast->parameter_declaration_clause = params; if (session->token_stream->lookAhead() != ')') { rewind(index); goto update_pos; } advance(); // skip ')' parseCvQualify(ast->fun_cv); parseExceptionSpecification(ast->exception_spec); } } update_pos: if (session->token_stream->cursor() == start) return false; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_enum); bool isClass = session->token_stream->lookAhead()==Token_class || session->token_stream->lookAhead()==Token_struct; if(isClass) { advance(); } NameAST *name = 0; parseName(name); TypeSpecifierAST *type = 0; if(session->token_stream->lookAhead() == ':') { advance(); if(!parseTypeSpecifier(type)) { rewind(start); return false; } } EnumSpecifierAST *ast = CreateNode(session->mempool); ast->name = name; ast->type = type; ast->isClass = isClass; if (session->token_stream->lookAhead() == '{') { advance(); ast->isOpaque = false; EnumeratorAST *enumerator = 0; if (parseEnumerator(enumerator)) { ast->enumerators = snoc(ast->enumerators, enumerator, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseEnumerator(enumerator)) { break; } ast->enumerators = snoc(ast->enumerators, enumerator, session->mempool); } } clearComment(); ADVANCE_NR('}', "}"); } else if (session->token_stream->lookAhead() == ';') { ast->isOpaque = true; } else { rewind(start); return false; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTemplateParameterList(const ListNode *&node) { TemplateParameterAST *param = 0; if (!parseTemplateParameter(param)) return false; node = snoc(node, param, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseTemplateParameter(param)) { syntaxError(); break; } else { node = snoc(node, param, session->mempool); } } return true; } bool Parser::parseTemplateParameter(TemplateParameterAST *&node) { uint start = session->token_stream->cursor(); TemplateParameterAST *ast = CreateNode(session->mempool); int tk = session->token_stream->lookAhead(); if ((tk == Token_class || tk == Token_typename || tk == Token_template) && parseTypeParameter(ast->type_parameter)) { // nothing to do } else if (!parseParameterDeclaration(ast->parameter_declaration)) return false; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTypeParameter(TypeParameterAST *&node) { uint start = session->token_stream->cursor(); TypeParameterAST *ast = CreateNode(session->mempool); ast->type = start; switch(session->token_stream->lookAhead()) { case Token_class: case Token_typename: { advance(); // skip class if(session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; } // parse optional name parseName(ast->name, AcceptTemplate); if (session->token_stream->lookAhead() == '=') { advance(); if(!parseTypeId(ast->type_id)) { //syntaxError(); rewind(start); return false; } } else if (session->token_stream->lookAhead() != ',' && session->token_stream->lookAhead() != '>') ///TODO: right-shift also OK? see spec 14.2/3 { rewind(start); return false; } } break; case Token_template: { advance(); // skip template ADVANCE('<', "<"); if (!parseTemplateParameterList(ast->template_parameters)) return false; ADVANCE('>', ">"); // TODO add to AST if (session->token_stream->lookAhead() == Token_class) advance(); if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; } // parse optional name if (parseName(ast->name, AcceptTemplate)) { if (session->token_stream->lookAhead() == '=') { advance(); if (!parseTypeId(ast->type_id)) { syntaxError(); return false; } } } if (session->token_stream->lookAhead() == '=') { advance(); parseName(ast->template_name, AcceptTemplate); } } break; default: return false; } // end switch UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } ///TODO: the spec has a decl-specifier, friend and constexpr e.g. are no storage class specifiers! bool Parser::parseStorageClassSpecifier(const ListNode *&node) { uint start = session->token_stream->cursor(); int tk; while (0 != (tk = session->token_stream->lookAhead()) && (tk == Token_friend || tk == Token_register || tk == Token_static || tk == Token_extern || tk == Token_mutable || tk == Token_thread_local || tk == Token_constexpr)) { node = snoc(node, session->token_stream->cursor(), session->mempool); advance(); } return start != session->token_stream->cursor(); } bool Parser::parseFunctionSpecifier(const ListNode *&node) { uint start = session->token_stream->cursor(); int tk; while (0 != (tk = session->token_stream->lookAhead()) && (tk == Token_inline || tk == Token_virtual || tk == Token_explicit)) { node = snoc(node, session->token_stream->cursor(), session->mempool); advance(); } return start != session->token_stream->cursor(); } bool Parser::parseTypeId(TypeIdAST *&node) { uint start = session->token_stream->cursor(); TypeSpecifierAST *spec = 0; if (!parseTypeSpecifier(spec)) { rewind(start); return false; } DeclaratorAST *decl = 0; parseAbstractDeclarator(decl); TypeIdAST *ast = CreateNode(session->mempool); ast->type_specifier = spec; ast->declarator = decl; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseInitDeclaratorList(const ListNode *&node) { InitDeclaratorAST *decl = 0; if (!parseInitDeclarator(decl)) return false; node = snoc(node, decl, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseInitDeclarator(decl)) { syntaxError(); break; } node = snoc(node, decl, session->mempool); } return true; } bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node) { uint start = session->token_stream->cursor(); ParameterDeclarationClauseAST *ast = CreateNode(session->mempool); if (!parseParameterDeclarationList(ast->parameter_declarations)) { if (session->token_stream->lookAhead() == ')') goto good; if (session->token_stream->lookAhead() == Token_ellipsis && session->token_stream->lookAhead(1) == ')') { ast->ellipsis = session->token_stream->cursor(); goto good; } return false; } good: if (session->token_stream->lookAhead() == Token_ellipsis) { ast->ellipsis = session->token_stream->cursor(); advance(); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseParameterDeclarationList(const ListNode *&node) { uint start = session->token_stream->cursor(); ParameterDeclarationAST *param = 0; if (!parseParameterDeclaration(param)) { rewind(start); return false; } node = snoc(node, param, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseParameterDeclaration(param)) { rewind(start); return false; } node = snoc(node, param, session->mempool); } return true; } bool Parser::parseParameterDeclaration(ParameterDeclarationAST *&node) { uint start = session->token_stream->cursor(); const ListNode *storage = 0; parseStorageClassSpecifier(storage); // parse decl spec TypeSpecifierAST *spec = 0; if (!parseTypeSpecifier(spec)) { rewind(start); return false; } int index = session->token_stream->cursor(); DeclaratorAST *decl = 0; if (!parseDeclarator(decl)) { rewind(index); // try with abstract declarator parseAbstractDeclarator(decl); } ExpressionAST *expr = 0; if (session->token_stream->lookAhead() == '=') { advance(); //FIXME: this should actually be an InitializerClause as per http://www.nongnu.org/hcb/#parameter-declaration parseLogicalOrExpression(expr, true) || parseBracedInitList(expr); } if( session->token_stream->lookAhead() != ',' && session->token_stream->lookAhead() != ')' && session->token_stream->lookAhead() != '>' ) { //Not a valid parameter declaration rewind(start); return false; } ParameterDeclarationAST *ast = CreateNode(session->mempool); ast->type_specifier = spec; ast->declarator = decl; ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) { uint start = session->token_stream->cursor(); int kind = session->token_stream->lookAhead(); if (kind != Token_class && kind != Token_struct && kind != Token_union) return false; uint class_key = session->token_stream->cursor(); advance(); WinDeclSpecAST *winDeclSpec = 0; parseWinDeclSpec(winDeclSpec); while (session->token_stream->lookAhead() == Token_identifier && session->token_stream->lookAhead(1) == Token_identifier) { advance(); } NameAST *name = 0; parseName(name, AcceptTemplate); const ListNode *virt_specifiers = 0; parseClassVirtSpecifier(virt_specifiers); BaseClauseAST *bases = 0; if (session->token_stream->lookAhead() == ':') { if (!parseBaseClause(bases)) { skipUntil('{'); } } if (session->token_stream->lookAhead() != '{') { rewind(start); return false; } ADVANCE('{', "{"); ClassSpecifierAST *ast = CreateNode(session->mempool); ast->win_decl_specifiers = winDeclSpec; ast->class_key = class_key; ast->name = name; ast->base_clause = bases; while (session->token_stream->lookAhead()) { if (session->token_stream->lookAhead() == '}') break; uint startDecl = session->token_stream->cursor(); DeclarationAST *memSpec = 0; if (!parseMemberSpecification(memSpec)) { if (startDecl == session->token_stream->cursor()) advance(); // skip at least one token skipUntilDeclaration(); } else ast->member_specs = snoc(ast->member_specs, memSpec, session->mempool); } clearComment(); ADVANCE_NR('}', "}"); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseAccessSpecifier(DeclarationAST *&node) { uint start = session->token_stream->cursor(); const ListNode *specs = 0; bool done = false; while (!done) { switch(session->token_stream->lookAhead()) { case Token___qt_signals__: case Token___qt_slots__: case Token_k_dcop: case Token_k_dcop_signals: case Token_public: case Token_protected: case Token_private: specs = snoc(specs, session->token_stream->cursor(), session->mempool); advance(); break; default: done = true; break; } } if (!specs) return false; ADVANCE(':', ":"); AccessSpecifierAST *ast = CreateNode(session->mempool); ast->specs = specs; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseMemberSpecification(DeclarationAST *&node) { uint start = session->token_stream->cursor(); if (session->token_stream->lookAhead() == ';') { advance(); return true; } else if (session->token_stream->lookAhead() == Token_Q_OBJECT || session->token_stream->lookAhead() == Token_K_DCOP) { advance(); return true; } else if (parseTypedef(node)) { return true; } else if (parseUsing(node)) { return true; } else if (parseTemplateDeclaration(node)) { return true; } else if (parseAccessSpecifier(node)) { return true; } else if (parseQProperty(node)) { return true; } else if (parseStaticAssert(node)) { return true; } rewind(start); const ListNode *cv = 0; parseCvQualify(cv); const ListNode *storageSpec = 0; parseStorageClassSpecifier(storageSpec); parseCvQualify(cv); Comment mcomment = comment(); clearComment(); TypeSpecifierAST *spec = 0; if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { parseCvQualify(cv); spec->cv = cv; const ListNode *declarators = 0; parseInitDeclaratorList(declarators); ADVANCE(';', ";"); SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->type_specifier = spec; ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); if( mcomment ) addComment(ast,mcomment); preparseLineComments(ast->end_token-1); if( m_commentStore.hasComment() ) addComment( ast, m_commentStore.takeCommentInRange( lineFromTokenNumber( --ast->end_token ) ) ); node = ast; return true; } else { rewind(start); if( parseDeclarationInternal(node) ) { //Add the comments to the declaration if( mcomment ) addComment(node, mcomment); preparseLineComments(node->end_token-1); if( m_commentStore.hasComment() ) addComment( node, m_commentStore.takeCommentInRange( lineFromTokenNumber( --node->end_token ) ) ); return true; } } return false; } bool Parser::parseCtorInitializer(CtorInitializerAST *&node) { uint start = session->token_stream->cursor(); CHECK(':'); CtorInitializerAST *ast = CreateNode(session->mempool); ast->colon = start; if (!parseMemInitializerList(ast->member_initializers)) { reportError(("Member initializers expected")); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) { uint start = session->token_stream->cursor(); int tk = session->token_stream->lookAhead(); if (tk == Token_class || tk == Token_struct || tk == Token_union || tk == Token_enum || tk == Token_typename) { uint type = session->token_stream->cursor(); advance(); NameAST *name = 0; if (parseName(name, AcceptTemplate)) { ElaboratedTypeSpecifierAST *ast = CreateNode(session->mempool); ast->type = type; ast->name = name; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } rewind(start); return false; } bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) { uint start = session->token_stream->cursor(); if (session->token_stream->lookAhead() == Token_throw) { advance(); ADVANCE('(', "("); ExceptionSpecificationAST *ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_ellipsis) { ast->ellipsis = session->token_stream->cursor(); advance(); } parseTypeIdList(ast->type_ids); if (!ast->ellipsis && session->token_stream->lookAhead() == Token_ellipsis) { ast->ellipsis = session->token_stream->cursor(); advance(); } ADVANCE(')', ")"); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } else if (session->token_stream->lookAhead() == Token_noexcept) { ExceptionSpecificationAST *ast = CreateNode(session->mempool); ast->no_except = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() == '(') { advance(); parseExpression(ast->noexcept_expression); CHECK(')'); } UPDATE_POS (ast, start, _M_last_valid_token+1); node = ast; return true; } return false; } bool Parser::parseEnumerator(EnumeratorAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_identifier); uint id = start; EnumeratorAST *ast = CreateNode(session->mempool); ast->id = id; if (session->token_stream->lookAhead() == '=') { advance(); if (!parseConstantExpression(ast->expression)) { reportError(("Constant expression expected")); } } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; moveComments(node); preparseLineComments( ast->end_token-1 ); if( m_commentStore.hasComment() ) addComment( node, m_commentStore.takeCommentInRange( lineFromTokenNumber(--ast->end_token) ) ); return true; } bool Parser::parseInitDeclarator(InitDeclaratorAST *&node) { uint start = session->token_stream->cursor(); DeclaratorAST *decl = 0; if (!parseDeclarator(decl)) { return false; } if (session->token_stream->lookAhead(0) == Token_asm) { advance(); skip('(', ')'); advance(); } InitializerAST *init = 0; parseInitializer(init); InitDeclaratorAST *ast = CreateNode(session->mempool); ast->declarator = decl; ast->initializer = init; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseBaseClause(BaseClauseAST *&node) { uint start = session->token_stream->cursor(); CHECK(':'); BaseSpecifierAST *baseSpec = 0; if (!parseBaseSpecifier(baseSpec)) return false; BaseClauseAST *ast = CreateNode(session->mempool); ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseBaseSpecifier(baseSpec)) { reportError(("Base class specifier expected")); break; } ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, session->mempool); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseInitializer(InitializerAST *&node) { uint start = session->token_stream->cursor(); int tk = session->token_stream->lookAhead(); InitializerAST *ast = CreateNode(session->mempool); if (tk == '=') { advance(); if (!parseInitializerClause(ast->initializer_clause)) { rewind(start); return false; } } else if (tk == '(') { advance(); parseExpressionList(ast->expression); CHECK(')'); } else if (!parseBracedInitList(ast->expression)) { rewind(start); return false; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseMemInitializerList(const ListNode *&node) { MemInitializerAST *init = 0; if (!parseMemInitializer(init)) return false; node = snoc(node, init, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (!parseMemInitializer(init)) break; node = snoc(node, init, session->mempool); } return true; } bool Parser::parseMemInitializer(MemInitializerAST *&node) { uint start = session->token_stream->cursor(); NameAST *initId = 0; if (!parseName(initId, AcceptTemplate)) { reportError(("Identifier expected")); return false; } ExpressionAST *expr = 0; bool expressionIsVariadic = false; if (session->token_stream->lookAhead() == '(') { advance(); parseExpressionList(expr); if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); expressionIsVariadic = true; } ADVANCE(')', ")"); } else { parseBracedInitList(expr); } bool initializerIsVariadic = false; if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); initializerIsVariadic = true; } MemInitializerAST *ast = CreateNode(session->mempool); ast->initializer_id = initId; ast->expression = expr; ast->initializerIsVariadic = initializerIsVariadic; ast->expressionIsVariadic = expressionIsVariadic; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTypeIdList(const ListNode *&node) { TypeIdAST *typeId = 0; if (!parseTypeId(typeId)) return false; node = snoc(node, typeId, session->mempool); while (session->token_stream->lookAhead() == ',') { advance(); if (parseTypeId(typeId)) { node = snoc(node, typeId, session->mempool); } else { reportError(("Type id expected")); break; } } return true; } bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) { uint start = session->token_stream->cursor(); BaseSpecifierAST *ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_virtual) { ast->virt = session->token_stream->cursor(); advance(); int tk = session->token_stream->lookAhead(); if (tk == Token_public || tk == Token_protected || tk == Token_private) { ast->access_specifier = session->token_stream->cursor(); advance(); } } else { int tk = session->token_stream->lookAhead(); if (tk == Token_public || tk == Token_protected || tk == Token_private) { ast->access_specifier = session->token_stream->cursor(); advance(); } if (session->token_stream->lookAhead() == Token_virtual) { ast->virt = session->token_stream->cursor(); advance(); } } if (!parseName(ast->name, AcceptTemplate)) reportError(("Class name expected")); if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseBracedInitList(ExpressionAST*& node) { uint start = session->token_stream->cursor(); CHECK('{'); InitializerListAST *list = 0; parseInitializerList(list); CHECK('}'); BracedInitListAST *ast = CreateNode(session->mempool); ast->list = list; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseInitializerList(InitializerListAST *&node) { uint start = session->token_stream->cursor(); const ListNode *clauses = 0; do { if (clauses) { advance(); // skip ',' separator between clauses if (session->token_stream->lookAhead() == '}') { // see https://bugs.kde.org/show_bug.cgi?id=233328 // and grammar spec on braced-init-list // init lists may have a trailing comma break; } } InitializerClauseAST *init_clause = 0; if (!parseInitializerClause(init_clause) && !parseDesignatedInitializer(init_clause)) { return false; } clauses = snoc(clauses,init_clause,session->mempool); } while (session->token_stream->lookAhead() == ','); InitializerListAST *list = CreateNode(session->mempool); list->clauses = clauses; if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); list->isVariadic = true; } UPDATE_POS(list, start, _M_last_valid_token+1); node = list; return true; } /** * Parse C99 designated initializers, e.g: * struct foo_t foo = { * .has_cake = true, * .nb_candles = 12, * }; * * int bar[10] = { * [1] = 15, * [9] = 25, * }; */ bool Parser::parseDesignatedInitializer(InitializerClauseAST *&ast) { uint start = session->token_stream->cursor(); uint memberOp = session->token_stream->cursor(); NameAST *member = 0; ExpressionAST *index = 0; const ListNode *indexes = 0; if (session->token_stream->lookAhead() == '.') { // Designated member advance(); if (!parseName(member, Parser::DontAcceptTemplate)) { rewind(start); return false; } } else { do { // Designated array index if (session->token_stream->lookAhead() != '[' || !parsePostfixExpressionInternal(index)) { rewind(start); return false; } indexes = snoc(indexes, index, session->mempool); } while (session->token_stream->lookAhead() == '['); } uint cm_end = session->token_stream->cursor(); uint asop = session->token_stream->cursor(); if (session->token_stream->lookAhead() != '=') { rewind(start); return false; } advance(); ExpressionAST *rightExpr = 0; if (!parseConditionalExpression(rightExpr) && !parseBracedInitList(rightExpr)) { rewind(start); return false; } BinaryExpressionAST *binaryExpr = CreateNode(session->mempool); binaryExpr->op = asop; binaryExpr->right_expression = rightExpr; if (member) { ClassMemberAccessAST *memberAst = CreateNode(session->mempool); memberAst->op = memberOp; memberAst->name = member; UPDATE_POS(memberAst, start, cm_end); binaryExpr->left_expression = memberAst; } else { PostfixExpressionAST *sub = CreateNode(session->mempool); sub->sub_expressions = indexes; UPDATE_POS(sub, start, cm_end); binaryExpr->left_expression = sub; } UPDATE_POS(binaryExpr, start, _M_last_valid_token+1); ast = CreateNode(session->mempool); ast->expression = binaryExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); return true; } bool Parser::parseInitializerClause(InitializerClauseAST *&node) { uint start = session->token_stream->cursor(); ExpressionAST *expr = 0; // assignment or braced-init-list parseAssignmentExpression(expr) || parseBracedInitList(expr); if (!expr) { rewind(start); return false; } InitializerClauseAST *ast = CreateNode(session->mempool); ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parsePtrToMember(PtrToMemberAST *&node) { uint start = session->token_stream->cursor(); TypeSpecifierAST* type_ast = 0; if(parseTypeSpecifier(type_ast)){ if (session->token_stream->lookAhead() == Token_scope && session->token_stream->lookAhead(1) == '*') { advance(); advance(); PtrToMemberAST *ast = CreateNode(session->mempool); ast->class_type=type_ast; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } rewind(start); return false; } bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, bool parseTemplateId) { uint start = session->token_stream->cursor(); bool tilde = false; uint id = 0; bool ellipsis = false; OperatorFunctionIdAST *operator_id = 0; if (session->token_stream->lookAhead() == Token_identifier // identifier with special meaning || session->token_stream->lookAhead() == Token_override || session->token_stream->lookAhead() == Token_final) { id = session->token_stream->cursor(); advance(); } else if (session->token_stream->lookAhead() == '~' && session->token_stream->lookAhead(1) == Token_identifier) { tilde = true; advance(); // skip ~ id = session->token_stream->cursor(); advance(); // skip classname } else if (session->token_stream->lookAhead() == Token_operator) { if (!parseOperatorFunctionId(operator_id)) return false; } else if (session->token_stream->lookAhead() == Token_ellipsis) { ellipsis = true; advance(); } else { return false; } UnqualifiedNameAST *ast = CreateNode(session->mempool); ast->tilde = tilde; ast->id = id; ast->ellipsis = ellipsis; ast->operator_id = operator_id; if (parseTemplateId) { uint index = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '<' && !(tokenMarkers(index) & IsNoTemplateArgumentList)) { advance(); // optional template arguments parseTemplateArgumentList(ast->template_arguments); if (session->token_stream->lookAhead() == '>') { advance(); } else if (session->token_stream->lookAhead() == Token_rightshift) { session->token_stream->splitRightShift(session->token_stream->cursor()); advance(); } else { addTokenMarkers(index, IsNoTemplateArgumentList); ast->template_arguments = 0; rewind(index); } } } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseStringLiteral(StringLiteralAST *&node) { uint start = session->token_stream->cursor(); if (session->token_stream->lookAhead() != Token_string_literal) return false; StringLiteralAST *ast = CreateNode(session->mempool); while (session->token_stream->lookAhead() == Token_string_literal) { ast->literals = snoc(ast->literals, session->token_stream->cursor(), session->mempool); advance(); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseExpressionStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ExpressionAST *expr = 0; parseCommaExpression(expr); ADVANCE(';', ";"); ExpressionStatementAST *ast = CreateNode(session->mempool); ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseJumpStatement(StatementAST *&node) { uint op = session->token_stream->cursor(); uint kind = session->token_stream->lookAhead(); uint identifier = 0; if (kind != Token_break && kind != Token_continue && kind != Token_goto) return false; advance(); if (kind == Token_goto) { ADVANCE(Token_identifier,"label"); identifier = op+1; } ADVANCE(';',";"); JumpStatementAST* ast = CreateNode(session->mempool); ast->op = op; ast->identifier = identifier; UPDATE_POS(ast,ast->op,_M_last_valid_token+1); node = ast; return true; } bool Parser::parseStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); switch(session->token_stream->lookAhead()) { case Token_while: return parseWhileStatement(node); case Token_do: return parseDoStatement(node); case Token_for: return parseForStatement(node); case Token_if: return parseIfStatement(node); case Token_switch: return parseSwitchStatement(node); case Token_try: return parseTryBlockStatement(node); case Token_case: case Token_default: return parseLabeledStatement(node); case Token_break: case Token_continue: case Token_goto: return parseJumpStatement(node); case Token_return: { ///TODO: cleanup and put this into parseJumpStatement to follow the spec advance(); ExpressionAST *expr = 0; parseCommaExpression(expr) || parseBracedInitList(expr); ADVANCE(';', ";"); ReturnStatementAST *ast = CreateNode(session->mempool); ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case '{': return parseCompoundStatement(node); case Token_identifier: if (parseLabeledStatement(node)) return true; break; } return parseExpressionOrDeclarationStatement(node); } //since advance includes comments, this checks for both, ; or ; // bool isValidExprOrDeclEnd(ParseSession* session) { int prev = session->token_stream->kind(session->token_stream->cursor() - 1); if (prev == Token_comment) { prev = session->token_stream->kind(session->token_stream->cursor() - 2); } return prev == ';'; } bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) { // hold any errors while the expression/declaration ambiguity is resolved // for this statement bool hold = holdErrors(true); uint start = session->token_stream->cursor(); ///@todo solve -1 thing StatementAST *decl_ast = 0; bool maybe_amb = parseDeclarationStatement(decl_ast); maybe_amb &= isValidExprOrDeclEnd(session); maybe_amb &= isValidExprOrDeclEnd(session); // if parsing as a declaration succeeded, then any pending errors are genuine. // Otherwise this is not a declaration so ignore the errors. if (decl_ast) reportPendingErrors(); else m_pendingErrors.clear(); uint end = session->token_stream->cursor(); rewind(start); StatementAST *expr_ast = 0; maybe_amb &= parseExpressionStatement(expr_ast); maybe_amb &= isValidExprOrDeclEnd(session); // if parsing as an expression succeeded, then any pending errors are genuine. // Otherwise this is not an expression so ignore the errors. if (expr_ast) reportPendingErrors(); else m_pendingErrors.clear(); if (maybe_amb) { Q_ASSERT(decl_ast != 0 && expr_ast != 0); ExpressionOrDeclarationStatementAST *ast = CreateNode(session->mempool); ast->declaration = decl_ast; ast->expression = expr_ast; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } else { rewind(std::max(end, session->token_stream->cursor())); node = decl_ast; if (!node) node = expr_ast; } holdErrors(hold); if (!node) syntaxError(); return node != 0; } bool Parser::parseCondition(ConditionAST *&node, bool initRequired) { uint start = session->token_stream->cursor(); ConditionAST *ast = CreateNode(session->mempool); TypeSpecifierAST *spec = 0; if (parseTypeSpecifier(spec)) { ast->type_specifier = spec; uint declarator_start = session->token_stream->cursor(); DeclaratorAST *decl = 0; if (!parseDeclarator(decl)) { rewind(declarator_start); if (!initRequired && !parseAbstractDeclarator(decl)) decl = 0; } if (decl) { ExpressionAST* expression = 0; if (session->token_stream->lookAhead() == '=') { advance(); parseExpression(expression); } else { parseBracedInitList(expression); } if (expression || !initRequired) { ast->declarator = decl; ast->expression = expression; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } } ast->type_specifier = 0; rewind(start); if (!parseCommaExpression(ast->expression)) { return false; } Q_ASSERT(ast->expression); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseWhileStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_while, "while"); ADVANCE('(' , "("); ConditionAST *cond = 0; if (!parseCondition(cond)) { reportError("Condition expected"); return false; } ADVANCE(')', ")"); StatementAST *body = 0; if (!parseStatement(body)) { reportError("Statement expected"); return false; } WhileStatementAST *ast = CreateNode(session->mempool); ast->condition = cond; ast->statement = body; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseDoStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_do, "do"); StatementAST *body = 0; if (!parseStatement(body)) { reportError(("Statement expected")); //return false; } ADVANCE_NR(Token_while, "while"); ADVANCE_NR('(' , "("); ExpressionAST *expr = 0; if (!parseCommaExpression(expr)) { reportError(("Expression expected")); //return false; } ADVANCE_NR(')', ")"); ADVANCE_NR(';', ";"); DoStatementAST *ast = CreateNode(session->mempool); ast->statement = body; ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseForStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_for, "for"); ADVANCE('(', "("); ForRangeDeclarationAst *rangeDecl = 0; StatementAST *init = 0; ConditionAST *cond = 0; if (!parseRangeBasedFor(rangeDecl)) { if (!parseForInitStatement(init)) { reportError(("'for' initialization expected")); return false; } parseCondition(cond); ADVANCE(';', ";"); } ExpressionAST *expr = 0; parseCommaExpression(expr); ADVANCE(')', ")"); StatementAST *body = 0; if (!parseStatement(body)) return false; ForStatementAST *ast = CreateNode(session->mempool); ast->init_statement = init; ast->range_declaration = rangeDecl; ast->condition = cond; ast->expression = expr; ast->statement = body; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseRangeBasedFor(ForRangeDeclarationAst *&node) { Comment mcomment = comment(); clearComment(); uint start = session->token_stream->cursor(); const ListNode *cv = 0; parseCvQualify(cv); const ListNode *storageSpec = 0; parseStorageClassSpecifier(storageSpec); parseCvQualify(cv); TypeSpecifierAST *spec = 0; // auto support: right now it is part of the storage spec, put it back if (storageSpec && session->token_stream->kind(storageSpec->toBack()->element) == Token_auto) { rewind(storageSpec->toBack()->element); } if (!parseTypeSpecifier(spec)) { rewind(start); return false; } parseCvQualify(cv); spec->cv = cv; DeclaratorAST *declarator = 0; if (!parseDeclarator(declarator, false /* no bitfield allowed */)) { rewind(start); return false; } if (session->token_stream->lookAhead() != ':') { rewind(start); return false; } advance(); ForRangeDeclarationAst *ast = CreateNode(session->mempool); ast->type_specifier = spec; ast->storage_specifiers = storageSpec; ast->declarator = declarator; if(mcomment) addComment(ast, mcomment); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseForInitStatement(StatementAST *&node) { if (parseDeclarationStatement(node)) return true; return parseExpressionStatement(node); } bool Parser::parseCompoundStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); CHECK('{'); CompoundStatementAST *ast = CreateNode(session->mempool); while (session->token_stream->lookAhead()) { if (session->token_stream->lookAhead() == '}') break; uint startStmt = session->token_stream->cursor(); StatementAST *stmt = 0; if (!parseStatement(stmt)) { if (startStmt == session->token_stream->cursor()) advance(); skipUntilStatement(); } else { ast->statements = snoc(ast->statements, stmt, session->mempool); } } clearComment(); ADVANCE_NR('}', "}"); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseIfStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_if, "if"); ADVANCE('(' , "("); IfStatementAST *ast = CreateNode(session->mempool); ConditionAST *cond = 0; if (!parseCondition(cond)) { reportError(("Condition expected")); return false; } ADVANCE(')', ")"); StatementAST *stmt = 0; if (!parseStatement(stmt)) { reportError(("Statement expected")); return false; } ast->condition = cond; ast->statement = stmt; if (session->token_stream->lookAhead() == Token_else) { advance(); if (!parseStatement(ast->else_statement)) { reportError(("Statement expected")); return false; } } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseSwitchStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); ADVANCE(Token_switch, "switch"); ADVANCE('(' , "("); ConditionAST *cond = 0; if (!parseCondition(cond)) { reportError(("Condition expected")); return false; } ADVANCE(')', ")"); StatementAST *stmt = 0; if (!parseStatement(stmt)) { reportError(("Statement expected")); return false; } SwitchStatementAST *ast = CreateNode(session->mempool); ast->condition = cond; ast->statement = stmt; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseLabeledStatement(StatementAST *&node) { switch(session->token_stream->lookAhead()) { case Token_identifier: case Token_default: { uint start = session->token_stream->cursor(); if (session->token_stream->lookAhead(1) == ':') { advance(); advance(); StatementAST *stmt = 0; if (parseStatement(stmt)) { LabeledStatementAST* ast = CreateNode(session->mempool); ast->label = start; ast->statement = stmt; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } break; } case Token_case: { uint start = session->token_stream->cursor(); advance(); ExpressionAST *expr = 0; if (!parseConstantExpression(expr)) { reportError(("Expression expected")); } else if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); if (!parseConstantExpression(expr)) { reportError(("Expression expected")); } } ADVANCE(':', ":"); LabeledStatementAST* ast = CreateNode(session->mempool); ast->label = start; ast->expression = expr; parseStatement(ast->statement); if(ast->expression || ast->statement) { UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } break; } return false; } ///TODO: decl-specifier-seq is currently not used at all, /// can lead to problems for certain orders of specifiers bool Parser::parseBlockDeclaration(DeclarationAST *&node) { switch(session->token_stream->lookAhead()) { case Token_typedef: return parseTypedef(node); case Token_using: return parseUsing(node); case Token_asm: return parseAsmDefinition(node); case Token_namespace: return parseNamespaceAliasDefinition(node); case Token_static_assert: return parseStaticAssert(node); } Comment mcomment = comment(); clearComment(); uint start = session->token_stream->cursor(); const ListNode *cv = 0; parseCvQualify(cv); const ListNode *storageSpec = 0; parseStorageClassSpecifier(storageSpec); parseCvQualify(cv); TypeSpecifierAST *spec = 0; // auto support: right now it is part of the storage spec, put it back if (storageSpec && session->token_stream->kind(storageSpec->toBack()->element) == Token_auto) { rewind(storageSpec->toBack()->element); } if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?! rewind(start); return false; } if (!storageSpec) // see also https://bugs.kde.org/show_bug.cgi?id=253827 parseStorageClassSpecifier(storageSpec); parseCvQualify(cv); spec->cv = cv; const ListNode *declarators = 0; parseInitDeclaratorList(declarators); if (session->token_stream->lookAhead() != ';') { rewind(start); return false; } advance(); SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->type_specifier = spec; ast->init_declarators = declarators; if(mcomment) addComment(ast, mcomment); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseStaticAssert(DeclarationAST*& node) { uint start = session->token_stream->cursor(); CHECK(Token_static_assert); ADVANCE('(', ")"); StaticAssertAST *ast = CreateNode(session->mempool); if (!parseConstantExpression(ast->expression)) { reportError("Constant expression expected"); } ADVANCE(',', ","); if (!parseStringLiteral(ast->string)) { reportError("String literal expected"); } ADVANCE(')', ")"); ADVANCE(';', ";"); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_namespace); NamespaceAliasDefinitionAST *ast = CreateNode(session->mempool); uint pos = session->token_stream->cursor(); ADVANCE(Token_identifier, "identifier"); ast->namespace_name = pos; ADVANCE('=', "="); if (!parseName(ast->alias_name)) { reportError(("Namespace name expected")); } ADVANCE(';', ";"); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseDeclarationStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); DeclarationAST *decl = 0; if (!parseBlockDeclaration(decl)) return false; DeclarationStatementAST *ast = CreateNode(session->mempool); ast->declaration = decl; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseDeclarationInternal(DeclarationAST *&node) { uint start = session->token_stream->cursor(); // that is for the case '__declspec(dllexport) int ...' or // '__declspec(dllexport) inline int ...', etc. WinDeclSpecAST *winDeclSpec = 0; parseWinDeclSpec(winDeclSpec); const ListNode *funSpec = 0; bool hasFunSpec = parseFunctionSpecifier(funSpec); const ListNode *cv = 0; parseCvQualify(cv); const ListNode *storageSpec = 0; bool hasStorageSpec = parseStorageClassSpecifier(storageSpec); if (hasStorageSpec && !hasFunSpec) hasFunSpec = parseFunctionSpecifier(funSpec); // that is for the case 'friend __declspec(dllexport) ....' parseWinDeclSpec(winDeclSpec); if (!cv) parseCvQualify(cv); int index = session->token_stream->cursor(); NameAST *name = 0; if (parseName(name, AcceptTemplate) && session->token_stream->lookAhead() == '(') { // no type specifier, maybe a constructor or a cast operator?? rewind(index); int startDeclarator = session->token_stream->cursor(); DeclaratorAST *declarator = 0; if (parseDeclarator(declarator) && declarator->parameter_declaration_clause) { switch(session->token_stream->lookAhead()) { case '=': { advance(); if (session->token_stream->lookAhead() == Token_delete || session->token_stream->lookAhead() == Token_default) { FunctionDefinitionAST::DefaultDeleted defaultDeleted = (session->token_stream->lookAhead() == Token_delete) ? FunctionDefinitionAST::Deleted : FunctionDefinitionAST::Default; advance(); CHECK(';'); // defaulted or deleted functions are definitions FunctionDefinitionAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->declarator = declarator; ast->defaultDeleted = defaultDeleted; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } case ':': { CtorInitializerAST *ctorInit = 0; StatementAST *funBody = 0; if (parseCtorInitializer(ctorInit) && parseFunctionBody(funBody)) { FunctionDefinitionAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->declarator = declarator; ast->function_body = funBody; ast->constructor_initializers = ctorInit; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } break; case Token_try: case '{': { StatementAST *funBody = 0; if (parseFunctionBody(funBody)) { FunctionDefinitionAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->declarator = declarator; ast->function_body = funBody; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } break; case '(': case '[': // ops!! it seems a declarator goto start_decl; break; } } // else expect something else rewind(startDeclarator); // check for simple-declaration const ListNode *declarators = 0; parseInitDeclaratorList(declarators); if (session->token_stream->lookAhead() == ';') { advance(); // simple-declaration SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->win_decl_specifiers = winDeclSpec; ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } start_decl: rewind(index); if (session->token_stream->lookAhead() == Token_const && session->token_stream->lookAhead(1) == Token_identifier && session->token_stream->lookAhead(2) == '=') { // constant definition advance(); // skip const const ListNode *declarators = 0; if (!parseInitDeclaratorList(declarators)) { syntaxError(); return false; } ADVANCE(';', ";"); SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } TypeSpecifierAST *spec = 0; // auto support: right now it is part of the storage spec, put it back if (hasStorageSpec && session->token_stream->kind(storageSpec->toBack()->element) == Token_auto) { rewind(storageSpec->toBack()->element); } if (parseTypeSpecifier(spec)) { Q_ASSERT(spec != 0); if (!hasFunSpec) parseFunctionSpecifier(funSpec); // e.g. "void inline" if (cv) spec->cv = cv; int startDeclarator = session->token_stream->cursor(); if (parseFunctionDefinitionInternal(node, start, winDeclSpec, storageSpec, funSpec, spec)) { return true; } // else simple-declaration rewind(startDeclarator); const ListNode *declarators = 0; parseInitDeclaratorList(declarators); if (session->token_stream->lookAhead() == ';') { advance(); // simple-declaration SimpleDeclarationAST *ast = CreateNode(session->mempool); ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->type_specifier = spec; ast->win_decl_specifiers = winDeclSpec; ast->init_declarators = declarators; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } syntaxError(); return false; } bool Parser::parseFunctionDefinitionInternal(DeclarationAST*& node, uint start, WinDeclSpecAST* winDeclSpec, const ListNode* storageSpec, const ListNode* funSpec, TypeSpecifierAST* spec) { DeclaratorAST* declarator = 0; StatementAST *funBody = 0; FunctionDefinitionAST::DefaultDeleted defaultDeleted = FunctionDefinitionAST::NotDefaultOrDeleted; if (!parseDeclarator(declarator)) { return false; } if (!declarator->parameter_declaration_clause) { // cannot be a function definition without a param decl clause rewind(start); return false; } if (session->token_stream->lookAhead() == '=' && (session->token_stream->lookAhead(1) == Token_delete || session->token_stream->lookAhead(1) == Token_default) && session->token_stream->lookAhead(2) == ';') { advance(); if (session->token_stream->lookAhead() == Token_delete) { defaultDeleted = FunctionDefinitionAST::Deleted; } else { defaultDeleted = FunctionDefinitionAST::Default; } advance(); advance(); } else if (!parseFunctionBody(funBody)) { return false; } FunctionDefinitionAST *ast = CreateNode(session->mempool); ast->win_decl_specifiers = winDeclSpec; ast->storage_specifiers = storageSpec; ast->function_specifiers = funSpec; ast->type_specifier = spec; ast->declarator = declarator; ast->function_body = funBody; ast->defaultDeleted = defaultDeleted; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseFunctionBody(StatementAST *&node) { if (session->token_stream->lookAhead() == Token_try) return parseTryBlockStatement(node); return parseCompoundStatement(node); } bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node) { if (parseClassSpecifier(node)) return true; else if (parseEnumSpecifier(node)) return true; else if (parseTypeSpecifier(node)) return true; return false; } bool Parser::parseTryBlockStatement(StatementAST *&node) { uint start = session->token_stream->cursor(); CHECK(Token_try); TryBlockStatementAST *ast = CreateNode(session->mempool); StatementAST *stmt = 0; if (!parseCompoundStatement(stmt)) { syntaxError(); return false; } ast->try_block = stmt; if (session->token_stream->lookAhead() != Token_catch) { reportError(("'catch' expected after try block")); return false; } while (session->token_stream->lookAhead() == Token_catch) { uint catchStart = session->token_stream->cursor(); advance(); ADVANCE('(', "("); ConditionAST *cond = 0; if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); } else if(session->token_stream->lookAhead() == ')') { //Do nothing, this is equivalent to ellipsis } else if (!parseCondition(cond, false)) { reportError(("condition expected")); return false; } ADVANCE(')', ")"); StatementAST *body = 0; if (!parseCompoundStatement(body)) { syntaxError(); return false; } CatchStatementAST *catch_ast = CreateNode(session->mempool); catch_ast->condition = cond; catch_ast->statement = body; UPDATE_POS(catch_ast, catchStart, _M_last_valid_token+1); ast->catch_blocks = snoc(ast->catch_blocks, catch_ast, session->mempool); } node = ast; UPDATE_POS(ast, start, _M_last_valid_token+1); return true; } bool Parser::parsePrimaryExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); switch(session->token_stream->lookAhead()) { case Token_string_literal: { PrimaryExpressionAST *ast = 0; ast = CreateNode(session->mempool); parseStringLiteral(ast->literal); ast->type = PrimaryExpressionAST::Literal; node = ast; } break; case Token_number_literal: case Token_char_literal: case Token_true: case Token_false: case Token_this: case Token_nullptr: { PrimaryExpressionAST *ast = 0; ast = CreateNode(session->mempool); ast->token = session->token_stream->cursor(); advance(); ast->type = PrimaryExpressionAST::Token; node = ast; } break; case '(': { PrimaryExpressionAST *ast = 0; advance(); if (session->token_stream->lookAhead() == '{') { StatementAST *expressionStatement = 0; if (!parseCompoundStatement(expressionStatement)) return false; ast = CreateNode(session->mempool); ast->expression_statement = expressionStatement; ast->type = PrimaryExpressionAST::Statement; } else { ExpressionAST *expression = 0; if (!parseExpression(expression)) return false; ast = CreateNode(session->mempool); ast->sub_expression = expression; ast->type = PrimaryExpressionAST::SubExpression; } CHECK(')'); node = ast; } break; default: NameAST *name = 0; if (parseName(name, EventuallyAcceptTemplate)) { PrimaryExpressionAST *ast = 0; ast = CreateNode(session->mempool); ast->name = name; ast->type = PrimaryExpressionAST::Name; node = ast; } else if(!parseLambdaExpression(node)) { return false; } break; } UPDATE_POS(node, start, _M_last_valid_token+1); return true; } /* postfix-expression-internal: [ expression ] ( expression-list [opt] ) (.|->) template [opt] id-expression (.|->) pseudo-destructor-name ++ -- */ bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) { uint start = session->token_stream->cursor(); switch (session->token_stream->lookAhead()) { case '[': { advance(); ExpressionAST *expr = 0; parseExpression(expr) || parseBracedInitList(expr); CHECK(']'); SubscriptExpressionAST *ast = CreateNode(session->mempool); ast->subscript = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case '(': { advance(); ExpressionAST *expr = 0; parseExpressionList(expr); ///TODO: is this the right place? can't find anything in the last public spec file... bool isVariadic = false; if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); isVariadic = true; } CHECK(')'); FunctionCallAST *ast = CreateNode(session->mempool); ast->arguments = expr; ast->isVariadic = isVariadic; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case '{': { ExpressionAST *expr = 0; if (parseBracedInitList(expr)) { UPDATE_POS(expr, start, _M_last_valid_token+1); node = expr; return true; } return false; } case '.': case Token_arrow: { uint op = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() == Token_template) advance(); NameAST *name = 0; if (!parseName(name, EventuallyAcceptTemplate)) return false; ClassMemberAccessAST *ast = CreateNode(session->mempool); ast->op = op; ast->name = name; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case Token_incr: case Token_decr: { uint op = session->token_stream->cursor(); advance(); IncrDecrExpressionAST *ast = CreateNode(session->mempool); ast->op = op; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; default: return false; } } /* postfix-expression: simple-type-specifier ( expression-list [opt] ) primary-expression postfix-expression-internal* */ bool Parser::parsePostfixExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); switch (session->token_stream->lookAhead()) { case Token_dynamic_cast: case Token_static_cast: case Token_reinterpret_cast: case Token_const_cast: { uint castOp = session->token_stream->cursor(); advance(); CHECK('<'); TypeIdAST *typeId = 0; parseTypeId(typeId); CHECK('>'); CHECK('('); ExpressionAST *expr = 0; parseCommaExpression(expr); CHECK(')'); CppCastExpressionAST *ast = CreateNode(session->mempool); ast->op = castOp; ast->type_id = typeId; ast->expression = expr; ExpressionAST *e = 0; while (parsePostfixExpressionInternal(e)) { ast->sub_expressions = snoc(ast->sub_expressions, e, session->mempool); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case Token_typename: { uint token = session->token_stream->cursor(); advance(); NameAST* name = 0; if (!parseName(name, AcceptTemplate)) return false; CHECK('('); ExpressionAST *expr = 0; parseExpressionList(expr); CHECK(')'); TypeIdentificationAST *ast = CreateNode(session->mempool); ast->typename_token = token; ast->name = name; ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case Token_typeid: { advance(); CHECK('('); TypeIdAST *typeId = 0; ExpressionAST *expression = 0; // either typeid or expression expected parseTypeId(typeId) || parseExpression(expression); CHECK(')'); TypeIDOperatorAST *ast = CreateNode(session->mempool); ast->expression = expression; ast->typeId = typeId; ExpressionAST *e = 0; while (parsePostfixExpressionInternal(e)) { ast->sub_expressions = snoc(ast->sub_expressions, e, session->mempool); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; default: break; } TypeSpecifierAST *typeSpec = 0; ExpressionAST *expr = 0; bool expectPrimary = true; if (parseSimpleTypeSpecifier(typeSpec,true)) { if (session->token_stream->lookAhead() == '(') { advance(); // skip '(' parseExpressionList(expr); CHECK(')'); expectPrimary = false; } else if (parseBracedInitList(expr)) { expectPrimary = false; } } if (expectPrimary) { typeSpec = 0; rewind(start); if (!parsePrimaryExpression(expr)) { return false; } } const ListNode *sub_expressions = 0; if (typeSpec && expr) { // If we have a type-specifier, make the expression a sub-expression sub_expressions = snoc(sub_expressions, expr, session->mempool); expr = 0; } ExpressionAST *sub_expression = 0; while (parsePostfixExpressionInternal(sub_expression)) { sub_expressions = snoc(sub_expressions, sub_expression, session->mempool); } node = expr; if (sub_expressions || !node) { PostfixExpressionAST *ast = CreateNode(session->mempool); ast->type_specifier = typeSpec; ast->expression = expr; ast->sub_expressions = sub_expressions; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseUnaryExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); switch(session->token_stream->lookAhead()) { case Token_incr: case Token_decr: case '*': case '&': case '+': case '-': case '!': case Token_not: case '~': case Token_compl: { uint op = session->token_stream->cursor(); advance(); ExpressionAST *expr = 0; if (!parseCastExpression(expr)) return false; UnaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; case Token_sizeof: { uint sizeof_token = session->token_stream->cursor(); advance(); bool isVariadic = false; if (session->token_stream->lookAhead() == Token_ellipsis) { isVariadic = true; advance(); } SizeofExpressionAST *ast = CreateNode(session->mempool); ast->sizeof_token = sizeof_token; ast->isVariadic = isVariadic; uint index = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '(') { advance(); if (parseTypeId(ast->type_id) && session->token_stream->lookAhead() == ')') { advance(); // skip ) UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } ast->type_id = 0; rewind(index); } if (!parseUnaryExpression(ast->expression)) return false; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } case Token_noexcept: // same as generic case, but parentheses are not optional { uint op = session->token_stream->cursor(); advance(); if (session->token_stream->lookAhead() != '(') { tokenRequiredError ('('); return false; } ExpressionAST *expr = 0; if (!parseUnaryExpression(expr)) return false; UnaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } default: break; } int token = session->token_stream->lookAhead(); if (token == Token_new || (token == Token_scope && session->token_stream->lookAhead(1) == Token_new)) return parseNewExpression(node); if (token == Token_delete || (token == Token_scope && session->token_stream->lookAhead(1) == Token_delete)) return parseDeleteExpression(node); return parsePostfixExpression(node); } bool Parser::parseNewExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); NewExpressionAST *ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_scope && session->token_stream->lookAhead(1) == Token_new) { ast->scope_token = session->token_stream->cursor(); advance(); } uint pos = session->token_stream->cursor(); CHECK(Token_new); ast->new_token = pos; if (session->token_stream->lookAhead() == '(') { // new-placement advance(); parseExpressionList(ast->expression); CHECK(')'); } if (session->token_stream->lookAhead() == '(') { advance(); parseTypeId(ast->type_id); CHECK(')'); } else { parseNewTypeId(ast->new_type_id); } parseNewInitializer(ast->new_initializer); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseNewTypeId(NewTypeIdAST *&node) { uint start = session->token_stream->cursor(); TypeSpecifierAST *typeSpec = 0; if (!parseTypeSpecifier(typeSpec)) return false; NewTypeIdAST *ast = CreateNode(session->mempool); ast->type_specifier = typeSpec; parseNewDeclarator(ast->new_declarator); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseNewDeclarator(NewDeclaratorAST *&node) { uint start = session->token_stream->cursor(); NewDeclaratorAST *ast = CreateNode(session->mempool); PtrOperatorAST *ptrOp = 0; if (parsePtrOperator(ptrOp)) { ast->ptr_op = ptrOp; parseNewDeclarator(ast->sub_declarator); } while (session->token_stream->lookAhead() == '[') { advance(); ExpressionAST *expr = 0; parseExpression(expr); ast->expressions = snoc(ast->expressions, expr, session->mempool); ADVANCE(']', "]"); } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseNewInitializer(NewInitializerAST *&node) { uint start = session->token_stream->cursor(); ExpressionAST *expr = 0; if (session->token_stream->lookAhead() == '(') { advance(); parseExpressionList(expr); CHECK(')'); } else if (!parseBracedInitList(expr)) { rewind(start); return false; } NewInitializerAST *ast = CreateNode(session->mempool); ast->expression = expr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseDeleteExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); DeleteExpressionAST *ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_scope && session->token_stream->lookAhead(1) == Token_delete) { ast->scope_token = session->token_stream->cursor(); advance(); } uint pos = session->token_stream->cursor(); CHECK(Token_delete); ast->delete_token = pos; if (session->token_stream->lookAhead() == '[') { ast->lbracket_token = session->token_stream->cursor(); advance(); uint pos = session->token_stream->cursor(); CHECK(']'); ast->rbracket_token = pos; } if (!parseCastExpression(ast->expression)) return false; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseCastExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (session->token_stream->lookAhead() == '(') { advance(); TypeIdAST *typeIdAst = 0; if (parseTypeId(typeIdAst)) { if (session->token_stream->lookAhead() == ')') { advance(); ExpressionAST *castExpressionAst = 0; if (parseCastExpression(castExpressionAst)) { CastExpressionAST *ast = CreateNode(session->mempool); ast->type_id = typeIdAst; ast->expression = castExpressionAst; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } } } } rewind(start); return parseUnaryExpression(node); } bool Parser::parsePmExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (!parseCastExpression(node) || !node) // ### fixme return false; while (session->token_stream->lookAhead() == Token_ptrmem) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseCastExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (!parsePmExpression(node)) return false; while (session->token_stream->lookAhead() == '*' || session->token_stream->lookAhead() == '/' || session->token_stream->lookAhead() == '%') { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parsePmExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseAdditiveExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (!parseMultiplicativeExpression(node)) return false; while (session->token_stream->lookAhead() == '+' || session->token_stream->lookAhead() == '-') { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseMultiplicativeExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseShiftExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (!parseAdditiveExpression(node)) return false; while (session->token_stream->lookAhead() == Token_rightshift || session->token_stream->lookAhead() == Token_leftshift) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseAdditiveExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseShiftExpression(node)) return false; while (session->token_stream->lookAhead() == '<' || (session->token_stream->lookAhead() == '>' && !templArgs) || session->token_stream->lookAhead() == Token_leq || session->token_stream->lookAhead() == Token_geq) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseShiftExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseRelationalExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == Token_eq || session->token_stream->lookAhead() == Token_not_eq || session->token_stream->lookAhead() == Token_xor_eq || session->token_stream->lookAhead() == Token_or_eq || session->token_stream->lookAhead() == Token_and_eq) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseRelationalExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseEqualityExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == '&' || session->token_stream->lookAhead() == Token_bitand) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseEqualityExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseAndExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == '^' || session->token_stream->lookAhead() == Token_xor) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseAndExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseExclusiveOrExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == '|' || session->token_stream->lookAhead() == Token_bitor) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseExclusiveOrExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseInclusiveOrExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == Token_and) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseInclusiveOrExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseLogicalAndExpression(node, templArgs)) return false; while (session->token_stream->lookAhead() == Token_or) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseLogicalAndExpression(rightExpr, templArgs)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseConditionalExpression(ExpressionAST *&node, bool templArgs) { uint start = session->token_stream->cursor(); if (!parseLogicalOrExpression(node, templArgs)) return false; if (session->token_stream->lookAhead() == '?') { advance(); ExpressionAST *leftExpr = 0; if (!parseExpression(leftExpr)) { //NOTE: allow ommitting operand, for compatibility with gcc, see also: // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC70 // https://bugs.kde.org/show_bug.cgi?id=292357 reportError("ISO C++ does not allow ?: with omitted middle operand", KDevelop::ProblemData::Warning); } CHECK(':'); ExpressionAST *rightExpr = 0; if (!parseAssignmentExpression(rightExpr)) return false; ConditionalExpressionAST *ast = CreateNode(session->mempool); ast->condition = node; ast->left_expression = leftExpr; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } //note: this does not really follow the grammar, // esp. the braced-init-list support might need to be // reworked, since the grammar says: // logical-or-expression assignment-operator initializer-clause bool Parser::parseAssignmentExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if(parseSignalSlotExpression(node)) return true; //Parsed a signal/slot expression, fine if (session->token_stream->lookAhead() == Token_throw && !parseThrowExpression(node)) return false; else if (!parseConditionalExpression(node)) return false; while ( token_is_assignment(session->token_stream->lookAhead()) ) { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseConditionalExpression(rightExpr) && !parseSignalSlotExpression(rightExpr) && !parseBracedInitList(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseConstantExpression(ExpressionAST *&node) { return parseConditionalExpression(node); } bool Parser::parseExpression(ExpressionAST *&node) { return parseCommaExpression(node); } bool Parser::parseExpressionList(ExpressionAST*& node) { InitializerListAST* listNode = 0; const bool success = parseInitializerList(listNode); node = listNode; return success; } bool Parser::parseSignalSlotExpression(ExpressionAST *&node) { if(session->token_stream->lookAhead() == Token___qt_signal__ || session->token_stream->lookAhead() == Token___qt_slot__) { uint start = session->token_stream->cursor(); if(session->token_stream->lookAhead() == Token___qt_signal__) CHECK(Token___qt_signal__); else CHECK(Token___qt_slot__); CHECK('('); SignalSlotExpressionAST *ast = CreateNode(session->mempool); parseUnqualifiedName(ast->name, false); CHECK('('); if(ast->name) parseTemplateArgumentList(ast->name->template_arguments); CHECK(')'); if(ast->name) ast->name->end_token = _M_last_valid_token+1; CHECK(')'); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; }else{ return false; } } bool Parser::parseQProperty(DeclarationAST *&node) { if(session->token_stream->lookAhead() == Token___qt_property__) { uint start = session->token_stream->cursor(); QPropertyDeclarationAST *ast = CreateNode(session->mempool); ast->member = 0; ast->getter = 0; ast->setter = 0; ast->resetter = 0; ast->notifier = 0; ast->designableMethod = 0; ast->scriptableMethod = 0; CHECK(Token___qt_property__); CHECK('('); if(!parseTypeSpecifier(ast->type)) return false; PtrOperatorAST *ptrOp = 0; while (parsePtrOperator(ptrOp)) ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, session->mempool); if(!parseName(ast->name)) return false; static KDevelop::IndexedString memberStr("MEMBER"); static KDevelop::IndexedString readStr("READ"); static KDevelop::IndexedString writeStr("WRITE"); static KDevelop::IndexedString resetStr("RESET"); static KDevelop::IndexedString notifyStr("NOTIFY"); static KDevelop::IndexedString revisionStr("REVISION"); static KDevelop::IndexedString designableStr("DESIGNABLE"); static KDevelop::IndexedString scriptableStr("SCRIPTABLE"); static KDevelop::IndexedString storedStr("STORED"); static KDevelop::IndexedString userStr("USER"); static KDevelop::IndexedString constantStr("CONSTANT"); static KDevelop::IndexedString finalStr("FINAL"); while(session->token_stream->lookAhead() != ')') { const KDevelop::IndexedString propertyField = session->token_stream->symbol(session->token_stream->cursor()); if (propertyField == memberStr) { advance(); // skip MEMBER if (!parseName(ast->member)) return false; } else if(propertyField == readStr) { advance(); // skip READ if(!parseName(ast->getter)) return false; }else if(propertyField == writeStr){ advance(); // skip WRITE if(!parseName(ast->setter)) return false; }else if(propertyField == resetStr){ advance(); // skip RESET if(!parseName(ast->resetter)) return false; }else if(propertyField == notifyStr){ advance(); // skip NOTIFY if(!parseName(ast->notifier)) return false; } else if (propertyField == revisionStr) { advance(); // skip REVISION if (session->token_stream->lookAhead() == Token_number_literal) { advance(); } else { return false; } } else if(propertyField == designableStr){ advance(); // skip DESIGNABLE if(session->token_stream->lookAhead() == Token_true){ advance(); // skip 'true' }else if(session->token_stream->lookAhead() == Token_false){ advance(); // skip 'false' }else{ if(!parseName(ast->designableMethod)) return false; } }else if(propertyField == scriptableStr){ advance(); // skip SCRIPTABLE if(session->token_stream->lookAhead() == Token_true){ advance(); // skip 'true' }else if(session->token_stream->lookAhead() == Token_false){ advance(); // skip 'false' }else{ if(!parseName(ast->scriptableMethod)) return false; } }else if(propertyField == storedStr){ advance(); // skip STORED if(session->token_stream->lookAhead() == Token_true){ advance(); // skip 'true' }else if(session->token_stream->lookAhead() == Token_false){ advance(); // skip 'false' }else{ return false; } }else if(propertyField == userStr){ advance(); // skip USER if(session->token_stream->lookAhead() == Token_true){ advance(); // skip 'true' }else if(session->token_stream->lookAhead() == Token_false){ advance(); // skip 'false' }else{ return false; } }else if(propertyField == constantStr){ advance(); // skip CONSTANT }else if(propertyField == finalStr){ advance(); // skip FINAL }else{ return false; } } CHECK(')'); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; }else{ return false; } } bool Parser::parseCommaExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); if (!parseAssignmentExpression(node)) return false; while (session->token_stream->lookAhead() == ',') { uint op = session->token_stream->cursor(); advance(); ExpressionAST *rightExpr = 0; if (!parseAssignmentExpression(rightExpr)) return false; BinaryExpressionAST *ast = CreateNode(session->mempool); ast->op = op; ast->left_expression = node; ast->right_expression = rightExpr; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; } return true; } bool Parser::parseThrowExpression(ExpressionAST *&node) { uint start = session->token_stream->cursor(); uint pos = session->token_stream->cursor(); CHECK(Token_throw); ThrowExpressionAST *ast = CreateNode(session->mempool); ast->throw_token = pos; parseAssignmentExpression(ast->expression); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseTrailingReturnType(TrailingReturnTypeAST*& node) { uint start = session->token_stream->cursor(); CHECK(Token_arrow); TrailingReturnTypeAST *ast = CreateNode(session->mempool); // trailing-type-specifier-seq TypeSpecifierAST* type = 0; while (parseTypeSpecifier(type)) { ast->type_specifier = snoc(ast->type_specifier, type, session->mempool); } // abstract-declarator_opt parseAbstractDeclarator(ast->abstractDeclarator); UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseLambdaExpression(ExpressionAST*& node) { uint start = session->token_stream->cursor(); // parse lambda-capture CHECK('['); uint defaultCapture = 0; const ListNode* captures = 0; // capture-default if ( (session->token_stream->lookAhead() == '&' || session->token_stream->lookAhead() == '=') && (session->token_stream->lookAhead(+1) == ']' || session->token_stream->lookAhead(+1) == ',')) { defaultCapture = session->token_stream->lookAhead(); advance(); if (session->token_stream->lookAhead() == ',') advance(); } // capture-list while(session->token_stream->lookAhead() && session->token_stream->lookAhead() != ']') { LambdaCaptureAST* capture = 0; if (!parseLambdaCapture(capture)) { break; } captures = snoc(captures, capture, session->mempool); if (session->token_stream->lookAhead() == ',') advance(); else break; } CHECK(']'); LambdaDeclaratorAST* declarator = 0; // optional parseLambdaDeclarator(declarator); StatementAST* compound; if (!parseCompoundStatement(compound)) { reportError("Compound statement expected"); rewind(start); return false; } LambdaExpressionAST* ast = CreateNode(session->mempool); ast->capture_list = captures; ast->compound = compound; ast->declarator = declarator; ast->default_capture = defaultCapture; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseLambdaCapture(LambdaCaptureAST*& node) { uint start = session->token_stream->cursor(); LambdaCaptureAST* ast = CreateNode(session->mempool); if (session->token_stream->lookAhead() == Token_this) { advance(); ast->isThis = true; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } if (session->token_stream->lookAhead() == '&') { ast->isRef = true; advance(); } if (!parseName(ast->identifier)) { rewind(start); return false; } if (session->token_stream->lookAhead() == Token_ellipsis) { advance(); ast->isVariadic = true; } UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseLambdaDeclarator(LambdaDeclaratorAST*& node) { uint start = session->token_stream->cursor(); CHECK('('); ParameterDeclarationClauseAST* params = 0; parseParameterDeclarationClause(params); CHECK(')'); ///TODO: attribute-specifier bool isMutable = false; if (session->token_stream->lookAhead() == Token_mutable) { isMutable = true; advance(); } ExceptionSpecificationAST* exception_spec = 0; parseExceptionSpecification(exception_spec); TrailingReturnTypeAST* trailing_return_type = 0; parseTrailingReturnType(trailing_return_type); LambdaDeclaratorAST* ast = CreateNode(session->mempool); ast->parameter_declaration_clause = params; ast->isMutable = isMutable; ast->exception_spec = exception_spec; ast->trailing_return_type = trailing_return_type; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; return true; } bool Parser::parseMemberVirtSpecifier(const ListNode< uint >*& node) { uint start = session->token_stream->cursor(); int tk; while (0 != (tk = session->token_stream->lookAhead()) && (tk == Token_override || tk == Token_final || tk == Token_new)) { node = snoc(node, session->token_stream->cursor(), session->mempool); advance(); } return start != session->token_stream->cursor(); } bool Parser::parseClassVirtSpecifier(const ListNode< uint >*& node) { uint start = session->token_stream->cursor(); int tk; while (0 != (tk = session->token_stream->lookAhead()) && (tk == Token_final || tk == Token_explicit)) { node = snoc(node, session->token_stream->cursor(), session->mempool); advance(); } return start != session->token_stream->cursor(); } bool Parser::holdErrors(bool hold) { bool current = _M_hold_errors; _M_hold_errors = hold; return current; } QString Parser::stringForNode(AST* node) const { if (!node) { return ""; } return session->stringForNode(node); }