gt: 		if (cond != FALSE)
context: /* LoopBlock Copyright (C) 1998-2002 Jochen Hoenicke.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program; see the file COPYING.LESSER.  If not, write to
   * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   * $Id: LoopBlock.java.in,v 4.3.2.2 2002/05/28 17:34:09 hoenicke Exp $
   */
  
  package jode.flow;
  import jode.decompiler.TabbedPrintWriter;
  import jode.type.Type;
  import jode.decompiler.LocalInfo;
  import jode.expr.Expression;
  import jode.expr.ConstOperator;
  import jode.expr.StoreInstruction;
  import jode.expr.LocalStoreOperator;
  import jode.expr.CombineableOperator;
  import jode.util.SimpleSet;
  
  import java.util.Set;
  
  /**
   * This is the structured block for an Loop block.
   */
  public class LoopBlock extends StructuredBlock implements BreakableBlock {
  
      public static final int WHILE = 0;
      public static final int DOWHILE = 1;
      public static final int FOR = 2;
      public static final int POSSFOR = 3;
  
      public static final Expression TRUE = 
          new ConstOperator(Boolean.TRUE);
      public static final Expression FALSE = 
          new ConstOperator(Boolean.FALSE);
  
      /**
       * The condition.  Must be of boolean type.
       */
      Expression cond;
      /**
       * The stack the condition eats.
       */
      VariableStack condStack;
      /**
       * The init instruction block, only valid if type == POSSFOR
       */
      InstructionBlock initBlock;
      /**
       * The increase instruction block, only valid if type == POSSFOR.
       */
      InstructionBlock incrBlock;
  
      /**
       * The init instruction, only valid if type == FOR.
       */
      Expression initInstr;
      /**
       * The increase instruction, only valid if type == FOR.
       */
      Expression incrInstr;
      
      /**
       * True, if the initializer is a declaration.
       */
      boolean isDeclaration;
  
      /**
       * The type of the loop.  This must be one of DOWHILE, WHILE or FOR.
       */
      int type;
  
      /**
       * The body of this loop.  This is always a valid block and not null.
       */
      StructuredBlock bodyBlock;
  
      /**
       * The stack after the break.
       */
      VariableStack breakedStack;
  
      /**
       * The stack at begin of the loop.
       */
      VariableStack continueStack;
  
      /*{ invariant { type == POSSFOR || (incrBlock == null && initBlock == null)
  		    :: "(while/do while) with incr";
  		    type == FOR || (incrInstr == null && initInstr == null)
  		    :: "(while/do while/poss for) with init";
  		    type != POSSFOR || incrBlock != null
  		    :: "possible for without incr";
  		    type != FOR || incrInstr != null
  		    :: "for without incr";
  		    type != POSSFOR ||
                      incrBlock.getInstruction() instanceof CombineableOperator
  		    :: "possible for with invalid incr";
  		    initBlock == null || 
  		    (initBlock.getInstruction() instanceof CombinableOperator)
  		    :: "Initializer is not combinableOperator";
  		    initInstr == null || 
  		    (initInstr instanceof CombinableOperator)
  		    :: "Initializer is not combinableOperator";
  		    cond != null && cond.getType() == Type.tBoolean
  		    :: "invalid condition type";
  		    type != POSSFOR || bodyBlock.contains(incr)
  		    :: "incr is not in body of possible for" } }*/
  
      /**
       * Returns the block where the control will normally flow to, when
       * the given sub block is finished (<em>not</em> ignoring the jump
       * after this block). (This is overwritten by SequentialBlock and
       * SwitchBlock).  If this isn't called with a direct sub block,
       * the behaviour is undefined, so take care.  
       * @return null, if the control flows to another FlowBlock.  */
      public StructuredBlock getNextBlock(StructuredBlock subBlock) {
          return this;
      }
  
      public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
          return null;
      }
      
      public LoopBlock(int type, Expression cond) {
          this.type = type;
          this.cond = cond;
          this.mayChangeJump = (cond == TRUE);
      }
  
      public void setBody(StructuredBlock body) {
          bodyBlock = body;
          bodyBlock.outer = this;
          body.setFlowBlock(flowBlock);
      }
  
      public void setInit(InstructionBlock initBlock) {
  	if (type == POSSFOR) {
  	    this.initBlock = initBlock;
          } else if (type == FOR) {
  	    this.initInstr = initBlock.getInstruction();
              initBlock.removeBlock();
  	}
      }
  
      public boolean conditionMatches(CombineableOperator combinable) {
          return (type == POSSFOR || cond.containsMatchingLoad(combinable));
      }
  
  
      public Expression getCondition() {
          return cond;
      }
  
      public void setCondition(Expression cond) {
          this.cond = cond;
          if (type == POSSFOR) {
              /* We can now say, if this is a for block or not.
               */
              if (cond.containsMatchingLoad((CombineableOperator)
  					  incrBlock.getInstruction())) {
                  type = FOR;
  		incrInstr = incrBlock.getInstruction();
                  incrBlock.removeBlock();
                  if (initBlock != null) {
                      if (cond.containsMatchingLoad
  			((CombineableOperator) initBlock.getInstruction())) {
  			initInstr = initBlock.getInstruction();
                          initBlock.removeBlock();
                      }
                  }
              } else {
                  /* This is not a for block, as it seems first.  Make
                   * it a while block again, and forget about init and
                   * incr.  */
                  type = WHILE;
              }
  	    initBlock = incrBlock = null;
          }
          mayChangeJump = false;
      }
  
      public int getType() {
          return type;
      }
  
      public void setType(int type) {
          this.type = type;
      }
  
      /**
       * Replaces the given sub block with a new block.
       * @param oldBlock the old sub block.
       * @param newBlock the new sub block.
       * @return false, if oldBlock wasn't a direct sub block.
       */
      public boolean replaceSubBlock(StructuredBlock oldBlock, 
                                     StructuredBlock newBlock) {
          if (bodyBlock == oldBlock)
              bodyBlock = newBlock;
          else
              return false;
          return true;
      }
  
      /**
       * Returns all sub block of this structured block.
       */
      public StructuredBlock[] getSubBlocks() {
          return new StructuredBlock[] { bodyBlock };
      }
  
      /**
       * Remove all variables from set, that we can declare inside the
       * loop-block.  This is the initializer for for-blocks.
       */
      public void removeLocallyDeclareable(Set set) {
  	if (type == FOR && initInstr instanceof StoreInstruction) {
  	    StoreInstruction storeOp = (StoreInstruction) initInstr;
  	    if (storeOp.getLValue() instanceof LocalStoreOperator) {
  		LocalInfo local = 
  		    ((LocalStoreOperator) storeOp.getLValue()).getLocalInfo();
  		set.remove(local);
  	    }
  	}
      }
  
      public Set getDeclarables() {
  	Set used = new SimpleSet();
          if (type == FOR) {
  	    incrInstr.fillDeclarables(used);
  	    if (initInstr != null)
  		initInstr.fillDeclarables(used);
  	}
  	cond.fillDeclarables(used);
          return used;
      }
  
      /**
       * Check if this is an local store instruction to a not yet declared
       * variable.  In that case mark this as declaration and return the 
       * variable.
       */
      public void checkDeclaration(Set declareSet) {
          if (initInstr instanceof StoreInstruction
  	    && (((StoreInstruction)initInstr).getLValue() 
  		instanceof LocalStoreOperator)) {
  	    StoreInstruction storeOp = (StoreInstruction) initInstr;
  	    LocalInfo local = 
  		((LocalStoreOperator) storeOp.getLValue()).getLocalInfo();
              if (declareSet.contains(local)) {
  		/* Special case: This is a variable assignment, and
  		 * the variable has not been declared before.  We can
  		 * change this to a initializing variable declaration.  
  		 */
  		isDeclaration = true;
  		declareSet.remove(local);
  	    }
  	}
      }
  
      /**
       * Make the declarations, i.e. initialize the declare variable
       * to correct values.  This will declare every variable that
       * is marked as used, but not done.
       * @param done The set of the already declare variables.
       */
      public void makeDeclaration(Set done) {
  	if (type == FOR) {
  	    if (initInstr != null)
  		initInstr.makeDeclaration(done);
  	    incrInstr.makeDeclaration(done);
  	}
  	cond.makeDeclaration(done);
  	super.makeDeclaration(done);
          if (type == FOR && initInstr != null)
  	    checkDeclaration(declare);
      }
  
      public void dumpSource(TabbedPrintWriter writer) 
  	throws java.io.IOException
      {
          super.dumpSource(writer);
      }
  
      public void dumpInstruction(TabbedPrintWriter writer) 
  	throws java.io.IOException
      {
          if (label != null) {
              writer.untab();
              writer.println(label+":");
              writer.tab();
          }
          boolean needBrace = bodyBlock.needsBraces();
          switch (type) {
          case POSSFOR:
              /* a possible for is now treated like a WHILE */
          case WHILE:
              if (cond == TRUE)
                  /* special syntax for endless loops: */
                  writer.print("for (;;)");
              else {
                  writer.print("while (");
  		cond.dumpExpression(writer.EXPL_PAREN, writer);
  		writer.print(")");
  	    }
              break;
          case DOWHILE:
              writer.print("do");
              break;
          case FOR:
              writer.print("for (");
  	    writer.startOp(writer.EXPL_PAREN, 0);
              if (initInstr != null) {
                  if (isDeclaration) {
  		    StoreInstruction store = (StoreInstruction) initInstr;
  		    LocalInfo local = ((LocalStoreOperator) store
  				       .getLValue()).getLocalInfo();
  		    writer.startOp(writer.NO_PAREN, 1);
  		    local.dumpDeclaration(writer);
  		    writer.breakOp();
  		    writer.print(" = ");
  		    store.getSubExpressions()[1]
  			.makeInitializer(local.getType());
  		    store.getSubExpressions()[1].dumpExpression(writer, 100);
  		    writer.endOp();
  		} else
  		    initInstr.dumpExpression(writer.NO_PAREN, writer);
              } else {
                  writer.print("/**/");
  	    }
              writer.print("; ");
  	    writer.breakOp();
  	    cond.dumpExpression(writer.IMPL_PAREN, writer);
  	    writer.print("; ");
  	    writer.breakOp();
  	    incrInstr.dumpExpression(writer.NO_PAREN, writer);
  	    writer.endOp();
  	    writer.print(")");
              break;
          }
  	if (needBrace)
  	    writer.openBrace();
  	else
  	    writer.println();
          writer.tab();
          bodyBlock.dumpSource(writer);
          writer.untab();
          if (type == DOWHILE) {
  	    if (needBrace)
  		writer.closeBraceContinue();
              writer.print("while (");
  	    cond.dumpExpression(writer.EXPL_PAREN, writer);
  	    writer.println(");");
          } else if (needBrace)
              writer.closeBrace();
      }
  
      boolean mayChangeJump = true;
  
      /**
       * The serial number for labels.
       */
      static int serialno = 0;
  
      /**
       * The label of this instruction, or null if it needs no label.
       */
      String label = null;
  
      /**
       * Returns the label of this block and creates a new label, if
       * there wasn't a label previously.
       */
      public String getLabel() {
          if (label == null)
              label = "while_"+(serialno++)+"_";
          return label;
      }
  
      /**
       * Is called by BreakBlock, to tell us that this block is breaked.
       */
      public void setBreaked() {
  	mayChangeJump = false;
      }
  
      /** 
       * This is called after the analysis is completely done.  It
       * will remove all PUSH/stack_i expressions, (if the bytecode
       * is correct).
       * @param stack the stack at begin of the block
       * @return null if there is no way to the end of this block,
       * otherwise the stack after the block has executed.  
       */
      public VariableStack mapStackToLocal(VariableStack stack) {
  	if (type == DOWHILE) {
  	    VariableStack afterBody = bodyBlock.mapStackToLocal(stack);
  	    if (afterBody != null)
  		mergeContinueStack(afterBody);
  
  	    if (continueStack != null) {
  		VariableStack newStack;
  		int params = cond.getFreeOperandCount();
  		if (params > 0) {
  		    condStack = continueStack.peek(params);
  		    newStack = continueStack.pop(params);
  		} else
  		    newStack = continueStack;
  
  		if (cond != TRUE)
  		    mergeBreakedStack(newStack);
  