/******************************************************************************* * Copyright (c) 2008, 2014 Wind River Systems, Inc. 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: * Markus Schorn - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding; /** * Handles the ambiguity between a binary- and a cast-expression. (type)+var versus (var)+var. * It also handles the impact on the grouping of the sub-expressions. */ public abstract class ASTAmbiguousBinaryVsCastExpression extends ASTAmbiguousNode implements IASTAmbiguousExpression { private final IASTBinaryExpression fBinaryExpression; private final IASTCastExpression fCastExpression; /** * The binary expression must have one of the following operators: +,-,&,*. The left hand side of the binary expression * must end with an expression in parenthesis (which could be read as the beginning of the cast-expression. * The cast-expression must contain the type-id (corresponding to the last expression in parenthesis on the left side of the * binary expression. The operand of the castExpression can be <code>null</code>, it will be computed from the binary expression. */ public ASTAmbiguousBinaryVsCastExpression(IASTBinaryExpression binaryExpression, IASTCastExpression castExpression) { fBinaryExpression= binaryExpression; fCastExpression= castExpression; } @Override public final IASTExpression copy() { throw new UnsupportedOperationException(); } @Override public final IASTExpression copy(CopyStyle style) { throw new UnsupportedOperationException(); } @Override public final void addExpression(IASTExpression e) { throw new UnsupportedOperationException(); } @Override public final IASTNode[] getNodes() { return getExpressions(); } @Override public IASTExpression[] getExpressions() { return new IASTExpression[] {fBinaryExpression, fCastExpression}; } @Override protected final IASTNode doResolveAmbiguity(ASTVisitor visitor) { final IASTAmbiguityParent owner= (IASTAmbiguityParent) getParent(); IASTNode nodeToReplace= this; // handle nested ambiguities first owner.replace(nodeToReplace, fCastExpression); nodeToReplace= fCastExpression; fCastExpression.getTypeId().accept(visitor); owner.replace(nodeToReplace, fBinaryExpression); nodeToReplace= fBinaryExpression; fBinaryExpression.accept(visitor); // find nested names final NameCollector nameCollector= new NameCollector(); fCastExpression.getTypeId().accept(nameCollector); final IASTName[] names= nameCollector.getNames(); // resolve names boolean hasIssue= false; for (IASTName name : names) { try { IBinding b = name.resolveBinding(); if (b instanceof IProblemBinding) { hasIssue= true; break; } } catch (Exception t) { hasIssue= true; break; } } if (hasIssue) { return nodeToReplace; } final IASTExpression left = fBinaryExpression.getOperand1(); final IASTExpression right = fBinaryExpression.getOperand2(); left.setParent(null); right.setParent(null); IASTUnaryExpression primaryInParenthesis= findTrailingBracketedPrimaryExpression(left); IASTExpression leadingCastExpression= findLeadingCastExpression(right); IASTExpression castedUnary= fCastExpression.getOperand(); if (primaryInParenthesis != null && leadingCastExpression != null && castedUnary instanceof IASTUnaryExpression) { IASTExpression lp= (IASTExpression) primaryInParenthesis.getParent(); IASTBinaryExpression rp= (IASTBinaryExpression) leadingCastExpression.getParent(); ((IASTUnaryExpression) castedUnary).setOperand(leadingCastExpression); setEnd(castedUnary, leadingCastExpression); setRange(fCastExpression, primaryInParenthesis, leadingCastExpression); IASTExpression root= joinExpressions(lp, fCastExpression, rp); if (root != null) { owner.replace(nodeToReplace, root); return root; } } return nodeToReplace; } private void setEnd(IASTNode node, IASTNode end) { final ASTNode target= (ASTNode) node; final ASTNode e= (ASTNode) end; target.setLength(e.getOffset() + e.getLength() - target.getOffset()); } private void setStart(IASTNode node, IASTNode start) { final ASTNode target= (ASTNode) node; final int offset = ((ASTNode) start).getOffset(); target.setOffsetAndLength(offset, target.getOffset() + target.getLength() - offset); } private void setRange(IASTNode node, IASTNode from, IASTNode to) { final int offset = ((ASTNode) from).getOffset(); final ASTNode t= (ASTNode) to; ((ASTNode) node).setOffsetAndLength(offset, t.getOffset()+t.getLength()-offset); } /** * @param l unary, cast or binary expression to the left, all parents are unary, cast or binary expressions. * @param middle initially a cast-expression, always suitable to put into l or r * @param r a binary expression to the right, all parents are binary expressions. */ private IASTExpression joinExpressions(IASTExpression l, IASTExpression middle, IASTBinaryExpression r) { while (true) { if (l == null) { if (r == null) { return middle; } r.setOperand1(middle); setStart(r, middle); middle= r; r= (IASTBinaryExpression) r.getParent(); } else if (l instanceof IASTCastExpression) { // cast binds stronger than binary operator ((IASTCastExpression) l).setOperand(middle); setEnd(l, middle); middle= l; // middle becomes cast-expr, can be put into r (a binary-expr) l= (IASTExpression) l.getParent(); } else if (l instanceof IASTUnaryExpression) { // // unary operator binds stronger than binary operator ((IASTUnaryExpression) l).setOperand(middle); setEnd(l, middle); middle= l; // middle becomes unary-expr, can be put into r (a binary-expr) l= (IASTExpression) l.getParent(); } else { if (r== null || getPrecendence((IASTBinaryExpression) l) >= getPrecendence(r)) { ((IASTBinaryExpression) l).setOperand2(middle); setEnd(l, middle); middle= l; // middle becomes binary, can be put into r because precedence is greater or equal. l= (IASTExpression) l.getParent(); } else { r.setOperand1(middle); setStart(r, middle); middle= r; // middle becomes binary, can be put into r because precedence is greater. r= (IASTBinaryExpression) r.getParent(); } } } } private int getPrecendence(IASTBinaryExpression r) { switch (r.getOperator()) { case IASTBinaryExpression.op_ellipses: case IASTBinaryExpression.op_assign: case IASTBinaryExpression.op_binaryAndAssign: case IASTBinaryExpression.op_binaryOrAssign: case IASTBinaryExpression.op_binaryXorAssign: case IASTBinaryExpression.op_divideAssign: case IASTBinaryExpression.op_minusAssign: case IASTBinaryExpression.op_moduloAssign: case IASTBinaryExpression.op_multiplyAssign: case IASTBinaryExpression.op_plusAssign: case IASTBinaryExpression.op_shiftLeftAssign: case IASTBinaryExpression.op_shiftRightAssign: return 0; case IASTBinaryExpression.op_logicalOr: return 1; case IASTBinaryExpression.op_logicalAnd: return 2; case IASTBinaryExpression.op_binaryOr: return 3; case IASTBinaryExpression.op_binaryXor: return 4; case IASTBinaryExpression.op_binaryAnd: return 5; case IASTBinaryExpression.op_equals: case IASTBinaryExpression.op_notequals: return 6; case IASTBinaryExpression.op_greaterThan: case IASTBinaryExpression.op_greaterEqual: case IASTBinaryExpression.op_lessThan: case IASTBinaryExpression.op_lessEqual: case IASTBinaryExpression.op_max: case IASTBinaryExpression.op_min: return 7; case IASTBinaryExpression.op_shiftLeft: case IASTBinaryExpression.op_shiftRight: return 8; case IASTBinaryExpression.op_plus: case IASTBinaryExpression.op_minus: return 9; case IASTBinaryExpression.op_multiply: case IASTBinaryExpression.op_divide: case IASTBinaryExpression.op_modulo: return 10; case IASTBinaryExpression.op_pmarrow: case IASTBinaryExpression.op_pmdot: return 11; } assert false; return 0; } private IASTUnaryExpression findTrailingBracketedPrimaryExpression(IASTExpression expr) { while (true) { if (expr instanceof IASTBinaryExpression) { expr= ((IASTBinaryExpression) expr).getOperand2(); } else if (expr instanceof IASTCastExpression) { expr= ((IASTCastExpression) expr).getOperand(); } else if (expr instanceof IASTUnaryExpression) { IASTUnaryExpression u= (IASTUnaryExpression) expr; if (u.getOperator() == IASTUnaryExpression.op_bracketedPrimary) return u; expr= u.getOperand(); } else { return null; } } } private IASTExpression findLeadingCastExpression(IASTExpression expr) { while (expr instanceof IASTBinaryExpression) { expr= ((IASTBinaryExpression) expr).getOperand1(); } return expr; } }