C interpriter
This commit is contained in:
parent
9fd2bfefec
commit
f124ba5585
@ -5,6 +5,6 @@ Collapsed=0
|
||||
|
||||
[Window][Debug]
|
||||
Pos=12,41
|
||||
Size=336,392
|
||||
Size=778,630
|
||||
Collapsed=0
|
||||
|
||||
|
14
python-c-interpriter/main.c
Normal file
14
python-c-interpriter/main.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include "other.h"
|
||||
|
||||
void main() {
|
||||
int a = 5;
|
||||
printf("%d", a);
|
||||
foo();
|
||||
int i = 10;
|
||||
while (i != 0)
|
||||
{
|
||||
printf("%d", i);
|
||||
i -= 1;
|
||||
|
||||
}
|
||||
}
|
159
python-c-interpriter/main.py
Normal file
159
python-c-interpriter/main.py
Normal file
@ -0,0 +1,159 @@
|
||||
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()
|
4
python-c-interpriter/other.h
Normal file
4
python-c-interpriter/other.h
Normal file
@ -0,0 +1,4 @@
|
||||
void foo() {
|
||||
int x = 10;
|
||||
printf("%d", x);
|
||||
}
|
Loading…
Reference in New Issue
Block a user