# Mik-2 Interpreter # by Ido Gendel, 2020 # Work in progress, of course... # How to program in Mik-2: # The character '#' marks a comment to end-of-line # First line is the memory initialization: # [addr1]=value1, [addr2]=value2 ... # Addresses are 0-based, values are signed integers # Following lines are commands: # cmd param # Available commands: # RD [addr] # Read value in memory address addr to register # WR [addr] # Write value from register to memory address addr # SU [addr] # Subtract value in memory address addr from value in register # JZ line # If value in register is 0, set program counter to line # # Command/line numbers are implicit, 0-based # WR to address [-1] will output the register value as ASCII to the terminal # JZ to a line number beyond the actual program will end the program # RD from an address not previously defined will return 0 COMMENT_IDENTIFIER = "#" PROGRAM_FILE = "program1.mik2" memory = {} program_counter = 0 register = 0 def addr_str_to_number(addr_str): b1 = addr_str.find("[") if b1 < 0: return "Missing '['" b2 = addr_str.find("]") if b2 < b1: return "Missing/misplaced ']'" try: value = int(addr_str[b1+1:b2]) if value < -1: return "Illegal address" else: return value except ValueError: return "Address Error" def initialize_memory(memory_string): global memory assign_list = memory_string.split(",") index = 0 for assign_str in assign_list: eq = assign_str.find("=") if eq <= 0: return "Missing/misplaced '=' in item " + str(index) addr = addr_str_to_number(assign_str[0:eq]) if type(addr) == str: return "Address error in item '" + str(index) + "' : " + addr try: value = int(assign_str[eq + 1:]) except ValueError: return "Value error in item " + str(index) memory[addr] = value index += 1 return "" def memory_write(key, value): memory[key] = value if -1 == key: print(chr(value), end="") def memory_read(key): if not (key in memory.keys()): memory[key] = 0 return memory[key] # command_str is stripped of all spaces def run_command(command_str): global program_counter global register cmd = command_str[:2] value_str = command_str[2:] addr = addr_str_to_number(value_str) program_counter += 1 if cmd == "RD": if type(addr) == str: return addr else: register = memory_read(addr) elif cmd == "WR": if type(addr) == str: return addr else: memory_write(addr, register) elif cmd == "SU": if type(addr) == str: return addr else: register -= memory_read(addr) elif cmd == "JZ": try: next_line = int(value_str) if 0 == register: program_counter = next_line except ValueError: return "line value" else: return "Unknown command" return "" print("Mik-2 interpreter by Ido Gendel, 2020") # Read entire program from file try: code_file = open(PROGRAM_FILE, "r") except FileNotFoundError: print("File not found!") exit() raw_code_lines = code_file.readlines() # Remove comments, newline characters and spaces code_lines = [] for line in raw_code_lines: comment_index = line.find(COMMENT_IDENTIFIER) if comment_index >= 0: line = line[:comment_index] if len(line) > 0: if line[-1] == "\n": line = line[:-1] code_lines.append(line.replace(" ", "")) # Parse and execute memory initialization line mem_issue = initialize_memory(code_lines[0]) if mem_issue != "": print("Error in line 0 (memory setup): " + mem_issue) print(code_lines[0]) exit() del code_lines[0] print("Memory: ", memory); print("Program started, press Ctrl+C to break...") print("----------") while True: if (program_counter < 0): print("\n----------\nIllegal line number: " + str(program_counter)) break if program_counter >= len(code_lines): print("\n----------\nProgram completed.") break command = code_lines[program_counter] cmd_issue = run_command(command) if cmd_issue != "": print("\n----------\nCommand error in '" + command + "' : " + cmd_issue) break print("Memory:", memory)