001: /* Operator Copyright (C) 1998-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: Operator.java.in,v 4.3.2.1 2002/05/28 17:34:06 hoenicke Exp $
018: */
019:
020: package jode.expr;
021:
022: import jode.type.Type;
023: import jode.GlobalOptions;
024: import jode.decompiler.TabbedPrintWriter;
025:
026: import java.util.Collection;
027: import java.util.Set;
028:
029: public abstract class Operator extends Expression {
030: /* Don't reorder these constants unless you know what you are doing! */
031: public final static int ADD_OP = 1;
032: public final static int SUB_OP = 2;
033: public final static int SHIFT_OP = 6;
034: public final static int AND_OP = 9;
035: public final static int ASSIGN_OP = 12;
036: public final static int OPASSIGN_OP = 12;
037: public final static int INC_OP = 24; /* must be even! */
038: public final static int DEC_OP = 25;
039: public final static int COMPARE_OP = 26; /* must be even! */
040: public final static int EQUALS_OP = 26;
041: public final static int NOTEQUALS_OP = 27;
042: public final static int LESS_OP = 28;
043: public final static int GREATEREQ_OP = 29;
044: public final static int GREATER_OP = 30;
045: public final static int LESSEQ_OP = 31;
046: public final static int LOG_AND_OP = 32; /* must be even! */
047: public final static int LOG_OR_OP = 33;
048: public final static int LOG_NOT_OP = 34;
049: public final static int NEG_OP = 36;
050: static String opString[] = { "", " + ", " - ", " * ", " / ", " % ",
051: " << ", " >> ", " >>> ", " & ", " | ", " ^ ", " = ",
052: " += ", " -= ", " *= ", " /= ", " %= ", " <<= ", " >>= ",
053: " >>>= ", " &= ", " |= ", " ^= ", "++", "--", " == ",
054: " != ", " < ", " >= ", " > ", " <= ", " && ", " || ", "!",
055: "~", "-" };
056:
057: protected int operatorIndex;
058: private int operandcount;
059:
060: Expression[] subExpressions;
061:
062: public Operator(Type type) {
063: this (type, 0);
064: }
065:
066: public Operator(Type type, int op) {
067: super (type);
068: this .operatorIndex = op;
069: if (type == null)
070: throw new jode.AssertError("type == null");
071: }
072:
073: public void initOperands(int opcount) {
074: operandcount = opcount;
075: subExpressions = new Expression[opcount];
076: for (int i = 0; i < opcount; i++) {
077: subExpressions[i] = new NopOperator(Type.tUnknown);
078: subExpressions[i].parent = this ;
079: }
080: updateSubTypes();
081: }
082:
083: public int getFreeOperandCount() {
084: return operandcount;
085: }
086:
087: /**
088: * Tells if this is an operator, that doesn't have any
089: * subExpression, yet.
090: */
091: public boolean isFreeOperator() {
092: return subExpressions.length == 0
093: || subExpressions[subExpressions.length - 1] instanceof NopOperator;
094: }
095:
096: /**
097: * Tells if this is an operator, that doesn't have any
098: * subExpression, yet, and that expects opcount operands
099: */
100: public boolean isFreeOperator(int opcount) {
101: return subExpressions.length == opcount
102: && (opcount == 0 || subExpressions[opcount - 1] instanceof NopOperator);
103: }
104:
105: public Expression addOperand(Expression op) {
106: for (int i = subExpressions.length; i-- > 0;) {
107: int opcount = subExpressions[i].getFreeOperandCount();
108: if (opcount > 0) {
109: subExpressions[i] = subExpressions[i].addOperand(op);
110: operandcount += subExpressions[i].getFreeOperandCount()
111: - opcount;
112: updateType();
113: return this ;
114: }
115: }
116: throw new jode.AssertError(
117: "addOperand called, but no operand needed");
118: }
119:
120: public Operator getOperator() {
121: return this ;
122: }
123:
124: public Expression[] getSubExpressions() {
125: return subExpressions;
126: }
127:
128: public void setSubExpressions(int i, Expression expr) {
129: int diff = expr.getFreeOperandCount()
130: - subExpressions[i].getFreeOperandCount();
131: subExpressions[i] = expr;
132: expr.parent = this ;
133: for (Operator ce = this ; ce != null; ce = (Operator) ce.parent)
134: ce.operandcount += diff;
135: updateType();
136: }
137:
138: public int getOperatorIndex() {
139: return operatorIndex;
140: }
141:
142: public void setOperatorIndex(int op) {
143: operatorIndex = op;
144: }
145:
146: public String getOperatorString() {
147: return opString[operatorIndex];
148: }
149:
150: public boolean opEquals(Operator o) {
151: return this == o;
152: }
153:
154: public Expression simplify() {
155: for (int i = 0; i < subExpressions.length; i++) {
156: subExpressions[i] = subExpressions[i].simplify();
157: subExpressions[i].parent = this ;
158: }
159: return this ;
160: }
161:
162: public void fillInGenSet(Collection in, Collection gen) {
163: if (this instanceof LocalVarOperator) {
164: LocalVarOperator varOp = (LocalVarOperator) this ;
165: if (varOp.isRead() && in != null)
166: in.add(varOp.getLocalInfo());
167: if (gen != null)
168: gen.add(varOp.getLocalInfo());
169: }
170: for (int i = 0; i < subExpressions.length; i++)
171: subExpressions[i].fillInGenSet(in, gen);
172: }
173:
174: public void fillDeclarables(Collection used) {
175: for (int i = 0; i < subExpressions.length; i++)
176: subExpressions[i].fillDeclarables(used);
177: }
178:
179: public void makeDeclaration(Set done) {
180: for (int i = 0; i < subExpressions.length; i++)
181: subExpressions[i].makeDeclaration(done);
182: }
183:
184: /**
185: * Checks if the value of the given expression can change, due to
186: * side effects in this expression. If this returns false, the
187: * expression can safely be moved behind the current expresion.
188: * @param expr the expression that should not change.
189: */
190: public boolean hasSideEffects(Expression expr) {
191: if (expr instanceof MatchableOperator
192: && expr
193: .containsConflictingLoad((MatchableOperator) expr))
194: return true;
195: for (int i = 0; i < subExpressions.length; i++) {
196: if (subExpressions[i].hasSideEffects(expr))
197: return true;
198: }
199: return false;
200: }
201:
202: /**
203: * Checks if this expression contains a conflicting load, that
204: * matches the given CombineableOperator. The sub expressions are
205: * not checked.
206: * @param op The combineable operator.
207: * @return if this expression contains a matching load.
208: */
209: public boolean containsConflictingLoad(MatchableOperator op) {
210: if (op.matches(this ))
211: return true;
212: for (int i = 0; i < subExpressions.length; i++) {
213: if (subExpressions[i].containsConflictingLoad(op))
214: return true;
215: }
216: return false;
217: }
218:
219: /**
220: * Checks if this expression contains a matching load, that matches the
221: * given Expression.
222: * @param comb The store expression.
223: * @return true, iff this expression contains a matching load.
224: * @exception ClassCastException, if e.getOperator
225: * is not a CombineableOperator.
226: */
227: public boolean containsMatchingLoad(CombineableOperator comb) {
228: Operator combOp = (Operator) comb;
229: if (comb.getLValue().matches(this )) {
230: if (subsEquals((Operator) comb.getLValue()))
231: return true;
232: }
233: for (int i = 0; i < subExpressions.length; i++) {
234: if (subExpressions[i].containsMatchingLoad(comb))
235: return true;
236: }
237: return false;
238: }
239:
240: /**
241: * Checks if the given Expression (which must be a CombineableOperator)
242: * can be combined into this expression.
243: * @param e The store expression, must be of type void.
244: * @return 1, if it can, 0, if no match was found and -1, if a
245: * conflict was found. You may wish to check for >0.
246: * @exception ClassCastException, if e.getOperator
247: * is not a CombineableOperator.
248: */
249: public int canCombine(CombineableOperator combOp) {
250: // GlobalOptions.err.println("Try to combine "+e+" into "+this);
251: if (combOp.getLValue() instanceof LocalStoreOperator
252: && ((Operator) combOp).getFreeOperandCount() == 0) {
253: // Special case for locals created on inlining methods, which may
254: // combine everywhere, as long as there are no side effects.
255:
256: for (int i = 0; i < subExpressions.length; i++) {
257: int result = subExpressions[i].canCombine(combOp);
258: if (result != 0)
259: return result;
260: if (subExpressions[i]
261: .hasSideEffects((Expression) combOp))
262: return -1;
263: }
264: }
265:
266: if (combOp.lvalueMatches(this ))
267: return subsEquals((Operator) combOp) ? 1 : -1;
268: if (subExpressions.length > 0)
269: return subExpressions[0].canCombine(combOp);
270: return 0;
271: }
272:
273: /**
274: * Combines the given Expression (which should be a StoreInstruction)
275: * into this expression. You must only call this if
276: * canCombine returns the value 1.
277: * @param e The store expression.
278: * @return The combined expression.
279: * @exception ClassCastException, if e.getOperator
280: * is not a CombineableOperator.
281: */
282: public Expression combine(CombineableOperator comb) {
283: Operator combOp = (Operator) comb;
284: if (comb.lvalueMatches(this )) {
285: /* We already checked in canCombine that subExpressions match */
286: comb.makeNonVoid();
287: combOp.parent = parent;
288: return combOp;
289: }
290: for (int i = 0; i < subExpressions.length; i++) {
291: Expression combined = subExpressions[i].combine(comb);
292: if (combined != null) {
293: subExpressions[i] = combined;
294: updateType();
295: return this ;
296: }
297: }
298: return null;
299: }
300:
301: public boolean subsEquals(Operator other) {
302: if (this == other)
303: return true;
304: if (other.subExpressions == null)
305: return (subExpressions == null);
306:
307: if (subExpressions.length != other.subExpressions.length)
308: return false;
309:
310: for (int i = 0; i < subExpressions.length; i++) {
311: if (!subExpressions[i].equals(other.subExpressions[i]))
312: return false;
313: }
314: return true;
315: }
316:
317: public boolean equals(Object o) {
318: if (this == o)
319: return true;
320: if (!(o instanceof Operator))
321: return false;
322: Operator other = (Operator) o;
323: return opEquals(other) && subsEquals(other);
324: }
325:
326: public boolean isConstant() {
327: for (int i = 0; i < subExpressions.length; i++)
328: if (!subExpressions[i].isConstant())
329: return false;
330: return true;
331: }
332:
333: public abstract void dumpExpression(TabbedPrintWriter writer)
334: throws java.io.IOException;
335: }
|