KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > flow > SwitchBlock


1 /* SwitchBlock Copyright (C) 1998-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; see the file COPYING.LESSER. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: SwitchBlock.java,v 4.15.2.1 2002/05/28 17:34:09 hoenicke Exp $
18  */

19
20 package jode.flow;
21 import jode.decompiler.TabbedPrintWriter;
22 import jode.expr.Expression;
23
24 /**
25  * This is the structured block for an empty block.
26  */

27 public class SwitchBlock extends InstructionContainer
28 implements BreakableBlock {
29     CaseBlock[] caseBlocks;
30     VariableStack exprStack;
31     VariableStack breakedStack;
32
33     public SwitchBlock(Expression instr,
34                int[] cases, FlowBlock[] dests) {
35     super(instr);
36
37     /* First remove all dests that jump to the default dest. */
38     int numCases = dests.length;
39     FlowBlock defaultDest = dests[cases.length];
40     for (int i=0; i< cases.length; i++) {
41         if (dests[i] == defaultDest) {
42         dests[i] = null;
43         numCases--;
44         }
45     }
46
47         caseBlocks = new CaseBlock[numCases];
48     FlowBlock lastDest = null;
49         for (int i=numCases-1; i>=0; i--) {
50         /**
51          * Sort the destinations by finding the greatest destAddr
52          */

53         int index = 0;
54         for (int j=1; j<dests.length; j++) {
55         if (dests[j] != null
56             && (dests[index] == null
57             || dests[j].getAddr() >= dests[index].getAddr()))
58             index = j;
59         }
60         /* assert(dests[index] != null) */
61
62         int value;
63         if (index == cases.length)
64         value = -1;
65         else
66         value = cases[index];
67
68         if (dests[index] == lastDest)
69         caseBlocks[i] = new CaseBlock(value);
70         else
71         caseBlocks[i] = new CaseBlock(value,
72                           new Jump(dests[index]));
73         caseBlocks[i].outer = this;
74         lastDest = dests[index];
75         dests[index] = null;
76         if (index == cases.length)
77         caseBlocks[i].isDefault = true;
78         }
79     caseBlocks[numCases-1].isLastBlock = true;
80         this.jump = null;
81         isBreaked = false;
82     }
83
84     /**
85      * This does take the instr into account and modifies stack
86      * accordingly. It then calls super.mapStackToLocal.
87      * @param stack the stack before the instruction is called
88      * @return stack the stack afterwards.
89      */

90     public VariableStack mapStackToLocal(VariableStack stack) {
91     VariableStack newStack;
92     int params = instr.getFreeOperandCount();
93     if (params > 0) {
94         exprStack = stack.peek(params);
95         newStack = stack.pop(params);
96     } else
97         newStack = stack;
98     VariableStack lastStack = newStack;
99     for (int i=0; i< caseBlocks.length; i++) {
100         if (lastStack != null)
101         newStack.merge(lastStack);
102         lastStack = caseBlocks[i].mapStackToLocal(newStack);
103     }
104     if (lastStack != null)
105         mergeBreakedStack(lastStack);
106     if (jump != null) {
107         jump.stackMap = breakedStack;
108         return null;
109     }
110     return breakedStack;
111     }
112
113     /**
114      * Is called by BreakBlock, to tell us what the stack can be after a
115      * break.
116      */

117     public void mergeBreakedStack(VariableStack stack) {
118     if (breakedStack != null)
119         breakedStack.merge(stack);
120     else
121         breakedStack = stack;
122     }
123
124     public void removePush() {
125     if (exprStack != null)
126         instr = exprStack.mergeIntoExpression(instr);
127     super.removePush();
128     }
129
130     /**
131      * Find the case that jumps directly to destination.
132      * @return The sub block of the case block, which jumps to destination.
133      */

134     public StructuredBlock findCase(FlowBlock destination) {
135     for (int i=0; i < caseBlocks.length; i++) {
136         if (caseBlocks[i].subBlock != null
137         && caseBlocks[i].subBlock instanceof EmptyBlock
138         && caseBlocks[i].subBlock.jump != null
139         && caseBlocks[i].subBlock.jump.destination == destination)
140         
141         return caseBlocks[i].subBlock;
142     }
143     return null;
144     }
145
146     /**
147      * Find the case that precedes the given case.
148      * @param block The sub block of the case, whose predecessor should
149      * be returned.
150      * @return The sub block of the case precedes the given case.
151      */

152     public StructuredBlock prevCase(StructuredBlock block) {
153     for (int i=caseBlocks.length-1; i>=0; i--) {
154         if (caseBlocks[i].subBlock == block) {
155         for (i--; i>=0; i--) {
156             if (caseBlocks[i].subBlock != null)
157             return caseBlocks[i].subBlock;
158         }
159         }
160     }
161     return null;
162     }
163
164     /**
165      * Returns the block where the control will normally flow to, when
166      * the given sub block is finished (<em>not</em> ignoring the jump
167      * after this block). (This is overwritten by SequentialBlock and
168      * SwitchBlock). If this isn't called with a direct sub block,
169      * the behaviour is undefined, so take care.
170      * @return null, if the control flows to another FlowBlock. */

171     public StructuredBlock getNextBlock(StructuredBlock subBlock) {
172     for (int i=0; i< caseBlocks.length-1; i++) {
173         if (subBlock == caseBlocks[i]) {
174         return caseBlocks[i+1];
175         }
176     }
177         return getNextBlock();
178     }
179
180     public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
181     for (int i=0; i< caseBlocks.length-1; i++) {
182         if (subBlock == caseBlocks[i]) {
183         return null;
184         }
185     }
186         return getNextFlowBlock();
187     }
188
189     public void dumpInstruction(TabbedPrintWriter writer)
190     throws java.io.IOException JavaDoc
191     {
192         if (label != null) {
193             writer.untab();
194             writer.println(label+":");
195             writer.tab();
196         }
197         writer.print("switch (");
198     instr.dumpExpression(writer.EXPL_PAREN, writer);
199     writer.print(")");
200     writer.openBrace();
201     for (int i=0; i < caseBlocks.length; i++)
202         caseBlocks[i].dumpSource(writer);
203     writer.closeBrace();
204     }
205
206     /**
207      * Returns all sub block of this structured block.
208      */

209     public StructuredBlock[] getSubBlocks() {
210         return caseBlocks;
211     }
212
213     boolean isBreaked = false;
214
215     /**
216      * The serial number for labels.
217      */

218     static int serialno = 0;
219
220     /**
221      * The label of this instruction, or null if it needs no label.
222      */

223     String JavaDoc label = null;
224
225     /**
226      * Returns the label of this block and creates a new label, if
227      * there wasn't a label previously.
228      */

229     public String JavaDoc getLabel() {
230         if (label == null)
231             label = "switch_"+(serialno++)+"_";
232         return label;
233     }
234
235     /**
236      * Is called by BreakBlock, to tell us that this block is breaked.
237      */

238     public void setBreaked() {
239     isBreaked = true;
240     }
241
242     /**
243      * Determines if there is a sub block, that flows through to the end
244      * of this block. If this returns true, you know that jump is null.
245      * @return true, if the jump may be safely changed.
246      */

247     public boolean jumpMayBeChanged() {
248         return !isBreaked
249             && (caseBlocks[caseBlocks.length-1].jump != null
250                 || caseBlocks[caseBlocks.length-1].jumpMayBeChanged());
251     }
252 }
253
Popular Tags