def has_short_move(self, dsts: List[str]) -> bool: if self.array_size() < 2: return False for dst in dsts: sign, dst = separate_sign(dst) if not self._main.is_sub(dst): return False target = cast(SubsystemBase, self._main.get_instance(dst)) if not target.is_writable_array(): return False if self.array_size() < 2 or target.array_size() < 2: return False for i in range(1, min(self.array_size(), target.array_size())): if (self.addressof(str(i)) - self.addressof(str(i - 1)) != target.addressof(str(i)) - target.addressof(str(i - 1))): return False return True
def put_clear_dsts(self, out_vars: list): """clear destinations without sign.""" for out_var in out_vars: sign, addr0 = separate_sign(out_var) addr = self._main.addressof(addr0) if sign == "": self._main.put_at(addr, "[-]")
def put_short_array_move(self, dsts: List[str], copy=False): if not self.has_short_move(dsts): raise Exception(f"destination is not compatible") base = self.addressof("0") sizes = set([]) dsts2: Tuple[int, str, SubsystemBase, int] = [] for dst in dsts: sign, dst = separate_sign(dst) sub = cast(SubsystemBase, self._main.get_instance(dst)) size = min(sub.array_size(), self.array_size()) sizes |= set([size]) dsts2.append((size, sign, sub, sub.addressof("0") - base)) sizes = sorted(list(sizes)) for i, size in enumerate(sizes): base_idx = 0 if i == 0 else sizes[i - 1] size2 = size - base_idx # n = 2 # 0, v0, n -> 1, v1, n-1 -> 1, v2, n-2 -> 0 self._main.put(">" * self.offset(base_idx * 2 + 2)) self._main.put("+" * size2) self._main.put("[-[>>+<<-]<") for dst_size, sign, dst, dst_addr in dsts2: if sign == "": self._main.put_at(dst_addr, "[-]") self._main.put("[") if copy: self._main.put(">+<") for dst_size, sign, dst, dst_addr in dsts2: o = "-" if sign == "-" else "+" self._main.put_at(dst_addr, o) self._main.put("-]") if copy: self._main.put(">[<+>-]<") self._main.put(">+>>]") self._main.put("<<[-<<]") self._main.put("<" * self.offset(base_idx * 2))
def put_juggling_push(self, value: str, first=False, last=False, tmps: List[int] = None): """starts and ends at first unused value""" sign, value = separate_sign(value) if self._main.is_var(value): addr = self._main.addressof(value) tmp = -1 if sign != "-": tmp = self._main.get_nearest_tmp(tmps, [addr]) if not first: self.put_juggling_end() self._main.put_at(addr, "[") if sign != "-": self._main.put_at(tmp, "+") self._main.put_at(self.offset(), ">>[>>]<+<[<<]") self._main.put_at(addr, "-]") self._main.put_at(self.offset(), ">>[>>]+[<<]") if sign != "-": self._main.put_move(tmp, [f"+#{addr}"]) if not last: self.put_juggling_start() return if first: self.put_juggling_start() if value == "input": self._main.put(",>+>") elif self._main.is_val(value): v = self._main.valueof(value) self.put_set_char(v) self._main.put("+>") else: raise Exception(f"unknown args{value}") if last: self.put_juggling_end()
def put(self, name: str, args: List[Union[int, str]], tmps: List[int] = None): if name == "init": return if name == "clean": self.put_clean() return if name in ["@=write", "@=writeln"]: self.put("@set", args) self.put(f"@{name[2:]}", []) return if name in ["@=+write", "@=+writeln"]: self.put("@+set", args) self.put(f"@{name[3:]}", []) return if name == "@set": self.put("@clear", []) name = "@+set" if name in "@+set": self._main.put(">" * self.offset() + ">>[>]") for c in " ".join(args): self.put_set_char(ord(c)) self._main.put("<[<]<" + "<" * self.offset()) return if name == "@clear": self._main.put_at(self.offset(), ">>[>]<[[-]<]<") return if name in ["@readln", "@read"]: self.put("@clear", []) name = "@+readln" if name == "@+readln": if len(args) == 0: self._main.put_at( self.offset(), ">>[>],----------[++++++++++>,----------]<[<]<") return arg = args[0] if self._main.is_var(arg): self._main.put_at(arg, "[") self._main.put_at(self.offset(), ">>[>]>+<[<]<") self._main.put_at(arg, "-]") else: size = self._main.valueof(arg) self._main.put_at(self.offset(), ">>[>]>" + "+" * size + "<<[<]<") self._main.put_at( self.offset(), ">>[>]>[->>>+<<<<," # 255 + "+[-" # 26 + ("----- ----- ----- ----- ----- -[" + "+++++ +++++ +++++ +++++ +++++ +") + "----------[>>+>+<<<-]" # 26 + "]" # 255 + "]" + ">>[<<+>>-]>[<<<++++++++++>>>>-<[-]]>[<<<[-]>>>-]<<<[>+<-]>]<<<[<]<" ) return # uses 2 right tmp if name == "@+read": if len(args) == 0: self._main.put_at(self.offset(), ">>[>]>+<<[<]<") else: arg = args[0] if self._main.is_var(arg): self._main.put_at(arg, "[") self._main.put_at(self.offset(), ">>[>]>+<[<]<") self._main.put_at(arg, "-]") else: size = self._main.valueof(arg) self._main.put_at(self.offset(), ">>[>]>" + "+" * size + "<<[<]<") self._main.put_at(self.offset(), ">>[>]>[-[>+<-]<,>>]<<[<]<") return if name == "@write": if len(args) > 0 and args[0] == "reversed": self._main.put_at(self.offset(), ">>[>]<[.<]<") else: self._main.put_at(self.offset(), ">>[.>]<[<]<") return if name == "@writeln": if len(args) > 0 and args[0] == "reversed": self._main.put_at(self.offset(), ">>[>]<[.<]++++++++++.[-]<") else: self._main.put_at(self.offset(), ">>[.>]++++++++++.[-]<[<]<") return if name in ["@push", "@copypush"]: if len(args) == 0: raise Exception("str:@push requires 1 arg") for arg in args: if arg == "input": self._main.put_at(self.offset(), ">>[>],<<[<]<") continue if self._main.is_var(arg): addr = self._main.addressof(arg) self._main.put_at(addr, "[") if name == "@copypush": self._main.put("+") self._main.put_at(self.offset(), ">>[>]>+<<[<]<") self._main.put_at(addr, "-]") self._main.put_at(self.offset(), ">>[>]>[<+>-]<<[<]<") if name == "@copypush": self._main.put("[") self._main.put_at(addr, "+") self._main.put("-]") continue v = self._main.valueof(arg) self._main.put(">" * self.offset() + ">>[>]") self.put_set_char(v) self._main.put("<<[<]<" + "<" * self.offset()) return if name == "@pop": if len(args) == 0: self._main.put_at(self.offset(), ">>[>]<[[-]<[<]]<") return self.put_clear_dsts(args) for arg in args: sign, addr0 = separate_sign(arg) addr = self._main.addressof(addr0) self._main.put_at(self.offset(), ">>[>]<[[>+<-]>[<<[<]<+>>[>]>-]<<[<]]<") self._main.put_at(self.offset(), "[") self._main.put_at(addr, "-" if sign == "-" else "+") self._main.put_at(self.offset(), "-]") return if name == "@drop": if len(args) == 0: self._main.put_at(self.offset(), ">>[-]>[[<+>-]>]<<[<]<") return self.put_clear_dsts(args) for arg in args: sign, addr0 = separate_sign(arg) addr = self._main.addressof(addr0) self._main.put_at(self.offset(), ">>[<<+>>-]>[[<+>-]>]<<[<]<") self._main.put_at(self.offset(), "[") self._main.put_at(addr, "-" if sign == "-" else "+") self._main.put_at(self.offset(), "-]") return if name in ["@move", "@move_reversed", "@split"]: if name == "@split": args2 = args[1:] else: args2 = args for arg in args2: if not self._main.is_sub(arg, "str"): raise Exception(f"[str:{name}] takes only str") arg_str: SubsystemBase = self._main.subsystem_by_alias(arg) arg_str.put("@clear", []) name = "@+" + name[1:] if name in ["@+move", "@+move_reversed"]: ins_pop = "@drop" if name == "@+move" else "@pop" self.put(ins_pop, [0]) self._main.put("[") self._main.put("[") if len(set(args)) != len(args): raise Exception(f"[str:{name}] takes every str only once") for arg in args: if not self._main.is_sub(arg, "str"): raise Exception(f"[str:{name}] takes only str") arg_str: SubsystemBase = self._main.subsystem_by_alias(arg) if arg_str == self: raise Exception("[str:@move] can not move to the same str") self._main.put_at(arg_str.offset(), ">>[>]>+<<[<]<") self._main.put("-]") for arg in args: arg_str: SubsystemBase = self._main.subsystem_by_alias(arg) self._main.put_at(arg_str.offset(), ">>[>]>[<+>-]<[<]<") self.put(ins_pop, [0]) self._main.put("]") return if name == "@+split": sep = args[0] if not self._main.is_val(sep): raise Exception( f"first arg of [str:{name}] should be immediate") n_sep = self._main.valueof(sep) args = args[1:] for arg in args: arg_str: SubsystemBase = self._main.subsystem_by_alias(arg) arg_str.put("@clear", []) for arg in args: arg_str: SubsystemBase = self._main.subsystem_by_alias(arg) """ inc it while it clear it self:drop self:tmp_L if self:L sub self:L sep if self:L add self:L sep self:@push self:L inc it """ self._main.put("+[[-]") # safe version of self.put("@drop", [self.offset()]) self._main.put_at(self.offset(), "[-]>>[<<+>>-]>[[<+>-]>]<<[<]<") n, m = calc_small_pair(n_sep, 1) if m == 1: self._main.put_at(self.offset(), "[" + ("-" * n) + "[" + ("+" * n)) else: self._main.put_at( self.offset(), "[>" + ("+" * n) + "[<" + ("-" * m) + ">-]<[>" + ("+" * n) + "[<" + ("+" * m) + ">-]<") # safe version of arg_str.put("@push", [self.offset()]) self._main.put_at(self.offset(), "[") self._main.put_at(arg_str.offset(), ">>[>]>+<<[<]<") self._main.put_at(self.offset(), "-]") self._main.put_at(arg_str.offset(), ">>[>]>[<+>-]<<[<]<") self._main.put("+") self._main.put_at(self.offset(), "[-]]]") self._main.put("]") return if name == "@len": self.put_clear_dsts(args) self._main.put_at(self.offset(), ">>[[>]<[>+<-]<[<]<+>>]>[[<+>-]>]<<[<]<[") for arg in args: sign, addr0 = separate_sign(arg) addr = self._main.addressof(addr0) self._main.put_at(addr, "-" if sign == "-" else "+") self._main.put_at(self.offset(), "-]") return raise Exception(f"wnknown ins: {name} {args}")
def put(self, name: str, args: list, tmps: List[int] = None): if name == "init": return if name == "clean": self.put_clean() return if name == "@clear": self._main.put_at(self.offset(), ">>[>>]<<[-<[-]<]") return if name == "@calc": if len(args) == 0: return for i, arg in enumerate(args): first = i == 0 last = i + 1 == len(args) if arg in ["0dup", "0swap", "0rot", "0drop"]: pass elif arg == "swap": self.put_juggling_rot(2, 1, first=first, last=last) elif arg[1:] == "swap" and arg[0].isdigit(): self.put_juggling_rot(2, int(arg[0]), first=first, last=last) elif arg == "dup": self.put_juggling_dup(1, 1, first=first, last=last) elif arg[1:] == "dup" and arg[0].isdigit(): self.put_juggling_dup(1, int(arg[0]), first=first, last=last) elif arg == "rot": self.put_juggling_rot(3, 1, first=first, last=last) elif arg[1:] == "rot" and arg[0].isdigit(): self.put_juggling_rot(3, int(arg[0]), first=first, last=last) elif arg == "drop": self.put_juggling_pop(None, first=first, last=last) elif arg == "over": self.put_juggling_over(1, first=first, last=last) elif arg[1:] == "over" and arg[0].isdigit(): self.put_juggling_over(int(arg[0]), first=first, last=last) elif arg == "+": self.put_juggling_add(sub=False, first=first, last=last) elif arg == "-": self.put_juggling_add(sub=True, first=first, last=last) elif arg == "1+": self.put_juggling_inc(dec=False, first=first, last=last) elif arg == "1-": self.put_juggling_inc(dec=True, first=first, last=last) elif arg == ".": self.put_juggling_pop("print", first=first, last=last) elif arg == ",": self.put_juggling_push("input", first=first, last=last, tmps=tmps) elif arg.isdigit(): self.put_juggling_push(str(int(arg)), first=first, last=last, tmps=tmps) elif arg == "'": self.put_juggling_push("32", first=first, last=last) elif arg.startswith("'"): self.put_juggling_push(str(ord(arg[1])), first=first, last=last) else: raise Exception(f"[stk:calc] can not compile [{arg}]") return if name in ["@push", "@copypush"]: if len(args) == 0: raise Exception("stk:@push requires 1 arg") for i, arg in enumerate(args): self.put_juggling_push(arg, i == 0, i + 1 == len(args), tmps=tmps) return if name == "@pop": if len(args) == 0: self._main.put_at(self.offset(), ">>[>>]<<[-<[-]<[<<]]") return self.put_clear_dsts(list(filter(self._main.is_var, args))) for arg in args: if arg == "print": self._main.put_at(self.offset(), ">>[>>]<<[-<.[-]<[<<]]") continue sign, arg = separate_sign(arg) if not self._main.is_var(arg): raise Exception(f"[@pop/n] with unknown arg") addr = self._main.addressof(arg) self._main.put_at(self.offset(), ">>[>>]<<[ <[ >[<<]") self._main.put_at(addr, "-" if sign == "-" else "+") self._main.put_at(self.offset(), ">>[>>]<<<-] >-<<[<<]]") return if name == "@empty": for arg in args: sign, addr0 = separate_sign(arg) addr = self._main.addressof(addr0) self._main.put_at(addr, "[-]+") tmp = self._main.get_nearest_tmp(tmps, args) self._main.put_at(self.offset(), ">>[<<") self._main.put_at(tmp, "+") self._main.put_at(self.offset(), ">>-]<<") self._main.put_at(tmp, "[") for arg in args: sign, addr0 = separate_sign(arg) addr = self._main.addressof(addr0) self._main.put_at(addr, "-") self._main.put_at(self.offset(), ">>+<<") self._main.put_at(tmp, "-]") return if name in ["@add", "@sub"]: self.put_juggling_add(name == "@sub", first=True, last=True) return if name == "@dup": n = 1 m = 1 if len(args) > 0: if self._main.is_var(args[0]): raise Exception( f"[stk:@dup] accepts only immediates for element size") m = self._main.valueof(args[0]) if len(args) > 1: if self._main.is_var(args[1]): raise Exception( f"[stk:@dup] for dynamic range is not implemented") n = self._main.valueof(args[1]) if n <= 0 or m <= 0: return self.put_juggling_dup(n, m, first=True, last=True) return if name == "@swap": # self._main.put_at(self.offset(), ">>[>>]<<[<[>>+<<-] <<[>>+<<-] >>>>[<<<<+>>>>-] <[<<]]") # return if len(args) > 1: raise Exception(f"[stk:@swap/{len(args)}] is not implemented") name = "@rot" if len(args) == 1: args = [args[0], "2"] else: args = ["1", "2"] if name == "@rot": n = 3 m = 1 if len(args) > 0: if self._main.is_var(args[0]): raise Exception( f"[stk:@rot] accepts only immediates for element size") m = self._main.valueof(args[0]) args = args[1:] if m <= 0: return if len(args) > 0: sign, arg = separate_sign(args[0]) if self._main.is_var(arg): if self.stk_tmps_ < 4: raise Exception( f"[{self.name()}:@rot] for dynamic range requires at least 4 stack-embedded tmps" ) if m != 1: raise Exception( f"[{self.name()}:@rot] for dynamic range is implemented only for element_size=1" ) addr = self._main.addressof(arg) tmp = -1 if sign != "-": tmp = self._main.get_nearest_tmp(tmps, [addr]) self._main.put_at(addr, "[-[+ [") if sign != "-": self._main.put_at(tmp, "+") # makes: ..., 0, 0, 0, n_range self._main.put_at(self.offset(), ">>[>>]>>+<<<<[<<]") self._main.put_at(addr, "-]") # makes: ..., v[N-2], 1, v[N-1], *n_range-1, 0, 0, 0, 0 self._main.put(">" * self.offset() + ">>[>>]>>[<<<<+>>>>-]<<<<--") # makes: ..., v[N-n_range], *0, v[N-n_range+1], 1, v[N-n_range+2], 1, 0, 0, 0, 0 self._main.put("[[<<+>>-]+<<--]") # makes: ..., 0, *0, v[N-n_range+1], 1, v[N-n_range+2], 1, v[N-n_range], 0, 0, 0 self._main.put("<[>>>[>>]<+<[<<]<-]>") # makes: ..., v[N-n_range+1], 1, v[N-n_range+2], 1, v[N-n_range], 1, 0, *0 self._main.put("+[>[<<+>>-]>]") self._main.put("<<[<<]" + "<" * self.offset()) self._main.put_at(addr, "]]") if sign != "-": self._main.put_move(tmp, [f"+#{addr}"]) return if self._main.is_val(arg): n = self._main.valueof(arg) self.put_juggling_rot(n, m, first=True, last=True) return if name == "@over": if len(args) > 1: raise Exception(f"[stk:@over/{len(args)}] is not implemented") m = self._main.valueof(args[0]) if len(args) > 0 else 1 self.put_juggling_over(m, first=True, last=True) return if name in ["@inc", "@dec"]: self.put_juggling_inc(name == "@dec", first=True, last=True) return if name == "@juggle": if len(args) == 0: raise Exception(f"[stk:@juggle/0] is not implemented") self.put_juggling_juggle(args, first=True, last=True) return raise Exception(f"wnknown ins: {name} {args}")
def put(self, ins_name: str, args: list, tmps: List[int]): if ins_name == "init": return if ins_name == "clean": self.put_clean(args) return if ins_name == "@clear": self.mem2_clean(args) return if (len(args) < 2 and ins_name in [ "@set", "@w_copy", "@w_move", "@w_copy", "@w_copyadd", "@w_copysub", "@w_move", "@w_moveadd", "@w_movesub", "@r_copy", "@r_copyadd", "@r_copysub", "@r_move", "@r_moveadd", "@r_movesub" ]): raise Exception(f"error: {ins_name} {args}") # aliases if ins_name in ["@w_copy", "@w_move"]: if self._main.is_val(args[0]): ins_name = "@set" if ins_name in ["@w_copyadd", "@w_copysub"]: sign = "+" if ins_name == "@w_copyadd" else "-" ins_name = "@w_copy" args = [args[0]] + [sign + x for x in args[1:]] if ins_name in ["@w_moveadd", "@w_movesub"]: sign = "+" if ins_name == "@w_moveadd" else "-" ins_name = "@w_move" args = [args[0]] + [sign + x for x in args[1:]] if ins_name in ["@r_copyadd", "@r_copysub"]: sign = "+" if ins_name == "@r_copyadd" else "-" ins_name = "@r_copy" args = [args[0]] + [sign + x for x in args[1:]] if ins_name in ["@r_moveadd", "@r_movesub"]: sign = "+" if ins_name == "@r_moveadd" else "-" ins_name = "@r_move" args = [args[0]] + [sign + x for x in args[1:]] if ins_name == "@set": if self._main.is_var(args[0]): raise Exception("[mem:@set var ...out] is not implemented") value = self._main.valueof(args[0]) for dst in args[1:]: dst_sign, dst = separate_sign(dst) if self._main.is_val(dst): idx = self._main.valueof(dst) dst_addr = self.offset(idx * 2 + 1) self._main.put_set(value, [f"{dst_sign}#{dst_addr}"]) elif self._main.is_var(dst): dst_addr = self._main.addressof(dst) tmp = self._main.get_nearest_tmp(tmps, [self.offset()]) self._main.put_copy(dst_addr, [f"+#{self.offset(2)}"]) self._main.put(">" * self.offset()) self._main.put(""">>[[>>+<<-]+>>-]<""") self._main.put_set(value, f"{dst_sign}#0") self._main.put("""<[-<<]""") self._main.put("<" * self.offset()) return if ins_name in ["@w_move", "@w_copy"]: if not self._main.is_var(args[0]): raise Exception( f"[mem:{ins_name} val ...out] is not implemented") addr = self._main.addressof(args[0]) if ins_name == "@w_copy": self._main.put_copy(addr, [f"+#{self.offset(4)}"]) else: self._main.put_move(addr, [f"+#{self.offset(4)}"]) out_vars = args[1:] tmp = self._main.get_nearest_tmp(tmps, [addr]) for i in range(len(out_vars)): name = out_vars[i] sign, name = separate_sign(name) if self._main.is_var(name): dst_addr = self._main.addressof(name) self._main.put_copy(dst_addr, [f"+#{self.offset(2)}"]) # for next destination if i < len(out_vars) - 1: self._main.put_copy(self.offset(4), [f"+#{self.offset()}"]) self._main.put(">" * self.offset()) self._main.put(""">>[->>[>>+<<-]<<[>>+<<-]+>>]""") if sign == "": self._main.put("""<[-]>""") self._main.put(""">>[<<<""") self._main.put("-" if sign == "-" else "+") self._main.put(""">>>-]<<<<[-<<]""") self._main.put("<" * self.offset()) if i < len(out_vars) - 1: self._main.put_move(tmp, [f"+#{self.offset(4)}"]) continue if self._main.is_val(name): dst_idx = self._main.valueof(name) self._main.put_at(self.offset(4), "[") self._main.put_at(self.offset(1 + dst_idx * 2), "+") if i + 1 < len(out_vars): self._main.put_at(self.offset(2), "+") self._main.put_at(self.offset(4), "-]") if i + 1 < len(out_vars): self._main.put_move(self.offset(2), [f"+#{self.offset(4)}"]) continue return if ins_name in ["@r_move", "@r_copy"]: src = args[0] if len(list(filter(self._main.is_var, args[1:]))) != len(args[1:]): raise Exception( f"unknown instruction: [mem:{ins_name}] with non-variable destinations" ) # static addressing if self._main.is_val(src): idx = self._main.valueof(src) addr = self.offset(idx * 2 + 1) if ins_name == "@r_copy": self._main.put_copy(addr, args[1:]) else: self._main.put_move(addr, args[1:]) elif self._main.is_var(src): idx_addr = self._main.addressof(src) self._main.put_copy(idx_addr, [f"+#{self.offset(2)}"]) self._main.put(">" * self.offset()) self._main.put(""">>[[>>+<<-]+>>-]""") if ins_name == "@r_copy": self._main.put("""<[>>>+<<<-]>>>[<<+<+>>>-]<<""") else: self._main.put("""<[>+<-]>""") self._main.put("""<<[->>>>[<<+>>-]<<<<<<]>>>>[<<+>>-]<<<<""") self._main.put("<" * self.offset()) self._main.put_move(self.offset(2), args[1:]) return raise Exception(f"error unknown: {ins_name} {args}")