示例#1
0
def parse_variable(ins):
    """ Helper function: parse a variable or array element. """
    name = util.parse_scalar(ins)
    indices = []
    if util.skip_white_read_if(ins, ('[', '(')):
        # it's an array, read indices
        while True:
            indices.append(vartypes.pass_int_unpack(parse_expression(ins)))
            if not util.skip_white_read_if(ins, (',',)):
                break
        util.require_read(ins, (']', ')'))
    return name, indices
示例#2
0
def value_erdev(ins):
    """ ERDEV$: device error string; not implemented. """
    logging.warning("ERDEV or ERDEV$ function not implemented.")
    if util.skip_white_read_if(ins, ('$',)):
        return vartypes.null('$')
    else:
        return vartypes.null('%')
示例#3
0
def value_point(ins):
    """ POINT: get pixel attribute at screen location. """
    util.require_read(ins, ('(',))
    arg0 = parse_expression(ins)
    screen = state.console_state.screen
    if util.skip_white_read_if(ins, (',',)):
        # two-argument mode
        arg1 = parse_expression(ins)
        util.require_read(ins, (')',))
        if screen.mode.is_text_mode:
            raise error.RunError(error.IFC)
        return vartypes.int_to_integer_signed(screen.drawing.point(
                        (fp.unpack(vartypes.pass_single(arg0)),
                         fp.unpack(vartypes.pass_single(arg1)), False)))
    else:
        # single-argument mode
        util.require_read(ins, (')',))
        try:
            x, y = screen.drawing.last_point
            fn = vartypes.pass_int_unpack(arg0)
            if fn == 0:
                return vartypes.int_to_integer_signed(x)
            elif fn == 1:
                return vartypes.int_to_integer_signed(y)
            elif fn == 2:
                fx, _ = screen.drawing.get_window_logical(x, y)
                return fp.pack(fx)
            elif fn == 3:
                _, fy = screen.drawing.get_window_logical(x, y)
                return fp.pack(fy)
        except AttributeError:
            return vartypes.null('%')
示例#4
0
def value_fn(ins):
    """ FN: get value of user-defined function. """
    fnname = util.get_var_name(ins)
    try:
        varnames, fncode = state.basic_state.functions[fnname]
    except KeyError:
        raise error.RunError(error.UNDEFINED_USER_FUNCTION)
    # save existing vars
    varsave = {}
    for name in varnames:
        if name in state.basic_state.variables:
            # copy the *value* - set_var is in-place it's safe for FOR loops
            varsave[name] = state.basic_state.variables[name][:]
    # read variables
    if util.skip_white_read_if(ins, ('(',)):
        exprs = parse_expr_list(ins, len(varnames), err=error.STX)
        if None in exprs:
            raise error.RunError(error.STX)
        for i in range(len(varnames)):
            var.set_var(varnames[i], exprs[i])
        util.require_read(ins, (')',))
    # execute the code
    fns = StringIO(fncode)
    fns.seek(0)
    value = parse_expression(fns)
    # restore existing vars
    for name in varsave:
        # re-assign the stored value
        state.basic_state.variables[name][:] = varsave[name]
    return value
示例#5
0
def parse_file_number(ins, file_mode='IOAR'):
    """ Helper function: parse a file number and retrieve the file object. """
    screen = None
    if util.skip_white_read_if(ins, ('#',)):
        number = vartypes.pass_int_unpack(parse_expression(ins))
        util.range_check(0, 255, number)
        screen = devices.get_file(number, file_mode)
        util.require_read(ins, (',',))
    return screen
示例#6
0
def value_fn(ins):
    """ FN: get value of user-defined function. """
    fnname = util.parse_scalar(ins)
    # recursion is not allowed as there's no way to terminate it
    if fnname in state.basic_state.user_function_parsing:
        raise error.RunError(error.OUT_OF_MEMORY)
    state.basic_state.user_function_parsing.add(fnname)
    try:
        varnames, fncode = state.basic_state.functions[fnname]
    except KeyError:
        raise error.RunError(error.UNDEFINED_USER_FUNCTION)
    # save existing vars
    varsave = {}
    for name in varnames:
        if name in state.basic_state.variables:
            # copy the *value* - set_var is in-place it's safe for FOR loops
            varsave[name] = state.basic_state.variables[name][:]
    # read variables
    if util.skip_white_read_if(ins, ('(',)):
        exprs = []
        while True:
            exprs.append(parse_expression(ins))
            if not util.skip_white_read_if(ins, (',',)):
                break
        if len(exprs) != len(varnames):
            raise error.RunError(error.STX)
        for name, value in zip(varnames, exprs):
            var.set_scalar(name, value)
        util.require_read(ins, (')',))
    # execute the code
    fns = StringIO(fncode)
    fns.seek(0)
    value = parse_expression(fns)
    # restore existing vars
    for name in varsave:
        # re-assign the stored value
        state.basic_state.variables[name][:] = varsave[name]
    state.basic_state.user_function_parsing.remove(fnname)
    return vartypes.pass_type(fnname[-1], value)
示例#7
0
def get_var_or_array_name(ins):
    """ Helper function: parse a variable or array name. """
    name = util.get_var_name(ins)
    indices = []
    if util.skip_white_read_if(ins, ('[', '(')):
        # it's an array, read indices
        indices = parse_int_list(ins, 255, 9) # subscript out of range
        while len(indices) > 0 and indices[-1] is None:
            indices = indices[:-1]
        if None in indices:
            raise error.RunError(error.STX)
        util.require_read(ins, (']', ')'))
    return name, indices
示例#8
0
def value_input(ins):
    """ INPUT$: get characters from the keyboard or a file. """
    util.require_read(ins, ('$',))
    util.require_read(ins, ('(',))
    num = vartypes.pass_int_unpack(parse_expression(ins))
    util.range_check(1, 255, num)
    infile = state.io_state.kybd_file
    if util.skip_white_read_if(ins, (',',)):
        infile = devices.get_file(parse_file_number_opthash(ins))
    util.require_read(ins, (')',))
    word = bytearray(infile.read_raw(num))
    if len(word) < num:
        # input past end
        raise error.RunError(error.INPUT_PAST_END)
    return state.basic_state.strings.store(word)
示例#9
0
def value_input(ins):
    """ INPUT$: get characters from the keyboard or a file. """
    util.require_read(ins, ('$',))
    util.require_read(ins, ('(',))
    num = vartypes.pass_int_unpack(parse_expression(ins))
    util.range_check(1, 255, num)
    infile = backend.kybd_file
    if util.skip_white_read_if(ins, (',',)):
        infile = iolayer.get_file(parse_file_number_opthash(ins))
    util.require_read(ins, (')',))
    word = vartypes.pack_string(bytearray(infile.read_raw(num)))
    if len(word) < num:
        # input past end
        raise error.RunError(62)
    return word
示例#10
0
def parse_expr_list(ins, size, err=5, separators=(',',), allow_last_empty=False):
    """ Helper function : parse a list of expressions. """
    output = []
    while True:
        output.append(parse_expression(ins, allow_empty=True))
        if not util.skip_white_read_if(ins, separators):
            break
    if len(output) > size:            
        raise error.RunError(err)
    # can't end on a comma: Missing Operand  
    if not allow_last_empty and output and output[-1] == None:
        raise error.RunError(22)
    while len(output) < size:
        output.append(None)
    return output
示例#11
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 = get_var_or_array_name(ins)
        var_ptr = machine.varptr(name, indices)
    util.require_read(ins, (')',))
    if var_ptr < 0:
        raise error.RunError(error.IFC)
    if dollar:
        return vartypes.pack_string(bytearray(chr(var.byte_size[name[-1]])) + vartypes.value_to_uint(var_ptr))
    else:
        return vartypes.pack_int(var_ptr)
示例#12
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
示例#13
0
def value_mid(ins):
    """ MID$: get substring. """
    util.require_read(ins, ('(',))
    s = var.copy_str(vartypes.pass_string(parse_expression(ins)))
    util.require_read(ins, (',',))
    start = vartypes.pass_int_unpack(parse_expression(ins))
    if util.skip_white_read_if(ins, (',',)):
        num = vartypes.pass_int_unpack(parse_expression(ins))
    else:
        num = len(s)
    util.require_read(ins, (')',))
    util.range_check(1, 255, start)
    util.range_check(0, 255, num)
    if num == 0 or start > len(s):
        return vartypes.null('$')
    start -= 1
    stop = start + num
    stop = min(stop, len(s))
    return state.basic_state.strings.store(s[start:stop])
示例#14
0
def value_screen(ins):
    """ SCREEN: get char or attribute at a location. """
    util.require_read(ins, ('(',))
    row = vartypes.pass_int_unpack(parse_expression(ins))
    util.require_read(ins, (',',), err=error.IFC)
    col = vartypes.pass_int_unpack(parse_expression(ins))
    z = 0
    if util.skip_white_read_if(ins, (',',)):
        z = vartypes.pass_int_unpack(parse_expression(ins))
    cmode = state.console_state.screen.mode
    util.range_check(1, cmode.height, row)
    if state.console_state.view_set:
        util.range_check(state.console_state.view_start, state.console_state.scroll_height, row)
    util.range_check(1, cmode.width, col)
    util.range_check(0, 255, z)
    util.require_read(ins, (')',))
    if z and not cmode.is_text_mode:
        return vartypes.null('%')
    else:
        return vartypes.int_to_integer_signed(state.console_state.screen.apage.get_char_attr(row, col, z!=0))
示例#15
0
def parse_file_number_opthash(ins):
    """ Helper function: parse a file number, with optional hash. """
    util.skip_white_read_if(ins, ('#',))
    number = vartypes.pass_int_unpack(parse_expression(ins))
    util.range_check(0, 255, number)
    return number