Exemple #1
0
def get_var_name(ins, allow_empty=False):
    """ Get variable name from token stream. """
    name = ''
    d = skip_white_read(ins).upper()
    if not d:
        pass
    elif d not in string.ascii_uppercase:
        # variable name must start with a letter
        ins.seek(-len(d), 1)
    else:
        while d and d in name_chars:
            name += d
            d = ins.read(1).upper()
        if d in '$%!#':
            name += d
        else:
            ins.seek(-len(d), 1)
    if not name and not allow_empty:
        raise error.RunError(error.STX)
    # append type specifier
    name = vartypes.complete_name(name)
    # only the first 40 chars are relevant in GW-BASIC, rest is discarded
    if len(name) > 41:
        name = name[:40] + name[-1]
    return name
Exemple #2
0
def get_var_name(ins, allow_empty=False):
    """ Get variable name from token stream. """
    name = ''
    d = skip_white_read(ins).upper()
    if not d:
        pass
    elif d not in string.ascii_uppercase:
        # variable name must start with a letter
        ins.seek(-len(d), 1)
    else:
        while d and d in name_chars:
            name += d
            d = ins.read(1).upper()
        if d in '$%!#':
            name += d
        else:
            ins.seek(-len(d), 1)
    if not name and not allow_empty:
        raise error.RunError(error.STX)
    # append type specifier
    name = vartypes.complete_name(name)
    # only the first 40 chars are relevant in GW-BASIC, rest is discarded
    if len(name) > 41:
        name = name[:40]+name[-1]
    return name
Exemple #3
0
def dim_array(name, dimensions):
    """ Allocate array space for an array of given dimensioned size. Raise errors if duplicate name or illegal index value. """
    if state.basic_state.array_base == None:
        state.basic_state.array_base = 0
    name = vartypes.complete_name(name)
    if name in state.basic_state.arrays:
        # duplicate definition
        raise error.RunError(10)
    for d in dimensions:
        if d < 0:
            # illegal function call
            raise error.RunError(5)
        elif d < state.basic_state.array_base:
            # subscript out of range
            raise error.RunError(9)
    size = array_len(dimensions)
    try:
        state.basic_state.arrays[name] = [ dimensions, bytearray(size*var_size_bytes(name)), 0 ]  
    except OverflowError:
        # out of memory
        raise error.RunError(7) 
    except MemoryError:
        # out of memory
        raise error.RunError(7) 
    # update memory model
    # first two bytes: chars of name or 0 if name is one byte long
    name_ptr = state.basic_state.array_current
    record_len = 1 + max(3, len(name)) + 3 + 2*len(dimensions)
    array_ptr = name_ptr + record_len
    state.basic_state.array_current += record_len + array_size_bytes(name)
    state.basic_state.array_memory[name] = (name_ptr, array_ptr)
Exemple #4
0
def set_var(name, value):
    """ Assign a value to a variable. """
    name = vartypes.complete_name(name)
    type_char = name[-1]
    # check if garbage needs collecting before allocating mem
    size = (max(3, len(name)) + 1 + byte_size[type_char])
    if type_char == '$':
        unpacked = vartypes.pass_string_unpack(value) 
        size += len(unpacked)
    if fre() <= size:
        # TODO: GARBTEST difference is because string literal is currently stored in string space, whereas GW stores it in code space.
        collect_garbage()
        if fre() <= size:
            raise error.RunError(7)
    # assign variables
    if type_char == '$':
        # every assignment to string leads to new pointer being allocated
        # TODO: string literals in programs have the var ptr point to program space.
        state.basic_state.variables[name] = state.basic_state.strings.store(bytearray(unpacked[:]))
    else:
        # make a copy of the value in case we want to use POKE on it - we would change both values otherwise
        # NOTE: this is an in-place copy - crucial for FOR!
        try:
            state.basic_state.variables[name][:] = vartypes.pass_type_keep(name[-1], value)[1][:]
        except KeyError:
            state.basic_state.variables[name] = vartypes.pass_type_keep(name[-1], value)[1][:]
    # update memory model
    # first two bytes: chars of name or 0 if name is one byte long
    if name not in state.basic_state.var_memory:
        name_ptr = state.basic_state.var_current
        var_ptr = name_ptr + max(3, len(name)) + 1 # byte_size first_letter second_letter_or_nul remaining_length_or_nul 
        state.basic_state.var_current += max(3, len(name)) + 1 + byte_size[name[-1]]
        state.basic_state.var_memory[name] = (name_ptr, var_ptr)
Exemple #5
0
def dim_array(name, dimensions):
    """ Allocate array space for an array of given dimensioned size. Raise errors if duplicate name or illegal index value. """
    if state.basic_state.array_base is None:
        state.basic_state.array_base = 0
    name = vartypes.complete_name(name)
    if name in state.basic_state.arrays:
        raise error.RunError(error.DUPLICATE_DEFINITION)
    for d in dimensions:
        if d < 0:
            raise error.RunError(error.IFC)
        elif d < state.basic_state.array_base:
            raise error.RunError(error.SUBSCRIPT_OUT_OF_RANGE)
    size = array_len(dimensions)
    # update memory model
    # first two bytes: chars of name or 0 if name is one byte long
    name_ptr = state.basic_state.array_current
    record_len = 1 + max(3, len(name)) + 3 + 2*len(dimensions)
    array_ptr = name_ptr + record_len
    array_bytes = size*var_size_bytes(name)
    check_free_memory(record_len + array_bytes, error.OUT_OF_MEMORY)
    state.basic_state.array_current += record_len + array_bytes
    state.basic_state.array_memory[name] = (name_ptr, array_ptr)
    try:
        state.basic_state.arrays[name] = [ dimensions, bytearray(array_bytes), 0 ]
    except OverflowError:
        # out of memory
        raise error.RunError(error.OUT_OF_MEMORY)
    except MemoryError:
        # out of memory
        raise error.RunError(error.OUT_OF_MEMORY)
Exemple #6
0
def set_scalar(name, value=None):
    """ Assign a value to a variable. """
    name = vartypes.complete_name(name)
    type_char = name[-1]
    if value is not None:
        value = vartypes.pass_type(type_char, value)
    # update memory model
    # check if garbage needs collecting before allocating memory
    if name not in state.basic_state.var_memory:
        # don't add string length, string already stored
        size = (max(3, len(name)) + 1 + vartypes.byte_size[type_char])
        check_free_memory(size, error.OUT_OF_MEMORY)
        # first two bytes: chars of name or 0 if name is one byte long
        name_ptr = state.basic_state.var_current
        # byte_size first_letter second_letter_or_nul remaining_length_or_nul
        var_ptr = name_ptr + max(3, len(name)) + 1
        state.basic_state.var_current += max(3, len(name)) + 1 + vartypes.byte_size[name[-1]]
        state.basic_state.var_memory[name] = (name_ptr, var_ptr)
    # don't change the value if just checking allocation
    if value is None:
        if name in state.basic_state.variables:
            return
        else:
            value = vartypes.null(type_char)
    # copy buffers
    try:
        # in-place copy is crucial for FOR
        state.basic_state.variables[name][:] = value[1][:]
    except KeyError:
        # copy into new buffer if not existing
        state.basic_state.variables[name] = value[1][:]
Exemple #7
0
def get_scalar(name):
    """ Retrieve the value of a scalar variable. """
    name = vartypes.complete_name(name)
    try:
        return (name[-1], state.basic_state.variables[name])
    except KeyError:
        return vartypes.null(name[-1])
Exemple #8
0
def dim_array(name, dimensions):
    """ Allocate array space for an array of given dimensioned size. Raise errors if duplicate name or illegal index value. """
    if state.basic_state.array_base is None:
        state.basic_state.array_base = 0
    name = vartypes.complete_name(name)
    if name in state.basic_state.arrays:
        raise error.RunError(error.DUPLICATE_DEFINITION)
    for d in dimensions:
        if d < 0:
            raise error.RunError(error.IFC)
        elif d < state.basic_state.array_base:
            raise error.RunError(error.SUBSCRIPT_OUT_OF_RANGE)
    size = array_len(dimensions)
    # update memory model
    # first two bytes: chars of name or 0 if name is one byte long
    name_ptr = state.basic_state.array_current
    record_len = 1 + max(3, len(name)) + 3 + 2*len(dimensions)
    array_ptr = name_ptr + record_len
    array_bytes = size*var_size_bytes(name)
    check_free_memory(record_len + array_bytes, error.OUT_OF_MEMORY)
    state.basic_state.array_current += record_len + array_bytes
    state.basic_state.array_memory[name] = (name_ptr, array_ptr)
    try:
        state.basic_state.arrays[name] = [ dimensions, bytearray(array_bytes), 0 ]
    except OverflowError:
        # out of memory
        raise error.RunError(error.OUT_OF_MEMORY)
    except MemoryError:
        # out of memory
        raise error.RunError(error.OUT_OF_MEMORY)
Exemple #9
0
def get_scalar(name):
    """ Retrieve the value of a scalar variable. """
    name = vartypes.complete_name(name)
    try:
        return (name[-1], state.basic_state.variables[name])
    except KeyError:
        return vartypes.null(name[-1])
Exemple #10
0
def set_scalar(name, value=None):
    """ Assign a value to a variable. """
    name = vartypes.complete_name(name)
    type_char = name[-1]
    if value is not None:
        value = vartypes.pass_type(type_char, value)
    # update memory model
    # check if garbage needs collecting before allocating memory
    if name not in state.basic_state.var_memory:
        # don't add string length, string already stored
        size = (max(3, len(name)) + 1 + vartypes.byte_size[type_char])
        check_free_memory(size, error.OUT_OF_MEMORY)
        # first two bytes: chars of name or 0 if name is one byte long
        name_ptr = state.basic_state.var_current
        # byte_size first_letter second_letter_or_nul remaining_length_or_nul
        var_ptr = name_ptr + max(3, len(name)) + 1
        state.basic_state.var_current += max(3, len(name)) + 1 + vartypes.byte_size[name[-1]]
        state.basic_state.var_memory[name] = (name_ptr, var_ptr)
    # don't change the value if just checking allocation
    if value is None:
        if name in state.basic_state.variables:
            return
        else:
            value = vartypes.null(type_char)
    # copy buffers
    try:
        # in-place copy is crucial for FOR
        state.basic_state.variables[name][:] = value[1][:]
    except KeyError:
        # copy into new buffer if not existing
        state.basic_state.variables[name] = value[1][:]
Exemple #11
0
def get_var(name):
    """ Retrieve the value of a variable. """
    name = vartypes.complete_name(name)
    try:
        if name[-1] == '$':
            return get_string_copy_packed(state.basic_state.variables[name])
        else:
            return (name[-1], state.basic_state.variables[name])
    except KeyError:
        return vartypes.null[name[-1]]
Exemple #12
0
def get_var(name):
    """ Retrieve the value of a variable. """
    name = vartypes.complete_name(name)
    try:
        if name[-1] == '$':
            return get_string_copy_packed(state.basic_state.variables[name])
        else:
            return (name[-1], state.basic_state.variables[name])
    except KeyError:
        return vartypes.null[name[-1]]
def varptr(name, indices):
    """Get address of variable. """
    name = vartypes.complete_name(name)
    if indices == []:
        try:
            _, var_ptr = state.basic_state.var_memory[name]
            return var_ptr
        except KeyError:
            return -1
    else:
        try:
            dimensions, _, _ = state.basic_state.arrays[name]
            _, array_ptr = state.basic_state.array_memory[name]
            # arrays are kept at the end of the var list
            return state.basic_state.var_current + array_ptr + var.var_size_bytes(name) * var.index_array(indices, dimensions) 
        except KeyError:
            return -1
Exemple #14
0
def varptr(name, indices):
    """Get address of variable. """
    name = vartypes.complete_name(name)
    if indices == []:
        try:
            _, var_ptr = state.basic_state.var_memory[name]
            return var_ptr
        except KeyError:
            return -1
    else:
        try:
            dimensions, _, _ = state.basic_state.arrays[name]
            _, array_ptr = state.basic_state.array_memory[name]
            # arrays are kept at the end of the var list
            return state.basic_state.var_current + array_ptr + var.var_size_bytes(
                name) * var.index_array(indices, dimensions)
        except KeyError:
            return -1
Exemple #15
0
def set_var(name, value):
    """ Assign a value to a variable. """
    name = vartypes.complete_name(name)
    type_char = name[-1]
    # check if garbage needs collecting before allocating mem
    size = (max(3, len(name)) + 1 + byte_size[type_char])
    if type_char == '$':
        unpacked = vartypes.pass_string_unpack(value)
        size += len(unpacked)
    if fre() <= size:
        # TODO: GARBTEST difference is because string literal is currently stored in string space, whereas GW stores it in code space.
        collect_garbage()
        if fre() <= size:
            raise error.RunError(error.OUT_OF_MEMORY)
    # assign variables
    if type_char == '$':
        # every assignment to string leads to new pointer being allocated
        # TODO: string literals in programs have the var ptr point to program space.
        state.basic_state.variables[name] = state.basic_state.strings.store(
            bytearray(unpacked[:]))
    else:
        # make a copy of the value in case we want to use POKE on it - we would change both values otherwise
        # NOTE: this is an in-place copy - crucial for FOR!
        try:
            state.basic_state.variables[name][:] = vartypes.pass_type_keep(
                name[-1], value)[1][:]
        except KeyError:
            state.basic_state.variables[name] = vartypes.pass_type_keep(
                name[-1], value)[1][:]
    # update memory model
    # first two bytes: chars of name or 0 if name is one byte long
    if name not in state.basic_state.var_memory:
        name_ptr = state.basic_state.var_current
        var_ptr = name_ptr + max(
            3, len(name)
        ) + 1  # byte_size first_letter second_letter_or_nul remaining_length_or_nul
        state.basic_state.var_current += max(
            3, len(name)) + 1 + byte_size[name[-1]]
        state.basic_state.var_memory[name] = (name_ptr, var_ptr)