diff --git a/AST.py b/AST.py index 2f451c7851b650df4c95dd099e81977a6376b849..1f2940f38d2da1303657c71159a99bfcb64c073b 100644 --- a/AST.py +++ b/AST.py @@ -17,6 +17,8 @@ class ASTNode(): # reachability: None = not set, True = maybe, False = no self.outMaybe = None # either None or True/False + def getConstant(self): + return None # Do certains actions on every node of the AST tree # call the same method in each class and its children recursively diff --git a/AstBuilding.py b/AstBuilding.py index b195fa3ce293a5e24503d18da203a6454e7db782..3c872478b01a49e1c4019c3878daab46139d6c44 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -1,6 +1,7 @@ from CompNode import CompNode from pprint import pprint from Environment import GlobalEnv +from TypeNodes import getSupers from CodeGenUtils import p, genProcedure, used_labels, local_labels, pLabel, genericHelperFunctions, globalImport # tree: (filename, parseTree) @@ -62,23 +63,38 @@ def reachabilityChecking(ASTs): # Returns a dictionary (type e.g. "boolean") -> str (the assembly code generated) def arrayClassMemory(types): # All method labels from java.lang.Object - # TODO: add subtype testing table methods = ["M_Object_Object_", "M_Object_equals_Object", "M_Object_toString_", "M_Object_hashCode_", "M_Object_clone_", "M_Object_getClass_"] - typeDict = {} primTypes = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types - for t in types: + typeDict = {} + # assignable = dict({"java.lang.Object" : 0, + # "java.lang.Cloneable" : 4, + # "java.io.Serializable" : 8 + # }) + + for tt in types: # Class memory layout # Label: "A_type" # Label for SIT pointer: "I_SIT_spot_typeName_array" # Label for method pointers: "V_typeName_methodName_param_array" + if tt.__class__.__name__ == "ClassNode": + t = tt.name + else: + t = tt + code = "section .data\n" code += "; Start of class memory layout\n" code += pLabel(name=t, type="array") + \ pLabel("SIT_spot_"+ t + "_array", "inter") + \ p(instruction="dd", arg1=64) + + # point to subtype table + code += pLabel("subT_spot_" + t, "inter") + code += p("dd", "42") + for m in methods: code += pLabel(name=t+"_"+m+"_array", type="vtable") + \ p(instruction="dd", arg1=64) + code += "; End of class memory layout\n" # Creating a function to initialize class memory layout @@ -94,6 +110,12 @@ def arrayClassMemory(types): code += p(instruction="extern", arg1=m) + \ p(instruction="mov", arg1="eax", arg2="dword V_"+t+"_"+m+"_array") + \ p(instruction="mov", arg1="[eax]", arg2="dword "+m, comment="points to method implementation") + + if tt.__class__.__name__ == "ClassNode": + code += p("extern", "A_subT_" + tt.name) + code += p("mov", "eax", "I_subT_spot_" + t) + code += p("mov", "[eax]", "dword A_subT_" + tt.name) + code += p(instruction="ret", arg1="") code += "; End of function to initialize class memory layout\n" if t in primTypes: @@ -113,21 +135,23 @@ def codeGenPrep(ASTs): interM = [] types = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types classNodes = [] + j = 0 for t in ASTs: classInterNode = t[1].typeDcl if classInterNode.__class__.__name__ == "ClassNode": - - types.append(classInterNode.name) + types.append(classInterNode) classNodes.append(classInterNode) else: # interfaceNode, get their methods to prep for SIT interM += classInterNode.methods + classInterNode.subTypeOffset = j * 4 # assign each type a position in the subtype testing table + j += 1 + # store SIT and subtype table size - for i in range(len(classNodes)): - classNodes[i].SITsize = len(interM) - classNodes[i].subTypeSize = len(types) - 5 # no primitive types in subtype table - classNodes[i].subTypeOffset = i * 4 # assign each type a position in the subtype testing table + for c in classNodes: + c.SITsize = len(interM) + c.subTypeSize = j # no primitive types in subtype table # prep SIT for i in range(len(interM)): diff --git a/CodeGenUtils.py b/CodeGenUtils.py index c953da3cd38254b328dbf339a5ac04b05e86f372..270f9a21af893614b205682528d3b5ede62f73ad 100644 --- a/CodeGenUtils.py +++ b/CodeGenUtils.py @@ -96,6 +96,7 @@ def genMethodInvoke(method): # generates shorter code for constant value conditionals and comparison conditionals # cond is either literalNode or ExprNode or NameNode +# cond could also be methodInvNode, arrayAccessNode or fieldAccessNode def iffalse(cond, label): result = "" if cond.__class__.__name__ == "NameNode": diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index da0eca1b286a4bcec3ace7274b5e971996a23bb9..043b18beea79d0ac1acf87da0b4b14f1e44ca281 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -163,6 +163,10 @@ class ArrayAccessNode(ASTNode): if not self.index.myType.isNum(): raise Exception("ERROR: Array index must be a number.") self.myType = TypeStruct(self.array.myType.name, self.array.myType.typePointer) + + def getIfFalse(self, label): + self.codeGen() + return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label) def addr(self): result = "; Start of calculating address for array access\n" + \ @@ -327,6 +331,21 @@ class AssignNode(ASTNode): self.code = self.right.code self.code += p("push", "eax") + # array assign check + if self.left.__class__.__name__ == "ArrayAccessNode" and (not self.left.myType.isPrimitive): + self.code += "; array assign subtype check\n" + self.left.array.codeGen() + self.code += self.left.array.code + + offset = self.right.myType.typePointer.subTypeOffset + self.code += p("mov", "ebx", "[eax]", "start subtype test") # access class tag of left object + self.code += p("mov", "ebx", "[ebx + 4]") # access subtype testing column + self.code += p("mov", "ebx", "[ebx + " + str(offset) + "]") # ebx has isSubtype + + # exception if not subtype, else do nothing (object is already in eax) + self.code += p("cmp", "[G__Zero]", "ebx") + self.code += p("je", "H__Throw_Exception") + self.code +=("; Evaluate left of assignment\n") self.code += self.left.addr() @@ -387,8 +406,9 @@ class CastNode(ASTNode): self.code += self.right.code # subtype test: - if not self.left.myType.isPrimitive: - # only test if right is not primitive (primitive types would be correctly static tested already) + if (not self.left.myType.isPrimitive) and self.right.myType.isArray == self.left.myType.isArray: + # only test if not primitive, both are array or both non array + # cast would've exception if array is casting to non-array and not Object offset = self.left.myType.typePointer.subTypeOffset self.code += p("mov", "ebx", "[eax]", "start subtype test") # access class tag of left object self.code += p("mov", "ebx", "[ebx + 4]") # access subtype testing column @@ -578,8 +598,8 @@ class ExprNode(ASTNode): self.left.codeGen() self.code += self.left.code - # only test if non-primitive - if not self.right.myType.isPrimitive: + # only test if non-primitive, both arrays or both non arrays + if (not self.right.myType.isPrimitive) and self.right.myType.isArray == self.left.myType.isArray: offset = self.right.myType.typePointer.subTypeOffset self.code += p("mov", "eax", "[eax]") # access class tag of left object self.code += p("mov", "eax", "[eax + 4]") # access subtype testing column @@ -856,6 +876,10 @@ class FieldAccessNode(ASTNode): checkProtected(self.ID.prefixLink, self) except: # where there are no mods return + + def getIfFalse(self, label): + self.codeGen() + return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label) # generates code that evaluates the address of field access # result stored in eax (address) @@ -886,8 +910,7 @@ class FieldAccessNode(ASTNode): return fieldNode = self.ID.prefixLink - label = fieldNode.typeName + "_" + fieldNode.name - self.code = "; Accessing a field :" + label + "\n" + self.code = "; Accessing a field \n" # Evaluating the address of the field we're trying to access if self.primary: self.code += self.addr() @@ -989,6 +1012,10 @@ class MethodInvNode(ASTNode): self.args.codeGen() self.code += self.args.code + def getIfFalse(self, label): + self.codeGen() + return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label) + def codeGen(self): if hasattr(self, "code"): return diff --git a/TypeNodes.py b/TypeNodes.py index 99fab645db712e1729f483ba14d6633671a8cda5..28b222c58dec73c4435f72bad8c0cc78a404ce47 100644 --- a/TypeNodes.py +++ b/TypeNodes.py @@ -19,7 +19,7 @@ class ClassInterNode(ASTNode): self.SITsize = 0 self.subTypeSize = 0 self.subTypeOffset = 0 - + # sets self.inherits = [] self.super = [] @@ -331,7 +331,7 @@ class ClassNode(ClassInterNode): ####### ADDING METHODS TO CLASS MEMORY LAYOUT AND FIELDS TO FIELD OFFSET TABLE ######### # Copying over the offsets of methods from superclass and DECLARING memory segment for the methods - lastMethodOffset = 0 # stores the largest method offset in the superCalss + lastMethodOffset = 4 # stores the largest method offset in the superCalss # TODO: set this to 4 after the implemntation of both the SIT and subtype testing table # Note: This is 4 less than the offset of where the next method would be located # This is to accomodate for the addition of 4 to lastMethodOffset in EVERY (including the first) iteration in the @@ -384,7 +384,7 @@ class ClassNode(ClassInterNode): self.data += p("dd", "42") # Layout subtype testing column - self.data += pLabel("subT_" + self.name, "inter") + self.data += pLabel("subT_" + self.name, "array") for i in range(self.subTypeSize): self.data += pLabel("subT_" + str(i), "inter") self.data += p("dd", "0") # 0 for False, 1 for True @@ -443,7 +443,7 @@ class ClassNode(ClassInterNode): # fill in subtype testing column self.code += "\n; Filling in subtype testing\n" self.code += p("mov", "eax", "I_subT_spot_" + self.name) - self.code += p("mov", "[eax]", "dword I_subT_" + self.name) + self.code += p("mov", "[eax]", "dword A_subT_" + self.name) for t in getSupers(self): # getSupers includes self dlabel = "I_subT_" + str(t.subTypeOffset // 4)