Пример #1
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);
     }
 }
Пример #2
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;
 }
Пример #3
0
        // %eax = left, %ebx = right, stack unchanged
        private void CGenPrepareIntegralOperands(CGenState state) {
            // 1. Load Left to EAX.
            // 
            // regs:
            // %eax = Left
            // 
            // stack:
            // +-----+
            // | ... | <- %esp
            // +-----+
            // 
            if (this.Left.CGenValue(state) != Reg.EAX) {
                throw new InvalidOperationException();
            }

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

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

            // 4. Move Right into EBX. Pop Left from stack, into EAX.
            // 
            // regs:
            // %eax = Left
            // %ebx = Right
            // 
            // stack:
            // +-----+
            // | ... | <- %esp has moved back.
            // +-----+
            // 
            state.MOVL(Reg.EAX, Reg.EBX);
            state.CGenPopLong(stack_size, Reg.EAX);
        }
Пример #4
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);
     }
 }
Пример #5
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;
 }
Пример #6
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();
            }
        }
Пример #7
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();
        }
Пример #8
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();
            }
        }
Пример #9
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);
            }
        }
Пример #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();
        }
Пример #11
0
 // Float
 // Before the actual calculation, the state is set to this.
 // 
 // regs:
 // %ecx = &expr
 // 
 // stack:
 // +-------+
 // | ..... | <- %esp
 // +-------+
 // 
 // float stack:
 // +-------+
 // | expr  | <- %st(1)
 // +-------+
 // |  1.0  | <- %st(0)
 // +-------+
 // 
 // After the calculation, the result should be in %st(0),
 // and memory should be updated.
 // 
 public abstract void CalcAndSaveFloat(CGenState state);
Пример #12
0
 public override void CGenAddress(CGenState state) {
     throw new InvalidOperationException("Cannot get the address of a cast expression.");
 }
Пример #13
0
 public override void CalcAndSaveByte(CGenState state) {
     state.SUBL(1, Reg.EAX);
     state.MOVB(Reg.AL, 0, Reg.ECX);
 }
Пример #14
0
        public override sealed Reg CGenValue(CGenState state) {

            // 1. Get the address of expr.
            // 
            // regs:
            // %eax = &expr
            // 
            // stack:
            // +-------+
            // | ..... | <- %esp
            // +-------+
            // 
            this.Expr.CGenAddress(state);

            // 2. Push address.
            // 
            // regs:
            // %eax = &expr
            // 
            // stack:
            // +-------+
            // | ..... |
            // +-------+
            // | &expr | <- %esp
            // +-------+
            // 
            Int32 stack_size = state.CGenPushLong(Reg.EAX);

            // 3. Get current Value of expr.
            // 
            // 1) If expr is an integral or pointer:
            // 
            // regs:
            // %eax = expr
            // 
            // stack:
            // +-------+
            // | ..... |
            // +-------+
            // | &expr | <- %esp
            // +-------+
            // 
            // 
            // 2) If expr is a float:
            // 
            // regs:
            // %eax = &expr
            // 
            // stack:
            // +-------+
            // | ..... |
            // +-------+
            // | &expr | <- %esp
            // +-------+
            // 
            // float stack:
            // +-------+
            // | expr  | <- %st(0)
            // +-------+
            // 
            Reg ret = this.Expr.CGenValue(state);

            switch (ret) {
                case Reg.EAX:
                    // expr is an integral or pointer.

                    // 4. Pop address to %ecx.
                    // 
                    // regs:
                    // %eax = expr
                    // %ecx = &expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    state.CGenPopLong(stack_size, Reg.ECX);

                    // 5. Cache current Value of Expr in %ebx.
                    // 
                    // regs:
                    // %eax = expr
                    // %ebx = expr
                    // %ecx = &expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    state.MOVL(Reg.EAX, Reg.EBX);

                    // 6. Calculate the new value in %ebx or %eax and save.
                    //    Set %eax to be the return Value.
                    // 
                    // regs:
                    // %eax = expr or (expr +- 1)
                    // %ebx = (expr +- 1) or expr
                    // %ecx = &expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    switch (this.Expr.Type.Kind) {
                        case ExprTypeKind.CHAR:
                        case ExprTypeKind.UCHAR:
                            CalcAndSaveByte(state);
                            return Reg.EAX;

                        case ExprTypeKind.SHORT:
                        case ExprTypeKind.USHORT:
                            CalcAndSaveWord(state);
                            return Reg.EAX;

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                            CalcAndSaveByte(state);
                            return Reg.EAX;

                        case ExprTypeKind.POINTER:
                            CalcAndSavePtr(state);
                            return Reg.EAX;

                        default:
                            throw new InvalidProgramException();
                    }

                case Reg.ST0:
                    // Expr is a float.

                    // 4. Pop address to %ecx.
                    // 
                    // regs:
                    // %ecx = &expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    state.CGenPopLong(stack_size, Reg.ECX);

                    // 5. Load 1.0 to FPU stack.
                    // 
                    // regs:
                    // %ecx = &expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    // float stack:
                    // +-------+
                    // | expr  | <- %st(1)
                    // +-------+
                    // |  1.0  | <- %st(0)
                    // +-------+
                    // 
                    state.FLD1();

                    // 6. Calculate the new value and save back.
                    //    Set %st(0) to be the new or original Value.
                    // 
                    // regs:
                    // %ecx = &Expr
                    // 
                    // stack:
                    // +-------+
                    // | ..... | <- %esp
                    // +-------+
                    // 
                    // float stack:
                    // +---------------------+
                    // | expr or (epxr +- 1) | <- %st(0)
                    // +---------------------+
                    // 
                    switch (this.Expr.Type.Kind) {
                        case ExprTypeKind.FLOAT:
                            CalcAndSaveFloat(state);
                            return Reg.ST0;

                        case ExprTypeKind.DOUBLE:
                            CalcAndSaveDouble(state);
                            return Reg.ST0;

                        default:
                            throw new InvalidProgramException();
                    }

                default:
                    throw new InvalidProgramException();
            }

        }
Пример #15
0
        public void CodeGenerate(CGenState state) {
            foreach (Tuple<Env, ExternDecln> decln in this.declns) {
                decln.Item2.CGenDecln(decln.Item1, state);
            }

        }
Пример #16
0
 public override Reg CGenValue(CGenState state) {
     state.MOVL((Int32)this.Value, Reg.EAX);
     return Reg.EAX;
 }
Пример #17
0
 public override void CalcAndSaveWord(CGenState state) {
     state.SUBL(1, Reg.EAX);
     state.MOVW(Reg.AX, 0, Reg.ECX);
 }
Пример #18
0
 public abstract void CalcAndSavePtr(CGenState state);
Пример #19
0
        // * function;
        // * extern function;
        // * static function;
        // * obj;
        // * obj = Init;
        // * static obj;
        // * static obj = Init;
        // * extern obj;
        // * extern obj = Init;
        public void CGenDecln(Env env, CGenState state) {

            if (env.IsGlobal()) {

                if (this.initr.IsSome) {
                    Initr initr = this.initr.Value;
                    switch (this.scs) {
                        case StorageClass.AUTO:
                            state.GLOBL(this.name);
                            break;

                        case StorageClass.EXTERN:
                            throw new InvalidProgramException();

                        case StorageClass.STATIC:
                            break;

                        case StorageClass.TYPEDEF:
                            // Ignore.
                            return;

                        default:
                            throw new InvalidProgramException();
                    }

                    state.DATA();

                    state.ALIGN(ExprType.ALIGN_LONG);

                    state.CGenLabel(this.name);

                    Int32 last = 0;
                    initr.Iterate(this.type, (Int32 offset, Expr expr) => {
                        if (offset > last) {
                            state.ZERO(offset - last);
                        }

                        if (!expr.IsConstExpr) {
                            throw new InvalidOperationException("Cannot initialize with non-const expression.");
                        }

                        switch (expr.Type.Kind) {
                            // TODO: without const char/short, how do I initialize?
                            case ExprTypeKind.CHAR:
                            case ExprTypeKind.UCHAR:
                            case ExprTypeKind.SHORT:
                            case ExprTypeKind.USHORT:
                                throw new NotImplementedException();
                            case ExprTypeKind.LONG:
                                state.LONG(((ConstLong)expr).Value);
                                break;

                            case ExprTypeKind.ULONG:
                                state.LONG((Int32)((ConstULong)expr).Value);
                                break;

                            case ExprTypeKind.POINTER:
                                state.LONG((Int32)((ConstPtr)expr).Value);
                                break;

                            case ExprTypeKind.FLOAT:
                                byte[] float_bytes = BitConverter.GetBytes(((ConstFloat)expr).Value);
                                Int32 intval = BitConverter.ToInt32(float_bytes, 0);
                                state.LONG(intval);
                                break;

                            case ExprTypeKind.DOUBLE:
                                byte[] double_bytes = BitConverter.GetBytes(((ConstDouble)expr).Value);
                                Int32 first_int = BitConverter.ToInt32(double_bytes, 0);
                                Int32 second_int = BitConverter.ToInt32(double_bytes, 4);
                                state.LONG(first_int);
                                state.LONG(second_int);
                                break;

                            default:
                                throw new InvalidProgramException();
                        }

                        last = offset + expr.Type.SizeOf;
                    });

                } else {

                    // Global without initialization.

                    switch (this.scs) {
                        case StorageClass.AUTO:
                            // .comm name,size,align
                            break;

                        case StorageClass.EXTERN:
                            break;

                        case StorageClass.STATIC:
                            // .local name
                            // .comm name,size,align
                            state.LOCAL(this.name);
                            break;

                        case StorageClass.TYPEDEF:
                            // Ignore.
                            return;

                        default:
                            throw new InvalidProgramException();
                    }

                    if (this.type.Kind != ExprTypeKind.FUNCTION) {
                        state.COMM(this.name, this.type.SizeOf, ExprType.ALIGN_LONG);
                    }

                    
                }

                state.NEWLINE();

            } else {
                // stack object

                state.CGenExpandStackTo(env.StackSize, ToString());

                Int32 stack_size = env.StackSize;

                // pos should be equal to stack_size, but whatever...
                Int32 pos = env.Find(this.name).Value.Offset;
                if (this.initr.IsNone) {
                    return;
                }

                Initr initr = this.initr.Value;
                initr.Iterate(this.type, (Int32 offset, Expr expr) => {
                    Reg ret = expr.CGenValue(state);
                    switch (expr.Type.Kind) {
                        case ExprTypeKind.CHAR:
                        case ExprTypeKind.UCHAR:
                            state.MOVB(Reg.EAX, pos + offset, Reg.EBP);
                            break;

                        case ExprTypeKind.SHORT:
                        case ExprTypeKind.USHORT:
                            state.MOVW(Reg.EAX, pos + offset, Reg.EBP);
                            break;

                        case ExprTypeKind.DOUBLE:
                            state.FSTPL(pos + offset, Reg.EBP);
                            break;

                        case ExprTypeKind.FLOAT:
                            state.FSTPS(pos + offset, Reg.EBP);
                            break;

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                        case ExprTypeKind.POINTER:
                            state.MOVL(Reg.EAX, pos + offset, Reg.EBP);
                            break;

                        case ExprTypeKind.STRUCT_OR_UNION:
                            state.MOVL(Reg.EAX, Reg.ESI);
                            state.LEA(pos + offset, Reg.EBP, Reg.EDI);
                            state.MOVL(expr.Type.SizeOf, Reg.ECX);
                            state.CGenMemCpy();
                            break;

                        case ExprTypeKind.ARRAY:
                        case ExprTypeKind.FUNCTION:
                            throw new InvalidProgramException($"How could a {expr.Type.Kind} be in a init list?");

                        default:
                            throw new InvalidProgramException();
                    }

                    state.CGenForceStackSizeTo(stack_size);

                });

            } // stack object
        }
Пример #20
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();
            }
        }
Пример #21
0
 public override sealed void CGenAddress(CGenState state) {
     throw new InvalidOperationException(
         "Cannot get the address of an unary arithmetic operator."
     );
 }
Пример #22
0
 public override void CalcAndSaveDouble(CGenState state) {
     state.FSUB(1, 0);
     state.FSTL(0, Reg.ECX);
 }
Пример #23
0
 public override void CalcAndSaveFloat(CGenState state) {
     state.FSUB(1, 0);
     state.FSTS(0, Reg.ECX);
 }
Пример #24
0
 public override void CalcAndSavePtr(CGenState state) {
     state.SUBL(this.Expr.Type.SizeOf, Reg.EAX);
     state.MOVL(Reg.EAX, 0, Reg.ECX);
 }
Пример #25
0
 public override sealed void CGenAddress(CGenState state) {
     throw new InvalidOperationException("Cannot get the address of a constant");
 }
Пример #26
0
 public abstract void CalcAndSaveDouble(CGenState state);
Пример #27
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;
 }
Пример #28
0
 public override void CalcAndSaveLong(CGenState state) {
     state.SUBL(1, Reg.EAX);
     state.MOVL(Reg.EAX, 0, Reg.ECX);
 }
Пример #29
0
 public override Reg CGenValue(CGenState state) {
     String name = state.CGenString(this.Value);
     state.LEA(name, Reg.EAX);
     return Reg.EAX;
 }
Пример #30
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();
            }
        }