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 fa09ac129cea569a7b89688837c107617110ccb2..d0474e356bca9e67d8425bf638e213000080b895 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -247,7 +247,7 @@ class AssignNode(ASTNode): def codeGen(self): self.right.codeGen() self.code = self.right.code - + if self.left.__class__.__name__ == "NameNode": if self.left.prefixLink.__class__.__name__ == "VarDclNode": # move init result to var location @@ -431,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: @@ -438,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 @@ -464,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..9141c44c4752c73eca72a10de9372e8c6573524d 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: 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':