From 18c73ee0f5ffc705a4fd3a49f6cc23f748b0dee3 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Thu, 12 Nov 2009 17:45:31 +0000 Subject: [PATCH] Simplification of binary expression parsing, bug 294029. --- .../cdt/core/parser/tests/ast2/AST2Tests.java | 23 + .../parser/AbstractGNUSourceCodeParser.java | 639 ++++++++++-------- .../core/dom/parser/c/GNUCSourceParser.java | 195 ++++-- .../dom/parser/cpp/GNUCPPSourceParser.java | 349 +++++----- 4 files changed, 705 insertions(+), 501 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index d21aa606760..548a5785952 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -7080,4 +7080,27 @@ public class AST2Tests extends AST2BaseTest { assertEquals(1, ff.getParameters().length); } } + + // void f() { + // int a= + public void testLargeExpression_294029() throws Exception { + // when running the test in a suite, it cannot handle more than 200 parenthesis. + // run as a single test it does > 600. + sValidateCopy= false; + StringBuilder buf= new StringBuilder(); + buf.append(getAboveComment()); + final int depth= 200; + for (int i = 0; i < depth; i++) { + buf.append('('); + } + buf.append('1'); + for (int i = 0; i < depth; i++) { + buf.append(")+1"); + } + buf.append(";}"); + String code= buf.toString(); + for(ParserLanguage lang : ParserLanguage.values()) { + IASTTranslationUnit tu = parseAndCheckBindings(code, lang); + } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 5d872a4de79..7a1355f727d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -65,6 +65,7 @@ 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.INodeFactory; +import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression; import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider; @@ -176,8 +177,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { protected IToken declarationMark; protected IToken nextToken; protected IToken lastTokenFromScanner; - protected boolean onTopInTemplateArgs= false; - protected boolean inBinaryExpression= true; protected boolean isCancelled = false; protected boolean parsePassed = true; @@ -881,69 +880,329 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return expression(); } - protected IASTExpression expression() throws BacktrackException, EndOfFileException { - IToken la = LA(1); - int startingOffset = la.getOffset(); - IASTExpression assignmentExpression = assignmentExpression(); - if (LT(1) != IToken.tCOMMA) - return assignmentExpression; + /** + * Models a cast expression followed by an operator. Can be linked into a chain. + * This is done right to left, such that a tree of variants can be built. + */ + protected static class CastExpressionOp { + final CastExpressionOp fLeft; + final IASTExpression fExpression; + final int fOperatorToken; + final int fLeftPrecedence; + final int fRightPrecedence; - IASTExpressionList expressionList = nodeFactory.newExpressionList(); - ((ASTNode) expressionList).setOffset(startingOffset); - expressionList.addExpression(assignmentExpression); + public CastExpressionOp(CastExpressionOp left, IASTExpression expression, int operatorToken, int leftPrecedence, int rightPrecedence) { + fLeft= left; + fExpression= expression; + fOperatorToken= operatorToken; + fLeftPrecedence= leftPrecedence; + fRightPrecedence= rightPrecedence; + } + } + + /** + * Helper class to temporarily store a sequence of operator followed by expression. + */ + private static final class OpCastExpressionStack { + private IASTExpression fExpressions[]= new IASTExpression[128]; + private int fPrecedenceAndTokens[]= new int[256]; + private int fPos=-1; + + boolean isEmpty() { + return fPos<0; + } - int lastOffset = 0; - while (LT(1) == IToken.tCOMMA) { - consume(); - IASTExpression secondExpression = assignmentExpression(); - expressionList.addExpression(secondExpression); - lastOffset = calculateEndOffset(secondExpression); - } - ((ASTNode) expressionList).setLength(lastOffset - startingOffset); - return expressionList; - } + public IASTExpression getExpression() { + return fExpressions[fPos]; + } + public int getLeftPrecedence() { + return fPrecedenceAndTokens[2*fPos]; + } - protected abstract IASTExpression assignmentExpression() - throws BacktrackException, EndOfFileException; + public int getOperatorToken() { + return fPrecedenceAndTokens[2*fPos+1]; + } - protected IASTExpression relationalExpression() throws BacktrackException, EndOfFileException { - IASTExpression result= shiftExpression(); - for (;;) { - int operator; - switch (LT(1)) { - case IToken.tGT: - if (onTopInTemplateArgs) - return result; - operator= IASTBinaryExpression.op_greaterThan; - break; - case IToken.tLT: - operator = IASTBinaryExpression.op_lessThan; - break; - case IToken.tLTEQUAL: - operator = IASTBinaryExpression.op_lessEqual; - break; - case IToken.tGTEQUAL: - operator = IASTBinaryExpression.op_greaterEqual; - break; - case IGCCToken.tMAX: - operator = IASTBinaryExpression.op_max; - break; - case IGCCToken.tMIN: - operator = IASTBinaryExpression.op_min; - break; - default: - return result; + public void push(int leftPrecedence, int operatorToken, IASTExpression trailing) { + final int pos= ++fPos; + if (pos == fExpressions.length) { + IASTExpression newExpressions[]= new IASTExpression[pos*2]; + int newPrecedenceAndTokens[]= new int[pos*4]; + System.arraycopy(fExpressions, 0, newExpressions, 0, pos); + System.arraycopy(fPrecedenceAndTokens, 0, newPrecedenceAndTokens, 0, 2*pos); + fExpressions= newExpressions; + fPrecedenceAndTokens= newPrecedenceAndTokens; + } + + fExpressions[pos]= trailing; + fPrecedenceAndTokens[2*pos]= leftPrecedence; + fPrecedenceAndTokens[2*pos+1]= operatorToken; + } + + public void pop() { + --fPos; + } + } + + protected final IASTExpression buildExpression(CastExpressionOp exprOp1, IASTExpression expr) throws BacktrackException { + if (exprOp1 == null) + return expr; + + // exprOp1 exprOp2 expr + CastExpressionOp exprOp2= exprOp1; + exprOp1= exprOp1.fLeft; + OpCastExpressionStack stack= null; + + while (exprOp1 != null) { + if (exprOp1.fRightPrecedence < exprOp2.fLeftPrecedence) { + // (exprOp2 expr) -> expr2 + expr= buildExpression(exprOp2.fExpression, exprOp2.fOperatorToken, expr, stack); + if (stack != null) { + while (!stack.isEmpty() && exprOp1.fRightPrecedence < stack.getLeftPrecedence()) { + final int opToken= stack.getOperatorToken(); + final IASTExpression expr2= stack.getExpression(); + stack.pop(); + expr= buildExpression(expr, opToken, expr2, stack); + } + } + } else { + // expr(Op2 expr) -> expr | op2 expr on stack + if (stack == null) { + stack= new OpCastExpressionStack(); + } + stack.push(exprOp2.fLeftPrecedence, exprOp2.fOperatorToken, expr); + expr= exprOp2.fExpression; + } + exprOp2= exprOp1; + exprOp1= exprOp1.fLeft; + } + + // (exprOp2 expr) -> expr2 + expr= buildExpression(exprOp2.fExpression, exprOp2.fOperatorToken, expr, stack); + if (stack != null) { + while (!stack.isEmpty()) { + final int opToken= stack.getOperatorToken(); + final IASTExpression expr2= stack.getExpression(); + stack.pop(); + expr= buildExpression(expr, opToken, expr2, stack); + } + } + return expr; + } + + private IASTExpression buildExpression(IASTExpression left, int token, IASTExpression right, OpCastExpressionStack stack) throws BacktrackException { + int op, unaryOp=0; + switch(token) { + case IToken.tQUESTION: + if (stack == null || stack.isEmpty() || stack.getOperatorToken() != IToken.tCOLON) { + assert false; + ASTNode node= (ASTNode) left; + throwBacktrack(node.getOffset(), node.getLength()); + return null; // Will never be reached. + } + IASTExpression negative= stack.getExpression(); + stack.pop(); + IASTConditionalExpression conditionalEx = nodeFactory.newConditionalExpession(left, right, negative); + setRange(conditionalEx, left); + if (negative != null) { + adjustLength(conditionalEx, negative); } - consume(); - IASTExpression rhs= shiftExpression(); - result = buildBinaryExpression(operator, result, rhs, calculateEndOffset(rhs)); - } - } + return conditionalEx; + + case IToken.tCOMMA: + IASTExpressionList list; + if (left instanceof IASTExpressionList) { + list= (IASTExpressionList) left; + } else { + list= nodeFactory.newExpressionList(); + list.addExpression(left); + setRange(list, left); + } + list.addExpression(right); + adjustLength(list, right); + return list; + + case IToken.tASSIGN: + op= IASTBinaryExpression.op_assign; + break; + case IToken.tSTARASSIGN: + op= IASTBinaryExpression.op_multiplyAssign; + break; + case IToken.tDIVASSIGN: + op= IASTBinaryExpression.op_divideAssign; + break; + case IToken.tMODASSIGN: + op= IASTBinaryExpression.op_moduloAssign; + break; + case IToken.tPLUSASSIGN: + op= IASTBinaryExpression.op_plusAssign; + break; + case IToken.tMINUSASSIGN: + op= IASTBinaryExpression.op_minusAssign; + break; + case IToken.tSHIFTRASSIGN: + op= IASTBinaryExpression.op_shiftRightAssign; + break; + case IToken.tSHIFTLASSIGN: + op= IASTBinaryExpression.op_shiftLeftAssign; + break; + case IToken.tAMPERASSIGN: + op= IASTBinaryExpression.op_binaryAndAssign; + break; + case IToken.tXORASSIGN: + op= IASTBinaryExpression.op_binaryXorAssign; + break; + case IToken.tBITORASSIGN: + op= IASTBinaryExpression.op_binaryOrAssign; + break; + case IToken.tOR: + op= IASTBinaryExpression.op_logicalOr; + break; + case IToken.tAND: + op= IASTBinaryExpression.op_logicalAnd; + break; + case IToken.tBITOR: + op= IASTBinaryExpression.op_binaryOr; + break; + case IToken.tXOR: + op= IASTBinaryExpression.op_binaryXor; + break; + case IToken.tAMPER: + op= IASTBinaryExpression.op_binaryAnd; + unaryOp= IASTUnaryExpression.op_amper; + break; + case IToken.tEQUAL: + op= IASTBinaryExpression.op_equals; + break; + case IToken.tNOTEQUAL: + op= IASTBinaryExpression.op_notequals; + break; + case IToken.tGT: + op= IASTBinaryExpression.op_greaterThan; + break; + case IToken.tLT: + op= IASTBinaryExpression.op_lessThan; + break; + case IToken.tLTEQUAL: + op= IASTBinaryExpression.op_lessEqual; + break; + case IToken.tGTEQUAL: + op= IASTBinaryExpression.op_greaterEqual; + break; + case IGCCToken.tMAX: + op= IASTBinaryExpression.op_max; + break; + case IGCCToken.tMIN: + op= IASTBinaryExpression.op_min; + break; + case IToken.tSHIFTL: + op= IASTBinaryExpression.op_shiftLeft; + break; + case IToken.tSHIFTR: + op= IASTBinaryExpression.op_shiftRight; + break; + case IToken.tPLUS: + op= IASTBinaryExpression.op_plus; + unaryOp= IASTUnaryExpression.op_plus; + break; + case IToken.tMINUS: + op= IASTBinaryExpression.op_minus; + unaryOp= IASTUnaryExpression.op_minus; + break; + case IToken.tSTAR: + op= IASTBinaryExpression.op_multiply; + unaryOp= IASTUnaryExpression.op_star; + break; + case IToken.tDIV: + op= IASTBinaryExpression.op_divide; + break; + case IToken.tMOD: + op= IASTBinaryExpression.op_modulo; + break; + case IToken.tDOTSTAR: + op = IASTBinaryExpression.op_pmdot; + break; + case IToken.tARROWSTAR: + op = IASTBinaryExpression.op_pmarrow; + break; + + default: + assert false; + ASTNode node= (ASTNode) left; + throwBacktrack(node.getOffset(), node.getLength()); + return null; + } + + CastAmbiguityMarker lca= null; + CastAmbiguityMarker rca= null; + if (left instanceof CastAmbiguityMarker) { + lca= (CastAmbiguityMarker) left; + left= lca.getExpression(); + assert !(left instanceof CastAmbiguityMarker); + } + if (right instanceof CastAmbiguityMarker) { + rca= (CastAmbiguityMarker) right; + right= rca.getExpression(); + assert !(right instanceof CastAmbiguityMarker); + } + IASTExpression result= buildBinaryExpression(op, left, right, calculateEndOffset(right)); + + if (lca != null) { + assert unaryOp != 0; + result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result, + lca.getTypeIdForCast(), unaryOp, lca.getUnaryOperatorOffset()); + } + + return rca == null ? result : rca.updateExpression(result); + } + + protected abstract IASTExpression expression() throws BacktrackException, EndOfFileException; + protected abstract IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException; + protected abstract IASTExpression constantExpression() throws BacktrackException, EndOfFileException; + protected abstract IASTExpression unaryExpression(boolean inBinary) throws BacktrackException, EndOfFileException; + protected abstract IASTExpression primaryExpression() throws BacktrackException, EndOfFileException; protected abstract IASTTypeId typeId(DeclarationOptions option) throws EndOfFileException; + + private final static class CastAmbiguityMarker extends ASTNode implements IASTExpression { + private IASTExpression fExpression; + private final IASTTypeId fTypeIdForCast; + private final int fUnaryOperatorOffset; - protected IASTExpression castExpression() throws EndOfFileException, BacktrackException { + CastAmbiguityMarker(IASTExpression unary, IASTTypeId typeIdForCast, int unaryOperatorOffset) { + fExpression= unary; + fTypeIdForCast= typeIdForCast; + fUnaryOperatorOffset= unaryOperatorOffset; + } + + public CastAmbiguityMarker updateExpression(IASTExpression expression) { + fExpression= expression; + return this; + } + + public IASTExpression getExpression() { + return fExpression; + } + + public IASTTypeId getTypeIdForCast() { + return fTypeIdForCast; + } + + public int getUnaryOperatorOffset() { + return fUnaryOperatorOffset; + } + + public IASTExpression copy() { + throw new UnsupportedOperationException(); + } + + public IType getExpressionType() { + throw new UnsupportedOperationException(); + } + } + + protected final IASTExpression castExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { if (LT(1) == IToken.tLPAREN) { final IToken mark= mark(); final int startingOffset= mark.getOffset(); @@ -957,12 +1216,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { // ambiguity with unary operator case IToken.tPLUS: case IToken.tMINUS: case IToken.tSTAR: case IToken.tAMPER: + final int operatorOffset = LA(1).getOffset(); IToken markEnd= mark(); backup(mark); try { - IASTExpression unary= unaryExpression(); - fTypeIdForCastAmbiguity= typeId; - return unary; + IASTExpression unary= unaryExpression(false); + return new CastAmbiguityMarker(unary, typeId, operatorOffset); } catch (BacktrackException bt) { backup(markEnd); unaryFailed= true; @@ -971,25 +1230,30 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } try { boolean couldBeFunctionCall= LT(1) == IToken.tLPAREN; - IASTExpression rhs= castExpression(); + IASTExpression rhs= castExpression(inBinaryExpression); + + CastAmbiguityMarker ca= null; + if (rhs instanceof CastAmbiguityMarker) { + ca= (CastAmbiguityMarker) rhs; + rhs= ca.getExpression(); + assert !(rhs instanceof CastAmbiguityMarker); + } IASTCastExpression result= buildCastExpression(IASTCastExpression.op_cast, typeId, rhs, startingOffset, calculateEndOffset(rhs)); if (!unaryFailed && couldBeFunctionCall && rhs instanceof IASTCastExpression == false) { IToken markEnd= mark(); - final IASTTypeId typeidForCastAmbiguity= fTypeIdForCastAmbiguity; backup(mark); try { IASTExpression expr= primaryExpression(); IASTFunctionCallExpression fcall = nodeFactory.newFunctionCallExpression(expr, null); IASTAmbiguousExpression ambiguity = createAmbiguousCastVsFunctionCallExpression(result, fcall); ((ASTNode) ambiguity).setOffsetAndLength((ASTNode) result); - return ambiguity; + return ca == null ? ambiguity : ca.updateExpression(ambiguity); } catch (BacktrackException bt) { } finally { backup(markEnd); - fTypeIdForCastAmbiguity= typeidForCastAmbiguity; } } - return result; + return ca == null ? result : ca.updateExpression(result); } catch (BacktrackException b) { if (unaryFailed) throw b; @@ -997,12 +1261,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } backup(mark); } - return unaryExpression(); + return unaryExpression(inBinaryExpression); } - protected abstract IASTExpression unaryExpression() throws BacktrackException, EndOfFileException; - protected abstract IASTExpression primaryExpression() throws BacktrackException, EndOfFileException; - protected abstract IASTTranslationUnit getTranslationUnit(); protected abstract void setupTranslationUnit() throws Exception; @@ -1109,112 +1370,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { parent.addDeclaration(declaration); } - protected IASTExpression assignmentOperatorExpression(int kind, - IASTExpression lhs) throws EndOfFileException, BacktrackException { - consume(); - IASTExpression rhs = assignmentExpression(); - return buildBinaryExpression(kind, lhs, rhs, calculateEndOffset(rhs)); - } - - protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { - return conditionalExpression(); - } - - protected IASTExpression logicalOrExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = logicalAndExpression(); - while (LT(1) == IToken.tOR) { - if (shallRejectLogicalOperator()) { - throwBacktrack(LA(1)); - } - - consume(); - IASTExpression secondExpression = logicalAndExpression(); - firstExpression = buildBinaryExpression( - IASTBinaryExpression.op_logicalOr, firstExpression, - secondExpression, calculateEndOffset(secondExpression)); - } - return firstExpression; - } - - protected boolean shallRejectLogicalOperator() { - return false; - } - - protected IASTExpression logicalAndExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = inclusiveOrExpression(); - while (LT(1) == IToken.tAND) { - if (shallRejectLogicalOperator()) { - throwBacktrack(LA(1)); - } - - consume(); - IASTExpression secondExpression = inclusiveOrExpression(); - firstExpression = buildBinaryExpression( - IASTBinaryExpression.op_logicalAnd, firstExpression, - secondExpression, calculateEndOffset(secondExpression)); - } - return firstExpression; - } - - protected IASTExpression inclusiveOrExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = exclusiveOrExpression(); - while (LT(1) == IToken.tBITOR) { - consume(); - IASTExpression secondExpression = exclusiveOrExpression(); - firstExpression = buildBinaryExpression( - IASTBinaryExpression.op_binaryOr, firstExpression, - secondExpression, calculateEndOffset(secondExpression)); - } - return firstExpression; - } - - protected IASTExpression exclusiveOrExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = andExpression(); - while (LT(1) == IToken.tXOR) { - consume(); - IASTExpression secondExpression = andExpression(); - firstExpression = buildBinaryExpression( - IASTBinaryExpression.op_binaryXor, firstExpression, - secondExpression, calculateEndOffset(secondExpression)); - } - return firstExpression; - } - - protected IASTExpression andExpression() throws EndOfFileException, BacktrackException { - IASTExpression firstExpression = equalityExpression(); - while (LT(1) == IToken.tAMPER) { - final int offset= consume().getOffset(); - final IASTTypeId typeid= fTypeIdForCastAmbiguity; fTypeIdForCastAmbiguity= null; - IASTExpression secondExpression = equalityExpression(); - firstExpression = buildBinaryExpression( - IASTBinaryExpression.op_binaryAnd, firstExpression, - secondExpression, calculateEndOffset(secondExpression)); - if (typeid != null) { - firstExpression = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) firstExpression, typeid, IASTUnaryExpression.op_amper, offset); - } - } - return firstExpression; - } - - protected IASTExpression equalityExpression() throws EndOfFileException, BacktrackException { - IASTExpression firstExpression = relationalExpression(); - for (;;) { - switch (LT(1)) { - case IToken.tEQUAL: - case IToken.tNOTEQUAL: - IToken t = consume(); - int operator = ((t.getType() == IToken.tEQUAL) ? IASTBinaryExpression.op_equals : IASTBinaryExpression.op_notequals); - IASTExpression secondExpression = relationalExpression(); - firstExpression = buildBinaryExpression(operator, - firstExpression, secondExpression, - calculateEndOffset(secondExpression)); - break; - default: - return firstExpression; - } - } - } - protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr1, IASTExpression expr2, int lastOffset) { IASTBinaryExpression result = nodeFactory.newBinaryExpression(operator, expr1, expr2); int o = ((ASTNode) expr1).getOffset(); @@ -1222,84 +1377,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return result; } - protected IASTExpression shiftExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = additiveExpression(); - for (;;) { - switch (LT(1)) { - case IToken.tSHIFTL: - case IToken.tSHIFTR: - IToken t = consume(); - int operator = t.getType() == IToken.tSHIFTL ? IASTBinaryExpression.op_shiftLeft : IASTBinaryExpression.op_shiftRight; - IASTExpression secondExpression = additiveExpression(); - firstExpression = buildBinaryExpression(operator, - firstExpression, secondExpression, - calculateEndOffset(secondExpression)); - break; - default: - return firstExpression; - } - } - } - - protected IASTExpression additiveExpression() throws BacktrackException, EndOfFileException { - IASTExpression result= multiplicativeExpression(); - for (;;) { - int operator; - int unaryOperator; - switch (LT(1)) { - case IToken.tPLUS: - operator= IASTBinaryExpression.op_plus; - unaryOperator= IASTUnaryExpression.op_plus; - break; - case IToken.tMINUS: - operator= IASTBinaryExpression.op_minus; - unaryOperator= IASTUnaryExpression.op_minus; - break; - default: - return result; - } - final int offset= consume().getOffset(); - final IASTTypeId typeid= fTypeIdForCastAmbiguity; fTypeIdForCastAmbiguity= null; - IASTExpression secondExpression = multiplicativeExpression(); - result = buildBinaryExpression(operator, result, secondExpression, calculateEndOffset(secondExpression)); - if (typeid != null) { - result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result, typeid, unaryOperator, offset); - } - } - } - - protected IASTExpression multiplicativeExpression() throws BacktrackException, EndOfFileException { - inBinaryExpression= true; - fTypeIdForCastAmbiguity= null; - IASTExpression result= pmExpression(); - for (;;) { - int operator; - switch (LT(1)) { - case IToken.tSTAR: - operator = IASTBinaryExpression.op_multiply; - break; - case IToken.tDIV: - operator = IASTBinaryExpression.op_divide; - break; - case IToken.tMOD: - operator = IASTBinaryExpression.op_modulo; - break; - default: - return result; - } - final int offset= consume().getOffset(); - final IASTTypeId typeid= fTypeIdForCastAmbiguity; fTypeIdForCastAmbiguity= null; - IASTExpression secondExpression= pmExpression(); - result= buildBinaryExpression(operator, result, secondExpression, calculateEndOffset(secondExpression)); - if (typeid != null) { - result = createCastVsBinaryExpressionAmbiguity((IASTBinaryExpression) result, typeid, IASTUnaryExpression.op_star, offset); - } - } - } - - protected abstract IASTExpression pmExpression() throws EndOfFileException, BacktrackException; - - private IASTExpression createCastVsBinaryExpressionAmbiguity(IASTBinaryExpression expr, final IASTTypeId typeid, int unaryOperator, int unaryOpOffset) { IASTUnaryExpression unary= nodeFactory.newUnaryExpression(unaryOperator, null); ((ASTNode) unary).setOffset(unaryOpOffset); @@ -1309,41 +1386,17 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return result; } - protected IASTExpression conditionalExpression() throws BacktrackException, EndOfFileException { - IASTExpression firstExpression = logicalOrExpression(); - if (LT(1) == IToken.tQUESTION) { - if (shallRejectLogicalOperator()) { - throwBacktrack(LA(1)); - } - - consume(); - IASTExpression secondExpression= null; - if (LT(1) != IToken.tCOLON) { - secondExpression = expression(); - } - IASTExpression thirdExpression = null; - - if (LT(1) != IToken.tEOC) { - consume(IToken.tCOLON); - thirdExpression = assignmentExpression(); - } - - IASTConditionalExpression result = nodeFactory.newConditionalExpession(firstExpression, secondExpression, thirdExpression); - if (thirdExpression != null) { - ((ASTNode) result).setOffsetAndLength(((ASTNode) firstExpression) - .getOffset(), calculateEndOffset(thirdExpression) - - ((ASTNode) firstExpression).getOffset()); - } - - return result; - } - return firstExpression; - } - - protected IASTExpression unarayExpression(int operator) throws EndOfFileException, BacktrackException { + protected IASTExpression unarayExpression(int operator, boolean inBinary) throws EndOfFileException, BacktrackException { final IToken operatorToken= consume(); - final IASTExpression operand= castExpression(); + IASTExpression operand= castExpression(inBinary); + CastAmbiguityMarker ca= null; + if (operand instanceof CastAmbiguityMarker) { + ca= (CastAmbiguityMarker) operand; + operand= ca.getExpression(); + assert !(operand instanceof CastAmbiguityMarker); + } + if (operator == IASTUnaryExpression.op_star && operand instanceof IASTLiteralExpression) { IASTLiteralExpression lit= (IASTLiteralExpression) operand; switch(lit.getKind()) { @@ -1356,7 +1409,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - return buildUnaryExpression(operator, operand, operatorToken.getOffset(), calculateEndOffset(operand)); + IASTExpression result= buildUnaryExpression(operator, operand, operatorToken.getOffset(), calculateEndOffset(operand)); + return ca == null ? result : ca.updateExpression(result); } protected IASTExpression buildUnaryExpression(int operator, IASTExpression operand, int offset, int lastOffset) { @@ -2131,7 +2185,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } protected IASTExpression parseTypeidInParenthesisOrUnaryExpression(boolean exprIsLimitedToParenthesis, - int offset, int typeExprKind, int unaryExprKind) throws BacktrackException, EndOfFileException { + int offset, int typeExprKind, int unaryExprKind, boolean inBinary) throws BacktrackException, EndOfFileException { IASTTypeId typeid; IASTExpression expr= null; IToken typeidLA= null; @@ -2184,6 +2238,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { typeid= null; } + CastAmbiguityMarker ca= null; backup(mark); try { if (exprIsLimitedToParenthesis) { @@ -2191,7 +2246,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { expr= expression(); endOffset2= consumeOrEOC(IToken.tRPAREN).getEndOffset(); } else { - expr= unaryExpression(); + expr= unaryExpression(inBinary); + if (expr instanceof CastAmbiguityMarker) { + ca= (CastAmbiguityMarker) expr; + expr= ca.getExpression(); + assert !(expr instanceof CastAmbiguityMarker); + } endOffset2= calculateEndOffset(expr); } } catch (BacktrackException bte) { @@ -2211,6 +2271,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } IASTExpression result2= buildUnaryExpression(unaryExprKind, expr, offset, endOffset2); + if (ca != null) + result2= ca.updateExpression(result2); + if (result1 == null) return result2; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index 0726b07b192..4dbecbc0c78 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -26,7 +26,6 @@ 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.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; @@ -444,74 +443,161 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { } } } + + @Override + protected IASTExpression expression() throws BacktrackException, EndOfFileException { + return expression(true, true); + } - - @Override + @Override protected IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException { - IASTExpression conditionalExpression = conditionalExpression(); - // if the condition not taken, try assignment operators - if (conditionalExpression instanceof IASTConditionalExpression) - return conditionalExpression; - switch (LT(1)) { - case IToken.tASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_assign, conditionalExpression); - case IToken.tSTARASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_multiplyAssign, conditionalExpression); - case IToken.tDIVASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_divideAssign, conditionalExpression); - case IToken.tMODASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_moduloAssign, conditionalExpression); - case IToken.tPLUSASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_plusAssign, conditionalExpression); - case IToken.tMINUSASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_minusAssign, conditionalExpression); - case IToken.tSHIFTRASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_shiftRightAssign, conditionalExpression); - case IToken.tSHIFTLASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_shiftLeftAssign, conditionalExpression); - case IToken.tAMPERASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_binaryAndAssign, conditionalExpression); - case IToken.tXORASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_binaryXorAssign, conditionalExpression); - case IToken.tBITORASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_binaryOrAssign, conditionalExpression); - } - return conditionalExpression; + return expression(false, true); + } + + @Override + protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { + return expression(false, false); } - @Override - protected IASTExpression pmExpression() throws BacktrackException, EndOfFileException { - return castExpression(); - } + private IASTExpression expression(boolean allowComma, boolean allowAssignment) throws BacktrackException, EndOfFileException { + int lt1; + int conditionCount= 0; + CastExpressionOp lastComponent= null; + IASTExpression lastExpression= castExpression(true); + loop: while(true) { + lt1= LT(1); + switch(lt1) { + case IToken.tQUESTION: + conditionCount++; + // ? : + // Precedence: 25 is lower than precedence of logical or; 1 is lower than precedence of expression + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 25, 1); + 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; + + // ? : + // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; + lastComponent= new CastExpressionOp(lastComponent, 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 + lastComponent= new CastExpressionOp(lastComponent, 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 + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 21, 20); + break; + + case IToken.tOR: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 30, 31); + break; + case IToken.tAND: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 40, 41); + break; + case IToken.tBITOR: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 50, 51); + break; + case IToken.tXOR: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 60, 61); + break; + case IToken.tAMPER: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 70, 71); + break; + case IToken.tEQUAL: + case IToken.tNOTEQUAL: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 80, 81); + break; + case IToken.tGT: + case IToken.tLT: + case IToken.tLTEQUAL: + case IToken.tGTEQUAL: + case IGCCToken.tMAX: + case IGCCToken.tMIN: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 90, 91); + break; + case IToken.tSHIFTL: + case IToken.tSHIFTR: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 100, 101); + break; + case IToken.tPLUS: + case IToken.tMINUS: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 110, 111); + break; + case IToken.tSTAR: + case IToken.tDIV: + case IToken.tMOD: + lastComponent= new CastExpressionOp(lastComponent, lastExpression, lt1, 120, 121); + break; + default: + break loop; + } + + consume(); // consume operator + lastExpression= castExpression(true); // next cast expression + } + + // Check for incomplete conditional expression + if (lt1 != IToken.tEOC && conditionCount > 0) + throwBacktrack(LA(1)); + + return buildExpression(lastComponent, lastExpression); + } + @Override - protected IASTExpression unaryExpression() throws EndOfFileException, BacktrackException { + protected IASTExpression unaryExpression(boolean inBinary) throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.tSTAR: - return unarayExpression(IASTUnaryExpression.op_star); + return unarayExpression(IASTUnaryExpression.op_star, inBinary); case IToken.tAMPER: - return unarayExpression(IASTUnaryExpression.op_amper); + return unarayExpression(IASTUnaryExpression.op_amper, inBinary); case IToken.tPLUS: - return unarayExpression(IASTUnaryExpression.op_plus); + return unarayExpression(IASTUnaryExpression.op_plus, inBinary); case IToken.tMINUS: - return unarayExpression(IASTUnaryExpression.op_minus); + return unarayExpression(IASTUnaryExpression.op_minus, inBinary); case IToken.tNOT: - return unarayExpression(IASTUnaryExpression.op_not); + return unarayExpression(IASTUnaryExpression.op_not, inBinary); case IToken.tBITCOMPLEMENT: - return unarayExpression(IASTUnaryExpression.op_tilde); + return unarayExpression(IASTUnaryExpression.op_tilde, inBinary); case IToken.tINCR: - return unarayExpression(IASTUnaryExpression.op_prefixIncr); + return unarayExpression(IASTUnaryExpression.op_prefixIncr, inBinary); case IToken.tDECR: - return unarayExpression(IASTUnaryExpression.op_prefixDecr); + return unarayExpression(IASTUnaryExpression.op_prefixDecr, inBinary); case IToken.t_sizeof: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof); + IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, inBinary); case IGCCToken.t_typeof: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof); + IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, inBinary); case IGCCToken.t___alignof__: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf); + IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, inBinary); default: return postfixExpression(); } @@ -669,7 +755,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { return compoundStatementExpression(); } t = consume(); - IASTExpression lhs = expression(); + IASTExpression lhs = expression(true, true); // instead of expression(), to keep the stack smaller int finalOffset = 0; switch (LT(1)) { case IToken.tRPAREN: @@ -998,14 +1084,9 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { if (encounteredRawType || encounteredTypename) throwBacktrack(LA(1)); - final boolean wasInBinary= inBinaryExpression; - try { - inBinaryExpression= false; - typeofExpression = parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof); - } finally { - inBinaryExpression= wasInBinary; - } + typeofExpression = parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), + IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, false); + encounteredTypename= true; endOffset= calculateEndOffset(typeofExpression); break; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index a0ae60987ed..a35716a2d6d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -27,7 +27,6 @@ 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.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; @@ -61,7 +60,6 @@ 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.ICPPASTBinaryExpression; 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; @@ -156,6 +154,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { private char[] currentClassName; private final ICPPNodeFactory nodeFactory; + private boolean fInTemplateParameterList; public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService log, ICPPParserExtensionConfiguration config) { @@ -316,8 +315,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { IToken secondMark = mark(); consume(IToken.tLT); - final boolean wasOnTop= onTopInTemplateArgs; - onTopInTemplateArgs= true; try { // bug 229062: content assist after '<' needs to prefer to backtrack here if (rejectLogicalOperatorInTemplateID == 1) { @@ -342,9 +339,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } catch (BacktrackException bt) { backup(secondMark); return templateName; - } finally { - onTopInTemplateArgs= wasOnTop; - } + } } private ICPPASTTemplateId buildTemplateID(IASTName templateName, int endOffset, List args) { @@ -475,7 +470,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { throw backtrack; backup(argStart); - IASTExpression expression = assignmentExpression(); + IASTExpression expression = expression(false, true, true); if (expression instanceof IASTIdExpression) { if (mark() != typeIdEnd) throw backtrack; @@ -496,7 +491,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } else { // not a type-id - try as expression backup(argStart); - IASTExpression expression = assignmentExpression(); + IASTExpression expression = expression(false, true, true); list.add(expression); } @@ -569,90 +564,166 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return name; } - @Override - protected IASTExpression expression() throws EndOfFileException, BacktrackException { - final boolean wasOnTop= onTopInTemplateArgs; - onTopInTemplateArgs= false; - try { - return super.expression(); - } finally { - onTopInTemplateArgs= wasOnTop; + @Override + protected IASTExpression expression() throws BacktrackException, EndOfFileException { + return expression(true, true, false); + } + + @Override + protected IASTExpression assignmentExpression() throws EndOfFileException, BacktrackException { + return expression(false, true, false); + } + + @Override + protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { + return expression(false, false, false); + } + + private IASTExpression expression(boolean allowComma, boolean allowAssignment, boolean onTopOfTemplateArgs) throws EndOfFileException, BacktrackException { + if (allowAssignment && LT(1) == IToken.t_throw) { + return throwExpression(); + } + + int lt1; + int conditionCount= 0; + CastExpressionOp lastComponent= null; + IASTExpression expr= castExpression(true); + + loop: while(true) { + // typically after a binary operator there cannot be a throw expression + boolean allowThrow= false; + lt1= LT(1); + switch(lt1) { + case IToken.tQUESTION: + conditionCount++; + // ? : + // Precedence: 25 is lower than precedence of logical or; 1 is lower than precedence of expression + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 25, 1); + if (LT(2) == IToken.tCOLON) { + // Gnu extension: The expression after '?' can be omitted. + consume(); // Consume operator + expr= null; // Next cast expression is just null + continue; + } + allowAssignment= true; // assignment expressions will be subsumed by the conditional expression + allowThrow= true; + break; + + case IToken.tCOLON: + if (--conditionCount < 0) + break loop; + + // ? : + // Precedence: 0 is lower than precedence of expression; 15 is lower than precedence of assignment; + lastComponent= new CastExpressionOp(lastComponent, 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) + break loop; + // Lowest precedence except inside the conditional expression + lastComponent= new CastExpressionOp(lastComponent, 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) + break loop; + // Assignments group right to left + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 21, 20); + break; + + case IToken.tOR: + if (onTopOfTemplateArgs && rejectLogicalOperatorInTemplateID > 0) { + throwBacktrack(LA(1)); + } + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 30, 31); + break; + case IToken.tAND: + if (onTopOfTemplateArgs && rejectLogicalOperatorInTemplateID > 0) { + throwBacktrack(LA(1)); + } + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 40, 41); + break; + case IToken.tBITOR: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 50, 51); + break; + case IToken.tXOR: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 60, 61); + break; + case IToken.tAMPER: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 70, 71); + break; + case IToken.tEQUAL: + case IToken.tNOTEQUAL: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 80, 81); + break; + case IToken.tGT: + if (onTopOfTemplateArgs) + break loop; + //$FALL-THROUGH$ + case IToken.tLT: + case IToken.tLTEQUAL: + case IToken.tGTEQUAL: + case IGCCToken.tMAX: + case IGCCToken.tMIN: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 90, 91); + break; + case IToken.tSHIFTL: + case IToken.tSHIFTR: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 100, 101); + break; + case IToken.tPLUS: + case IToken.tMINUS: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 110, 111); + break; + case IToken.tSTAR: + case IToken.tDIV: + case IToken.tMOD: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 120, 121); + break; + case IToken.tDOTSTAR: + case IToken.tARROWSTAR: + lastComponent= new CastExpressionOp(lastComponent, expr, lt1, 130, 131); + break; + default: + break loop; + } + + consume(); // consume operator + if (allowThrow && LT(1) == IToken.t_throw) { + expr= throwExpression(); + switch (LT(1)) { + case IToken.tCOLON: + case IToken.tCOMMA: + break; + default: + break loop; + } + } + expr= castExpression(true); // next cast expression } + + // Check for incomplete conditional expression + if (lt1 != IToken.tEOC && conditionCount > 0) + throwBacktrack(LA(1)); + + return buildExpression(lastComponent, expr); } - @Override - protected boolean shallRejectLogicalOperator() { - return onTopInTemplateArgs && rejectLogicalOperatorInTemplateID > 0; - } - - @Override - protected IASTExpression constantExpression() throws EndOfFileException, BacktrackException { - final boolean wasOnTop= onTopInTemplateArgs; - onTopInTemplateArgs= false; - try { - return super.constantExpression(); - } finally { - onTopInTemplateArgs= wasOnTop; - } - } - - @Override - protected IASTExpression assignmentExpression() throws EndOfFileException, - BacktrackException { - if (LT(1) == IToken.t_throw) { - return throwExpression(); - } - - // if this is a conditional expression, return right away. - IASTExpression conditionalExpression = conditionalExpression(); - if (conditionalExpression instanceof IASTConditionalExpression) - return conditionalExpression; - - switch (LT(1)) { - case IToken.tASSIGN: - return assignmentOperatorExpression(IASTBinaryExpression.op_assign, - conditionalExpression); - case IToken.tSTARASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_multiplyAssign, - conditionalExpression); - case IToken.tDIVASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_divideAssign, conditionalExpression); - case IToken.tMODASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_moduloAssign, conditionalExpression); - case IToken.tPLUSASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_plusAssign, conditionalExpression); - case IToken.tMINUSASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_minusAssign, conditionalExpression); - case IToken.tSHIFTRASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_shiftRightAssign, - conditionalExpression); - case IToken.tSHIFTLASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_shiftLeftAssign, - conditionalExpression); - case IToken.tAMPERASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_binaryAndAssign, - conditionalExpression); - case IToken.tXORASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_binaryXorAssign, - conditionalExpression); - case IToken.tBITORASSIGN: - return assignmentOperatorExpression( - IASTBinaryExpression.op_binaryOrAssign, - conditionalExpression); - } - return conditionalExpression; - } - - protected IASTExpression throwExpression() throws EndOfFileException, BacktrackException { + private IASTExpression throwExpression() throws EndOfFileException, BacktrackException { IToken throwToken = consume(); IASTExpression throwExpression = null; try { @@ -667,34 +738,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { throwExpression, throwToken.getOffset(), o); // fix for 95225 } - @Override - protected IASTExpression pmExpression() throws EndOfFileException, BacktrackException { - IASTExpression firstExpression = castExpression(); - for (;;) { - switch (LT(1)) { - case IToken.tDOTSTAR: - case IToken.tARROWSTAR: - IToken t = consume(); - IASTExpression secondExpression = castExpression(); - int operator = 0; - switch (t.getType()) { - case IToken.tDOTSTAR: - operator = ICPPASTBinaryExpression.op_pmdot; - break; - case IToken.tARROWSTAR: - operator = ICPPASTBinaryExpression.op_pmarrow; - break; - } - firstExpression = buildBinaryExpression(operator, - firstExpression, secondExpression, - calculateEndOffset(secondExpression)); - break; - default: - return firstExpression; - } - } - } - protected IASTExpression deleteExpression() throws EndOfFileException, BacktrackException { int startingOffset = LA(1).getOffset(); boolean global = false; @@ -713,7 +756,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { consume(IToken.tRBRACKET); vectored = true; } - IASTExpression castExpression = castExpression(); + IASTExpression castExpression = castExpression(false); ICPPASTDeleteExpression deleteExpression = nodeFactory.newDeleteExpression(castExpression); ((ASTNode) deleteExpression).setOffsetAndLength(startingOffset, calculateEndOffset(castExpression) - startingOffset); deleteExpression.setIsGlobal(global); @@ -855,24 +898,24 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { @Override - protected IASTExpression unaryExpression() throws EndOfFileException, BacktrackException { + protected IASTExpression unaryExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { switch (LT(1)) { case IToken.tSTAR: - return unarayExpression(IASTUnaryExpression.op_star); + return unarayExpression(IASTUnaryExpression.op_star, inBinaryExpression); case IToken.tAMPER: - return unarayExpression(IASTUnaryExpression.op_amper); + return unarayExpression(IASTUnaryExpression.op_amper, inBinaryExpression); case IToken.tPLUS: - return unarayExpression(IASTUnaryExpression.op_plus); + return unarayExpression(IASTUnaryExpression.op_plus, inBinaryExpression); case IToken.tMINUS: - return unarayExpression(IASTUnaryExpression.op_minus); + return unarayExpression(IASTUnaryExpression.op_minus, inBinaryExpression); case IToken.tNOT: - return unarayExpression(IASTUnaryExpression.op_not); + return unarayExpression(IASTUnaryExpression.op_not, inBinaryExpression); case IToken.tBITCOMPLEMENT: - return unarayExpression(IASTUnaryExpression.op_tilde); + return unarayExpression(IASTUnaryExpression.op_tilde, inBinaryExpression); case IToken.tINCR: - return unarayExpression(IASTUnaryExpression.op_prefixIncr); + return unarayExpression(IASTUnaryExpression.op_prefixIncr, inBinaryExpression); case IToken.tDECR: - return unarayExpression(IASTUnaryExpression.op_prefixDecr); + return unarayExpression(IASTUnaryExpression.op_prefixDecr, inBinaryExpression); case IToken.t_new: return newExpression(); case IToken.t_delete: @@ -884,23 +927,23 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.t_delete: return deleteExpression(); default: - return postfixExpression(); + return postfixExpression(inBinaryExpression); } case IToken.t_sizeof: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof); + IASTTypeIdExpression.op_sizeof, IASTUnaryExpression.op_sizeof, inBinaryExpression); case IGCCToken.t_typeof: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof); + IASTTypeIdExpression.op_typeof, IASTUnaryExpression.op_typeof, inBinaryExpression); case IGCCToken.t___alignof__: return parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf); + IASTTypeIdExpression.op_alignof, IASTUnaryExpression.op_alignOf, inBinaryExpression); default: - return postfixExpression(); + return postfixExpression(inBinaryExpression); } } - protected IASTExpression postfixExpression() throws EndOfFileException, BacktrackException { + private IASTExpression postfixExpression(boolean inBinaryExpression) throws EndOfFileException, BacktrackException { IASTExpression firstExpression = null; boolean isTemplate = false; @@ -989,7 +1032,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { break; case IToken.t_typeid: int so = consume().getOffset(); - firstExpression= parseTypeidInParenthesisOrUnaryExpression(true, so, ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid); + firstExpression = parseTypeidInParenthesisOrUnaryExpression(true, so, + ICPPASTTypeIdExpression.op_typeid, ICPPASTUnaryExpression.op_typeid, inBinaryExpression); break; default: @@ -1191,7 +1235,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } t = consume(); int finalOffset= 0; - IASTExpression lhs= expression(); + IASTExpression lhs= expression(true, true, false); // instead of expression(), to keep the stack smaller switch (LT(1)) { case IToken.tRPAREN: case IToken.tEOC: @@ -1421,15 +1465,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return templateSpecialization; } - final boolean wasOnTop= onTopInTemplateArgs; - onTopInTemplateArgs= true; - List parms; - try { - parms = templateParameterList(); - consume(IToken.tGT); - } finally { - onTopInTemplateArgs= wasOnTop; - } + List parms= templateParameterList(); + consume(IToken.tGT); IASTDeclaration d = declaration(option); ICPPASTTemplateDeclaration templateDecl = nodeFactory.newTemplateDeclaration(d); ((ASTNode) templateDecl).setOffsetAndLength(firstToken.getOffset(), calculateEndOffset(d) - firstToken.getOffset()); @@ -1526,8 +1563,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { consume(); continue; } else { - ICPPASTParameterDeclaration parm = parameterDeclaration(); - returnValue.add(parm); + boolean inTParList= fInTemplateParameterList; + try { + fInTemplateParameterList= true; + ICPPASTParameterDeclaration parm = parameterDeclaration(); + returnValue.add(parm); + } finally { + fInTemplateParameterList= inTParList; + } } } } @@ -2182,14 +2225,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (encounteredRawType || encounteredTypename) throwBacktrack(LA(1)); - final boolean wasInBinary= inBinaryExpression; - try { - inBinaryExpression= false; - typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), - IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof); - } finally { - inBinaryExpression= wasInBinary; - } + typeofExpression= parseTypeidInParenthesisOrUnaryExpression(false, consume().getOffset(), + IGNUASTTypeIdExpression.op_typeof, IGNUASTUnaryExpression.op_typeof, false); encounteredTypename= true; endOffset= calculateEndOffset(typeofExpression); @@ -2617,7 +2654,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // if we get this far, it means that we did not // try this now instead // assignmentExpression - IASTExpression assignmentExpression = assignmentExpression(); + IASTExpression assignmentExpression = expression(false, true, fInTemplateParameterList); if (inAggregateInitializer && skipTrivialExpressionsInAggregateInitializers) { if (!ASTQueries.canContainName(assignmentExpression)) return null;