| /******************************************************************************* |
| * Copyright (c) 2005, 2012 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 Rational Software) - Initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| * Ed Swartz (Nokia) |
| * Mike Kucera (IBM) - bug #206952 |
| * Sergey Prigogin (Google) |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.dom.parser.c; |
| |
| 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.IASTAttribute; |
| import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; |
| 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.IASTFieldDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFieldReference; |
| 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.IASTFunctionDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTIdExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTIfStatement; |
| 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.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; |
| 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.IASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; |
| 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.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IScope; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTArrayDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTPointer; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICASTTypedefNameSpecifier; |
| import org.eclipse.cdt.core.dom.ast.c.ICNodeFactory; |
| import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.gnu.c.IGCCASTArrayRangeDesignator; |
| import org.eclipse.cdt.core.dom.parser.IExtensionToken; |
| import org.eclipse.cdt.core.dom.parser.c.ICParserExtensionConfiguration; |
| 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.core.parser.util.CollectionUtils; |
| 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.IASTAmbiguousExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement; |
| |
| /** |
| * Source parser for gnu-c syntax. |
| */ |
| public class GNUCSourceParser extends AbstractGNUSourceCodeParser { |
| private static final int DEFAULT_POINTEROPS_LIST_SIZE = 4; |
| private static final int DEFAULT_PARAMETERS_LIST_SIZE = 4; |
| |
| private final boolean supportGCCStyleDesignators; |
| private IIndex index; |
| protected IASTTranslationUnit translationUnit; |
| |
| private int fPreventKnrCheck= 0; |
| |
| private final ICNodeFactory nodeFactory; |
| |
| public GNUCSourceParser(IScanner scanner, ParserMode parserMode, |
| IParserLogService logService, ICParserExtensionConfiguration config) { |
| this(scanner, parserMode, logService, config, null); |
| } |
| |
| public GNUCSourceParser(IScanner scanner, ParserMode parserMode, |
| IParserLogService logService, ICParserExtensionConfiguration config, |
| IIndex index) { |
| super(scanner, logService, parserMode, CNodeFactory.getDefault(), |
| config.supportStatementsInExpressions(), |
| config.supportTypeofUnaryExpressions(), |
| config.supportAlignOfUnaryExpression(), |
| config.supportKnRC(), |
| config.supportAttributeSpecifiers(), |
| config.supportDeclspecSpecifiers(), |
| config.getBuiltinBindingsProvider()); |
| supportGCCStyleDesignators = config.supportGCCStyleDesignators(); |
| supportParameterInfoBlock= config.supportParameterInfoBlock(); |
| supportExtendedSizeofOperator= config.supportExtendedSizeofOperator(); |
| supportFunctionStyleAsm= config.supportFunctionStyleAssembler(); |
| this.index= index; |
| this.nodeFactory = CNodeFactory.getDefault(); |
| } |
| |
| @Override |
| protected IASTInitializer optionalInitializer(IASTDeclarator dtor, DeclarationOptions options) throws EndOfFileException, BacktrackException { |
| if (LTcatchEOF(1) == IToken.tASSIGN) { |
| final int offset= consume().getOffset(); |
| IASTInitializerClause initClause = initClause(false); |
| IASTEqualsInitializer result= nodeFactory.newEqualsInitializer(initClause); |
| return setRange(result, offset, calculateEndOffset(initClause)); |
| } |
| return null; |
| } |
| |
| private IASTInitializerClause initClause(boolean inAggregate) throws EndOfFileException, BacktrackException { |
| final int offset = LA(1).getOffset(); |
| if (LT(1) != IToken.tLBRACE) { |
| IASTExpression assignmentExpression= expression(ExprKind.eAssignment); |
| if (inAggregate && skipTrivialExpressionsInAggregateInitializers) { |
| if (!ASTQueries.canContainName(assignmentExpression)) |
| return null; |
| } |
| return assignmentExpression; |
| } |
| |
| // it's an aggregate initializer |
| consume(IToken.tLBRACE); |
| IASTInitializerList result = nodeFactory.newInitializerList(); |
| |
| // bug 196468, gcc accepts empty braces. |
| if (supportGCCStyleDesignators && LT(1) == IToken.tRBRACE) { |
| int endOffset= consume().getEndOffset(); |
| setRange(result, offset, endOffset); |
| return result; |
| } |
| |
| for (;;) { |
| final int checkOffset= LA(1).getOffset(); |
| // required at least one initializer list |
| // get designator list |
| List<? extends ICASTDesignator> designator= designatorList(); |
| if (designator == null) { |
| IASTInitializerClause clause= initClause(true); |
| // depending on value of skipTrivialItemsInCompoundInitializers initializer may be null |
| // in any way add the initializer such that the actual size can be tracked. |
| result.addClause(clause); |
| } else { |
| ICASTDesignatedInitializer desigInitializer = nodeFactory.newDesignatedInitializer((IASTInitializerClause) null); |
| setRange(desigInitializer, designator.get(0)); |
| for (ICASTDesignator d : designator) { |
| desigInitializer.addDesignator(d); |
| } |
| |
| if (LT(1) != IToken.tEOC) { |
| // Gnu extension: the assign operator is optional |
| if (LT(1) == IToken.tASSIGN) |
| consume(IToken.tASSIGN); |
| |
| IASTInitializerClause clause= initClause(false); |
| desigInitializer.setOperand(clause); |
| adjustLength(desigInitializer, clause); |
| } |
| result.addClause(desigInitializer); |
| } |
| |
| // can end with ", }" or "}" |
| boolean canContinue= LT(1) == IToken.tCOMMA; |
| if (canContinue) |
| consume(); |
| |
| switch (LT(1)) { |
| case IToken.tRBRACE: |
| int lastOffset = consume().getEndOffset(); |
| setRange(result, offset, lastOffset); |
| return result; |
| |
| case IToken.tEOC: |
| setRange(result, offset, LA(1).getOffset()); |
| return result; |
| } |
| |
| if (!canContinue || LA(1).getOffset() == checkOffset) { |
| throwBacktrack(offset, LA(1).getEndOffset() - offset); |
| } |
| } |
| // consume the closing brace |
| } |
| |
| |
| private List<? extends ICASTDesignator> designatorList() throws EndOfFileException, BacktrackException { |
| final int lt1= LT(1); |
| if (lt1 == IToken.tDOT || lt1 == IToken.tLBRACKET) { |
| List<ICASTDesignator> designatorList= null; |
| while (true) { |
| switch (LT(1)) { |
| case IToken.tDOT: |
| int offset = consume().getOffset(); |
| IASTName n = identifier(); |
| ICASTFieldDesignator fieldDesignator = nodeFactory.newFieldDesignator(n); |
| setRange(fieldDesignator, offset, calculateEndOffset(n)); |
| if (designatorList == null) |
| designatorList = new ArrayList<ICASTDesignator>(DEFAULT_DESIGNATOR_LIST_SIZE); |
| designatorList.add(fieldDesignator); |
| break; |
| |
| case IToken.tLBRACKET: |
| offset = consume().getOffset(); |
| IASTExpression constantExpression = expression(); |
| if (supportGCCStyleDesignators && LT(1) == IToken.tELLIPSIS) { |
| consume(IToken.tELLIPSIS); |
| IASTExpression constantExpression2 = expression(); |
| int lastOffset = consume(IToken.tRBRACKET).getEndOffset(); |
| IGCCASTArrayRangeDesignator designator = nodeFactory.newArrayRangeDesignatorGCC(constantExpression, constantExpression2); |
| setRange(designator, offset, lastOffset); |
| if (designatorList == null) |
| designatorList = new ArrayList<ICASTDesignator>(DEFAULT_DESIGNATOR_LIST_SIZE); |
| designatorList.add(designator); |
| } else { |
| int lastOffset = consume(IToken.tRBRACKET).getEndOffset(); |
| ICASTArrayDesignator designator = nodeFactory.newArrayDesignator(constantExpression); |
| setRange(designator, offset, lastOffset); |
| if (designatorList == null) |
| designatorList = new ArrayList<ICASTDesignator>(DEFAULT_DESIGNATOR_LIST_SIZE); |
| designatorList.add(designator); |
| } |
| break; |
| |
| default: |
| return designatorList; |
| } |
| } |
| } |
| |
| // fix for 84176: if reach identifier and it's not a designator then return empty designator list |
| if (supportGCCStyleDesignators && lt1 == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) { |
| int offset= LA(1).getOffset(); |
| IASTName n = identifier(); |
| int lastOffset = consume(IToken.tCOLON).getEndOffset(); |
| ICASTFieldDesignator designator = nodeFactory.newFieldDesignator(n); |
| setRange(designator, offset, lastOffset); |
| return Collections.singletonList(designator); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| protected IASTDeclaration declaration(final DeclarationOptions declOption) throws EndOfFileException, BacktrackException { |
| switch (LT(1)) { |
| case IToken.t_asm: |
| return asmDeclaration(); |
| case IToken.tSEMI: |
| IToken semi= consume(); |
| IASTDeclSpecifier declspec= nodeFactory.newSimpleDeclSpecifier(); |
| IASTSimpleDeclaration decl= nodeFactory.newSimpleDeclaration(declspec); |
| decl.setDeclSpecifier(declspec); |
| ((ASTNode) declspec).setOffsetAndLength(semi.getOffset(), 0); |
| ((ASTNode) decl).setOffsetAndLength(semi.getOffset(), semi.getLength()); |
| return decl; |
| } |
| |
| return simpleDeclaration(declOption); |
| } |
| |
| private IASTDeclaration simpleDeclaration(final 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) { |
| 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}; |
| 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= ArrayUtil.append( IASTDeclarator.class, declarators, dtor); |
| } |
| declarators= 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.tLBRACE: |
| return functionDefinition(firstOffset, declSpec, declarators); |
| |
| default: |
| insertSemi= true; |
| if (declOption == DeclarationOptions.LOCAL) { |
| endOffset= figureEndOffset(declSpec, declarators); |
| if (firstOffset != endOffset) { |
| break; |
| } |
| } else { |
| if (markBeforDtor != null) { |
| endOffset= calculateEndOffset(declSpec); |
| if (firstOffset != endOffset && !isOnSameLine(endOffset, markBeforDtor.getOffset())) { |
| backup(markBeforDtor); |
| declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY; |
| break; |
| } |
| } |
| endOffset= figureEndOffset(declSpec, declarators); |
| if (lt1 == 0) { |
| break; |
| } |
| if (firstOffset != endOffset) { |
| if (!isOnSameLine(endOffset, LA(1).getOffset())) { |
| break; |
| } |
| if (declarators.length == 1 && declarators[0] instanceof IASTFunctionDeclarator) { |
| break; |
| } |
| } |
| } |
| throwBacktrack(LA(1)); |
| } |
| |
| // no function body |
| IASTSimpleDeclaration simpleDeclaration = nodeFactory.newSimpleDeclaration(declSpec); |
| for (IASTDeclarator declarator : declarators) |
| simpleDeclaration.addDeclarator(declarator); |
| |
| setRange(simpleDeclaration, firstOffset, endOffset); |
| if (altDeclSpec != null && altDtor != null) { |
| simpleDeclaration = new CASTAmbiguousSimpleDeclaration(simpleDeclaration, altDeclSpec, altDtor); |
| setRange(simpleDeclaration, firstOffset, endOffset); |
| } |
| |
| if (insertSemi) { |
| IASTProblem problem= createProblem(IProblem.MISSING_SEMICOLON, endOffset-1, 1); |
| throwBacktrack(problem, simpleDeclaration); |
| } |
| return simpleDeclaration; |
| } |
| |
| private IASTDeclaration functionDefinition(int firstOffset, IASTDeclSpecifier declSpec, |
| IASTDeclarator[] declarators) throws BacktrackException, EndOfFileException { |
| if (declarators.length != 1) |
| throwBacktrack(firstOffset, LA(1).getEndOffset()); |
| |
| final IASTDeclarator outerDtor= declarators[0]; |
| final IASTDeclarator fdtor= ASTQueries.findTypeRelevantDeclarator(outerDtor); |
| if (!(fdtor instanceof IASTFunctionDeclarator)) |
| throwBacktrack(firstOffset, LA(1).getEndOffset() - firstOffset); |
| |
| IASTFunctionDefinition funcDefinition = nodeFactory.newFunctionDefinition(declSpec, (IASTFunctionDeclarator) fdtor, null); |
| |
| try { |
| IASTStatement s= handleFunctionBody(); |
| funcDefinition.setBody(s); |
| ((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(s) - firstOffset); |
| |
| return funcDefinition; |
| } catch (BacktrackException bt) { |
| final IASTNode n= bt.getNodeBeforeProblem(); |
| if (n instanceof IASTCompoundStatement) { |
| funcDefinition.setBody((IASTCompoundStatement) n); |
| ((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(n) - firstOffset); |
| throwBacktrack(bt.getProblem(), funcDefinition); |
| } |
| throw bt; |
| } |
| } |
| |
| |
| @Override |
| protected void setupTranslationUnit() throws DOMException { |
| translationUnit = nodeFactory.newTranslationUnit(scanner); |
| translationUnit.setIndex(index); |
| |
| // 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); |
| } |
| } |
| } |
| |
| @Override |
| protected IASTExpression expression() throws BacktrackException, EndOfFileException { |
| return expression(ExprKind.eExpression); |
| } |
| |
| @Override |
| protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { |
| return expression(ExprKind.eConstant); |
| } |
| |
| private IASTExpression expression(final ExprKind kind) throws EndOfFileException, BacktrackException { |
| final boolean allowComma= kind == ExprKind.eExpression; |
| boolean allowAssignment= kind != ExprKind.eConstant; |
| int lt1; |
| int conditionCount= 0; |
| BinaryOperator lastOperator= null; |
| IASTExpression lastExpression= castExpression(CastExprCtx.eDirectlyInBExpr, null); |
| loop: while (true) { |
| 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, lastExpression, lt1, 25, 0); |
| if (LT(2) == IToken.tCOLON) { |
| // Gnu extension: The expression after '?' can be omitted. |
| consume(); // Consume operator |
| lastExpression= null; // Next cast expression is just null |
| continue; |
| } |
| allowAssignment= true; // assignment expressions will be subsumed by the conditional expression |
| break; |
| |
| case IToken.tCOLON: |
| if (--conditionCount < 0) |
| break loop; |
| |
| // <logical-or> ? <expression> : <assignment-expression> |
| // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 0, 15); |
| allowAssignment= true; // assignment expressions will be subsumed by the conditional expression |
| break; |
| |
| case IToken.tCOMMA: |
| if (!allowComma && conditionCount == 0) |
| break loop; |
| // Lowest precedence except inside the conditional expression |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, 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) |
| break loop; |
| // Assignments group right to left |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 21, 20); |
| break; |
| |
| case IToken.tOR: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 30, 31); |
| break; |
| case IToken.tAND: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 40, 41); |
| break; |
| case IToken.tBITOR: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 50, 51); |
| break; |
| case IToken.tXOR: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 60, 61); |
| break; |
| case IToken.tAMPER: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 70, 71); |
| break; |
| case IToken.tEQUAL: |
| case IToken.tNOTEQUAL: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 80, 81); |
| break; |
| case IToken.tGT: |
| case IToken.tLT: |
| case IToken.tLTEQUAL: |
| case IToken.tGTEQUAL: |
| case IGCCToken.tMAX: |
| case IGCCToken.tMIN: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 90, 91); |
| break; |
| case IToken.tSHIFTL: |
| case IToken.tSHIFTR: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 100, 101); |
| break; |
| case IToken.tPLUS: |
| case IToken.tMINUS: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 110, 111); |
| break; |
| case IToken.tSTAR: |
| case IToken.tDIV: |
| case IToken.tMOD: |
| lastOperator= new BinaryOperator(lastOperator, lastExpression, lt1, 120, 121); |
| break; |
| default: |
| break loop; |
| } |
| |
| consume(); // consume operator |
| lastExpression= castExpression(CastExprCtx.eDirectlyInBExpr, null); // next cast expression |
| } |
| |
| // Check for incomplete conditional expression |
| if (lt1 != IToken.tEOC && conditionCount > 0) |
| throwBacktrack(LA(1)); |
| |
| return buildExpression(lastOperator, lastExpression); |
| } |
| |
| @Override |
| protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr1, IASTInitializerClause expr2, int lastOffset) { |
| IASTBinaryExpression result = nodeFactory.newBinaryExpression(operator, expr1, (IASTExpression) expr2); |
| int o = ((ASTNode) expr1).getOffset(); |
| ((ASTNode) result).setOffsetAndLength(o, lastOffset - o); |
| 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_sizeof: |
| 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); |
| default: |
| return postfixExpression(ctx, strat); |
| } |
| } |
| |
| private IASTExpression postfixExpression(CastExprCtx ctx, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { |
| IASTExpression firstExpression = null; |
| switch (LT(1)) { |
| case IToken.tLPAREN: |
| // ( 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 = (IASTInitializerList) initClause(false); |
| firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); |
| setRange(firstExpression, offset, calculateEndOffset(i)); |
| break; |
| } |
| } catch (BacktrackException bt) { |
| } |
| backup(m); |
| firstExpression= primaryExpression(ctx, strat); |
| break; |
| |
| default: |
| firstExpression = primaryExpression(ctx, strat); |
| break; |
| } |
| |
| IASTExpression secondExpression = null; |
| for (;;) { |
| switch (LT(1)) { |
| case IToken.tLBRACKET: |
| // array access |
| consume(); |
| secondExpression = expression(); |
| int last; |
| switch (LT(1)) { |
| case IToken.tRBRACKET: |
| last = consume().getEndOffset(); |
| break; |
| case IToken.tEOC: |
| last = Integer.MAX_VALUE; |
| break; |
| default: |
| throw backtrack; |
| } |
| |
| IASTArraySubscriptExpression s = nodeFactory.newArraySubscriptExpression(firstExpression, secondExpression); |
| ((ASTNode) s).setOffsetAndLength(((ASTNode) firstExpression).getOffset(), |
| last - ((ASTNode) firstExpression).getOffset()); |
| firstExpression = s; |
| break; |
| case IToken.tLPAREN: |
| // function call |
| int endOffset; |
| List<IASTExpression> argList= null; |
| consume(IToken.tLPAREN); |
| boolean isFirst= true; |
| while (true) { |
| final int lt1= LT(1); |
| if (lt1 == IToken.tRPAREN) { |
| endOffset= consume().getEndOffset(); |
| break; |
| } else if (lt1 == IToken.tEOC) { |
| endOffset= LA(1).getEndOffset(); |
| break; |
| } |
| if (isFirst) { |
| isFirst= false; |
| } else { |
| consume(IToken.tCOMMA); |
| } |
| |
| IASTExpression expr= expression(ExprKind.eAssignment); |
| if (argList == null) { |
| argList= new ArrayList<IASTExpression>(); |
| } |
| argList.add(expr); |
| } |
| |
| final IASTExpression[] args; |
| if (argList == null) { |
| args= IASTExpression.EMPTY_EXPRESSION_ARRAY; |
| } else { |
| args= argList.toArray(new IASTExpression[argList.size()]); |
| } |
| IASTFunctionCallExpression f = nodeFactory.newFunctionCallExpression(firstExpression, args); |
| firstExpression = setRange(f, firstExpression, endOffset); |
| break; |
| case IToken.tINCR: |
| int offset = consume().getEndOffset(); |
| firstExpression = buildUnaryExpression( |
| IASTUnaryExpression.op_postFixIncr, firstExpression, |
| ((ASTNode) firstExpression).getOffset(), offset); |
| break; |
| case IToken.tDECR: |
| offset = consume().getEndOffset(); |
| firstExpression = buildUnaryExpression( |
| IASTUnaryExpression.op_postFixDecr, firstExpression, |
| ((ASTNode) firstExpression).getOffset(), offset); |
| break; |
| case IToken.tDOT: |
| // member access |
| IToken dot = consume(); |
| IASTName name = identifier(); |
| if (name == null) |
| throwBacktrack(((ASTNode) firstExpression).getOffset(), |
| ((ASTNode) firstExpression).getLength() + dot.getLength()); |
| IASTFieldReference result = nodeFactory.newFieldReference(name, firstExpression); |
| result.setIsPointerDereference(false); |
| ((ASTNode) result).setOffsetAndLength( |
| ((ASTNode) firstExpression).getOffset(), |
| calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset()); |
| firstExpression = result; |
| break; |
| case IToken.tARROW: |
| // member access |
| IToken arrow = consume(); |
| name = identifier(); |
| if (name == null) |
| throwBacktrack(((ASTNode) firstExpression).getOffset(), |
| ((ASTNode) firstExpression).getLength() + arrow.getLength()); |
| result = nodeFactory.newFieldReference(name, firstExpression); |
| result.setIsPointerDereference(true); |
| ((ASTNode) result).setOffsetAndLength( |
| ((ASTNode) firstExpression).getOffset(), |
| calculateEndOffset(name) - ((ASTNode) firstExpression).getOffset()); |
| firstExpression = result; |
| break; |
| default: |
| return firstExpression; |
| } |
| } |
| } |
| |
| @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: |
| t = consume(); |
| literalExpression = nodeFactory.newLiteralExpression(IASTLiteralExpression.lk_string_literal, t.getImage()); |
| ((ASTNode) literalExpression).setOffsetAndLength(t.getOffset(), t.getEndOffset() - t.getOffset()); |
| return literalExpression; |
| 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.getLength()); |
| return literalExpression; |
| case IToken.tLPAREN: |
| if (supportStatementsInExpressions && LT(2) == IToken.tLBRACE) { |
| return compoundStatementExpression(); |
| } |
| t = consume(); |
| IASTExpression lhs = expression(ExprKind.eExpression); // instead of expression(), to keep the stack smaller |
| int finalOffset = 0; |
| 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.tCOMPLETION: |
| case IToken.tEOC: |
| int startingOffset = LA(1).getOffset(); |
| IASTName name = identifier(); |
| IASTIdExpression idExpression = nodeFactory.newIdExpression(name); |
| ((ASTNode) idExpression).setOffsetAndLength((ASTNode) name); |
| return idExpression; |
| default: |
| IToken la = LA(1); |
| startingOffset = la.getOffset(); |
| throwBacktrack(startingOffset, la.getLength()); |
| return null; |
| } |
| |
| } |
| |
| |
| @Override |
| protected IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException, BacktrackException { |
| if (!canBeTypeSpecifier()) { |
| return null; |
| } |
| final int offset = mark().getOffset(); |
| IASTDeclSpecifier declSpecifier = null; |
| IASTDeclarator declarator = null; |
| |
| fPreventKnrCheck++; |
| try { |
| Decl decl= declSpecifierSequence_initDeclarator(option, false); |
| declSpecifier= decl.fDeclSpec1; |
| declarator= decl.fDtor1; |
| } catch (FoundAggregateInitializer lie) { |
| // type-ids have not compound initializers |
| throwBacktrack(lie.fDeclarator); |
| } finally { |
| fPreventKnrCheck--; |
| } |
| |
| IASTTypeId result = nodeFactory.newTypeId(declSpecifier, declarator); |
| setRange(result, offset, figureEndOffset(declSpecifier, declarator)); |
| return result; |
| } |
| |
| /** |
| * Parse a Pointer Operator. |
| * |
| * ptrOperator : "*" (cvQualifier)* | "&" | ::? nestedNameSpecifier "*" |
| * (cvQualifier)* |
| * |
| * @throws BacktrackException to request a backtrack |
| */ |
| protected void consumePointerOperators(List<IASTPointerOperator> pointerOps) |
| throws EndOfFileException, BacktrackException { |
| for (;;) { |
| // __attribute__ in-between pointers |
| __attribute_decl_seq(supportAttributeSpecifiers, false); |
| |
| IToken mark = mark(); |
| IToken last = null; |
| |
| boolean isConst = false, isVolatile = false, isRestrict = false; |
| |
| if (LT(1) != IToken.tSTAR) { |
| backup(mark); |
| break; |
| } |
| |
| last = consume(); |
| int startOffset = mark.getOffset(); |
| for (;;) { |
| IToken t = LA(1); |
| switch (LT(1)) { |
| case IToken.t_const: |
| last = consume(); |
| isConst = true; |
| break; |
| case IToken.t_volatile: |
| last = consume(); |
| isVolatile = true; |
| break; |
| case IToken.t_restrict: |
| last = consume(); |
| isRestrict = true; |
| break; |
| } |
| |
| if (t == LA(1)) |
| break; |
| } |
| |
| ICASTPointer po = nodeFactory.newPointer(); |
| ((ASTNode) po).setOffsetAndLength(startOffset, last.getEndOffset() - startOffset); |
| po.setConst(isConst); |
| po.setVolatile(isVolatile); |
| po.setRestrict(isRestrict); |
| pointerOps.add(po); |
| } |
| } |
| |
| |
| private final static int INLINE=0x1, CONST=0x2, RESTRICT=0x4, VOLATILE=0x8, |
| SHORT=0x10, UNSIGNED= 0x20, SIGNED=0x40, COMPLEX=0x80, IMAGINARY=0x100; |
| |
| @Override |
| protected Decl declSpecifierSeq(final DeclarationOptions declOption) throws BacktrackException, EndOfFileException { |
| int storageClass= IASTDeclSpecifier.sc_unspecified; |
| int simpleType= IASTSimpleDeclSpecifier.t_unspecified; |
| int options= 0; |
| int isLong= 0; |
| |
| IToken returnToken= null; |
| IASTDeclSpecifier result= null; |
| IASTDeclSpecifier altResult= null; |
| try { |
| IASTName identifier= null; |
| IASTExpression typeofExpression= null; |
| IASTProblem problem= null; |
| |
| 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: // eof |
| break declSpecifiers; |
| // storage class specifiers |
| case IToken.t_auto: |
| 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_typedef: |
| storageClass = IASTDeclSpecifier.sc_typedef; |
| endOffset= consume().getEndOffset(); |
| break; |
| |
| // Function Specifier |
| case IToken.t_inline: |
| options |= INLINE; |
| endOffset= consume().getEndOffset(); |
| break; |
| |
| // Type Qualifiers |
| 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; |
| |
| // Type Specifiers |
| case IToken.t_void: |
| if (encounteredTypename) |
| break declSpecifiers; |
| simpleType = IASTSimpleDeclSpecifier.t_void; |
| encounteredRawType= true; |
| 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_short: |
| if (encounteredTypename) |
| break declSpecifiers; |
| options |= SHORT; |
| 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_long: |
| if (encounteredTypename) |
| break declSpecifiers; |
| isLong++; |
| 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_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__Bool: |
| if (encounteredTypename) |
| break declSpecifiers; |
| simpleType = IASTSimpleDeclSpecifier.t_bool; |
| 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.tIDENTIFIER: |
| case IToken.tCOMPLETION: |
| case IToken.tEOC: |
| if (encounteredTypename || encounteredRawType) |
| break declSpecifiers; |
| |
| if ((endOffset != offset || declOption.fAllowEmptySpecifier) && LT(1) != IToken.tCOMPLETION) { |
| altResult= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset); |
| returnToken= mark(); |
| } |
| |
| identifier = identifier(); |
| endOffset= calculateEndOffset(identifier); |
| encounteredTypename= true; |
| break; |
| case IToken.t_struct: |
| case IToken.t_union: |
| if (encounteredTypename || encounteredRawType) |
| break declSpecifiers; |
| try { |
| result= structOrUnionSpecifier(); |
| } catch (BacktrackException bt) { |
| result= elaboratedTypeSpecifier(); |
| } |
| endOffset= calculateEndOffset(result); |
| encounteredTypename= true; |
| break; |
| case IToken.t_enum: |
| if (encounteredTypename || encounteredRawType) |
| break declSpecifiers; |
| try { |
| result= enumSpecifier(); |
| } catch (BacktrackException bt) { |
| if (bt.getNodeBeforeProblem() instanceof IASTDeclSpecifier) { |
| result= (IASTDeclSpecifier) bt.getNodeBeforeProblem(); |
| problem = bt.getProblem(); |
| break declSpecifiers; |
| } else { |
| result= elaboratedTypeSpecifier(); |
| } |
| } |
| 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; |
| |
| default: |
| if (lt1 >= IExtensionToken.t__otherDeclSpecModifierFirst && lt1 <= IExtensionToken.t__otherDeclSpecModifierLast) { |
| handleOtherDeclSpecModifier(); |
| endOffset= LA(1).getOffset(); |
| break; |
| } |
| break declSpecifiers; |
| } |
| |
| if (encounteredRawType && encounteredTypename) |
| throwBacktrack(LA(1)); |
| } |
| |
| // check for empty specification |
| if (!encounteredRawType && !encounteredTypename && LT(1) != IToken.tEOC && !declOption.fAllowEmptySpecifier) { |
| if (offset == endOffset) { |
| throwBacktrack(LA(1)); |
| } |
| } |
| |
| if (result != null) { |
| configureDeclSpec(result, storageClass, options); |
| if ((options & RESTRICT) != 0) { |
| if (result instanceof ICASTCompositeTypeSpecifier) { |
| ((ICASTCompositeTypeSpecifier) result).setRestrict(true); |
| } else if (result instanceof CASTEnumerationSpecifier) { |
| ((CASTEnumerationSpecifier) result).setRestrict(true); |
| } else if (result instanceof CASTElaboratedTypeSpecifier) { |
| ((CASTElaboratedTypeSpecifier) result).setRestrict(true); |
| } |
| } |
| setRange(result, offset, endOffset); |
| if (problem != null) |
| throwBacktrack(problem, result); |
| } else if (identifier != null) { |
| result= buildNamedTypeSpecifier(identifier, 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 ICASTTypedefNameSpecifier buildNamedTypeSpecifier(IASTName name, int storageClass, |
| int options, int offset, int endOffset) { |
| ICASTTypedefNameSpecifier declSpec = nodeFactory.newTypedefNameSpecifier(name); |
| configureDeclSpec(declSpec, storageClass, options); |
| declSpec.setRestrict((options & RESTRICT) != 0); |
| ((ASTNode) declSpec).setOffsetAndLength(offset, endOffset - offset); |
| return declSpec; |
| } |
| |
| private ICASTSimpleDeclSpecifier buildSimpleDeclSpec(int storageClass, int simpleType, |
| int options, int isLong, IASTExpression typeofExpression, int offset, int endOffset) { |
| ICASTSimpleDeclSpecifier declSpec= nodeFactory.newSimpleDeclSpecifier(); |
| |
| configureDeclSpec(declSpec, storageClass, options); |
| declSpec.setType(simpleType); |
| declSpec.setLong(isLong == 1); |
| declSpec.setLongLong(isLong > 1); |
| declSpec.setRestrict((options & RESTRICT) != 0); |
| declSpec.setUnsigned((options & UNSIGNED) != 0); |
| declSpec.setSigned((options & SIGNED) != 0); |
| declSpec.setShort((options & SHORT) != 0); |
| declSpec.setComplex((options & COMPLEX) != 0); |
| declSpec.setImaginary((options & IMAGINARY) != 0); |
| if (typeofExpression != null) { |
| declSpec.setDeclTypeExpression(typeofExpression); |
| typeofExpression.setParent(declSpec); |
| } |
| |
| ((ASTNode) declSpec).setOffsetAndLength(offset, endOffset - offset); |
| return declSpec; |
| } |
| |
| private void configureDeclSpec(IASTDeclSpecifier declSpec, int storageClass, int options) { |
| declSpec.setStorageClass(storageClass); |
| declSpec.setConst((options & CONST) != 0); |
| declSpec.setVolatile((options & VOLATILE) != 0); |
| declSpec.setInline((options & INLINE) != 0); |
| } |
| |
| /** |
| * Parse a class/struct/union definition. |
| * |
| * classSpecifier : classKey name (baseClause)? "{" (memberSpecification)* |
| * "}" |
| * |
| * @throws BacktrackException to request a backtrack |
| */ |
| protected ICASTCompositeTypeSpecifier structOrUnionSpecifier() throws BacktrackException, EndOfFileException { |
| int classKind = 0; |
| IToken mark= mark(); |
| final int offset= mark.getOffset(); |
| |
| // class key |
| switch (LT(1)) { |
| case IToken.t_struct: |
| consume(); |
| classKind = IASTCompositeTypeSpecifier.k_struct; |
| break; |
| case IToken.t_union: |
| consume(); |
| classKind = IASTCompositeTypeSpecifier.k_union; |
| break; |
| default: |
| throwBacktrack(LA(1)); |
| return null; // line 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 = identifier(); |
| } |
| |
| // if __attribute__ or __declspec occurs after struct/union/class identifier and before the { or ; |
| __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); |
| |
| if (LT(1) != IToken.tLBRACE) { |
| IToken errorPoint = LA(1); |
| backup(mark); |
| throwBacktrack(errorPoint); |
| } |
| |
| if (name == null) { |
| name= nodeFactory.newName(); |
| } |
| ICASTCompositeTypeSpecifier result = nodeFactory.newCompositeTypeSpecifier(classKind, name); |
| declarationListInBraces(result, offset, DeclarationOptions.C_MEMBER); |
| return result; |
| } |
| |
| protected IASTElaboratedTypeSpecifier elaboratedTypeSpecifier() throws BacktrackException, EndOfFileException { |
| // this is an elaborated class specifier |
| IToken t = consume(); |
| int eck = 0; |
| |
| switch (t.getType()) { |
| 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: |
| backup(t); |
| throwBacktrack(t.getOffset(), t.getLength()); |
| } |
| |
| // if __attribute__ or __declspec occurs after struct/union/class and before the identifier |
| __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); |
| |
| IASTName name = identifier(); |
| IASTElaboratedTypeSpecifier result = nodeFactory.newElaboratedTypeSpecifier(eck, name); |
| ((ASTNode) result).setOffsetAndLength(t.getOffset(), calculateEndOffset(name) - t.getOffset()); |
| return result; |
| } |
| |
| @Override |
| protected IASTDeclarator initDeclarator(IASTDeclSpecifier declspec, final DeclarationOptions option) |
| throws EndOfFileException, BacktrackException, FoundAggregateInitializer { |
| IASTDeclarator d = declarator(declspec, option); |
| |
| final int lt1= LTcatchEOF(1); |
| if (lt1 == IToken.tLBRACE) { |
| if (!(ASTQueries.findTypeRelevantDeclarator(d) instanceof IASTFunctionDeclarator)) { |
| throwBacktrack(LA(1)); |
| } |
| } |
| |
| if (lt1 == IToken.tASSIGN && LT(2) == IToken.tLBRACE) |
| throw new FoundAggregateInitializer(declspec, d); |
| |
| IASTInitializer i = optionalInitializer(d, option); |
| if (i != null) { |
| d.setInitializer(i); |
| ((ASTNode) d).setLength(calculateEndOffset(i) - ((ASTNode) d).getOffset()); |
| } |
| return d; |
| } |
| |
| protected IASTDeclarator declarator(IASTDeclSpecifier declSpec, DeclarationOptions option) throws EndOfFileException, BacktrackException { |
| final int startingOffset = LA(1).getOffset(); |
| int endOffset = startingOffset; |
| |
| List<IASTPointerOperator> pointerOps = new ArrayList<IASTPointerOperator>(DEFAULT_POINTEROPS_LIST_SIZE); |
| consumePointerOperators(pointerOps); |
| if (!pointerOps.isEmpty()) { |
| endOffset = calculateEndOffset(pointerOps.get(pointerOps.size() - 1)); |
| } |
| |
| // Accept __attribute__ or __declspec between pointer operators and declarator. |
| List<IASTAttribute> attributes = |
| __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); |
| |
| // Look for identifier or nested declarator |
| final int lt1= LT(1); |
| if (lt1 == IToken.tIDENTIFIER) { |
| if (option.fRequireAbstract) |
| throwBacktrack(LA(1)); |
| |
| final IASTName declaratorName = identifier(); |
| endOffset= calculateEndOffset(declaratorName); |
| return declarator(pointerOps, attributes, declaratorName, null, startingOffset, |
| endOffset, option); |
| } |
| |
| if (lt1 == IToken.tLPAREN) { |
| IASTDeclarator cand1= null; |
| IToken cand1End= null; |
| // try an abstract function declarator |
| if (option.fAllowAbstract) { |
| final IToken mark= mark(); |
| try { |
| cand1= declarator(pointerOps, attributes, nodeFactory.newName(), null, |
| startingOffset, endOffset, option); |
| if (option.fRequireAbstract) |
| return cand1; |
| |
| cand1End= LA(1); |
| } catch (BacktrackException e) { |
| } |
| backup(mark); |
| } |
| // try a nested declarator |
| try { |
| consume(); |
| if (LT(1) == IToken.tRPAREN) |
| throwBacktrack(LA(1)); |
| |
| final IASTDeclarator nested= declarator(declSpec, option); |
| endOffset= consume(IToken.tRPAREN).getEndOffset(); |
| final IASTDeclarator cand2= declarator(pointerOps, attributes, null, nested, |
| startingOffset, endOffset, option); |
| if (cand1 == null || cand1End == null) |
| return cand2; |
| final IToken cand2End= LA(1); |
| if (cand1End == cand2End) { |
| CASTAmbiguousDeclarator result= new CASTAmbiguousDeclarator(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) { |
| throwBacktrack(LA(1)); |
| } |
| return declarator(pointerOps, attributes, nodeFactory.newName(), null, startingOffset, |
| endOffset, option); |
| } |
| |
| private IASTDeclarator declarator(final List<IASTPointerOperator> pointerOps, |
| List<IASTAttribute> attributes, final IASTName declaratorName, |
| final IASTDeclarator nestedDeclarator, final int startingOffset, int endOffset, |
| final DeclarationOptions option) throws EndOfFileException, BacktrackException { |
| IASTDeclarator result= null; |
| int lt1; |
| loop: while (true) { |
| lt1= LTcatchEOF(1); |
| switch (lt1) { |
| case IToken.tLPAREN: |
| result= functionDeclarator(isAbstract(declaratorName, nestedDeclarator) |
| ? DeclarationOptions.PARAMETER : DeclarationOptions.C_PARAMETER_NON_ABSTRACT); |
| setDeclaratorID(result, declaratorName, nestedDeclarator); |
| break loop; |
| |
| case IToken.tLBRACKET: |
| result= arrayDeclarator(); |
| setDeclaratorID(result, declaratorName, nestedDeclarator); |
| break loop; |
| |
| case IToken.tCOLON: |
| if (!option.fAllowBitField) |
| throwBacktrack(LA(1)); |
| |
| result= bitFieldDeclarator(); |
| setDeclaratorID(result, declaratorName, nestedDeclarator); |
| break loop; |
| |
| case IGCCToken.t__attribute__: // if __attribute__ is after a declarator |
| if (!supportAttributeSpecifiers) |
| throwBacktrack(LA(1)); |
| attributes = CollectionUtils.merge(attributes, |
| __attribute_decl_seq(true, supportDeclspecSpecifiers)); |
| break; |
| case IGCCToken.t__declspec: |
| if (!supportDeclspecSpecifiers) |
| throwBacktrack(LA(1)); |
| attributes = CollectionUtils.merge(attributes, |
| __attribute_decl_seq(supportAttributeSpecifiers, true)); |
| break; |
| default: |
| break loop; |
| } |
| } |
| if (lt1 != 0) { |
| attributes = CollectionUtils.merge(attributes, |
| __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers)); |
| } |
| |
| if (result == null) { |
| result= nodeFactory.newDeclarator(null); |
| setDeclaratorID(result, declaratorName, nestedDeclarator); |
| } else { |
| endOffset= calculateEndOffset(result); |
| } |
| |
| if (lt1 != 0 && LT(1) == IToken.t_asm) { // asm labels bug 226121 |
| consume(); |
| endOffset= asmExpression(null).getEndOffset(); |
| |
| __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); |
| } |
| |
| for (IASTPointerOperator po : pointerOps) { |
| result.addPointerOperator(po); |
| } |
| |
| if (attributes != null) { |
| for (IASTAttribute attribute : attributes) { |
| result.addAttribute(attribute); |
| } |
| } |
| |
| ((ASTNode) result).setOffsetAndLength(startingOffset, endOffset - startingOffset); |
| return result; |
| } |
| |
| private boolean isAbstract(IASTName declaratorName, IASTDeclarator nestedDeclarator) { |
| nestedDeclarator= ASTQueries.findInnermostDeclarator(nestedDeclarator); |
| if (nestedDeclarator != null) { |
| declaratorName= nestedDeclarator.getName(); |
| } |
| return declaratorName == null || declaratorName.toCharArray().length == 0; |
| } |
| |
| private void setDeclaratorID(IASTDeclarator declarator, IASTName declaratorName, IASTDeclarator nestedDeclarator) { |
| if (nestedDeclarator != null) { |
| declarator.setNestedDeclarator(nestedDeclarator); |
| declarator.setName(nodeFactory.newName()); |
| } else { |
| declarator.setName(declaratorName); |
| } |
| } |
| |
| private IASTDeclarator functionDeclarator(DeclarationOptions paramOption) throws EndOfFileException, BacktrackException { |
| IToken last = consume(IToken.tLPAREN); |
| int startOffset= last.getOffset(); |
| |
| // check for K&R C parameters (0 means it's not K&R C) |
| if (fPreventKnrCheck == 0 && supportKnRC) { |
| fPreventKnrCheck++; |
| try { |
| final int numKnRCParms = countKnRCParms(); |
| if (numKnRCParms > 0) { // KnR C parameters were found |
| IASTName[] parmNames = new IASTName[numKnRCParms]; |
| IASTDeclaration[] parmDeclarations = new IASTDeclaration[numKnRCParms]; |
| |
| boolean seenParameter= false; |
| for (int i = 0; i <= parmNames.length; i++) { |
| switch (LT(1)) { |
| case IToken.tCOMMA: |
| last = consume(); |
| parmNames[i] = identifier(); |
| seenParameter = true; |
| break; |
| case IToken.tIDENTIFIER: |
| if (seenParameter) |
| throwBacktrack(startOffset, last.getEndOffset() - startOffset); |
| |
| parmNames[i] = identifier(); |
| seenParameter = true; |
| break; |
| case IToken.tRPAREN: |
| last = consume(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // now that the parameter names are parsed, parse the parameter declarations |
| // count for parameter declarations <= count for parameter names. |
| int endOffset= last.getEndOffset(); |
| for (int i = 0; i < numKnRCParms && LT(1) != IToken.tLBRACE; i++) { |
| try { |
| IASTDeclaration decl= simpleDeclaration(DeclarationOptions.LOCAL); |
| IASTSimpleDeclaration ok= checkKnrParameterDeclaration(decl, parmNames); |
| if (ok != null) { |
| parmDeclarations[i]= ok; |
| endOffset= calculateEndOffset(ok); |
| } else { |
| final ASTNode node = (ASTNode) decl; |
| parmDeclarations[i] = createKnRCProblemDeclaration(node.getOffset(), node.getLength()); |
| endOffset= calculateEndOffset(node); |
| } |
| } catch (BacktrackException b) { |
| parmDeclarations[i] = createKnRCProblemDeclaration(b.getOffset(), b.getLength()); |
| endOffset= b.getOffset() + b.getLength(); |
| } |
| } |
| |
| parmDeclarations = ArrayUtil.removeNulls( IASTDeclaration.class, parmDeclarations ); |
| ICASTKnRFunctionDeclarator functionDecltor = nodeFactory.newKnRFunctionDeclarator(parmNames, parmDeclarations); |
| ((ASTNode) functionDecltor).setOffsetAndLength(startOffset, endOffset-startOffset); |
| return functionDecltor; |
| } |
| } finally { |
| fPreventKnrCheck--; |
| } |
| } |
| |
| boolean seenParameter= false; |
| boolean encounteredVarArgs= false; |
| List<IASTParameterDeclaration> parameters= null; |
| int endOffset= last.getEndOffset(); |
| |
| paramLoop: while (true) { |
| switch (LT(1)) { |
| case IToken.tRPAREN: |
| case IToken.tEOC: |
| endOffset= consume().getEndOffset(); |
| break paramLoop; |
| case IToken.tELLIPSIS: |
| endOffset= consume().getEndOffset(); |
| encounteredVarArgs = true; |
| break; |
| case IToken.tCOMMA: |
| endOffset= consume().getEndOffset(); |
| seenParameter = false; |
| break; |
| default: |
| if (seenParameter) |
| throwBacktrack(startOffset, endOffset - startOffset); |
| |
| IASTParameterDeclaration pd = parameterDeclaration(paramOption); |
| endOffset = calculateEndOffset(pd); |
| if (parameters == null) |
| parameters = new ArrayList<IASTParameterDeclaration>(DEFAULT_PARAMETERS_LIST_SIZE); |
| parameters.add(pd); |
| seenParameter = true; |
| break; |
| } |
| } |
| IASTStandardFunctionDeclarator fc = nodeFactory.newFunctionDeclarator(null); |
| fc.setVarArgs(encounteredVarArgs); |
| if (parameters != null) { |
| for (IASTParameterDeclaration pd : parameters) { |
| fc.addParameterDeclaration(pd); |
| } |
| } |
| ((ASTNode) fc).setOffsetAndLength(startOffset, endOffset-startOffset); |
| return fc; |
| } |
| |
| private IASTSimpleDeclaration checkKnrParameterDeclaration(IASTDeclaration decl, final IASTName[] parmNames) { |
| if (!(decl instanceof IASTSimpleDeclaration)) |
| return null; |
| |
| IASTSimpleDeclaration declaration= ((IASTSimpleDeclaration) decl); |
| IASTDeclarator[] decltors = declaration.getDeclarators(); |
| for (IASTDeclarator decltor : decltors) { |
| boolean decltorOk = false; |
| final char[] nchars = ASTQueries.findInnermostDeclarator(decltor).getName().toCharArray(); |
| for (IASTName parmName : parmNames) { |
| if (CharArrayUtils.equals(nchars, parmName.toCharArray())) { |
| decltorOk= true; |
| break; |
| } |
| } |
| if (!decltorOk) |
| return null; |
| } |
| return declaration; |
| } |
| |
| /** |
| * Parse an array declarator starting at the square bracket. |
| */ |
| private IASTArrayDeclarator arrayDeclarator() throws EndOfFileException, BacktrackException { |
| ArrayList<IASTArrayModifier> arrayMods = new ArrayList<IASTArrayModifier>(DEFAULT_POINTEROPS_LIST_SIZE); |
| int start= LA(1).getOffset(); |
| consumeArrayModifiers(arrayMods); |
| if (arrayMods.isEmpty()) |
| throwBacktrack(LA(1)); |
| |
| final int endOffset = calculateEndOffset(arrayMods.get(arrayMods.size() - 1)); |
| final IASTArrayDeclarator 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 IASTFieldDeclarator bitFieldDeclarator() throws EndOfFileException, BacktrackException { |
| int start= consume(IToken.tCOLON).getOffset(); |
| |
| final IASTExpression bitField = constantExpression(); |
| final int endOffset = calculateEndOffset(bitField); |
| |
| IASTFieldDeclarator d = nodeFactory.newFieldDeclarator(null, bitField); |
| d.setBitFieldSize(bitField); |
| |
| ((ASTNode) d).setOffsetAndLength(start, endOffset-start); |
| return d; |
| } |
| |
| |
| @Override |
| protected IASTName identifier() throws EndOfFileException, BacktrackException { |
| final IToken t= LA(1); |
| IASTName n; |
| switch (t.getType()) { |
| case IToken.tIDENTIFIER: |
| consume(); |
| n = nodeFactory.newName(t.getCharImage()); |
| break; |
| |
| case IToken.tCOMPLETION: |
| case IToken.tEOC: |
| consume(); |
| n = nodeFactory.newName(t.getCharImage()); |
| createCompletionNode(t).addName(n); |
| return n; |
| |
| default: |
| throw backtrack; |
| } |
| |
| setRange(n, t.getOffset(), t.getEndOffset()); |
| return n; |
| } |
| |
| protected void consumeArrayModifiers(List<IASTArrayModifier> arrayMods) throws EndOfFileException, BacktrackException { |
| while (LT(1) == IToken.tLBRACKET) { |
| // eat the '[' |
| int startOffset = consume().getOffset(); |
| |
| boolean isStatic = false; |
| boolean isConst = false; |
| boolean isRestrict = false; |
| boolean isVolatile = false; |
| boolean isVarSized = false; |
| |
| outerLoop: do { |
| switch (LT(1)) { |
| case IToken.t_static: |
| isStatic = true; |
| consume(); |
| break; |
| case IToken.t_const: |
| isConst = true; |
| consume(); |
| break; |
| case IToken.t_volatile: |
| isVolatile = true; |
| consume(); |
| break; |
| case IToken.t_restrict: |
| isRestrict = true; |
| consume(); |
| break; |
| case IToken.tSTAR: |
| isVarSized = true; |
| consume(); |
| break outerLoop; |
| default: |
| break outerLoop; |
| } |
| } while (true); |
| |
| IASTExpression exp = null; |
| |
| if (LT(1) != IToken.tRBRACKET) { |
| if (!(isStatic || isRestrict || isConst || isVolatile)) |
| exp = expression(ExprKind.eAssignment); |
| else |
| exp = constantExpression(); |
| } |
| int lastOffset; |
| switch (LT(1)) { |
| case IToken.tRBRACKET: |
| lastOffset = consume().getEndOffset(); |
| break; |
| case IToken.tEOC: |
| lastOffset = Integer.MAX_VALUE; |
| break; |
| default: |
| throw backtrack; |
| } |
| |
| ICASTArrayModifier arrayMod = nodeFactory.newArrayModifier(exp); |
| arrayMod.setStatic(isStatic); |
| arrayMod.setConst(isConst); |
| arrayMod.setVolatile(isVolatile); |
| arrayMod.setRestrict(isRestrict); |
| arrayMod.setVariableSized(isVarSized); |
| ((ASTNode) arrayMod).setOffsetAndLength(startOffset, lastOffset - startOffset); |
| arrayMods.add(arrayMod); |
| } |
| } |
| |
| |
| protected IASTParameterDeclaration parameterDeclaration(DeclarationOptions option) throws BacktrackException, EndOfFileException { |
| final IToken current = LA(1); |
| int startingOffset = current.getOffset(); |
| if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) { |
| skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0); |
| } |
| |
| IASTDeclSpecifier declSpec = null; |
| IASTDeclarator declarator = null; |
| IASTDeclSpecifier altDeclSpec = null; |
| IASTDeclarator altDeclarator = null; |
| |
| try { |
| fPreventKnrCheck++; |
| Decl decl= declSpecifierSequence_initDeclarator(option, false); |
| declSpec= decl.fDeclSpec1; |
| declarator= decl.fDtor1; |
| altDeclSpec= decl.fDeclSpec2; |
| altDeclarator= decl.fDtor2; |
| } catch (FoundAggregateInitializer lie) { |
| declSpec= lie.fDeclSpec; |
| declarator= lie.fDeclarator; |
| } finally { |
| fPreventKnrCheck--; |
| } |
| |
| final int length = figureEndOffset(declSpec, declarator) - startingOffset; |
| IASTParameterDeclaration result = nodeFactory.newParameterDeclaration(declSpec, declarator); |
| ((ASTNode) result).setOffsetAndLength(startingOffset, length); |
| if (altDeclarator != null && altDeclSpec != null) { |
| IASTParameterDeclaration alt = nodeFactory.newParameterDeclaration(altDeclSpec, altDeclarator); |
| ((ASTNode) alt).setOffsetAndLength(startingOffset, length); |
| // order is important, prefer variant with declspec over the one without |
| result= new CASTAmbiguousParameterDeclaration(result, alt); |
| ((ASTNode) result).setOffsetAndLength((ASTNode) alt); |
| } |
| return result; |
| } |
| |
| |
| @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(); |
| default: |
| // can be many things: |
| // label |
| if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) { |
| return parseLabelStatement(); |
| } |
| |
| return parseDeclarationOrExpressionStatement(); |
| } |
| } |
| |
| @Override |
| protected void nullifyTranslationUnit() { |
| translationUnit = null; |
| } |
| |
| |
| private int countKnRCParms() { |
| IToken mark = null; |
| int parmCount = 0; |
| boolean previousWasIdentifier = false; |
| |
| try { |
| mark = mark(); |
| |
| // starts at the beginning of the parameter list |
| for (;;) { |
| if (LT(1) == IToken.tCOMMA) { |
| consume(); |
| previousWasIdentifier = false; |
| } else if (LT(1) == IToken.tIDENTIFIER) { |
| consume(); |
| if (previousWasIdentifier) { |
| backup(mark); |
| return 0; // i.e. KnR C won't have int f(typedef x) |
| // char |
| // x; {} |
| } |
| previousWasIdentifier = true; |
| parmCount++; |
| } else if (LT(1) == IToken.tRPAREN) { |
| if (!previousWasIdentifier) { |
| // if the first token encountered is tRPAREN then it's not K&R C |
| // the first token when counting K&R C parms is always an identifier |
| backup(mark); |
| return 0; |
| } |
| consume(); |
| break; |
| } else { |
| backup(mark); |
| return 0; // i.e. KnR C won't have int f(char) char x; {} |
| } |
| } |
| |
| // if the next token is a tSEMI then the declaration was a regular |
| // declaration statement i.e. int f(type_def); |
| final int lt1= LT(1); |
| if (lt1 == IToken.tSEMI || lt1 == IToken.tLBRACE) { |
| backup(mark); |
| return 0; |
| } |
| |
| // look ahead for the start of the function body, if end of file is |
| // found then return 0 parameters found (implies not KnR C) |
| int previous=-1; |
| while (LT(1) != IToken.tLBRACE) { |
| // fix for 100104: check if the parameter declaration is a valid one |
| try { |
| simpleDeclaration(DeclarationOptions.LOCAL); |
| } catch (BacktrackException e) { |
| backup(mark); |
| return 0; |
| } |
| |
| final IToken t = LA(1); |
| if (t.getType() == IToken.tEOC) |
| break; |
| |
| final int next = t.hashCode(); |
| if (next == previous) { // infinite loop detected |
| break; |
| } |
| previous = next; |
| } |
| |
| backup(mark); |
| return parmCount; |
| } catch (EndOfFileException eof) { |
| if (mark != null) |
| backup(mark); |
| |
| return 0; |
| } |
| } |
| |
| private IASTProblemDeclaration createKnRCProblemDeclaration(int offset, int length) throws EndOfFileException { |
| IASTProblem p = createProblem(IProblem.SYNTAX_ERROR, offset, length); |
| IASTProblemDeclaration pd = nodeFactory.newProblemDeclaration(p); |
| ((ASTNode) pd).setOffsetAndLength((ASTNode) p); |
| |
| // consume until LBRACE is found (to leave off at the function body and |
| // continue from there) |
| IToken previous=null; |
| IToken next=null; |
| while (LT(1) != IToken.tLBRACE) { |
| next = consume(); |
| if (next == previous || next.getType() == IToken.tEOC) { // infinite loop detected |
| break; |
| } |
| previous = next; |
| } |
| |
| return pd; |
| } |
| |
| @Override |
| protected ASTVisitor createAmbiguityNodeVisitor() { |
| return new CASTAmbiguityResolver(); |
| } |
| |
| @Override |
| protected IASTAmbiguousStatement createAmbiguousStatement() { |
| return new CASTAmbiguousStatement(); |
| } |
| |
| @Override |
| protected IASTAmbiguousExpression createAmbiguousExpression() { |
| return new CASTAmbiguousExpression(); |
| } |
| |
| @Override |
| protected IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr) { |
| return new CASTAmbiguousBinaryVsCastExpression(binary, castExpr); |
| } |
| |
| @Override |
| protected IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall) { |
| return new CASTAmbiguousCastVsFunctionCallExpression(castExpr, funcCall); |
| } |
| |
| protected IASTStatement parseIfStatement() throws EndOfFileException, BacktrackException { |
| IASTIfStatement result = null; |
| IASTIfStatement if_statement = null; |
| int start = LA(1).getOffset(); |
| if_loop: while (true) { |
| int so = consume(IToken.t_if).getOffset(); |
| consume(IToken.tLPAREN); |
| // condition |
| IASTExpression condition= condition(true); |
| if (LT(1) == IToken.tEOC) { |
| // Completing in the condition |
| IASTIfStatement new_if = nodeFactory.newIfStatement(condition, null, null); |
| |
| if (if_statement != null) { |
| if_statement.setElseClause(new_if); |
| } |
| return result != null ? result : new_if; |
| } |
| consume(IToken.tRPAREN); |
| |
| IASTStatement thenClause = statement(); |
| IASTIfStatement new_if_statement = nodeFactory.newIfStatement(null, null, null); |
| ((ASTNode) new_if_statement).setOffset(so); |
| if( condition != null ) // shouldn't be possible but failure in condition() makes it so |
| { |
| new_if_statement.setConditionExpression(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; |
| } |
| |
| |
| protected IASTStatement parseSwitchStatement() throws EndOfFileException, BacktrackException { |
| int startOffset; |
| startOffset = consume().getOffset(); |
| consume(IToken.tLPAREN); |
| IASTExpression switch_condition = condition(true); |
| switch (LT(1)) { |
| case IToken.tRPAREN: |
| consume(); |
| break; |
| case IToken.tEOC: |
| break; |
| default: |
| throwBacktrack(LA(1)); |
| } |
| |
| IASTStatement switch_body = parseSwitchBody(); |
| IASTSwitchStatement switch_statement = nodeFactory.newSwitchStatement(switch_condition, switch_body); |
| ((ASTNode) switch_statement).setOffsetAndLength(startOffset, |
| (switch_body != null ? calculateEndOffset(switch_body) : LA(1).getEndOffset()) - startOffset); |
| return switch_statement; |
| } |
| |
| protected IASTStatement parseForStatement() throws EndOfFileException, BacktrackException { |
| int startOffset; |
| startOffset = consume().getOffset(); |
| consume(IToken.tLPAREN); |
| IASTStatement init = forInitStatement(); |
| IASTExpression for_condition = null; |
| switch (LT(1)) { |
| case IToken.tSEMI: |
| case IToken.tEOC: |
| break; |
| default: |
| for_condition = condition(false); |
| } |
| switch (LT(1)) { |
| case IToken.tSEMI: |
| consume(); |
| break; |
| case IToken.tEOC: |
| break; |
| default: |
| throw backtrack; |
| } |
| IASTExpression iterationExpression = null; |
| switch (LT(1)) { |
| case IToken.tRPAREN: |
| case IToken.tEOC: |
| break; |
| default: |
| iterationExpression = expression(); |
| } |
| switch (LT(1)) { |
| case IToken.tRPAREN: |
| consume(); |
| break; |
| case IToken.tEOC: |
| break; |
| default: |
| throw backtrack; |
| } |
| |
| IASTForStatement for_statement = nodeFactory.newForStatement(init, for_condition, iterationExpression, null); |
| if (LT(1) != IToken.tEOC) { |
| IASTStatement for_body = statement(); |
| ((ASTNode) for_statement).setOffsetAndLength(startOffset, calculateEndOffset(for_body) - startOffset); |
| for_statement.setBody(for_body); |
| } |
| return for_statement; |
| } |
| } |