001: /* CaseBlock 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: CaseBlock.java,v 4.15.4.2 2002/05/28 17:34:08 hoenicke Exp $
018: */
019:
020: package jode.flow;
021:
022: import jode.expr.ConstOperator;
023: import jode.type.Type;
024:
025: /**
026: * This block represents a case instruction. A case instruction is a
027: * part of a switch construction and may have a subpart or not (for
028: * multiple case directly after each other.
029: *
030: * @author Jochen Hoenicke */
031: public class CaseBlock extends StructuredBlock {
032: /**
033: * The inner block that jumps to the subroutine, or null
034: * if this is a value only.
035: */
036: StructuredBlock subBlock;
037:
038: /**
039: * The value of this case.
040: */
041: int value;
042:
043: /**
044: * True, if this is the default case
045: */
046: boolean isDefault = false;
047:
048: /**
049: * True, if the previous case falls through to this case
050: */
051: boolean isFallThrough = false;
052:
053: /**
054: * True, if this is the last case in a switch
055: */
056: boolean isLastBlock = false;
057:
058: public CaseBlock(int value) {
059: this .value = value;
060: subBlock = null;
061: }
062:
063: public CaseBlock(int value, Jump dest) {
064: this .value = value;
065: subBlock = new EmptyBlock(dest);
066: subBlock.outer = this ;
067: }
068:
069: public void checkConsistent() {
070: if (!(outer instanceof SwitchBlock))
071: throw new jode.AssertError("Inconsistency");
072: super .checkConsistent();
073: }
074:
075: /**
076: * Replaces the given sub block with a new block.
077: * @param oldBlock the old sub block.
078: * @param newBlock the new sub block.
079: * @return false, if oldBlock wasn't a direct sub block.
080: */
081: public boolean replaceSubBlock(StructuredBlock oldBlock,
082: StructuredBlock newBlock) {
083: if (subBlock == oldBlock)
084: subBlock = newBlock;
085: else
086: return false;
087: return true;
088: }
089:
090: /**
091: * Tells if we want braces around this case. We only need braces
092: * if there is a declaration on the first level (list of
093: * sequential blocks).
094: */
095: protected boolean wantBraces() {
096: StructuredBlock block = subBlock;
097: if (block == null)
098: return false;
099: for (;;) {
100: if (block.declare != null && !block.declare.isEmpty()) {
101: /* A declaration; we need braces. */
102: return true;
103: }
104:
105: if (!(block instanceof SequentialBlock)) {
106: /* This was the last block on the first level.
107: * Finally check if that is an declaring InstructionBlock.
108: */
109: if (block instanceof InstructionBlock
110: && ((InstructionBlock) block).isDeclaration)
111: return true;
112:
113: /* If we get here, we need no braces.
114: */
115: return false;
116: }
117:
118: StructuredBlock[] subBlocks = block.getSubBlocks();
119: if (subBlocks[0] instanceof InstructionBlock
120: && ((InstructionBlock) subBlocks[0]).isDeclaration) {
121: /* An instruction block declares on the same level as
122: * the surrounding SequentialBlock.
123: */
124: return true;
125: }
126:
127: /* continue with the second sub block. */
128: block = subBlocks[1];
129: }
130: }
131:
132: /**
133: * Returns all sub block of this structured block.
134: */
135: public StructuredBlock[] getSubBlocks() {
136: return (subBlock != null) ? new StructuredBlock[] { subBlock }
137: : new StructuredBlock[0];
138: }
139:
140: public void dumpInstruction(jode.decompiler.TabbedPrintWriter writer)
141: throws java.io.IOException {
142: if (isDefault) {
143: /* If this is the default case and does nothing, we can
144: * skip this.
145: * We have to make sure, that nothing flows into the default
146: * block though. XXX remove if sure.
147: */
148: if (isLastBlock && subBlock instanceof EmptyBlock
149: && subBlock.jump == null)
150: return;
151: if (subBlock instanceof BreakBlock
152: && ((BreakBlock) subBlock).breaksBlock == this ) {
153: /* make sure that the previous block is correctly breaked */
154: if (isFallThrough) {
155: writer.tab();
156: subBlock.dumpSource(writer);
157: writer.untab();
158: }
159: return;
160: }
161: if (isFallThrough) {
162: writer.tab();
163: writer.println("/* fall through */");
164: writer.untab();
165: }
166: writer.print("default:");
167: } else {
168: if (isFallThrough) {
169: writer.tab();
170: writer.println("/* fall through */");
171: writer.untab();
172: }
173: ConstOperator constOp = new ConstOperator(
174: new Integer(value));
175: Type type = ((SwitchBlock) outer).getInstruction()
176: .getType();
177: constOp.setType(type);
178: constOp.makeInitializer(type);
179: writer.print("case " + constOp.toString() + ":");
180: }
181: if (subBlock != null) {
182: boolean needBraces = wantBraces();
183: if (needBraces)
184: writer.openBrace();
185: else
186: writer.println();
187: if (subBlock != null) {
188: writer.tab();
189: subBlock.dumpSource(writer);
190: writer.untab();
191: }
192: if (needBraces)
193: writer.closeBrace();
194: } else
195: writer.println();
196: }
197:
198: /**
199: * Determines if there is a sub block, that flows through to the end
200: * of this block. If this returns true, you know that jump is null.
201: * @return true, if the jump may be safely changed.
202: */
203: public boolean jumpMayBeChanged() {
204: return subBlock.jump != null || subBlock.jumpMayBeChanged();
205: }
206: }
|