From e0251572d862e628d2265b5f0b04be9cfb703d9f Mon Sep 17 00:00:00 2001 From: Xun Yang <x299yang@uwaterloo.ca> Date: Mon, 6 Apr 2020 14:27:57 -0400 Subject: [PATCH] ifNode and iffalse and boolean literals --- CodeGenUtils.py | 27 +++++++++++++++++- ExprPrimaryNodes.py | 57 ++++++++++++++++++++++++++++++-------- LineNodes.py | 34 ++++++++++++++++++++++- Tests/A5/J1_01_ifelse.java | 20 +++++++++++++ UnitNodes.py | 5 ++++ 5 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 Tests/A5/J1_01_ifelse.java diff --git a/CodeGenUtils.py b/CodeGenUtils.py index 03b3370..c461da7 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 fa09ac1..d0474e3 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 422c307..9141c44 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 0000000..cd3fbe7 --- /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 b811b12..15b42cc 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': -- GitLab