public async Task advent_glulx_start_function()
        {
            #region code
            //label_0:
            //    call 48 ()
            //    return 0";
            #endregion

            using (var stream = Resources.LoadResource(Resources.Glulx_Advent))
            {
                var machine = await GlulxMachine.CreateAsync(stream);

                var graph = ControlFlowGraph.Compute(machine.StartFunction.Body);

                Assert.Equal(3, graph.Blocks.Count);

                Assert.Single(graph.EntryBlock.Successors);
                Assert.Empty(graph.EntryBlock.Predecessors);

                Assert.Empty(graph.ExitBlock.Successors);
                Assert.Single(graph.ExitBlock.Predecessors);

                VerifyLabel(0, graph,
                            Predecessors(Entry),
                            Successors(Exit),
                            StatementCount(3));
            }
        }
示例#2
0
        public uint Evaluate(Function function)
        {
            var cfg    = ControlFlowGraph.Compute(function.Body);
            var block  = cfg.GetBlock(cfg.EntryBlock.Successors[0]);
            var result = 0u;

            while (!block.IsExit)
            {
                var nextBlockId = block.ID.GetNext();

                foreach (var statement in block.Statements)
                {
                    var jump = false;

                    // First, handle any control flow statements

                    void HandleReturnStatement(AstReturnStatement returnStatement)
                    {
                        result      = Evaluate(returnStatement.Expression);
                        nextBlockId = BlockId.Exit;
                        jump        = true;
                    }

                    void HandleJumpStatement(AstJumpStatement jumpStatement)
                    {
                        nextBlockId = new BlockId(jumpStatement.Label.Index);
                        jump        = true;
                    }

                    switch (statement.Kind)
                    {
                    case AstNodeKind.ReturnStatement:
                        HandleReturnStatement((AstReturnStatement)statement);
                        break;

                    case AstNodeKind.JumpStatement:
                        HandleJumpStatement((AstJumpStatement)statement);
                        break;

                    case AstNodeKind.BranchStatement:
                    {
                        var branchStatement = (AstBranchStatement)statement;
                        var condition       = Evaluate(branchStatement.Condition);
                        if (condition == 1)
                        {
                            switch (branchStatement.Statement.Kind)
                            {
                            case AstNodeKind.ReturnStatement:
                                HandleReturnStatement((AstReturnStatement)branchStatement.Statement);
                                break;

                            case AstNodeKind.JumpStatement:
                                HandleJumpStatement((AstJumpStatement)branchStatement.Statement);
                                break;

                            default:
                                throw new InvalidOperationException($"Invalid statement kind for branch: {branchStatement.Statement.Kind}");
                            }
                        }

                        continue;
                    }
                    }

                    if (jump)
                    {
                        break;
                    }

                    Evaluate(statement);
                }

                block = cfg.GetBlock(nextBlockId);
            }

            return(result);
        }
        public async Task glulxercise_glulx_function_48_has_correct_body()
        {
            #region code
            //label_0:
            //    call fb ()
            //    local_0 <- 74a
            //    push call 1c8bd (28c95, 0)
            //    if (pop != 4d2) then
            //        jump label_4
            //label_1:
            //    push call 1c8bd (28c95, 1)
            //    if (pop != 2) then
            //        jump label_4
            //label_2:
            //    push call 1c8bd (28c95, 2)
            //    if (pop != 0) then
            //        jump label_4
            //label_3:
            //    output-char a
            //    output-string 1d122
            //    call 1c93c (28c95, 1, 3)
            //    call 1c93c (28c95, 2, 3)
            //    output-string 1d147
            //    restore-undo
            //    output-string 1d156
            //    output-num local_0
            //    output-string 1d161
            //    quit
            //label_4:
            //    output-char a
            //    call 4e9 ()
            //    output-char a
            //    call e61 ()
            //    call 672 ()
            //    output-string 1d16d
            //    output-string 1d1a7
            //    return 1
            #endregion

            using (var stream = Resources.LoadResource(Resources.Glulx_Glulxercise))
            {
                var machine = await GlulxMachine.CreateAsync(stream);

                var function = machine.GetFunction(0x48);
                var graph    = ControlFlowGraph.Compute(function.Body);

                Assert.Equal(7, graph.Blocks.Count);

                Assert.Single(graph.EntryBlock.Successors);
                Assert.Empty(graph.EntryBlock.Predecessors);

                Assert.Empty(graph.ExitBlock.Successors);
                Assert.Equal(2, graph.ExitBlock.Predecessors.Count);

                VerifyLabel(0, graph,
                            Predecessors(Entry),
                            Successors(1, 4),
                            StatementCount(5));

                VerifyLabel(1, graph,
                            Predecessors(0),
                            Successors(2, 4),
                            StatementCount(3));

                VerifyLabel(2, graph,
                            Predecessors(1),
                            Successors(3, 4),
                            StatementCount(3));

                VerifyLabel(3, graph,
                            Predecessors(2),
                            Successors(Exit),
                            StatementCount(11));

                VerifyLabel(4, graph,
                            Predecessors(0, 1, 2),
                            Successors(Exit),
                            StatementCount(9));
            }
        }