public override void DoVisit(AST_Block node) { Console.Write("(BLK "); Console.Write(node.type + " {"); VisitChildren(node); Console.Write("})"); }
//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); }
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); } } }
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(); }
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); }
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); } }
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); } }
public abstract void DoVisit(AST_Block ast);