Exemplo n.º 1
0
        public override void CGenStmt(Env env, CGenState state)
        {
            Int32 label = state.DefaultLabel;

            state.CGenLabel(label);
            this.Stmt.CGenStmt(env, state);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Before: %st(0) = left, %st(1) = right, stack unchanged.
        /// After: with SetDouble, %eax = left op right, stack unchanged.
        /// </summary>
        public override sealed void OperateDouble(CGenState state)
        {
            // In the beginning, %st(0) = Left, %st(1) = Right.
            //
            // float stack:
            // +-----+
            // | rhs | <- %st(1)
            // +-----+
            // | lhs | <- %st(0)
            // +-----+
            //

            // 1. Do comparison between %st(0) and %st(1).
            //    Pop one Value from FPU stack.
            //
            // float stack:
            // +-----+
            // | rhs | <- %st(0)
            // +-----+
            //
            state.FUCOMIP();

            // 2. Pop another Value from FPU stack.
            //
            // float stack:
            // +-----+ empty
            //
            state.FSTP(Reg.ST0);

            // 3. Set bit based on comparison result.
            SetDouble(state);
            state.MOVZBL(Reg.AL, Reg.EAX);
        }
Exemplo n.º 3
0
        public override Reg CGenValue(CGenState state)
        {
            Int32 label_set = state.label_idx;

            state.label_idx++;
            Int32 label_finish = state.label_idx;

            state.label_idx++;

            Reg ret = this.Left.CGenValue(state);

            switch (ret)
            {
            case Reg.EAX:
                state.TESTL(Reg.EAX, Reg.EAX);
                state.JNZ(label_set);
                break;

            case Reg.ST0:
                state.FLDZ();
                state.FUCOMIP();
                state.FSTP(Reg.ST0);
                state.JNZ(label_set);
                break;

            default:
                throw new InvalidProgramException();
            }

            ret = this.Right.CGenValue(state);
            switch (ret)
            {
            case Reg.EAX:
                state.TESTL(Reg.EAX, Reg.EAX);
                state.JNZ(label_set);
                break;

            case Reg.ST0:
                state.FLDZ();
                state.FUCOMIP();
                state.FSTP(Reg.ST0);
                state.JNZ(label_set);
                break;

            default:
                throw new InvalidProgramException();
            }

            state.MOVL(0, Reg.EAX);

            state.JMP(label_finish);

            state.CGenLabel(label_set);

            state.MOVL(1, Reg.EAX);

            state.CGenLabel(label_finish);

            return(Reg.EAX);
        }
Exemplo n.º 4
0
        public override void CGenStmt(Env env, CGenState state)
        {
            Int32 start_label    = state.RequestLabel();
            Int32 finish_label   = state.RequestLabel();
            Int32 continue_label = state.RequestLabel();

            // start:
            state.CGenLabel(start_label);

            // Body
            state.InLoop(continue_label, finish_label);
            this.Body.CGenStmt(env, state);
            state.OutLabels();

            state.CGenLabel(continue_label);

            // test Cond
            Reg ret = CGenExprStmt(env, this.Cond, state);

            CGenTest(ret, state);

            state.JNZ(start_label);

            state.CGenLabel(finish_label);
        }
Exemplo n.º 5
0
        public override void CGenStmt(Env env, CGenState state)
        {
            ExprType ret_type = env.GetCurrentFunction().ReturnType;

            Int32 stack_size = state.StackSize;

            if (this.ExprOpt.IsSome)
            {
                // Evaluate the Value.
                this.ExprOpt.Value.CGenValue(state);

                // If the function returns a struct, copy it to the address given by 8(%ebp).
                if (this.ExprOpt.Value.Type is StructOrUnionType)
                {
                    state.MOVL(Reg.EAX, Reg.ESI);
                    state.MOVL(2 * ExprType.SIZEOF_POINTER, Reg.EBP, Reg.EDI);
                    state.MOVL(this.ExprOpt.Value.Type.SizeOf, Reg.ECX);
                    state.CGenMemCpy();
                    state.MOVL(2 * ExprType.SIZEOF_POINTER, Reg.EBP, Reg.EAX);
                }

                // Restore stack size.
                state.CGenForceStackSizeTo(stack_size);
            }
            // Jump to end of the function.
            state.JMP(state.ReturnLabel);
        }
Exemplo n.º 6
0
        public override Reg CGenValue(CGenState state)
        {
            Reg ret = this.Expr.CGenValue(state);

            switch (ret)
            {
            case Reg.EAX:
                state.TESTL(Reg.EAX, Reg.EAX);
                state.SETE(Reg.AL);
                state.MOVZBL(Reg.AL, Reg.EAX);
                return(Reg.EAX);

            case Reg.ST0:
                /// Compare Expr with 0.0
                /// < see cref = "BinaryComparisonOp.OperateFloat(CGenState)" />
                state.FLDZ();
                state.FUCOMIP();
                state.FSTP(Reg.ST0);
                state.SETE(Reg.AL);
                state.MOVZBL(Reg.AL, Reg.EAX);
                return(Reg.EAX);

            default:
                throw new InvalidProgramException();
            }
        }
Exemplo n.º 7
0
 public void CodeGenerate(CGenState state)
 {
     foreach (Tuple <Env, ExternDecln> decln in this.declns)
     {
         decln.Item2.CGenDecln(decln.Item1, state);
     }
 }
Exemplo n.º 8
0
        public override Reg CGenValue(CGenState state)
        {
            String name = state.CGenString(this.Value);

            state.LEA(name, Reg.EAX);
            return(Reg.EAX);
        }
Exemplo n.º 9
0
        public override void CGenStmt(Env env, CGenState state)
        {
            Int32 label = state.CaseLabel(this.Value);

            state.CGenLabel(label);
            this.Stmt.CGenStmt(env, state);
        }
Exemplo n.º 10
0
        private Compiler(String source)
        {
            this.Source = source;

            // Lexical analysis
            Scanner scanner = new Scanner(source);

            this.Tokens = scanner.Tokens.ToImmutableList();

            // Parse
            var parserResult = CParsers.Parse(this.Tokens);

            if (parserResult.Source.Count() != 1)
            {
                throw new InvalidOperationException("Error: not finished parsing");
            }
            this.SyntaxTree = parserResult.Result;

            // Semantic analysis
            var semantReturn = this.SyntaxTree.GetTranslnUnit();

            this.AbstractSyntaxTree = semantReturn.Value;
            this.Environment        = semantReturn.Env;

            // Code generation
            var state = new CGenState();

            this.AbstractSyntaxTree.CodeGenerate(state);
            this.Assembly = state.ToString();
        }
Exemplo n.º 11
0
        public void CGenPrepareWord(Env env, CGenState state) {
            // 1. Load lhs to EAX.
            // 
            // regs:
            // %eax = lhs
            // 
            // stack:
            // +-----+
            // | ... | <- %esp
            // +-----+
            // 
            if (lhs.CGenValue(env, state) != Reg.EAX) {
                throw new InvalidOperationException();
            }

            // 2. Push lhs to stack.
            // 
            // regs:
            // %eax = lhs
            // 
            // stack:
            // +-----+
            // | ... |
            // +-----+
            // | lhs | <- %esp has decreased by 4
            // +-----+
            // 
            Int32 stack_size = state.CGenPushLong(Reg.EAX);

            // 3. Load rhs to EAX.
            // 
            // regs:
            // %eax = rhs
            // 
            // stack:
            // +-----+
            // | ... |
            // +-----+
            // | lhs | <- %esp
            // +-----+
            // 
            if (rhs.CGenValue(env, state) != Reg.EAX) {
                throw new InvalidOperationException();
            }

            // 4. Move rhs into EBX. Pop lhs from stack, into EAX.
            // 
            // regs:
            // %eax = lhs
            // %ebx = rhs
            // 
            // stack:
            // +-----+
            // | ... | <- %esp has moved back.
            // +-----+
            // 
            state.MOVL(Reg.EAX, Reg.EBX);
            state.CGenPopLong(stack_size, Reg.EAX);
        }
Exemplo n.º 12
0
        public Reg CGenExprStmt(Env env, Expr expr, CGenState state)
        {
            Int32 stack_size = state.StackSize;
            Reg   ret        = expr.CGenValue(state);

            state.CGenForceStackSizeTo(stack_size);
            return(ret);
        }
Exemplo n.º 13
0
 public override Reg CGenValue(Env env, CGenState state)
 {
     Reg ret = expr.CGenValue(env, state);
     if (ret != Reg.EAX) {
         throw new InvalidProgramException();
     }
     state.NOT(Reg.EAX);
     return Reg.EAX;
 }
Exemplo n.º 14
0
 public override void CGenStmt(Env env, CGenState state)
 {
     if (this.ExprOpt.IsSome)
     {
         Int32 stack_size = state.StackSize;
         this.ExprOpt.Value.CGenValue(state);
         state.CGenForceStackSizeTo(stack_size);
     }
 }
Exemplo n.º 15
0
        public override void CGenAddress(CGenState state)
        {
            Reg ret = this.Expr.CGenValue(state);

            if (ret != Reg.EAX)
            {
                throw new InvalidProgramException();
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// flds addr
        /// </summary>
        public override Reg CGenValue(CGenState state)
        {
            byte[] bytes  = BitConverter.GetBytes(this.Value);
            Int32  intval = BitConverter.ToInt32(bytes, 0);
            String name   = state.CGenLongConst(intval);

            state.FLDS(name);
            return(Reg.ST0);
        }
Exemplo n.º 17
0
        public override Reg CGenValue(CGenState state)
        {
            Reg reg = Reg.EAX;

            foreach (Expr expr in this.Exprs)
            {
                reg = expr.CGenValue(state);
            }
            return(reg);
        }
Exemplo n.º 18
0
        /// <summary>
        /// fldl addr
        /// </summary>
        public override Reg CGenValue(CGenState state)
        {
            byte[] bytes     = BitConverter.GetBytes(this.Value);
            Int32  firstInt  = BitConverter.ToInt32(bytes, 0);
            Int32  secondInt = BitConverter.ToInt32(bytes, 4);
            String name      = state.CGenLongLongConst(firstInt, secondInt);

            state.FLDL(name);
            return(Reg.ST0);
        }
Exemplo n.º 19
0
        public override Reg CGenValue(CGenState state)
        {
            Reg ret = this.Expr.CGenValue(state);

            if (ret != Reg.EAX)
            {
                throw new InvalidProgramException();
            }
            state.NOT(Reg.EAX);
            return(Reg.EAX);
        }
Exemplo n.º 20
0
 public override void CGenStmt(Env env, CGenState state)
 {
     foreach (Tuple <Env, Decln> decln in this.Declns)
     {
         decln.Item2.CGenDecln(decln.Item1, state);
     }
     foreach (Tuple <Env, Stmt> stmt in this.Stmts)
     {
         stmt.Item2.CGenStmt(stmt.Item1, state);
     }
 }
Exemplo n.º 21
0
        public override void CGenStmt(Env env, CGenState state)
        {
            Reg ret = CGenExprStmt(env, this.Cond, state);

            Int32 finish_label = state.RequestLabel();

            CGenTest(ret, state);

            state.JZ(finish_label);

            this.Stmt.CGenStmt(env, state);

            state.CGenLabel(finish_label);
        }
Exemplo n.º 22
0
 /// <summary>
 /// 1. %st(0) = left, %st(1) = right, stack unchanged
 /// 2. Operate{Float, Double}
 /// </summary>
 public void CGenArithmetic(CGenState state)
 {
     if (this.Type is FloatType)
     {
         CGenFloat(state);
     }
     else if (this.Type is DoubleType)
     {
         CGenDouble(state);
     }
     else
     {
         CGenIntegral(state);
     }
 }
Exemplo n.º 23
0
        public void CGenDecln(Env env, CGenState state)
        {
            //     .text
            //     [.globl <func>]
            // <func>:
            //     pushl %ebp
            //     movl %esp, %ebp
            //
            state.TEXT();
            Env.Entry entry = env.Find(this.name).Value;
            state.COMMENT(ToString());
            switch (entry.Kind)
            {
            case Env.EntryKind.GLOBAL:
                switch (this.scs)
                {
                case StorageClass.AUTO:
                case StorageClass.EXTERN:
                    state.GLOBL(this.name);
                    break;

                case StorageClass.STATIC:
                    // static definition
                    break;

                default:
                    throw new InvalidOperationException();
                }
                break;

            default:
                throw new InvalidOperationException();
            }
            state.CGenFuncStart(this.name);

            state.InFunction(GotoLabelsGrabber.GrabLabels(this.stmt));

            this.stmt.CGenStmt(env, state);

            state.CGenLabel(state.ReturnLabel);
            state.OutFunction();

            //     leave
            //     ret
            state.LEAVE();
            state.RET();
            state.NEWLINE();
        }
Exemplo n.º 24
0
 public override sealed Reg CGenValue(CGenState state)
 {
     CGenArithmetic(state);
     if (this.Type is FloatType || this.Type is DoubleType)
     {
         return(Reg.ST0);
     }
     else if (this.Type is LongType || this.Type is ULongType)
     {
         return(Reg.EAX);
     }
     else
     {
         throw new InvalidOperationException("Invalid operand type.");
     }
 }
Exemplo n.º 25
0
        public override Reg CGenValue(CGenState state)
        {
            Reg ret = this.Expr.CGenValue(state);

            switch (this.Kind)
            {
            case TypeCastType.DOUBLE_TO_FLOAT:
            case TypeCastType.FLOAT_TO_DOUBLE:
            case TypeCastType.PRESERVE_INT16:
            case TypeCastType.PRESERVE_INT8:
            case TypeCastType.NOP:
                return(ret);

            case TypeCastType.DOUBLE_TO_INT32:
            case TypeCastType.FLOAT_TO_INT32:
                state.CGenConvertFloatToLong();
                return(Reg.EAX);

            case TypeCastType.INT32_TO_DOUBLE:
            case TypeCastType.INT32_TO_FLOAT:
                state.CGenConvertLongToFloat();
                return(Reg.ST0);

            case TypeCastType.INT16_TO_INT32:
                state.MOVSWL(Reg.AX, Reg.EAX);
                return(ret);

            case TypeCastType.INT8_TO_INT16:
            case TypeCastType.INT8_TO_INT32:
                state.MOVSBL(Reg.AL, Reg.EAX);
                return(ret);

            case TypeCastType.UINT16_TO_UINT32:
                state.MOVZWL(Reg.AX, Reg.EAX);
                return(ret);

            case TypeCastType.UINT8_TO_UINT16:
            case TypeCastType.UINT8_TO_UINT32:
                state.MOVZBL(Reg.AL, Reg.EAX);
                return(ret);

            default:
                throw new InvalidProgramException();
            }
        }
Exemplo n.º 26
0
        public override Reg CGenValue(CGenState state)
        {
            Reg ret = this.Expr.CGenValue(state);

            switch (ret)
            {
            case Reg.EAX:
                state.NEG(Reg.EAX);
                return(Reg.EAX);

            case Reg.ST0:
                state.FCHS();
                return(Reg.ST0);

            default:
                throw new InvalidProgramException();
            }
        }
Exemplo n.º 27
0
        public override void CGenAddress(CGenState state)
        {
            if (this.Expr.Type.Kind != ExprTypeKind.STRUCT_OR_UNION)
            {
                throw new InvalidProgramException();
            }

            // %eax = address of struct or union
            this.Expr.CGenAddress(state);

            // offset inside the pack
            Int32 offset = ((StructOrUnionType)this.Expr.Type)
                           .Attribs
                           .First(_ => _.name == this.Name)
                           .offset;

            state.ADDL(offset, Reg.EAX);
        }
Exemplo n.º 28
0
        //
        //          test Cond
        //          jz false ---+
        //          true_expr   |
        // +------- jmp finish  |
        // |    false: <--------+
        // |        false_expr
        // +--> finish:
        //
        public override Reg CGenValue(CGenState state)
        {
            Int32 stack_size = state.StackSize;
            Reg   ret        = this.Cond.CGenValue(state);

            state.CGenForceStackSizeTo(stack_size);

            // test Cond
            switch (ret)
            {
            case Reg.EAX:
                state.TESTL(Reg.EAX, Reg.EAX);
                break;

            case Reg.ST0:
                /// Compare Expr with 0.0
                /// < see cref = "BinaryComparisonOp.OperateFloat(CGenState)" />
                state.FLDZ();
                state.FUCOMIP();
                state.FSTP(Reg.ST0);
                break;

            default:
                throw new InvalidProgramException();
            }

            Int32 false_label  = state.RequestLabel();
            Int32 finish_label = state.RequestLabel();

            state.JZ(false_label);

            this.TrueExpr.CGenValue(state);

            state.JMP(finish_label);

            state.CGenLabel(false_label);

            ret = this.FalseExpr.CGenValue(state);

            state.CGenLabel(finish_label);

            return(ret);
        }
Exemplo n.º 29
0
        public void CGenTest(Env env, Reg ret, CGenState state) {
            // test cond
            switch (ret) {
                case Reg.EAX:
                    state.TESTL(Reg.EAX, Reg.EAX);
                    break;

                case Reg.ST0:
                    /// Compare expr with 0.0
                    /// < see cref = "BinaryArithmeticComp.OperateFloat(CGenState)" />
                    state.FLDZ();
                    state.FUCOMIP();
                    state.FSTP(Reg.ST0);
                    break;

                default:
                    throw new InvalidProgramException();
            }
        }
Exemplo n.º 30
0
        public override Reg CGenValue(Env env, CGenState state) {
            Reg ret = this.expr.CGenValue(env, state);
            switch (this.kind) {
                case Kind.DOUBLE_TO_FLOAT:
                case Kind.FLOAT_TO_DOUBLE:
                case Kind.PRESERVE_INT16:
                case Kind.PRESERVE_INT8:
                case Kind.NOP:
                    return ret;

                case Kind.DOUBLE_TO_INT32:
                case Kind.FLOAT_TO_INT32:
                    state.CGenConvertFloatToLong();
                    return Reg.EAX;

                case Kind.INT32_TO_DOUBLE:
                case Kind.INT32_TO_FLOAT:
                    state.CGenConvertLongToFloat();
                    return Reg.ST0;

                case Kind.INT16_TO_INT32:
                    state.MOVSWL(Reg.AX, Reg.EAX);
                    return ret;

                case Kind.INT8_TO_INT16:
                case Kind.INT8_TO_INT32:
                    state.MOVSBL(Reg.AL, Reg.EAX);
                    return ret;

                case Kind.UINT16_TO_UINT32:
                    state.MOVZWL(Reg.AX, Reg.EAX);
                    return ret;

                case Kind.UINT8_TO_UINT16:
                case Kind.UINT8_TO_UINT32:
                    state.MOVZBL(Reg.AL, Reg.EAX);
                    return ret;

                default:
                    throw new InvalidProgramException();
            }
        }
        public void CGenDecln(Env env, CGenState state) {
            //     .text
            //     [.globl <func>]
            // <func>:
            //     pushl %ebp
            //     movl %esp, %ebp
            // 
            state.TEXT();
            Env.Entry entry = env.Find(name).Value;
            state.COMMENT(ToString());
            switch (entry.kind) {
            case Env.EntryKind.GLOBAL:
                switch (scs) {
                case Decln.SCS.AUTO:
                case Decln.SCS.EXTERN:
                    state.GLOBL(name);
                    break;
                case Decln.SCS.STATIC:
                    // static definition
                    break;
                default:
                    throw new InvalidOperationException();
                }
                break;
            default:
                throw new InvalidOperationException();
            }
            state.CGenFuncStart(name);

            state.InFunction(GotoLabelsGrabber.GrabLabels(this.stmt));

            stmt.CGenStmt(env, state);

            state.CGenLabel(state.ReturnLabel);
            state.OutFunction();

            //     leave
            //     ret
            state.LEAVE();
            state.RET();
            state.NEWLINE();
        }
Exemplo n.º 32
0
        /// <summary>
        /// 1. %eax = left, %ebx = right, stack unchanged
        /// 2. Operate{Long, ULong}
        /// </summary>
        protected void CGenIntegral(CGenState state)
        {
            // %eax = left, %ebx = right, stack unchanged
            CGenPrepareIntegralOperands(state);

            if (this.Type is LongType)
            {
                // %eax = left op right, stack unchanged
                OperateLong(state);
            }
            else if (this.Type is ULongType)
            {
                // %eax = left op right, stack unchanged
                OperateULong(state);
            }
            else
            {
                throw new InvalidOperationException();
            }
        }
Exemplo n.º 33
0
        public void CGenTest(Reg ret, CGenState state)
        {
            // test Cond
            switch (ret)
            {
            case Reg.EAX:
                state.TESTL(Reg.EAX, Reg.EAX);
                break;

            case Reg.ST0:
                /// Compare Expr with 0.0
                /// < see cref = "BinaryComparisonOp.OperateFloat(CGenState)" />
                state.FLDZ();
                state.FUCOMIP();
                state.FSTP(Reg.ST0);
                break;

            default:
                throw new InvalidProgramException();
            }
        }
Exemplo n.º 34
0
        public override void CGenStmt(Env env, CGenState state)
        {
            // Init
            this.Init.Map(_ => CGenExprStmt(env, _, state));

            Int32 start_label    = state.RequestLabel();
            Int32 finish_label   = state.RequestLabel();
            Int32 continue_label = state.RequestLabel();

            // start:
            state.CGenLabel(start_label);

            // test cont
            this.Cond.Map(_ => {
                Reg ret = CGenExprStmt(env, _, state);
                CGenTest(ret, state);
                return(ret);
            });

            // jz finish
            state.JZ(finish_label);

            // Body
            state.InLoop(continue_label, finish_label);
            this.Body.CGenStmt(env, state);
            state.OutLabels();

            // continue:
            state.CGenLabel(continue_label);

            // Loop
            this.Loop.Map(_ => CGenExprStmt(env, _, state));

            // jmp start
            state.JMP(start_label);

            // finish:
            state.CGenLabel(finish_label);
        }
Exemplo n.º 35
0
        public override void CGenAddress(CGenState state)
        {
            Env.Entry entry  = this.Env.Find(this.Name).Value;
            Int32     offset = entry.Offset;

            switch (entry.Kind)
            {
            case Env.EntryKind.FRAME:
            case Env.EntryKind.STACK:
                state.LEA(offset, Reg.EBP, Reg.EAX);
                return;

            case Env.EntryKind.GLOBAL:
                state.LEA(this.Name, Reg.EAX);
                return;

            case Env.EntryKind.ENUM:
            case Env.EntryKind.TYPEDEF:
            default:
                throw new InvalidProgramException("cannot get the address of " + entry.Kind);
            }
        }
        public void CodeGenerate(CGenState state) {
            foreach (Tuple<Env, ExternDecln> decln in declns) {
                decln.Item2.CGenDecln(decln.Item1, state);
            }

        }
Exemplo n.º 37
0
 public override void CGenStmt(Env env, CGenState state) {
     state.CGenLabel(state.GotoLabel(this.label));
     state.CGenForceStackSizeTo(state.StackSize);
     this.stmt.CGenStmt(env, state);
 }
Exemplo n.º 38
0
        public override void CGenAddress(Env env, CGenState state)
        {
            Env.Entry entry = env.Find(name).Value;
            Int32 offset = entry.offset;

            switch (entry.kind) {
                case Env.EntryKind.FRAME:
                case Env.EntryKind.STACK:
                    state.LEA(offset, Reg.EBP, Reg.EAX);
                    return;

                case Env.EntryKind.GLOBAL:
                    state.LEA(name, Reg.EAX);
                    return;

                case Env.EntryKind.ENUM:
                case Env.EntryKind.TYPEDEF:
                default:
                    throw new InvalidProgramException("cannot get the address of " + entry.kind);
            }
        }
Exemplo n.º 39
0
        public override Reg CGenValue(Env env, CGenState state)
        {
            Env.Entry entry = env.Find(name).Value;

            Int32 offset = entry.offset;
            //if (entry.kind == Env.EntryKind.STACK) {
            //    offset = -offset;
            //}

            switch (entry.kind) {
                case Env.EntryKind.ENUM:
                    // 1. If the variable is an enum constant,
                    //    return the value in %eax.
                    state.MOVL(offset, Reg.EAX);
                    return Reg.EAX;

                case Env.EntryKind.FRAME:
                case Env.EntryKind.STACK:
                    // 2. If the variable is a function argument or a local variable,
                    //    the address would be offset(%ebp).
                    switch (type.kind) {
                        case ExprType.Kind.LONG:
                        case ExprType.Kind.ULONG:
                        case ExprType.Kind.POINTER:
                            // %eax = offset(%ebp)
                            state.MOVL(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.FLOAT:
                            // %st(0) = offset(%ebp)
                            state.FLDS(offset, Reg.EBP);
                            return Reg.ST0;

                        case ExprType.Kind.DOUBLE:
                            // %st(0) = offset(%ebp)
                            state.FLDL(offset, Reg.EBP);
                            return Reg.ST0;

                        case ExprType.Kind.STRUCT_OR_UNION:
                            // %eax = address
                            state.LEA(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                            //state.LEA(offset, Reg.EBP, Reg.ESI); // source address
                            //state.CGenExpandStackBy(Utils.RoundUp(type.SizeOf, 4));
                            //state.LEA(0, Reg.ESP, Reg.EDI); // destination address
                            //state.MOVL(type.SizeOf, Reg.ECX); // nbytes
                            //state.CGenMemCpy();
                            //return Reg.STACK;

                        case ExprType.Kind.VOID:
                            throw new InvalidProgramException("How could a variable be void?");
                            // %eax = $0
                            // state.MOVL(0, Reg.EAX);
                            // return Reg.EAX;

                        case ExprType.Kind.FUNCTION:
                            throw new InvalidProgramException("How could a variable be a function designator?");
                            // %eax = function_name
                            // state.MOVL(name, Reg.EAX);
                            // return Reg.EAX;

                        case ExprType.Kind.CHAR:
                            // %eax = [char -> long](off(%ebp))
                            state.MOVSBL(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.UCHAR:
                            // %eax = [uchar -> ulong](off(%ebp))
                            state.MOVZBL(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.SHORT:
                            // %eax = [short -> long](off(%ebp))
                            state.MOVSWL(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.USHORT:
                            // %eax = [ushort -> ulong](off(%ebp))
                            state.MOVZWL(offset, Reg.EBP, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.ARRAY:
                            // %eax = (off(%ebp))
                            state.LEA(offset, Reg.EBP, Reg.EAX); // source address
                            return Reg.EAX;

                        default:
                            throw new InvalidOperationException($"Cannot get value of {type.kind}");
                    }

                case Env.EntryKind.GLOBAL:
                    switch (type.kind) {
                        case ExprType.Kind.CHAR:
                            state.MOVSBL(name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.UCHAR:
                            state.MOVZBL(name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.SHORT:
                            state.MOVSWL(name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.USHORT:
                            state.MOVZWL(name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.LONG:
                        case ExprType.Kind.ULONG:
                        case ExprType.Kind.POINTER:
                            state.MOVL(name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.FUNCTION:
                            state.MOVL("$" + name, Reg.EAX);
                            return Reg.EAX;

                        case ExprType.Kind.FLOAT:
                            state.FLDS(name);
                            return Reg.ST0;

                        case ExprType.Kind.DOUBLE:
                            state.FLDL(name);
                            return Reg.ST0;

                        case ExprType.Kind.STRUCT_OR_UNION:
                            state.MOVL($"${name}", Reg.EAX);
                            return Reg.EAX;

                            //state.LEA(name, Reg.ESI); // source address
                            //state.CGenExpandStackBy(Utils.RoundUp(type.SizeOf, 4));
                            //state.LEA(0, Reg.ESP, Reg.EDI); // destination address
                            //state.MOVL(type.SizeOf, Reg.ECX); // nbytes
                            //state.CGenMemCpy();
                            //return Reg.STACK;

                        case ExprType.Kind.VOID:
                            throw new InvalidProgramException("How could a variable be void?");
                            //state.MOVL(0, Reg.EAX);
                            //return Reg.EAX;

                        case ExprType.Kind.ARRAY:
                            state.MOVL($"${name}", Reg.EAX);
                            return Reg.EAX;

                        default:
                            throw new InvalidProgramException("cannot get the value of a " + type.kind.ToString());
                    }

                case Env.EntryKind.TYPEDEF:
                default:
                    throw new InvalidProgramException("cannot get the value of a " + entry.kind.ToString());
            }
        }
Exemplo n.º 40
0
        //
        //          test cond
        //          jz false ---+
        //          true_expr   |
        // +------- jmp finish  |
        // |    false: <--------+
        // |        false_expr
        // +--> finish:
        //
        public override Reg CGenValue(Env env, CGenState state)
        {
            Int32 stack_size = state.StackSize;
            Reg ret = cond.CGenValue(env, state);
            state.CGenForceStackSizeTo(stack_size);

            // test cond
            switch (ret) {
                case Reg.EAX:
                    state.TESTL(Reg.EAX, Reg.EAX);
                    break;

                case Reg.ST0:
                    /// Compare expr with 0.0
                    /// < see cref = "BinaryArithmeticComp.OperateFloat(CGenState)" />
                    state.FLDZ();
                    state.FUCOMIP();
                    state.FSTP(Reg.ST0);
                    break;

                default:
                    throw new InvalidProgramException();
            }

            Int32 false_label = state.RequestLabel();
            Int32 finish_label = state.RequestLabel();

            state.JZ(false_label);

            true_expr.CGenValue(env, state);

            state.JMP(finish_label);

            state.CGenLabel(false_label);

            ret = false_expr.CGenValue(env, state);

            state.CGenLabel(finish_label);

            return ret;
        }
Exemplo n.º 41
0
 public override Reg CGenValue(Env env, CGenState state)
 {
     expr.CGenAddress(env, state);
     return Reg.EAX;
 }
Exemplo n.º 42
0
 public override void CGenStmt(Env env, CGenState state) {
     Int32 label = state.CaseLabel(value);
     state.CGenLabel(label);
     stmt.CGenStmt(env, state);
 }
Exemplo n.º 43
0
 public override void CGenStmt(Env env, CGenState state) {
     Int32 label = state.DefaultLabel;
     state.CGenLabel(label);
     stmt.CGenStmt(env, state);
 }
Exemplo n.º 44
0
 public override Reg CGenValue(Env env, CGenState state)
 {
     Reg reg = Reg.EAX;
     foreach (Expr expr in exprs) {
         reg = expr.CGenValue(env, state);
     }
     return reg;
 }
Exemplo n.º 45
0
 public Reg CGenExprStmt(Env env, Expr expr, CGenState state) {
     Int32 stack_size = state.StackSize;
     Reg ret = expr.CGenValue(env, state);
     state.CGenForceStackSizeTo(stack_size);
     return ret;
 }
Exemplo n.º 46
0
        public override void CGenAddress(Env env, CGenState state)
        {
            if (expr.type.kind != ExprType.Kind.STRUCT_OR_UNION) {
                throw new InvalidProgramException();
            }

            // %eax = address of struct or union
            expr.CGenAddress(env, state);

            // offset inside the pack
            Int32 offset = ((TStructOrUnion)expr.type)
                        .Attribs
                        .First(_ => _.name == name)
                        .offset;

            state.ADDL(offset, Reg.EAX);
        }
Exemplo n.º 47
0
 public override void CGenAddress(Env env, CGenState state)
 {
     Reg ret = expr.CGenValue(env, state);
     if (ret != Reg.EAX) {
         throw new InvalidProgramException();
     }
 }
Exemplo n.º 48
0
        public override Reg CGenValue(Env env, CGenState state)
        {
            // 1. %eax = &lhs
            lvalue.CGenAddress(env, state);

            // 2. push %eax
            Int32 pos = state.CGenPushLong(Reg.EAX);

            Reg ret = rvalue.CGenValue(env, state);
            switch (lvalue.type.kind) {
                case ExprType.Kind.CHAR:
                case ExprType.Kind.UCHAR:
                    // pop %ebx
                    // now %ebx = %lhs
                    state.CGenPopLong(pos, Reg.EBX);

                    // *%ebx = %al
                    state.MOVB(Reg.AL, 0, Reg.EBX);

                    return Reg.EAX;

                case ExprType.Kind.SHORT:
                case ExprType.Kind.USHORT:
                    // pop %ebx
                    // now %ebx = %lhs
                    state.CGenPopLong(pos, Reg.EBX);

                    // *%ebx = %al
                    state.MOVW(Reg.AX, 0, Reg.EBX);

                    return Reg.EAX;

                case ExprType.Kind.LONG:
                case ExprType.Kind.ULONG:
                case ExprType.Kind.POINTER:
                    // pop %ebx
                    // now %ebx = &lhs
                    state.CGenPopLong(pos, Reg.EBX);

                    // *%ebx = %al
                    state.MOVL(Reg.EAX, 0, Reg.EBX);

                    return Reg.EAX;

                case ExprType.Kind.FLOAT:
                    // pop %ebx
                    // now %ebx = &lhs
                    state.CGenPopLong(pos, Reg.EBX);

                    // *%ebx = %st(0)
                    state.FSTS(0, Reg.EBX);

                    return Reg.ST0;

                case ExprType.Kind.DOUBLE:
                    // pop %ebx
                    // now %ebx = &lhs
                    state.CGenPopLong(pos, Reg.EBX);

                    // *%ebx = %st(0)
                    state.FSTL(0, Reg.EBX);

                    return Reg.ST0;

                case ExprType.Kind.STRUCT_OR_UNION:
                    // pop %edi
                    // now %edi = &lhs
                    state.CGenPopLong(pos, Reg.EDI);

                    // %esi = &rhs
                    state.MOVL(Reg.EAX, Reg.ESI);

                    // %ecx = nbytes
                    state.MOVL(lvalue.type.SizeOf, Reg.ECX);

                    state.CGenMemCpy();

                    // %eax = &lhs
                    state.MOVL(Reg.EDI, Reg.EAX);

                    return Reg.EAX;

                case ExprType.Kind.FUNCTION:
                case ExprType.Kind.VOID:
                case ExprType.Kind.ARRAY:
                case ExprType.Kind.INCOMPLETE_ARRAY:
                default:
                    throw new InvalidProgramException("cannot assign to a " + type.kind.ToString());
            }
        }
Exemplo n.º 49
0
        public override void CGenStmt(Env env, CGenState state) {
            Int32 start_label = state.RequestLabel();
            Int32 finish_label = state.RequestLabel();
            Int32 continue_label = state.RequestLabel();

            // start:
            state.CGenLabel(start_label);

            // body
            state.InLoop(continue_label, finish_label);
            body.CGenStmt(env, state);
            state.OutLabels();

            state.CGenLabel(continue_label);

            // test cond
            Reg ret = CGenExprStmt(env, cond, state);
            CGenTest(env, ret, state);

            state.JNZ(start_label);

            state.CGenLabel(finish_label);
        }
Exemplo n.º 50
0
 public override void CGenAddress(Env env, CGenState state)
 {
     throw new Exception("Error: cannot get the address of a function call.");
 }
Exemplo n.º 51
0
        public override void CGenStmt(Env env, CGenState state) {
            Reg ret = CGenExprStmt(env, cond, state);

            CGenTest(env, ret, state);

            Int32 false_label = state.RequestLabel();
            Int32 finish_label = state.RequestLabel();

            state.JZ(false_label);

            true_stmt.CGenStmt(env, state);

            state.JMP(finish_label);

            state.CGenLabel(false_label);

            false_stmt.CGenStmt(env, state);

            state.CGenLabel(finish_label);

        }
Exemplo n.º 52
0
        public override Reg CGenValue(Env env, CGenState state)
        {
            // GCC's IA-32 calling convention
            // Caller is responsible to push all arguments to the stack in reverse order.
            // Each argument is at least aligned to 4 bytes - even a char would take 4 bytes.
            // The return value is stored in %eax, or %st(0), if it is a scalar.
            //
            // The stack would look like this after pushing all the arguments:
            // +--------+
            // |  ....  |
            // +--------+
            // |  argn  |
            // +--------+
            // |  ....  |
            // +--------+
            // |  arg2  |
            // +--------+
            // |  arg1  |
            // +--------+ <- %esp before call
            //
            // Things are different with structs and unions.
            // Since structs may not fit in 4 bytes, it has to be returned in memory.
            // Caller allocates a chunk of memory for the struct and push the address of it as an extra argument.
            // Callee returns %eax with that address.
            //
            // The stack would look like this after pushing all the arguments:
            //      +--------+
            // +--> | struct | <- struct should be returned here.
            // |    +--------+
            // |    |  argn  |
            // |    +--------+
            // |    |  ....  |
            // |    +--------+
            // |    |  arg2  |
            // |    +--------+
            // |    |  arg1  |
            // |    +--------+
            // +----|  addr  | <- %esp before call
            //      +--------+
            //

            state.NEWLINE();
            state.COMMENT($"Before pushing the arguments, stack size = {state.StackSize}.");

            var r_pack = Utils.PackArguments(args.Select(_ => _.type).ToList());
            Int32 pack_size = r_pack.Item1;
            IReadOnlyList<Int32> offsets = r_pack.Item2;

            if (type is TStructOrUnion) {
                // If the function returns a struct

                // Allocate space for return value.
                state.COMMENT("Allocate space for returning stack.");
                state.CGenExpandStackWithAlignment(type.SizeOf, type.Alignment);

                // Temporarily store the address in %eax.
                state.MOVL(Reg.ESP, Reg.EAX);

                // add an extra argument and move all other arguments upwards.
                pack_size += ExprType.SIZEOF_POINTER;
                offsets = offsets.Select(_ => _ + ExprType.SIZEOF_POINTER).ToList();
            }

            // Allocate space for arguments.
            // If returning struct, the extra pointer is included.
            state.COMMENT($"Arguments take {pack_size} bytes.");
            state.CGenExpandStackBy(pack_size);
            state.NEWLINE();

            // Store the address as the first argument.
            if (type is TStructOrUnion) {
                state.COMMENT("Putting extra argument for struct return address.");
                state.MOVL(Reg.EAX, 0, Reg.ESP);
                state.NEWLINE();
            }

            // This is the stack size before calling the function.
            Int32 header_base = -state.StackSize;

            // Push the arguments onto the stack in reverse order
            for (Int32 i = args.Count; i-- > 0;) {
                Expr arg = args[i];
                Int32 pos = header_base + offsets[i];

                state.COMMENT($"Argument {i} is at {pos}");

                Reg ret = arg.CGenValue(env, state);
                switch (arg.type.kind) {
                    case ExprType.Kind.ARRAY:
                    case ExprType.Kind.CHAR:
                    case ExprType.Kind.UCHAR:
                    case ExprType.Kind.SHORT:
                    case ExprType.Kind.USHORT:
                    case ExprType.Kind.LONG:
                    case ExprType.Kind.ULONG:
                    case ExprType.Kind.POINTER:
                        if (ret != Reg.EAX) {
                            throw new InvalidProgramException();
                        }
                        state.MOVL(Reg.EAX, pos, Reg.EBP);
                        break;

                    case ExprType.Kind.DOUBLE:
                        if (ret != Reg.ST0) {
                            throw new InvalidProgramException();
                        }
                        state.FSTPL(pos, Reg.EBP);
                        break;

                    case ExprType.Kind.FLOAT:
                        if (ret != Reg.ST0) {
                            throw new InvalidProgramException();
                        }
                        state.FSTPL(pos, Reg.EBP);
                        break;

                    case ExprType.Kind.STRUCT_OR_UNION:
                        if (ret != Reg.EAX) {
                            throw new InvalidProgramException();
                        }
                        state.MOVL(Reg.EAX, Reg.ESI);
                        state.LEA(pos, Reg.EBP, Reg.EDI);
                        state.MOVL(arg.type.SizeOf, Reg.ECX);
                        state.CGenMemCpy();
                        break;

                    default:
                        throw new InvalidProgramException();
                }

                state.NEWLINE();

            }

            // When evaluating arguments, the stack might be changed.
            // We must restore the stack.
            state.CGenForceStackSizeTo(-header_base);

            // Get function address
            if (func.type is TFunction) {
                func.CGenAddress(env, state);
            } else if (func.type is TPointer) {
                func.CGenValue(env, state);
            } else {
                throw new InvalidProgramException();
            }

            state.CALL("*%eax");

            state.COMMENT("Function returned.");
            state.NEWLINE();

            if (type.kind == ExprType.Kind.FLOAT || type.kind == ExprType.Kind.DOUBLE) {
                return Reg.ST0;
            } else {
                return Reg.EAX;
            }
        }
Exemplo n.º 53
0
        public override void CGenStmt(Env env, CGenState state) {
            // init
            init.Map(_ => CGenExprStmt(env, _, state));

            Int32 start_label = state.RequestLabel();
            Int32 finish_label = state.RequestLabel();
            Int32 continue_label = state.RequestLabel();

            // start:
            state.CGenLabel(start_label);

            // test cont
            cond.Map(_ => {
                Reg ret = CGenExprStmt(env, _, state);
                CGenTest(env, ret, state);
                return ret;
            });
            
            // jz finish
            state.JZ(finish_label);

            // body
            state.InLoop(continue_label, finish_label);
            body.CGenStmt(env, state);
            state.OutLabels();

            // continue:
            state.CGenLabel(continue_label);

            // loop
            loop.Map(_ => CGenExprStmt(env, _, state));

            // jmp start
            state.JMP(start_label);

            // finish:
            state.CGenLabel(finish_label);
        }
Exemplo n.º 54
0
        public override Reg CGenValue(Env env, CGenState state)
        {
            // %eax is the address of the struct/union
            if (expr.CGenValue(env, state) != Reg.EAX) {
                throw new InvalidProgramException();
            }

            if (expr.type.kind != ExprType.Kind.STRUCT_OR_UNION) {
                throw new InvalidProgramException();
            }

            // size of the struct or union
            Int32 struct_size = expr.type.SizeOf;

            // offset inside the pack
            Int32 attrib_offset = ((TStructOrUnion)expr.type)
                        .Attribs
                        .First(_ => _.name == name)
                        .offset;

            // can't be a function designator.
            switch (type.kind) {
                case ExprType.Kind.ARRAY:
                case ExprType.Kind.STRUCT_OR_UNION:
                    state.ADDL(attrib_offset, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.CHAR:
                    state.MOVSBL(attrib_offset, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.UCHAR:
                    state.MOVZBL(attrib_offset, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.SHORT:
                    state.MOVSWL(attrib_offset, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.USHORT:
                    state.MOVZWL(attrib_offset, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.LONG:
                case ExprType.Kind.ULONG:
                case ExprType.Kind.POINTER:
                    state.MOVL(attrib_offset, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.FLOAT:
                    state.FLDS(attrib_offset, Reg.EAX);
                    return Reg.ST0;

                case ExprType.Kind.DOUBLE:
                    state.FLDL(attrib_offset, Reg.EAX);
                    return Reg.ST0;

                default:
                    throw new InvalidProgramException();
            }
        }
Exemplo n.º 55
0
        public virtual void CGenPush(Env env, CGenState state)
        {
            Reg ret = CGenValue(env, state);

            switch (type.kind) {
                case ExprType.Kind.CHAR:
                case ExprType.Kind.UCHAR:
                case ExprType.Kind.SHORT:
                case ExprType.Kind.USHORT:
                case ExprType.Kind.LONG:
                case ExprType.Kind.ULONG:
                    // Integral
                    if (ret != Reg.EAX) {
                        throw new InvalidProgramException("Integral values should be returned to %eax");
                    }
                    state.CGenPushLong(Reg.EAX);
                    break;

                case ExprType.Kind.FLOAT:
                    // Float
                    if (ret != Reg.ST0) {
                        throw new InvalidProgramException("Floats should be returned to %st(0)");
                    }
                    state.CGenExpandStackBy4Bytes();
                    state.FSTS(0, Reg.ESP);
                    break;

                case ExprType.Kind.DOUBLE:
                    // Double
                    if (ret != Reg.ST0) {
                        throw new InvalidProgramException("Doubles should be returned to %st(0)");
                    }
                    state.CGenExpandStackBy8Bytes();
                    state.FSTL(0, Reg.ESP);
                    break;

                case ExprType.Kind.ARRAY:
                case ExprType.Kind.FUNCTION:
                case ExprType.Kind.POINTER:
                    // Pointer
                    if (ret != Reg.EAX) {
                        throw new InvalidProgramException("Pointer values should be returned to %eax");
                    }
                    state.CGenPushLong(Reg.EAX);
                    break;

                case ExprType.Kind.INCOMPLETE_ARRAY:
                case ExprType.Kind.VOID:
                    throw new InvalidProgramException(type.kind.ToString() + " can't be pushed onto the stack");

                case ExprType.Kind.STRUCT_OR_UNION:
                    throw new NotImplementedException();
            }
        }
Exemplo n.º 56
0
 public abstract Reg CGenValue(Env env, CGenState state);
Exemplo n.º 57
0
        public override Reg CGenValue(Env env, CGenState state)
        {
            Reg ret = expr.CGenValue(env, state);
            if (ret != Reg.EAX) {
                throw new InvalidProgramException();
            }
            if (expr.type.kind != ExprType.Kind.POINTER) {
                throw new InvalidProgramException();
            }

            ExprType type = ((TPointer)expr.type).ref_t;
            switch (type.kind) {
                case ExprType.Kind.ARRAY:
                case ExprType.Kind.FUNCTION:
                    return Reg.EAX;

                case ExprType.Kind.CHAR:
                    state.MOVSBL(0, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.UCHAR:
                    state.MOVZBL(0, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.SHORT:
                    state.MOVSWL(0, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.USHORT:
                    state.MOVZWL(0, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.LONG:
                case ExprType.Kind.ULONG:
                case ExprType.Kind.POINTER:
                    state.MOVL(0, Reg.EAX, Reg.EAX);
                    return Reg.EAX;

                case ExprType.Kind.FLOAT:
                    state.FLDS(0, Reg.EAX);
                    return Reg.ST0;

                case ExprType.Kind.DOUBLE:
                    state.FLDL(0, Reg.EAX);
                    return Reg.ST0;

                case ExprType.Kind.STRUCT_OR_UNION:
                    //// %esi = src address
                    //state.MOVL(Reg.EAX, Reg.ESI);

                    //// %edi = dst address
                    //state.CGenExpandStackBy(Utils.RoundUp(type.SizeOf, 4));
                    //state.LEA(0, Reg.ESP, Reg.EDI);

                    //// %ecx = nbytes
                    //state.MOVL(type.SizeOf, Reg.ECX);

                    //state.CGenMemCpy();

                    //return Reg.STACK;
                    return Reg.EAX;

                case ExprType.Kind.VOID:
                default:
                    throw new InvalidProgramException();
            }
        }
Exemplo n.º 58
0
        public override void CGenStmt(Env env, CGenState state) {

            // Inside a switch statement, the initializations are ignored,
            // but the stack size should be changed.
            List<Tuple<Env, Decln>> declns;
            List<Tuple<Env, Stmt>> stmts;
            switch (stmt.kind) {
                case Kind.COMPOUND:
                    declns = ((CompoundStmt)stmt).declns;
                    stmts = ((CompoundStmt)stmt).stmts;
                    break;
                default:
                    throw new NotImplementedException();
            }

            // Track all case values.
            IReadOnlyList<Int32> values = CaseLabelsGrabber.GrabLabels(this);

            // Make sure there are no duplicates.
            if (values.Distinct().Count() != values.Count) {
                throw new InvalidOperationException("case labels not unique.");
            }
            // Request labels for these values.
            Dictionary<Int32, Int32> value_to_label = values.ToDictionary(value => value, value => state.RequestLabel());

            Int32 label_finish = state.RequestLabel();

            Int32 num_default_stmts = stmts.Count(_ => _.Item2.kind == Kind.DEFAULT);
            if (num_default_stmts > 1) {
                throw new InvalidOperationException("duplicate defaults.");
            }
            Int32 label_default =
                num_default_stmts == 1 ?
                state.RequestLabel() :
                label_finish;

            Int32 saved_stack_size = state.StackSize;
            Int32 stack_size =
                declns.Any() ?
                declns.Last().Item1.StackSize :
                saved_stack_size;

            // 1. Evaluate expr.
            CGenExprStmt(env, expr, state);

            // 2. Expand stack.
            state.CGenForceStackSizeTo(stack_size);

            // 3. Make the Jump list.
            foreach (KeyValuePair<Int32, Int32> value_label_pair in value_to_label) {
                state.CMPL(value_label_pair.Key, Reg.EAX);
                state.JZ(value_label_pair.Value);
            }
            state.JMP(label_default);

            // 4. List all the statements.
            state.InSwitch(label_finish, label_default, value_to_label);
            foreach (Tuple<Env, Stmt> env_stmt_pair in stmts) {
                env_stmt_pair.Item2.CGenStmt(env_stmt_pair.Item1, state);
            }
            state.OutLabels();

            // 5. finish:
            state.CGenLabel(label_finish);
            
            // 6. Restore stack size.
            state.CGenForceStackSizeTo(saved_stack_size);
        }
Exemplo n.º 59
0
 public override void CGenStmt(Env env, CGenState state) {
     Int32 label = state.GotoLabel(this.label);
     state.JMP(label);
 }
Exemplo n.º 60
0
 public virtual void CGenAddress(Env env, CGenState state)
 {
     throw new NotImplementedException();
 }