Esempio n. 1
0
 public override void DoVisit(AST_Block node)
 {
     Console.Write("(BLK ");
     Console.Write(node.type + " {");
     VisitChildren(node);
     Console.Write("})");
 }
Esempio n. 2
0
        //NOTE: returns jump instruction to be patched later
        Instruction EmitConditionPlaceholderAndBody(AST_Block ast, int idx)
        {
            //condition
            Visit(ast.children[idx]);
            var jump_op = Emit(Opcodes.JumpZ, new int[] { 0 });

            Visit(ast.children[idx + 1]);
            return(jump_op);
        }
Esempio n. 3
0
 void PatchBreaks(AST_Block block)
 {
     for (int i = non_patched_breaks.Count; i-- > 0;)
     {
         var npb = non_patched_breaks[i];
         if (npb.block == block)
         {
             AddOffsetFromTo(npb.jump_op, Peek());
             non_patched_breaks.RemoveAt(i);
         }
     }
 }
Esempio n. 4
0
 void PatchContinues(AST_Block block)
 {
     for (int i = non_patched_continues.Count; i-- > 0;)
     {
         var npc = non_patched_continues[i];
         if (npc.block == block)
         {
             AddOffsetFromTo(npc.jump_op, continue_jump_markers[npc.block]);
             non_patched_continues.RemoveAt(i);
         }
     }
     continue_jump_markers.Clear();
 }
Esempio n. 5
0
        void VisitDefer(AST_Block ast)
        {
            var parent_block = ctrl_blocks.Count > 0 ? ctrl_blocks.Peek() : null;

            if (parent_block != null)
            {
                block_has_defers.Add(parent_block);
            }

            var block_op = Emit(Opcodes.Block, new int[] { (int)ast.type, 0 /*patched later*/ });

            VisitChildren(ast);
            AddOffsetFromTo(block_op, Peek(), operand_idx: 1);
        }
Esempio n. 6
0
        void VisitControlBlock(AST_Block ast)
        {
            var parent_block = ctrl_blocks.Count > 0 ? ctrl_blocks.Peek() : null;

            bool parent_is_paral =
                parent_block != null &&
                (parent_block.type == BlockType.PARAL ||
                 parent_block.type == BlockType.PARAL_ALL);

            bool is_paral =
                ast.type == BlockType.PARAL ||
                ast.type == BlockType.PARAL_ALL;

            ctrl_blocks.Push(ast);

            var block_op = Emit(Opcodes.Block, new int[] { (int)ast.type, 0 /*patched later*/ });

            for (int i = 0; i < ast.children.Count; ++i)
            {
                var child = ast.children[i];

                //NOTE: let's automatically wrap all children with sequence if
                //      they are inside paral block
                if (is_paral &&
                    (!(child is AST_Block child_block) ||
                     (child_block.type != BlockType.SEQ && child_block.type != BlockType.DEFER)))
                {
                    var seq_child = new AST_Block(BlockType.SEQ);
                    seq_child.children.Add(child);
                    child = seq_child;
                }

                Visit(child);
            }

            ctrl_blocks.Pop();

            bool need_block = is_paral || parent_is_paral || block_has_defers.Contains(ast) || HasOffsetsTo(block_op);

            if (need_block)
            {
                AddOffsetFromTo(block_op, Peek(), operand_idx: 1);
            }
            else
            {
                head.Remove(block_op);
            }
        }
Esempio n. 7
0
        public override void DoVisit(AST_Block ast)
        {
            switch (ast.type)
            {
            case BlockType.IF:

                //if()
                // ^-- to be patched with position out of 'if body'
                //{
                // ...
                // jmp_opcode
                // ^-- to be patched with position out of 'if body'
                //}
                //else if()
                // ^-- to be patched with position out of 'if body'
                //{
                // ...
                // jmp_opcode
                // ^-- to be patched with position out of 'if body'
                //}
                //else
                //{
                //}

                Instruction last_jmp_op = null;
                int         i           = 0;
                //NOTE: amount of children is even if there's no 'else'
                for (; i < ast.children.Count; i += 2)
                {
                    //break if there's only 'else leftover' left
                    if ((i + 2) > ast.children.Count)
                    {
                        break;
                    }

                    var if_op = EmitConditionPlaceholderAndBody(ast, i);
                    if (last_jmp_op != null)
                    {
                        AddOffsetFromTo(last_jmp_op, Peek());
                    }

                    //check if uncoditional jump out of 'if body' is required,
                    //it's required only if there are other 'else if' or 'else'
                    if (ast.children.Count > 2)
                    {
                        last_jmp_op = Emit(Opcodes.Jump, new int[] { 0 });
                        AddOffsetFromTo(if_op, Peek());
                    }
                    else
                    {
                        AddOffsetFromTo(if_op, Peek());
                    }
                }
                //check fo 'else leftover'
                if (i != ast.children.Count)
                {
                    Visit(ast.children[i]);
                    AddOffsetFromTo(last_jmp_op, Peek());
                }
                break;

            case BlockType.WHILE:
            {
                if (ast.children.Count != 2)
                {
                    throw new Exception("Unexpected amount of children (must be 2)");
                }

                loop_blocks.Push(ast);

                var begin_op = Peek();

                var cond_op = EmitConditionPlaceholderAndBody(ast, 0);

                //to the beginning of the loop
                var jump_op = Emit(Opcodes.Jump, new int[] { 0 });
                AddOffsetFromTo(jump_op, begin_op);

                //patch 'jump out of the loop' position
                AddOffsetFromTo(cond_op, Peek());

                PatchContinues(ast);

                PatchBreaks(ast);

                loop_blocks.Pop();
            }
            break;

            case BlockType.DOWHILE:
            {
                if (ast.children.Count != 2)
                {
                    throw new Exception("Unexpected amount of children (must be 2)");
                }

                loop_blocks.Push(ast);

                var begin_op = Peek();

                Visit(ast.children[0]);
                Visit(ast.children[1]);
                var cond_op = Emit(Opcodes.JumpZ, new int[] { 0 });

                //to the beginning of the loop
                var jump_op = Emit(Opcodes.Jump, new int[] { 0 });
                AddOffsetFromTo(jump_op, begin_op);

                //patch 'jump out of the loop' position
                AddOffsetFromTo(cond_op, Peek());

                PatchContinues(ast);

                PatchBreaks(ast);

                loop_blocks.Pop();
            }
            break;

            case BlockType.FUNC:
            {
                VisitChildren(ast);
            }
            break;

            case BlockType.SEQ:
            case BlockType.PARAL:
            case BlockType.PARAL_ALL:
            {
                VisitControlBlock(ast);
            }
            break;

            case BlockType.DEFER:
            {
                VisitDefer(ast);
            }
            break;

            default:
                throw new Exception("Not supported block type: " + ast.type);
            }
        }
Esempio n. 8
0
 public abstract void DoVisit(AST_Block ast);