public bool CreateTypes(CompilerContext context, ProgramUnit programUnit) { bool failed = false; foreach (string uses in programUnit.Uses) { List<string> searchDirs = new List<string>(); searchDirs.Add(System.IO.Path.GetDirectoryName(programUnit.Start.Path)); searchDirs.AddRange(context.Includes); string headerPath = null; foreach (string dir in searchDirs) { string includePath = System.IO.Path.Combine( dir, uses + ".th"); if (System.IO.File.Exists(includePath)) { headerPath = includePath; break; } } if (headerPath != null && !context.AlreadyUsed(uses)) { context.AddAlreadyUsed(uses); ProgramUnit usedProgramUnit = null; using (TokenReader reader = new TokenReader(headerPath, this.log)) { Parser includeParser = new Parser(this.log); if (includeParser.TryParse(reader, out usedProgramUnit)) { if (!this.CreateTypes(context, usedProgramUnit)) { failed = true; } } else { failed = true; } } } } context.ClearUses(); foreach (string uses in programUnit.Uses) { context.AddUses(uses); } context.Namespace = programUnit.Namespace; foreach (TypeDeclaration typeDecl in programUnit.Types) { TypeDefinition typeDef = null; if (!context.TryDeclareType(typeDecl.Name, out typeDef)) { string message = string.Format( Properties.Resources.CodeGenerator_TypeAlreadyDeclared, typeDecl.Name); log.Write(new Message( typeDecl.Start.Path, typeDecl.Start.Line, typeDecl.Start.Column, Severity.Error, message)); failed = true; } ClassDeclaration classDecl = typeDecl as ClassDeclaration; if (classDecl != null) { typeDef.IsClass = true; typeDef.IsPublic = classDecl.IsPublic; typeDef.IsStaticClass = classDecl.IsStatic; if (classDecl.BaseType != null) { TypeDefinition baseType = null; if (!context.TryFindTypeByName(classDecl.BaseType, out baseType)) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_UndefinedType, classDecl.BaseType); this.log.Write(new Message( classDecl.Start.Path, classDecl.Start.Line, classDecl.Start.Column, Severity.Error, message)); failed = true; } else { if (!baseType.IsClass || baseType.IsStaticClass) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_BaseTypeNotClass, baseType.FullName); this.log.Write(new Message( classDecl.Start.Path, classDecl.Start.Line, classDecl.Start.Column, Severity.Error, message)); failed = true; } else { typeDef.BaseClass = baseType; } } } bool hasVirtualMethods = false; foreach (MethodDeclaration meth in classDecl.PublicMethods) { MethodInfo methodInfo = null; if (!this.TryCreateMethod(context, typeDef, meth, out methodInfo)) { failed = true; continue; } methodInfo.IsPublic = true; typeDef.Methods.Add(methodInfo); if (methodInfo.IsVirtual) { hasVirtualMethods = true; } } foreach (MethodDeclaration meth in classDecl.ProtectedMethods) { MethodInfo methodInfo = null; if (!this.TryCreateMethod(context, typeDef, meth, out methodInfo)) { failed = true; continue; } methodInfo.IsProtected = true; typeDef.Methods.Add(methodInfo); if (methodInfo.IsVirtual) { hasVirtualMethods = true; } } foreach (MethodDeclaration meth in classDecl.PrivateMethods) { MethodInfo methodInfo = null; if (!this.TryCreateMethod(context, typeDef, meth, out methodInfo)) { failed = true; continue; } methodInfo.IsProtected = true; typeDef.Methods.Add(methodInfo); if (methodInfo.IsVirtual) { hasVirtualMethods = true; } } int size = 0; if (typeDef.BaseClass != null) { size = typeDef.BaseClass.Size; } if (hasVirtualMethods) { FieldInfo vtblPtr = typeDef.GetVTablePointer(); if (vtblPtr == null) { vtblPtr = typeDef.AddVTablePointer(context, size); size += vtblPtr.Type.Size; } } if (classDecl.Fields != null) { foreach (var field in classDecl.Fields.Variables) { TypeDefinition fieldType = null; if (!this.TryResolveTypeReference(context, field.Type, out fieldType)) { failed = true; continue; } foreach (string identifier in field.VariableNames) { FieldInfo fieldInfo = new FieldInfo(); fieldInfo.Name = identifier; fieldInfo.Type = fieldType; fieldInfo.IsStatic = classDecl.IsStatic; if (!fieldInfo.IsStatic) { fieldInfo.Offset = size; size += fieldType.Size; } typeDef.Fields.Add(fieldInfo); } } } typeDef.Size = size; } } return !failed; }
public FieldInfo AddVTablePointer(CompilerContext context, int offset) { TypeDefinition ptrType = null; context.TryFindTypeByName("^", out ptrType); FieldInfo field = new FieldInfo { Name = VTablePointerFieldName, IsPublic = true, Offset = offset, Type = context.GetArrayType(ptrType, 0) }; this.fields.Add(field); return field; }
private bool TryResolveTypeReference( CompilerContext context, TypeReference typeRef, out TypeDefinition typeDef) { NamedTypeReference namedType = typeRef as NamedTypeReference; if (namedType != null) { if (!context.TryFindTypeByName(namedType.TypeName, out typeDef)) { string message = string.Format( Properties.Resources.CodeGenerator_UndefinedType, namedType.TypeName); this.log.Write(new Message( namedType.Start.Path, namedType.Start.Line, namedType.Start.Column, Severity.Error, message)); return false; } return true; } PointerTypeReference pointerType = typeRef as PointerTypeReference; if (pointerType != null) { TypeDefinition innerType = null; if (!this.TryResolveTypeReference(context, pointerType.ElementType, out innerType)) { typeDef = null; return false; } typeDef = context.GetPointerType(innerType); return true; } ArrayTypeReference arrayType = typeRef as ArrayTypeReference; if (arrayType != null) { TypeDefinition innerType = null; if (!this.TryResolveTypeReference(context, arrayType.ElementType, out innerType)) { typeDef = null; return false; } int elementCount = 0; if (arrayType.ElementCount != null) { LiteralExpression litElementCount = arrayType.ElementCount as LiteralExpression; if (litElementCount == null || !(litElementCount.Value is int)) { log.Write(new Message( arrayType.ElementCount.Start.Path, arrayType.ElementCount.Start.Line, arrayType.ElementCount.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayTypeIntElementExpected)); typeDef = null; return false; } elementCount = (int)(litElementCount.Value); } typeDef = context.GetArrayType(innerType, elementCount); return true; } typeDef = null; return false; }
private bool TryFindSystemMemory(Token start, CompilerContext context, out TypeDefinition memoryType) { if (!context.TryFindTypeByName("System.Memory", out memoryType)) { log.Write(new Message( start.Path, start.Line, start.Column, Severity.Error, Properties.Resources.CodeGenerator_SystemMemoryNotDeclared)); return false; } return true; }
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 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 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; }