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 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 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 less_eq(self, left, right, label): if is_number(left) and is_number(right): if left <= right: self.push('JUMP lbl'.format(lbl=label)) return l_reg = self.loaddd(left, 2) r_reg = self.loaddd(right, 3) self.push('SUB {l} {r}'.format(l=l_reg, r=r_reg)) self.push('JZERO {l} {lb}'.format(l=l_reg, lb=label))
def check_scope(self, operand): if is_number(operand): pass elif is_int(operand): if operand[1] not in self.scope: raise_error(msg="Undeclared variable {}".format(operand[1]), lineno=operand[2]) elif is_array(operand): if is_number(operand[2]): self.check_inttab(operand) else: raise CompilerError("Unexpected operand")
def flow_if_then(self, cmd): _, cond, if_true = cmd _, cond_symb, left, right = cond if is_number(left) and is_number(right): if not self.eval_cond(cond_symb, left, right): return label_false = self.next_label() self.flow += self.add_goto_if(self.neg(cond), label_false) self.generate(if_true) self.flow += ('label', label_false),
def flow_while(self, cmd): _, cond, body = cmd _, cond_symb, left, right = cond if is_number(left) and is_number(right): if not self.eval_cond(cond_symb, left, right): return label_start, label_end = self.next_label(2) self.flow += self.add_label(label_start) self.flow += self.add_goto_if(self.neg(cond), label_end) self.generate(body) self.flow += self.add_goto(label_start) self.flow += self.add_label(label_end)
def store_arr(self, iden_arr, val_reg): _, name, inner, _ = iden_arr if is_number(inner): offset = inner + self.arr_offset(iden_arr) self.gen_number(offset) self.push('STORE {}'.format(val_reg)) return 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_arr) self.gen_number(offset, 0) self.push(''' ADD 0 1 STORE {} '''.format(val_reg)) return else: offset = self.arr_offset(iden_arr) self.gen_number(offset, 0) self.push(''' ADD {} {} STORE {} '''.format(0, inner_reg, val_reg)) return
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 flow_if_else(self, cmd): _, cond, if_true, if_false = cmd _, cond_symb, left, right = cond label_false, label_end = self.next_label(), self.next_label() if is_number(left) and is_number(right): if not self.eval_cond(cond_symb, left, right): self.generate(if_false) return self.flow += self.add_goto_if(self.neg(cond), label_false) self.generate(if_true) self.flow += self.add_goto(label_end) self.flow += self.add_label(label_false) self.generate(if_false) self.flow += self.add_label(label_end)
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 eq(self, left, right, label): if is_number(left) and is_number(right): if left == right: self.push('JUMP {}'.format(label)) else: return l_reg = self.loaddd(left, 2) r_reg = self.loaddd(right, 3) self.push(''' COPY 0 {l} COPY 1 {r} SUB 0 {r} JZERO 0 ${sub} JUMP ${end} SUB 1 {l} JZERO 1 {lbl} '''.format(l=l_reg, r=r_reg, lbl=label, end=3, sub=2))
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 flow_for_down(self, cmd): _, iterator, start, end, body = cmd if is_number(start) and is_number(end): if start < end: return limit = (iterator[0], '#' + iterator[1], iterator[2]) label_start, label_end = self.next_label(2) self.flow += ('assign', iterator, ('expression', start)), self.flow += ('assign', limit, ('expression', end)), self.flow += self.add_goto_if((iterator, '<', limit), label_end) self.flow += self.add_label(label_start) self.generate(body) self.flow += self.add_goto_if((iterator, '<=', limit), label_end) self.flow += ('assign', iterator, ('expression', '-', iterator, 1)), self.flow += self.add_goto(label_start) self.flow += self.add_label(label_end)
def check_inttab(self, variable): _, symbol, index, lineno = variable arr_start = '#'.join([symbol, '0']) if arr_start not in self.scope: raise_error("Usage of undeclared array {}".format(symbol), lineno) if is_number(index): self.check_inttab_index(variable) elif is_int(index): self.check_variable(index) else: raise CompilerError("Unexpected array index")
def read_array(self, iden): _, name, sub_iden, _ = iden if is_number(sub_iden): offset = sub_iden + self.arr_offset(iden) self.gen_number(offset) self.push(''' GET {} STORE {} '''.format(1, 1)) elif is_declared_var(sub_iden, self.symtab): offset = self.arr_offset(iden) self.gen_number(offset, 2) inner_reg = self.loaddd(sub_iden, 3) self.push(''' SUB 0 0 ADD 0 2 ADD 0 3 GET 1 STORE 1 ''')
def write_arr(self, iden): _, name, inner, _ = iden if is_number(inner): offset = inner + self.arr_offset(iden) self.gen_number(offset) self.push(''' LOAD {} PUT {} '''.format(1, 1)) return elif is_declared_var(inner, self.symtab): self.loaddd(inner, 2) offset = self.arr_offset(iden) self.gen_number(offset, 3) self.push(''' SUB 0 0 ADD 0 2 ADD 0 3 LOAD 1 PUT 1 ''')
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 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)