private bool TryEmitAssignment( AssignmentStatement assignmentStatement, CompilerContext context, Scope scope, MethodImpl method) { string location = null; TypeDefinition storageType = null; TypeDefinition valueType = null; if (!this.TryEmitExpression(assignmentStatement.Value, context, scope, method, out valueType)) { return false; } this.PushResult(method, valueType); MethodInfo calleeMethod = null; if (!this.TryEmitReference(assignmentStatement.Storage, context, scope, method, out location, out storageType, out calleeMethod)) { return false; } if (!this.ValidateCanCast(assignmentStatement, storageType, valueType)) { return false; } if (valueType.Size == 8 && !valueType.IsClass) { method.Statements.Add(new AsmStatement { Instruction = "pop eax" }); method.Statements.Add(new AsmStatement { Instruction = "pop edx" }); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea ecx,{0}", location) }); method.Statements.Add(new AsmStatement { Instruction = "mov [ecx],eax" }); method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" }); method.Statements.Add(new AsmStatement { Instruction = "mov [ecx],edx" }); } else if (valueType.Size <= 4 && !valueType.IsClass) { method.Statements.Add(new AsmStatement { Instruction = "pop eax" }); switch (storageType.Size) { case 1: { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov byte ptr {0},al", location) }); } break; case 2: { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov word ptr {0},ax", location) }); } break; default: { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov {0},eax", location) }); } break; } } else { method.Statements.Add(new AsmStatement { Instruction = "mov esi,esp" }); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea edi,{0}", location) }); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ecx,{0}", valueType.Size) }); method.Statements.Add(new AsmStatement { Instruction = "cld" }); method.Statements.Add(new AsmStatement { Instruction = "rep movsb" }); method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", valueType.Size) }); } return true; }
private bool TryEmitBlockStatement( BlockStatement statement, CompilerContext context, Scope scope, MethodImpl method) { bool failed = false; foreach (Statement s in statement.Statements) { if (!this.TryEmitStatement(s, context, scope, method)) { failed = true; } } return !failed; }
private bool TryEmitAddressExpression( AddressExpression addrExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { string innerLoc = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(addrExpr.Inner, context, scope, method, out innerLoc, out storageType, out calleeMethod)) { valueType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", innerLoc) }); valueType = context.GetPointerType(storageType); return true; }
private bool TryEmitAllocCall(Token start, CompilerContext context, Scope scope, MethodImpl method, int size) { TypeDefinition memoryType = null; if (!this.TryFindSystemMemory(start, context, out memoryType)) { return false; } MethodInfo allocMethod = memoryType.Methods.FirstOrDefault(e => string.CompareOrdinal("Alloc", e.Name) == 0); if (allocMethod == null) { log.Write(new Message( start.Path, start.Line, start.Column, Severity.Error, Properties.Resources.CodeGenerator_SystemMemoryMissingAlloc)); return false; } method.Module.AddProto(allocMethod); method.Statements.Add(new AsmStatement { Instruction = "mov eax," + size.ToString() }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "call " + allocMethod.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,4" }); return true; }
private bool TryEmitFreeCall(Token start, CompilerContext context, Scope scope, MethodImpl method) { TypeDefinition memoryType = null; if (!this.TryFindSystemMemory(start, context, out memoryType)) { return false; } MethodInfo freeMethod = memoryType.Methods.FirstOrDefault(e => string.CompareOrdinal(e.Name, "Free") == 0); if (freeMethod == null) { log.Write(new Message( start.Path, start.Line, start.Column, Severity.Error, Properties.Resources.CodeGenerator_SystemMemoryMissingFree)); return false; } method.Module.AddProto(freeMethod); method.Statements.Add(new AsmStatement { Instruction = string.Format("call {0}", freeMethod.MangledName) }); return true; }
private bool TryEmitLiteralExpression( LiteralExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (expression.Value == null) { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); return context.TryFindTypeByName("^", out valueType); } if (expression.Value is int) { if ((int)expression.Value == 0) { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); } else { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,{0}", expression.Value) }); } return context.TryFindTypeByName("integer", out valueType); } if (expression.Value is char) { method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,{0}", (int)expression.Value) }); return context.TryFindTypeByName("character", out valueType); } if (expression.Value is string) { string label = method.Module.DefineLiteralString((string)expression.Value); method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[offset {0}]", label) }); return context.TryFindTypeByName("#0character", out valueType); } if (expression.Value is decimal) { decimal exprValue = (decimal)expression.Value; if (exprValue == 0.0M) { method.Statements.Add(new AsmStatement { Instruction = "fldz" }); } else if (exprValue == 1.0M) { method.Statements.Add(new AsmStatement { Instruction = "fld1" }); } else { string label = method.Module.DefineConstant((double)exprValue); method.Statements.Add(new AsmStatement { Instruction = string.Format("fld qword ptr [{0}]", label) }); } return context.TryFindTypeByName("double", out valueType); } if (expression.Value is bool) { bool boolVal = (bool)expression.Value; if (boolVal) { method.Statements.Add(new AsmStatement { Instruction = "mov eax,1" }); } else { method.Statements.Add(new AsmStatement { Instruction = "xor eax,eax" }); } return context.TryFindTypeByName("boolean", out valueType); } valueType = null; return false; }
private bool TryEmitSimpleExpression( SimpleExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { TypeDefinition rightSideType = null; if (!this.TryEmitExpression(expression.Right, context, scope, method, out rightSideType)) { valueType = null; return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(expression.Left, context, scope, method, out leftSideType)) { valueType = null; return false; } if (leftSideType.IsFloatingPoint) { if (rightSideType.IsFloatingPoint) { if (rightSideType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); } method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } else if (rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "fild [esp]" }); method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } switch (expression.Operator) { case Keyword.Plus: { method.Statements.Add(new AsmStatement { Instruction = "faddp" }); } break; case Keyword.Minus: { method.Statements.Add(new AsmStatement { Instruction = "fsubp" }); } break; } } else if (leftSideType.Size <= 4) { if (rightSideType.Size <= 4 && !rightSideType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx" }); switch (expression.Operator) { case Keyword.Plus: { method.Statements.Add(new AsmStatement { Instruction = "add eax,ecx" }); } break; case Keyword.Minus: { method.Statements.Add(new AsmStatement { Instruction = "sub eax,ecx" }); } break; case Keyword.Or: { method.Statements.Add(new AsmStatement { Instruction = "or eax,ecx" }); } break; } } } valueType = leftSideType; return true; }
private bool TryEmitDeleteStatement(DeleteStatement deleteStatement, CompilerContext context, Scope scope, MethodImpl method) { TypeDefinition valueType = null; if (!this.TryEmitExpression(deleteStatement.Value, context, scope, method, out valueType)) { return false; } if (!valueType.IsPointer && !valueType.IsArray) { this.log.Write( new Message( deleteStatement.Start.Path, deleteStatement.Start.Line, deleteStatement.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_DeleteOperandMustBePointerOrArray)); return false; } if (valueType.IsPointer) { this.PushResult(method, valueType); TypeDefinition innerType = valueType.InnerType; if (innerType != null) { MethodInfo destructor = innerType.GetDestructor(); if (destructor != null) { this.PushResult(method, valueType); method.Module.AddProto(destructor); if (destructor.IsVirtual) { FieldInfo vtblPointer = innerType.GetVTablePointer(); if (vtblPointer.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", vtblPointer.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "mov ecx,[eax]" }); if (destructor.VTableIndex > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", destructor.VTableIndex * 4) }); } method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [ecx]" }); } else { method.Statements.Add(new AsmStatement { Instruction = string.Format("call {0}", destructor.MangledName) }); } method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", valueType.Size) }); } } if (!this.TryEmitFreeCall(deleteStatement.Start, context, scope, method)) { return false; } method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", valueType.Size) }); return true; } log.Write(new Message( deleteStatement.Start.Path, deleteStatement.Start.Line, deleteStatement.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_DeleteOperandArrayNotSupported)); return false; }
private bool TryEmitReference( ReferenceExpression referenceExpression, CompilerContext context, Scope scope, MethodImpl method, out string location, out TypeDefinition storageType, out MethodInfo calleeMethod) { calleeMethod = null; NamedReferenceExpression namedRef = referenceExpression as NamedReferenceExpression; if (namedRef != null) { SymbolEntry symbol = null; if (scope.TryLookup(namedRef.Identifier, out symbol)) { storageType = symbol.Type; LocalVariable localVar = symbol as LocalVariable; if (localVar != null) { location = string.Format("_{0}$[ebp]", localVar.Name); return true; } else { ParameterVariable parVar = symbol as ParameterVariable; if (parVar != null) { location = string.Format("_{0}$[ebp]", parVar.Name); return true; } } } foreach (var field in method.Method.Type.Fields) { if (string.CompareOrdinal(field.Name, namedRef.Identifier) == 0) { SymbolEntry symThis = null; if(!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in method.Method.Type.Methods) { if (string.CompareOrdinal(memberMethod.Name, namedRef.Identifier) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { SymbolEntry symThis = null; if (!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); } if (memberMethod.IsVirtual) { location = "[ecx]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } if (context.TryFindTypeByName(namedRef.Identifier, out storageType)) { location = null; return true; } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredIdentifier, namedRef.Identifier); log.Write(new Message( namedRef.Start.Path, namedRef.Start.Line, namedRef.Start.Column, Severity.Error, message)); } MemberReferenceExpression memberRef = referenceExpression as MemberReferenceExpression; if (memberRef != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCalleeMethod = null; if (this.TryEmitReference(memberRef.Inner, context, scope, method, out innerLoc, out innerType, out innerCalleeMethod)) { foreach (var field in innerType.Fields) { if (string.CompareOrdinal(field.Name, memberRef.MemberName) == 0) { method.Statements.Add( new AsmStatement { Instruction = string.Format("lea ecx,{0}", innerLoc) }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in innerType.Methods) { if (string.CompareOrdinal(memberMethod.Name, memberRef.MemberName) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", innerLoc) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } if (memberMethod.IsVirtual && memberRef.UseVirtualDispatch) { location = "[eax]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredMember, memberRef.MemberName, innerType.FullName); log.Write(new Message( memberRef.Start.Path, memberRef.Start.Line, memberRef.Start.Column, Severity.Error, message)); } } CallReferenceExpression callExpr = referenceExpression as CallReferenceExpression; if (callExpr != null) { location = null; return this.TryEmitExpression(callExpr, context, scope, method, out storageType); } ArrayIndexReferenceExpression arrayIndexExpr = referenceExpression as ArrayIndexReferenceExpression; if (arrayIndexExpr != null) { TypeDefinition indexType = null; if (!this.TryEmitExpression( arrayIndexExpr.Index, context, scope, method, out indexType)) { location = null; storageType = null; return false; } if (indexType.IsFloatingPoint || indexType.IsArray || indexType.IsClass || indexType.IsPointer) { this.log.Write(new Message( arrayIndexExpr.Index.Start.Path, arrayIndexExpr.Index.Start.Line, arrayIndexExpr.Index.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayIndexIntExpected)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "push eax" }); string innerLoc = null; TypeDefinition innerType = null; MethodInfo arrayCalleeMethod = null; if (!this.TryEmitReference( arrayIndexExpr.Inner, context, scope, method, out innerLoc, out innerType, out arrayCalleeMethod)) { location = null; storageType = null; return false; } if (!innerType.IsArray) { log.Write(new Message( arrayIndexExpr.Inner.Start.Path, arrayIndexExpr.Inner.Start.Line, arrayIndexExpr.Inner.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayTypeExpected)); location = null; storageType = null; return false; } if (innerType.Size > 4) { method.Statements.Add(new AsmStatement { Instruction = "lea ecx," + innerLoc }); } else { method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); } method.Statements.Add(new AsmStatement { Instruction = "pop eax" }); int elementSize = innerType.InnerType.Size; if(elementSize > 1) { int shiftSize = 0; switch(elementSize) { case 2: shiftSize = 1; break; case 4: shiftSize = 2; break; case 8: shiftSize = 3; break; case 16: shiftSize = 4; break; case 32: shiftSize = 5; break; case 64: shiftSize = 6; break; default: method.Statements.Add(new AsmStatement { Instruction = string.Format("imul eax,{0}", elementSize) }); break; } if (shiftSize != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("shl eax,{0}", shiftSize) }); } } method.Statements.Add(new AsmStatement { Instruction = "add ecx,eax" }); location = "[ecx]"; storageType = innerType.InnerType; return true; } DereferenceExpression derefExpr = referenceExpression as DereferenceExpression; if (derefExpr != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCall = null; if (!this.TryEmitReference( derefExpr.Inner, context, scope, method, out innerLoc, out innerType, out innerCall)) { location = null; storageType = null; return false; } if (!innerType.IsPointer) { log.Write(new Message( derefExpr.Start.Path, derefExpr.Start.Line, derefExpr.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_CannotDerefNonPointer)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); location = "[ecx]"; storageType = innerType.InnerType; return true; } InheritedReferenceExpression inhRefExpr = referenceExpression as InheritedReferenceExpression; if (inhRefExpr != null) { storageType = method.Method.Type.BaseClass; if (storageType == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NoBaseTypeForInherited, method.Method.Type.FullName); this.log.Write(new Message( inhRefExpr.Start.Path, inhRefExpr.Start.Line, inhRefExpr.Start.Column, Severity.Error, message)); location = null; return false; } SymbolEntry thisSymbol = null; if (!scope.TryLookup("this", out thisSymbol)) { // reference a static on the base class. location = null; } else { location = "_this$[ebp]"; } return true; } location = null; storageType = null; return false; }
private bool TryEmitRelationExpresion( RelationalExpression relExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { context.TryFindTypeByName("boolean", out valueType); TypeDefinition rightSideType = null; if (!this.TryEmitExpression(relExpr.Right, context, scope, method, out rightSideType)) { return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(relExpr.Left, context, scope, method, out leftSideType)) { return false; } if (rightSideType.IsFloatingPoint) { if (leftSideType.IsFloatingPoint) { switch (rightSideType.Size) { case 4: method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); break; case 8: method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); break; default: method.Statements.Add(new AsmStatement { Instruction = "fld tword ptr [esp]" }); break; } method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", rightSideType.Size) }); method.Statements.Add(new AsmStatement { Instruction = "fcompp" }); method.Statements.Add(new AsmStatement { Instruction = "fnstsw ax" }); method.Statements.Add(new AsmStatement { Instruction = "sahf" }); switch (relExpr.Operator) { case Keyword.Equals: { method.Statements.Add(new AsmStatement { Instruction = "sete al" }); } break; case Keyword.LessThan: { method.Statements.Add(new AsmStatement { Instruction = "seta al" }); } break; case Keyword.LessThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setae al" }); } break; case Keyword.GreaterThan: { method.Statements.Add(new AsmStatement { Instruction = "setb al" }); } break; case Keyword.GreaterThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setbe al" }); } break; case Keyword.NotEqual: { method.Statements.Add(new AsmStatement { Instruction = "setne al" }); } break; } } else { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_NoAutomaticConversion, leftSideType.FullName, rightSideType.FullName); this.log.Write(new Message( relExpr.Start.Path, relExpr.Start.Line, relExpr.Start.Column, Severity.Error, message)); return false; } } else if(leftSideType.IsFloatingPoint) { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_NoAutomaticConversion, leftSideType.FullName, rightSideType.FullName); this.log.Write(new Message( relExpr.Start.Path, relExpr.Start.Line, relExpr.Start.Column, Severity.Error, message)); return false; } else { if(leftSideType.Size <= 4 && rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx"}); method.Statements.Add(new AsmStatement { Instruction = "cmp eax,ecx"}); switch (relExpr.Operator) { case Keyword.Equals: { method.Statements.Add(new AsmStatement { Instruction = "sete al" }); } break; case Keyword.LessThan: { method.Statements.Add(new AsmStatement { Instruction = "setl al" }); } break; case Keyword.LessThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setle al" }); } break; case Keyword.GreaterThan: { method.Statements.Add(new AsmStatement { Instruction = "setg al" }); } break; case Keyword.GreaterThanOrEquals: { method.Statements.Add(new AsmStatement { Instruction = "setge al" }); } break; case Keyword.NotEqual: { method.Statements.Add(new AsmStatement { Instruction = "setne al" }); } break; } } } return true; }
private bool TryEmitNotExpression( NotExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (!this.TryEmitExpression(expression.Inner, context, scope, method, out valueType)) { return false; } if (valueType.IsPointer || valueType.IsClass || valueType.IsArray || valueType.IsInterface || valueType.IsFloatingPoint || valueType.Size > 4) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NotNotSupported, valueType.FullName); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); return false; } else { switch (valueType.Size) { case 4: method.Statements.Add(new AsmStatement { Instruction = "not eax" }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = "not ax" }); break; case 1: method.Statements.Add(new AsmStatement { Instruction = "not al" }); break; } if (string.CompareOrdinal(valueType.MangledName, "f") == 0) { method.Statements.Add(new AsmStatement { Instruction = "and al,1" }); } } return true; }
private bool TryEmitNewExpression( NewExpression newExpr, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { valueType = null; TypeDefinition objectType = null; if (!this.TryResolveTypeReference(context, newExpr.Type, out objectType)) { valueType = null; return false; } if (!objectType.IsClass && newExpr.ConstructorArguments.Count() > 0) { log.Write(new Message( newExpr.Start.Path, newExpr.Start.Line, newExpr.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ConstructorArgumentsAreOnlySupportedOnClassTypes)); return false; } valueType = context.GetPointerType(objectType); if (!this.TryEmitAllocCall(newExpr.Start, context, scope, method, objectType.Size)) { return false; } MethodInfo constructor = null; int argSize = 0; if (objectType.IsClass) { int nullTestStart = method.Statements.Count; List<TypeDefinition> argTypes = new List<TypeDefinition>(); foreach (Expression arg in newExpr.ConstructorArguments.Reverse()) { TypeDefinition argType = null; if (!this.TryEmitExpression(arg, context, scope, method, out argType)) { return false; } this.PushResult(method, argType); argSize += ((argType.Size + 3) / 4) * 4; argTypes.Insert(0, argType); } if (!context.TryFindConstructor(objectType, argTypes, out constructor)) { // ok to have no default constructor if (argTypes.Count > 0) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_CannotFindConstructor, objectType.FullName); log.Write(new Message( newExpr.Start.Path, newExpr.Start.Line, newExpr.Start.Column, Severity.Error, message)); return false; } } if (constructor != null) { LocalVariable tempPtr = scope.DefineTempVariable(valueType); string jumpLabel = method.Module.GetNextJumpLabel(); List<AsmStatement> saveAlloc = new List<AsmStatement>(); saveAlloc.Add(new AsmStatement { Instruction = string.Format("mov _{0}$[ebp],eax", tempPtr.Name) }); saveAlloc.Add(new AsmStatement { Instruction = "test eax,eax" }); saveAlloc.Add(new AsmStatement { Instruction = "jz " + jumpLabel }); method.Statements.InsertRange(nullTestStart, saveAlloc); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,_{0}$[ebp]", tempPtr.Name) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Module.AddProto(constructor); method.Statements.Add(new AsmStatement { Instruction = "call " + constructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = string.Format("add esp,{0}", argSize + 4) }); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov eax,_{0}$[ebp]", tempPtr.Name), Label = jumpLabel }); } } return true; }
private bool TryEmitNegativeExpression( NegativeExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { if (!this.TryEmitExpression(expression.Inner, context, scope, method, out valueType)) { return false; } if (valueType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "fchs" }); } else if (valueType.IsPointer || valueType.IsClass || valueType.IsArray || valueType.IsInterface) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NegativeNotSupported, valueType.FullName); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); return false; } else { method.Statements.Add(new AsmStatement { Instruction = "neg eax" }); } return true; }
private bool TryEmitCall(CallStatement callStatement, CompilerContext context, Scope scope, MethodImpl method) { TypeDefinition typeDef = null; return this.TryEmitExpression(callStatement.Expression, context, scope, method, out typeDef); }
private bool TryEmitStatement( Statement statement, CompilerContext context, Scope scope, MethodImpl method) { AssignmentStatement assignmentStatement = statement as AssignmentStatement; if (assignmentStatement != null) { return TryEmitAssignment(assignmentStatement, context, scope, method); } else { CallStatement callStatement = statement as CallStatement; if (callStatement != null) { return TryEmitCall(callStatement, context, scope, method); } else { IfStatement ifStatement = statement as IfStatement; if (ifStatement != null) { return TryEmitIfStatement(ifStatement, context, scope, method); } else { WhileStatement whileStatement = statement as WhileStatement; if (whileStatement != null) { return TryEmitWhileStatement(whileStatement, context, scope, method); } else { BlockStatement blockStatement = statement as BlockStatement; if (blockStatement != null) { return TryEmitBlockStatement(blockStatement, context, scope, method); } else { DeleteStatement deleteStatement = statement as DeleteStatement; if (deleteStatement != null) { return TryEmitDeleteStatement(deleteStatement, context, scope, method); } } } } } } return false; }
private bool TryEmitCopy( string sourceLocation, string targetLocation, TypeDefinition type, CompilerContext context, Scope scope, MethodImpl method) { if (string.CompareOrdinal("[ebx]", sourceLocation) != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea ebx,{0}", sourceLocation) }); } if (string.CompareOrdinal("[edx]", targetLocation) != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea edx,{0}", targetLocation) }); } int size = type.Size; while (size >= 4) { method.Statements.Add(new AsmStatement { Instruction = "mov eax, dword ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov dword ptr [edx],eax" }); method.Statements.Add(new AsmStatement { Instruction = "add ebx,4" }); method.Statements.Add(new AsmStatement { Instruction = "add edx,4" }); size -= 4; } if (size >= 2) { method.Statements.Add(new AsmStatement { Instruction = "mov ax, word ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov word ptr [edx],ax" }); method.Statements.Add(new AsmStatement { Instruction = "add ebx,2" }); method.Statements.Add(new AsmStatement { Instruction = "add edx,2" }); size -= 2; } if (size >= 1) { method.Statements.Add(new AsmStatement { Instruction = "mov al, byte ptr [ebx]" }); method.Statements.Add(new AsmStatement { Instruction = "mov byte ptr [edx],al" }); } return true; }
private bool TryEmitTermExpression( TermExpression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { TypeDefinition rightSideType = null; if (!this.TryEmitExpression(expression.Right, context, scope, method, out rightSideType)) { valueType = null; return false; } this.PushResult(method, rightSideType); TypeDefinition leftSideType = null; if (!this.TryEmitExpression(expression.Left, context, scope, method, out leftSideType)) { valueType = null; return false; } if (leftSideType.IsFloatingPoint) { if (rightSideType.IsFloatingPoint) { if (rightSideType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr [esp]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr [esp]" }); } method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } else if (rightSideType.Size <= 4) { method.Statements.Add(new AsmStatement { Instruction = "fild [esp]" }); method.Statements.Add(new AsmStatement { Instruction = "add esp," + rightSideType.Size }); } switch (expression.Operator) { case Keyword.Star: { method.Statements.Add(new AsmStatement { Instruction = "fmulp" }); } break; case Keyword.Slash: { method.Statements.Add(new AsmStatement { Instruction = "fdivp" }); } break; } } else if (leftSideType.Size <= 4) { if (rightSideType.Size <= 4 && !rightSideType.IsFloatingPoint) { method.Statements.Add(new AsmStatement { Instruction = "pop ecx" }); switch (expression.Operator) { case Keyword.Star: { method.Statements.Add(new AsmStatement { Instruction = "imul eax,ecx" }); } break; case Keyword.Mod: { method.Statements.Add(new AsmStatement { Instruction = "xor edx,edx" }); method.Statements.Add(new AsmStatement { Instruction = "idiv ecx" }); method.Statements.Add(new AsmStatement { Instruction = "mov eax,edx" }); } break; case Keyword.And: { method.Statements.Add(new AsmStatement { Instruction = "and eax,ecx" }); } break; case Keyword.Div: { method.Statements.Add(new AsmStatement { Instruction = "xor edx,edx" }); method.Statements.Add(new AsmStatement { Instruction = "idiv ecx" }); } break; } } } valueType = leftSideType; return true; }
private bool TryEmitExpression( Expression expression, CompilerContext context, Scope scope, MethodImpl method, out TypeDefinition valueType) { LiteralExpression literalExpr = expression as LiteralExpression; if (literalExpr != null) { return this.TryEmitLiteralExpression(literalExpr, context, scope, method, out valueType); } CallReferenceExpression callExpr = expression as CallReferenceExpression; if (callExpr != null) { int argSize = 0; int argStatementStart = method.Statements.Count; Expression[] arguments = callExpr.Arguments.ToArray(); List<TypeDefinition> argTypes = new List<TypeDefinition>(); for (int i = arguments.Length - 1; i >= 0; i--) { TypeDefinition argType = null; if (!this.TryEmitExpression(arguments[i], context, scope, method, out argType)) { valueType = null; return false; } argTypes.Insert(0, argType); argSize += ((argType.Size + 3) / 4) * 4; this.PushResult(method, argType); } string callLoc = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(callExpr.Inner, context, scope, method, out callLoc, out storageType, out calleeMethod)) { valueType = null; return false; } // fix up calling overloads here vs. inside TryEmitReference. if (calleeMethod != null) { MethodInfo overload = calleeMethod.Type.FindMethod(calleeMethod.Name, argTypes); if (overload != null) { if (string.CompareOrdinal(calleeMethod.MangledName, callLoc) == 0) { callLoc = overload.MangledName; } method.Module.AddProto(overload); calleeMethod = overload; storageType = overload.ReturnType; } } if (storageType != null) { if (callLoc == null) { // must be a constructor call. MethodInfo constructor = storageType.FindConstructor(argTypes); if (constructor == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_CannotFindConstructor, storageType.FullName); log.Write(new Message( callExpr.Start.Path, callExpr.Start.Line, callExpr.Start.Column, Severity.Error, message)); valueType = null; return false; } calleeMethod = constructor; callLoc = constructor.MangledName; method.Module.AddProto(constructor); // create room on the stack for the result. AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }; method.Statements.Insert(argStatementStart, resultPush); // push the ref to the storage for the class on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[esp+{0}]", argSize) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } else if (storageType.IsClass || !storageType.IsFloatingPoint && storageType.Size > 8) { // create room on the stack for the result. AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }; method.Statements.Insert(argStatementStart, resultPush); // push the ref to the storage for the class on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format( "lea ebx,[esp+{0}]", calleeMethod.IsStatic ? argSize : argSize + 4) }); method.Statements.Add(new AsmStatement { Instruction = "push ebx" }); argSize += 4; } } if (calleeMethod.IsVirtual && callExpr.Inner.UseVirtualDispatch) { FieldInfo vtablePtr = calleeMethod.Type.GetVTablePointer(); if (string.CompareOrdinal(callLoc, "[eax]") != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", callLoc) }); } if (vtablePtr.Offset > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", vtablePtr.Offset) }); } method.Statements.Add(new AsmStatement { Instruction = "mov ecx,[eax]" }); if (calleeMethod.VTableIndex > 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", calleeMethod.VTableIndex * 4) }); } method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [ecx]" }); } else { method.Statements.Add(new AsmStatement { Instruction = "call " + callLoc }); } if (!calleeMethod.IsStatic) { argSize += 4; } if (argSize > 0) { method.Statements.Add(new AsmStatement { Instruction = "add esp," + argSize.ToString() }); } if (calleeMethod.Parameters.Count != argTypes.Count) { string message = string.Format( System.Globalization.CultureInfo.InvariantCulture, Properties.Resources.CodeGenerator_UnexpectedArgumentCount, calleeMethod.Name, calleeMethod.Parameters.Count, argTypes.Count); this.log.Write(new Message( expression.Start.Path, expression.Start.Line, expression.Start.Column, Severity.Error, message)); valueType = null; return false; } bool argsValid = true; for (int i = 0; i < calleeMethod.Parameters.Count; i++) { if (!this.ValidateCanCast(expression, calleeMethod.Parameters[i].Type, argTypes[i])) { argsValid = false; } } valueType = storageType; return argsValid; } ReferenceExpression refExpr = expression as ReferenceExpression; if (refExpr != null) { string location = null; TypeDefinition storageType = null; MethodInfo calleeMethod = null; if (!this.TryEmitReference(refExpr, context, scope, method, out location, out storageType, out calleeMethod)) { valueType = null; return false; } if (storageType.IsFloatingPoint) { if (storageType.Size == 8) { method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr " + location }); } else if (storageType.Size == 4) { method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr " + location }); } else { method.Statements.Add(new AsmStatement { Instruction = "fld tword ptr " + location }); } } else if (storageType.IsArray) { if (storageType.ArrayElementCount > 0) { method.Statements.Add(new AsmStatement { Instruction = "lea eax," + location }); valueType = context.GetArrayType(storageType.InnerType, 0); return true; } else { method.Statements.Add(new AsmStatement { Instruction = "mov eax," + location }); } } else if (storageType.Size <= 8 && !storageType.IsClass) { switch (storageType.Size) { case 8: method.Statements.Add(new AsmStatement { Instruction = "lea ecx, " + location }); method.Statements.Add(new AsmStatement { Instruction = "mov eax,[ecx]" }); method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" }); method.Statements.Add(new AsmStatement { Instruction = "mov edx,[ecx]" }); break; case 4: method.Statements.Add(new AsmStatement { Instruction = "mov eax,dword ptr " + location }); break; case 2: method.Statements.Add(new AsmStatement { Instruction = "mov ax,word ptr " + location }); break; case 1: method.Statements.Add(new AsmStatement { Instruction = "mov al,byte ptr " + location }); break; } } else if (storageType.IsClass) { // construct a new copy on the stack. method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", location) }); method.Statements.Add(new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) }); MethodInfo copyConstructor = storageType.GetCopyConstructor(context); if (copyConstructor != null) { method.Module.AddProto(copyConstructor); method.Statements.Add(new AsmStatement { Instruction = "lea ecx,[esp]" }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); method.Statements.Add(new AsmStatement { Instruction = "call " + copyConstructor.MangledName }); method.Statements.Add(new AsmStatement { Instruction = "add esp,8" }); } else { // raw copy. method.Statements.Add(new AsmStatement { Instruction = "mov edi,esp" }); method.Statements.Add(new AsmStatement { Instruction = "mov esi,eax" }); method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ecx,{0}", storageType.Size) }); method.Statements.Add(new AsmStatement { Instruction = "cld" }); method.Statements.Add(new AsmStatement { Instruction = "rep movsb" }); } } valueType = storageType; return true; } SimpleExpression simpleExpr = expression as SimpleExpression; if (simpleExpr != null) { return this.TryEmitSimpleExpression(simpleExpr, context, scope, method, out valueType); } TermExpression termExpr = expression as TermExpression; if (termExpr != null) { return this.TryEmitTermExpression(termExpr, context, scope, method, out valueType); } RelationalExpression relExpr = expression as RelationalExpression; if (relExpr != null) { return this.TryEmitRelationExpresion(relExpr, context, scope, method, out valueType); } AddressExpression addrExpr = expression as AddressExpression; if (addrExpr != null) { return this.TryEmitAddressExpression(addrExpr, context, scope, method, out valueType); } NewExpression newExpr = expression as NewExpression; if (newExpr != null) { return this.TryEmitNewExpression(newExpr, context, scope, method, out valueType); } NotExpression notExpr = expression as NotExpression; if (notExpr != null) { return this.TryEmitNotExpression(notExpr, context, scope, method, out valueType); } NegativeExpression negExpr = expression as NegativeExpression; if (negExpr != null) { return this.TryEmitNegativeExpression(negExpr, context, scope, method, out valueType); } valueType = null; return false; }
private bool TryEmitWhileStatement(WhileStatement whileStatement, CompilerContext context, Scope scope, MethodImpl method) { string topLabel = method.Module.GetNextJumpLabel(); method.Statements.Add(new AsmStatement { Instruction = "nop", Label = topLabel }); TypeDefinition conditionType = null; if (!this.TryEmitExpression(whileStatement.Condition, context, scope, method, out conditionType)) { return false; } if (!this.ValidateConditionType(whileStatement.Condition, conditionType)) { return false; } string endLabel = method.Module.GetNextJumpLabel(); method.Statements.Add(new AsmStatement { Instruction = "test al,al" }); method.Statements.Add(new AsmStatement { Instruction = "jz " + endLabel }); if (!this.TryEmitStatement(whileStatement.BodyStatement, context, scope, method)) { return false; } method.Statements.Add(new AsmStatement { Instruction = "jmp " + topLabel }); method.Statements.Add(new AsmStatement { Instruction = "nop", Label = endLabel }); return true; }
private bool TryEmitIfStatement(IfStatement ifStatement, CompilerContext context, Scope scope, MethodImpl method) { TypeDefinition conditionType = null; if (!this.TryEmitExpression(ifStatement.Condition, context, scope, method, out conditionType)) { return false; } if (!this.ValidateConditionType(ifStatement.Condition, conditionType)) { return false; } string elseLabel = null; if (ifStatement.FalseStatement != null) { elseLabel = method.Module.GetNextJumpLabel(); } string endLabel = method.Module.GetNextJumpLabel(); if (elseLabel == null) { elseLabel = endLabel; } method.Statements.Add(new AsmStatement { Instruction = "test al,al" }); method.Statements.Add(new AsmStatement { Instruction = "jz " + elseLabel }); if (!this.TryEmitStatement(ifStatement.TrueStatement, context, scope, method)) { return false; } if (ifStatement.FalseStatement != null) { method.Statements.Add(new AsmStatement { Instruction = "jmp " + endLabel }); method.Statements.Add(new AsmStatement { Instruction = "nop", Label = elseLabel }); if (!this.TryEmitStatement(ifStatement.FalseStatement, context, scope, method)) { return false; } } method.Statements.Add(new AsmStatement { Instruction = "nop", Label = endLabel }); return true; }
public Scope BeginScope(MethodInfo method) { Scope scope = new Scope(); if (method.ReturnType != null) { LocalVariable returnVar = scope.DefineLocalVariable(method.Name, method.ReturnType); scope.ReturnVariable = returnVar; if (method.ReturnType.Size > 8 && !method.ReturnType.IsFloatingPoint || method.ReturnType.IsClass) { scope.LargeReturnVariable = scope.DefineParameter( "$result", this.GetPointerType(method.ReturnType)); } } if (!method.IsStatic) { scope.DefineParameter("this", this.GetPointerType(method.Type)); } foreach (ParameterInfo parameterInfo in method.Parameters) { scope.DefineParameter(parameterInfo.Name, parameterInfo.Type); } return scope; }