private static void EncloseSingleInst(GotoStatement stmt, Instruction inst) { AstBlock block = ParentBlock(stmt.Goto); AstBlock newBlock = new AstBlock(AstBlockType.If, stmt.Condition); block.AddAfter(stmt.Goto, newBlock); newBlock.AddFirst(new AstOperation(inst)); }
private static void RemoveEmptyBlocks(AstBlock mainBlock) { Queue <AstBlock> pending = new Queue <AstBlock>(); pending.Enqueue(mainBlock); while (pending.TryDequeue(out AstBlock block)) { foreach (IAstNode node in block) { if (node is AstBlock childBlock) { pending.Enqueue(childBlock); } } AstBlock parent = block.Parent; if (parent == null) { continue; } AstBlock nextBlock = Next(block) as AstBlock; bool hasElse = nextBlock != null && nextBlock.Type == AstBlockType.Else; bool isIf = block.Type == AstBlockType.If; if (block.Count == 0) { if (isIf) { if (hasElse) { nextBlock.TurnIntoIf(InverseCond(block.Condition)); } parent.Remove(block); } else if (block.Type == AstBlockType.Else) { parent.Remove(block); } } else if (isIf && parent.Type == AstBlockType.Else && parent.Count == (hasElse ? 2 : 1)) { AstBlock parentOfParent = parent.Parent; parent.Remove(block); parentOfParent.AddAfter(parent, block); if (hasElse) { parent.Remove(nextBlock); parentOfParent.AddAfter(block, nextBlock); } parentOfParent.Remove(parent); block.TurnIntoElseIf(); } } }
private static void MoveOutward(GotoStatement stmt, int gLevel, int lLevel) { AstBlock origin = ParentBlock(stmt.Goto); AstBlock block = origin; // Check if a loop is enclosing the goto, and the block that is // directly related to the label is above the loop block. // In that case, we need to introduce a break to get out of the loop. AstBlock loopBlock = origin; int loopLevel = gLevel; while (loopLevel > lLevel) { AstBlock child = loopBlock; loopBlock = loopBlock.Parent; loopLevel--; if (child.Type == AstBlockType.DoWhile) { EncloseSingleInst(stmt, Instruction.LoopBreak); block.Remove(stmt.Goto); loopBlock.AddAfter(child, stmt.Goto); block = loopBlock; gLevel = loopLevel; } } // Insert ifs to skip the parts that shouldn't be executed due to the goto. bool tryInsertElse = stmt.IsUnconditional && origin.Type == AstBlockType.If; while (gLevel > lLevel) { Enclose(block, AstBlockType.If, stmt.Condition, Next(stmt.Goto)); block.Remove(stmt.Goto); AstBlock child = block; // We can't move the goto in the middle of a if and a else block, in // this case we need to move it after the else. // IsLoop may need to be updated if the label is inside the else, as // introducing a loop is the only way to ensure the else will be executed. if (Next(child) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else) { child = elseBlock; } block = block.Parent; block.AddAfter(child, stmt.Goto); gLevel--; if (tryInsertElse && child == origin) { AstBlock lBlock = ParentBlock(stmt.Label); IAstNode last = block == lBlock && !stmt.IsLoop ? stmt.Label : null; AstBlock newBlock = Enclose(block, AstBlockType.Else, null, Next(stmt.Goto), last); if (newBlock != null) { block.Remove(stmt.Goto); block.AddAfter(newBlock, stmt.Goto); } } } }