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; }
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; }
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; }
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; }
public void AddMethod(MethodDefinition method) { methods.Add(method); }