diff --git a/CodeGenUtils.py b/CodeGenUtils.py index 03b33709a18ef8101fcae36f184f726cf3f1c1c2..c461da718ad4c2aa377c99833bd1c2608492b6cd 100644 --- a/CodeGenUtils.py +++ b/CodeGenUtils.py @@ -15,9 +15,17 @@ def p(instruction, arg1, arg2="", comment=""): # (local label are just for local running of the code) used_labels = set() local_labels = 0 +control_flow_label = 0 + +def getCFlowLabel(): + global control_flow_label + control_flow_label += 1 + return str(control_flow_label) def pLabel(name, type, comment=""): - if type == "local": + global local_labels + global used_labels + if type == "local": l = "_" + str(local_labels) local_labels += 1 else: @@ -70,6 +78,23 @@ def genMethodInvoke(method): return (pro, epi) +# generates shorter code for constant value conditionals and comparison conditionals +# cond is either literalNode or ExprNode +def iffalse(cond, label): + result = "" + val = cond.getConstant() + if val != None: + if val == True: + result = "" # no jump if true + elif val == False: + result += p("jmp", label) + # else val == Int shouldn't happen here, since we already done typeCheck + else: + result = cond.getIfFalse(label) + + return result + + #################################################### diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index 23cb9896cf43efb2c227ad60ef8501fd5d915c72..d0474e356bca9e67d8425bf638e213000080b895 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -247,9 +247,11 @@ class AssignNode(ASTNode): def codeGen(self): self.right.codeGen() self.code = self.right.code - if self.left.prefixLink.__class__.__name__ == "VarDclNode": - # move init result to var location - self.code += p("mov", "[ebp + " + str(self.left.prefixLink.offset) + "]", "eax") + + if self.left.__class__.__name__ == "NameNode": + if self.left.prefixLink.__class__.__name__ == "VarDclNode": + # move init result to var location + self.code += p("mov", "[ebp + " + str(self.left.prefixLink.offset) + "]", "eax") ################################################################################## @@ -429,6 +431,9 @@ class ExprNode(ASTNode): 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)) def codeGen(self): + if hasattr(self, "code") and self.code != "": + return + self.code = "" # Unary: @@ -436,17 +441,7 @@ class ExprNode(ASTNode): self.code = "" return - # get left output - if not hasattr(self.left, "code"): - self.left.codeGen() - self.code += self.left.code - self.code += p("push", "eax") # left result onto stack - - # get right output - if not hasattr(self.right, "code"): - self.right.codeGen() - self.code += self.right.code - self.code += p("pop", "ebx") # left output into ebx + self.code += self.codeGenLeftRight() # now: # ebx = left result @@ -462,6 +457,46 @@ class ExprNode(ASTNode): self.code += p(ops[self.op], "ebx", "eax", " " + ops[self.op] + " left and right") self.code += p("mov", "eax", "ebx", " move result to eax") + # generate shorter code if self.op = comparison + def getIfFalse(self, label): + if self.op not in ['==', '!=', '<=', '>=', '>', '<']: + self.codeGen() + return self.code + else: + result = self.codeGenLeftRight() + result += p("cmp", "ebx", "eax", "left " + self.op + " right") + if self.op == '==': + result += p("jne", label) # jump if false (not equal) + elif self.op == '!=': + result += p("je", label) # jump if false (equal) + elif self.op == '>': + result += p("jle", label) # jump if false (le) + elif self.op == '<': + result += p("jge", label) # jump if false (ge) + elif self.op == '>=': + result += p("jl", label) # jump if false (lt) + elif self.op == '<=': + result += p("jg", label) # jump if false (gt) + return result + + + # helper for codeGen for getting code from left and right + def codeGenLeftRight(self): + result = "" + # get left output + if not hasattr(self.left, "code"): + self.left.codeGen() + result += self.left.code + result += p("push", "eax") # left result onto stack + + # get right output + if not hasattr(self.right, "code"): + self.right.codeGen() + result += self.right.code + result += p("pop", "ebx") # left output into ebx + + return result + # returns True, False, Int or None (for non-constant expr) # children of exprNode is either exprNode or literalNode def getConstant(self): diff --git a/LineNodes.py b/LineNodes.py index 422c307b2b1984a596ca70f2d3da68a726a4e3c5..f697308d154d1325eacb7dc3734dadaf6dba5017 100644 --- a/LineNodes.py +++ b/LineNodes.py @@ -2,7 +2,7 @@ from AST import ASTNode, getParseTreeNodes, getASTNode from Environment import Env from ExprPrimaryNodes import makeNodeFromExpr, makeNodeFromAllPrimary, MethodInvNode, ClassCreateNode from TheTypeNode import TypeNode, TypeStruct -from CodeGenUtils import p +from CodeGenUtils import p, getCFlowLabel, iffalse # Contains: # block @@ -231,6 +231,38 @@ class IfNode(ASTNode): # no need to check reachability for empty elseBody, since in[elseBody] = in[L] self.outMaybe = self.ifBody.outMaybe + def codeGen(self): + if hasattr(self, "code") and self.code != "": + return + + n = getCFlowLabel() + elseLabel = "_else" + n + endLabel = "_end" + n + + self.code = "; start of if clause" + n + "\n" + + if self.elseBody: + self.code += iffalse(self.ifConditional, elseLabel) + else: + self.code += iffalse(self.ifConditional, endLabel) + + self.code += "; start of ifBody code for if clause" + n + "\n" + + self.ifBody.codeGen() + self.code += self.ifBody.code + + if self.elseBody: + self.code += "; start of elseBody code for if clause" + n + "\n" + self.code += p("jmp", endLabel) + self.code += elseLabel + ":\n" + + self.elseBody.codeGen() + self.code += self.elseBody.code + + self.code += endLabel + ":\n" + self.code += "; end of if clause" + n + "\n" + + # whileStatement, whileStatementNoShortIf # Rules: @@ -300,6 +332,7 @@ class ReturnNode(ASTNode): self.children = [] self.expr = None # could be None self.typeName = typeName + self.method = None # methodNode that this return belongs to if len(parseTree.children) == 3: self.expr = makeNodeFromExpr(parseTree.children[1], typeName) @@ -323,10 +356,14 @@ class ReturnNode(ASTNode): self.outMaybe = False # out[L] = no def codeGen(self): + if hasattr(self, "code") and self.code != "": + return + self.code = "" if self.expr: self.expr.codeGen() self.code += self.expr.code + self.code += p("jmp", self.method.label + "_end", None, "Return to the end of this method.") # forStatement and forStatementNoShortIf # Rules: diff --git a/MemberNodes.py b/MemberNodes.py index 58cd412256a5542c460f7d07223e4c8ffda03a1d..e7c13c8114c06de25639ac58367da0afcfedf29b 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -153,6 +153,7 @@ class MethodNode(ASTNode): for n in returnNodes: + n.method = self # Checking for functions of type void # Only valid if either the function doesn't have a return statement, or the return statement is a semicolon (return;) if self.myType and self.myType.name == "void": @@ -183,6 +184,7 @@ class MethodNode(ASTNode): if hasattr(self, "code") and self.code != "": return + self.label = "M_" + self.typeName + "_" + self.name + "_" + self.paramTypes self.code = pLabel(self.typeName + "_" + self.name + "_" + self.paramTypes, "method") if self.body: @@ -197,6 +199,8 @@ class MethodNode(ASTNode): self.body.codeGen() bodyCode += self.body.code + bodyCode += self.label + "_end: ; end of method for " + self.name + "\n" + # pop off all the local var for i in range(len(vars)): bodyCode += p("pop", "edx") diff --git a/Tests/A5/J1_basicTest.java b/Tests/A5/J1_01_basicTest.java similarity index 53% rename from Tests/A5/J1_basicTest.java rename to Tests/A5/J1_01_basicTest.java index 62d83f0272a10e8e7c53858de6fb243d1792228d..dd5b796567130e138dfea50ded9552ea150e5a63 100644 --- a/Tests/A5/J1_basicTest.java +++ b/Tests/A5/J1_01_basicTest.java @@ -1,9 +1,9 @@ -public class J1_basicTest { +public class J1_01_basicTest { - public J1_basicTest() {} + public J1_01_basicTest() {} public static int test() { - return J1_basicTest.test2(); + return J1_01_basicTest.test2(); } public static int test2(){ diff --git a/Tests/A5/J1_01_ifelse.java b/Tests/A5/J1_01_ifelse.java new file mode 100644 index 0000000000000000000000000000000000000000..cd3fbe7b04c1e0704acbf18dd690183ddbdbc2dc --- /dev/null +++ b/Tests/A5/J1_01_ifelse.java @@ -0,0 +1,20 @@ +public class J1_01_ifelse { + + public J1_01_ifelse() {} + + public static int test() { + return J1_01_ifelse.test2(); + } + + public static int test2(){ + int i = 2; + if (1 == 2) + i = 4; + if (i >= 1+1) { + i = 6; + } else { + i = 8; + } + return i; + } +} diff --git a/UnitNodes.py b/UnitNodes.py index b811b12b160656d4e4021db87ebac316bf361849..15b42ccf69d916eea3097c34d0d06d78477ffdba 100644 --- a/UnitNodes.py +++ b/UnitNodes.py @@ -47,6 +47,11 @@ class LiteralNode(ASTNode): # int if self.name == 'int': self.code += p("mov", "eax", str(self.getConstant()), " set to literal int") + if self.name == 'boolean': + if self.getConstant: + self.code = p("mov", "eax", "1", " set to literal true") + else: + self.code = p("mov", "eax", "0", " set to literal false") def getConstant(self): if self.name == 'int':