CMU Coding Bootcamp
at main 4.3 kB view raw
1from typing import List 2 3 4def findLabel(lines: List[List[str]], label: str) -> int: 5 """Find the line number of a label""" 6 for i, line in enumerate(lines): 7 if line[0] == label + ":": 8 return i 9 raise ValueError(f"Label '{label}' not found") 10 11 12def parse(args: List[int], values: List[int], arg: str) -> int: 13 """Parse an argument string into an integer value""" 14 arg_val = 0 15 16 if arg.isdigit(): 17 arg_val = int(arg) 18 elif arg.startswith("L"): 19 arg_val = values[int(arg[1:])] 20 elif arg.startswith("A"): 21 arg_val = args[int(arg[1:])] 22 23 return arg_val 24 25 26def runL(args: List[int], values: List[int], line: List[str]): 27 """Run a Set command""" 28 out_var = int(line[0][1:]) 29 op = line[1] 30 31 if out_var >= len(values): 32 values.extend([0] * (out_var - len(values) + 1)) 33 34 if op.isdigit(): 35 values[out_var] = int(op) 36 else: 37 var1, var2 = line[2], line[3] 38 var1_val, var2_val = parse(args, values, var1), parse(args, values, var2) 39 if op == "+": 40 values[out_var] = var1_val + var2_val 41 elif op == "-": 42 values[out_var] = var1_val - var2_val 43 else: 44 raise ValueError(f"Invalid Operator: {op}") 45 46 47def handleTargetError(target: int, lines: List[List[str]]) -> int | None: 48 if target < 0 or target >= len(lines): 49 raise ValueError(f"Invalid Jump Target: {target}") 50 return target 51 52 53def runJMP(args: List[int], values: List[int], line: List[str], lines) -> int | None: 54 """Return the target line number or None for a JMP command""" 55 command = line[0] 56 if command == "JMP": 57 jump_targ = line[1] 58 if jump_targ.isdigit(): 59 target = int(line[1]) 60 return handleTargetError(target, lines) 61 else: 62 target = findLabel(lines, line[1]) 63 return handleTargetError(target, lines) 64 else: 65 expr = line[1] 66 if command[3] == "+": 67 var = int(expr[1]) 68 if values[var] > 0: 69 target = findLabel(lines, line[2]) 70 return handleTargetError(target, lines) 71 return None 72 elif command[3] == "0": 73 var = int(expr[1]) 74 if values[var] == 0: 75 target = findLabel(lines, line[2]) 76 return handleTargetError(target, lines) 77 return None 78 else: 79 raise ValueError(f"Invalid Jump Target: {line[0]}") 80 81 82def runSimpleProgram(program: str, args: List[int]): 83 """Run a simple program with given arguments.""" 84 lines = program.splitlines() 85 lines = [line.strip() for line in lines if line.strip()] 86 lines = [line.split() for line in lines if not line.startswith("!")] 87 88 values: List[int] = [] 89 i = 0 90 return_value = None 91 while not return_value: 92 line = lines[i] 93 i += 1 94 # print(f"executing {i}: {line}, L: {values}, A: {args}") 95 command = line[0] 96 if ":" in line: 97 continue 98 if command.startswith("L"): 99 runL(args, values, line) 100 elif command.startswith("JMP"): 101 jump_to = runJMP(args, values, line, lines) 102 if jump_to != None: 103 i = jump_to 104 elif command == "RTN": 105 val = line[1] 106 # print(f"RTN {val} from A: {args}, L: {values}") 107 return_value = parse(args, values, val) 108 break 109 return return_value 110 111 112def testRunSimpleProgram(): 113 print("Testing runSimpleProgram()...", end="") 114 largest = """! largest: Returns max(A0, A1) 115 L0 - A0 A1 116 JMP+ L0 a0 117 RTN A1 118 a0: 119 RTN A0""" 120 assert runSimpleProgram(largest, [5, 6]) == 6 121 assert runSimpleProgram(largest, [6, 5]) == 6 122 123 sumToN = """! SumToN: Returns 1 + ... + A0 124 ! L0 is a counter, L1 is the result 125 L0 0 126 L1 0 127 loop: 128 L2 - L0 A0 129 JMP0 L2 done 130 L0 + L0 1 131 L1 + L1 L0 132 JMP loop 133 done: 134 RTN L1""" 135 assert runSimpleProgram(sumToN, [5]) == 1 + 2 + 3 + 4 + 5 136 assert runSimpleProgram(sumToN, [10]) == 10 * 11 // 2 137 print("Passed!") 138 139 140testRunSimpleProgram()