Beispiel #1
0
        private bool ParseDestructorDefinition(TokenReader reader, out MethodDefinition method)
        {
            method = null;
            Token start = reader.Peek();
            if (!this.Expect(reader, Keyword.Destructor))
            {
                return false;
            }

            string methodName = null;
            if (!this.ParseFullNameDeclaration(reader, out methodName))
            {
                return false;
            }

            methodName = methodName + ".destructor";

            MethodDefinition methodDef = new MethodDefinition(
                start,
                methodName);

            if (!this.Expect(reader, Keyword.LeftParen))
            {
                return false;
            }

            if (!this.Expect(reader, Keyword.RightParen))
            {
                return false;
            }

            if (!this.Expect(reader, Keyword.SemiColon))
            {
                return false;
            }

            Token tok = reader.Peek();
            if (tok.Is(Keyword.Var))
            {
                VarBlock varBlock = null;
                if (!this.ParseVarBlock(reader, true, out varBlock))
                {
                    return false;
                }

                methodDef.LocalVariables = varBlock;
            }

            BlockStatement body = null;
            if (!this.ParseBlockStatement(reader, out body))
            {
                return false;
            }

            methodDef.Body = body;
            method = methodDef;
            return true;
        }
Beispiel #2
0
        private bool ParseConstructorDefinition(TokenReader reader, out MethodDefinition method)
        {
            Token start = reader.Peek();
            method = null;
            if (!this.Expect(reader, Keyword.Constructor))
            {
                return false;
            }

            string methodName = null;
            if (!this.ParseFullNameDeclaration(reader, out methodName))
            {
                return false;
            }

            methodName = methodName + ".constructor";

            MethodDefinition methodDef = new MethodDefinition(
                start,
                methodName);

            if (!this.Expect(reader, Keyword.LeftParen))
            {
                return false;
            }

            Token tok = reader.Peek();
            while (!tok.Is(Keyword.RightParen))
            {
                ParameterDeclaration parameter = null;
                if (!this.ParseParameterDeclaration(reader, out parameter))
                {
                    return false;
                }

                methodDef.AddParameter(parameter);

                tok = reader.Peek();
                if (tok.Is(Keyword.SemiColon))
                {
                    reader.Read();
                    tok = reader.Peek();
                }
            }

            if (!this.Expect(reader, Keyword.RightParen))
            {
                return false;
            }

            if (!this.Expect(reader, Keyword.SemiColon))
            {
                return false;
            }

            tok = reader.Peek();
            if (tok.Is(Keyword.Inherited))
            {
                reader.Read();
                if (!this.Expect(reader, Keyword.LeftParen))
                {
                    return false;
                }

                tok = reader.Peek();
                while (!tok.Is(Keyword.RightParen))
                {
                    Expression arg = null;
                    if (!this.ParseExpression(reader, out arg))
                    {
                        return false;
                    }

                    methodDef.BaseConstructorArguments.Add(arg);
                    tok = reader.Peek();
                    if (!tok.Is(Keyword.Comma))
                    {
                        break;
                    }
                    else
                    {
                        reader.Read();
                    }
                }

                if (!this.Expect(reader, Keyword.RightParen))
                {
                    return false;
                }

                if (!this.Expect(reader, Keyword.SemiColon))
                {
                    return false;
                }
            }

            tok = reader.Peek();
            if (tok.Is(Keyword.Var))
            {
                VarBlock varBlock = null;
                if (!this.ParseVarBlock(reader, true, out varBlock))
                {
                    return false;
                }

                methodDef.LocalVariables = varBlock;
            }

            BlockStatement body = null;
            if (!this.ParseBlockStatement(reader, out body))
            {
                return false;
            }

            methodDef.Body = body;
            method = methodDef;
            return true;
        }
Beispiel #3
0
        private bool TryImplementMethod(
            MethodImpl method,
            CompilerContext context,
            MethodDefinition methodDef,
            TypeDefinition typeDef)
        {
            bool failed = false;
            if (method.Method.Type.GetVTablePointer() != null)
            {
                method.Module.DefineVTable(method.Method.Type);
            }

            if (!string.IsNullOrEmpty(methodDef.ExternImpl))
            {
                method.Module.AddExtern(methodDef.ExternImpl);
                method.Statements.Add(new AsmStatement { Instruction = "jmp " + methodDef.ExternImpl });
                return true;
            }

            Stack<LocalVariable> destructables = new Stack<LocalVariable>();
            Scope scope = context.BeginScope(method.Method);
            if (string.CompareOrdinal(method.Method.Name, "constructor") == 0)
            {
                if (method.Method.Type.BaseClass != null)
                {
                    MethodInfo baseInit = null;
                    int argSize = 0;
                    if (methodDef.BaseConstructorArguments.Count > 0)
                    {
                        List<TypeDefinition> argTypes = new List<TypeDefinition>();
                        foreach (Expression arg in methodDef.BaseConstructorArguments.Reverse())
                        {
                            TypeDefinition valueType = null;
                            if (!this.TryEmitExpression(arg, context, scope, method, out valueType))
                            {
                                return false;
                            }

                            PushResult(method, valueType);
                            argSize += ((valueType.Size + 3) / 4) * 4;
                            argTypes.Insert(0, valueType);
                        }

                        baseInit = method.Method.Type.BaseClass.FindConstructor(argTypes);
                        if (baseInit == null)
                        {
                            string message = string.Format(
                                System.Globalization.CultureInfo.CurrentCulture,
                                Properties.Resources.CodeGenerator_CannotFindConstructor,
                                method.Method.Type.BaseClass);
                            log.Write(new Message(
                                methodDef.Start.Path,
                                methodDef.Start.Line,
                                methodDef.Start.Column,
                                Severity.Error,
                                message));
                            return false;
                        }
                    }
                    else
                    {
                        baseInit = method.Method.Type.BaseClass.GetDefaultConstructor();
                    }

                    if (baseInit != null)
                    {
                        method.Module.AddProto(baseInit);
                        method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" });
                        method.Statements.Add(new AsmStatement { Instruction = "push ecx" });
                        argSize += 4;
                        method.Statements.Add(new AsmStatement { Instruction = "call " + baseInit.MangledName });
                        method.Statements.Add(new AsmStatement { Instruction = "add esp," + argSize });
                    }
                }

                FieldInfo vtable = method.Method.Type.GetVTablePointer();
                if (vtable != null)
                {
                    // method.Module.ExternList.Add("$Vtbl_" + method.Method.Type.MangledName);
                    method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[$Vtbl_{0}]", method.Method.Type.MangledName) });
                    method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" });
                    if (vtable.Offset > 0)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", vtable.Offset) });
                    }

                    method.Statements.Add(new AsmStatement { Instruction = "mov [ecx],eax" });
                }

                // init member vars
                foreach (FieldInfo field in method.Method.Type.Fields)
                {
                    if (field.IsStatic || !field.Type.IsClass)
                    {
                        continue;
                    }

                    MethodInfo memberConstructor = field.Type.GetDefaultConstructor();
                    if (memberConstructor != null)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" });
                        if (field.Offset > 0)
                        {
                            method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", field.Offset) });
                        }

                        method.Statements.Add(new AsmStatement { Instruction = "push ecx" });
                        method.Module.AddProto(memberConstructor);
                        method.Statements.Add(new AsmStatement { Instruction = "call " + memberConstructor.MangledName });
                        method.Statements.Add(new AsmStatement { Instruction = "add esp,4" });
                    }
                }
            }

            if (methodDef.LocalVariables != null)
            {
                foreach (VariableDeclaration varDecl in methodDef.LocalVariables.Variables)
                {
                    TypeDefinition varType = null;
                    if (!this.TryResolveTypeReference(context, varDecl.Type, out varType))
                    {
                        failed = true;
                        continue;
                    }

                    MethodInfo defaultConstructor = varType.GetDefaultConstructor();
                    MethodInfo destructor = varType.GetDestructor();
                    foreach (string varName in varDecl.VariableNames)
                    {
                        LocalVariable localVar = scope.DefineLocalVariable(varName, varType);
                        if (destructor != null)
                        {
                            destructables.Push(localVar);
                        }

                        if (varDecl.InitExpression != null)
                        {
                            TypeDefinition initValueType = null;
                            if (!this.TryEmitExpression(varDecl.InitExpression, context, scope, method, out initValueType))
                            {
                                failed = true;
                                continue;
                            }

                            if (varType.IsPointer || varType.IsArray && varType.ArrayElementCount == 0)
                            {
                                method.Statements.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", localVar.Name) });
                            }
                            else if (varType.IsFloatingPoint)
                            {
                                if (varType.Size == 4)
                                {
                                    method.Statements.Add(new AsmStatement { Instruction = string.Format("fstp dword ptr _{0}$[ebp]", localVar.Name) });
                                }
                                else
                                {
                                    method.Statements.Add(new AsmStatement { Instruction = string.Format("fstp qword ptr _{0}$[ebp]", localVar.Name) });
                                }
                            }
                            else if (!varType.IsClass)
                            {
                                switch (varType.Size)
                                {
                                    case 1:
                                        method.Statements.Add(new AsmStatement { Instruction = string.Format("mov byte ptr _{0}$[ebp],al", localVar.Name) });
                                        break;
                                    case 2:
                                        method.Statements.Add(new AsmStatement { Instruction = string.Format("mov word ptr _{0}$[ebp],ax", localVar.Name) });
                                        break;
                                    case 4:
                                        method.Statements.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", localVar.Name) });
                                        break;
                                }
                            }
                        }
                        else if (defaultConstructor != null)
                        {
                            method.Module.AddProto(defaultConstructor);
                            method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,_{0}$[ebp]", localVar.Name) });
                            method.Statements.Add(new AsmStatement { Instruction = "push eax" });
                            method.Statements.Add(new AsmStatement { Instruction = "call " + defaultConstructor.MangledName });
                            method.Statements.Add(new AsmStatement { Instruction = "add esp,4" });
                        }
                    }
                }
            }

            // statements alloc temp variables, so the frame setup code has to be last.
            if (!this.TryEmitBlockStatement(methodDef.Body, context, scope, method))
            {
                failed = true;
            }

            List<AsmStatement> frame = new List<AsmStatement>();
            frame.Add(new AsmStatement { Instruction = "push ebp" });
            frame.Add(new AsmStatement { Instruction = "mov ebp,esp" });
            if (scope.LocalOffset != 0)
            {
                int localOffset = scope.LocalOffset;
                int alignFix = localOffset % 4;
                if (alignFix != 0)
                {
                    localOffset += 4 - alignFix;
                }

                frame.Add(new AsmStatement { Instruction = "sub esp," + localOffset });
            }

            method.Statements.InsertRange(0, frame);

            while (destructables.Count > 0)
            {
                LocalVariable destructable = destructables.Pop();
                MethodInfo destructor = destructable.Type.GetDestructor();
                method.Module.AddProto(destructor);
                method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,_{0}$[ebp]", destructable.Name) });
                method.Statements.Add(new AsmStatement { Instruction = "push eax" });
                method.Statements.Add(new AsmStatement { Instruction = "call " + destructor.MangledName });
                method.Statements.Add(new AsmStatement { Instruction = "add esp,4" });
            }

            if (method.Method.ReturnType != null)
            {
                SymbolEntry returnVar = scope.ReturnVariable;
                if (method.Method.ReturnType.IsFloatingPoint)
                {
                    if (method.Method.ReturnType.Size == 8)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("fld qword ptr _{0}$[ebp]", returnVar.Name) });
                    }
                    else
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("fld dword ptr _{0}$[ebp]", returnVar.Name) });
                    }
                }
                else if (method.Method.ReturnType.Size <= 8 && !method.Method.ReturnType.IsClass)
                {
                    if (method.Method.ReturnType.Size > 4)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("lea ecx,dword ptr _{0}$[ebp]", returnVar.Name) });
                        method.Statements.Add(new AsmStatement { Instruction = "mov eax,dword ptr [ecx]" });
                        method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" });
                        switch (method.Method.ReturnType.Size)
                        {
                            case 8:
                                method.Statements.Add(new AsmStatement { Instruction = "mov edx,dword ptr [ecx]" });
                                break;
                            case 7:
                                method.Statements.Add(new AsmStatement { Instruction = "mov edx,dword ptr [ecx]" });
                                break;
                            case 6:
                                method.Statements.Add(new AsmStatement { Instruction = "mov dx,word ptr [ecx]" });
                                break;
                            case 5:
                                method.Statements.Add(new AsmStatement { Instruction = "mov dl,byte ptr [ecx]" });
                                break;
                        }
                    }
                    else
                    {
                        switch (method.Method.ReturnType.Size)
                        {
                            case 4:
                                method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax, dword ptr _{0}$[ebp]", returnVar.Name) });
                                break;
                            case 3:
                                method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax, dword ptr _{0}$[ebp]", returnVar.Name) });
                                break;
                            case 2:
                                method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ax, word ptr _{0}$[ebp]", returnVar.Name) });
                                break;
                            case 1:
                                method.Statements.Add(new AsmStatement { Instruction = string.Format("mov al, byte ptr _{0}$[ebp]", returnVar.Name) });
                                if (string.CompareOrdinal(returnVar.Type.MangledName, "f") == 0)
                                {
                                    method.Statements.Add(new AsmStatement { Instruction = "and eax,1" });
                                }

                                break;
                        }
                    }
                }
                else
                {
                    method.Statements.Add(
                        new AsmStatement { Instruction = string.Format("mov edx, _{0}$[ebp]", scope.LargeReturnVariable.Name) });
                    if (!TryEmitCopy(
                        string.Format("_{0}$[ebp]", returnVar.Name),
                        "[edx]",
                        returnVar.Type,
                        context,
                        scope,
                        method))
                    {
                        failed = true;
                    }
                }
            }

            if (string.CompareOrdinal("destructor", method.Method.Name) == 0)
            {
                // call destructors on all fields.
                foreach (FieldInfo field in method.Method.Type.Fields)
                {
                    if (!field.IsStatic)
                    {
                        if (field.Type.IsClass)
                        {
                            MethodInfo memberDestructor = field.Type.GetDestructor();
                            if (memberDestructor != null)
                            {
                                method.Statements.Add(new AsmStatement { Instruction = "mov ecx,_this$[ebp]" });
                                if (field.Offset > 0)
                                {
                                    method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", field.Offset) });
                                }

                                method.Statements.Add(new AsmStatement { Instruction = "push ecx" });
                                if (memberDestructor.IsVirtual)
                                {
                                    FieldInfo memberVTable = field.Type.GetVTablePointer();
                                    if (memberVTable.Offset > 0)
                                    {
                                        method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", memberVTable.Offset) });
                                    }

                                    method.Statements.Add(new AsmStatement { Instruction = "mov eax,[ecx]" });
                                    if (memberDestructor.VTableIndex > 0)
                                    {
                                        method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", memberDestructor.VTableIndex * 4) });
                                    }

                                    method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [eax]" });
                                }
                                else
                                {
                                    method.Module.AddProto(memberDestructor);
                                    method.Statements.Add(new AsmStatement { Instruction = "call " + memberDestructor.MangledName });
                                }

                                method.Statements.Add(new AsmStatement { Instruction = "add esp,4" });
                            }
                        }
                    }
                }

                // call base class destructor at the end.
                TypeDefinition baseClass = method.Method.Type.BaseClass;
                if (baseClass != null)
                {
                    MethodInfo baseDestructor = baseClass.GetDestructor();
                    if (baseDestructor != null)
                    {
                        method.Module.AddProto(baseDestructor);
                        method.Statements.Add(new AsmStatement { Instruction = "mov eax,_this$[ebp]" });
                        method.Statements.Add(new AsmStatement { Instruction = "push eax" });
                        method.Statements.Add(new AsmStatement { Instruction = "call " + baseDestructor.MangledName });
                        method.Statements.Add(new AsmStatement { Instruction = "add esp,4" });
                    }
                }
            }

            method.Statements.Add(new AsmStatement { Instruction = "mov esp,ebp" });
            method.Statements.Add(new AsmStatement { Instruction = "pop ebp" });
            method.Statements.Add(new AsmStatement { Instruction = "ret" });
            scope.SaveSymbols(method.Symbols);
            return !failed;
        }
Beispiel #4
0
        private bool ParseMethodDefinition(TokenReader reader, out MethodDefinition method)
        {
            method = null;
            Token tok = reader.Peek();
            Token start = tok;
            bool isFunction = false;
            if (tok.Is(Keyword.Constructor))
            {
                return this.ParseConstructorDefinition(reader, out method);
            }

            if (tok.Is(Keyword.Destructor))
            {
                return this.ParseDestructorDefinition(reader, out method);
            }

            if (tok.Is(Keyword.Function))
            {
                isFunction = true;
                reader.Read();
            }
            else
            {
                if (!this.Expect(reader, Keyword.Procedure))
                {
                    return false;
                }
            }

            string methodName = null;
            if (!this.ParseFullNameDeclaration(reader, out methodName))
            {
                return false;
            }

            MethodDefinition methodDef = new MethodDefinition(
                start,
                methodName);

            if (!this.Expect(reader, Keyword.LeftParen))
            {
                return false;
            }

            tok = reader.Peek();
            while (!tok.Is(Keyword.RightParen))
            {
                ParameterDeclaration parameter = null;
                if (!this.ParseParameterDeclaration(reader, out parameter))
                {
                    return false;
                }

                methodDef.AddParameter(parameter);

                tok = reader.Peek();
                if (tok.Is(Keyword.SemiColon))
                {
                    reader.Read();
                    tok = reader.Peek();
                }
            }

            if (!this.Expect(reader, Keyword.RightParen))
            {
                return false;
            }

            if (isFunction)
            {
                if (!this.Expect(reader, Keyword.Colon))
                {
                    return false;
                }

                TypeReference returnType = null;
                if (!this.ParseTypeReference(reader, out returnType))
                {
                    return false;
                }

                methodDef.ReturnType = returnType;
            }

            if (!this.Expect(reader, Keyword.SemiColon))
            {
                return false;
            }

            tok = reader.Peek();
            if (tok.Is(Keyword.Extern))
            {
                reader.Read();
                string externalImpl = null;
                tok = reader.Read();
                LiteralToken litTok = tok as LiteralToken;
                if (tok == null || litTok == null || !(litTok.Value is string))
                {
                    string message = string.Format(
                        System.Globalization.CultureInfo.CurrentCulture,
                        Properties.Resources.Parser_Unexpected,
                        tok != null ? tok.ToString() : Properties.Resources.Parser_EndOfFile);
                    this.log.Write(
                        new Message(
                            reader.Path,
                            reader.Line,
                            reader.Column,
                            Severity.Error,
                            message));
                    return false;
                }

                externalImpl = (string)litTok.Value;
                methodDef.ExternImpl = externalImpl;
            }
            else
            {
                if (tok.Is(Keyword.Var))
                {
                    VarBlock varBlock = null;
                    if (!this.ParseVarBlock(reader, true, out varBlock))
                    {
                        return false;
                    }

                    methodDef.LocalVariables = varBlock;
                }

                BlockStatement body = null;
                if (!this.ParseBlockStatement(reader, out body))
                {
                    return false;
                }

                methodDef.Body = body;
            }

            method = methodDef;
            return true;
        }
Beispiel #5
0
 public void AddMethod(MethodDefinition method)
 {
     methods.Add(method);
 }