import sys
import os
import re

# ──────── Interpreter State ────────

class Frame:
    def __init__(self, function_name, locals=None):
        self.function_name = function_name
        self.locals = locals or {}

class InterpreterState:
    def __init__(self):
        self.stack = []  # Call stack
        self.functions = {}  # name → AST

    def push_frame(self, name):
        self.stack.append(Frame(name))

    def pop_frame(self):
        return self.stack.pop()

    def current_frame(self):
        return self.stack[-1] if self.stack else None

    def debug_bt(self):
        print("\nBacktrace:")
        for i, frame in enumerate(reversed(self.stack)):
            print(f"  #{i} {frame.function_name}")
        print()

    def debug_vars(self):
        frame = self.current_frame()
        print("\nVariables:")
        if frame:
            for k, v in frame.locals.items():
                print(f"  {k} = {v}")
        else:
            print("  No active frame.")
        print()

# ──────── C Parser (toy) ────────

def parse_c_file(filename, included=None):
    if included is None:
        included = set()

    abs_path = os.path.abspath(filename)
    if abs_path in included:
        return {}

    included.add(abs_path)

    try:
        with open(abs_path) as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found.")
        return {}

    ast = {}
    current_fn = None
    body = []

    for line in lines:
        line = line.strip()
        if line.startswith("#include"):
            match = re.match(r'#include\s+"(.+?)"', line)
            if match:
                included_ast = parse_c_file(os.path.join(os.path.dirname(abs_path), match.group(1)), included)
                ast.update(included_ast)
        elif line.startswith("void"):
            fn_match = re.match(r'void\s+(\w+)\s*\(\s*\)\s*{', line)
            if fn_match:
                if current_fn:
                    ast[current_fn] = body
                    body = []
                current_fn = fn_match.group(1)
        elif line == "}":
            if current_fn:
                ast[current_fn] = body
                current_fn = None
                body = []
        elif re.match(r'int\s+\w+\s*=\s*\d+;', line):
            var_match = re.match(r'int\s+(\w+)\s*=\s*(\d+);', line)
            body.append(('decl', var_match.group(1), int(var_match.group(2))))
        elif re.match(r'printf\(".*",\s*\w+\);', line):
            print_match = re.match(r'printf\(".*",\s*(\w+)\);', line)
            body.append(('print', print_match.group(1)))
        elif re.match(r'\w+\(\);', line):
            call_match = re.match(r'(\w+)\(\);', line)
            body.append(('call', call_match.group(1)))
    return ast

# ──────── Interpreter Executor ────────

class Interpreter:
    def __init__(self, state):
        self.state = state

    def run_function(self, name):
        if name not in self.state.functions:
            print(f"Function '{name}' not defined.")
            return
        self.state.push_frame(name)
        body = self.state.functions[name]
        for stmt in body:
            self.exec_stmt(stmt)
        self.state.pop_frame()

    def exec_stmt(self, stmt):
        frame = self.state.current_frame()
        if stmt[0] == 'decl':
            _, var, val = stmt
            frame.locals[var] = val
        elif stmt[0] == 'print':
            var = stmt[1]
            print(frame.locals.get(var, 'undefined'))
        elif stmt[0] == 'call':
            self.run_function(stmt[1])

# ──────── Debugger CLI ────────

def debugger_loop(state, interp):
    print("Mini C Interpreter Debugger")
    print("Commands: run, bt, vars, quit")
    while True:
        cmd = input("(debug) ").strip()
        if cmd == "run":
            interp.run_function("main")
        elif cmd == "bt":
            state.debug_bt()
        elif cmd == "vars":
            state.debug_vars()
        elif cmd == "quit":
            break
        else:
            print("Unknown command. Use: run, bt, vars, quit")

# ──────── Entry Point ────────

def main():
    if len(sys.argv) < 2:
        print("Usage: python c_interpreter.py <file.c>")
        return

    filename = sys.argv[1]
    ast = parse_c_file(filename)
    if not ast:
        print("No functions parsed.")
        return

    state = InterpreterState()
    state.functions = ast
    interp = Interpreter(state)
    debugger_loop(state, interp)

if __name__ == "__main__":
    main()