Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: eb9b2ba6620d58fbff2a51758b575fecc4678913 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*******************************************************************************
 * 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;
	}
}

Back to the top