Exemple #1
0
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]
Exemple #2
0
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]
Exemple #3
0
 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)))
Exemple #4
0
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))))
Exemple #5
0
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))))
Exemple #6
0
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')
Exemple #7
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 ''
Exemple #8
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 ''
Exemple #9
0
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
Exemple #10
0
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')
Exemple #11
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
Exemple #12
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
Exemple #13
0
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))))
Exemple #14
0
 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))
Exemple #15
0
 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))
Exemple #16
0
 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)))
Exemple #17
0
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))))
Exemple #18
0
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))))
Exemple #19
0
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
Exemple #20
0
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))))
Exemple #21
0
 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)
Exemple #22
0
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
Exemple #23
0
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
Exemple #24
0
 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)
Exemple #25
0
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)
Exemple #26
0
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)
Exemple #27
0
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
Exemple #28
0
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
Exemple #29
0
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)))
Exemple #30
0
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)))
Exemple #31
0
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)))
Exemple #32
0
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))))
Exemple #33
0
 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)))
Exemple #34
0
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])
Exemple #35
0
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)))
Exemple #36
0
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)))
Exemple #37
0
 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)))
Exemple #38
0
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])