/******************************************************************************* * Copyright (c) 2002, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * John Camelon (IBM Corporation) - initial API and implementation * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=151207 * Ed Swartz (Nokia) * Mike Kucera (IBM) * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator; import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression.Operator; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTInitializerList; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTPointer; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTArrayDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpandable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory; import org.eclipse.cdt.core.dom.parser.IExtensionToken; import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.parser.EndOfFileException; import org.eclipse.cdt.core.parser.IGCCToken; import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.ParserMode; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser; import org.eclipse.cdt.internal.core.dom.parser.BacktrackException; import org.eclipse.cdt.internal.core.dom.parser.DeclarationOptions; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousExpression; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement; import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.BranchPoint; import org.eclipse.cdt.internal.core.dom.parser.cpp.NameOrTemplateIDVariants.Variant; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; /** * This is our implementation of the IParser interface, serving as a parser for * GNU C and C++. From time to time we will make reference to the ANSI ISO * specifications. */ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { private static final int DEFAULT_PARM_LIST_SIZE = 4; private static final int DEFAULT_CATCH_HANDLER_LIST_SIZE= 4; private static enum DtorStrategy {PREFER_FUNCTION, PREFER_NESTED} private final boolean allowCPPRestrict; private final boolean supportExtendedTemplateSyntax; private final boolean supportAutoTypeSpecifier; private final IIndex index; protected ICPPASTTranslationUnit translationUnit; private int functionBodyCount= 0; private char[] currentClassName; private final ICPPNodeFactory nodeFactory; private TemplateIdStrategy fTemplateParameterListStrategy; public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService log, ICPPParserExtensionConfiguration config) { this(scanner, mode, log, config, null); } public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService log, ICPPParserExtensionConfiguration config, IIndex index) { super(scanner, log, mode, CPPNodeFactory.getDefault(), config.supportStatementsInExpressions(), config.supportTypeofUnaryExpressions(), config.supportAlignOfUnaryExpression(), config.supportKnRC(), config.supportAttributeSpecifiers(), config.supportDeclspecSpecifiers(), config.getBuiltinBindingsProvider()); allowCPPRestrict = config.allowRestrictPointerOperators(); supportExtendedTemplateSyntax = config.supportExtendedTemplateSyntax(); supportParameterInfoBlock= config.supportParameterInfoBlock(); supportExtendedSizeofOperator= config.supportExtendedSizeofOperator(); supportFunctionStyleAsm= config.supportFunctionStyleAssembler(); functionCallCanBeLValue= true; supportAutoTypeSpecifier= true; this.index= index; this.nodeFactory = CPPNodeFactory.getDefault(); scanner.setSplitShiftROperator(true); } @Override protected IASTName identifier() throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.tIDENTIFIER: case IToken.tCOMPLETION: case IToken.tEOC: return buildName(-1, consume()); } throw backtrack; } private IASTName qualifiedName() throws BacktrackException, EndOfFileException { TemplateIdStrategy strat= new TemplateIdStrategy(); IToken m= mark(); for(;;) { try { return qualifiedName(strat, CastExprCtx.eNotInBExpr); } catch (BacktrackException e) { if (strat.setNextAlternative()) { backup(m); } else { throw e; } } } } /** * Parses a qualified name. */ private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException { final TemplateIdStrategy strat= (TemplateIdStrategy) s; ICPPASTQualifiedName qname= null; IASTName name= null; final int offset= LA(1).getOffset(); int endOffset= offset; if (LT(1) == IToken.tCOLONCOLON) { endOffset= consume().getEndOffset(); qname= nodeFactory.newQualifiedName(); qname.setFullyQualified(true); } boolean mustBeLast= false; boolean haveName= false; loop: for(;;) { boolean keywordTemplate= false; if (qname != null && LT(1) == IToken.t_template) { consume(); keywordTemplate= true; } int destructorOffset= -1; if (LT(1) == IToken.tBITCOMPLEMENT) { destructorOffset= consume().getOffset(); mustBeLast= true; } switch (LT(1)) { case IToken.tIDENTIFIER: case IToken.tCOMPLETION: case IToken.tEOC: IToken nt= consume(); name = buildName(destructorOffset, nt); break; case IToken.t_operator: name= operatorId(); break; default: if (!haveName || destructorOffset >= 0 || keywordTemplate) { throwBacktrack(LA(1)); } name= nodeFactory.newName(CharArrayUtils.EMPTY); if (qname != null) { qname.addName(name); } break loop; } haveName= true; // Check for template-id if (LTcatchEOF(1) == IToken.tLT) { final boolean inBinaryExpression = ctx != CastExprCtx.eNotInBExpr; final int haveArgs = haveTemplateArguments(inBinaryExpression); boolean templateID= true; if (!keywordTemplate) { if (haveArgs == -1) { templateID= false; } else if (haveArgs == 0) { if (strat.ignoreTemplateID()) { templateID= false; } else { strat.addTemplateName(name); } } } if (templateID) { if (haveArgs == -1) throwBacktrack(LA(1)); name= addTemplateArguments(name, strat); } } endOffset= calculateEndOffset(name); if (qname != null) { qname.addName(name); } if (LTcatchEOF(1) != IToken.tCOLONCOLON) break loop; if (mustBeLast) throwBacktrack(LA(1)); endOffset= consume().getEndOffset(); // :: if (qname == null) { qname= nodeFactory.newQualifiedName(); qname.addName(name); } } if (qname != null) { setRange(qname, offset, endOffset); name= qname; } return name; } private IASTName buildName(int destructorOffset, IToken nt) { IASTName name; if (destructorOffset < 0) { name= nodeFactory.newName(nt.getCharImage()); setRange(name, nt.getOffset(), nt.getEndOffset()); } else { char[] nchars= nt.getCharImage(); final int len= nchars.length; char[] image = new char[len+1]; image[0]= '~'; System.arraycopy(nchars, 0, image, 1, len); name= nodeFactory.newName(image); setRange(name, destructorOffset, nt.getEndOffset()); } switch (nt.getType()) { case IToken.tEOC: case IToken.tCOMPLETION: createCompletionNode(nt).addName(name); break; } return name; } private IASTName addTemplateArguments(IASTName templateName, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { // Parse for template arguments consume(IToken.tLT); List<IASTNode> list = templateArgumentList(strat); IToken end= LA(1); switch (end.getType()) { case IToken.tGT_in_SHIFTR: case IToken.tGT: consume(); break; case IToken.tEOC: break; default: throw backtrack; } return buildTemplateID(templateName, end.getEndOffset(), list); } private ICPPASTTemplateId buildTemplateID(IASTName templateName, int endOffset, List<IASTNode> args) { ICPPASTTemplateId result = nodeFactory.newTemplateId(templateName); setRange(result, ((ASTNode) templateName).getOffset(), endOffset); for (IASTNode n : args) { if (n instanceof IASTTypeId) { result.addTemplateArgument((IASTTypeId) n); } else if (n instanceof IASTExpression) { result.addTemplateArgument((IASTExpression) n); } else if (n instanceof ICPPASTAmbiguousTemplateArgument) { result.addTemplateArgument((ICPPASTAmbiguousTemplateArgument) n); } } return result; } /** * Makes a fast check whether there could be template arguments. * -1: no, 0: ambiguous, 1: yes */ private static final int NO_TEMPLATE_ID= -1; private static final int AMBIGUOUS_TEMPLATE_ID= 0; private static final int TEMPLATE_ID= 1; private int haveTemplateArguments(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { final IToken mark= mark(); try { consume(); int nk= 0; int depth= 0; int angleDepth= 1; int limit= 10000; while(--limit > 0) { switch (consume().getType()) { case IToken.tEOC: case IToken.tCOMPLETION: return AMBIGUOUS_TEMPLATE_ID; case IToken.tLT: if (nk == 0) { angleDepth++; } break; case IToken.tGT_in_SHIFTR: case IToken.tGT: if (nk == 0) { --angleDepth; if (!inBinaryExpression) return angleDepth == 0 ? TEMPLATE_ID : AMBIGUOUS_TEMPLATE_ID; int end= endsTemplateIDInBinaryExpression(); if (end == NO_TEMPLATE_ID) { if (angleDepth == 0) return NO_TEMPLATE_ID; } else { return AMBIGUOUS_TEMPLATE_ID; } } break; case IToken.tLBRACKET: if (nk == 0) { nk= IToken.tLBRACKET; depth= 0; } else if (nk == IToken.tLBRACKET) { depth++; } break; case IToken.tRBRACKET: if (nk == IToken.tLBRACKET) { if (--depth < 0) { nk= 0; } } break; case IToken.tLPAREN: if (nk == 0) { nk= IToken.tLPAREN; depth= 0; } else if (nk == IToken.tLPAREN) { depth++; } break; case IToken.tRPAREN: if (nk == IToken.tLPAREN) { if (--depth < 0) { nk= 0; } } break; case IToken.tSEMI: case IToken.tLBRACE: case IToken.tRBRACE: if (nk == 0) { return NO_TEMPLATE_ID; } break; } } return 0; } finally { backup(mark); } } /** * If '>' is followed by an expression, then it denotes the binary operator, * else it is the end of a template-id, or special-cast. */ private int endsTemplateIDInBinaryExpression() { int lt1= LTcatchEOF(1); switch (lt1) { // Can be start of expression, or the scope operator applied to the template-id case IToken.tCOLONCOLON: // 'CT<int>::member' or 'c<1 && 2 > ::g' return AMBIGUOUS_TEMPLATE_ID; // Can be start of expression or the function-call operator applied to a template-id case IToken.tLPAREN: // 'ft<int>(args)' or 'c<1 && 2 > (x+y)' return AMBIGUOUS_TEMPLATE_ID; // Start of unary expression case IToken.tMINUS: case IToken.tPLUS: case IToken.tAMPER: case IToken.tSTAR: case IToken.tNOT: case IToken.tBITCOMPLEMENT: case IToken.tINCR: case IToken.tDECR: case IToken.t_new: case IToken.t_delete: case IToken.t_sizeof: case IGCCToken.t___alignof__: return NO_TEMPLATE_ID; // Start of a postfix expression case IToken.t_typename: case IToken.t_char: case IToken.t_char16_t: case IToken.t_char32_t: case IToken.t_wchar_t: case IToken.t_bool: case IToken.t_short: case IToken.t_int: case IToken.t_long: case IToken.t_signed: case IToken.t_unsigned: case IToken.t_float: case IToken.t_double: case IToken.t_dynamic_cast: case IToken.t_static_cast: case IToken.t_reinterpret_cast: case IToken.t_const_cast: case IToken.t_typeid: return NO_TEMPLATE_ID; // Start of a primary expression case IToken.tINTEGER: case IToken.tFLOATINGPT: case IToken.tSTRING: case IToken.tLSTRING: case IToken.tUTF16STRING: case IToken.tUTF32STRING: case IToken.tCHAR: case IToken.tLCHAR: case IToken.tUTF16CHAR: case IToken.tUTF32CHAR: case IToken.t_false: case IToken.t_true: case IToken.t_this: case IToken.tIDENTIFIER: case IToken.t_operator: case IToken.tCOMPLETION: return NO_TEMPLATE_ID; // Tokens that end an expression case IToken.tSEMI: case IToken.tCOMMA: case IToken.tLBRACE: case IToken.tRBRACE: case IToken.tRBRACKET: case IToken.tRPAREN: case IToken.tELLIPSIS: // pack-expansion case IToken.t_struct: case IToken.t_class: case IToken.t_template: return TEMPLATE_ID; // Binary operator case IToken.tGT: case IToken.tGT_in_SHIFTR: case IToken.tEQUAL: return TEMPLATE_ID; default: return AMBIGUOUS_TEMPLATE_ID; } } private List<IASTNode> templateArgumentList(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { int startingOffset = LA(1).getOffset(); int endOffset = 0; List<IASTNode> list= null; boolean needComma= false; int lt1= LT(1); while (lt1 != IToken.tGT && lt1 != IToken.tGT_in_SHIFTR && lt1 != IToken.tEOC) { if (needComma) { if (lt1 != IToken.tCOMMA) { throwBacktrack(startingOffset, endOffset - startingOffset); } consume(); } else { needComma= true; } IASTNode node= templateArgument(strat); if (list == null) { list= new ArrayList<IASTNode>(); } list.add(node); lt1= LT(1); } if (list == null) { return Collections.emptyList(); } return list; } private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { IToken argStart = mark(); ICPPASTTypeId typeId= null; int lt1= 0; try { typeId= typeId(DeclarationOptions.TYPEID); lt1 = LT(1); } catch (BacktrackException e) { } if (typeId != null && (lt1 == IToken.tCOMMA || lt1 == IToken.tGT || lt1 == IToken.tGT_in_SHIFTR || lt1 == IToken.tEOC || lt1 == IToken.tELLIPSIS)) { // This is potentially a type-id, now check ambiguity with id-expression IASTDeclSpecifier declspec= typeId.getDeclSpecifier(); if (declspec instanceof IASTNamedTypeSpecifier) { final IASTNamedTypeSpecifier namedDeclspec = (IASTNamedTypeSpecifier) declspec; IASTName name= namedDeclspec.getName(); if (name.contains(typeId)) { IToken typeIdEnd= mark(); IASTIdExpression idExpr= setRange(nodeFactory.newIdExpression(name), name); try { IASTExpression expression = expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, idExpr, strat); boolean isAmbiguous= (expression == idExpr); if (LT(1) == IToken.tELLIPSIS) { IToken ellipsis= consume(); if (isAmbiguous) { addPackExpansion(typeId, ellipsis); } expression= addPackExpansion(expression, ellipsis); } if (isAmbiguous) { ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument(); ambiguity.addTypeId(typeId); ambiguity.addIdExpression(expression); return ambiguity; } return expression; } catch (BacktrackException e) { // Use the typeId } backup(typeIdEnd); namedDeclspec.setName(name); } } // There is no ambiguity, use the type-id if (LT(1) == IToken.tELLIPSIS) { addPackExpansion(typeId, consume()); } return typeId; } // Not a type-id, parse as expression backup(argStart); IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat); if (LT(1) == IToken.tELLIPSIS) { expr= addPackExpansion(expr, consume()); } return expr; } private void addPackExpansion(ICPPASTTypeId typeId, IToken consume) { final int endOffset= consume.getEndOffset(); adjustEndOffset(typeId, endOffset); typeId.setIsPackExpansion(true); } private IASTExpression addPackExpansion(IASTExpression expr, IToken ellipsis) { IASTExpression result= nodeFactory.newPackExpansionExpression(expr); return setRange(result, expr, ellipsis.getEndOffset()); } private IASTName operatorId() throws BacktrackException, EndOfFileException { final IToken firstToken = consume(IToken.t_operator); int endOffset= firstToken.getEndOffset(); IASTTypeId typeId = null; OverloadableOperator op = null; final int lt1= LT(1); switch (lt1) { case IToken.tLPAREN: op = OverloadableOperator.PAREN; // operator () consume(); endOffset = consume(IToken.tRPAREN).getEndOffset(); break; case IToken.tLBRACKET: op = OverloadableOperator.BRACKET; // operator [] consume(); endOffset = consume(IToken.tRBRACKET).getEndOffset(); break; case IToken.t_new: case IToken.t_delete: if (LT(2) == IToken.tLBRACKET) { op= lt1 == IToken.t_new ? OverloadableOperator.NEW_ARRAY : OverloadableOperator.DELETE_ARRAY; consume(); consume(); endOffset= consume(IToken.tRBRACKET).getEndOffset(); } else { IToken t= consume(); endOffset= t.getEndOffset(); op= OverloadableOperator.valueOf(t); } break; case IToken.tGT_in_SHIFTR: consume(); endOffset= consume(IToken.tGT_in_SHIFTR).getEndOffset(); op= OverloadableOperator.SHIFTR; break; default: op= OverloadableOperator.valueOf(LA(1)); if (op != null) { endOffset= consume().getEndOffset(); } break; } if (op != null) { IASTName name= nodeFactory.newOperatorName(op.toCharArray()); setRange(name, firstToken.getOffset(), endOffset); return name; } // must be a conversion function typeId= typeId(DeclarationOptions.TYPEID_CONVERSION); IASTName name = nodeFactory.newConversionName(typeId); setRange(name, firstToken.getOffset(), calculateEndOffset(typeId)); return name; } /** * Information for the parser, whether a binary expression is parsed in the context of a * template-id an ambiguous template-id (one where the '<' could be a greater sign) or * else where. */ private enum BinaryExprCtx {eInTemplateID, eNotInTemplateID} @Override protected IASTExpression expression() throws BacktrackException, EndOfFileException { return expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null); } @Override protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null); } private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { final boolean allowComma= kind==ExprKind.eExpression; boolean allowAssignment= kind !=ExprKind.eConstant; if (allowAssignment && LT(1) == IToken.t_throw) { return throwExpression(); } final boolean handleVariants= strat == null; if (handleVariants) { strat= new TemplateIdStrategy(); } final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset(); int lt1; int conditionCount= 0; BinaryOperator lastOperator= null; NameOrTemplateIDVariants variants= null; if (expr == null) { Object e = castExpressionForBinaryExpression(handleVariants, strat); if (e instanceof IASTExpression) { expr= (IASTExpression) e; } else { variants= new NameOrTemplateIDVariants(); final Variant variant = (Variant) e; expr= variant.getExpression(); variants.addBranchPoint(variant.getNext(), lastOperator, allowAssignment, conditionCount); } } boolean doneExpression= false; do { // Typically after a binary operator there cannot be a throw expression boolean allowThrow= false; // Brace initializers are allowed on the right hand side of an expression boolean allowBraceInitializer= false; BacktrackException tryRecovery= null; final int operatorOffset= LA().getOffset(); lt1= LT(1); switch (lt1) { case IToken.tQUESTION: conditionCount++; // <logical-or> ? <expression> : <assignment-expression> // Precedence: 25 is lower than precedence of logical or; 0 is lower than precedence of expression lastOperator= new BinaryOperator(lastOperator, expr, lt1, 25, 0); allowAssignment= true; // assignment expressions will be subsumed by the conditional expression allowThrow= true; break; case IToken.tCOLON: if (--conditionCount < 0) { doneExpression= true; } else { // <logical-or> ? <expression> : <assignment-expression> // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; lastOperator= new BinaryOperator(lastOperator, expr, lt1, 0, 15); allowAssignment= true; // assignment expressions will be subsumed by the conditional expression allowThrow= true; } break; case IToken.tCOMMA: allowThrow= true; if (!allowComma && conditionCount == 0) { doneExpression= true; } else { // Lowest precedence except inside the conditional expression lastOperator= new BinaryOperator(lastOperator, expr, lt1, 10, 11); } break; case IToken.tASSIGN: case IToken.tSTARASSIGN: case IToken.tDIVASSIGN: case IToken.tMODASSIGN: case IToken.tPLUSASSIGN: case IToken.tMINUSASSIGN: case IToken.tSHIFTRASSIGN: case IToken.tSHIFTLASSIGN: case IToken.tAMPERASSIGN: case IToken.tXORASSIGN: case IToken.tBITORASSIGN: if (!allowAssignment && conditionCount == 0) { doneExpression= true; } else { // Assignments group right to left lastOperator= new BinaryOperator(lastOperator, expr, lt1, 21, 20); allowBraceInitializer= true; } break; case IToken.tOR: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 30, 31); break; case IToken.tAND: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 40, 41); break; case IToken.tBITOR: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 50, 51); break; case IToken.tXOR: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 60, 61); break; case IToken.tAMPER: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 70, 71); break; case IToken.tEQUAL: case IToken.tNOTEQUAL: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 80, 81); break; case IToken.tGT: if (ctx == BinaryExprCtx.eInTemplateID) { doneExpression= true; break; } //$FALL-THROUGH$ case IToken.tLT: case IToken.tLTEQUAL: case IToken.tGTEQUAL: case IGCCToken.tMAX: case IGCCToken.tMIN: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 90, 91); break; case IToken.tGT_in_SHIFTR: if (ctx == BinaryExprCtx.eInTemplateID) { doneExpression= true; break; } if (LT(2) != IToken.tGT_in_SHIFTR) { IToken token = LA(1); backtrack.initialize(token.getOffset(), token.getLength()); tryRecovery= backtrack; break; } lt1= IToken.tSHIFTR; // convert back consume(); // consume the extra token //$FALL-THROUGH$ case IToken.tSHIFTL: case IToken.tSHIFTR: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 100, 101); break; case IToken.tPLUS: case IToken.tMINUS: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 110, 111); break; case IToken.tSTAR: case IToken.tDIV: case IToken.tMOD: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 120, 121); break; case IToken.tDOTSTAR: case IToken.tARROWSTAR: lastOperator= new BinaryOperator(lastOperator, expr, lt1, 130, 131); break; default: doneExpression= true; break; } if (!doneExpression && tryRecovery == null) { consume(); // consumes the operator // Link variants that are closed by the new operator if (variants != null) { variants.closeVariants(operatorOffset, lastOperator); } // Determine next sub-expression if (lt1 == IToken.tQUESTION && LT(1) == IToken.tCOLON) { // Missing sub-expression after '?' (gnu-extension) expr= null; } else if (allowThrow && LT(1) == IToken.t_throw) { // Throw expression expr= throwExpression(); lt1= LT(1); if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA) break; } else if (allowBraceInitializer && LT(1) == IToken.tLBRACE) { // Brace initializer expr= bracedInitList(true); lt1= LT(1); if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA) break; } else { // Cast expression IToken m= mark(); try { Object e = castExpressionForBinaryExpression(handleVariants, strat); if (e instanceof IASTExpression) { expr= (IASTExpression) e; } else { final Variant ae = (Variant) e; expr= ae.getExpression(); if (variants == null) variants= new NameOrTemplateIDVariants(); variants.addBranchPoint(ae.getNext(), lastOperator, allowAssignment, conditionCount); } } catch (BacktrackException e) { if (variants == null) throw e; tryRecovery= e; backup(m); } } } if (tryRecovery != null || doneExpression) { if (variants != null) { if (lt1 == IToken.tEOC) { variants.discardOpenVariants(operatorOffset); } else { // Try fall-back to an open variant Variant fallback= variants.findFallback(operatorOffset); if (fallback == null) { if (tryRecovery != null) throw tryRecovery; variants.discardOpenVariants(operatorOffset); } else { // Restore state and continue doneExpression= false; BranchPoint varPoint= fallback.getOwner(); allowAssignment= varPoint.isAllowAssignment(); conditionCount= varPoint.getConditionCount(); lastOperator= varPoint.getLeftOperator(); expr= fallback.getExpression(); variants.useFallback(fallback); // Advance to the right token int offset= fallback.getRightOffset(); while (LA().getOffset() < offset) { consume(); } } } } } } while (!doneExpression); // Check for incomplete conditional expression if (lt1 != IToken.tEOC && conditionCount > 0) throwBacktrack(LA(1)); if (variants != null && !variants.isEmpty()) { CPPASTTemplateIDAmbiguity result = new CPPASTTemplateIDAmbiguity(this, lastOperator, expr, variants.getOrderedBranchPoints()); setRange(result, startOffset, calculateEndOffset(expr)); return result; } return buildExpression(lastOperator, expr); } public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat) throws EndOfFileException, BacktrackException { if (!handleVariants) return castExpression(CastExprCtx.eDirectlyInBExpr, strat); Variant variants= null; IASTExpression singleExpression= null; IASTName[] firstNames= null; final IToken mark= mark(); IToken lastToken= null; strat.reset(); for(;;) { try { IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat); if (variants == null) { if (singleExpression == null || lastToken == null) { singleExpression= e; firstNames= strat.getTemplateNames(); } else { variants= new Variant(null, singleExpression, firstNames, lastToken.getOffset()); singleExpression= null; firstNames= null; } } lastToken= LA(); if (variants != null) { variants = new Variant(variants, e, strat.getTemplateNames(), lastToken.getOffset()); } if (!strat.setNextAlternative()) { break; } } catch (BacktrackException e) { if (!strat.setNextAlternative()) { if (lastToken == null) throw e; backup(lastToken); break; } } backup(mark); } return variants != null ? variants : singleExpression; } @Override protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr1, IASTInitializerClause expr2, int lastOffset) { IASTBinaryExpression result = nodeFactory.newBinaryExpression(operator, expr1, expr2); int o = ((ASTNode) expr1).getOffset(); ((ASTNode) result).setOffsetAndLength(o, lastOffset - o); return result; } private IASTExpression throwExpression() throws EndOfFileException, BacktrackException { IToken throwToken = consume(); IASTExpression throwExpression = null; try { throwExpression = expression(); } catch (BacktrackException bte) { backup(throwToken); consume(); } int o = throwExpression != null ? calculateEndOffset(throwExpression) : throwToken.getEndOffset(); return buildUnaryExpression(ICPPASTUnaryExpression.op_throw, throwExpression, throwToken.getOffset(), o); // fix for 95225 } protected IASTExpression deleteExpression() throws EndOfFileException, BacktrackException { int startingOffset = LA(1).getOffset(); boolean global = false; if (LT(1) == IToken.tCOLONCOLON) { // global scope consume(); global = true; } consume(IToken.t_delete); boolean vectored = false; if (LT(1) == IToken.tLBRACKET) { // array delete consume(); consume(IToken.tRBRACKET); vectored = true; } IASTExpression castExpression = castExpression(CastExprCtx.eNotInBExpr, null); ICPPASTDeleteExpression deleteExpression = nodeFactory.newDeleteExpression(castExpression); ((ASTNode) deleteExpression).setOffsetAndLength(startingOffset, calculateEndOffset(castExpression) - startingOffset); deleteExpression.setIsGlobal(global); deleteExpression.setIsVectored(vectored); return deleteExpression; } /** * Parse a new-expression. There is room for ambiguities. With P for placement, T for typeid, * and I for initializer the potential patterns (with the new omitted) are: * easy: T, T(I) * medium: (P) T(I), (P) (T)(I) * hard: (T), (P) T, (P) (T), (T)(I) */ protected IASTExpression newExpression() throws BacktrackException, EndOfFileException { IToken la = LA(1); int offset= la.getOffset(); final boolean isGlobal = la.getType() == IToken.tCOLONCOLON; if (isGlobal) { consume(); } consume(IToken.t_new); if (LT(1) == IToken.tLPAREN) { consume(); // consider placement first (P) ... List<IASTInitializerClause> plcmt= null; IASTTypeId typeid= null; boolean isNewTypeId= true; IASTInitializer init= null; int endOffset= 0; IToken mark= mark(); IToken end= null; try { plcmt= expressionList(); endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); final int lt1= LT(1); if (lt1 == IToken.tEOC) { return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset); } if (lt1 == IToken.tLPAREN) { // (P)(T) ... isNewTypeId= false; consume(IToken.tLPAREN); typeid= typeId(DeclarationOptions.TYPEID); endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); } else { // (P) T ... typeid= typeId(DeclarationOptions.TYPEID_NEW); endOffset= calculateEndOffset(typeid); } end= LA(1); } catch (BacktrackException e) { plcmt= null; typeid= null; } if (typeid != null && plcmt != null) { // (P)(T)(I) or (P) T (I) int lt1= LT(1); if (lt1 == IToken.tEOC) return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset); if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) { init= bracedOrCtorStyleInitializer(); endOffset= calculateEndOffset(init); return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset); } } // (T) ... backup(mark); IASTTypeId typeid2= null; IASTInitializer init2= null; int endOffset2; try { typeid2= typeId(DeclarationOptions.TYPEID); endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset(); final int lt1= LT(1); if (lt1 == IToken.tEOC) return newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2); if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) { if (plcmt != null && ASTQueries.findTypeRelevantDeclarator(typeid2.getAbstractDeclarator()) instanceof IASTArrayDeclarator) { throwBacktrack(LA(1)); } // (T)(I) init2= bracedOrCtorStyleInitializer(); endOffset2= calculateEndOffset(init2); } } catch (BacktrackException e) { if (plcmt == null) throw e; endOffset2= -1; } if (plcmt == null || endOffset2 > endOffset) return newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2); if (endOffset != endOffset2) { backup(end); return newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset); } // ambiguity: IASTExpression ex1= newExpression(isGlobal, plcmt, typeid, isNewTypeId, init, offset, endOffset); IASTExpression ex2= newExpression(isGlobal, null, typeid2, false, init2, offset, endOffset2); IASTAmbiguousExpression ambiguity= createAmbiguousExpression(); ambiguity.addExpression(ex1); ambiguity.addExpression(ex2); ((ASTNode) ambiguity).setOffsetAndLength((ASTNode) ex1); return ambiguity; } // T ... final IASTTypeId typeid = typeId(DeclarationOptions.TYPEID_NEW); int endOffset = calculateEndOffset(typeid); IASTInitializer init= null; final int lt1= LT(1); if (lt1 == IToken.tLPAREN || lt1 == IToken.tLBRACE) { // T(I) init= bracedOrCtorStyleInitializer(); endOffset= calculateEndOffset(init); } return newExpression(isGlobal, null, typeid, true, init, offset, endOffset); } private IASTExpression newExpression(boolean isGlobal, List<IASTInitializerClause> plcmt, IASTTypeId typeid, boolean isNewTypeId, IASTInitializer init, int offset, int endOffset) { IASTInitializerClause[] plcmtArray= null; if (plcmt != null && !plcmt.isEmpty()) { plcmtArray= plcmt.toArray(new IASTInitializerClause[plcmt.size()]); } ICPPASTNewExpression result = nodeFactory.newNewExpression(plcmtArray, init, typeid); result.setIsGlobal(isGlobal); result.setIsNewTypeId(isNewTypeId); ((ASTNode) result).setOffsetAndLength(offset, endOffset - offset); return result; } @Override protected IASTExpression unaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.tSTAR: return unaryExpression(IASTUnaryExpression.op_star, ctx, strat); case IToken.tAMPER: return unaryExpression(IASTUnaryExpression.op_amper, ctx, strat); case IToken.tPLUS: return unaryExpression(IASTUnaryExpression.op_plus, ctx, strat); case IToken.tMINUS: return unaryExpression(IASTUnaryExpression.op_minus, ctx, strat); case IToken.tNOT: return unaryExpression(IASTUnaryExpression.op_not, ctx, strat); case IToken.tBITCOMPLEMENT: return unaryExpression(IASTUnaryExpression.op_tilde, ctx, strat); case IToken.tINCR: return unaryExpression(IASTUnaryExpression.op_prefixIncr, ctx, strat); case IToken.tDECR: return unaryExpression(IASTUnaryExpression.op_prefixDecr, ctx, strat); case IToken.t_new: return newExpression(); case IToken.t_delete: return deleteExpression(); case IToken.tCOLONCOLON: switch (LT(2)) { case IToken.t_new: return newExpression(); case IToken.t_delete: return deleteExpression(); default: return postfixExpression(ctx, strat); } case IToken.t_sizeof: if (LTcatchEOF(2) == IToken.tELLIPSIS) { int offset= consume().getOffset(); // sizeof consume(); // ... consume(IToken.tLPAREN); // ( IASTName id= identifier(); IASTIdExpression idexpr= nodeFactory.newIdExpression(id); setRange(idexpr, id); IASTUnaryExpression expr= nodeFactory.newUnaryExpression(IASTUnaryExpression.op_sizeofParameterPack, idexpr); final int lt1= LT(1); if (lt1 == IToken.tEOC) { setRange(expr, offset, calculateEndOffset(id)); } else { final int endOffset = consume(IToken.tRPAREN).getEndOffset(); // ) setRange(expr, offset, endOffset); } return expr; } return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, ctx, strat); case IGCCToken.t___alignof__: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, ctx, strat); case IGCCToken.tTT_has_nothrow_assign: case IGCCToken.tTT_has_nothrow_constructor: case IGCCToken.tTT_has_nothrow_copy: case IGCCToken.tTT_has_trivial_assign: case IGCCToken.tTT_has_trivial_constructor: case IGCCToken.tTT_has_trivial_copy: case IGCCToken.tTT_has_trivial_destructor: case IGCCToken.tTT_has_virtual_destructor: case IGCCToken.tTT_is_abstract: case IGCCToken.tTT_is_base_of: case IGCCToken.tTT_is_class: case IGCCToken.tTT_is_empty: case IGCCToken.tTT_is_enum: case IGCCToken.tTT_is_pod: case IGCCToken.tTT_is_polymorphic: case IGCCToken.tTT_is_union: return parseTypeTrait(); default: return postfixExpression(ctx, strat); } } private IASTExpression parseTypeTrait() throws EndOfFileException, BacktrackException { IToken first= consume(); final boolean isBinary= isBinaryTrait(first); consume(IToken.tLPAREN); IASTTypeId typeId= typeId(DeclarationOptions.TYPEID); IASTTypeId secondTypeId= null; if (isBinary) { consumeOrEOC(IToken.tCOMMA); if (LT(1) != IToken.tEOC) { secondTypeId= typeId(DeclarationOptions.TYPEID); } } int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); IASTExpression result; if (isBinary) { result= nodeFactory.newBinaryTypeIdExpression(getBinaryTypeTraitOperator(first), typeId, secondTypeId); } else { result= nodeFactory.newTypeIdExpression(getUnaryTypeTraitOperator(first), typeId); } return setRange(result, first.getOffset(), endOffset); } private boolean isBinaryTrait(IToken first) { switch(first.getType()) { case IGCCToken.tTT_is_base_of: return true; } return false; } private Operator getBinaryTypeTraitOperator(IToken first) { switch(first.getType()) { case IGCCToken.tTT_is_base_of: return IASTBinaryTypeIdExpression.Operator.__is_base_of; } assert false; return null; } private int getUnaryTypeTraitOperator(IToken first) { switch(first.getType()) { case IGCCToken.tTT_has_nothrow_assign: return IASTTypeIdExpression.op_has_nothrow_assign; case IGCCToken.tTT_has_nothrow_constructor: return IASTTypeIdExpression.op_has_nothrow_constructor; case IGCCToken.tTT_has_nothrow_copy: return IASTTypeIdExpression.op_has_nothrow_copy; case IGCCToken.tTT_has_trivial_assign: return IASTTypeIdExpression.op_has_trivial_assign; case IGCCToken.tTT_has_trivial_constructor: return IASTTypeIdExpression.op_has_trivial_constructor; case IGCCToken.tTT_has_trivial_copy: return IASTTypeIdExpression.op_has_trivial_copy; case IGCCToken.tTT_has_trivial_destructor: return IASTTypeIdExpression.op_has_trivial_destructor; case IGCCToken.tTT_has_virtual_destructor: return IASTTypeIdExpression.op_has_virtual_destructor; case IGCCToken.tTT_is_abstract: return IASTTypeIdExpression.op_is_abstract; case IGCCToken.tTT_is_class: return IASTTypeIdExpression.op_is_class; case IGCCToken.tTT_is_empty: return IASTTypeIdExpression.op_is_abstract; case IGCCToken.tTT_is_enum: return IASTTypeIdExpression.op_is_abstract; case IGCCToken.tTT_is_pod: return IASTTypeIdExpression.op_is_abstract; case IGCCToken.tTT_is_polymorphic: return IASTTypeIdExpression.op_is_abstract; case IGCCToken.tTT_is_union: return IASTTypeIdExpression.op_is_abstract; } assert false; return 0; } /** * postfix-expression: * [gnu-extension, compound literals in c++] * ( type-name ) { initializer-list } * ( type-name ) { initializer-list , } * * primary-expression * postfix-expression [ expression ] * postfix-expression [ braced-init-list ] * postfix-expression ( expression-list_opt ) * simple-type-specifier ( expression-list_opt ) * simple-type-specifier braced-init-list * typename-specifier ( expression-list_opt ) * typename-specifier braced-init-list * postfix-expression . templateopt id-expression * postfix-expression -> templateopt id-expression * postfix-expression . pseudo-destructor-name * postfix-expression -> pseudo-destructor-name * postfix-expression ++ * postfix-expression -- * dynamic_cast < type-id > ( expression ) * static_cast < type-id > ( expression ) * reinterpret_cast < type-id > ( expression ) * const_cast < type-id > ( expression ) * typeid ( expression ) * typeid ( type-id ) */ private IASTExpression postfixExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { IASTExpression firstExpression = null; boolean isTemplate = false; switch (LT(1)) { case IToken.t_dynamic_cast: firstExpression = specialCastExpression(ICPPASTCastExpression.op_dynamic_cast); break; case IToken.t_static_cast: firstExpression = specialCastExpression(ICPPASTCastExpression.op_static_cast); break; case IToken.t_reinterpret_cast: firstExpression = specialCastExpression(ICPPASTCastExpression.op_reinterpret_cast); break; case IToken.t_const_cast: firstExpression = specialCastExpression(ICPPASTCastExpression.op_const_cast); break; case IToken.t_typeid: // 'typeid' ( expression ) // 'typeid' ( type-id ) int so = consume().getOffset(); firstExpression = parseTypeidInParenthesisOrUnaryExpression(true, so, ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid, ctx, strat); break; case IToken.tLPAREN: // Gnu-extension: compound literals in c++ // ( type-name ) { initializer-list } // ( type-name ) { initializer-list , } IToken m = mark(); try { int offset = consume().getOffset(); IASTTypeId t= typeId(DeclarationOptions.TYPEID); consume(IToken.tRPAREN); if (LT(1) == IToken.tLBRACE) { IASTInitializer i = bracedInitList(false); firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); setRange(firstExpression, offset, calculateEndOffset(i)); break; } } catch (BacktrackException bt) { } backup(m); firstExpression= primaryExpression(ctx, strat); break; // typename-specifier ( expression-list_opt ) // typename-specifier braced-init-list // simple-type-specifier ( expression-list_opt ) // simple-type-specifier braced-init-list case IToken.t_typename: case IToken.t_char: case IToken.t_char16_t: case IToken.t_char32_t: case IToken.t_wchar_t: case IToken.t_bool: case IToken.t_short: case IToken.t_int: case IToken.t_long: case IToken.t_signed: case IToken.t_unsigned: case IToken.t_float: case IToken.t_double: case IToken.t_decltype: case IToken.t_void: case IGCCToken.t_typeof: firstExpression = simpleTypeConstructorExpression(simpleTypeSpecifier()); break; default: firstExpression = primaryExpression(ctx, strat); if (firstExpression instanceof IASTIdExpression && LT(1) == IToken.tLBRACE) { IASTName name = ((IASTIdExpression) firstExpression).getName(); ICPPASTDeclSpecifier declSpec= nodeFactory.newTypedefNameSpecifier(name); firstExpression = simpleTypeConstructorExpression(setRange(declSpec, name)); } break; } for (;;) { switch (LT(1)) { case IToken.tLBRACKET: // postfix-expression [ expression ] // postfix-expression [ braced-init-list ] consume(IToken.tLBRACKET); IASTInitializerClause expression; if (LT(1) == IToken.tLBRACE) { expression= bracedInitList(false); } else { expression= expression(); } int endOffset= consumeOrEOC(IToken.tRBRACKET).getEndOffset(); IASTArraySubscriptExpression s = nodeFactory.newArraySubscriptExpression(firstExpression, expression); firstExpression= setRange(s, firstExpression, endOffset); break; case IToken.tLPAREN: // postfix-expression ( expression-list_opt ) // simple-type-specifier ( expression-list_opt ) // cannot be distinguished consume(IToken.tLPAREN); IASTInitializerClause[] initArray; if (LT(1) == IToken.tRPAREN) { initArray= IASTExpression.EMPTY_EXPRESSION_ARRAY; } else { final List<IASTInitializerClause> exprList = expressionList(); initArray = exprList.toArray(new IASTInitializerClause[exprList.size()]); } endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset(); IASTFunctionCallExpression fce = nodeFactory.newFunctionCallExpression(firstExpression, initArray); firstExpression= setRange(fce, firstExpression, endOffset); break; case IToken.tINCR: endOffset = consume().getEndOffset(); firstExpression = buildUnaryExpression(IASTUnaryExpression.op_postFixIncr, firstExpression, ((ASTNode) firstExpression).getOffset(), endOffset); break; case IToken.tDECR: endOffset = consume().getEndOffset(); firstExpression = buildUnaryExpression(IASTUnaryExpression.op_postFixDecr, firstExpression, ((ASTNode) firstExpression).getOffset(), endOffset); break; case IToken.tDOT: // member access IToken dot = consume(); if (LT(1) == IToken.t_template) { consume(); isTemplate = true; } IASTName name = qualifiedName(strat, ctx); if (name == null) throwBacktrack(((ASTNode) firstExpression).getOffset(), ((ASTNode) firstExpression).getLength() + dot.getLength()); ICPPASTFieldReference fieldReference = nodeFactory.newFieldReference(name, firstExpression); fieldReference.setIsPointerDereference(false); fieldReference.setIsTemplate(isTemplate); ((ASTNode) fieldReference).setOffsetAndLength( ((ASTNode) firstExpression).getOffset(), calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset()); firstExpression = fieldReference; break; case IToken.tARROW: // member access IToken arrow = consume(); if (LT(1) == IToken.t_template) { consume(); isTemplate = true; } name = qualifiedName(strat, ctx); if (name == null) throwBacktrack(((ASTNode) firstExpression).getOffset(), ((ASTNode) firstExpression).getLength() + arrow.getLength()); fieldReference = nodeFactory.newFieldReference(name, firstExpression); fieldReference.setIsPointerDereference(true); fieldReference.setIsTemplate(isTemplate); ((ASTNode) fieldReference).setOffsetAndLength( ((ASTNode) firstExpression).getOffset(), calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset()); firstExpression = fieldReference; break; default: return firstExpression; } } } @Override protected IASTAmbiguousExpression createAmbiguousExpression() { return new CPPASTAmbiguousExpression(); } @Override protected IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr) { return new CPPASTAmbiguousBinaryVsCastExpression(binary, castExpr); } @Override protected IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall) { return new CPPASTAmbiguousCastVsFunctionCallExpression(castExpr, funcCall); } protected ICPPASTAmbiguousTemplateArgument createAmbiguousTemplateArgument() { return new CPPASTAmbiguousTemplateArgument(); } private IASTExpression simpleTypeConstructorExpression(ICPPASTDeclSpecifier declSpec) throws EndOfFileException, BacktrackException { IASTInitializer initializer = bracedOrCtorStyleInitializer(); ICPPASTSimpleTypeConstructorExpression result = nodeFactory.newSimpleTypeConstructorExpression( declSpec, initializer); return setRange(result, declSpec, calculateEndOffset(initializer)); } @Override protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { IToken t = null; IASTLiteralExpression literalExpression = null; switch (LT(1)) { // TO DO: we need more literals... case IToken.tINTEGER: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_integer_constant, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset()- t.getOffset()); return literalExpression; case IToken.tFLOATINGPT: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_float_constant, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); return literalExpression; case IToken.tSTRING: case IToken.tLSTRING: case IToken.tUTF16STRING: case IToken.tUTF32STRING: return stringLiteral(); case IToken.tCHAR: case IToken.tLCHAR: case IToken.tUTF16CHAR: case IToken.tUTF32CHAR: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_char_constant, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); return literalExpression; case IToken.t_false: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_false, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); return literalExpression; case IToken.t_true: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_true, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); return literalExpression; case IToken.t_this: t = consume(); literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_this, t.getImage()); ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); return literalExpression; case IToken.tLPAREN: if (supportStatementsInExpressions && LT(2) == IToken.tLBRACE) { return compoundStatementExpression(); } t = consume(); int finalOffset= 0; IASTExpression lhs= expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null); // instead of expression(), to keep the stack smaller switch (LT(1)) { case IToken.tRPAREN: case IToken.tEOC: finalOffset = consume().getEndOffset(); break; default: throwBacktrack(LA(1)); } return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset); case IToken.tIDENTIFIER: case IToken.tCOLONCOLON: case IToken.t_operator: case IToken.tCOMPLETION: case IToken.tBITCOMPLEMENT: { IASTName name = qualifiedName(strat, ctx); IASTIdExpression idExpression = nodeFactory.newIdExpression(name); ((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset() + ((ASTNode) name).getLength() - ((ASTNode) name).getOffset()); return idExpression; } case IToken.tLBRACKET: return lambdaExpression(); default: IToken la = LA(1); int startingOffset = la.getOffset(); throwBacktrack(startingOffset, la.getLength()); return null; } } private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.tSTRING: case IToken.tLSTRING: case IToken.tUTF16STRING: case IToken.tUTF32STRING: break; default: throwBacktrack(LA(1)); } IToken t= consume(); ICPPASTLiteralExpression r= nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_string_literal, t.getImage()); return setRange(r, t.getOffset(), t.getEndOffset()); } private IASTExpression lambdaExpression() throws EndOfFileException, BacktrackException { final int offset= LA().getOffset(); ICPPASTLambdaExpression lambdaExpr= nodeFactory.newLambdaExpression(); // Lambda introducer consume(IToken.tLBRACKET); boolean needComma= false; switch(LT(1)) { case IToken.tASSIGN: lambdaExpr.setCaptureDefault(CaptureDefault.BY_COPY); consume(); needComma= true; break; case IToken.tAMPER: final int lt2 = LT(2); if (lt2 == IToken.tCOMMA || lt2 == IToken.tRBRACKET) { lambdaExpr.setCaptureDefault(CaptureDefault.BY_REFERENCE); consume(); needComma= true; } break; } loop: for(;;) { switch (LT(1)) { case IToken.tEOC: return setRange(lambdaExpr, offset, LA().getEndOffset()); case IToken.tRBRACKET: consume(); break loop; } if (needComma) { consume(IToken.tCOMMA); } ICPPASTCapture cap= capture(); lambdaExpr.addCapture(cap); needComma= true; } if (LT(1) == IToken.tLPAREN) { ICPPASTFunctionDeclarator dtor = functionDeclarator(true); lambdaExpr.setDeclarator(dtor); if (LT(1) == IToken.tEOC) return setRange(lambdaExpr, offset, calculateEndOffset(dtor)); } IASTCompoundStatement body = functionBody(); lambdaExpr.setBody(body); return setRange(lambdaExpr, offset, calculateEndOffset(body)); } private ICPPASTCapture capture() throws EndOfFileException, BacktrackException { final int offset= LA().getOffset(); final ICPPASTCapture result = nodeFactory.newCapture(); switch (LT(1)) { case IToken.t_this: return setRange(result, offset, consume().getEndOffset()); case IToken.tAMPER: consume(); result.setIsByReference(true); break; } final IASTName identifier= identifier(); result.setIdentifier(identifier); if (LT(1) == IToken.tELLIPSIS) { result.setIsPackExpansion(true); return setRange(result, offset, consume().getEndOffset()); } return setRange(result, offset, calculateEndOffset(identifier)); } protected IASTExpression specialCastExpression(int kind) throws EndOfFileException, BacktrackException { final int offset = LA(1).getOffset(); final int optype= consume().getType(); consume(IToken.tLT); final IASTTypeId typeID = typeId(DeclarationOptions.TYPEID); consumeOrEOC(IToken.tGT); consumeOrEOC(IToken.tLPAREN); IASTExpression operand= null; if (LT(1) != IToken.tEOC) { operand= expression(); } final int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); int operator; switch (optype) { case IToken.t_dynamic_cast: operator = ICPPASTCastExpression.op_dynamic_cast; break; case IToken.t_static_cast: operator = ICPPASTCastExpression.op_static_cast; break; case IToken.t_reinterpret_cast: operator = ICPPASTCastExpression.op_reinterpret_cast; break; case IToken.t_const_cast: operator = ICPPASTCastExpression.op_const_cast; break; default: operator = IASTCastExpression.op_cast; break; } return buildCastExpression(operator, typeID, operand, offset, endOffset); } /** * The merger of using-declaration and using-directive in ANSI C++ grammar. * using-declaration: using typename? ::? nested-name-specifier * unqualified-id ; using :: unqualified-id ; using-directive: using * namespace ::? nested-name-specifier? namespace-name ; * * @throws BacktrackException * request for a backtrack */ protected IASTDeclaration usingClause() throws EndOfFileException, BacktrackException { final int offset= consume().getOffset(); if (LT(1) == IToken.t_namespace) { // using-directive int endOffset = consume().getEndOffset(); IASTName name = null; switch (LT(1)) { case IToken.tIDENTIFIER: case IToken.tCOLONCOLON: case IToken.tCOMPLETION: name = qualifiedName(); break; default: throwBacktrack(offset, endOffset - offset); } __attribute__(); switch (LT(1)) { case IToken.tSEMI: case IToken.tEOC: endOffset = consume().getEndOffset(); break; default: throw backtrack; } ICPPASTUsingDirective astUD = nodeFactory.newUsingDirective(name); ((ASTNode) astUD).setOffsetAndLength(offset, endOffset - offset); return astUD; } ICPPASTUsingDeclaration result = usingDeclaration(offset); return result; } private ICPPASTUsingDeclaration usingDeclaration(final int offset) throws EndOfFileException, BacktrackException { boolean typeName = false; if (LT(1) == IToken.t_typename) { typeName = true; consume(); } IASTName name = qualifiedName(); int end; switch (LT(1)) { case IToken.tSEMI: case IToken.tEOC: end = consume().getEndOffset(); break; default: throw backtrack; } ICPPASTUsingDeclaration result = nodeFactory.newUsingDeclaration(name); ((ASTNode) result).setOffsetAndLength(offset, end - offset); result.setIsTypename(typeName); return result; } /** * static_assert-declaration: static_assert ( constant-expression , string-literal ) ; */ private ICPPASTStaticAssertDeclaration staticAssertDeclaration() throws EndOfFileException, BacktrackException { int offset= consume(IToken.t_static_assert).getOffset(); consume(IToken.tLPAREN); IASTExpression e= constantExpression(); int endOffset= calculateEndOffset(e); ICPPASTLiteralExpression lit= null; if (LT(1) != IToken.tEOC) { consume(IToken.tCOMMA); lit= stringLiteral(); consume(IToken.tRPAREN); endOffset= consume(IToken.tSEMI).getEndOffset(); } ICPPASTStaticAssertDeclaration assertion = nodeFactory.newStaticAssertion(e, lit); return setRange(assertion, offset, endOffset); } /** * Implements Linkage specification in the ANSI C++ grammar. * linkageSpecification : extern "string literal" declaration | extern * "string literal" { declaration-seq } * * @throws BacktrackException * request for a backtrack */ protected ICPPASTLinkageSpecification linkageSpecification() throws EndOfFileException, BacktrackException { int offset= consume().getOffset(); // t_extern String spec = consume().getImage(); // tString ICPPASTLinkageSpecification linkage = nodeFactory.newLinkageSpecification(spec); if (LT(1) == IToken.tLBRACE) { declarationListInBraces(linkage, offset, DeclarationOptions.GLOBAL); return linkage; } // single declaration IASTDeclaration d = declaration(DeclarationOptions.GLOBAL); linkage.addDeclaration(d); setRange(linkage, offset, calculateEndOffset(d)); return linkage; } /** * Represents the amalgamation of template declarations, template * instantiations and specializations in the ANSI C++ grammar. * template-declaration: export? template < template-parameter-list > * declaration explicit-instantiation: template declaration * explicit-specialization: template <>declaration * @param option * * @throws BacktrackException * request for a backtrack */ protected IASTDeclaration templateDeclaration(DeclarationOptions option) throws EndOfFileException, BacktrackException { final int offset= LA(1).getOffset(); boolean exported = false; int explicitInstMod= 0; switch (LT(1)) { case IToken.t_export: exported = true; consume(); break; case IToken.t_extern: consume(); explicitInstMod= ICPPASTExplicitTemplateInstantiation.EXTERN; break; case IToken.t_static: consume(); explicitInstMod= ICPPASTExplicitTemplateInstantiation.STATIC; break; case IToken.t_inline: consume(); explicitInstMod= ICPPASTExplicitTemplateInstantiation.INLINE; break; } consume(IToken.t_template); if (LT(1) != IToken.tLT) { // explicit-instantiation IASTDeclaration d = declaration(option); ICPPASTExplicitTemplateInstantiation ti= nodeFactory.newExplicitTemplateInstantiation(d); ti.setModifier(explicitInstMod); setRange(ti, offset, calculateEndOffset(d)); return ti; } // Modifiers for explicit instantiations if (explicitInstMod != 0) { throwBacktrack(LA(1)); } consume(IToken.tLT); if (LT(1) == IToken.tGT) { // explicit-specialization consume(); IASTDeclaration d = declaration(option); ICPPASTTemplateSpecialization templateSpecialization = nodeFactory.newTemplateSpecialization(d); setRange(templateSpecialization, offset, calculateEndOffset(d)); return templateSpecialization; } List<ICPPASTTemplateParameter> parms= outerTemplateParameterList(); consume(IToken.tGT, IToken.tGT_in_SHIFTR); IASTDeclaration d = declaration(option); ICPPASTTemplateDeclaration templateDecl = nodeFactory.newTemplateDeclaration(d); setRange(templateDecl, offset, calculateEndOffset(d)); templateDecl.setExported(exported); for (int i = 0; i < parms.size(); ++i) { ICPPASTTemplateParameter parm = parms.get(i); templateDecl.addTemplateParameter(parm); } return templateDecl; } /** * template-parameter-list: template-parameter template-parameter-list , * template-parameter template-parameter: type-parameter * parameter-declaration type-parameter: class identifier? class identifier? = * type-id typename identifier? typename identifier? = type-id template < * template-parameter-list > class identifier? template < * template-parameter-list > class identifier? = id-expression template-id: * template-name < template-argument-list?> template-name: identifier * template-argument-list: template-argument template-argument-list , * template-argument template-argument: assignment-expression type-id * id-expression * * @throws BacktrackException * request for a backtrack */ protected List<ICPPASTTemplateParameter> outerTemplateParameterList() throws BacktrackException, EndOfFileException { fTemplateParameterListStrategy= new TemplateIdStrategy(); try { List<ICPPASTTemplateParameter> result = new ArrayList<ICPPASTTemplateParameter>(DEFAULT_PARM_LIST_SIZE); IToken m= mark(); for(;;) { try { return templateParameterList(result); } catch (BacktrackException e) { if (!fTemplateParameterListStrategy.setNextAlternative()) { fTemplateParameterListStrategy= null; throw e; } result.clear(); backup(m); } } } finally { fTemplateParameterListStrategy= null; } } private List<ICPPASTTemplateParameter> templateParameterList(List<ICPPASTTemplateParameter> result) throws EndOfFileException, BacktrackException { boolean needComma= false; for (;;) { final int lt1= LT(1); if (lt1 == IToken.tGT || lt1 == IToken.tEOC || lt1 == IToken.tGT_in_SHIFTR) { return result; } if (needComma) { consume(IToken.tCOMMA); } else { needComma= true; } result.add(templateParameter()); } } private ICPPASTTemplateParameter templateParameter() throws EndOfFileException, BacktrackException { final int lt1= LT(1); final IToken start= mark(); if (lt1 == IToken.t_class || lt1 == IToken.t_typename) { try { int type = (lt1 == IToken.t_class ? ICPPASTSimpleTypeTemplateParameter.st_class : ICPPASTSimpleTypeTemplateParameter.st_typename); boolean parameterPack= false; IASTName identifierName = null; IASTTypeId defaultValue = null; int endOffset = consume().getEndOffset(); if (LT(1) == IToken.tELLIPSIS) { parameterPack= true; endOffset= consume().getOffset(); } if (LT(1) == IToken.tIDENTIFIER) { // optional identifier identifierName = identifier(); endOffset = calculateEndOffset(identifierName); } else { identifierName = nodeFactory.newName(); } if (LT(1) == IToken.tASSIGN) { // optional = type-id if (parameterPack) throw backtrack; consume(); defaultValue = typeId(DeclarationOptions.TYPEID); // type-id endOffset = calculateEndOffset(defaultValue); } // Check if followed by comma switch (LT(1)) { case IToken.tGT: case IToken.tEOC: case IToken.tGT_in_SHIFTR: case IToken.tCOMMA: ICPPASTSimpleTypeTemplateParameter tpar = nodeFactory.newSimpleTypeTemplateParameter(type, identifierName, defaultValue); tpar.setIsParameterPack(parameterPack); setRange(tpar, start.getOffset(), endOffset); return tpar; } } catch (BacktrackException bt) { } // Can be a non-type template parameter, see bug 333285 backup(start); } else if (lt1 == IToken.t_template) { boolean parameterPack= false; IASTName identifierName = null; IASTExpression defaultValue = null; consume(); consume(IToken.tLT); List<ICPPASTTemplateParameter> tparList = templateParameterList(new ArrayList<ICPPASTTemplateParameter>()); consume(IToken.tGT, IToken.tGT_in_SHIFTR); int endOffset = consume(IToken.t_class).getEndOffset(); if (LT(1) == IToken.tELLIPSIS) { parameterPack= true; endOffset= consume().getOffset(); } if (LT(1) == IToken.tIDENTIFIER) { // optional identifier identifierName = identifier(); endOffset = calculateEndOffset(identifierName); if (LT(1) == IToken.tASSIGN) { // optional = type-id if (parameterPack) throw backtrack; consume(); defaultValue = primaryExpression(CastExprCtx.eNotInBExpr, null); endOffset = calculateEndOffset(defaultValue); } } else { identifierName = nodeFactory.newName(); } ICPPASTTemplatedTypeTemplateParameter tpar = nodeFactory.newTemplatedTypeTemplateParameter(identifierName, defaultValue); tpar.setIsParameterPack(parameterPack); setRange(tpar, start.getOffset(), endOffset); for (int i = 0; i < tparList.size(); ++i) { ICPPASTTemplateParameter p = tparList.get(i); tpar.addTemplateParameter(p); } return tpar; } // Try non-type template parameter return parameterDeclaration(); } /** * The most abstract construct within a translationUnit : a declaration. * declaration : {"asm"} asmDefinition | {"namespace"} namespaceDefinition | * {"using"} usingDeclaration | {"export"|"template"} templateDeclaration | * {"extern"} linkageSpecification | simpleDeclaration Notes: - folded in * blockDeclaration - merged alternatives that required same LA - * functionDefinition into simpleDeclaration - namespaceAliasDefinition into * namespaceDefinition - usingDirective into usingDeclaration - * explicitInstantiation and explicitSpecialization into templateDeclaration * * @throws BacktrackException * request a backtrack */ @Override protected IASTDeclaration declaration(DeclarationOptions option) throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.t_asm: return asmDeclaration(); case IToken.t_namespace: return namespaceDefinitionOrAlias(); case IToken.t_using: return usingClause(); case IToken.t_static_assert: return staticAssertDeclaration(); case IToken.t_export: case IToken.t_template: return templateDeclaration(option); case IToken.t_extern: if (LT(2) == IToken.tSTRING) return linkageSpecification(); if (LT(2) == IToken.t_template) return templateDeclaration(option); break; case IToken.t_static: case IToken.t_inline: if (supportExtendedTemplateSyntax && LT(2) == IToken.t_template) return templateDeclaration(option); if (LT(2) == IToken.t_namespace) { return namespaceDefinitionOrAlias(); } break; case IToken.tSEMI: IToken t= consume(); IASTSimpleDeclSpecifier declspec= nodeFactory.newSimpleDeclSpecifier(); IASTSimpleDeclaration decl= nodeFactory.newSimpleDeclaration(declspec); ((ASTNode) declspec).setOffsetAndLength(t.getOffset(), 0); ((ASTNode) decl).setOffsetAndLength(t.getOffset(), t.getLength()); return decl; case IToken.t_public: case IToken.t_protected: case IToken.t_private: if (option == DeclarationOptions.CPP_MEMBER) { t= consume(); int key= t.getType(); int endOffset= consume(IToken.tCOLON).getEndOffset(); ICPPASTVisibilityLabel label = nodeFactory.newVisibilityLabel(token2Visibility(key)); setRange(label, t.getOffset(), endOffset); return label; } break; } try { return simpleDeclaration(option); } catch (BacktrackException e) { if (option != DeclarationOptions.CPP_MEMBER || declarationMark == null) throw e; BacktrackException orig= new BacktrackException(e); // copy the exception IToken mark= mark(); backup(declarationMark); try { return usingDeclaration(declarationMark.getOffset()); } catch (BacktrackException e2) { backup(mark); throw orig; // throw original exception; } } } /** * Serves as the namespace declaration portion of the ANSI C++ grammar. * namespace-definition: namespace identifier { namespace-body } | namespace { * namespace-body } namespace-body: declaration-seq? * * @throws BacktrackException * request a backtrack */ protected IASTDeclaration namespaceDefinitionOrAlias() throws BacktrackException, EndOfFileException { final int offset= LA().getOffset(); int endOffset; boolean isInline= false; if (LT(1) == IToken.t_inline) { consume(); isInline= true; } consume(IToken.t_namespace); // optional name IASTName name = null; if (LT(1) == IToken.tIDENTIFIER) { name = identifier(); endOffset= calculateEndOffset(name); } else { name = nodeFactory.newName(); } // bug 195701, gcc 4.2 allows visibility attribute for namespaces. __attribute_decl_seq(true, false); if (LT(1) == IToken.tLBRACE) { ICPPASTNamespaceDefinition ns = nodeFactory.newNamespaceDefinition(name); ns.setIsInline(isInline); declarationListInBraces(ns, offset, DeclarationOptions.GLOBAL); return ns; } if (LT(1) == IToken.tASSIGN) { endOffset= consume().getEndOffset(); if (name.toString() == null) { throwBacktrack(offset, endOffset - offset); return null; } IASTName qualifiedName= qualifiedName(); endOffset = consume(IToken.tSEMI).getEndOffset(); ICPPASTNamespaceAlias alias = nodeFactory.newNamespaceAlias(name, qualifiedName); ((ASTNode) alias).setOffsetAndLength(offset, endOffset - offset); return alias; } throwBacktrack(LA(1)); return null; } @Override protected boolean isLegalWithoutDtor(IASTDeclSpecifier declSpec) { if (declSpec instanceof IASTElaboratedTypeSpecifier) { return ((IASTElaboratedTypeSpecifier) declSpec).getKind() != IASTElaboratedTypeSpecifier.k_enum; } return super.isLegalWithoutDtor(declSpec); } /** * Parses a declaration with the given options. */ protected IASTDeclaration simpleDeclaration(DeclarationOptions declOption) throws BacktrackException, EndOfFileException { if (LT(1) == IToken.tLBRACE) throwBacktrack(LA(1)); final int firstOffset= LA(1).getOffset(); int endOffset= firstOffset; boolean insertSemi= false; IASTDeclSpecifier declSpec= null; IASTDeclarator dtor= null; IASTDeclSpecifier altDeclSpec= null; IASTDeclarator altDtor= null; IToken markBeforDtor= null; try { Decl decl= declSpecifierSequence_initDeclarator(declOption, true); markBeforDtor= decl.fDtorToken1; declSpec= decl.fDeclSpec1; dtor= decl.fDtor1; altDeclSpec= decl.fDeclSpec2; altDtor= decl.fDtor2; } catch (FoundAggregateInitializer lie) { declSpec= lie.fDeclSpec; // scalability: don't keep references to tokens, initializer may be large declarationMark= null; dtor= addInitializer(lie, declOption); } catch (BacktrackException e) { IASTNode node= e.getNodeBeforeProblem(); if (node instanceof IASTDeclSpecifier && isLegalWithoutDtor((IASTDeclSpecifier) node)) { IASTSimpleDeclaration d= nodeFactory.newSimpleDeclaration((IASTDeclSpecifier) node); setRange(d, node); throwBacktrack(e.getProblem(), d); } throw e; } IASTDeclarator[] declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY; if (dtor != null) { declarators= new IASTDeclarator[]{dtor}; if (!declOption.fSingleDtor) { while (LTcatchEOF(1) == IToken.tCOMMA) { consume(); try { dtor= initDeclarator(declSpec, declOption); } catch (FoundAggregateInitializer e) { // scalability: don't keep references to tokens, initializer may be large declarationMark= null; markBeforDtor= null; dtor= addInitializer(e, declOption); } declarators = (IASTDeclarator[]) ArrayUtil.append(IASTDeclarator.class, declarators, dtor); } declarators = (IASTDeclarator[]) ArrayUtil.removeNulls(IASTDeclarator.class, declarators); } } final int lt1= LTcatchEOF(1); switch (lt1) { case IToken.tEOC: endOffset= figureEndOffset(declSpec, declarators); break; case IToken.tSEMI: endOffset= consume().getEndOffset(); break; case IToken.tCOLON: if (declOption == DeclarationOptions.RANGE_BASED_FOR) { endOffset= figureEndOffset(declSpec, declarators); break; } //$FALL-THROUGH$ case IToken.t_try: case IToken.tLBRACE: case IToken.tASSIGN: // defaulted or deleted function definition if (declarators.length != 1) throwBacktrack(LA(1)); dtor= declarators[0]; if (altDeclSpec != null && altDtor != null && dtor != null && !(ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator)) { declSpec= altDeclSpec; dtor= altDtor; } return functionDefinition(firstOffset, declSpec, dtor); default: insertSemi= true; if (declOption == DeclarationOptions.LOCAL) { endOffset= figureEndOffset(declSpec, declarators); break; } else { if (isLegalWithoutDtor(declSpec) && markBeforDtor != null && !isOnSameLine(calculateEndOffset(declSpec), markBeforDtor.getOffset())) { backup(markBeforDtor); declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY; endOffset= calculateEndOffset(declSpec); break; } endOffset= figureEndOffset(declSpec, declarators); if (lt1 == 0 || !isOnSameLine(endOffset, LA(1).getOffset())) { break; } if (declarators.length == 1 && declarators[0] instanceof IASTFunctionDeclarator) { break; } } throwBacktrack(LA(1)); } // no function body final boolean isAmbiguous= altDeclSpec != null && altDtor != null && declarators.length == 1; IASTSimpleDeclaration simpleDeclaration; if (isAmbiguous) { // class C { C(T); }; // if T is a type this is a constructor, so // prefer the empty declspec, it shall be used if both variants show no problems simpleDeclaration= nodeFactory.newSimpleDeclaration(altDeclSpec); simpleDeclaration.addDeclarator(altDtor); } else { simpleDeclaration= nodeFactory.newSimpleDeclaration(declSpec); for (IASTDeclarator declarator : declarators) { simpleDeclaration.addDeclarator(declarator); } } setRange(simpleDeclaration, firstOffset, endOffset); if (isAmbiguous) { simpleDeclaration = new CPPASTAmbiguousSimpleDeclaration(simpleDeclaration, declSpec, dtor); setRange(simpleDeclaration, firstOffset, endOffset); } if (insertSemi) { IASTProblem problem= createProblem(IProblem.MISSING_SEMICOLON, endOffset-1, 1); throwBacktrack(problem, simpleDeclaration); } return simpleDeclaration; } private IASTDeclaration functionDefinition(final int firstOffset, IASTDeclSpecifier declSpec, IASTDeclarator outerDtor) throws EndOfFileException, BacktrackException { final IASTDeclarator dtor= ASTQueries.findTypeRelevantDeclarator(outerDtor); if (dtor instanceof ICPPASTFunctionDeclarator == false) throwBacktrack(firstOffset, LA(1).getEndOffset() - firstOffset); ICPPASTFunctionDefinition fdef; if (LT(1) == IToken.t_try) { consume(); fdef= nodeFactory.newFunctionTryBlock(declSpec, (ICPPASTFunctionDeclarator) dtor, null); } else { fdef= nodeFactory.newFunctionDefinition(declSpec, (ICPPASTFunctionDeclarator) dtor, null); } if (LT(1) == IToken.tASSIGN) { consume(); IToken kind= consume(); switch(kind.getType()) { case IToken.t_default: fdef.setIsDefaulted(true); break; case IToken.t_delete: fdef.setIsDeleted(true); break; default: throwBacktrack(kind); } return adjustEndOffset(fdef, consume(IToken.tSEMI).getEndOffset()); } if (LT(1) == IToken.tCOLON) { ctorInitializer(fdef); } try { IASTStatement body= handleFunctionBody(); fdef.setBody(body); setRange(fdef, firstOffset, calculateEndOffset(body)); } catch (BacktrackException bt) { final IASTNode n= bt.getNodeBeforeProblem(); if (n instanceof IASTCompoundStatement && !(fdef instanceof ICPPASTFunctionWithTryBlock)) { fdef.setBody((IASTCompoundStatement) n); setRange(fdef, firstOffset, calculateEndOffset(n)); throwBacktrack(bt.getProblem(), fdef); } throw bt; } if (fdef instanceof ICPPASTFunctionWithTryBlock) { ICPPASTFunctionWithTryBlock tryblock= (ICPPASTFunctionWithTryBlock) fdef; List<ICPPASTCatchHandler> handlers = new ArrayList<ICPPASTCatchHandler>(DEFAULT_CATCH_HANDLER_LIST_SIZE); catchHandlerSequence(handlers); ICPPASTCatchHandler last= null; for (ICPPASTCatchHandler catchHandler : handlers) { tryblock.addCatchHandler(catchHandler); last= catchHandler; } if (last != null) { adjustLength(tryblock, last); } } return fdef; } /** * ctor-initializer: * : mem-initializer-list * mem-initializer-list: * mem-initializer ...? * mem-initializer ...?, mem-initializer-list * mem-initializer: * mem-initializer-id ( expression-list? ) * mem-initializer-id braced-init-list * mem-initializer-id: * ::? nested-name-specifier? class-name * identifier */ protected void ctorInitializer(ICPPASTFunctionDefinition fdef) throws EndOfFileException, BacktrackException { consume(IToken.tCOLON); loop: for(;;) { final int offset= LA(1).getOffset(); final IASTName name = qualifiedName(); final IASTInitializer init; int endOffset; if (LT(1) != IToken.tEOC) { init = bracedOrCtorStyleInitializer(); endOffset= calculateEndOffset(init); } else { init= null; endOffset= calculateEndOffset(name); } ICPPASTConstructorChainInitializer ctorInitializer = nodeFactory.newConstructorChainInitializer(name, init); if (LT(1) == IToken.tELLIPSIS) { ctorInitializer.setIsPackExpansion(true); endOffset= consume().getEndOffset(); } fdef.addMemberInitializer(setRange(ctorInitializer, offset, endOffset)); if (LT(1) == IToken.tCOMMA) { consume(); } else { break loop; } } } /** * This routine parses a parameter declaration * * @throws BacktrackException * request a backtrack */ protected ICPPASTParameterDeclaration parameterDeclaration() throws BacktrackException, EndOfFileException { final int startOffset= LA(1).getOffset(); if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) { skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); } IASTDeclSpecifier declSpec= null; IASTDeclarator declarator; try { Decl decl= declSpecifierSequence_initDeclarator(DeclarationOptions.PARAMETER, false); declSpec= decl.fDeclSpec1; declarator= decl.fDtor1; } catch (FoundAggregateInitializer lie) { declSpec= lie.fDeclSpec; declarator= addInitializer(lie, DeclarationOptions.PARAMETER); } final ICPPASTParameterDeclaration parm = nodeFactory.newParameterDeclaration(declSpec, declarator); final int endOffset = figureEndOffset(declSpec, declarator); setRange(parm, startOffset, endOffset); return parm; } private final static int INLINE=0x1, CONST=0x2, RESTRICT=0x4, VOLATILE=0x8, SHORT=0x10, UNSIGNED= 0x20, SIGNED=0x40, COMPLEX=0x80, IMAGINARY=0x100, VIRTUAL=0x200, EXPLICIT=0x400, FRIEND=0x800; private static final int FORBID_IN_EMPTY_DECLSPEC = CONST | RESTRICT | VOLATILE | SHORT | UNSIGNED | SIGNED | COMPLEX | IMAGINARY | FRIEND; /** * This function parses a declaration specifier sequence, as according to * the ANSI C++ specification. * declSpecifier : * "register" | "static" | "extern" | "mutable" | * "inline" | "virtual" | "explicit" | * "typedef" | "friend" | * "const" | "volatile" | * "short" | "long" | "signed" | "unsigned" | "int" | * "char" | "wchar_t" | "bool" | "float" | "double" | "void" | * "auto" | * ("typename")? name | * { "class" | "struct" | "union" } classSpecifier | * {"enum"} enumSpecifier */ @Override protected Decl declSpecifierSeq(final DeclarationOptions option) throws BacktrackException, EndOfFileException { return declSpecifierSeq(option, false); } private ICPPASTDeclSpecifier simpleTypeSpecifier() throws BacktrackException, EndOfFileException { Decl d= declSpecifierSeq(null, true); return (ICPPASTDeclSpecifier) d.fDeclSpec1; } private ICPPASTDeclSpecifier simpleTypeSpecifierSequence() throws BacktrackException, EndOfFileException { Decl d= declSpecifierSeq(null, false); return (ICPPASTDeclSpecifier) d.fDeclSpec1; } private Decl declSpecifierSeq(final DeclarationOptions option, final boolean single) throws BacktrackException, EndOfFileException { int storageClass = IASTDeclSpecifier.sc_unspecified; int simpleType = IASTSimpleDeclSpecifier.t_unspecified; int options= 0; int isLong= 0; IToken returnToken= null; ICPPASTDeclSpecifier result= null; ICPPASTDeclSpecifier altResult= null; try { IASTName identifier= null; IASTExpression typeofExpression= null; IASTProblem problem= null; boolean isTypename = false; boolean encounteredRawType= false; boolean encounteredTypename= false; final int offset = LA(1).getOffset(); int endOffset= offset; declSpecifiers: for (;;) { final int lt1= LTcatchEOF(1); switch (lt1) { case 0: // encountered eof break declSpecifiers; // storage class specifiers case IToken.t_auto: if (supportAutoTypeSpecifier) { if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_auto; encounteredRawType= true; endOffset= consume().getEndOffset(); break; } else { storageClass = IASTDeclSpecifier.sc_auto; endOffset= consume().getEndOffset(); } break; case IToken.t_register: storageClass = IASTDeclSpecifier.sc_register; endOffset= consume().getEndOffset(); break; case IToken.t_static: storageClass = IASTDeclSpecifier.sc_static; endOffset= consume().getEndOffset(); break; case IToken.t_extern: storageClass = IASTDeclSpecifier.sc_extern; endOffset= consume().getEndOffset(); break; case IToken.t_mutable: storageClass = IASTDeclSpecifier.sc_mutable; endOffset= consume().getEndOffset(); break; case IToken.t_typedef: storageClass = IASTDeclSpecifier.sc_typedef; endOffset= consume().getEndOffset(); break; // function specifiers case IToken.t_inline: options |= INLINE; endOffset= consume().getEndOffset(); break; case IToken.t_virtual: options |= VIRTUAL; endOffset= consume().getEndOffset(); break; case IToken.t_explicit: options |= EXPLICIT; endOffset= consume().getEndOffset(); break; case IToken.t_friend: options |= FRIEND; endOffset= consume().getEndOffset(); break; // type specifier case IToken.t_const: options |= CONST; endOffset= consume().getEndOffset(); break; case IToken.t_volatile: options |= VOLATILE; endOffset= consume().getEndOffset(); break; case IToken.t_restrict: options |= RESTRICT; endOffset= consume().getEndOffset(); break; case IToken.t_signed: if (encounteredTypename) break declSpecifiers; options |= SIGNED; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_unsigned: if (encounteredTypename) break declSpecifiers; options |= UNSIGNED; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_short: if (encounteredTypename) break declSpecifiers; options |= SHORT; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_long: if (encounteredTypename) break declSpecifiers; isLong++; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t__Complex: if (encounteredTypename) break declSpecifiers; options |= COMPLEX; endOffset= consume().getEndOffset(); break; case IToken.t__Imaginary: if (encounteredTypename) break declSpecifiers; options |= IMAGINARY; endOffset= consume().getEndOffset(); break; case IToken.t_char: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_char; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_wchar_t: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_wchar_t; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_char16_t: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_char16_t; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_char32_t: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_char32_t; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_bool: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_bool; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_int: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_int; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_float: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_float; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_double: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_double; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_void: if (encounteredTypename) break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_void; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_typename: if (encounteredTypename || encounteredRawType) break declSpecifiers; consume(); identifier= qualifiedName(); endOffset= calculateEndOffset(identifier); isTypename = true; encounteredTypename= true; break; case IToken.tBITCOMPLEMENT: case IToken.tCOLONCOLON: case IToken.tIDENTIFIER: case IToken.tCOMPLETION: if (encounteredRawType || encounteredTypename) break declSpecifiers; if (option != null && option.fAllowEmptySpecifier && LT(1) != IToken.tCOMPLETION) { if ((options & FORBID_IN_EMPTY_DECLSPEC) == 0 && storageClass == IASTDeclSpecifier.sc_unspecified) { altResult= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset); returnToken= mark(); } } identifier= qualifiedName(); if (identifier.getLookupKey().length == 0 && LT(1) != IToken.tEOC) throwBacktrack(LA(1)); endOffset= calculateEndOffset(identifier); encounteredTypename= true; break; case IToken.t_class: case IToken.t_struct: case IToken.t_union: if (encounteredTypename || encounteredRawType) break declSpecifiers; try { result= classSpecifier(); } catch (BacktrackException bt) { result= elaboratedTypeSpecifier(); } endOffset= calculateEndOffset(result); encounteredTypename= true; break; case IToken.t_enum: if (encounteredTypename || encounteredRawType) break declSpecifiers; try { result= enumDeclaration(option != null && option.fAllowOpaqueEnum); } catch (BacktrackException bt) { if (bt.getNodeBeforeProblem() instanceof ICPPASTDeclSpecifier) { result= (ICPPASTDeclSpecifier) bt.getNodeBeforeProblem(); problem= bt.getProblem(); break declSpecifiers; } throw bt; } endOffset= calculateEndOffset(result); encounteredTypename= true; break; case IGCCToken.t__attribute__: // if __attribute__ is after the declSpec if (!supportAttributeSpecifiers) throwBacktrack(LA(1)); __attribute_decl_seq(true, false); break; case IGCCToken.t__declspec: // __declspec precedes the identifier if (identifier != null || !supportDeclspecSpecifiers) throwBacktrack(LA(1)); __attribute_decl_seq(false, true); break; case IGCCToken.t_typeof: if (encounteredRawType || encounteredTypename) throwBacktrack(LA(1)); simpleType= IASTSimpleDeclSpecifier.t_typeof; consume(IGCCToken.t_typeof); typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, LA(1).getOffset(), IASTTypeIdExpression.op_typeof, -1, CastExprCtx.eNotInBExpr, null); encounteredTypename= true; endOffset= calculateEndOffset(typeofExpression); break; case IToken.t_decltype: if (encounteredRawType || encounteredTypename) throwBacktrack(LA(1)); simpleType= IASTSimpleDeclSpecifier.t_decltype; consume(IToken.t_decltype); consume(IToken.tLPAREN); typeofExpression= expression(); endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); encounteredTypename= true; break; default: if (lt1 >= IExtensionToken.t__otherDeclSpecModifierFirst && lt1 <= IExtensionToken.t__otherDeclSpecModifierLast) { handleOtherDeclSpecModifier(); endOffset= LA(1).getOffset(); break; } break declSpecifiers; } if (encounteredRawType && encounteredTypename) throwBacktrack(LA(1)); if (single) break declSpecifiers; } // check for empty specification if (!encounteredRawType && !encounteredTypename && LT(1) != IToken.tEOC && (option == null || !option.fAllowEmptySpecifier)) { throwBacktrack(LA(1)); } if (result != null) { configureDeclSpec(result, storageClass, options); // cannot store restrict in the cpp-nodes. // if ((options & RESTRICT) != 0) { // } setRange(result, offset, endOffset); if (problem != null) { throwBacktrack(problem, result); } } else if (identifier != null) { result= buildNamedTypeSpecifier(identifier, isTypename, storageClass, options, offset, endOffset); } else { result= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset); } } catch (BacktrackException e) { if (returnToken != null) { backup(returnToken); result= altResult; altResult= null; returnToken= null; } else { throw e; } } Decl target= new Decl(); target.fDeclSpec1= result; target.fDeclSpec2= altResult; target.fDtorToken1= returnToken; return target; } private ICPPASTNamedTypeSpecifier buildNamedTypeSpecifier(IASTName name, boolean isTypename, int storageClass, int options, int offset, int endOffset) { ICPPASTNamedTypeSpecifier declSpec = nodeFactory.newTypedefNameSpecifier(name); declSpec.setIsTypename(isTypename); configureDeclSpec(declSpec, storageClass, options); ((ASTNode) declSpec).setOffsetAndLength(offset, endOffset - offset); return declSpec; } private ICPPASTSimpleDeclSpecifier buildSimpleDeclSpec(int storageClass, int simpleType, int options, int isLong, IASTExpression typeofExpression, int offset, int endOffset) { ICPPASTSimpleDeclSpecifier declSpec= nodeFactory.newSimpleDeclSpecifier(); configureDeclSpec(declSpec, storageClass, options); declSpec.setType(simpleType); declSpec.setLong(isLong == 1); declSpec.setLongLong(isLong > 1); declSpec.setShort((options & SHORT) != 0); declSpec.setUnsigned((options & UNSIGNED) != 0); declSpec.setSigned((options & SIGNED) != 0); declSpec.setComplex((options & COMPLEX) != 0); declSpec.setImaginary((options & IMAGINARY) != 0); declSpec.setDeclTypeExpression(typeofExpression); ((ASTNode) declSpec).setOffsetAndLength(offset, endOffset-offset); return declSpec; } private void configureDeclSpec(ICPPASTDeclSpecifier declSpec, int storageClass, int options) { declSpec.setStorageClass(storageClass); declSpec.setConst((options & CONST) != 0); declSpec.setVolatile((options & VOLATILE) != 0); declSpec.setInline((options & INLINE) != 0); declSpec.setFriend((options & FRIEND) != 0); declSpec.setVirtual((options & VIRTUAL) != 0); declSpec.setExplicit((options & EXPLICIT) != 0); declSpec.setRestrict((options & RESTRICT) != 0); } private ICPPASTDeclSpecifier enumDeclaration(boolean allowOpaque) throws BacktrackException, EndOfFileException { IToken mark= mark(); final int offset= consume(IToken.t_enum).getOffset(); int endOffset= 0; boolean isScoped= false; IASTName name= null; ICPPASTDeclSpecifier baseType= null; try { int lt1= LT(1); if (lt1 == IToken.t_class || lt1 == IToken.t_struct) { isScoped= true; consume(); } // if __attribute__ or __declspec occurs after struct/union/class and before the identifier __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); if (isScoped || LT(1) == IToken.tIDENTIFIER) { name= identifier(); endOffset= calculateEndOffset(name); } if (LT(1) == IToken.tCOLON) { consume(); baseType= simpleTypeSpecifierSequence(); endOffset= calculateEndOffset(baseType); } } catch (BacktrackException e) { backup(mark); return elaboratedTypeSpecifier(); } final int lt1= LT(1); final boolean isDef= lt1 == IToken.tLBRACE || (lt1 == IToken.tEOC && baseType != null); final boolean isOpaque= !isDef && allowOpaque && lt1 == IToken.tSEMI; if (!isDef && !isOpaque) { backup(mark); return elaboratedTypeSpecifier(); } mark= null; if (isOpaque && !isScoped && baseType == null) throwBacktrack(LA(1)); if (name == null) { if (isOpaque) throwBacktrack(LA(1)); name= nodeFactory.newName(); } final ICPPASTEnumerationSpecifier result= nodeFactory.newEnumerationSpecifier(isScoped, name, baseType); result.setIsOpaque(isOpaque); if (lt1 == IToken.tLBRACE) { endOffset= enumBody(result); } assert endOffset != 0; return setRange(result, offset, endOffset); } /** * Parse an elaborated type specifier. * * @throws BacktrackException * request a backtrack */ protected ICPPASTElaboratedTypeSpecifier elaboratedTypeSpecifier() throws BacktrackException, EndOfFileException { // this is an elaborated class specifier final int lt1= LT(1); int eck = 0; switch (lt1) { case IToken.t_class: eck = ICPPASTElaboratedTypeSpecifier.k_class; break; case IToken.t_struct: eck = IASTElaboratedTypeSpecifier.k_struct; break; case IToken.t_union: eck = IASTElaboratedTypeSpecifier.k_union; break; case IToken.t_enum: eck = IASTElaboratedTypeSpecifier.k_enum; break; default: throwBacktrack(LA(1)); } final int offset= consume().getOffset(); // if __attribute__ or __declspec occurs after struct/union/class and before the identifier __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); IASTName name = qualifiedName(); return setRange(nodeFactory.newElaboratedTypeSpecifier(eck, name), offset, calculateEndOffset(name)); } @Override protected IASTDeclarator initDeclarator(IASTDeclSpecifier declspec, DeclarationOptions option) throws EndOfFileException, BacktrackException, FoundAggregateInitializer { final IToken mark= mark(); IASTDeclarator dtor1= null; IToken end1= null; IASTDeclarator dtor2= null; BacktrackException bt= null; try { dtor1= initDeclarator(DtorStrategy.PREFER_FUNCTION, declspec, option); verifyDtor(declspec, dtor1, option); int lt1= LTcatchEOF(1); switch (lt1) { case 0: return dtor1; case IToken.tLBRACE: if (option.fCanBeFollowedByBrace || ASTQueries.findTypeRelevantDeclarator(dtor1) instanceof IASTFunctionDeclarator) return dtor1; dtor1= null; throwBacktrack(LA(1)); break; case IToken.tCOLON: // a colon can be used after a type-id in a conditional expression if (option != DeclarationOptions.CPP_MEMBER && option != DeclarationOptions.GLOBAL) break; //$FALL-THROUGH$ case IToken.t_throw: case IToken.t_try: case IToken.t_const: case IToken.t_volatile: case IToken.tASSIGN: // defaulted or deleted function definition if (option == DeclarationOptions.TYPEID_TRAILING_RETURN_TYPE || ASTQueries.findTypeRelevantDeclarator(dtor1) instanceof IASTFunctionDeclarator) { return dtor1; } else { dtor1= null; throwBacktrack(LA(1)); } } if (!(dtor1 instanceof IASTFunctionDeclarator)) return dtor1; end1= LA(1); } catch (BacktrackException e) { bt= e; } if (!option.fAllowCtorStyleInitializer || !canHaveConstructorInitializer(declspec, dtor1)) { if (bt != null) throw bt; return dtor1; } backup(mark); try { dtor2= initDeclarator(DtorStrategy.PREFER_NESTED, declspec, option); if (dtor1 == null) { return dtor2; } } catch (BacktrackException e) { if (dtor1 != null) { backup(end1); return dtor1; } throw e; } // we have an ambiguity if (end1 != null && LA(1).getEndOffset() != end1.getEndOffset()) { backup(end1); return dtor1; } if (functionBodyCount != 0) { // prefer the variable prototype: IASTDeclarator h= dtor1; dtor1= dtor2; dtor2= h; } CPPASTAmbiguousDeclarator dtor= new CPPASTAmbiguousDeclarator(dtor1, dtor2); dtor.setOffsetAndLength((ASTNode) dtor1); return dtor; } /** * Tries to detect illegal versions of declarations */ private void verifyDtor(IASTDeclSpecifier declspec, IASTDeclarator dtor, DeclarationOptions opt) throws BacktrackException { if (CPPVisitor.doesNotSpecifyType(declspec)) { if (ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator) { boolean isQualified= false; IASTName name= ASTQueries.findInnermostDeclarator(dtor).getName(); if (name instanceof ICPPASTQualifiedName) { isQualified= true; name= name.getLastName(); } if (name instanceof ICPPASTTemplateId) name= ((ICPPASTTemplateId) name).getTemplateName(); // accept conversion operator if (name instanceof ICPPASTConversionName) return; // accept destructor final char[] nchars= name.getLookupKey(); if (nchars.length > 0 && nchars[0] == '~') return; if (opt == DeclarationOptions.CPP_MEMBER) { // accept constructor within class body if (CharArrayUtils.equals(nchars, currentClassName)) return; } else if (isQualified) { // accept qualified constructor outside of class body return; } } ASTNode node= (ASTNode) dtor; throwBacktrack(node.getOffset(), node.getLength()); } } private boolean canHaveConstructorInitializer(IASTDeclSpecifier declspec, IASTDeclarator dtor) { if (declspec instanceof ICPPASTDeclSpecifier) { ICPPASTDeclSpecifier cppspec= (ICPPASTDeclSpecifier) declspec; if (cppspec.isFriend()) { return false; } if (cppspec.getStorageClass() == IASTDeclSpecifier.sc_typedef) { return false; } } if (declspec instanceof ICPPASTSimpleDeclSpecifier) { ICPPASTSimpleDeclSpecifier sspec= (ICPPASTSimpleDeclSpecifier) declspec; if (CPPVisitor.doesNotSpecifyType(declspec)) { return false; } if (sspec.getType() == IASTSimpleDeclSpecifier.t_void && dtor != null && dtor.getPointerOperators().length == 0 && dtor.getNestedDeclarator() == null) { return false; } } if (dtor != null) { IASTName name = ASTQueries.findInnermostDeclarator(dtor).getName().getLastName(); if (name instanceof ICPPASTTemplateId) { name= ((ICPPASTTemplateId) name).getTemplateName(); } if (name instanceof ICPPASTOperatorName || name instanceof ICPPASTConversionName) return false; } return true; } /** * Parses the initDeclarator construct of the ANSI C++ spec. initDeclarator : * declarator ("=" initializerClause | "(" expressionList ")")? * * @return declarator that this parsing produced. * @throws BacktrackException * request a backtrack * @throws FoundAggregateInitializer */ private IASTDeclarator initDeclarator(DtorStrategy strategy, IASTDeclSpecifier declspec, DeclarationOptions option) throws EndOfFileException, BacktrackException, FoundAggregateInitializer { final IASTDeclarator dtor= declarator(strategy, option); if (option.fAllowInitializer) { final IASTDeclarator typeRelevantDtor = ASTQueries.findTypeRelevantDeclarator(dtor); if (option != DeclarationOptions.PARAMETER && typeRelevantDtor instanceof IASTFunctionDeclarator) { // Function declarations don't have initializers // For member functions we need to consider pure-virtual syntax if (option == DeclarationOptions.CPP_MEMBER && LTcatchEOF(1) == IToken.tASSIGN && LTcatchEOF(2) == IToken.tINTEGER) { consume(); IToken t = consume(); char[] image = t.getCharImage(); if (image.length != 1 || image[0] != '0') { throwBacktrack(t); } ((ICPPASTFunctionDeclarator) typeRelevantDtor).setPureVirtual(true); adjustEndOffset(dtor, t.getEndOffset()); // we can only adjust the offset of the outermost dtor. } } else { if (LTcatchEOF(1) == IToken.tASSIGN && LTcatchEOF(2) == IToken.tLBRACE) throw new FoundAggregateInitializer(declspec, dtor); IASTInitializer initializer= optionalInitializer(dtor, option); if (initializer != null) { if (initializer instanceof IASTInitializerList && ((IASTInitializerList) initializer).getSize() == 0) { // Avoid ambiguity between constructor with body and variable with initializer switch (LTcatchEOF(1)) { case IToken.tCOMMA: case IToken.tSEMI: case IToken.tRPAREN: break; case 0: throw backtrack; default: throwBacktrack(LA(1)); } } dtor.setInitializer(initializer); adjustLength(dtor, initializer); } } } return dtor; } /** * initializer: * brace-or-equal-initializer * ( expression-list ) * * brace-or-equal-initializer: * = initializer-clause * braced-init-list */ @Override protected IASTInitializer optionalInitializer(IASTDeclarator dtor, DeclarationOptions option) throws EndOfFileException, BacktrackException { final int lt1= LTcatchEOF(1); // = initializer-clause if (lt1 == IToken.tASSIGN) { // Check for deleted or defaulted function syntax. final int lt2= LTcatchEOF(2); if (lt2 == IToken.t_delete || lt2 == IToken.t_default) return null; int offset= consume().getOffset(); final boolean allowSkipping = LT(1) == IToken.tLBRACE && specifiesArray(dtor); IASTInitializerClause initClause = initClause(allowSkipping); IASTEqualsInitializer initExpr= nodeFactory.newEqualsInitializer(initClause); return setRange(initExpr, offset, calculateEndOffset(initClause)); } // braced-init-list if (option.fAllowBracedInitializer && lt1 == IToken.tLBRACE) { return bracedInitList(false); } // ( expression-list ) if (option.fAllowCtorStyleInitializer && lt1 == IToken.tLPAREN) { return ctorStyleInitializer(false); } return null; } private boolean specifiesArray(IASTDeclarator dtor) { dtor = ASTQueries.findTypeRelevantDeclarator(dtor); return dtor instanceof IASTArrayDeclarator; } private IASTInitializer bracedOrCtorStyleInitializer() throws EndOfFileException, BacktrackException { final int lt1= LT(1); if (lt1 == IToken.tLPAREN) { return ctorStyleInitializer(true); } return bracedInitList(false); } /** * ( expression-list_opt ) */ private ICPPASTConstructorInitializer ctorStyleInitializer(boolean optionalExpressionList) throws EndOfFileException, BacktrackException { IASTInitializerClause[] initArray; int offset = consume(IToken.tLPAREN).getOffset(); // ( ) if (optionalExpressionList && LT(1) == IToken.tRPAREN) { initArray= IASTExpression.EMPTY_EXPRESSION_ARRAY; } else { final List<IASTInitializerClause> exprList = expressionList(); initArray = exprList.toArray(new IASTInitializerClause[exprList.size()]); } int endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset(); return setRange(nodeFactory.newConstructorInitializer(initArray), offset, endOffset); } private List<IASTInitializerClause> expressionList() throws EndOfFileException, BacktrackException { return initializerList(false); } /** * initializer-clause: * assignment-expression * braced-init-list */ private IASTInitializerClause initClause(boolean allowSkipping) throws EndOfFileException, BacktrackException { // braced-init-list if (LT(1) == IToken.tLBRACE) { return bracedInitList(allowSkipping); } // assignment expression TemplateIdStrategy strat= fTemplateParameterListStrategy; final BinaryExprCtx ctx= strat != null ? BinaryExprCtx.eInTemplateID : BinaryExprCtx.eNotInTemplateID; IASTExpression assignmentExpression = expression(ExprKind.eAssignment, ctx, null, strat); if (allowSkipping && skipTrivialExpressionsInAggregateInitializers) { if (!ASTQueries.canContainName(assignmentExpression)) return null; } return assignmentExpression; } /** * braced-init-list: * { initializer-list ,opt } * { } */ private ICPPASTInitializerList bracedInitList(boolean allowSkipping) throws EndOfFileException, BacktrackException { int offset = consume(IToken.tLBRACE).getOffset(); // { } if (LT(1) == IToken.tRBRACE) { return setRange(nodeFactory.newInitializerList(), offset, consume().getEndOffset()); } // { initializer-list ,opt } List<IASTInitializerClause> initList= initializerList(allowSkipping); if (LT(1) == IToken.tCOMMA) consume(); int endOffset= consumeOrEOC(IToken.tRBRACE).getEndOffset(); ICPPASTInitializerList result = nodeFactory.newInitializerList(); for (IASTInitializerClause init : initList) { result.addClause(init); } return setRange(result, offset, endOffset); } /** * initializerList: * initializer-clause ...opt * initializer-list , initializer-clause ...opt */ private List<IASTInitializerClause> initializerList(boolean allowSkipping) throws EndOfFileException, BacktrackException { List<IASTInitializerClause> result= null; // List of initializer clauses loop: for(;;) { // Clause may be null, add to initializer anyways, such that the size can be computed. IASTInitializerClause clause = initClause(allowSkipping); if (LT(1) == IToken.tELLIPSIS) { final int endOffset = consume(IToken.tELLIPSIS).getEndOffset(); if (clause instanceof ICPPASTPackExpandable) { // Mark initializer lists directly as pack expansions ((ICPPASTPackExpandable) clause).setIsPackExpansion(true); adjustEndOffset(clause, endOffset); } else if (clause instanceof IASTExpression) { // Wrap pack expanded assignment expressions IASTExpression packExpansion= nodeFactory.newPackExpansionExpression((IASTExpression) clause); clause= setRange(packExpansion, clause, endOffset); } } if (result == null) { result= new ArrayList<IASTInitializerClause>(); } result.add(clause); if (LT(1) != IToken.tCOMMA) break; switch (LT(2)) { case IToken.tRBRACE: case IToken.tRPAREN: case IToken.tEOC: break loop; } consume(IToken.tCOMMA); } if (result == null) return Collections.emptyList(); return result; } @Override protected ICPPASTTypeId typeId(DeclarationOptions option) throws EndOfFileException, BacktrackException { if (!canBeTypeSpecifier()) { throwBacktrack(LA(1)); } final int offset = LA().getOffset(); IASTDeclSpecifier declSpecifier = null; IASTDeclarator declarator = null; try { Decl decl= declSpecifierSequence_initDeclarator(option, false); declSpecifier= decl.fDeclSpec1; declarator= decl.fDtor1; } catch (FoundAggregateInitializer lie) { // type-ids have no initializers throwBacktrack(lie.fDeclarator); } ICPPASTTypeId result = nodeFactory.newTypeId(declSpecifier, declarator); setRange(result, offset, figureEndOffset(declSpecifier, declarator)); return result; } /** * Parse a declarator, as according to the ANSI C++ specification. * declarator : (ptrOperator)* directDeclarator * directDeclarator : * declaratorId | * directDeclarator "(" parameterDeclarationClause ")" (cvQualifier)* (exceptionSpecification)* | * directDeclarator "[" (constantExpression)? "]" | * "(" declarator")" | * directDeclarator "(" parameterDeclarationClause ")" (oldKRParameterDeclaration)* * * declaratorId : name * @return declarator that this parsing produced. * @throws BacktrackException * request a backtrack */ protected IASTDeclarator declarator(DtorStrategy strategy, DeclarationOptions option) throws EndOfFileException, BacktrackException { final int startingOffset = LA(1).getOffset(); int endOffset = startingOffset; List<? extends IASTPointerOperator> pointerOps = consumePointerOperators(); if (pointerOps != null) { endOffset = calculateEndOffset(pointerOps.get(pointerOps.size() - 1)); } // Accept __attribute__ or __declspec between pointer operators and declarator. __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); // Look for identifier or nested declarator boolean hasEllipsis= false; if (option.fAllowParameterPacks && LT(1) == IToken.tELLIPSIS) { consume(); hasEllipsis= true; } final int lt1= LT(1); switch (lt1) { case IToken.tBITCOMPLEMENT: case IToken.t_operator: case IToken.tCOLONCOLON: case IToken.tIDENTIFIER: case IToken.tCOMPLETION: if (option.fRequireAbstract) throwBacktrack(LA(1)); final IASTName declaratorName= !option.fRequireSimpleName ? qualifiedName() : identifier(); endOffset= calculateEndOffset(declaratorName); return declarator(pointerOps, hasEllipsis, declaratorName, null, startingOffset, endOffset, strategy, option); } if (lt1 == IToken.tLPAREN) { IASTDeclarator cand1= null; IToken cand1End= null; // try an abstract function declarator if (option.fAllowAbstract && option.fAllowFunctions) { final IToken mark= mark(); try { cand1= declarator(pointerOps, hasEllipsis, nodeFactory.newName(), null, startingOffset, endOffset, strategy, option); if (option.fRequireAbstract || !option.fAllowNested || hasEllipsis) return cand1; cand1End= LA(1); } catch (BacktrackException e) { } backup(mark); } // type-ids for new or operator-id: if (!option.fAllowNested || hasEllipsis) { if (option.fAllowAbstract) { return declarator(pointerOps, hasEllipsis, nodeFactory.newName(), null, startingOffset, endOffset, strategy, option); } throwBacktrack(LA(1)); } // try a nested declarator try { consume(); if (LT(1) == IToken.tRPAREN) throwBacktrack(LA(1)); final IASTDeclarator nested= declarator(DtorStrategy.PREFER_FUNCTION, option); endOffset= consume(IToken.tRPAREN).getEndOffset(); final IASTDeclarator cand2= declarator(pointerOps, hasEllipsis, nodeFactory.newName(), nested, startingOffset, endOffset, strategy, option); if (cand1 == null || cand1End == null) return cand2; final IToken cand2End= LA(1); if (cand1End == cand2End) { CPPASTAmbiguousDeclarator result= new CPPASTAmbiguousDeclarator(cand1, cand2); ((ASTNode) result).setOffsetAndLength((ASTNode) cand1); return result; } // use the longer variant if (cand1End.getOffset() < cand2End.getOffset()) return cand2; } catch (BacktrackException e) { if (cand1 == null) throw e; } backup(cand1End); return cand1; } // try abstract declarator if (!option.fAllowAbstract) { // bit-fields may be abstract if (!option.fAllowBitField || LT(1) != IToken.tCOLON) throwBacktrack(LA(1)); } return declarator(pointerOps, hasEllipsis, nodeFactory.newName(), null, startingOffset, endOffset, strategy, option); } /** * Parse a Pointer Operator. ptrOperator : "*" (cvQualifier)* | "&" | ::? * nestedNameSpecifier "*" (cvQualifier)* * * @throws BacktrackException * request a backtrack */ private List<? extends IASTPointerOperator> consumePointerOperators() throws EndOfFileException, BacktrackException { List<IASTPointerOperator> result= null; for (;;) { // __attribute__ in-between pointers __attribute_decl_seq(supportAttributeSpecifiers, false); final int lt1 = LT(1); if (lt1 == IToken.tAMPER || lt1 == IToken.tAND) { IToken endToken= consume(); final int offset= endToken.getOffset(); if (allowCPPRestrict && LT(1) == IToken.t_restrict) { endToken= consume(); } ICPPASTReferenceOperator refOp = nodeFactory.newReferenceOperator(lt1 == IToken.tAND); setRange(refOp, offset, endToken.getEndOffset()); if (result != null) { result.add(refOp); return result; } return Collections.singletonList(refOp); } IToken mark = mark(); final int startOffset = mark.getOffset(); boolean isConst = false, isVolatile = false, isRestrict = false; IASTName name= null; int coloncolon= LT(1) == IToken.tCOLONCOLON ? 1 : 0; loop: while (LTcatchEOF(coloncolon+1) == IToken.tIDENTIFIER) { switch (LTcatchEOF(coloncolon+2)) { case IToken.tCOLONCOLON: coloncolon+= 2; break; case IToken.tLT: coloncolon= 1; break loop; default: coloncolon= 0; break loop; } } if (coloncolon != 0) { try { name= qualifiedName(); if (name.getLookupKey().length != 0) { backup(mark); return result; } } catch (BacktrackException bt) { backup(mark); return result; } } if (LTcatchEOF(1) != IToken.tSTAR) { backup(mark); return result; } int endOffset= consume().getEndOffset(); loop: for (;;) { switch (LTcatchEOF(1)) { case IToken.t_const: endOffset= consume().getEndOffset(); isConst = true; break; case IToken.t_volatile: endOffset= consume().getEndOffset(); isVolatile = true; break; case IToken.t_restrict: if (!allowCPPRestrict) throwBacktrack(LA(1)); endOffset= consume().getEndOffset(); isRestrict = true; break; default: break loop; } } IASTPointer pointer; if (name != null) { pointer= nodeFactory.newPointerToMember(name); } else { pointer = nodeFactory.newPointer(); } pointer.setConst(isConst); pointer.setVolatile(isVolatile); pointer.setRestrict(isRestrict); setRange(pointer, startOffset, endOffset); if (result == null) { result= new ArrayList<IASTPointerOperator>(4); } result.add(pointer); } } private IASTDeclarator declarator(List<? extends IASTPointerOperator> pointerOps, boolean hasEllipsis, IASTName declaratorName, IASTDeclarator nestedDeclarator, int startingOffset, int endOffset, DtorStrategy strategy, DeclarationOptions option) throws EndOfFileException, BacktrackException { ICPPASTDeclarator result= null; loop: while(true) { final int lt1= LTcatchEOF(1); switch (lt1) { case IToken.tLPAREN: if (option.fAllowFunctions && strategy == DtorStrategy.PREFER_FUNCTION) { result= functionDeclarator(false); setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator); } break loop; case IToken.tLBRACKET: result= arrayDeclarator(option); setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator); break loop; case IToken.tCOLON: if (!option.fAllowBitField || nestedDeclarator != null) break loop; // no backtrack because typeid can be followed by colon result= bitFieldDeclarator(); setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator); break loop; case IGCCToken.t__attribute__: // if __attribute__ is after a declarator if (!supportAttributeSpecifiers) throwBacktrack(LA(1)); __attribute_decl_seq(true, supportDeclspecSpecifiers); break; case IGCCToken.t__declspec: if (!supportDeclspecSpecifiers) throwBacktrack(LA(1)); __attribute_decl_seq(supportAttributeSpecifiers, true); break; default: break loop; } } __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); if (result == null) { result= nodeFactory.newDeclarator(null); setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator); } else { endOffset= calculateEndOffset(result); } if (LTcatchEOF(1) == IToken.t_asm) { // asm labels bug 226121 consume(); endOffset= asmExpression(null).getEndOffset(); __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); } if (pointerOps != null) { for (IASTPointerOperator po : pointerOps) { result.addPointerOperator(po); } } ((ASTNode) result).setOffsetAndLength(startingOffset, endOffset - startingOffset); return result; } private void setDeclaratorID(ICPPASTDeclarator declarator, boolean hasEllipsis, IASTName declaratorName, IASTDeclarator nestedDeclarator) { if (nestedDeclarator != null) { declarator.setNestedDeclarator(nestedDeclarator); declarator.setName(nodeFactory.newName()); } else { declarator.setName(declaratorName); } declarator.setDeclaresParameterPack(hasEllipsis); } /** * Parse a function declarator starting with the left parenthesis. */ private ICPPASTFunctionDeclarator functionDeclarator(boolean isLambdaDeclarator) throws EndOfFileException, BacktrackException { IToken last = consume(IToken.tLPAREN); final int startOffset= last.getOffset(); int endOffset= last.getEndOffset(); final ICPPASTFunctionDeclarator fc = nodeFactory.newFunctionDeclarator(null); ICPPASTParameterDeclaration pd= null; paramLoop: while(true) { switch (LT(1)) { case IToken.tRPAREN: case IToken.tEOC: endOffset= consume().getEndOffset(); break paramLoop; case IToken.tELLIPSIS: consume(); endOffset= consume(IToken.tRPAREN).getEndOffset(); fc.setVarArgs(true); break paramLoop; case IToken.tCOMMA: if (pd == null) throwBacktrack(LA(1)); endOffset= consume().getEndOffset(); pd= null; break; default: if (pd != null) throwBacktrack(startOffset, endOffset - startOffset); pd = parameterDeclaration(); fc.addParameterDeclaration(pd); endOffset = calculateEndOffset(pd); break; } } // Handle ambiguity between parameter pack and varargs. if (pd != null) { ICPPASTDeclarator dtor = pd.getDeclarator(); if (dtor != null && !(dtor instanceof IASTAmbiguousDeclarator)) { if (dtor.declaresParameterPack() && dtor.getNestedDeclarator() == null && dtor.getInitializer() == null && dtor.getName().getSimpleID().length == 0) { ((IASTAmbiguityParent) fc).replace(pd, new CPPASTAmbiguousParameterDeclaration(pd)); } } } // Consume any number of __attribute__ tokens after the parameters __attribute_decl_seq(supportAttributeSpecifiers, false); // cv-qualifiers if (isLambdaDeclarator) { if (LT(1) == IToken.t_mutable) { fc.setMutable(true); endOffset= consume().getEndOffset(); } } else { cvloop: while(true) { switch (LT(1)) { case IToken.t_const: fc.setConst(true); endOffset= consume().getEndOffset(); break; case IToken.t_volatile: fc.setVolatile(true); endOffset= consume().getEndOffset(); break; default: break cvloop; } } } // throws clause if (LT(1) == IToken.t_throw) { fc.setEmptyExceptionSpecification(); consume(); // throw consume(IToken.tLPAREN); thloop: while (true) { switch (LT(1)) { case IToken.tRPAREN: case IToken.tEOC: endOffset = consume().getEndOffset(); break thloop; case IToken.tCOMMA: consume(); break; default: int thoffset = LA(1).getOffset(); try { ICPPASTTypeId typeId = typeId(DeclarationOptions.TYPEID); if (LT(1) == IToken.tELLIPSIS) { typeId.setIsPackExpansion(true); adjustEndOffset(typeId, consume().getEndOffset()); } fc.addExceptionSpecificationTypeId(typeId); } catch (BacktrackException e) { int thendoffset = LA(1).getOffset(); if (thoffset == thendoffset) { thendoffset = consume().getEndOffset(); } IASTProblem p = createProblem(IProblem.SYNTAX_ERROR, thoffset, thendoffset-thoffset); IASTProblemTypeId typeIdProblem = nodeFactory.newProblemTypeId(p); ((ASTNode) typeIdProblem).setOffsetAndLength(((ASTNode) p)); fc.addExceptionSpecificationTypeId(typeIdProblem); } break; } } // more __attribute__ after throws __attribute_decl_seq(supportAttributeSpecifiers, false); } if (LT(1) == IToken.tARROW) { consume(); IASTTypeId typeId= typeId(DeclarationOptions.TYPEID_TRAILING_RETURN_TYPE); fc.setTrailingReturnType(typeId); endOffset= calculateEndOffset(typeId); } return setRange(fc, startOffset, endOffset); } /** * Parse an array declarator starting at the square bracket. */ private ICPPASTArrayDeclarator arrayDeclarator(DeclarationOptions option) throws EndOfFileException, BacktrackException { ArrayList<IASTArrayModifier> arrayMods = new ArrayList<IASTArrayModifier>(4); int start= LA(1).getOffset(); consumeArrayModifiers(option, arrayMods); if (arrayMods.isEmpty()) throwBacktrack(LA(1)); final int endOffset = calculateEndOffset(arrayMods.get(arrayMods.size() - 1)); final ICPPASTArrayDeclarator d = nodeFactory.newArrayDeclarator(null); for (IASTArrayModifier m : arrayMods) { d.addArrayModifier(m); } ((ASTNode) d).setOffsetAndLength(start, endOffset-start); return d; } /** * Parses for a bit field declarator starting with the colon */ private ICPPASTFieldDeclarator bitFieldDeclarator() throws EndOfFileException, BacktrackException { int start= consume(IToken.tCOLON).getOffset(); final IASTExpression bitField = constantExpression(); final int endOffset = calculateEndOffset(bitField); ICPPASTFieldDeclarator d = nodeFactory.newFieldDeclarator(null, bitField); ((ASTNode) d).setOffsetAndLength(start, endOffset-start); return d; } /** * Parse a class/struct/union definition. classSpecifier : classKey name * (baseClause)? "{" (memberSpecification)* "}" * * @throws BacktrackException * request a backtrack */ protected ICPPASTCompositeTypeSpecifier classSpecifier() throws BacktrackException, EndOfFileException { int classKind = 0; IToken mark = mark(); final int offset= mark.getOffset(); // class key switch (LT(1)) { case IToken.t_class: consume(); classKind = ICPPASTCompositeTypeSpecifier.k_class; break; case IToken.t_struct: consume(); classKind = IASTCompositeTypeSpecifier.k_struct; break; case IToken.t_union: consume(); classKind = IASTCompositeTypeSpecifier.k_union; break; default: throwBacktrack(mark); return null; // line is never reached, hint for the parser } // if __attribute__ or __declspec occurs after struct/union/class and before the identifier __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); // class name IASTName name = null; if (LT(1) == IToken.tIDENTIFIER) name = qualifiedName(); else name = nodeFactory.newName(); // if __attribute__ or __declspec occurs after struct/union/class identifier and before the { or ; __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); ICPPASTCompositeTypeSpecifier astClassSpecifier = nodeFactory.newCompositeTypeSpecifier(classKind, name); // base clause if (LT(1) == IToken.tCOLON) { baseClause(astClassSpecifier); // content assist within the base-clause if (LT(1) == IToken.tEOC) { return astClassSpecifier; } } if (LT(1) != IToken.tLBRACE) { IToken errorPoint = LA(1); backup(mark); throwBacktrack(errorPoint); } mark= null; // don't hold on to tokens while parsing the members. final char[] outerName= currentClassName; currentClassName= name.getLookupKey(); try { declarationListInBraces(astClassSpecifier, offset, DeclarationOptions.CPP_MEMBER); } finally { currentClassName= outerName; } return astClassSpecifier; } protected int token2Visibility(int type) { switch (type) { case IToken.t_public: return ICPPASTVisibilityLabel.v_public; case IToken.t_protected: return ICPPASTVisibilityLabel.v_protected; case IToken.t_private: return ICPPASTVisibilityLabel.v_private; } return 0; } /** * Parse a base clause for a class specification. * base-clause: * : base-specifier-list * base-specifier-list: * base-specifier * base-specifier-list, base-specifier */ private void baseClause(ICPPASTCompositeTypeSpecifier astClassSpec) throws EndOfFileException, BacktrackException { consume(IToken.tCOLON); for (;;) { ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier baseSpec = baseSpecifier(); astClassSpec.addBaseSpecifier(baseSpec); if (LT(1) == IToken.tELLIPSIS) { baseSpec.setIsPackExpansion(true); adjustEndOffset(baseSpec, consume().getEndOffset()); } if (LT(1) != IToken.tCOMMA) { return; } consume(); } } /** * base-specifier: * ::? nested-name-specifier? class-name * virtual access-specifier? ::? nested-name-specifier? class-name * access-specifier virtual? ::? nested-name-specifier? class-name * * access-specifier: private | protected | public * @return */ private ICPPASTBaseSpecifier baseSpecifier() throws EndOfFileException, BacktrackException { int startOffset= LA(1).getOffset(); boolean isVirtual = false; int visibility = 0; IASTName name = null; loop: for (;;) { switch (LT(1)) { case IToken.t_virtual: isVirtual = true; consume(); break; case IToken.t_public: visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_public; consume(); break; case IToken.t_protected: visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_protected; consume(); break; case IToken.t_private: visibility = ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.v_private; consume(); break; default: break loop; } } name = qualifiedName(); ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier baseSpec = nodeFactory.newBaseSpecifier(name, visibility, isVirtual); setRange(baseSpec, startOffset, calculateEndOffset(name)); return baseSpec; } protected void catchHandlerSequence(List<ICPPASTCatchHandler> collection) throws EndOfFileException, BacktrackException { if (LT(1) == IToken.tEOC) return; if (LT(1) != IToken.t_catch) throwBacktrack(LA(1)); // error, need at least one int lt1 = LT(1); while (lt1 == IToken.t_catch) { int startOffset = consume().getOffset(); consume(IToken.tLPAREN); boolean isEllipsis = false; IASTDeclaration decl = null; try { if (LT(1) == IToken.tELLIPSIS) { consume(IToken.tELLIPSIS); isEllipsis = true; } else { decl= simpleSingleDeclaration(DeclarationOptions.EXCEPTION); } if (LT(1) != IToken.tEOC) consume(IToken.tRPAREN); } catch (BacktrackException bte) { failParse(); IASTProblem p = createProblem(bte); IASTProblemDeclaration pd = nodeFactory.newProblemDeclaration(p); ((ASTNode) pd).setOffsetAndLength(((ASTNode) p)); decl = pd; } ICPPASTCatchHandler handler = nodeFactory.newCatchHandler(decl, null); if (LT(1) != IToken.tEOC) { IASTStatement compoundStatement = catchBlockCompoundStatement(); ((ASTNode) handler).setOffsetAndLength(startOffset, calculateEndOffset(compoundStatement) - startOffset); handler.setIsCatchAll(isEllipsis); if (compoundStatement != null) { handler.setCatchBody(compoundStatement); } } collection.add(handler); lt1 = LTcatchEOF(1); } } private IASTSimpleDeclaration simpleSingleDeclaration(DeclarationOptions options) throws BacktrackException, EndOfFileException { final int startOffset= LA(1).getOffset(); IASTDeclSpecifier declSpec; IASTDeclarator declarator; try { Decl decl= declSpecifierSequence_initDeclarator(options, true); declSpec= decl.fDeclSpec1; declarator= decl.fDtor1; } catch (FoundAggregateInitializer lie) { declSpec= lie.fDeclSpec; declarator= addInitializer(lie, options); } final int endOffset = figureEndOffset(declSpec, declarator); final IASTSimpleDeclaration decl= nodeFactory.newSimpleDeclaration(declSpec); if (declarator != null) decl.addDeclarator(declarator); ((ASTNode) decl).setOffsetAndLength(startOffset, endOffset - startOffset); return decl; } protected IASTStatement catchBlockCompoundStatement() throws BacktrackException, EndOfFileException { if (mode == ParserMode.QUICK_PARSE || mode == ParserMode.STRUCTURAL_PARSE || !isActiveCode()) { int offset = LA(1).getOffset(); IToken last = skipOverCompoundStatement(); IASTCompoundStatement cs = nodeFactory.newCompoundStatement(); setRange(cs, offset, last.getEndOffset()); return cs; } else if (mode == ParserMode.COMPLETION_PARSE || mode == ParserMode.SELECTION_PARSE) { if (scanner.isOnTopContext()) return compoundStatement(); int offset = LA(1).getOffset(); IToken last = skipOverCompoundStatement(); IASTCompoundStatement cs = nodeFactory.newCompoundStatement(); setRange(cs, offset, last.getEndOffset()); return cs; } return compoundStatement(); } @Override protected void setupTranslationUnit() throws DOMException { translationUnit = nodeFactory.newTranslationUnit(scanner); translationUnit.setIndex(index); // add built-in names to the scope // add built-in names to the scope if (builtinBindingsProvider != null) { IScope tuScope = translationUnit.getScope(); IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope); for (IBinding binding : bindings) { ASTInternal.addBinding(tuScope, binding); } } } private void consumeArrayModifiers(DeclarationOptions option, List<IASTArrayModifier> collection) throws EndOfFileException, BacktrackException { boolean allowExpression= option == DeclarationOptions.TYPEID_NEW; while (LT(1) == IToken.tLBRACKET) { int o = consume().getOffset(); // eat the '[' IASTExpression exp = null; if (LT(1) != IToken.tRBRACKET && LT(1) != IToken.tEOC) { exp = allowExpression ? expression() : constantExpression(); allowExpression= false; } int l; switch (LT(1)) { case IToken.tRBRACKET: case IToken.tEOC: l = consume().getEndOffset(); break; default: throw backtrack; } IASTArrayModifier arrayMod = nodeFactory.newArrayModifier(exp); ((ASTNode) arrayMod).setOffsetAndLength(o, l - o); collection.add(arrayMod); } return; } @Override protected IASTTranslationUnit getTranslationUnit() { return translationUnit; } @Override protected IASTStatement statement() throws EndOfFileException, BacktrackException { switch (LT(1)) { // labeled statements case IToken.t_case: return parseCaseStatement(); case IToken.t_default: return parseDefaultStatement(); // compound statement case IToken.tLBRACE: return parseCompoundStatement(); // selection statement case IToken.t_if: return parseIfStatement(); case IToken.t_switch: return parseSwitchStatement(); // iteration statements case IToken.t_while: return parseWhileStatement(); case IToken.t_do: return parseDoStatement(); case IToken.t_for: return parseForStatement(); // jump statement case IToken.t_break: return parseBreakStatement(); case IToken.t_continue: return parseContinueStatement(); case IToken.t_return: return parseReturnStatement(); case IToken.t_goto: return parseGotoStatement(); case IToken.tSEMI: return parseNullStatement(); case IToken.t_try: return parseTryStatement(); default: // can be many things: // label if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) { return parseLabelStatement(); } return parseDeclarationOrExpressionStatement(); } } protected IASTStatement parseTryStatement() throws EndOfFileException, BacktrackException { int startO = consume().getOffset(); IASTStatement tryBlock = compoundStatement(); List<ICPPASTCatchHandler> catchHandlers = new ArrayList<ICPPASTCatchHandler>(DEFAULT_CATCH_HANDLER_LIST_SIZE); catchHandlerSequence(catchHandlers); ICPPASTTryBlockStatement tryStatement = nodeFactory.newTryBlockStatement(tryBlock); ((ASTNode) tryStatement).setOffset(startO); for (int i = 0; i < catchHandlers.size(); ++i) { ICPPASTCatchHandler handler = catchHandlers.get(i); tryStatement.addCatchHandler(handler); ((ASTNode) tryStatement).setLength(calculateEndOffset(handler) - startO); } return tryStatement; } @Override protected void nullifyTranslationUnit() { translationUnit = null; } @Override protected IASTStatement parseWhileStatement() throws EndOfFileException, BacktrackException { int startOffset = consume().getOffset(); consume(IToken.tLPAREN); IASTNode while_condition = cppStyleCondition(IToken.tRPAREN); switch (LT(1)) { case IToken.tRPAREN: consume(); break; case IToken.tEOC: break; default: throwBacktrack(LA(1)); } IASTStatement while_body = null; if (LT(1) != IToken.tEOC) while_body = statement(); IASTWhileStatement while_statement; if (while_condition instanceof IASTExpression) while_statement = nodeFactory.newWhileStatement((IASTExpression)while_condition, while_body); else while_statement = nodeFactory.newWhileStatement((IASTDeclaration)while_condition, while_body); ((ASTNode) while_statement).setOffsetAndLength(startOffset, (while_body != null ? calculateEndOffset(while_body) : LA(1).getEndOffset()) - startOffset); return while_statement; } protected IASTNode cppStyleCondition(int expectToken) throws BacktrackException, EndOfFileException { IASTExpression e= null; IASTSimpleDeclaration decl= null; IToken end= null; IToken mark = mark(); try { decl= simpleSingleDeclaration(DeclarationOptions.CONDITION); end= LA(1); final int la= end.getType(); if (la != expectToken && la != IToken.tEOC) { end= null; decl= null; } } catch (BacktrackException b) { } backup(mark); try { e= expression(); final IToken end2= LA(1); final int la= end2.getType(); if (la != expectToken && la != IToken.tEOC) { throwBacktrack(end2); } if (end == null) return e; final int endOffset = end.getOffset(); final int endOffset2 = end2.getOffset(); if (endOffset == endOffset2) { CPPASTAmbiguousCondition ambig= new CPPASTAmbiguousCondition(e, decl); setRange(ambig, e); return ambig; } if (endOffset < endOffset2) return e; } catch (BacktrackException bt) { if (end == null) { if (expectToken == IToken.tRPAREN) { backup(mark); return skipProblemConditionInParenthesis(mark.getOffset()); } throw bt; } } backup(end); return decl; } @Override protected ASTVisitor createAmbiguityNodeVisitor() { return new CPPASTAmbiguityResolver(); } @Override protected IASTAmbiguousStatement createAmbiguousStatement() { return new CPPASTAmbiguousStatement(); } protected IASTStatement parseIfStatement() throws EndOfFileException, BacktrackException { ICPPASTIfStatement result = null; ICPPASTIfStatement if_statement = null; int start = LA(1).getOffset(); if_loop: while (true) { int so = consume(IToken.t_if).getOffset(); consume(IToken.tLPAREN); // condition IASTNode condition= cppStyleCondition(IToken.tRPAREN); if (LT(1) == IToken.tEOC) { // Completing in the condition ICPPASTIfStatement new_if = nodeFactory.newIfStatement(); if (condition instanceof IASTExpression) new_if.setConditionExpression((IASTExpression) condition); else if (condition instanceof IASTDeclaration) new_if.setConditionDeclaration((IASTDeclaration) condition); if (if_statement != null) { if_statement.setElseClause(new_if); } return result != null ? result : new_if; } consume(IToken.tRPAREN); IASTStatement thenClause = statement(); ICPPASTIfStatement new_if_statement = nodeFactory.newIfStatement(); ((ASTNode) new_if_statement).setOffset(so); if (condition != null && (condition instanceof IASTExpression || condition instanceof IASTDeclaration)) // shouldn't be possible but failure in condition() makes it so { if (condition instanceof IASTExpression) new_if_statement.setConditionExpression((IASTExpression) condition); else if (condition instanceof IASTDeclaration) new_if_statement.setConditionDeclaration((IASTDeclaration) condition); } if (thenClause != null) { new_if_statement.setThenClause(thenClause); ((ASTNode) new_if_statement).setLength(calculateEndOffset(thenClause) - ((ASTNode) new_if_statement).getOffset()); } if (LT(1) == IToken.t_else) { consume(); if (LT(1) == IToken.t_if) { // an else if, don't recurse, just loop and do another if if (if_statement != null) { if_statement.setElseClause(new_if_statement); ((ASTNode) if_statement).setLength(calculateEndOffset(new_if_statement) - ((ASTNode) if_statement).getOffset()); } if (result == null && if_statement != null) result = if_statement; if (result == null) result = new_if_statement; if_statement = new_if_statement; continue if_loop; } IASTStatement elseStatement = statement(); new_if_statement.setElseClause(elseStatement); if (if_statement != null) { if_statement.setElseClause(new_if_statement); ((ASTNode) if_statement).setLength(calculateEndOffset(new_if_statement) - ((ASTNode) if_statement).getOffset()); } else { if (result == null) result = new_if_statement; if_statement = new_if_statement; } } else { if (thenClause != null) ((ASTNode) new_if_statement).setLength(calculateEndOffset(thenClause) - start); if (if_statement != null) { if_statement.setElseClause(new_if_statement); ((ASTNode) new_if_statement).setLength(calculateEndOffset(new_if_statement) - start); } if (result == null && if_statement != null) result = if_statement; if (result == null) result = new_if_statement; if_statement = new_if_statement; } break if_loop; } reconcileLengths(result); return result; } @Override protected IASTCompoundStatement functionBody() throws EndOfFileException, BacktrackException { ++functionBodyCount; try { return super.functionBody(); } finally { --functionBodyCount; } } protected IASTStatement parseSwitchStatement() throws EndOfFileException, BacktrackException { int startOffset; startOffset = consume().getOffset(); consume(IToken.tLPAREN); IASTNode switch_condition = cppStyleCondition(IToken.tRPAREN); switch (LT(1)) { case IToken.tRPAREN: consume(); break; case IToken.tEOC: break; default: throwBacktrack(LA(1)); } IASTStatement switch_body = parseSwitchBody(); ICPPASTSwitchStatement switch_statement = nodeFactory.newSwitchStatement(); ((ASTNode) switch_statement).setOffsetAndLength(startOffset, (switch_body != null ? calculateEndOffset(switch_body) : LA(1).getEndOffset()) - startOffset); if (switch_condition instanceof IASTExpression) { switch_statement.setControllerExpression((IASTExpression) switch_condition); } else if (switch_condition instanceof IASTDeclaration) { switch_statement.setControllerDeclaration((IASTDeclaration) switch_condition); } if (switch_body != null) { switch_statement.setBody(switch_body); } return switch_statement; } protected IASTStatement parseForStatement() throws EndOfFileException, BacktrackException { final int offset= consume(IToken.t_for).getOffset(); consume(IToken.tLPAREN); IToken mark= mark(); IASTStatement forStmt; try { forStmt= startRangeBasedForLoop(); } catch (BacktrackException e) { backup(mark); forStmt= startTraditionalForLoop(); } mark= null; int endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset(); if (LT(1) != IToken.tEOC) { IASTStatement body = statement(); if (forStmt instanceof ICPPASTRangeBasedForStatement) { ((ICPPASTRangeBasedForStatement) forStmt).setBody(body); } else { ((IASTForStatement) forStmt).setBody(body); } endOffset= calculateEndOffset(body); } return setRange(forStmt, offset, endOffset); } // Look for "for-range-declaration : for-range-initializer" // for-range-declaration: // attribute-specifier? type-specifier-seq declarator // for-range-initializer: // expression // braced-init-list private ICPPASTRangeBasedForStatement startRangeBasedForLoop() throws EndOfFileException, BacktrackException { IASTDeclaration decl= simpleDeclaration(DeclarationOptions.RANGE_BASED_FOR); consume(IToken.tCOLON); IASTInitializerClause init= null; switch (LT(1)) { case IToken.tEOC: break; case IToken.tLBRACE: init= bracedInitList(false); break; default: init= expression(); } ICPPASTRangeBasedForStatement result = nodeFactory.newRangeBasedForStatement(); result.setDeclaration(decl); result.setInitializerClause(init); return result; } private IASTForStatement startTraditionalForLoop() throws BacktrackException, EndOfFileException { final IASTStatement initStmt = forInitStatement(); IASTNode condition= null; IASTExpression iterExpr= null; int lt1 = LT(1); if (lt1 != IToken.tSEMI && lt1 != IToken.tEOC) { condition = cppStyleCondition(IToken.tSEMI); } consumeOrEOC(IToken.tSEMI); lt1 = LT(1); if (lt1 != IToken.tRPAREN && lt1 != IToken.tEOC) { iterExpr = expression(); } ICPPASTForStatement result = nodeFactory.newForStatement(); result.setInitializerStatement(initStmt); if (condition instanceof IASTExpression) { result.setConditionExpression((IASTExpression) condition); } else if (condition instanceof IASTDeclaration) { result.setConditionDeclaration((IASTDeclaration) condition); } result.setIterationExpression(iterExpr); return result; } @Override protected IASTStatement parseReturnStatement() throws EndOfFileException, BacktrackException { final int offset= consume(IToken.t_return).getOffset(); // t_return // Optional expression IASTInitializerClause expr = null; final int lt1 = LT(1); if (lt1 == IToken.tLBRACE) { expr= bracedInitList(true); } else if (lt1 != IToken.tSEMI) { expr = expression(); } // Semicolon final int endOffset= consumeOrEOC(IToken.tSEMI).getEndOffset(); return setRange(nodeFactory.newReturnStatement(expr), offset, endOffset); } }