/******************************************************************************* * 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 * Yuan Zhang / Beth Tibbitts (IBM Research) * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.c; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.restoreTypedefs; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.c.ICArrayType; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; /** * Binary expression for c */ public class CASTBinaryExpression extends ASTNode implements IASTBinaryExpression, IASTAmbiguityParent { private int op; private IASTExpression operand1; private IASTExpression operand2; public CASTBinaryExpression() { } public CASTBinaryExpression(int op, IASTExpression operand1, IASTExpression operand2) { this.op = op; setOperand1(operand1); setOperand2(operand2); } @Override public CASTBinaryExpression copy() { return copy(CopyStyle.withoutLocations); } @Override public CASTBinaryExpression copy(CopyStyle style) { CASTBinaryExpression copy = new CASTBinaryExpression(); copy.op = op; copy.setOperand1(operand1 == null ? null : operand1.copy(style)); copy.setOperand2(operand2 == null ? null : operand2.copy(style)); return copy(copy, style); } @Override public int getOperator() { return op; } @Override public IASTExpression getOperand1() { return operand1; } @Override public IASTExpression getOperand2() { return operand2; } @Override public IASTInitializerClause getInitOperand2() { return operand2; } /** * @param op An op_X field from {@link IASTBinaryExpression} */ @Override public void setOperator(int op) { assertNotFrozen(); this.op = op; } @Override public void setOperand1(IASTExpression expression) { assertNotFrozen(); operand1 = expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(OPERAND_ONE); } } @Override public void setOperand2(IASTExpression expression) { assertNotFrozen(); operand2 = expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(OPERAND_TWO); } } @Override public boolean accept(ASTVisitor action) { if (operand1 instanceof IASTBinaryExpression || operand2 instanceof IASTBinaryExpression) { return acceptWithoutRecursion(this, action); } if (action.shouldVisitExpressions) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } if (operand1 != null && !operand1.accept(action)) return false; if (operand2 != null && !operand2.accept(action)) return false; if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; return true; } private static class N { final IASTBinaryExpression fExpression; int fState; N fNext; N(IASTBinaryExpression expr) { fExpression = expr; } } public static boolean acceptWithoutRecursion(IASTBinaryExpression bexpr, ASTVisitor action) { N stack= new N(bexpr); while (stack != null) { IASTBinaryExpression expr= stack.fExpression; if (stack.fState == 0) { if (action.shouldVisitExpressions) { switch (action.visit(expr)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: stack= stack.fNext; continue; } } stack.fState= 1; IASTExpression op1 = expr.getOperand1(); if (op1 instanceof IASTBinaryExpression) { N n= new N((IASTBinaryExpression) op1); n.fNext= stack; stack= n; continue; } if (op1 != null && !op1.accept(action)) return false; } if (stack.fState == 1) { stack.fState= 2; IASTExpression op2 = expr.getOperand2(); if (op2 instanceof IASTBinaryExpression) { N n= new N((IASTBinaryExpression) op2); n.fNext= stack; stack= n; continue; } if (op2 != null && !op2.accept(action)) return false; } if (action.shouldVisitExpressions && action.leave(expr) == ASTVisitor.PROCESS_ABORT) return false; stack= stack.fNext; } return true; } @Override public void replace(IASTNode child, IASTNode other) { if (child == operand1) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); operand1 = (IASTExpression) other; } if (child == operand2) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); operand2 = (IASTExpression) other; } } @Override public IType getExpressionType() { final int op = getOperator(); IType originalType1 = getOperand1().getExpressionType(); IType originalType2 = getOperand2().getExpressionType(); final IType type1= CVisitor.unwrapTypedefs(originalType1); final IType type2= CVisitor.unwrapTypedefs(originalType2); IType type= CArithmeticConversion.convertCOperandTypes(op, type1, type2); if (type != null) { return restoreTypedefs(type, originalType1, originalType2); } switch (op) { case op_lessEqual: case op_lessThan: case op_greaterEqual: case op_greaterThan: case op_logicalAnd: case op_logicalOr: case op_equals: case op_notequals: return new CBasicType(Kind.eInt, 0, this); case IASTBinaryExpression.op_plus: if (type1 instanceof IArrayType) { return arrayTypeToPointerType((ICArrayType) type1); } else if (type2 instanceof IPointerType) { return restoreTypedefs(type2, originalType2); } else if (type2 instanceof IArrayType) { return arrayTypeToPointerType((ICArrayType) type2); } break; case IASTBinaryExpression.op_minus: if (type2 instanceof IPointerType || type2 instanceof IArrayType) { if (type1 instanceof IPointerType || type1 instanceof IArrayType) { return CVisitor.getPtrDiffType(this); } return restoreTypedefs(type1, originalType1); } break; } return restoreTypedefs(type1, originalType1); } private IType arrayTypeToPointerType(ICArrayType type) { return new CPointerType(type.getType(), (type.isConst() ? CPointerType.IS_CONST : 0) | (type.isRestrict() ? CPointerType.IS_RESTRICT : 0) | (type.isVolatile() ? CPointerType.IS_VOLATILE : 0)); } @Override public boolean isLValue() { switch (getOperator()) { case op_assign: case op_binaryAndAssign: case op_binaryOrAssign: case op_binaryXorAssign: case op_divideAssign: case op_minusAssign: case op_moduloAssign: case op_multiplyAssign: case op_plusAssign: case op_shiftLeftAssign: case op_shiftRightAssign: return true; } return false; } @Override public final ValueCategory getValueCategory() { return isLValue() ? ValueCategory.LVALUE : ValueCategory.PRVALUE; } }