CMU Coding Bootcamp
at 89ac97c03e735fee060d5cd62eb7d910e89bee89 146 lines 4.6 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_var = 0 15 16 if arg.isdigit(): 17 arg_var = int(arg) 18 elif arg.startswith("L"): 19 arg_var = values[int(arg[1:])] 20 elif arg.startswith("A"): 21 arg_var = args[int(arg[1:])] 22 23 return arg_var 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 op1, op2 = line[2], line[3] 38 op1_val, op2_val = parse(args, values, op1), parse(args, values, op2) 39 if op == "+": 40 values[out_var] = op1_val + op2_val 41 elif op == "-": 42 values[out_var] = op1_val - op2_val 43 else: 44 raise ValueError(f"Invalid Operator: {op}") 45 46 47def runJMP(args: List[int], values: List[int], line: List[str], lines) -> int | None: 48 """Return the target line number or None for a JMP command""" 49 command = line[0] 50 if command == "JMP": 51 jump_targ = line[1] 52 if jump_targ.isdigit(): 53 target = int(line[1]) 54 if target < 0 or target >= len(lines): 55 raise ValueError(f"Invalid Jump Target: {target}") 56 return target 57 else: 58 target = findLabel(lines, line[1]) 59 if target < 0 or target >= len(lines): 60 raise ValueError(f"Invalid Jump Target: {target}") 61 return target 62 else: 63 expr = line[1] 64 if command[3] == "+": 65 var = int(expr[1]) 66 if values[var] > 0: 67 target = findLabel(lines, line[2]) 68 if target < 0 or target >= len(lines): 69 raise ValueError(f"Invalid Jump Target: {target}") 70 return target 71 return 72 elif command[3] == "0": 73 var = int(expr[1]) 74 if values[var] == 0: 75 target = findLabel(lines, line[2]) 76 if target < 0 or target >= len(lines): 77 raise ValueError(f"Invalid Jump Target: {target}") 78 return target 79 return 80 else: 81 raise ValueError(f"Invalid Jump Target: {line[0]}") 82 83 84def runSimpleProgram(program: str, args: List[int]): 85 """Run a simple program with given arguments.""" 86 lines = program.splitlines() 87 lines = [line.strip() for line in lines if line.strip()] 88 lines = [line.split() for line in lines if not line.startswith("!")] 89 90 values: List[int] = [] 91 target = None 92 i = 0 93 return_value = None 94 while not return_value: 95 line = lines[i] 96 # print(f"executing {i}: {line}, L: {values}, A: {args}") 97 command = line[0] 98 if ":" in line or (target and target != i): 99 i += 1 100 continue 101 if target == i: 102 target = None 103 i += 1 104 if command.startswith("L"): 105 runL(args, values, line) 106 elif command.startswith("JMP"): 107 jump_to = runJMP(args, values, line, lines) 108 if jump_to != None: 109 i = jump_to 110 elif command == "RTN": 111 val = line[1] 112 # print(f"RTN {val} from A: {args}, L: {values}") 113 return_value = parse(args, values, val) 114 break 115 return return_value 116 117 118def testRunSimpleProgram(): 119 print("Testing runSimpleProgram()...", end="") 120 largest = """! largest: Returns max(A0, A1) 121 L0 - A0 A1 122 JMP+ L0 a0 123 RTN A1 124 a0: 125 RTN A0""" 126 assert runSimpleProgram(largest, [5, 6]) == 6 127 assert runSimpleProgram(largest, [6, 5]) == 6 128 129 sumToN = """! SumToN: Returns 1 + ... + A0 130 ! L0 is a counter, L1 is the result 131 L0 0 132 L1 0 133 loop: 134 L2 - L0 A0 135 JMP0 L2 done 136 L0 + L0 1 137 L1 + L1 L0 138 JMP loop 139 done: 140 RTN L1""" 141 assert runSimpleProgram(sumToN, [5]) == 1 + 2 + 3 + 4 + 5 142 assert runSimpleProgram(sumToN, [10]) == 10 * 11 // 2 143 print("Passed!") 144 145 146testRunSimpleProgram()