def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(',)) lst = parse_expr_list(ins, 2, err=error.STX) util.require_read(ins, (')',)) if not lst[0]: raise error.RunError(error.STX) screen = state.console_state.screen if not lst[1]: # single-argument version try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(lst[0]) if fn == 0: return vartypes.pack_int(x) elif fn == 1: return vartypes.pack_int(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['%'] else: # two-argument mode if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.pack_int(screen.drawing.point( (fp.unpack(vartypes.pass_single_keep(lst[0])), fp.unpack(vartypes.pass_single_keep(lst[1])), False)))
def value_pmap(ins): """ PMAP: convert between logical and physical coordinates. """ util.require_read(ins, ('(', )) coord = parse_expression(ins) util.require_read(ins, (',', )) mode = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')', )) util.range_check(0, 3, mode) screen = state.console_state.screen if screen.mode.is_text_mode: return vartypes.null['%'] if mode == 0: value, _ = screen.drawing.get_window_physical( fp.unpack(vartypes.pass_single_keep(coord)), fp.Single.zero) return vartypes.pack_int(value) elif mode == 1: _, value = screen.drawing.get_window_physical( fp.Single.zero, fp.unpack(vartypes.pass_single_keep(coord))) return vartypes.pack_int(value) elif mode == 2: value, _ = screen.drawing.get_window_logical( vartypes.pass_int_unpack(coord), 0) return fp.pack(value) elif mode == 3: _, value = screen.drawing.get_window_logical( 0, vartypes.pass_int_unpack(coord)) return fp.pack(value)
def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(', )) lst = parse_expr_list(ins, 2, err=error.STX) util.require_read(ins, (')', )) if not lst[0]: raise error.RunError(error.STX) screen = state.console_state.screen if not lst[1]: # single-argument version try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(lst[0]) if fn == 0: return vartypes.pack_int(x) elif fn == 1: return vartypes.pack_int(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['%'] else: # two-argument mode if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.pack_int( screen.drawing.point( (fp.unpack(vartypes.pass_single_keep(lst[0])), fp.unpack(vartypes.pass_single_keep(lst[1])), False)))
def value_sgn(ins): """ SGN: get sign. """ inp = vartypes.pass_number_keep(parse_bracket(ins)) if inp[0] == '%': inp_int = vartypes.unpack_int(inp) return vartypes.pack_int(0 if inp_int==0 else (1 if inp_int > 0 else -1)) else: return vartypes.pack_int(fp.unpack(inp).sign() )
def value_sgn(ins): """ SGN: get sign. """ inp = vartypes.pass_number_keep(parse_bracket(ins)) if inp[0] == '%': inp_int = vartypes.unpack_int(inp) return vartypes.pack_int(0 if inp_int == 0 else ( 1 if inp_int > 0 else -1)) else: return vartypes.pack_int(fp.unpack(inp).sign())
def value_lpos(ins): """ LPOS: get the current printer column. """ num = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 3, num) printer = state.io_state.devices['LPT' + max(1, num) + ':'] if printer.device_file: return vartypes.pack_int(printer.device_file.col) else: return vartypes.pack_int(1)
def value_lof(ins): """ LOF: get length of file. """ util.skip_white(ins) num = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) util.range_check(0, 255, num) the_file = devices.get_file(num) return vartypes.pack_int(the_file.lof() )
def value_play(ins): """ PLAY: get length of music queue. """ voice = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 255, voice) if not (is_pcjr_syntax and voice in (1, 2)): voice = 0 return vartypes.pack_int(state.console_state.sound.queue_length(voice))
def value_play(ins): """ PLAY: get length of music queue. """ voice = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 255, voice) if not(is_pcjr_syntax and voice in (1, 2)): voice = 0 return vartypes.pack_int(state.console_state.sound.queue_length(voice))
def value_loc(ins): """ LOC: get file pointer. """ util.skip_white(ins) num = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) util.range_check(0, 255, num) the_file = iolayer.get_file(num) return vartypes.pack_int(the_file.loc())
def value_lof(ins): """ LOF: get length of file. """ util.skip_white(ins) num = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) util.range_check(0, 255, num) the_file = devices.get_file(num) return vartypes.pack_int(the_file.lof())
def value_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep( right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack( vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left, right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not ( vartypes.gt(left, right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep( vartypes.gt(left, right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left, right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right)) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right)) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) elif op == tk.EQV: return vartypes.twoscomp_to_int(~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right))) elif op == tk.IMP: return vartypes.twoscomp_to_int((~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right)) else: raise error.RunError(error.STX)
def value_csrlin(ins): """ CSRLIN: get the current screen row. """ row, col = state.console_state.row, state.console_state.col if (col == state.console_state.screen.mode.width and state.console_state.overflow and row < state.console_state.scroll_height): # in overflow position, return row+1 except on the last row row += 1 return vartypes.pack_int(row)
def value_pos(ins): """ POS: get the current screen column. """ # parse the dummy argument, doesnt matter what it is as long as it's a legal expression parse_bracket(ins) col = state.console_state.col if col == state.console_state.screen.mode.width and state.console_state.overflow: # in overflow position, return column 1. col = 1 return vartypes.pack_int(col)
def value_pen(ins): """ PEN: poll the light pen. """ fn = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 9, fn) pen = state.console_state.pen.poll(fn) if pen is None or not state.basic_state.events.pen.enabled: # should return 0 or char pos 1 if PEN not ON pen = 1 if fn >= 6 else 0 return vartypes.pack_int(pen)
def value_pmap(ins): """ PMAP: convert between logical and physical coordinates. """ util.require_read(ins, ('(',)) coord = parse_expression(ins) util.require_read(ins, (',',)) mode = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')',)) util.range_check(0, 3, mode) screen = state.console_state.screen if screen.mode.is_text_mode: return vartypes.null['%'] if mode == 0: value, _ = screen.drawing.get_window_physical(fp.unpack(vartypes.pass_single_keep(coord)), fp.Single.zero) return vartypes.pack_int(value) elif mode == 1: _, value = screen.drawing.get_window_physical(fp.Single.zero, fp.unpack(vartypes.pass_single_keep(coord))) return vartypes.pack_int(value) elif mode == 2: value, _ = screen.drawing.get_window_logical(vartypes.pass_int_unpack(coord), 0) return fp.pack(value) elif mode == 3: _, value = screen.drawing.get_window_logical(0, vartypes.pass_int_unpack(coord)) return fp.pack(value)
def value_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left,right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not(vartypes.gt(left,right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.gt(left,right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left,right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right) ) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right) ) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right) ) elif op == tk.EQV: return vartypes.twoscomp_to_int( ~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) ) elif op == tk.IMP: return vartypes.twoscomp_to_int( (~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right) ) else: raise error.RunError(error.STX)
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)
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)
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(',)) row, col, z = parse_int_list(ins, 3, 5) if row is None or col is None: raise error.RunError(error.IFC) if z is None: z = 0 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.pack_int(state.console_state.screen.apage.get_char_attr(row, col, z!=0))
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(', )) row, col, z = parse_int_list(ins, 3, 5) if row is None or col is None: raise error.RunError(error.IFC) if z is None: z = 0 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.pack_int( state.console_state.screen.apage.get_char_attr(row, col, z != 0))
def value_err(ins): """ ERR: get error code of last error. """ return vartypes.pack_int(state.basic_state.errn)
def value_asc(ins): """ ASC: ordinal ASCII value of a character. """ s = vartypes.pass_string_unpack(parse_bracket(ins)) if not s: raise error.RunError(error.IFC) return vartypes.pack_int(s[0])
def draw(self, gml): """ DRAW: Execute a Graphics Macro Language string. """ # don't convert to uppercase as VARPTR$ elements are case sensitive gmls = StringIO(gml) plot, goback = True, False while True: c = util.skip_read(gmls, draw_and_play.ml_whitepace).upper() if c == "": break elif c == ";": continue elif c == "B": # do not draw plot = False elif c == "N": # return to postiton after move goback = True elif c == "X": # execute substring sub = draw_and_play.ml_parse_string(gmls) self.draw(str(sub)) elif c == "C": # set foreground colour # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ";": self.last_attr = 0 else: self.last_attr = draw_and_play.ml_parse_number(gmls) elif c == "S": # set scale self.draw_scale = draw_and_play.ml_parse_number(gmls) elif c == "A": # set angle # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ";": self.draw_angle = 0 else: self.draw_angle = 90 * draw_and_play.ml_parse_number(gmls) elif c == "T": # 'turn angle' - set (don't turn) the angle to any value if gmls.read(1).upper() != "A": raise error.RunError(5) # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ";": self.draw_angle = 0 else: self.draw_angle = draw_and_play.ml_parse_number(gmls) # one-variable movement commands: elif c in ("U", "D", "L", "R", "E", "F", "G", "H"): step = draw_and_play.ml_parse_number(gmls, default=vartypes.pack_int(1)) x0, y0 = self.last_point x1, y1 = 0, 0 if c in ("U", "E", "H"): y1 -= step elif c in ("D", "F", "G"): y1 += step if c in ("L", "G", "H"): x1 -= step elif c in ("R", "E", "F"): x1 += step self.draw_step(x0, y0, x1, y1, plot, goback) plot = True goback = False # two-variable movement command elif c == "M": relative = util.skip(gmls, draw_and_play.ml_whitepace) in ("+", "-") x = draw_and_play.ml_parse_number(gmls) if util.skip(gmls, draw_and_play.ml_whitepace) != ",": raise error.RunError(5) else: gmls.read(1) y = draw_and_play.ml_parse_number(gmls) x0, y0 = self.last_point if relative: self.draw_step(x0, y0, x, y, plot, goback) else: if plot: self.draw_line(x0, y0, x, y, self.last_attr) self.last_point = x, y if goback: self.last_point = x0, y0 plot = True goback = False elif c == "P": # paint - flood fill colour = draw_and_play.ml_parse_number(gmls) if util.skip_read(gmls, draw_and_play.ml_whitepace) != ",": raise error.RunError(5) bound = draw_and_play.ml_parse_number(gmls) x, y = self.get_window_logical(*self.last_point) self.paint((x, y, False), None, colour, bound, None)
def value_not(ins): """ NOT: get two's complement NOT, -x-1. """ return vartypes.pack_int(~vartypes.pass_int_unpack(parse_expr_unit(ins)))
def value_peek(ins): """ PEEK: read memory location. """ addr = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) if state.basic_state.protected and not state.basic_state.run_mode: raise error.RunError(error.IFC) return vartypes.pack_int(machine.peek(addr))
def value_inp(ins): """ INP: get value from machine port. """ port = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) return vartypes.pack_int(machine.inp(port))
def value_len(ins): """ LEN: length of string. """ return vartypes.pack_int(len(vartypes.pass_string_unpack(parse_bracket(ins))) )
def value_cvi(ins): """ CVI: return the int value of a byte representation. """ cstr = vartypes.pass_string_unpack(parse_bracket(ins)) if len(cstr) < 2: raise error.RunError(error.IFC) return vartypes.pack_int(vartypes.sint_to_value(cstr[:2]))
def parse_expr_unit(ins): """ Compute the value of the expression unit at the current code pointer. """ d = util.skip_white(ins) # string literal if d == '"': ins.read(1) output = bytearray() # while tokenised nmbers 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) return vartypes.pack_string(output) # variable name elif d in string.ascii_uppercase: name, indices = get_var_or_array_name(ins) return var.get_var_or_array(name, indices) # 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.pack_int(util.parse_jumpnum(ins)) # brackets elif d == '(': return parse_bracket(ins) # single-byte tokens else: ins.read(1) if d == tk.INPUT: return value_input(ins) elif d == tk.SCREEN: return value_screen(ins) elif d == tk.USR: return value_usr(ins) elif d == tk.FN: return value_fn(ins) elif d == tk.NOT: return value_not(ins) elif d == tk.ERL: return value_erl(ins) elif d == tk.ERR: return value_err(ins) elif d == tk.STRING: return value_string(ins) elif d == tk.INSTR: return value_instr(ins) elif d == tk.VARPTR: return value_varptr(ins) elif d == tk.CSRLIN: return value_csrlin(ins) elif d == tk.POINT: return value_point(ins) elif d == tk.INKEY: return value_inkey(ins) elif d == tk.O_PLUS: return parse_expr_unit(ins) elif d == tk.O_MINUS: return value_neg(ins) # two-byte tokens elif d == '\xFD': d += ins.read(1) if d == tk.CVI: return value_cvi(ins) elif d == tk.CVS: return value_cvs(ins) elif d == tk.CVD: return value_cvd(ins) elif d == tk.MKI: return value_mki(ins) elif d == tk.MKS: return value_mks(ins) elif d == tk.MKD: return value_mkd(ins) elif d == tk.EXTERR: return value_exterr(ins) # two-byte tokens elif d == '\xFE': d += ins.read(1) if d == tk.DATE: return value_date(ins) elif d == tk.TIME: return value_time(ins) elif d == tk.PLAY: return value_play(ins) elif d == tk.TIMER: return value_timer(ins) elif d == tk.ERDEV: return value_erdev(ins) elif d == tk.IOCTL: return value_ioctl(ins) elif d == tk.ENVIRON: return value_environ(ins) elif d == tk.PMAP: return value_pmap(ins) # two-byte tokens elif d == '\xFF': d += ins.read(1) if d == tk.LEFT: return value_left(ins) elif d == tk.RIGHT: return value_right(ins) elif d == tk.MID: return value_mid(ins) elif d == tk.SGN: return value_sgn(ins) elif d == tk.INT: return value_int(ins) elif d == tk.ABS: return value_abs(ins) elif d == tk.SQR: return value_sqr(ins) elif d == tk.RND: return value_rnd(ins) elif d == tk.SIN: return value_sin(ins) elif d == tk.LOG: return value_log(ins) elif d == tk.EXP: return value_exp(ins) elif d == tk.COS: return value_cos(ins) elif d == tk.TAN: return value_tan(ins) elif d == tk.ATN: return value_atn(ins) elif d == tk.FRE: return value_fre(ins) elif d == tk.INP: return value_inp(ins) elif d == tk.POS: return value_pos(ins) elif d == tk.LEN: return value_len(ins) elif d == tk.STR: return value_str(ins) elif d == tk.VAL: return value_val(ins) elif d == tk.ASC: return value_asc(ins) elif d == tk.CHR: return value_chr(ins) elif d == tk.PEEK: return value_peek(ins) elif d == tk.SPACE: return value_space(ins) elif d == tk.OCT: return value_oct(ins) elif d == tk.HEX: return value_hex(ins) elif d == tk.LPOS: return value_lpos(ins) elif d == tk.CINT: return value_cint(ins) elif d == tk.CSNG: return value_csng(ins) elif d == tk.CDBL: return value_cdbl(ins) elif d == tk.FIX: return value_fix(ins) elif d == tk.PEN: return value_pen(ins) elif d == tk.STICK: return value_stick(ins) elif d == tk.STRIG: return value_strig(ins) elif d == tk.EOF: return value_eof(ins) elif d == tk.LOC: return value_loc(ins) elif d == tk.LOF: return value_lof(ins) else: return None
def set_gwbasic_vars(self, dictionary): """ Retrieve variables from Python script """ for new_var_name, new_var_value in dictionary.iteritems(): var_name = self.name_recover(new_var_name) if type(new_var_value) == str: if var_name[-1] != '$': raise Exception("Type mismatch. Variable name is %s, but a string value was received (%s)" % (new_var_name , new_var_value)) ins = cStringIO.StringIO(var_name) var_name = util.get_var_name(ins) var.set_var(var_name, vartypes.pack_string(bytearray(new_var_value + "\0"))) elif type(new_var_value) == int: if var_name[-1] != '%': raise Exception("Type mismatch. Variable name is %s, but a integer value was received (%d)" % (new_var_name , new_var_value)) ins = cStringIO.StringIO(var_name) var_name = util.get_var_name(ins) var.set_var(var_name, vartypes.pack_int(new_var_value)) elif type(new_var_value) == float: if var_name[-1] == '!': ins = cStringIO.StringIO(var_name) var_name = util.get_var_name(ins) bytearray_val = fp.Single.from_value(new_var_value).to_bytes() var.set_var(var_name, ('!', bytearray_val)) elif var_name[-1] == '#': ins = cStringIO.StringIO(var_name) var_name = util.get_var_name(ins) bytearray_val = fp.Double.from_value(new_var_value).to_bytes() var.set_var(var_name, ('#', bytearray_val)) else: raise Exception("Type mismatch. Variable name is %s, but a floating-point value was received (%f)" % (new_var_name , new_var_value)) elif type(new_var_value) == list: matrix = np.array(new_var_value) dimensions = matrix.shape if var_name in state.basic_state.arrays.keys(): var.erase_array(var_name) dimensions = [x for x in dimensions] var.dim_array(var_name, dimensions) indexes = [list(xrange(d)) for d in dimensions] indexes = list(itertools.product(*indexes)) for index in indexes: item_value = new_var_value for coord in index: item_value = item_value[coord] if var_name[-1] == '$': matrix_element = vartypes.pack_string(bytearray(item_value + "\0")) elif var_name[-1] == '%': matrix_element = vartypes.pack_int(item_value) elif var_name[-1] == '!': matrix_element = ( '!', fp.Single.from_value(item_value).to_bytes()) elif var_name[-1] == '#': matrix_element = ('#', fp.Double.from_value(item_value).to_bytes()) else: raise Exception("Array type unknown for variable %s" % new_var_name) try: var.set_var_or_array(var_name, index, matrix_element) except: import traceback traceback.print_exc() else: logging.debug('Received variable was not processed: %s.', new_var_name)
def value_len(ins): """ LEN: length of string. """ return vartypes.pack_int( len(vartypes.pass_string_unpack(parse_bracket(ins))))
def value_stick(ins): """ STICK: poll the joystick. """ fn = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 3, fn) return vartypes.pack_int(state.console_state.stick.poll(fn))
def parse_expr_unit(ins): """ Compute the value of the expression unit at the current code pointer. """ d = util.skip_white(ins) # string literal if d == '"': ins.read(1) output = bytearray() # while tokenised nmbers 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) return vartypes.pack_string(output) # variable name elif d in string.ascii_uppercase: name, indices = get_var_or_array_name(ins) return var.get_var_or_array(name, indices) # 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.pack_int(util.parse_jumpnum(ins)) # brackets elif d == '(': return parse_bracket(ins) # single-byte tokens else: ins.read(1) if d == tk.INPUT: return value_input(ins) elif d == tk.SCREEN: return value_screen(ins) elif d == tk.USR: return value_usr(ins) elif d == tk.FN: return value_fn(ins) elif d == tk.NOT: return value_not(ins) elif d == tk.ERL: return value_erl(ins) elif d == tk.ERR: return value_err(ins) elif d == tk.STRING: return value_string(ins) elif d == tk.INSTR: return value_instr(ins) elif d == tk.VARPTR: return value_varptr(ins) elif d == tk.CSRLIN: return value_csrlin(ins) elif d == tk.POINT: return value_point(ins) elif d == tk.INKEY: return value_inkey(ins) elif d == tk.O_PLUS: return parse_expr_unit(ins) elif d == tk.O_MINUS: return value_neg(ins) # two-byte tokens elif d == '\xFD': d += ins.read(1) if d == tk.CVI: return value_cvi(ins) elif d == tk.CVS: return value_cvs(ins) elif d == tk.CVD: return value_cvd(ins) elif d == tk.MKI: return value_mki(ins) elif d == tk.MKS: return value_mks(ins) elif d == tk.MKD: return value_mkd(ins) elif d == tk.EXTERR: return value_exterr(ins) # two-byte tokens elif d == '\xFE': d += ins.read(1) if d == tk.DATE: return value_date(ins) elif d == tk.TIME: return value_time(ins) elif d == tk.PLAY: return value_play(ins) elif d == tk.TIMER: return value_timer(ins) elif d == tk.ERDEV: return value_erdev(ins) elif d == tk.IOCTL: return value_ioctl(ins) elif d == tk.ENVIRON: return value_environ(ins) elif d == tk.PMAP: return value_pmap(ins) # two-byte tokens elif d == '\xFF': d += ins.read(1) if d == tk.LEFT: return value_left(ins) elif d == tk.RIGHT: return value_right(ins) elif d == tk.MID: return value_mid(ins) elif d == tk.SGN: return value_sgn(ins) elif d == tk.INT: return value_int(ins) elif d == tk.ABS: return value_abs(ins) elif d == tk.SQR: return value_sqr(ins) elif d == tk.RND: return value_rnd(ins) elif d == tk.SIN: return value_sin(ins) elif d == tk.LOG: return value_log(ins) elif d == tk.EXP: return value_exp(ins) elif d == tk.COS: return value_cos(ins) elif d == tk.TAN: return value_tan(ins) elif d == tk.ATN: return value_atn(ins) elif d == tk.FRE: return value_fre(ins) elif d == tk.INP: return value_inp(ins) elif d == tk.POS: return value_pos(ins) elif d == tk.LEN: return value_len(ins) elif d == tk.STR: return value_str(ins) elif d == tk.VAL: return value_val(ins) elif d == tk.ASC: return value_asc(ins) elif d == tk.CHR: return value_chr(ins) elif d == tk.PEEK: return value_peek(ins) elif d == tk.SPACE: return value_space(ins) elif d == tk.OCT: return value_oct(ins) elif d == tk.HEX: return value_hex(ins) elif d == tk.LPOS: return value_lpos(ins) elif d == tk.CINT: return value_cint(ins) elif d == tk.CSNG: return value_csng(ins) elif d == tk.CDBL: return value_cdbl(ins) elif d == tk.FIX: return value_fix(ins) elif d == tk.PEN: return value_pen(ins) elif d == tk.STICK: return value_stick(ins) elif d == tk.STRIG: return value_strig(ins) elif d == tk.EOF: return value_eof(ins) elif d == tk.LOC: return value_loc(ins) elif d == tk.LOF: return value_lof(ins) else: return None
def parse_expr_unit(ins): """ Compute the value of the expression unit at the current code pointer. """ d = util.skip_white(ins) # string literal if d == '"': ins.read(1) output = bytearray() # while tokenised nmbers 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 util.end_line + ('"',): output += d d = ins.read(1) if d == '\0': ins.seek(-1, 1) return vartypes.pack_string(output) # variable name elif d >= 'A' and d <= 'Z': name, indices = get_var_or_array_name(ins) return var.get_var_or_array(name, indices) # 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 >= '0' and d <= '9': outs = StringIO() representation.tokenise_number(ins, outs) outs.seek(0) return util.parse_value(outs) # number literals elif d in token.number: return util.parse_value(ins) # gw-basic allows adding line numbers to numbers elif d == token.T_UINT: return vartypes.pack_int(util.parse_jumpnum(ins)) # brackets elif d == '(': return parse_bracket(ins) # single-byte tokens else: ins.read(1) if d == '\x85': return value_input(ins) elif d == '\xC8': return value_screen(ins) elif d == '\xD0': return value_usr(ins) elif d == '\xD1': return value_fn(ins) elif d == '\xD3': return value_not(ins) elif d == '\xD4': return value_erl(ins) elif d == '\xD5': return value_err(ins) elif d == '\xD6': return value_string(ins) elif d == '\xD8': return value_instr(ins) elif d == '\xDA': return value_varptr(ins) elif d == '\xDB': return value_csrlin(ins) elif d == '\xDC': return value_point(ins) elif d == '\xDE': return value_inkey(ins) elif d == '\xE9': return parse_expr_unit(ins) elif d == '\xEA': return value_neg(ins) # two-byte tokens elif d == '\xFD': d = ins.read(1) if d == '\x81': return value_cvi(ins) elif d =='\x82': return value_cvs(ins) elif d =='\x83': return value_cvd(ins) elif d =='\x84': return value_mki(ins) elif d =='\x85': return value_mks(ins) elif d =='\x86': return value_mkd(ins) elif d == '\x8b': return value_exterr(ins) # two-byte tokens elif d == '\xFE': d = ins.read(1) if d == '\x8D': return value_date(ins) elif d == '\x8E': return value_time(ins) elif d == '\x93': return value_play(ins) elif d == '\x94': return value_timer(ins) elif d == '\x95': return value_erdev(ins) elif d == '\x96': return value_ioctl(ins) elif d == '\x9B': return value_environ(ins) elif d == '\x9E': return value_pmap(ins) # two-byte tokens elif d == '\xFF': d = ins.read(1) if d == '\x81': return value_left(ins) elif d == '\x82': return value_right(ins) elif d == '\x83': return value_mid(ins) elif d == '\x84': return value_sgn(ins) elif d == '\x85': return value_int(ins) elif d == '\x86': return value_abs(ins) elif d == '\x87': return value_sqrt(ins) elif d == '\x88': return value_rnd(ins) elif d == '\x89': return value_sin(ins) elif d == '\x8a': return value_log(ins) elif d == '\x8b': return value_exp(ins) elif d == '\x8c': return value_cos(ins) elif d == '\x8D': return value_tan(ins) elif d == '\x8E': return value_atn(ins) elif d == '\x8F': return value_fre(ins) elif d == '\x90': return value_inp(ins) elif d == '\x91': return value_pos(ins) elif d == '\x92': return value_len(ins) elif d == '\x93': return value_str(ins) elif d == '\x94': return value_val(ins) elif d == '\x95': return value_asc(ins) elif d == '\x96': return value_chr(ins) elif d == '\x97': return value_peek(ins) elif d == '\x98': return value_space(ins) elif d == '\x99': return value_oct(ins) elif d == '\x9A': return value_hex(ins) elif d == '\x9B': return value_lpos(ins) elif d == '\x9C': return value_cint(ins) elif d == '\x9D': return value_csng(ins) elif d == '\x9E': return value_cdbl(ins) elif d == '\x9F': return value_fix(ins) elif d == '\xA0': return value_pen(ins) elif d == '\xA1': return value_stick(ins) elif d == '\xA2': return value_strig(ins) elif d == '\xA3': return value_eof(ins) elif d == '\xA4': return value_loc(ins) elif d == '\xA5': return value_lof(ins) else: return None
def draw(self, gml): """ DRAW: Execute a Graphics Macro Language string. """ # don't convert to uppercase as VARPTR$ elements are case sensitive gmls = StringIO(gml) plot, goback = True, False while True: c = util.skip_read(gmls, draw_and_play.ml_whitepace).upper() if c == '': break elif c == ';': continue elif c == 'B': # do not draw plot = False elif c == 'N': # return to postiton after move goback = True elif c == 'X': # execute substring sub = draw_and_play.ml_parse_string(gmls) self.draw(str(sub)) elif c == 'C': # set foreground colour # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ';': self.last_attr = 0 else: self.last_attr = draw_and_play.ml_parse_number(gmls) elif c == 'S': # set scale self.draw_scale = draw_and_play.ml_parse_number(gmls) elif c == 'A': # set angle # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ';': self.draw_angle = 0 else: self.draw_angle = 90 * draw_and_play.ml_parse_number(gmls) elif c == 'T': # 'turn angle' - set (don't turn) the angle to any value if gmls.read(1).upper() != 'A': raise error.RunError(error.IFC) # allow empty spec (default 0), but only if followed by a semicolon if util.skip(gmls, draw_and_play.ml_whitepace) == ';': self.draw_angle = 0 else: self.draw_angle = draw_and_play.ml_parse_number(gmls) # one-variable movement commands: elif c in ('U', 'D', 'L', 'R', 'E', 'F', 'G', 'H'): step = draw_and_play.ml_parse_number( gmls, default=vartypes.pack_int(1)) x0, y0 = self.last_point x1, y1 = 0, 0 if c in ('U', 'E', 'H'): y1 -= step elif c in ('D', 'F', 'G'): y1 += step if c in ('L', 'G', 'H'): x1 -= step elif c in ('R', 'E', 'F'): x1 += step self.draw_step(x0, y0, x1, y1, plot, goback) plot = True goback = False # two-variable movement command elif c == 'M': relative = util.skip(gmls, draw_and_play.ml_whitepace) in ('+', '-') x = draw_and_play.ml_parse_number(gmls) if util.skip(gmls, draw_and_play.ml_whitepace) != ',': raise error.RunError(error.IFC) else: gmls.read(1) y = draw_and_play.ml_parse_number(gmls) x0, y0 = self.last_point if relative: self.draw_step(x0, y0, x, y, plot, goback) else: if plot: self.draw_line(x0, y0, x, y, self.last_attr) self.last_point = x, y if goback: self.last_point = x0, y0 plot = True goback = False elif c == 'P': # paint - flood fill colour = draw_and_play.ml_parse_number(gmls) if util.skip_read(gmls, draw_and_play.ml_whitepace) != ',': raise error.RunError(error.IFC) bound = draw_and_play.ml_parse_number(gmls) x, y = self.get_window_logical(*self.last_point) self.paint((x, y, False), None, colour, bound, None)