def test_if_gen(self): context = Context() target = context.allocate_register() e = If(EQ(Var("x"), IntConst(1)), Assign(Var("y"), Minus(Var("x"), IntConst(1))), Assign(Var("x"), IntConst(2))) e.gen(context, target) expected = """ LOAD r14,var_x LOAD r13,const_1 SUB r0,r14,r13 JUMP/PM else_1 #== LOAD r14,var_x LOAD r13,const_1 SUB r14,r14,r13 STORE r14,var_y JUMP fi_2 else_1: LOAD r14,const_2 STORE r14,var_x fi_2: const_1: DATA 1 const_2: DATA 2 var_x: DATA 0 var_y: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def gen(self, context: Context, target: str): """Code generation for a constant reference. Generates code to load the value of that constant from memory. """ context.add_line(f" LOAD {target},r0,r0[510]")
def gen(self, context: Context, target: str): """Generate code into the context object. Result of expression evaluation will be left in target register. """ label = context.get_const_symbol(self.value) context.add_line(f" LOAD {target},{label}") return
def gen(self, context: Context, target: str): """ Generate code for the lhs then rhs """ register = context.allocate_register() self.left.gen(context, target=register) self.right.gen(context, target=register) context.free_register(register)
def test_42n(self): const = IntConst(-42) context = Context() const.gen(context, "r12") expected = """ LOAD r12,const_n_42 const_n_42: DATA -42 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_var(self): var = Var("silly") context = Context() var.gen(context, "r8") expected = """ LOAD r8,var_silly var_silly: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def gen(self, context: Context, target: str): self.left.gen(context, target) pos = context.new_label("already_positive") context.add_line(f" SUB r0,{target},r0 # <Abs>") context.add_line(f" JUMP/PZ {pos}") context.add_line(f" SUB {target},r0,{target} # Flip the sign") context.add_line(f"{pos}: # </Abs>")
def test_neg_gen(self): context = Context() target = context.allocate_register() e = Neg(IntConst(8)) e.gen(context, target) expected = """ LOAD r14,const_8 SUB r14,r0,r14 # Flip the sign const_8: DATA 8 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_assign(self): context = Context() assignment = Assign(Var("universe"), IntConst(42)) assignment.gen(context, "r5") expected = """ LOAD r5,const_42 STORE r5,var_universe const_42: DATA 42 var_universe: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_div_gen(self): context = Context() target = context.allocate_register() e = Div(Var("x"), IntConst(3)) e.gen(context, target) expected = """ LOAD r14,var_x LOAD r13,const_3 DIV r14,r14,r13 const_3: DATA 3 var_x: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_abs_gen(self): context = Context() target = context.allocate_register() e = Abs(IntConst(-3)) e.gen(context, target) expected = """ LOAD r14,const_n_3 SUB r0,r14,r0 # <Abs> JUMP/PZ already_positive_1 SUB r14,r0,r14 # Flip the sign already_positive_1: # </Abs> const_n_3: DATA -3 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_LE_iffalse(self): """>=, jump if false""" context = Context() target = context.allocate_register() e = LE(IntConst(3), IntConst(5)) e.condjump(context, target, "here_if_false", jump_cond=False) expected = """ LOAD r14,const_3 LOAD r13,const_5 SUB r0,r14,r13 JUMP/P here_if_false #<= const_3: DATA 3 const_5: DATA 5 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_LT_iftrue(self): """<, jump if true""" context = Context() target = context.allocate_register() e = LT(IntConst(3), IntConst(5)) e.condjump(context, target, "here_if_true") expected = """ LOAD r14,const_3 LOAD r13,const_5 SUB r0,r14,r13 JUMP/M here_if_true #< const_3: DATA 3 const_5: DATA 5 """ generated = context.get_lines() self.codeEqual(generated, expected)
def gen(self, context: Context, target: str): """Looping""" loop_head = context.new_label("while_do") loop_exit = context.new_label("od") context.add_line(f"{loop_head}:") self.cond.condjump(context, target, loop_exit, jump_cond=False) self.expr.gen(context, target) context.add_line(f" JUMP {loop_head}") context.add_line(f"{loop_exit}:")
def gen(self, context: Context, target: str): predicate = context.new_label("if") self.cond.condjump(context, target, predicate, jump_cond=False) otherwise = context.new_label("else") context.add_line(f"{predicate}") #self.cond.gen(context, target) execute = context.new_label("fi") context.add_line(f" JUMP {execute}")
def test_while_gen(self): context = Context() target = context.allocate_register() e = While(EQ(Var("x"), Var("x")), Assign(Var("x"), Minus(Var("x"), IntConst(1)))) e.gen(context, target) expected = """ while_do_1: LOAD r14,var_x LOAD r13,var_x SUB r0,r14,r13 JUMP/PM od_2 #== LOAD r14,var_x LOAD r13,const_1 SUB r14,r14,r13 STORE r14,var_x JUMP while_do_1 od_2: const_1: DATA 1 var_x: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def gen(self, context: Context, target: str): """If""" # loop_head = context.new_label("if") # loop_else = context.new_label("else") # loop_exit = context.new_label("fi") # loop_else = context.new_label("else") loop_exit = context.new_label("fi") self.cond.condjump(context, target, loop_else, jump_cond=False) self.thenpart.gen(context, target) context.add_line(f"JUMP {loop_exit}") context.add_line(f"{loop_else}:") self.elsepart.gen(context, target) context.add_line(f"{loop_exit}:")
def test_binop_combo(self): """Combining the operations involves some register management. """ e = Plus(Times(Var("x"), Var("y")), Minus(IntConst(2), IntConst(3))) context = Context() target = context.allocate_register() e.gen(context, target) expected = """ LOAD r14,var_x LOAD r13,var_y MUL r14,r14,r13 LOAD r13,const_2 LOAD r12,const_3 SUB r13,r13,r12 ADD r14,r14,r13 const_2: DATA 2 const_3: DATA 3 var_x: DATA 0 var_y: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def test_seq(self): context = Context() assignment_1 = Assign(Var("x"), IntConst(7)) assignment_1.gen(context, "r14") assignment_2 = Assign(Var("y"), Var("x")) assignment_2.gen(context, "r14") assignment_3 = Assign(Var("z"), Var("y")) assignment_3.gen(context, "r14") expected = """ LOAD r14,const_7 STORE r14,var_x LOAD r14,var_x STORE r14,var_y LOAD r14,var_y STORE r14,var_z const_7: DATA 7 var_x: DATA 0 var_y: DATA 0 var_z: DATA 0 """ generated = context.get_lines() self.codeEqual(generated, expected)
def condjump(self, context: Context, target: str, label: str, jump_cond: bool = True): """Generate jump to label conditional on relation. """ self.left.gen(context, target) reg = context.allocate_register() self.right.gen(context, reg) if jump_cond: cond = self.cond_code_true else: cond = self.cond_code_false # All relations are implemented by subtraction. What varies is # the condition code controlling the jump. context.add_line(f" SUB r0,{target},{reg}") context.add_line(f" JUMP/{cond} {label} #{self.opsym}") context.free_register(reg)
def gen(self, context: Context, target: str): """Get value from input by loading instruction from memory address 510""" self.expr.eval() context.add_line(f" LOAD {target},r0,r0[510]")
def gen(self, context: Context, target: str): self.left.gen(context, target) context.add_line(f" SUB {target},r0,{target} # Flip the sign")
def gen(self, context: Context, target: str): self.left.gen(context, target) reg = context.allocate_register() self.right.gen(context, reg) context.add_line(f" {self._opcode()} {target},{target},{reg}") context.free_register(reg)
def gen(self, context: Context, target: str): """ Negation: subtract from 0 """ self.left.gen(context, target) context.add_line(f" SUB {target},r0,{target} # Flip the sign")
def lvalue(self, context: Context) -> str: """Return the label that the compiler will use for this variable""" return context.get_var_symbol(self.name)
def gen(self, context: Context, target: str): """Store value of expression into variable""" loc = self.left.lvalue(context) self.right.gen(context, target) context.add_line(f" STORE {target},{loc}")
def gen(self, context: Context, target: str): """We print by storing to the memory-mapped address 511""" self.expr.gen(context, target) context.add_line(f" STORE {target},r0,r0[511]")