diff options
author | elioat <elioat@tilde.institute> | 2025-01-19 11:11:30 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-01-19 11:11:30 -0500 |
commit | 3d7c196b4486b01ab399dff17b75483682fe4c35 (patch) | |
tree | 0e1ddf7ced568d47596e2354e2919515dbe8d7f2 | |
parent | 5fef9e4cb3fb6ea79245533eefc39a05884e7bc6 (diff) | |
download | tour-3d7c196b4486b01ab399dff17b75483682fe4c35.tar.gz |
*
-rwxr-xr-x | awk/vm/compiler.py | 82 | ||||
-rw-r--r-- | awk/vm/debug.coffee | 6 | ||||
-rw-r--r-- | awk/vm/simple.coffee | 4 | ||||
-rw-r--r-- | awk/vm/simple_test.coffee | 8 | ||||
-rw-r--r-- | awk/vm/stack_test.coffee | 15 | ||||
-rw-r--r-- | awk/vm/test_steps.coffee | 15 | ||||
-rwxr-xr-x | awk/vm/vm.awk | 49 |
7 files changed, 154 insertions, 25 deletions
diff --git a/awk/vm/compiler.py b/awk/vm/compiler.py index 4cd7b83..a406779 100755 --- a/awk/vm/compiler.py +++ b/awk/vm/compiler.py @@ -38,21 +38,38 @@ class Compiler: def compile_assignment(self, line): """Compile assignment statements like 'x = 5' or 'x = y + z'""" + # Remove any comments from the line + line = line.split('#')[0].strip() + 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 + print(f"# Compiling assignment: {var_name} = {expression}", file=sys.stderr) + + # First get the memory location mem_loc = self.allocate_variable(var_name) - # Compile the right-hand expression - vm_code = self.compile_expression(expression) + # Then compile the expression + expr_code = self.compile_expression(expression) + if not expr_code: + print(f"# Error: Failed to compile expression: {expression}", file=sys.stderr) + return None - # Store result in variable's memory location - vm_code.append(f"{mem_loc} !") + # Generate code that: + # 1. Evaluates the expression + # 2. Duplicates the result (for storing and leaving on stack) + # 3. Stores at memory location + vm_code = [] + vm_code.extend(expr_code) # Evaluate expression + vm_code.append("DUP") # Make a copy + vm_code.append(str(mem_loc)) # Push memory location + vm_code.append("@") # Read current value (for debugging) + vm_code.append("DROP") # Drop the old value + vm_code.append("!") # Store new value return vm_code @@ -60,6 +77,9 @@ class Compiler: """Compile expressions like '5', 'x + y', etc.""" vm_code = [] + # Remove any comments from the expression + expr = expr.split('#')[0].strip() + # Handle simple number if expr.isdigit(): vm_code.append(expr) @@ -74,39 +94,67 @@ class Compiler: # Handle binary operations ops = { '+': '+', - '*': '2*', # Note: This is a simplification - '-': 'NOT +', # This is a hack, proper subtraction would need more + '*': '*', + '-': 'NOT +', } + # Try each operator 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 + parts = expr.split(op, 1) + if len(parts) == 2: + left = parts[0].strip() + right = parts[1].strip() + + print(f"# Debug: left={left}, right={right}", file=sys.stderr) + + # Generate code for left operand + left_code = self.compile_expression(left) + if not left_code: + continue + vm_code.extend(left_code) + + # Generate code for right operand + right_code = self.compile_expression(right) + if not right_code: + continue + vm_code.extend(right_code) + + # Add the operation + vm_code.append(ops[op]) + return vm_code return vm_code def compile(self, source): """Compile source code to VM instructions""" output = [] + debug_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 line == "SHOW": + output.append("SHOW") + continue + if '=' in line: vm_code = self.compile_assignment(line) if vm_code: output.extend(vm_code) + debug_output.append(f"{' '.join(vm_code)} # {line}") + if not line.startswith('result ='): # If not final result + output.append("DROP") # Drop the duplicate we left on stack continue + + print("# Generated VM code:", file=sys.stderr) + for line in debug_output: + print(f"# {line}", file=sys.stderr) - # Other statement types can be added here - + # Add final SHOW to see the result + output.append("SHOW") return ' '.join(output) def main(): diff --git a/awk/vm/debug.coffee b/awk/vm/debug.coffee new file mode 100644 index 0000000..0663cec --- /dev/null +++ b/awk/vm/debug.coffee @@ -0,0 +1,6 @@ +x = 5 +SHOW +y = 3 +SHOW +z = x + y +SHOW \ No newline at end of file diff --git a/awk/vm/simple.coffee b/awk/vm/simple.coffee new file mode 100644 index 0000000..0a596a7 --- /dev/null +++ b/awk/vm/simple.coffee @@ -0,0 +1,4 @@ +x = 5 +y = 3 +z = x + y +result = z * 2 \ No newline at end of file diff --git a/awk/vm/simple_test.coffee b/awk/vm/simple_test.coffee new file mode 100644 index 0000000..8fec5ba --- /dev/null +++ b/awk/vm/simple_test.coffee @@ -0,0 +1,8 @@ +x = 5 +SHOW +y = 3 +SHOW +z = x + y # Should be 8 +SHOW +result = z * 2 # Should be 16 +SHOW \ No newline at end of file diff --git a/awk/vm/stack_test.coffee b/awk/vm/stack_test.coffee new file mode 100644 index 0000000..ab29e63 --- /dev/null +++ b/awk/vm/stack_test.coffee @@ -0,0 +1,15 @@ +# First store 5 in memory location 0 +x = 5 +SHOW + +# Then store 3 in memory location 1 +y = 3 +SHOW + +# Add them: load 5, load 3, add them +z = x + y +SHOW + +# Double z: load 8, multiply by 2 +result = z * 2 +SHOW \ No newline at end of file diff --git a/awk/vm/test_steps.coffee b/awk/vm/test_steps.coffee new file mode 100644 index 0000000..f1d0415 --- /dev/null +++ b/awk/vm/test_steps.coffee @@ -0,0 +1,15 @@ +# Step 1: Initialize x +x = 5 +SHOW + +# Step 2: Initialize y +y = 3 +SHOW + +# Step 3: Add x and y +z = x + y +SHOW + +# Step 4: Double z +result = z * 2 +SHOW \ No newline at end of file diff --git a/awk/vm/vm.awk b/awk/vm/vm.awk index 0d7565f..a130d88 100755 --- a/awk/vm/vm.awk +++ b/awk/vm/vm.awk @@ -33,6 +33,7 @@ function push(value) { print "Stack overflow!" > "/dev/stderr" exit 1 } + printf "# DEBUG: Pushing %d onto stack\n", value > "/dev/stderr" stack[stack_pointer++] = value } @@ -41,7 +42,9 @@ function pop() { print "Stack underflow!" > "/dev/stderr" exit 1 } - return stack[--stack_pointer] + value = stack[--stack_pointer] + printf "# DEBUG: Popping %d from stack\n", value > "/dev/stderr" + return value } # Basic stack manipulation @@ -69,7 +72,9 @@ function op_over() { function op_add() { b = pop() a = pop() - push(a + b) + result = a + b + printf "# DEBUG: Adding %d + %d = %d\n", a, b, result > "/dev/stderr" + push(result) } function op_and() { @@ -105,6 +110,14 @@ function op_2div() { push(int(a / 2)) } +function op_multiply() { + b = pop() + a = pop() + result = a * b + printf "# DEBUG: Multiplying %d * %d = %d\n", a, b, result > "/dev/stderr" + push(result) +} + # Register operations function op_a() { push(A) @@ -121,12 +134,15 @@ function op_bstore() { # Memory operations function op_fetch() { addr = pop() - push(memory[addr]) + value = memory[addr] + printf "# DEBUG: Fetching %d from memory[%d]\n", value, addr > "/dev/stderr" + push(value) } function op_store() { - value = pop() - addr = pop() + addr = pop() # First pop the address + value = pop() # Then pop the value + printf "# DEBUG: Storing %d at memory[%d]\n", value, addr > "/dev/stderr" memory[addr] = value } @@ -166,7 +182,23 @@ function print_state() { print_stack() printf "Registers: A=%d B=%d P=%d\n", A, B, P printf "Memory[P]=%d Memory[B]=%d\n", memory[P], memory[B] - printf "-------------------\n" + printf "Memory: " + for (i = 0; i < 4; i++) { # Show first 4 memory locations + printf "[%d]=%d ", i, memory[i] + } + printf "\n-------------------\n" +} + +function op_swap() { + if (stack_pointer < 2) { + print "Stack underflow on SWAP!" > "/dev/stderr" + exit 1 + } + # Swap the top two elements on the stack + temp = stack[stack_pointer - 1] + stack[stack_pointer - 1] = stack[stack_pointer - 2] + stack[stack_pointer - 2] = temp + printf "# DEBUG: Swapping top two stack elements\n" > "/dev/stderr" } function execute_instruction(inst) { @@ -186,6 +218,7 @@ function execute_instruction(inst) { if (inst == "NOT") { op_not(); return } if (inst == "2*") { op_2times(); return } # multiply-step if (inst == "2/") { op_2div(); return } # divide-step + if (inst == "*") { op_multiply(); return } if (inst == "A") { op_a(); return } # push A register if (inst == "A!") { op_astore(); return } # store A register if (inst == "B!") { op_bstore(); return } # store B register @@ -198,6 +231,8 @@ function execute_instruction(inst) { if (inst == "@P") { op_fetchp(); return } # fetch from memory at P if (inst == "!P") { op_storep(); return } # store to memory at P if (inst == ".") { return } # NO-OP + if (inst == "SHOW") { print_state(); return } + if (inst == "SWAP") { op_swap(); return } print "Unknown instruction: " inst > "/dev/stderr" exit 1 @@ -216,6 +251,4 @@ function execute_instruction(inst) { for (i = 1; i <= n; i++) { execute_instruction(words[i]) } - # Print state after each line of input - print_state() } |