about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-01-19 11:11:30 -0500
committerelioat <elioat@tilde.institute>2025-01-19 11:11:30 -0500
commit3d7c196b4486b01ab399dff17b75483682fe4c35 (patch)
tree0e1ddf7ced568d47596e2354e2919515dbe8d7f2
parent5fef9e4cb3fb6ea79245533eefc39a05884e7bc6 (diff)
downloadtour-3d7c196b4486b01ab399dff17b75483682fe4c35.tar.gz
*
-rwxr-xr-xawk/vm/compiler.py82
-rw-r--r--awk/vm/debug.coffee6
-rw-r--r--awk/vm/simple.coffee4
-rw-r--r--awk/vm/simple_test.coffee8
-rw-r--r--awk/vm/stack_test.coffee15
-rw-r--r--awk/vm/test_steps.coffee15
-rwxr-xr-xawk/vm/vm.awk49
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()
 }