예제 #1
0
 private SimanticsBlock FindSwitchBlockStart(SimanticsBlock end)
 {
     while (end.Parent != null)
     {
         if (end.BlockType == SimanticsBlockType.Switch)
         {
             return(end);
         }
         end = end.Parent;
     }
     return(null);
 }
예제 #2
0
        private void OutputBlock(SimanticsBlock block, CSTranslationClass cls)
        {
            for (int i = 0; i < block.IBody.Count - 1; i++)
            {
                var inst = block.IBody[i];
                var body = cls.Instructions[inst.Index];
                switch (body.ReturnType)
                {
                case PrimitiveReturnType.SimanticsTrue:
                case PrimitiveReturnType.SimanticsTrueFalse:     //truefalse result discarded, same destination
                    WriteLines(body.Body, true); break;

                case PrimitiveReturnType.NativeStatementTrue:
                case PrimitiveReturnType.NativeStatementTrueFalse:     //truefalse result discarded, same destination
                    WriteLines(body.Body, false); break;

                case PrimitiveReturnType.NativeExpressionTrueFalse:
                    //we have a problem... the expression needs to evaluate, but we don't do anything with the result.
                    //put it in the boolean temp and ignore it.
                    if (body.Body.Count == 1)
                    {
                        WriteLine($"_bResult = {body.Body.First()};");
                    }
                    else
                    {
                        WriteLines(body.Body, true);
                    }
                    break;

                case PrimitiveReturnType.SimanticsSubroutine:
                //a subroutine that yields but doesn't branch.
                default:
                    throw new Exception("Non-statement in the middle of a sequence (detected areas with no branching)?");
                }
            }

            var lastInst = block.IBody[block.IBody.Count - 1];
            var lastBody = cls.Instructions[lastInst.Index];

            LastInstruction = block.LastInstructionIndex;

            string caseConst = null;

            if (block.BlockType == SimanticsBlockType.Switch ||
                block.BlockType == SimanticsBlockType.SwitchCase ||
                block.BlockType == SimanticsBlockType.SwitchLast)
            {
                caseConst = CSScopeMemory.GetConstant(Context, block.SwitchOperand.RhsOwner, block.SwitchOperand.RhsData);
            }

            switch (block.BlockType)
            {
            case SimanticsBlockType.InstructionSequence:
            case SimanticsBlockType.IfElse:
                //just set the instruction based on the value and return back to the while loop
                if (lastBody.ReturnType == PrimitiveReturnType.SimanticsSubroutine || lastInst.Yields)
                {
                    UpdateInstruction();
                    if (lastBody.Body.Count > 1)
                    {
                        WriteLines(lastBody.Body, false);
                        WriteLine($"return _sResult;");
                    }
                    else
                    {
                        WriteLine($"return {lastBody.Body.First()};");
                    }
                    break;
                }

                switch (lastBody.ReturnType)
                {
                case PrimitiveReturnType.NativeStatementTrueFalse:
                    if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer)
                    {
                        goto case PrimitiveReturnType.NativeStatementTrue;
                    }
                    WriteLines(lastBody.Body, false);
                    WriteLine("if (_bResult) ");
                    OutputBinaryBranch(lastInst.Instruction, cls);
                    break;

                case PrimitiveReturnType.NativeExpressionTrueFalse:
                    if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer)
                    {
                        WriteLine($"_bResult = {lastBody.Body.First()}; //true and false do the same thing");
                        OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    }
                    else
                    {
                        WriteLine($"if ({lastBody.Body.First()}) ");
                        OutputBinaryBranch(lastInst.Instruction, cls);
                    }
                    break;

                case PrimitiveReturnType.SimanticsTrueFalse:
                    if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer)
                    {
                        goto case PrimitiveReturnType.SimanticsTrue;
                    }
                    WriteLine($"if ({lastBody.Body.First()} == VMPrimitiveExitCode.GOTO_TRUE) ");
                    OutputBinaryBranch(lastInst.Instruction, cls);
                    break;

                case PrimitiveReturnType.SimanticsStatement:
                    if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer)
                    {
                        WriteLines(lastBody.Body, false);
                        OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    }
                    else
                    {
                        WriteLines(lastBody.Body, false);
                        WriteLine($"if (_sResult == VMPrimitiveExitCode.GOTO_TRUE) ");
                        OutputBinaryBranch(lastInst.Instruction, cls);
                    }
                    break;

                case PrimitiveReturnType.NativeStatementTrue:
                    WriteLines(lastBody.Body, false);
                    OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    break;

                case PrimitiveReturnType.SimanticsTrue:
                    WriteLines(lastBody.Body, true);
                    OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    break;
                }

                if (block.Parent == cls.Structure.RootBlock && cls.HasGlobalSwitch)
                {
                    WriteLine("break;");
                }
                break;

            case SimanticsBlockType.Switch:
                string switchLhs = CSScopeMemory.GetExpression(Context, block.SwitchOperand.LhsOwner, block.SwitchOperand.LhsData, true);
                WriteLine($"switch ({switchLhs}) ");
                WriteLine("{");
                IndentLevel++;
                WriteLine($"case {caseConst}:");
                IndentLevel++;
                var set = new HashSet <string> {
                    caseConst
                };
                cls.SwitchPreviousCases[block] = set;
                OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                WriteLine($"break;");
                IndentLevel--;
                OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls);
                break;

            case SimanticsBlockType.SwitchCase:
                var cset = cls.SwitchPreviousCases[FindSwitchBlockStart(block)];

                if (cset.Contains(caseConst))
                {
                    WriteLine($"// case {caseConst} duplicated! skipped block at {lastInst.Instruction.FalsePointer}");
                }
                else
                {
                    cset.Add(caseConst);
                    WriteLine($"case {caseConst}:");
                    IndentLevel++;
                    OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    WriteLine($"break;");
                    IndentLevel--;
                }
                OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls);
                break;

            case SimanticsBlockType.SwitchLast:
                var lset = cls.SwitchPreviousCases[FindSwitchBlockStart(block)];

                if (lset.Contains(caseConst))
                {
                    WriteLine($"// case {caseConst} duplicated! skipped block at {lastInst.Instruction.FalsePointer}");
                }
                else
                {
                    lset.Add(caseConst);
                    WriteLine($"case {caseConst}:");
                    IndentLevel++;
                    OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls);
                    WriteLine($"break;");
                    IndentLevel--;
                }
                WriteLine($"default:");
                IndentLevel++;
                OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls);
                WriteLine($"break;");
                IndentLevel--;
                IndentLevel--;
                WriteLine("}");
                if (FindSwitchBlockStart(block).Parent == cls.Structure.RootBlock && cls.HasGlobalSwitch)
                {
                    WriteLine("break;");
                }
                break;

            default:
                throw new Exception($"Block type {block.BlockType.ToString()} not yet implemented.");
            }
            //our last instruction
        }