Example #1
0
        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);
                    }
                }
            }
        }
Example #2
0
        //This is a modified version of the algorithm presented on the paper
        //"Taming Control Flow: A Structured Approach to Eliminating Goto Statements".
        public static void Eliminate(GotoStatement[] gotos)
        {
            for (int index = gotos.Length - 1; index >= 0; index--)
            {
                GotoStatement stmt = gotos[index];

                AstBlock gBlock = ParentBlock(stmt.Goto);
                AstBlock lBlock = ParentBlock(stmt.Label);

                int gLevel = Level(gBlock);
                int lLevel = Level(lBlock);

                if (IndirectlyRelated(gBlock, lBlock, gLevel, lLevel))
                {
                    AstBlock drBlock = gBlock;

                    int drLevel = gLevel;

                    do
                    {
                        drBlock = drBlock.Parent;

                        drLevel--;
                    }while (!DirectlyRelated(drBlock, lBlock, drLevel, lLevel));

                    MoveOutward(stmt, gLevel, drLevel);

                    gBlock = drBlock;
                    gLevel = drLevel;

                    if (Previous(stmt.Goto) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else)
                    {
                        //It's possible that the label was enclosed inside an else block,
                        //in this case we need to update the block and level.
                        //We also need to set the IsLoop for the case when the label is
                        //now before the goto, due to the newly introduced else block.
                        lBlock = ParentBlock(stmt.Label);

                        lLevel = Level(lBlock);

                        if (!IndirectlyRelated(elseBlock, lBlock, gLevel + 1, lLevel))
                        {
                            stmt.IsLoop = true;
                        }
                    }
                }

                if (DirectlyRelated(gBlock, lBlock, gLevel, lLevel))
                {
                    if (gLevel > lLevel)
                    {
                        MoveOutward(stmt, gLevel, lLevel);
                    }
                    else
                    {
                        if (stmt.IsLoop)
                        {
                            Lift(stmt);
                        }

                        MoveInward(stmt);
                    }
                }

                gBlock = ParentBlock(stmt.Goto);

                if (stmt.IsLoop)
                {
                    EncloseDoWhile(stmt, gBlock, stmt.Label);
                }
                else
                {
                    Enclose(gBlock, AstBlockType.If, stmt.Condition, Next(stmt.Goto), stmt.Label);
                }

                gBlock.Remove(stmt.Goto);
            }
        }