def value_environ(ins): """ ENVIRON$: get environment string. """ util.require_read(ins, ('$',)) expr = parse_bracket(ins) if expr[0] == '$': return vartypes.pack_string(shell.get_env(vartypes.unpack_string(expr))) else: expr = vartypes.pass_int_unpack(expr) util.range_check(1, 255, expr) return vartypes.pack_string(shell.get_env_entry(expr))
def value_environ(ins): """ ENVIRON$: get environment string. """ util.require_read(ins, ('$', )) expr = parse_bracket(ins) if expr[0] == '$': return vartypes.pack_string(shell.get_env( vartypes.unpack_string(expr))) else: expr = vartypes.pass_int_unpack(expr) util.range_check(1, 255, expr) return vartypes.pack_string(shell.get_env_entry(expr))
def _input_entry(self, typechar, allow_past_end): """ Read a number or string entry for INPUT """ word, blanks = '', '' last = self._skip_whitespace(self.whitespace_input) # read first non-whitespace char c = self.read(1) # LF escapes quotes # may be true if last == '', hence "in ('\n', '\0')" not "in '\n0'" quoted = (c == '"' and typechar == '$' and last not in ('\n', '\0')) if quoted: c = self.read(1) # LF escapes end of file, return empty string if not c and not allow_past_end and last not in ('\n', '\0'): raise error.RunError(error.INPUT_PAST_END) # we read the ending char before breaking the loop # this may raise FIELD OVERFLOW # on reading from a KYBD: file, control char replacement takes place # which means we need to use read() not read_raw() while c and not ((typechar != '$' and c in self.soft_sep) or (c in ',\r' and not quoted)): if c == '"' and quoted: # whitespace after quote will be skipped below break elif c == '\n' and not quoted: # LF, LFCR are dropped entirely c = self.read(1) if c == '\r': c = self.read(1) continue elif c == '\0': # NUL is dropped even within quotes pass elif c in self.whitespace_input and not quoted: # ignore whitespace in numbers, except soft separators # include internal whitespace in strings if typechar == '$': blanks += c else: word += blanks + c blanks = '' if len(word) + len(blanks) >= 255: break if not quoted: c = self.read(1) else: # no CRLF replacement inside quotes. # -- but should there be KYBD: control char replacement? c = self.read_raw(1) # if separator was a whitespace char or closing quote # skip trailing whitespace before any comma or hard separator if c and c in self.whitespace_input or (quoted and c == '"'): self._skip_whitespace(' ') if (self.next_char in ',\r'): c = self.read(1) # file position is at one past the separator char # convert result to requested type, be strict about non-numeric chars value = vartypes.pack_string(bytearray(word)) if typechar != '$': value = representation.str_to_value_keep(value, allow_nonnum=False) return value, c
def vplus(left, right): """ Left+right. """ if left[0] == '$': return vartypes.pack_string( vartypes.pass_string_unpack(left) + vartypes.pass_string_unpack(right)) else: return vartypes.number_add(left, right)
def _input_entry(self, typechar, allow_past_end): """ Read a number or string entry from KYBD: for INPUT# """ word, blanks = '', '' if self.input_last: c, self.input_last = self.input_last, '' else: last = self._skip_whitespace(self.whitespace_input) # read first non-whitespace char c = self.read(1) # LF escapes quotes # may be true if last == '', hence "in ('\n', '\0')" not "in '\n0'" quoted = (c == '"' and typechar == '$' and last not in ('\n', '\0')) if quoted: c = self.read(1) # LF escapes end of file, return empty string if not c and not allow_past_end and last not in ('\n', '\0'): raise error.RunError(error.INPUT_PAST_END) # we read the ending char before breaking the loop # this may raise FIELD OVERFLOW # on reading from a KYBD: file, control char replacement takes place # which means we need to use read() not read_raw() parsing_trail = False while c and not (c in ',\r' and not quoted): if c == '"' and quoted: parsing_trail = True elif c == '\n' and not quoted: # LF, LFCR are dropped entirely c = self.read(1) if c == '\r': c = self.read(1) continue elif c == '\0': # NUL is dropped even within quotes pass elif c in self.whitespace_input and not quoted: # ignore whitespace in numbers, except soft separators # include internal whitespace in strings if typechar == '$': blanks += c else: word += blanks + c blanks = '' if len(word) + len(blanks) >= 255: break # there should be KYBD: control char replacement here even if quoted c = self.read(1) if parsing_trail: if c not in self.whitespace_input: if c not in (',', '\r'): self.input_last = c break parsing_trail = parsing_trail or (typechar != '$' and c == ' ') # file position is at one past the separator char # convert result to requested type, be strict about non-numeric chars value = vartypes.pack_string(bytearray(word)) if typechar != '$': value = representation.str_to_value_keep(value, allow_nonnum=False) return value, c
def str_to_type(word, type_char): """ Convert Python-string to requested type. """ packed = vartypes.pack_string(bytearray(word)) if type_char == '$': return packed else: try: return str_to_value_keep(packed, allow_nonnum=False) except AttributeError: return None
def get_string_copy_packed(sequence): """ Return a packed copy of a string from its 3-byte sequence. """ length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if address >= memory.var_start(): # string is stored in string space return state.basic_state.strings.copy_packed(sequence) else: # string is stored in code space or field buffers if address < memory.field_mem_start: return vartypes.pack_string('\0' * length) # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset offset = start % memory.field_mem_offset try: return vartypes.pack_string(state.io_state.fields[number][offset:offset+length]) except KeyError, IndexError: return vartypes.pack_string('\0' * length)
def get_string_copy_packed(sequence): """ Return a packed copy of a string from its 3-byte sequence. """ length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if address >= memory.var_start(): # string is stored in string space return state.basic_state.strings.copy_packed(sequence) else: # string is stored in code space or field buffers if address < memory.field_mem_start: return vartypes.pack_string('\0' * length) # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset offset = start % memory.field_mem_offset try: return vartypes.pack_string( state.io_state.fields[number].buffer[offset:offset + length]) except KeyError, IndexError: return vartypes.pack_string('\0' * length)
def value_right(ins): """ RIGHT$: get substring at the end of string. """ util.require_read(ins, ('(', )) s = vartypes.pass_string_unpack(parse_expression(ins)) util.require_read(ins, (',', )) stop = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')', )) util.range_check(0, 255, stop) if stop == 0: return vartypes.null['$'] stop = min(stop, len(s)) return vartypes.pack_string(s[-stop:])
def value_right(ins): """ RIGHT$: get substring at the end of string. """ util.require_read(ins, ('(',)) s = vartypes.pass_string_unpack(parse_expression(ins)) util.require_read(ins, (',',)) stop = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')',)) util.range_check(0, 255, stop) if stop == 0: return vartypes.null['$'] stop = min(stop, len(s)) return vartypes.pack_string(s[-stop:])
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 = vartypes.pack_string(bytearray(infile.read_raw(num))) if len(word) < num: # input past end raise error.RunError(error.INPUT_PAST_END) return word
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(',)) n, j = parse_expr_list(ins, 2) n = vartypes.pass_int_unpack(n) util.range_check(0, 255, n) if j[0] == '$': j = vartypes.unpack_string(j) util.range_check(1, 255, len(j)) j = j[0] else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')',)) return vartypes.pack_string(bytearray(chr(j)*n))
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(', )) n, j = parse_expr_list(ins, 2) n = vartypes.pass_int_unpack(n) util.range_check(0, 255, n) if j[0] == '$': j = vartypes.unpack_string(j) util.range_check(1, 255, len(j)) j = j[0] else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')', )) return vartypes.pack_string(bytearray(chr(j) * n))
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 = vartypes.pack_string(bytearray(infile.read_raw(num))) if len(word) < num: # input past end raise error.RunError(error.INPUT_PAST_END) return word
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_mid(ins): """ MID$: get substring. """ util.require_read(ins, ('(',)) s = vartypes.pass_string_unpack(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 vartypes.pack_string(s[start:stop])
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_mid(ins): """ MID$: get substring. """ util.require_read(ins, ('(', )) s = vartypes.pass_string_unpack(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 vartypes.pack_string(s[start:stop])
def value_hex(ins): """ HEX$: hexadecimal representation of int. """ # allow range -32768 to 65535 val = vartypes.pass_int_unpack(parse_bracket(ins), 0xffff) return vartypes.pack_string(representation.hex_to_str(vartypes.value_to_sint(val))[2:])
def value_oct(ins): """ OCT$: octal representation of int. """ # allow range -32768 to 65535 val = vartypes.pass_int_unpack(parse_bracket(ins), 0xffff) return vartypes.pack_string(representation.oct_to_str(vartypes.value_to_sint(val))[2:])
def value_chr(ins): """ CHR$: character for ASCII value. """ val = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 255, val) return vartypes.pack_string(bytearray(chr(val)))
def value_mkd(ins): """ MKD$: return the byte representation of a double. """ return vartypes.pack_string(vartypes.pass_double_keep(parse_bracket(ins))[1])
def value_time(ins): """ TIME$: get current system time. """ return vartypes.pack_string(timedate.get_time())
def value_space(ins): """ SPACE$: repeat spaces. """ num = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 255, num) return vartypes.pack_string(bytearray(' '*num))
def value_inkey(ins): """ INKEY$: get a character from the keyboard. """ return vartypes.pack_string(bytearray(state.console_state.keyb.get_char()))
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 value_oct(ins): """ OCT$: octal representation of int. """ # allow range -32768 to 65535 val = vartypes.pass_int_unpack(parse_bracket(ins), 0xffff) return vartypes.pack_string( representation.oct_to_str(vartypes.value_to_sint(val))[2:])
def value_date(ins): """ DATE$: get current system date. """ return vartypes.pack_string(timedate.get_date())
def value_mki(ins): """ MKI$: return the byte representation of an int. """ return vartypes.pack_string(vartypes.value_to_sint(vartypes.pass_int_unpack(parse_bracket(ins))))
def value_space(ins): """ SPACE$: repeat spaces. """ num = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 255, num) return vartypes.pack_string(bytearray(' ' * num))
def value_mks(ins): """ MKS$: return the byte representation of a single. """ return vartypes.pack_string(vartypes.pass_single_keep(parse_bracket(ins))[1])
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 value_mkd(ins): """ MKD$: return the byte representation of a double. """ return vartypes.pack_string( vartypes.pass_double_keep(parse_bracket(ins))[1])
def value_mks(ins): """ MKS$: return the byte representation of a single. """ return vartypes.pack_string( vartypes.pass_single_keep(parse_bracket(ins))[1])
def value_hex(ins): """ HEX$: hexadecimal representation of int. """ # allow range -32768 to 65535 val = vartypes.pass_int_unpack(parse_bracket(ins), 0xffff) return vartypes.pack_string( representation.hex_to_str(vartypes.value_to_sint(val))[2:])
def vplus(left, right): """ Left+right. """ if left[0] == '$': return vartypes.pack_string(vartypes.pass_string_unpack(left) + vartypes.pass_string_unpack(right)) else: return vartypes.number_add(left, right)
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 copy_packed(self, key): """ Return a packed copy of the string by its 2-byte key or 3-byte sequence. """ return vartypes.pack_string(self.retrieve(key)[:])
def value_mki(ins): """ MKI$: return the byte representation of an int. """ return vartypes.pack_string( vartypes.value_to_sint(vartypes.pass_int_unpack(parse_bracket(ins))))
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)