def get_data_memory_array(address): """ Retrieve data from data memory: array space """ name_addr = -1 arr_addr = -1 the_arr = None for name in state.basic_state.array_memory: name_try, arr_try = state.basic_state.array_memory[name] if name_try <= address and name_try > name_addr: name_addr, arr_addr = name_try, arr_try the_arr = name if the_arr is None: return -1 if address >= state.basic_state.var_current + arr_addr: offset = address - arr_addr - state.basic_state.var_current if offset >= var.array_size_bytes(the_arr): return -1 _, byte_array, _ = state.basic_state.arrays[the_arr] return byte_array[offset] else: offset = address - name_addr - state.basic_state.var_current if offset < max(3, len(the_arr)) + 1: return get_name_in_memory(the_arr, offset) else: offset -= max(3, len(the_arr)) + 1 dimensions, _, _ = state.basic_state.arrays[the_arr] data_rep = vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned( var.array_size_bytes(the_arr) + 1 + 2 * len(dimensions)) + chr(len(dimensions))) for d in dimensions: data_rep += vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned( d + 1 - state.basic_state.array_base)) return data_rep[offset]
def get_data_memory_array(address): """ Retrieve data from data memory: array space """ name_addr = -1 arr_addr = -1 the_arr = None for name in state.basic_state.array_memory: name_try, arr_try = state.basic_state.array_memory[name] if name_try <= address and name_try > name_addr: name_addr, arr_addr = name_try, arr_try the_arr = name if the_arr is None: return -1 if address >= state.basic_state.var_current + arr_addr: offset = address - arr_addr - state.basic_state.var_current if offset >= var.array_size_bytes(the_arr): return -1 _, byte_array, _ = state.basic_state.arrays[the_arr] return byte_array[offset] else: offset = address - name_addr - state.basic_state.var_current if offset < max(3, len(the_arr))+1: return get_name_in_memory(the_arr, offset) else: offset -= max(3, len(the_arr))+1 dimensions, _, _ = state.basic_state.arrays[the_arr] data_rep = vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned( var.array_size_bytes(the_arr) + 1 + 2*len(dimensions)) + chr(len(dimensions))) for d in dimensions: data_rep += vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned( d + 1 - state.basic_state.array_base)) return data_rep[offset]
def __init__(self, fhandle, filetype, number, name, mode, seg, offset, length): """ Initialise program file object and write header. """ devices.RawFile.__init__(self, fhandle, filetype, mode) self.number = number # don't lock binary files self.lock = b'' self.access = b'RW' self.seg, self.offset, self.length = 0, 0, 0 if self.mode == b'O': self.write(devices.type_to_magic[filetype]) if self.filetype == b'M': self.write( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(seg)) + vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(offset)) + vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(length))) self.seg, self.offset, self.length = seg, offset, length else: # drop magic byte self.read_raw(1) if self.filetype == b'M': self.seg = vartypes.integer_to_int_unsigned( vartypes.bytes_to_integer(self.read(2))) self.offset = vartypes.integer_to_int_unsigned( vartypes.bytes_to_integer(self.read(2))) # size gets ignored: even the \x1a at the end is read self.length = vartypes.integer_to_int_unsigned( vartypes.bytes_to_integer(self.read(2)))
def bsave(g, offset, length): """ Save a block of memory into a file. """ addr = state.basic_state.segment * 0x10 + offset g.write(str(get_memory_block(addr, length))) # Tandys repeat the header at the end of the file if tandy_syntax: g.write('\xfd' + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(state.basic_state.segment)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(offset)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(length))))
def bsave(g, offset, length): """ Save a block of memory into a file. """ addr = state.basic_state.segment * 0x10 + offset g.write(str(get_memory_block(addr, length))) # Tandys repeat the header at the end of the file if tandy_syntax: g.write('\xfd' + str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(state.basic_state.segment)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned( offset)) + vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(length))))
def rebuild_line_dict(): """ Preparse to build line number dictionary. """ state.basic_state.line_numbers, offsets = {}, [] state.basic_state.bytecode.seek(0) scanline, scanpos, last = 0, 0, 0 while True: state.basic_state.bytecode.read(1) # pass \x00 scanline = util.parse_line_number(state.basic_state.bytecode) if scanline == -1: scanline = 65536 # if parse_line_number returns -1, it leaves the stream pointer here: 00 _00_ 00 1A break state.basic_state.line_numbers[scanline] = scanpos last = scanpos util.skip_to(state.basic_state.bytecode, tk.end_line) scanpos = state.basic_state.bytecode.tell() offsets.append(scanpos) state.basic_state.line_numbers[65536] = scanpos # rebuild offsets state.basic_state.bytecode.seek(0) last = 0 for pos in offsets: state.basic_state.bytecode.read(1) state.basic_state.bytecode.write( str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(program_memory_start + pos)))) state.basic_state.bytecode.read(pos - last - 3) last = pos # ensure program is properly sealed - last offset must be 00 00. keep, but ignore, anything after. state.basic_state.bytecode.write('\0\0\0')
def tokenise_uint(ins): """ Convert an unsigned int (line number) to tokenised form. """ word = bytearray() while True: c = ins.read(1) if c and c in string.digits + ascii_whitespace: word += c else: ins.seek(-len(c), 1) break # don't claim trailing w/s while len(word) > 0 and chr(word[-1]) in ascii_whitespace: del word[-1] ins.seek(-1, 1) # remove all whitespace trimword = bytearray() for c in word: if chr(c) not in ascii_whitespace: trimword += chr(c) word = trimword # line number (jump) if len(word) > 0: if int(word) >= 65530: # note: anything >= 65530 is illegal in GW-BASIC # in loading an ASCII file, GWBASIC would interpret these as # '6553 1' etcetera, generating a syntax error on load. # keep 6553 as line number and push back the last number: ins.seek(4 - len(word), 1) word = word[:4] return str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(int(word)))) else: return ''
def tokenise_uint(ins): """ Convert an unsigned int (line number) to tokenised form. """ word = bytearray() while True: c = ins.read(1) if c and c in string.digits + ascii_whitespace: word += c else: ins.seek(-len(c), 1) break # don't claim trailing w/s while len(word)>0 and chr(word[-1]) in ascii_whitespace: del word[-1] ins.seek(-1, 1) # remove all whitespace trimword = bytearray() for c in word: if chr(c) not in ascii_whitespace: trimword += chr(c) word = trimword # line number (jump) if len(word) > 0: if int(word) >= 65530: # note: anything >= 65530 is illegal in GW-BASIC # in loading an ASCII file, GWBASIC would interpret these as # '6553 1' etcetera, generating a syntax error on load. # keep 6553 as line number and push back the last number: ins.seek(4-len(word), 1) word = word[:4] return str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(int(word)))) else: return ''
def store_line(linebuf): """ Store the given line buffer. """ if state.basic_state.protected: raise error.RunError(error.IFC) # get the new line number linebuf.seek(1) scanline = util.parse_line_number(linebuf) # check if linebuf is an empty line after the line number empty = (util.skip_white_read(linebuf) in tk.end_line) pos, afterpos, deleteable, beyond = find_pos_line_dict(scanline, scanline) if empty and not deleteable: raise error.RunError(error.UNDEFINED_LINE_NUMBER) # read the remainder of the program into a buffer to be pasted back after the write state.basic_state.bytecode.seek(afterpos) rest = state.basic_state.bytecode.read() # insert state.basic_state.bytecode.seek(pos) # write the line buffer to the program buffer length = 0 if not empty: # set offsets linebuf.seek(3) # pass \x00\xC0\xDE length = len(linebuf.getvalue()) state.basic_state.bytecode.write( '\0' + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(program_memory_start + pos + length))) + linebuf.read()) # write back the remainder of the program truncate_program(rest) # update all next offsets by shifting them by the length of the added line update_line_dict(pos, afterpos, length, deleteable, beyond) if not empty: state.basic_state.line_numbers[scanline] = pos # clear all program stacks flow.init_program() state.basic_state.last_stored = scanline
def rebuild_line_dict(): """ Preparse to build line number dictionary. """ state.basic_state.line_numbers, offsets = {}, [] state.basic_state.bytecode.seek(0) scanline, scanpos, last = 0, 0, 0 while True: state.basic_state.bytecode.read(1) # pass \x00 scanline = util.parse_line_number(state.basic_state.bytecode) if scanline == -1: scanline = 65536 # if parse_line_number returns -1, it leaves the stream pointer here: 00 _00_ 00 1A break state.basic_state.line_numbers[scanline] = scanpos last = scanpos util.skip_to(state.basic_state.bytecode, tk.end_line) scanpos = state.basic_state.bytecode.tell() offsets.append(scanpos) state.basic_state.line_numbers[65536] = scanpos # rebuild offsets state.basic_state.bytecode.seek(0) last = 0 for pos in offsets: state.basic_state.bytecode.read(1) state.basic_state.bytecode.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(program_memory_start + pos)))) state.basic_state.bytecode.read(pos - last - 3) last = pos # ensure program is properly sealed - last offset must be 00 00. keep, but ignore, anything after. state.basic_state.bytecode.write('\0\0\0')
def delete_last(self): """ Delete the string provided if it is at the top of string space. """ last_address = self.current + 1 last_key = str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(last_address))) try: length = len(self.strings[last_key]) self.current += length del self.strings[last_key] except KeyError: # happens if we're called before an out-of-memory exception is handled # and the string wasn't allocated pass
def delete_last(self): """ Delete the string provided if it is at the top of string space. """ last_address = self.current + 1 last_key = str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(last_address))) try: length = len(self.strings[last_key]) self.current += length del self.strings[last_key] except KeyError: # happens if we're called before an out-of-memory exception is handled # and the string wasn't allocated pass
def tokenise_hex(ins, outs): """ Convert hex expression in Python string to number token. """ # pass the H in &H ins.read(1) word = '' while True: c = util.peek(ins) # hex literals must not be interrupted by whitespace if not c or c not in string.hexdigits: break else: word += ins.read(1) val = int(word, 16) if word else 0 outs.write(tk.T_HEX + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(val))))
def attach_var(self, name, indices, offset, length): """ Attach a FIELD variable. """ if name[-1] != '$': # type mismatch raise error.RunError(error.TYPE_MISMATCH) if offset + length > len(self.buffer): # FIELD overflow raise error.RunError(error.FIELD_OVERFLOW) # create a string pointer str_addr = self.address + offset str_sequence = chr(length) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(str_addr)) # assign the string ptr to the variable name # desired side effect: if we re-assign this string variable through LET, it's no longer connected to the FIELD. var.set_variable(name, indices, vartypes.bytes_to_string(str_sequence))
def attach_var(self, name, indices, offset, length): """ Attach a FIELD variable. """ if name[-1] != '$': # type mismatch raise error.RunError(error.TYPE_MISMATCH) if offset + length > len(self.buffer): # FIELD overflow raise error.RunError(error.FIELD_OVERFLOW) # create a string pointer str_addr = self.address + offset str_sequence = chr(length) + vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(str_addr)) # assign the string ptr to the variable name # desired side effect: if we re-assign this string variable through LET, it's no longer connected to the FIELD. var.set_variable(name, indices, vartypes.bytes_to_string(str_sequence))
def __init__(self, fhandle, filetype, number, name, mode, seg, offset, length): """ Initialise program file object and write header. """ devices.RawFile.__init__(self, fhandle, filetype, mode) self.number = number # don't lock binary files self.lock = b'' self.access = b'RW' self.seg, self.offset, self.length = 0, 0, 0 if self.mode == b'O': self.write(devices.type_to_magic[filetype]) if self.filetype == b'M': self.write(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(seg)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(offset)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(length))) self.seg, self.offset, self.length = seg, offset, length else: # drop magic byte self.read_raw(1) if self.filetype == b'M': self.seg = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(self.read(2))) self.offset = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(self.read(2))) # size gets ignored: even the \x1a at the end is read self.length = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(self.read(2)))
def tokenise_hex(ins, outs): """ Convert hex expression in Python string to number token. """ # pass the H in &H ins.read(1) word = '' while True: c = util.peek(ins) # hex literals must not be interrupted by whitespace if not c or c not in string.hexdigits: break else: word += ins.read(1) val = int(word, 16) if word else 0 outs.write( tk.T_HEX + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(val))))
def tokenise_oct(ins, outs): """ Convert octal expression in Python string to number token. """ # O is optional, could also be &777 instead of &O777 if util.peek(ins).upper() == 'O': ins.read(1) word = '' while True: c = util.peek(ins) # oct literals may be interrupted by whitespace if c and c in number_whitespace: ins.read(1) elif not c or c not in string.octdigits: break else: word += ins.read(1) val = int(word, 8) if word else 0 outs.write(tk.T_OCT + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(val))))
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$',)) util.require_read(ins, ('(',)) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = parse_variable(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')',)) if var_ptr < 0: raise error.RunError(error.IFC) var_ptr = vartypes.int_to_integer_unsigned(var_ptr) if dollar: return state.basic_state.strings.store(chr(vartypes.byte_size[name[-1]]) + vartypes.integer_to_bytes(var_ptr)) else: return var_ptr
def tokenise_oct(ins, outs): """ Convert octal expression in Python string to number token. """ # O is optional, could also be &777 instead of &O777 if util.peek(ins).upper() == 'O': ins.read(1) word = '' while True: c = util.peek(ins) # oct literals may be interrupted by whitespace if c and c in number_whitespace: ins.read(1) elif not c or c not in string.octdigits: break else: word += ins.read(1) val = int(word, 8) if word else 0 outs.write( tk.T_OCT + str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(val))))
def store(self, in_str, address=None): """ Store a new string and return the string pointer. """ size = len(in_str) # don't store overlong strings if size > 255: raise error.RunError(error.STRING_TOO_LONG) if address is None: # reserve string space; collect garbage if necessary check_free_memory(size, error.OUT_OF_STRING_SPACE) # find new string address self.current -= size address = self.current + 1 key = str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(address))) # don't store empty strings if size > 0: if key in self.strings: logging.debug('String key %s at %d already defined.' % (repr(key), address)) # copy and convert to bytearray self.strings[key] = bytearray(in_str) return vartypes.bytes_to_string(chr(size) + key)
def update_line_dict(pos, afterpos, length, deleteable, beyond): """ Update line number dictionary after deleting lines. """ # subtract length of line we replaced length -= afterpos - pos addr = program_memory_start + afterpos state.basic_state.bytecode.seek(afterpos + length + 1) # pass \x00 while True: next_addr = state.basic_state.bytecode.read(2) if len(next_addr) < 2 or next_addr == '\0\0': break next_addr = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(next_addr)) state.basic_state.bytecode.seek(-2, 1) state.basic_state.bytecode.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(next_addr + length)))) state.basic_state.bytecode.read(next_addr - addr - 2) addr = next_addr # update line number dict for key in deleteable: del state.basic_state.line_numbers[key] for key in beyond: state.basic_state.line_numbers[key] += length
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$', )) util.require_read(ins, ('(', )) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = parse_variable(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')', )) if var_ptr < 0: raise error.RunError(error.IFC) var_ptr = vartypes.int_to_integer_unsigned(var_ptr) if dollar: return state.basic_state.strings.store( chr(vartypes.byte_size[name[-1]]) + vartypes.integer_to_bytes(var_ptr)) else: return var_ptr
def store(self, in_str, address=None): """ Store a new string and return the string pointer. """ size = len(in_str) # don't store overlong strings if size > 255: raise error.RunError(error.STRING_TOO_LONG) if address is None: # reserve string space; collect garbage if necessary check_free_memory(size, error.OUT_OF_STRING_SPACE) # find new string address self.current -= size address = self.current + 1 key = str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(address))) # don't store empty strings if size > 0: if key in self.strings: logging.debug('String key %s at %d already defined.' % (repr(key), address)) # copy and convert to bytearray self.strings[key] = bytearray(in_str) return vartypes.bytes_to_string(chr(size) + key)
def parse_literal(ins): """ Compute the value of the literal at the current code pointer. """ d = util.skip_white(ins) # string literal if d == '"': ins.read(1) if ins == state.basic_state.bytecode: address = ins.tell() + memory.code_start else: address = None output = bytearray() # while tokenised numbers inside a string literal will be printed as tokenised numbers, they don't actually execute as such: # a \00 character, even if inside a tokenised number, will break a string literal (and make the parser expect a # line number afterwards, etc. We follow this. d = ins.read(1) while d not in tk.end_line + ('"', ): output += d d = ins.read(1) if d == '\0': ins.seek(-1, 1) # store for easy retrieval, but don't reserve space in string memory return state.basic_state.strings.store(output, address) # number literals as ASCII are accepted in tokenised streams. only if they start with a figure (not & or .) # this happens e.g. after non-keywords like AS. They are not acceptable as line numbers. elif d in string.digits: outs = StringIO() representation.tokenise_number(ins, outs) outs.seek(0) return representation.parse_value(outs) # number literals elif d in tk.number: return representation.parse_value(ins) # gw-basic allows adding line numbers to numbers elif d == tk.T_UINT: return vartypes.int_to_integer_unsigned(util.parse_jumpnum(ins)) else: raise error.RunError(error.STX)
def parse_literal(ins): """ Compute the value of the literal at the current code pointer. """ d = util.skip_white(ins) # string literal if d == '"': ins.read(1) if ins == state.basic_state.bytecode: address = ins.tell() + memory.code_start else: address = None output = bytearray() # while tokenised numbers inside a string literal will be printed as tokenised numbers, they don't actually execute as such: # a \00 character, even if inside a tokenised number, will break a string literal (and make the parser expect a # line number afterwards, etc. We follow this. d = ins.read(1) while d not in tk.end_line + ('"',): output += d d = ins.read(1) if d == '\0': ins.seek(-1, 1) # store for easy retrieval, but don't reserve space in string memory return state.basic_state.strings.store(output, address) # number literals as ASCII are accepted in tokenised streams. only if they start with a figure (not & or .) # this happens e.g. after non-keywords like AS. They are not acceptable as line numbers. elif d in string.digits: outs = StringIO() representation.tokenise_number(ins, outs) outs.seek(0) return representation.parse_value(outs) # number literals elif d in tk.number: return representation.parse_value(ins) # gw-basic allows adding line numbers to numbers elif d == tk.T_UINT: return vartypes.int_to_integer_unsigned(util.parse_jumpnum(ins)) else: raise error.RunError(error.STX)
def store_line(linebuf): """ Store the given line buffer. """ if state.basic_state.protected: raise error.RunError(error.IFC) # get the new line number linebuf.seek(1) scanline = util.parse_line_number(linebuf) # check if linebuf is an empty line after the line number empty = (util.skip_white_read(linebuf) in tk.end_line) pos, afterpos, deleteable, beyond = find_pos_line_dict(scanline, scanline) if empty and not deleteable: raise error.RunError(error.UNDEFINED_LINE_NUMBER) # read the remainder of the program into a buffer to be pasted back after the write state.basic_state.bytecode.seek(afterpos) rest = state.basic_state.bytecode.read() # insert state.basic_state.bytecode.seek(pos) # write the line buffer to the program buffer length = 0 if not empty: # set offsets linebuf.seek(3) # pass \x00\xC0\xDE length = len(linebuf.getvalue()) state.basic_state.bytecode.write('\0' + str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(program_memory_start + pos + length))) + linebuf.read()) # write back the remainder of the program truncate_program(rest) # update all next offsets by shifting them by the length of the added line update_line_dict(pos, afterpos, length, deleteable, beyond) if not empty: state.basic_state.line_numbers[scanline] = pos # clear all program stacks flow.init_program() state.basic_state.last_stored = scanline
def update_line_dict(pos, afterpos, length, deleteable, beyond): """ Update line number dictionary after deleting lines. """ # subtract length of line we replaced length -= afterpos - pos addr = program_memory_start + afterpos state.basic_state.bytecode.seek(afterpos + length + 1) # pass \x00 while True: next_addr = state.basic_state.bytecode.read(2) if len(next_addr) < 2 or next_addr == '\0\0': break next_addr = vartypes.integer_to_int_unsigned( vartypes.bytes_to_integer(next_addr)) state.basic_state.bytecode.seek(-2, 1) state.basic_state.bytecode.write( str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(next_addr + length)))) state.basic_state.bytecode.read(next_addr - addr - 2) addr = next_addr # update line number dict for key in deleteable: del state.basic_state.line_numbers[key] for key in beyond: state.basic_state.line_numbers[key] += length
def sprite_size_to_record_ega(self, dx, dy): """ Write 4-byte record of sprite size in EGA modes. """ return (vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dx)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dy)))
def number_xor(left, right): """ Bitwise XOR. """ return vartypes.int_to_integer_unsigned( vartypes.integer_to_int_unsigned(vartypes.pass_integer(left)) ^ vartypes.integer_to_int_unsigned(vartypes.pass_integer(right)))
def number_and(left, right): """ Bitwise AND. """ return vartypes.int_to_integer_unsigned( vartypes.integer_to_int_unsigned(vartypes.pass_integer(left)) & vartypes.integer_to_int_unsigned(vartypes.pass_integer(right)))
def number_eqv(left, right): """ Bitwise equivalence. """ return vartypes.int_to_integer_unsigned(0xffff-( vartypes.integer_to_int_unsigned(vartypes.pass_integer(left)) ^ vartypes.integer_to_int_unsigned(vartypes.pass_integer(right))))
def sprite_size_to_record(self, dx, dy): """ Write 4-byte record of sprite size. """ return ( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(dx * self.bitsperpixel)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dy)))
def renum(new_line, start_line, step): """ Renumber stored program. """ new_line = 10 if new_line is None else new_line start_line = 0 if start_line is None else start_line step = 10 if step is None else step # get a sorted list of line numbers keys = sorted([ k for k in state.basic_state.line_numbers.keys() if k >= start_line]) # assign the new numbers old_to_new = {} for old_line in keys: if old_line < 65535 and new_line > 65529: raise error.RunError(error.IFC) if old_line == 65536: break old_to_new[old_line] = new_line state.basic_state.last_stored = new_line new_line += step # write the new numbers for old_line in old_to_new: state.basic_state.bytecode.seek(state.basic_state.line_numbers[old_line]) # skip the \x00\xC0\xDE & overwrite line number state.basic_state.bytecode.read(3) state.basic_state.bytecode.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(old_to_new[old_line])))) # write the indirect line numbers ins = state.basic_state.bytecode ins.seek(0) while util.skip_to_read(ins, (tk.T_UINT,)) == tk.T_UINT: # get the old g number jumpnum = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(ins.read(2))) # handle exception for ERROR GOTO if jumpnum == 0: pos = ins.tell() # skip line number token ins.seek(-3, 1) if util.backskip_white(ins) == tk.GOTO and util.backskip_white(ins) == tk.ERROR: ins.seek(pos) continue ins.seek(pos) try: newjump = old_to_new[jumpnum] except KeyError: # not redefined, exists in program? if jumpnum not in state.basic_state.line_numbers: linum = get_line_number(ins.tell()-1) console.write_line('Undefined line ' + str(jumpnum) + ' in ' + str(linum)) newjump = jumpnum ins.seek(-2, 1) ins.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(newjump)))) # rebuild the line number dictionary new_lines = {} for old_line in old_to_new: new_lines[old_to_new[old_line]] = state.basic_state.line_numbers[old_line] del state.basic_state.line_numbers[old_line] state.basic_state.line_numbers.update(new_lines) # stop running if we were flow.set_pointer(False) # reset loop stacks state.basic_state.gosub_return = [] state.basic_state.for_next_stack = [] state.basic_state.while_wend_stack = [] # renumber error handler if state.basic_state.on_error: state.basic_state.on_error = old_to_new[state.basic_state.on_error] # renumber event traps for handler in state.basic_state.events.all: if handler.gosub: handler.set_jump(old_to_new[handler.gosub])
def number_imp(left, right): """ Bitwise implication. """ return vartypes.int_to_integer_unsigned( (0xffff-vartypes.integer_to_int_unsigned(vartypes.pass_integer(left))) | vartypes.integer_to_int_unsigned(vartypes.pass_integer(right)))
def sprite_size_to_record_ega(self, dx, dy): """ Write 4-byte record of sprite size in EGA modes. """ return (vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dx)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dy)))
def sprite_size_to_record(self, dx, dy): """ Write 4-byte record of sprite size. """ return (vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dx*self.bitsperpixel)) + vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(dy)))
def renum(new_line, start_line, step): """ Renumber stored program. """ new_line = 10 if new_line is None else new_line start_line = 0 if start_line is None else start_line step = 10 if step is None else step # get a sorted list of line numbers keys = sorted( [k for k in state.basic_state.line_numbers.keys() if k >= start_line]) # assign the new numbers old_to_new = {} for old_line in keys: if old_line < 65535 and new_line > 65529: raise error.RunError(error.IFC) if old_line == 65536: break old_to_new[old_line] = new_line state.basic_state.last_stored = new_line new_line += step # write the new numbers for old_line in old_to_new: state.basic_state.bytecode.seek( state.basic_state.line_numbers[old_line]) # skip the \x00\xC0\xDE & overwrite line number state.basic_state.bytecode.read(3) state.basic_state.bytecode.write( str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(old_to_new[old_line])))) # write the indirect line numbers ins = state.basic_state.bytecode ins.seek(0) while util.skip_to_read(ins, (tk.T_UINT, )) == tk.T_UINT: # get the old g number jumpnum = vartypes.integer_to_int_unsigned( vartypes.bytes_to_integer(ins.read(2))) # handle exception for ERROR GOTO if jumpnum == 0: pos = ins.tell() # skip line number token ins.seek(-3, 1) if util.backskip_white(ins) == tk.GOTO and util.backskip_white( ins) == tk.ERROR: ins.seek(pos) continue ins.seek(pos) try: newjump = old_to_new[jumpnum] except KeyError: # not redefined, exists in program? if jumpnum not in state.basic_state.line_numbers: linum = get_line_number(ins.tell() - 1) console.write_line('Undefined line ' + str(jumpnum) + ' in ' + str(linum)) newjump = jumpnum ins.seek(-2, 1) ins.write( str( vartypes.integer_to_bytes( vartypes.int_to_integer_unsigned(newjump)))) # rebuild the line number dictionary new_lines = {} for old_line in old_to_new: new_lines[ old_to_new[old_line]] = state.basic_state.line_numbers[old_line] del state.basic_state.line_numbers[old_line] state.basic_state.line_numbers.update(new_lines) # stop running if we were flow.set_pointer(False) # reset loop stacks state.basic_state.gosub_return = [] state.basic_state.for_next_stack = [] state.basic_state.while_wend_stack = [] # renumber error handler if state.basic_state.on_error: state.basic_state.on_error = old_to_new[state.basic_state.on_error] # renumber event traps for handler in state.basic_state.events.all: if handler.gosub: handler.set_jump(old_to_new[handler.gosub])