diff options
author | elioat <elioat@tilde.institute> | 2025-01-19 10:52:07 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-01-19 10:52:07 -0500 |
commit | 5fef9e4cb3fb6ea79245533eefc39a05884e7bc6 (patch) | |
tree | 74ad72ce0fe19ceb95502a8112c1a4d0ed692066 | |
parent | 2ae79a0cf9d0f7439fac454d65e2cb8f962b7ca9 (diff) | |
download | tour-5fef9e4cb3fb6ea79245533eefc39a05884e7bc6.tar.gz |
*
-rwxr-xr-x | awk/vm/compiler.py | 124 | ||||
-rw-r--r-- | awk/vm/test.coffee | 7 |
2 files changed, 131 insertions, 0 deletions
diff --git a/awk/vm/compiler.py b/awk/vm/compiler.py new file mode 100755 index 0000000..4cd7b83 --- /dev/null +++ b/awk/vm/compiler.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +""" +A simple compiler that translates CoffeeScript-like syntax to VM instructions. +Example input: + + # Simple arithmetic + x = 5 + y = 3 + z = x + y + + # Using memory + array = [] + array[0] = 42 + array[1] = array[0] * 2 + +Will compile to VM instructions like: + + 5 A! # store 5 in A register + 3 B! # store 3 in B register + A @B + # add them +""" + +import sys +import re + +class Compiler: + def __init__(self): + self.variables = {} # Maps variable names to memory locations + self.next_memory = 0 # Next available memory location + + def allocate_variable(self, name): + """Allocate memory location for a variable""" + if name not in self.variables: + self.variables[name] = self.next_memory + self.next_memory += 1 + return self.variables[name] + + def compile_assignment(self, line): + """Compile assignment statements like 'x = 5' or 'x = y + z'""" + match = re.match(r'(\w+)\s*=\s*(.+)', line) + if not match: + return None + + var_name = match.group(1) + expression = match.group(2) + + # Allocate memory for the variable + mem_loc = self.allocate_variable(var_name) + + # Compile the right-hand expression + vm_code = self.compile_expression(expression) + + # Store result in variable's memory location + vm_code.append(f"{mem_loc} !") + + return vm_code + + def compile_expression(self, expr): + """Compile expressions like '5', 'x + y', etc.""" + vm_code = [] + + # Handle simple number + if expr.isdigit(): + vm_code.append(expr) + return vm_code + + # Handle variable reference + if expr in self.variables: + vm_code.append(str(self.variables[expr])) + vm_code.append("@") + return vm_code + + # Handle binary operations + ops = { + '+': '+', + '*': '2*', # Note: This is a simplification + '-': 'NOT +', # This is a hack, proper subtraction would need more + } + + for op in ops: + if op in expr: + left, right = expr.split(op) + vm_code.extend(self.compile_expression(left.strip())) + vm_code.extend(self.compile_expression(right.strip())) + vm_code.append(ops[op]) + return vm_code + + return vm_code + + def compile(self, source): + """Compile source code to VM instructions""" + output = [] + + for line in source.split('\n'): + # Skip empty lines and comments + line = line.strip() + if not line or line.startswith('#'): + continue + + # Handle assignment + if '=' in line: + vm_code = self.compile_assignment(line) + if vm_code: + output.extend(vm_code) + continue + + # Other statement types can be added here + + return ' '.join(output) + +def main(): + if len(sys.argv) > 1: + with open(sys.argv[1]) as f: + source = f.read() + else: + source = sys.stdin.read() + + compiler = Compiler() + vm_code = compiler.compile(source) + print(vm_code) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/awk/vm/test.coffee b/awk/vm/test.coffee new file mode 100644 index 0000000..aecda14 --- /dev/null +++ b/awk/vm/test.coffee @@ -0,0 +1,7 @@ +# Calculate sum +x = 5 +y = 3 +z = x + y + +# Double it +result = z * 2 |