#!/usr/bin/env python3 import sys import os import pickle # These opcode definitions must match those in compiler.py. PUSH_INT = 0 PUSH_FLOAT = 1 LOAD_LOCAL = 2 STORE_LOCAL = 3 ADD_OP = 4 SUB_OP = 5 MUL_OP = 6 DIV_OP = 7 EQ_OP = 8 JMP_IF_FALSE= 9 JMP = 10 CALL_OP = 11 RET_OP = 12 LOAD_FIELD = 13 MAKE_STRUCT = 14 class Runtime: def __init__(self, func_table): # Preserve insertion order by converting to a list. self.func_table = list(func_table.values()) def run_function(self, func_index, args): func = self.func_table[func_index] locals_ = [0] * func['n_locals'] for i, arg in enumerate(args): locals_[i] = arg stack = [] ip = 0 code = func['code'] while ip < len(code): instr = code[ip] op = instr[0] if op == PUSH_INT: stack.append(instr[1]) elif op == PUSH_FLOAT: stack.append(instr[1]) elif op == LOAD_LOCAL: stack.append(locals_[instr[1]]) elif op == STORE_LOCAL: locals_[instr[1]] = stack.pop() elif op == ADD_OP: b = stack.pop(); a = stack.pop() stack.append(a + b) elif op == SUB_OP: b = stack.pop(); a = stack.pop() stack.append(a - b) elif op == MUL_OP: b = stack.pop(); a = stack.pop() stack.append(a * b) elif op == DIV_OP: b = stack.pop(); a = stack.pop() stack.append(a // b) elif op == EQ_OP: b = stack.pop(); a = stack.pop() stack.append(1 if a == b else 0) elif op == JMP_IF_FALSE: offset = instr[1] cond = stack.pop() if cond == 0: ip += offset continue elif op == JMP: ip += instr[1] continue elif op == CALL_OP: callee_index = instr[1] num_args = instr[2] call_args = [stack.pop() for _ in range(num_args)][::-1] ret_val = self.run_function(callee_index, call_args) stack.append(ret_val) elif op == RET_OP: return stack.pop() if stack else 0 elif op == LOAD_FIELD: struct_val = stack.pop() field_index = instr[1] stack.append(struct_val[field_index]) elif op == MAKE_STRUCT: n = instr[1] fields = [stack.pop() for _ in range(n)][::-1] stack.append(tuple(fields)) else: raise RuntimeError("Unknown opcode: " + str(op)) ip += 1 return 0 if __name__ == '__main__': bytecode_file = "program.bc" if not os.path.exists(bytecode_file): sys.exit("Error: Bytecode file not found. Please compile the source first.") with open(bytecode_file, "rb") as f: func_table = pickle.load(f) main_index = None for idx, (fname, fobj) in enumerate(func_table.items()): if fname == 'main': main_index = idx break if main_index is None: sys.exit("Error: main function not found in bytecode.") runtime = Runtime(func_table) result = runtime.run_function(main_index, [0, 0]) print("Program finished with result:", result)