diff --git a/A5.zip b/A5.zip new file mode 100644 index 0000000000000000000000000000000000000000..d96a475d26c7beedde45a56f4d87912d3beca574 Binary files /dev/null and b/A5.zip differ diff --git a/CodeGenUtils.py b/CodeGenUtils.py index 270f9a21af893614b205682528d3b5ede62f73ad..4eac0e2ca23fa280418322a8a88710eefd77d66b 100644 --- a/CodeGenUtils.py +++ b/CodeGenUtils.py @@ -102,7 +102,8 @@ def iffalse(cond, label): if cond.__class__.__name__ == "NameNode": cond.codeGen() result += cond.code - result += p("jz", label) + result += p(instruction="cmp", arg1="eax", arg2=0, comment="comparing eax with 0") + result += p(instruction="je", arg1=label) return result val = cond.getConstant() diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index 043b18beea79d0ac1acf87da0b4b14f1e44ca281..b46b1cc6e63a3f6657b2ca4b991421d87b026de9 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -5,6 +5,7 @@ import MemberNodes from TheTypeNode import TypeNode, TypeStruct from NameNode import NameNode, checkProtected from CodeGenUtils import p, pLabel, genMethodInvoke, importHelper, getCFlowLabel +from codeGenNodes import genNameNode # file containing smaller (lower level nodes) in the AST # nodes in this file: @@ -93,16 +94,22 @@ def helperDisambigName(node): # args exprs, exprs expr COMMA exprs class ArgsNode(ASTNode): # always list all fields in the init method to show the class structure - def __init__(self, parseTree, typeName): + def __init__(self, parseTree, typeName, exprs = []): self.parseTree = parseTree self.exprs = [] # a list of expressions self.env = None self.children = [] self.typeName = typeName # the type (class/interface) this node belongs under - exprs = getParseTreeNodes(['expr'], parseTree) - for e in exprs: - self.exprs.append(makeNodeFromExpr(e, typeName)) + if exprs == []: + exprs = getParseTreeNodes(['expr'], parseTree) + for e in exprs: + self.exprs.append(makeNodeFromExpr(e, typeName)) + else: + # manually induce exprs + # for converting string concatenation to a method call + # see ExprPrimaryNodes:ExprNode on string concat + self.exprs = exprs self.children.extend(self.exprs) @@ -163,7 +170,7 @@ 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) @@ -326,16 +333,13 @@ class AssignNode(ASTNode): def codeGen(self): self.code = "" - self.code +=("; Evaluate right of assignment\n") - self.right.codeGen() - 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 + self.code += p("push", "eax") offset = self.right.myType.typePointer.subTypeOffset self.code += p("mov", "ebx", "[eax]", "start subtype test") # access class tag of left object @@ -348,9 +352,14 @@ class AssignNode(ASTNode): self.code +=("; Evaluate left of assignment\n") self.code += self.left.addr() + self.code += p("push", "eax") + + self.code +=("; Evaluate right of assignment\n") + self.right.codeGen() + self.code += self.right.code self.code += p("pop", "ebx") - self.code += p("mov", "[eax]", "ebx") + self.code += p("mov", "[ebx]", "eax") self.code += ("; End of assignment\n") @@ -358,21 +367,30 @@ class AssignNode(ASTNode): # cast: castExpr LPAREN castType RPAREN unaryNotPlusMinus class CastNode(ASTNode): # always list all fields in the init method to show the class structure - def __init__(self, parseTree, typeName): + def __init__(self, parseTree, typeName, left = None, right = None): self.parseTree = parseTree - self.left = parseTree.children[1] # cast: (left)right - self.right = makeNodeFromExpr(parseTree.children[3], typeName) # expr self.env = None self.children = [] self.typeName = typeName # the type (class/interface) this node belongs under - if self.left.name == 'expr': - self.left = makeNodeFromExpr(self.left, typeName) - else: #primitiveType or ArrayType - self.left = TypeNode(self.left, typeName) - # since a type might be mis-parsed as a name - if self.left.__class__.__name__ == 'NameNode': - self.left = TypeNode(self.parseTree.children[1], typeName) + if left is None or right is None: + self.left = parseTree.children[1] # cast: (left)right + self.right = makeNodeFromExpr(parseTree.children[3], typeName) # expr + + if self.left.name == 'expr': + self.left = makeNodeFromExpr(self.left, typeName) + else: #primitiveType or ArrayType + self.left = TypeNode(self.left, typeName) + # since a type might be mis-parsed as a name + if self.left.__class__.__name__ == 'NameNode': + self.left = TypeNode(self.parseTree.children[1], typeName) + + else: + # manually induce left and right + # for converting string concatenation to a method call + # see ExprPrimaryNodes:ExprNode on string concat + self.left = left + self.right = right self.children.append(self.left) self.children.append(self.right) @@ -406,17 +424,24 @@ class CastNode(ASTNode): self.code += self.right.code # subtype test: - 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 - 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") + # only test if not primitive + if self.right.myType.isArray == self.left.myType.isArray: + if (not self.right.myType.isPrimitive): + # 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 + 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") + else: # one is array, one is Object/Serializable/Cloneable + # make sure cast only one way + if self.left.myType.isArray: + self.code += p("jmp", "H__Throw_Exception") + self.code += "; end of casting\n" ################################################################################### @@ -488,21 +513,26 @@ class ClassCreateNode(ASTNode): # 2. Pointing first item to vtable self.code += importHelper(classDef.name, self.typeName, "C_"+classDef.name) self.code += p(instruction="mov", arg1="[eax]", arg2="dword C_" + classDef.name, comment="first item is vtable pointer") + self.code += p("mov", "ebx", "eax", "store obj ptr at ebx") # 3. Calling constructor self.code += "; Calling constructor for object\n" - self.code += p(instruction="push", arg1="eax", comment="pushing object as first argument") - # Evaluate arguments and pushing parameters + + # Evaluate arguments if self.args and hasattr(self.args, "codeGen"): - self.args.codeGen() + if not hasattr(self.args, "code"): + self.args.codeGen() self.code += self.args.code + + self.code += p(instruction="push", arg1="ebx", comment="pushing object as last argument") label = "M_" + self.cons.typeName + "_" + self.cons.name + "_" + self.cons.paramTypes self.code += importHelper(classDef.name, self.typeName, label) self.code += p(instruction="call", arg1=label, comment="Calling constructor") # 4. Popping parameters and pointer to object - self.code += p(instruction="add", arg1="esp", arg2=len(self.args.exprs)*4, comment="Popping parameters") + \ - p(instruction="pop", arg1="eax", comment="eax now contains pointer to newly created object") + self.code += p(instruction="pop", arg1="eax", comment="eax now contains pointer to newly created object") + self.code += p(instruction="add", arg1="esp", arg2=len(self.args.exprs)*4, comment="Popping parameters") + self.code += ";End of object creation\n" @@ -582,6 +612,80 @@ class ExprNode(ASTNode): or (self.right.myType.name =='java.lang.String' and self.left.myType.name not in ['void'])) and self.op == '+': self.myType = TypeStruct('java.lang.String', self.env.getNode('java.lang.String', 'type')) self.myType.link(self.env) + + # if left/right is a string, we don't need value of + concatLeft = self.left + concatRight = self.right + + # var1 + var2 === String.valueOf(var1).concat( String.valueOf(var2) ) + + if self.left.myType.name != 'java.lang.String' or self.right.myType.name != 'java.lang.String': + # methodInvoc name LPAREN args RPAREN (because it's static) + # MethodInvNode + # ID = NameNode + # - name = "String.valueOf" + # args = ArgsNode + # - exprs = [self.left] + + # create MethodInvNode to call String.valueOf(left) and String.valueOf(right) + # 1. Make NameNode for String.valueOf + valueOfNameNode = NameNode(self.parseTree, True, self.typeName, "String.valueOf") + valueOfNameNode.env = self.env + + # store these as they could change in step 2 + leftValueOf = self.left + rightValueOf = self.right + + # 2. cast to Object if it is not safe to call String.valueOf + safeTypes = ['java.lang.String', 'char', 'int', 'short', 'byte', 'boolean', 'java.lang.Object', 'String'] + + if self.left.myType.name not in safeTypes or self.right.myType.name not in safeTypes: + + # CastNode + # - left = TypeNode + # - myType = TypeStruct + # - name = 'java.lang.Object' + # - typePointer = call link() ! + # - right = value of thing being casted + + # create object TypeNode + objectCastType = TypeNode('VOID', self.typeName) + objectCastType.myType = TypeStruct('java.lang.Object', None) + objectCastType.myType.link(self.env) + + if self.left.myType.name not in safeTypes: + leftValueOf = CastNode(self.parseTree, self.typeName, objectCastType, self.left) + + if self.right.myType.name not in safeTypes: + rightValueOf = CastNode(self.parseTree, self.typeName, objectCastType, self.right) + + # 3. call String.valueOf on the variable that needs to be converted + if self.left.myType.name != 'java.lang.String': + leftArg = ArgsNode(self.parseTree, self.typeName, [leftValueOf]) + concatLeft = MethodInvNode(self.parseTree, self.typeName, valueOfNameNode, leftArg) + + if self.right.myType.name != 'java.lang.String': + rightArg = ArgsNode(self.parseTree, self.typeName, [rightValueOf]) + concatRight = MethodInvNode(self.parseTree, self.typeName, valueOfNameNode, rightArg) + + # methodInvoc primary PERIOD ID LPAREN args RPAREN + # MethodInvNode + # primary = self.left + # ID = NameNode + # - name = "concat" + # args = ArgsNode + # - exprs = [self.right] + + # create MethodInvNode to call left.concat(right) + # 1. Make NameNode for String.concat (name = "concat") + concatNameNode = NameNode(self.parseTree, True, self.typeName, "concat") + # 2. Make ArgsNode for right + rightArg = ArgsNode(self.parseTree, self.typeName, [concatRight]) + # 3. Put it all together + self.concatMethodInv = MethodInvNode(self.parseTree, self.typeName, concatNameNode, rightArg, concatLeft) + # 4. Check type to be safe + self.concatMethodInv.checkType() + return raise Exception("ERROR: Incompatible types. Left of {} type can't be used with right of {} type on operation {}".format(self.left.myType.name, self.right.myType.name, self.op)) @@ -599,16 +703,38 @@ class ExprNode(ASTNode): self.code += self.left.code # 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 - self.code += p("mov", "eax", "[eax + " + str(offset) + "]") # subType column stores 0 or 1 already - else: # primitive type can be staticly evaluated - if self.right.myType.assignable(self.left.myType): - self.code += p("mov", "eax", "1") - else: + if self.right.myType.isArray == self.left.myType.isArray: + if not self.left.myType.isPrimitive: + 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 + self.code += p("mov", "eax", "[eax + " + str(offset) + "]") # subType column stores 0 or 1 already + + else: # primitive type can be staticly evaluated + if self.right.myType.assignable(self.left.myType): + self.code += p("mov", "eax", "1") + else: + self.code += p("mov", "eax", "0") + + else: # non array is never an instance of array, array could be non array + if self.right.myType.isArray: self.code += p("mov", "eax", "0") + else: + if self.right.myType.assignable(self.left.myType): + self.code += p("mov", "eax", "1") + n = getCFlowLabel() + endLabel = "_end" + n + + self.left.codeGen() + self.code += self.left.code + + self.code += p("cmp", "eax", "[G__Zero]") + self.code += p("mov", "eax", "1") + self.code += p("jne", endLabel) + self.code += p("mov", "eax", "0") + self.code += p(endLabel + ":", "") + else: + self.code += p("mov", "eax", "0") self.code += ("; end of instanceof\n") return @@ -646,8 +772,10 @@ class ExprNode(ASTNode): self.code += self.left.code if self.op == '&&': + # if left result == false, break out self.code += p("cmp", "eax", "0") elif self.op == '||': + # if left result == true, break out self.code += p("cmp", "eax", "1") self.code += p("je", endLabel, "", " breaking out of " + self.op) @@ -672,6 +800,14 @@ class ExprNode(ASTNode): self.code += p(endLabel + ":", "") return + # String Add + if (self.left.myType.name =='java.lang.String' or self.right.myType.name =='java.lang.String') and self.op == '+': + # ( String.valueOf(right) ).concat( left ) + if not hasattr(self.concatMethodInv, "code"): + self.concatMethodInv.codeGen() + self.code += self.concatMethodInv.code + return + # is binary and rest can use helper function: self.code += self.codeGenLeftRight() @@ -698,10 +834,7 @@ class ExprNode(ASTNode): return # Binary operations: - # String Add TODO - if (self.left.myType.name =='java.lang.String' or self.right.myType.name =='java.lang.String') \ - and self.op == '+': - return + # Number Add, Subtract, Multiply if self.op in ['+', '-', '*']: # operation -> generated code @@ -719,6 +852,11 @@ class ExprNode(ASTNode): # switch eax and ebx, because "idiv ebx" -> eax = edx:eax / ebx self.code += p('xchg', 'eax', 'ebx') + # divide by 0 check + if self.op == '/': + self.code += p("cmp", "ebx", "0") + self.code += p("je", "H__Throw_Exception") + self.code += p('push', 'edx') # save edx in case someone else was using it self.code += p('cdq', '', None, " set edx to the sign of eax") self.code += p("idiv", "ebx", "", " left:eax " + self.op + " right:ebx") @@ -876,7 +1014,7 @@ 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) @@ -928,7 +1066,7 @@ class FieldAccessNode(ASTNode): # methodInvoc class MethodInvNode(ASTNode): # always list all fields in the init method to show the class structure - def __init__(self, parseTree, typeName): + def __init__(self, parseTree, typeName, ID = '', args = None, primary = None): self.parseTree = parseTree self.primary = None # can be empty self.ID = '' # can be either ID or compID @@ -938,12 +1076,23 @@ class MethodInvNode(ASTNode): self.method = None self.typeName = typeName # the type (class/interface) this node belongs under - # input parse tree is either: methodInvoc primary PERIOD ID LPAREN args RPAREN - # methodInvoc name LPAREN args RPAREN - self.ID = NameNode(parseTree.children[-4], True, typeName) - self.args = ArgsNode(parseTree.children[-2], typeName) - if parseTree.children[0].name == 'primary': - self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName) + if ID == '' or args is None: + # input parse tree is either: methodInvoc primary PERIOD ID LPAREN args RPAREN + # methodInvoc name LPAREN args RPAREN + self.ID = NameNode(parseTree.children[-4], True, typeName) + self.args = ArgsNode(parseTree.children[-2], typeName) + if parseTree.children[0].name == 'primary': + self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName) + self.override = False + else: + # manually induce ID and args + # for converting string concatenation to a method call + # see ExprPrimaryNodes:ExprNode on string concat + self.ID = ID + self.args = args + if primary is not None: + self.primary = primary + self.override = True self.children.append(self.primary) self.children.append(self.args) @@ -986,7 +1135,7 @@ class MethodInvNode(ASTNode): if m: # check static - if (not self.ID.shouldBeStatic) and 'static' in m.mods: + if (not self.ID.shouldBeStatic and not self.override) and 'static' in m.mods: raise Exception("ERROR: Non-static access of static method {}.".format(m.name)) # check protected @@ -1059,6 +1208,10 @@ class MethodInvNode(ASTNode): self.code += self.primary.code else: # a name node if not hasattr(self.ID, "code"): + if not self.ID.prefixNodes: + cNameNode = genNameNode(self.typeName) + cNameNode.isThis = True + self.ID.prefixNodes.append(cNameNode) self.ID.codeGen() self.code += self.ID.code diff --git a/LineNodes.py b/LineNodes.py index 20338426a2c6dfafa0f6e43120f470d14fc4f8ed..be572513acf7298856bd71447d9e0e6932e9da1f 100644 --- a/LineNodes.py +++ b/LineNodes.py @@ -111,7 +111,7 @@ class BlockNode(ASTNode): # 1. variableDcl type ID # 2. variableDcl type ID ASSIGN variableInit class VarDclNode(ASTNode): - def __init__(self, parseTree, typeName, checkAssign=False): + def __init__(self, parseTree, typeName, checkAssign=False, isField=None): self.parseTree = parseTree self.dclType = None self.name = None # variable name @@ -119,6 +119,7 @@ class VarDclNode(ASTNode): self.env = None self.children = [] self.typeName = typeName + self.isField = isField self.dclType = TypeNode(parseTree.children[0], typeName) self.name = parseTree.children[1].lex diff --git a/MemberNodes.py b/MemberNodes.py index 4a3d14c93f93a3fcf03d82ef26b549f5dc8fb01c..8f5168e3aeb7e6c9901ea1b7493ddd47423ca747 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -26,7 +26,7 @@ class FieldNode(ASTNode): self.mods.append(m.lex) elif node.name == 'variableDcl': - self.variableDcl = VarDclNode(node, self.typeName) + self.variableDcl = VarDclNode(node, self.typeName, isField=self) self.name = self.variableDcl.name self.myType = self.variableDcl.myType @@ -118,7 +118,10 @@ class MethodNode(ASTNode): for n in nameNodes: paramNode = ParamNode(n, self.typeName) self.params.append(paramNode) - self.paramTypes += paramNode.paramType.myType.name + if paramNode.paramType.myType.isArray: + self.paramTypes += paramNode.paramType.myType.name + "Array" + else: + self.paramTypes += paramNode.paramType.myType.name nameNodes = getParseTreeNodes(['type', 'VOID'], parseTree, ['methodBody', 'params']) for n in nameNodes: @@ -260,6 +263,14 @@ class MethodNode(ASTNode): if hasattr(self, "code") and self.code != "": return + # populate param offsets + # params + stackoffset = 12 + rparams = self.params.copy() + rparams.reverse() + for i, param in enumerate(rparams): + param.offset = i * 4 + stackoffset # 12 since the stack is now of the order: ebp, eip, o, params + myClass = self.env.getNode(self.typeName, 'type') self.label = "M_" + self.typeName + "_" + self.name + "_" + self.paramTypes @@ -278,7 +289,7 @@ class MethodNode(ASTNode): if myClass.superClass: suLabel = "M_" + myClass.superClass.name + "_" + myClass.superClass.name + "_" bodyCode += importHelper(myClass.superClass.name, self.typeName, suLabel) - bodyCode += p("mov", "eax", "[ebp - " + str(thisLoc) + "]") + bodyCode += p("mov", "eax", "[ebp + " + str(thisLoc) + "]") bodyCode += p("push", "eax", None, "# Pass THIS as argument to superClass.") bodyCode += p("call", suLabel) bodyCode += p("add", "esp", "4") # pop object off stack @@ -349,11 +360,28 @@ def getNameNodes(node): # Output: A list of local var dcl to be pushed onto the stack def getVarDclNodes(node): result = [] - for s in node.statements: - if s.__class__.__name__ == 'VarDclNode': - result += [s] - if s.__class__.__name__ == 'BlockNode': - result += getVarDclNodes(node) + if node.__class__.__name__ == 'VarDclNode': + return [node] + elif node.__class__.__name__ == 'BlockNode': + for s in node.statements: + if s.__class__.__name__ == 'VarDclNode': + result += [s] + + if s.__class__.__name__ == 'BlockNode': + result += getVarDclNodes(node) + + if s.__class__.__name__ == 'ForNode': + if s.forInit: + result += [s.forInit] + if s.bodyStatement: + result += getVarDclNodes(s.bodyStatement) + + if s.__class__.__name__ =='WhileNode' and s.whileBody: + result += getVarDclNodes(s.whileBody) + if s.__class__.__name__ == "IfNode": + result += getVarDclNodes(s.ifBody) + if s.elseBody: + result += getVarDclNodes(s.elseBody) return result diff --git a/NameNode.py b/NameNode.py index 859f25fdeb799941053e0a70b25754de7ab09056..2ad7f34093d8b6b13193f44059922c78fc3919e5 100644 --- a/NameNode.py +++ b/NameNode.py @@ -19,7 +19,7 @@ from codeGenNodes import genNameNode class NameNode(ASTNode): - def __init__(self, parseTree, methodInvoke, typeName): + def __init__(self, parseTree, methodInvoke, typeName, name = ""): self.parseTree = parseTree self.name = "" # str: stores original lex of the name (ID/COMPID) @@ -40,7 +40,14 @@ class NameNode(ASTNode): self.staticField = None self.prefixNodes = [] # stores the past prefix links so we can evaluate them one by one - self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex + if name == "": + self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex + else: + # manually induce name + # for converting string concatenation to a method call + # see ExprPrimaryNodes:ExprNode on string concat + self.name = name + self.IDs = self.name.split(".") # Updates the resolved/identified prefix @@ -85,6 +92,8 @@ class NameNode(ASTNode): def checkLocalVar(self): if not self.IDs: return True + if 'this' in self.name: + return False ID = self.IDs[0] localVarNode = self.env.findNode(ID, "expr") if localVarNode: @@ -110,9 +119,10 @@ class NameNode(ASTNode): self.addToPrefix("contain") # evaluate THIS first, fieldnode will be added to prefixNodes in checkType() - cNameNode = genNameNode(self.typeName) - cNameNode.isThis = True - self.prefixNodes.append(cNameNode) + if not self.prefixNodes: + cNameNode = genNameNode(self.typeName) + cNameNode.isThis = True + self.prefixNodes.append(cNameNode) return True return False @@ -235,6 +245,7 @@ class NameNode(ASTNode): self.methodClass = meth.env.getNode(meth.typeName, 'type') self.methodName = self.IDs[0] + else: if curType.myType and curType.myType.isArray and self.IDs[0] == 'length': self.myType = TypeStruct("int", None) diff --git a/TheTypeNode.py b/TheTypeNode.py index 40d6498737def14bc01a31fb026fa2a94a6aadb2..5100a731ab618ef1127190eca60e90c438e7ab15 100644 --- a/TheTypeNode.py +++ b/TheTypeNode.py @@ -41,7 +41,7 @@ class TypeStruct(): self.isPrimitive = False self.typePointer = typePointer self.name = name - if name in ['boolean', 'byte', 'char', 'int', 'short', 'void']: + if name in ['boolean', 'byte', 'char', 'int', 'short', 'void', 'null']: self.isPrimitive = True def link(self, env): diff --git a/TypeNodes.py b/TypeNodes.py index 28b222c58dec73c4435f72bad8c0cc78a404ce47..57ff04b96876eeffa31397d0c1ebda79a60954be 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 = [] @@ -414,11 +414,18 @@ class ClassNode(ClassInterNode): className = key[0] mLabel = "M_" + className + "_" + key[0] + "_" + key[1] # method implementation - # First need to import method implementation labels - if className != self.name: + # native write: (badly hardcoded here) + if vLabel == "V_OutputStream_nativeWrite_int": + mLabel = "NATIVEjava.io.OutputStream.nativeWrite" self.code += p(instruction="extern", arg1=mLabel, comment="importing method implementation label") - self.code += p(instruction="mov", arg1="eax", arg2=vLabel, comment="Filling in class memory segment for method " + mLabel) - self.code += p(instruction="mov", arg1="[eax]", arg2="dword " + mLabel) + self.code += p(instruction="mov", arg1="eax", arg2=vLabel, comment="Filling in class memory segment for method " + mLabel) + self.code += p(instruction="mov", arg1="[eax]", arg2="dword " + mLabel) + else: + # First need to import method implementation labels + if className != self.name: + self.code += p(instruction="extern", arg1=mLabel, comment="importing method implementation label") + self.code += p(instruction="mov", arg1="eax", arg2=vLabel, comment="Filling in class memory segment for method " + mLabel) + self.code += p(instruction="mov", arg1="[eax]", arg2="dword " + mLabel) self.code += "; End of function for filling in methods in class memory layout\n" diff --git a/UnitNodes.py b/UnitNodes.py index 606114766223e0f486d3e7238a877ad841611c2f..9f80a5f677810171453094cdb2878099c71709cf 100644 --- a/UnitNodes.py +++ b/UnitNodes.py @@ -1,7 +1,7 @@ from AST import ASTNode, getParseTreeNodes from Environment import Env from TheTypeNode import TypeNode, TypeStruct -from CodeGenUtils import p, getLStringLabel +from CodeGenUtils import p, getLStringLabel, importHelper # LiteralNode # ParamNode @@ -35,6 +35,13 @@ class LiteralNode(ASTNode): self.value = False else: self.value = True + if self.value == "'\\n'": + self.value = ord('\n') + elif self.name == 'char' and len(self.value) == 3: + self.value = ord(self.value[1]) + elif self.name == 'char': + self.value = ord(self.value) + def linkType(self): if self.name == "java.lang.String": @@ -55,20 +62,90 @@ class LiteralNode(ASTNode): self.code += p("mov", "eax", "0", " set to literal false") return - # char TODO + # char if self.name == 'char': + # store literal char as ASCII self.code += p("mov", "eax", str(self.getConstant()), " set to literal char") return - # string TODO - # if self.name == 'java.lang.String': - # n = getLStringLabel() - # lStringLabel = "_literalstring" + n + # string + if self.name == 'java.lang.String': + self.code += ";Start of String Literal Creation for class " + self.typeName + "\n" + # generate array of characters + # then call new String(array) + + # remove quotation marks + value = self.value[1:-1] + + # FIRST: create char array for this string + # 1. Allocating space for the char array in heap + # Note: uses ecx to temporarily store the array length + self.code += ";Start of char array creation\n" + \ + p(instruction="mov", arg1="eax", arg2=str(len(value)), comment="array length") + \ + p(instruction="push", arg1="ecx", comment="saving ecx's value") + \ + p(instruction="mov", arg1="ecx", arg2="eax", comment="ecx now stroes the array's length") + \ + p(instruction="add", arg1="eax", arg2=2, comment="number of items to allocate on heap") + \ + p(instruction="imul", arg1="eax", arg2=4, comment="number of bytes to allocate on heap") + \ + p(instruction="call", arg1="__malloc", comment="allocating memory for array on heap") + + # 2. Pointing first item to vtable + aLabel = "A_char" + self.code += p(instruction="extern", arg1=aLabel) + \ + p(instruction="mov", arg1="[eax]", arg2="dword "+aLabel, comment="first item is vtable pointer") + + # 3. Storing length in the second slot + self.code += p(instruction="mov", arg1="[eax+4]", arg2="ecx", comment="storing array length in second slot") + + # 4. populate array with this string literal's chars + self.code += ";Start of populating char array\n" + # loop through string + for i in range(len(value)): + self.code += p(instruction="mov", arg1="[eax+"+str(8+i*4)+"]", arg2="dword " + str(ord(value[i])), comment="a["+str(i)+"]="+str(value[i])) + self.code += ";End of populating char array\n" + + # 5. Restoring ecx + self.code += p(instruction="pop", arg1="ecx", comment="restoring register ecx") + self.code += ";End of char array creation\n" + + # SECOND: create new string object with the char array + + # push array pointer + self.code += p(instruction="push", arg1="eax", comment="save pointer to char array") - # self.code += p(lStringLabel + ":", "") - # self.code += p("db", str(self.getConstant())) - # self.code += p("mov", "eax", "[" + lStringLabel + "]", " set to literal string") - # return + # 1. alloc enough space for this object + classDef = self.env.getNode('java.lang.String', 'type') + fieldOffset = classDef.fieldOffset + numFields = len(fieldOffset) + numBytes = (numFields + 1) * 4 + self.code += "; Creating an object for class " + self.typeName + "\n" + self.code += p(instruction="mov", arg1="eax", arg2=numBytes, comment="allocating memory for object") + \ + p(instruction="call", arg1="__malloc") + + # 2. Pointing first item to vtable + self.code += importHelper(classDef.name, self.typeName, "C_"+classDef.name) + self.code += p(instruction="mov", arg1="[eax]", arg2="dword C_" + classDef.name, comment="first item is vtable pointer") + + # restore pointer to our char array + self.code += p("pop", "ebx", comment="restore pointer to our char array") + + # 3. Calling constructor + self.code += "; Calling constructor for String\n" + # Evaluate arguments and pushing parameters + self.code += p("push", "ebx", comment="add our char array as arg") + self.code += p(instruction="push", arg1="eax", comment="pushing object as last argument") + + + # 4. call String::String(char[] chars) + label = "M_String_String_charArray" + self.code += importHelper(classDef.name, self.typeName, label) + self.code += p(instruction="call", arg1=label, comment="Calling constructor") + + # 4. Popping parameters and pointer to object + self.code += p(instruction="pop", arg1="eax", comment="eax now contains pointer to newly created object") + self.code += p("add", "esp", "4", "Popping parameters") + self.code += ";End of object creation\n" + self.code += ";End of String Literal Creation for class " + self.typeName + "\n" + return # null if self.name == 'null': @@ -76,8 +153,8 @@ class LiteralNode(ASTNode): return # int - if self.name == 'int': - self.code += p("mov", "eax", str(self.getConstant()), " set to literal int") + if self.name in ['int', 'short']: + self.code += p("mov", "eax", str(self.getConstant()), " set to literal num") return def getConstant(self): diff --git a/codeGenNodes.py b/codeGenNodes.py index 828dc5bd2a13dc32f6d11b36c4b56bf8cbf310d8..f5ae3c8781f24e4bd435f36f3dda564e48bb0364 100644 --- a/codeGenNodes.py +++ b/codeGenNodes.py @@ -20,7 +20,13 @@ class genNameNode(): self.code += p("add", "eax", 4) self.code += p("mov", "eax", "[eax]") elif self.nodeLink.__class__.__name__ == "VarDclNode": - self.code = p("mov", "eax", "[ebp - " + str(self.nodeLink.offset) + "]") + if self.nodeLink.isField : + self.code = p("mov", "eax", "[ebp + 8]") + self.code += p("call", "H__Null_Check") + self.code += p("add", "eax", self.nodeLink.isField.offset) + self.code += p("mov", "eax", "[eax]") + else: + self.code = p("mov", "eax", "[ebp - " + str(self.nodeLink.offset) + "]") elif self.nodeLink.__class__.__name__ == "ParamNode": self.code = p("mov", "eax", "[ebp + " + str(self.nodeLink.offset) + "]") elif self.nodeLink.__class__.__name__ == "FieldNode": @@ -47,15 +53,20 @@ class genNameNode(): result += p("call", "H__Null_Check") result += p("add", "eax", 4) elif self.nodeLink.__class__.__name__ == "VarDclNode": - result = p("mov", "eax", "ebp") - result += p("sub", "eax", str(self.nodeLink.offset)) + if self.nodeLink.isField : + result = p("mov", "eax", "[ebp + 8]") + result += p("call", "H__Null_Check") + result += p("add", "eax", self.nodeLink.isField.offset) + else: + result = p("mov", "eax", "ebp") + result += p("sub", "eax", str(self.nodeLink.offset)) elif self.nodeLink.__class__.__name__ == "ParamNode": result = p("mov", "eax", "ebp") result += p("add", "eax", str(self.nodeLink.offset)) elif self.nodeLink.__class__.__name__ == "FieldNode": if self.isStatic: label = self.nodeLink.typeName + "_" + self.nodeLink.name - self.code += importHelper(self.nodeLink.typeName, self.typeName, "S_"+label) + \ + result += importHelper(self.nodeLink.typeName, self.typeName, "S_"+label) + \ p("mov", "eax", "dword S_"+label) else: # object will already be in eax