import sys def encode_one_symbol(): global basic # Здесь кодируем единичный символ symbol = params[counter] if symbol != "\n": if symbol in cyrillic: # Преобразуем кириллицу в КОИ-7 Н2 basic += bytes(cyrillic[symbol], "ascii") else: if ord(symbol) > 128: # Если встречается непечатный символ, заменяем его звёздочкой basic += bytes("*", "ascii") else: basic += bytes(symbol, "ascii") tokens = {"CLS": 128, "FOR": 129, "NEXT": 130, "DATA": 131, "INPUT": 132, "DIM": 133, "READ": 134, "CUR": 135, "GOTO": 136, "RUN": 137, "IF": 138, "RESTORE": 139, "GOSUB": 140, "RETURN": 141, "REM": 142, "STOP": 143, "DPL": 144, "ON": 145, "PLOT": 146, "LINE": 147, "POKE": 148, "PRINT": 149, "DEF": 150, "CONT": 151, "LIST": 152, "CLEAR": 153, "MLOAD": 154, "MSAVE": 155, "NEW": 156, "TAB(": 157, "TO": 158, "SPC(": 159, "FN": 160, "THEN": 161, "NOT": 162, "STEP": 163, "+": 164, "-": 165, "*": 166, "/": 167, "^": 168, "AND": 169, "OR": 170, ">": 171, "=": 172, "<": 173, "SGN": 174, "INT": 175, "ABS": 176, "USR": 177, "FRE": 178, "INP": 179, "POS": 180, "SQR": 181, "RND": 182, "LOG": 183, "EXP": 184, "COS": 185, "SIN": 186, "TAN": 187, "ATN": 188, "PEEK": 189, "LEN": 190, "STR$": 191, "VAL": 192, "ASC": 193, "CHR$": 194, "LEFT$": 195, "RIGHT$": 196, "MID$": 197, "CIRCLE": 198, "MERGE": 199, "AUTO": 200, "RENUM": 201, "RCOM": 202, "DELETE": 203, "COMP": 204, "SYST": 205, "EDIT": 206, } cyrillic = {"А": "a", "Б": "b", "В": "w", "Г": "g", "Д": "d", "Е": "e", "Ё": "e", "Ж": "v", "З": "z", "И": "i", "Й": "j", "К": "k", "Л": "l", "М": "m", "Н": "n", "О": "o", "П": "p", "Р": "r", "С": "s", "Т": "t", "У": "u", "Ф": "f", "Х": "h", "Ц": "c", "Ч": "~", "Ш": "{", "Щ": "}", "Ь": "x", "Ы": "y", "Ъ": "^", "Э": "|", "Ю": "`", "Я": "q" } if len(sys.argv) == 1: print('Использование: python bas2rks.py имя_файла') else: filename = sys.argv[1] with open(filename, 'r') as file: listing = file.readlines() basic = bytearray() start = 0x29f0 # Адрес загрузки первой строки BASIC-программы token_marker = False quotes = False basic += b'\x00' # Стартовый ноль address = 1 for line in listing: next_line = address basic += b'\x00\x00' # Резервируем место под адрес следующей строки address += 2 line_number = int(line.split(" ", 1)[0]) basic.append(line_number % 256) basic.append(line_number // 256) address += 2 params = line.upper().split(" ", 1)[1] counter = 0 while counter < len(params): if not quotes: for i in range(7, 0, -1): # Максимальная длина токена RESTORE current_set = params[counter:counter + i] if current_set in tokens: token_marker = True counter += i address += 1 # Здесь кодируем токен basic.append(tokens[current_set]) if current_set == "REM": # После REM всё подряд преобразуем в текст token_marker = False while counter < len(params): encode_one_symbol() counter += 1 address += 1 break if token_marker: token_marker = False else: if counter < len(params): if params[counter] == '"': # Внутри кавычек всё подряд преобразуем в текст quotes = not quotes encode_one_symbol() counter += 1 address += 1 basic += b'\x00' # Замыкающий строку ноль # Вписываем адрес следующей строки basic[next_line] = (start + address) % 256 basic[next_line + 1] = (start + address) // 256 basic += b'\x00\x00' # Два финальных нуля в конце программы # Вычисление контрольной суммы cs = 0 for i in range(len(basic)): cs += basic[i] cs += (basic[i] << 8) cs = (cs & 0xff00) | ((cs + basic[len(basic) - 1]) & 0xff) # Добавляем контрольную сумму basic.append(cs % 256) basic.append(cs // 256) # Формируем заголовок header = bytearray() header += b'\xd4\xd4' # Формируем имя BASIC из имени файла - откидываем расширение и преобразуем всё в КОИ-7 Н2 filename = filename.rsplit('.', 1)[0] name = filename.upper() new_name = "" for i in range(len(name)): if name[i] in cyrillic: new_name += cyrillic[name[i]] else: new_name += name[i] # Добавляем 256 нулей и финальные байты заголовка header += new_name.encode() header += bytearray(256) header += b'\xe6\xd3\xd3\xd3' basic = header + basic # Сохраняем готовый файл with open(filename + ".rks", 'wb') as f_obj: f_obj.write(basic)