def operation_substract(self, target, operands): x, y = operands if is_number(x): # t := 1 - 1 if is_number(y): if x - y > 0: self.parse('GENERATE n', n=x - y) else: self.parse('ZERO') # t := 1 - a # t := 1 - a[x] elif is_variable(y): self.parse('GENERATE n', n=x) self.parse('SUB a', a=y) elif is_variable(x): # t := a - 1 if is_number(y): if y == 0: self.parse('LOAD a', a=x) elif y == 1: self.parse('LOAD a', a=x) self.parse('DEC') else: self.parse('GENERATE n', n=y) self.parse('STORE a', a=Reg.r0) self.parse('LOAD x', x=x) self.parse('SUB a', a=Reg.r0) # t := a - b # t := a - b[x] elif is_variable(y): self.parse('LOAD a', a=x) self.parse('SUB a', a=y) else: raise CompilerError("Unexpected symbol") self.parse('STORE a', a=target)
def check_expression(self, cmd): _, *expression = cmd if len(expression) == 1: [var] = expression if is_variable(var): self.check_variable(var) self.check_initialized(var) elif len(expression) == 3: [_, l_var, r_var] = expression for var in [l_var, r_var]: if is_variable(var): self.check_variable(var) self.check_initialized(var) else: raise CompilerError("Unexpected expression")
def comp_gt(self, cond, label): left, _, right = cond code = "" if is_number(left) and is_number(right): if left > right: self.parse('JUMP @label', label=label) return if is_number(left) and left == 0: return if is_number(right): if right == 0: code = """ JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, label=label) return if is_number(right): code += """ GENERATE r_val STORE right """ if is_number(left): code += """ GENERATE l_val """ else: code += """ LOAD left """ code += """ SUB right JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, l_val=left, r_val=right, left=left if is_variable(left) else Reg.r0, right=right if is_variable(right) else Reg.r1, label=label)
def operation_add(self, target, operands): x, y = operands if is_array(x) and is_array(y): pass if is_number(x): if is_number(y): self.parse('GENERATE n', n=x + y) self.parse('STORE t', t=target) return else: x, y = y, x # t := a + 1 if is_number(y): if y == 0: self.parse('LOAD x', x=x) elif y == 1: self.parse('LOAD x', x=x) self.parse('INC') else: self.parse('GENERATE n', n=y) self.parse('ADD x', x=x) # t := a + b # t := a + b[x] elif is_variable(y): self.parse('LOAD x', x=x) self.parse('ADD y', y=y) else: raise CompilerError("Unexpected symbol") self.parse('STORE a', a=target)
def assign_mul(self, trg_iden, left, right): res_reg = 4 l_reg = self.loaddd(left, 2) r_reg = self.loaddd(right, 3) code = ''' SUB {res} {res} JZERO {r} ${end} JODD {l} ${add} JUMP ${half} ADD {res} {r} HALF {l} ADD {r} {r} JUMP ${jzero} '''.format(res=res_reg, r=r_reg, l=l_reg, add=2, half=2, end=7, jzero=(-6)) self.push(code) if is_arr(trg_iden): self.store_arr(trg_iden, res_reg) elif is_variable(trg_iden): self.store_var(trg_iden, res_reg)
def gen_write(self, node): _, iden = node if is_variable(iden): self.write_variable(iden) elif is_number(iden): self.write_number(iden) elif is_arr(iden): self.write_arr(iden)
def check_for_up(self, cmd): _, iterator, start, end, cmds = cmd for el in [v for v in [start, end] if is_variable(v)]: if is_variable(el): self.check_variable(el) self.check_initialized(el) self.check_iterator(iterator) _, iter_symbol, iter_lineno = iterator self.add_iterator(iter_symbol) self.initialized[iter_symbol] = True self.analyze(cmds) self.initialized[iter_symbol] = False self.remove_from_scope(iter_symbol)
def loadd(self, var): if is_number(var): reg = self.get_free_reg() self.gen_number(var, reg) return reg elif is_variable(var): reg = self.check_in_regs(var[1]) if not reg: reg = self.load(var) return reg
def reserve_memory(self, symtab): for iden in symtab: if is_variable(iden): self.memory[iden[1]] = self.mem_id self.mem_id += 1 for iden in symtab: if is_arr(iden): self.memory[iden[1]] = self.mem_id self.mem_id += iden[3] - iden[2] + 1
def load(self, iden): if is_variable(iden): pos_in_mem = self.memory[iden[1]] self.gen_number(pos_in_mem) dst_reg = self.get_reg(iden[1]) self.push('LOAD reg', reg=dst_reg) self.regs[dst_reg] = iden[1] return dst_reg else: pass
def loaddd(self, iden, trg_reg): if is_number(iden): self.gen_number(iden, trg_reg) return trg_reg elif is_variable(iden): iden_reg = self.check_in_regs(iden[1]) if not iden_reg: iden_mem_id = self.memory[iden[1]] self.gen_number(iden_mem_id) self.push('LOAD {}'.format(trg_reg)) else: self.push('COPY {} {}'.format(trg_reg, iden_reg)) return trg_reg elif is_arr(iden): _, name, inner, _ = iden if is_number(inner): offset = inner + self.arr_offset(iden) self.gen_number(offset) self.push('LOAD {}'.format(trg_reg)) return trg_reg elif is_declared_var(inner, self.symtab): inner_reg = self.check_in_regs(inner) if not inner_reg: inner_mem_id = self.memory[inner] self.gen_number(inner_mem_id, 0) self.push(''' LOAD 1 ''') offset = self.arr_offset(iden) self.gen_number(offset, 0) self.push(''' ADD 0 1 LOAD {} '''.format(trg_reg)) return trg_reg else: offset = self.arr_offset(iden) self.gen_number(offset, 0) self.push(''' ADD {} {} LOAD {} '''.format(0, inner_reg, trg_reg)) return trg_reg elif is_declared_var(iden, self.symtab): iden_reg = self.check_in_regs(iden) if not iden_reg: iden_mem_id = self.memory[iden] self.gen_number(iden_mem_id) self.push('LOAD {}'.format(trg_reg)) else: self.push('COPY {} {}'.format(trg_reg, iden_reg)) return trg_reg pass
def assign(self, target, expression): _, *value = expression if is_operation(value): self.assign_operation(target, value) else: if is_variable(value[0]): self.assign_variable(target, value[0]) elif is_number(value[0]): self.assign_number(target, value[0]) else: raise CompilerError("Unknown value type")
def assign_minus(self, trg_iden, left, right): l_reg = self.loaddd(left, 2) r_reg = self.loaddd(right, 3) self.push(''' SUB {l} {r} '''.format(l=l_reg, r=r_reg)) if is_arr(trg_iden): self.store_arr(trg_iden, l_reg) elif is_variable(trg_iden): self.store_var(trg_iden, l_reg)
def comp_geq(self, cond, label): left, _, right = cond if is_number(right) and right == 0: self.parse("JUMP @label", label=label) return code = "" if is_number(right): code += """ GENERATE r_val STORE right """ if is_number(left): code += """ GENERATE l_val """ else: code += """ LOAD left """ code += """ INC SUB right JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, l_val=left, r_val=right, left=left if is_variable(left) else Reg.r0, right=right if is_variable(right) else Reg.r1, label=label)
def assign_mod(self, trg_iden, left, right): l_reg = self.loaddd(left, 2) r_reg = self.loaddd(right, 3) res_reg = 4 divide = ''' COPY {res} {l} JZERO {r} ${end} COPY 1 {r} COPY {res} 1 SUB {res} {l} JZERO {res} ${body} JUMP ${out} ADD 1 1 JUMP ${loop} SUB {res} {res} COPY 0 1 SUB 0 {l} JZERO 0 ${add} ADD {res} {res} HALF 1 JUMP ${check} ADD {res} {res} INC {res} SUB {l} 1 HALF 1 COPY 0 {r} SUB 0 1 JZERO 0 ${loop2} JUMP ${out2} SUB {l} {l} SUB {res} {res} '''.format(res=res_reg, l=l_reg, r=r_reg, end=23, body=2, out=3, loop=-5, add=4, check=5, loop2=-12, out2=3) self.push(divide) if is_arr(trg_iden): self.store_arr(trg_iden, l_reg) elif is_variable(trg_iden): self.store_var(trg_iden, l_reg)
def parse_array(self, left, right): _, var, index, *_ = right if is_number(index): array = self.mem['{}#0'.format(var)] arr_addr = array['address'] cell_addr = index + arr_addr code = '{cmd} {param}'.format(cmd=left, param=cell_addr) self.code.append(code) elif is_reg(index): self.code.append('{cmd}I {reg}'.format(cmd=left, reg=index[1])) elif is_variable(index): left += 'I' array = self.mem['{}#0'.format(var)] arr_start_ptr = array['start_ptr'] if left == 'LOADI': self.code.append( 'LOAD {arr_start_ptr}'.format(arr_start_ptr=arr_start_ptr)) code = """ ADD x STORE r9 LOADI r9 """ self.parse(code, x=index, r9=Reg.r9) elif left in ['STOREI', 'ADDI', 'SUBI']: self.parse(""" STORE r8 """, r8=Reg.r8) self.code.append( 'LOAD {arr_start_ptr}'.format(arr_start_ptr=arr_start_ptr)) code = """ADD x STORE r9 LOAD r8 {cmd} r9 """.format(cmd=left, arr_size=arr_start_ptr) self.parse(code, x=index, r9=Reg.r9, r8=Reg.r8) else: raise CompilerError("Unexpected command")
def comp_neq(self, cond, label): left, _, right = cond if is_number(left) and is_number(right): if left == right: return else: self.parse('JUMP @label', label=label) return if is_number(right): right, left = left, right if is_number(left) and left == 0: code = """ LOAD a JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, a=right, label=label) return if is_number(left) and left == 1: code = """ LOAD a JZERO @label DEC JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, a=right, label=label) return code = "" if is_number(left): code += """ GENERATE l_val STORE left """ if is_number(right): code += """ GENERATE r_val STORE right """ code += """ LOAD left SUB right JZERO #FALSE1 JUMP @label #FALSE1: LOAD right SUB left JZERO #FALSE JUMP @label #FALSE: """ self.parse(code, l_val=left, r_val=right, left=left if is_variable(left) else Reg.r0, right=right if is_variable(right) else Reg.r1, label=label)
def read(self, target): if is_variable(target): self.read_variable(target) else: raise CompilerError("Cannot READ non-variable")
def write(self, value): if is_variable(value): self.write_variable(value) else: self.write_number(value)
def operation_divmod(self, target, operands, division=True): [left, right] = operands if is_number(left) and is_number(right): if division: self.parse('GENERATE n', n=0 if right == 0 else left // right) else: self.parse('GENERATE n', n=0 if right == 0 else left % right) self.parse('STORE t', t=target) return # TODO: mul two times ? # 0 -> r2 code = """ ZERO STORE r2 """ # x -> r0 code += """ GENERATE l_val """ if is_number(left) else """ LOAD left """ code += """ STORE r0 JZERO #END """ # y -> r1, r3 code += """ GENERATE r_val """ if is_number(right) else """ LOAD right """ code += """ JZERO #END STORE r1 """ code += """ STORE r3 """ if is_number(right) else "" code += """ JUMP #FIRST_SHIFT #SHIFT: LOAD r1 #FIRST_SHIFT: SHL STORE r1 SHL DEC SUB r0 JZERO #SHIFT LOAD r1 """ code += """ #LOOP: INC SUB {const_addr} JZERO #END """.format(const_addr='r3' if is_number(right) else 'right') code += """ LOAD r1 SUB r0 JZERO #ADD #NO_ADD: LOAD r2 SHL STORE r2 LOAD r1 SHR STORE r1 JUMP #LOOP #ADD: LOAD r2 SHL INC STORE r2 LOAD r0 SUB r1 STORE r0 LOAD r1 SHR STORE r1 JUMP #LOOP #END: LOAD {target_reg} STORE target """.format(target_reg='r2' if division else 'r0') self.parse(code, l_val=left, r_val=right, left=left if is_variable(left) else Reg.r4, right=right if is_variable(right) else Reg.r5, target=target, r0=Reg.r0, r1=Reg.r1, r2=Reg.r2, r3=Reg.r3)
def operation_modulo(self, target, operands): [left, right] = operands if is_number(left) and is_number(right): self.parse('GENERATE n', n=0 if right == 0 else left % right) self.parse('STORE t', t=target) return code = '' # 0 -> r2 code += """ ZERO STORE r2 """ # x -> r0 code += """ GENERATE l_val """ if is_number(left) else """ LOAD left """ code += """ STORE r0 JZERO #END """ # y -> r1, r3 code += """ GENERATE r_val """ if is_number(right) else '' code += """ LOAD right """ if not is_number(right) and right != left else '' code += """ JZERO #END_RIGHT STORE r1 """ code += """ STORE r3 """ if is_number(right) else "" code += """ JUMP #FIRST_SHIFT #SHIFT: LOAD r1 #FIRST_SHIFT: SHL STORE r1 SHL DEC SUB r0 JZERO #SHIFT LOAD r1 """ code += """ #LOOP: INC SUB {const_addr} JZERO #END """.format( const_addr='r3' if is_number(right) else 'right') code += """ LOAD r1 SUB r0 JZERO #ADD #NO_ADD: LOAD r2 SHL STORE r2 LOAD r1 SHR STORE r1 JUMP #LOOP #ADD: LOAD r2 SHL INC STORE r2 LOAD r0 SUB r1 STORE r0 LOAD r1 SHR STORE r1 JUMP #LOOP #END_RIGHT: ZERO STORE target JUMP #FINISH #END: LOAD {target_reg} STORE target #FINISH: """.format(target_reg='r0') self.parse(code, l_val=left, r_val=right, left=left if is_variable(left) else Reg.r4, right=right if is_variable(right) else Reg.r5, target=target, r0=Reg.r0, r1=Reg.r1, r2=Reg.r2, r3=Reg.r3)
def operation_multiply(self, target, operands): [left, right] = operands if is_number(right): left, right = right, left if is_number(left) and is_number(right): self.parse('GENERATE n', n=left * right) self.parse('STORE t', t=target) return if is_number(left): if left % 2 == 0 and float(int(log(left, 2))) == log(left, 2): count = int(sqrt(left)) code = """ LOAD right """ for _ in range(count): code += """ SHL """ code += """ STORE target """ self.parse(code, right=right, target=target) return elif left == 1 and target != left: code = """ LOAD right STORE target """ self.parse(code, right=right, target=target) return elif target == right and left == 1: return code = "" if is_number(left) and is_number(right): if right > left: left, right = right, left if is_number(left): code += """ GENERATE l_val STORE left """ if is_number(right): code += """ GENERATE r_val STORE right """ code += """ ZERO STORE r2 """ code += """ LOAD left SUB right JZERO #RIGHT_BIGGER #LEFT_BIGGER: LOAD left STORE r0 LOAD right STORE r1 JUMP #START #RIGHT_BIGGER:""" if left != right and not ( is_number(left) and is_number(right)) else '' code += """ LOAD right STORE r0 LOAD left STORE r1 #START: JZERO #END JODD #IS_ODD JUMP #NOT_ODD #IS_ODD: LOAD r2 ADD r0 STORE r2 #NOT_ODD: LOAD r0 SHL STORE r0 LOAD r1 SHR STORE r1 JUMP #START #END: LOAD r2 STORE target """ self.parse(code, l_val=left, r_val=right, r0=Reg.r0, r1=Reg.r1, r2=Reg.r2, left=left if is_variable(left) else Reg.r4, right=right if is_variable(right) else Reg.r5, target=target)
def check_condition(self, condition): *_, left_op, right_op = condition for operand in [left_op, right_op]: if is_variable(operand): self.check_variable(operand) self.check_initialized(operand)
def gen_read(self, node): _, iden = node if is_variable(iden): self.read_variable(iden) elif is_arr(iden): self.read_array(iden)
def check_write(self, cmd): _, operand = cmd if is_variable(operand): self.check_variable(operand) self.check_initialized(operand)