Interprited_C/python-c-compialer/runtime.py
2025-03-30 20:23:07 -05:00

108 lines
3.5 KiB
Python

#!/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)