void MunchStm(TreeStm stm)
        {
            switch (stm)
            {
            case StmCJump cjump:
            {
                if (cjump.Left is ExpConst c)
                {
                    Temp constTemp = new Temp();
                    Emit(new InstrBinary(InstrBinary.Kind.MOV, new Operand.Reg(constTemp), new Operand.Imm(c.Value)));
                    Emit(new InstrBinary(InstrBinary.Kind.CMP, new Operand.Reg(constTemp), MunchExp(cjump.Right)));
                }
                else
                {
                    Operand op1 = MunchExp(cjump.Left);
                    Operand op2 = MunchExp(cjump.Right);

                    if (op1 is Operand.Mem && op2 is Operand.Mem)
                    {
                        Operand.Reg memTemp = new Operand.Reg(new Temp());
                        Emit(new InstrBinary(InstrBinary.Kind.MOV, memTemp, op1));
                        Emit(new InstrBinary(InstrBinary.Kind.CMP, memTemp, op2));
                    }
                    else
                    {
                        Emit(new InstrBinary(InstrBinary.Kind.CMP, op1, op2));
                    }
                    //Emit(new InstrBinary(InstrBinary.Kind.CMP, MunchExp(cjump.Left), MunchExp(cjump.Right)));
                }

                InstrJump.Cond cond;

                switch (cjump.Rel)
                {
                case StmCJump.Relation.EQ:
                {
                    cond = InstrJump.Cond.NE;
                    break;
                }

                case StmCJump.Relation.GE:
                {
                    cond = InstrJump.Cond.L;
                    break;
                }

                case StmCJump.Relation.GT:
                {
                    cond = InstrJump.Cond.LE;
                    break;
                }

                case StmCJump.Relation.LE:
                {
                    cond = InstrJump.Cond.G;
                    break;
                }

                case StmCJump.Relation.LT:
                {
                    cond = InstrJump.Cond.GE;
                    break;
                }

                case StmCJump.Relation.NE:
                {
                    cond = InstrJump.Cond.E;
                    break;
                }

                default: throw new Exception("No Relation matched!");
                }
                Emit(new InstrJump(cond, cjump.LabelFalse));
                break;
            }

            case StmJump jump:
            {
                Emit(new InstrJump(InstrJump.Kind.JMP, jump.PossibleTargets[0]));
                break;
            }

            case StmLabel label:
            {
                Emit(new InstrLabel(label.Label));
                break;
            }

            case StmMove move:
            {
                Operand op1 = MunchExp(move.Dest);
                Operand op2 = MunchExp(move.Source);

                if (op1 is Operand.Mem && op2 is Operand.Mem)
                {
                    Operand.Reg t = new Operand.Reg(new Temp());

                    Emit(new InstrBinary(InstrBinary.Kind.MOV, t, op2));
                    Emit(new InstrBinary(InstrBinary.Kind.MOV, op1, t));
                }
                else
                {
                    Emit(new InstrBinary(InstrBinary.Kind.MOV, op1, op2));
                }

                break;
            }

            case StmSeq seq:
            {
                throw new Exception("No Sequences allowed!");
            }

            default:
            {
                throw new Exception("No case matched!");
            }
            }
        }
        Operand MunchExp(TreeExp exp)
        {
            switch (exp)
            {
            case ExpBinOp binop:
            {
                InstrBinary.Kind operation;

                switch (binop.Operator)
                {
                case ExpBinOp.Op.AND:
                {
                    operation = InstrBinary.Kind.AND;
                    break;
                }

                case ExpBinOp.Op.ARSHIFT:
                {
                    operation = InstrBinary.Kind.SHR;
                    break;
                }

                case ExpBinOp.Op.DIV:
                {
                    Emit(new InstrBinary(InstrBinary.Kind.MOV, new Operand.Reg(EAX), MunchExp(binop.Left)));
                    Operand     op   = MunchExp(binop.Right);
                    Operand.Reg temp = new Operand.Reg(new Temp());
                    if (op is Operand.Reg)
                    {
                        Emit(new InstrNullary(InstrNullary.Kind.CDQ));
                        Emit(new InstrUnary(InstrUnary.Kind.IDIV, op));
                    }
                    else
                    {
                        Emit(new InstrBinary(InstrBinary.Kind.MOV, temp, op));
                        Emit(new InstrNullary(InstrNullary.Kind.CDQ));
                        Emit(new InstrUnary(InstrUnary.Kind.IDIV, temp));
                    }
                    return(new Operand.Reg(EAX));
                }

                case ExpBinOp.Op.LSHIFT:
                {
                    operation = InstrBinary.Kind.SHL;
                    break;
                }

                case ExpBinOp.Op.MINUS:
                {
                    operation = InstrBinary.Kind.SUB;
                    break;
                }

                case ExpBinOp.Op.MUL:
                {
                    operation = InstrBinary.Kind.IMUL;
                    break;
                }

                case ExpBinOp.Op.OR:
                {
                    operation = InstrBinary.Kind.OR;
                    break;
                }

                case ExpBinOp.Op.PLUS:
                {
                    operation = InstrBinary.Kind.ADD;
                    break;
                }

                default: throw new Exception("not matched");
                }

                Operand tempOp = new Operand.Reg(new Temp());
                Emit(new InstrBinary(InstrBinary.Kind.MOV, tempOp, MunchExp(binop.Left)));
                Emit(new InstrBinary(operation, tempOp, MunchExp(binop.Right)));
                return(tempOp);
            }

            case ExpCall call:
            {
                ExpName name;

                if (call.Function is ExpName n)
                {
                    name = n;
                }
                else
                {
                    throw new Exception("No label");
                }

                for (int i = 0; i < call.Args.Count; i++)
                {
                    Temp argTemp = new Temp();
                    Emit(new InstrBinary(InstrBinary.Kind.MOV, new Operand.Reg(argTemp), MunchExp(call.Args[i])));
                    Emit(new InstrUnary(InstrUnary.Kind.PUSH, new Operand.Reg(argTemp)));
                }

                //Emit(new InstrBinary(InstrBinary.Kind.SUB, ))
                Emit(new InstrJump(InstrJump.Kind.CALL, name.Label, new List <RegTemp> {
                        (RegTemp)EAX, (RegTemp)ECX, (RegTemp)EDX
                    }));
                Emit(new InstrBinary(InstrBinary.Kind.ADD, new Operand.Reg(ESP), new Operand.Imm(call.Args.Count * 4)));
                return(new Operand.Reg(EAX));
            }

            case ExpConst con:
            {
                return(new Operand.Imm(con.Value));
            }

            case ExpMem mem:
            {
                // very confusing

                Temp bas = new Temp(); Temp index = new Temp();
                Emit(new InstrBinary(InstrBinary.Kind.MOV, new Operand.Reg(bas), MunchExp(mem.Address)));
                return(new Operand.Mem(bas));
            }

            case ExpName name:
            {
                Emit(new InstrLabel(name.Label));
                return(new Operand.Reg(new Temp()));
            }

            case ExpParam param:
            {
                //Temp parTemp = new Temp();
                //Emit(new InstrBinary(InstrBinary.Kind.MOV, new Operand.Reg(parTemp), new Operand.Mem(EBP, 0, null, (currentParamCount - param.Number) * 4 + 8)));
                //return new Operand.Reg(parTemp);
                return(new Operand.Mem(EBP, 0, null, (currentParamCount - param.Number) * 4 + 8));
            }

            case ExpTemp temp:
            {
                return(new Operand.Reg(temp.Temp));
            }

            default: throw new Exception("No expression matched.");
            }
        }