about summary refs log tree commit diff stats
path: root/awk
diff options
context:
space:
mode:
Diffstat (limited to 'awk')
-rwxr-xr-xawk/forth/f.awk369
-rwxr-xr-xawk/forth/old/f.awk344
-rw-r--r--awk/forth/old/test.forth44
-rw-r--r--awk/forth/test.forth34
-rwxr-xr-xawk/retro/retro.awk250
-rwxr-xr-xawk/retro/test.awk52
-rwxr-xr-xawk/retro/vm.awk364
-rwxr-xr-xawk/scheme/s.awk139
-rw-r--r--awk/scheme/scheme/README.md220
-rw-r--r--awk/scheme/scheme/TODO.txt70
-rwxr-xr-xawk/scheme/scheme/bin/compiler.awk660
-rwxr-xr-xawk/scheme/scheme/bin/repl161
-rwxr-xr-xawk/scheme/scheme/bin/vm.awk997
-rw-r--r--awk/scheme/scheme/diagram.md91
-rw-r--r--awk/scheme/scheme/examples/cons.test.scm3
-rw-r--r--awk/scheme/scheme/examples/define.test.scm2
-rw-r--r--awk/scheme/scheme/examples/lambda.test.scm12
-rw-r--r--awk/scheme/scheme/examples/let-and-define.test.scm9
-rw-r--r--awk/scheme/scheme/examples/let.test.scm2
-rwxr-xr-xawk/scheme/scheme/scheme3
-rw-r--r--awk/scheme/scheme/scratch/arch-notes.md115
-rw-r--r--awk/scheme/scheme/scratch/complex_test.scm.asm44
-rw-r--r--awk/scheme/scheme/scratch/ideas-for-string-support.md556
-rw-r--r--awk/scheme/scheme/scratch/random.txt112
-rwxr-xr-xawk/scheme/scheme/scratch/run.sh5
-rw-r--r--awk/scheme/scheme/scratch/test.asm16
-rw-r--r--awk/scheme/scheme/scratch/test.scm8
-rw-r--r--awk/scheme/scheme/scratch/test.scm.asm7
-rw-r--r--awk/vm/README.md91
-rwxr-xr-xawk/vm/compiler.py172
-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.coffee7
-rw-r--r--awk/vm/test_steps.coffee15
-rwxr-xr-xawk/vm/vm.awk254
-rwxr-xr-xawk/vm/vm_tests.sh42
38 files changed, 5303 insertions, 0 deletions
diff --git a/awk/forth/f.awk b/awk/forth/f.awk
new file mode 100755
index 0000000..16de171
--- /dev/null
+++ b/awk/forth/f.awk
@@ -0,0 +1,369 @@
+#!/usr/bin/awk -f
+
+# I wanted to implement something non-trivial using awk. 
+# If I was clever I wouldn’t implement forth directly in awk,
+# instead I’d implement a simple virtual machine using awk, 
+# and then implement the forth using the virtual machine’s byte code
+# ...but there is only so much brain power I can exert on such a silly project.
+
+BEGIN {
+    # Initialize stacks and dictionaries
+    stack_ptr = 0
+    dict_size = 0
+    
+    # Built-in words, and some documentation (I could use stack comments,
+    # but I find those sort of unintuitive)
+    dict["+"] = "+     : Adds the top two numbers on the stack."
+    dict["-"] = "-     : Subtracts the top number from the second top number on the stack."
+    dict["*"] = "*     : Multiplies the top two numbers on the stack."
+    dict["/"] = "/     : Divides the second top number by the top number on the stack."
+    dict["."] = ".     : Prints the top of the stack."
+    dict[".s"] = ".s    : Shows all values on the stack."
+    dict["dup"] = "dup   : Duplicates the top value on the stack."
+    dict["drop"] = "drop  : Removes the top value from the stack."
+    dict["swap"] = "swap  : Swaps the top two values on the stack."
+    dict["over"] = "over  : Copies the second top value to the top of the stack."
+    dict["rot"] = "rot   : Rotates the top three values on the stack."
+    dict["="] = "=     : Compares the top two values for equality."
+    dict["<"] = "<     : Checks if the second top value is less than the top value."
+    dict[">"] = ">     : Checks if the second top value is greater than the top value."
+    dict["bye"] = "bye   : Exits the interpreter."
+    dict["words"] = "words : Lists all available words and their documentation."
+    
+    # State flags
+    compiling = 0
+    current_def = ""
+    def_name = ""
+    
+    # If an input file isn't specified, enter REPL mode
+    if (ARGC == 1) {
+        repl()
+    }
+}
+
+# Handle file input
+{
+    if (FILENAME ~ /\.forth$/) {
+        interpret($0)
+    }
+}
+
+function repl() {
+    print "f.awk! A forth interpreter.\nUse 'bye' to exit.\nUse 'words' to list all available words.\n"
+    while (1) {
+        printf "f> "
+        if (getline input < "/dev/tty" <= 0) break
+        interpret(input)
+    }
+}
+
+function interpret(line) {
+    gsub(/\(.*\)/, "", line)  # Remove everything from ( to )
+    gsub(/\\.*$/, "", line)   # Remove backslash comments, too
+
+    n = split(line, words, /[ \t]+/)
+    
+    for (i = 1; i <= n; i++) {
+        word = words[i]
+        if (word == "") continue
+        
+        # print "Processing word: " word
+        
+        if (word == ":") {
+            compiling = 1
+            i++
+            def_name = words[i]
+            current_def = ""
+            continue
+        }
+        
+        if (compiling) {
+            if (word == ";") {
+                # Store user-defined word with its name and definition
+                dict[def_name] = "word " current_def
+                compiling = 0
+                continue
+            }
+            current_def = current_def " " word
+            continue
+        }
+        
+        # Execute the word and skip further processing if it's .s
+        if (word == ".s") {
+            execute_word(word)
+            break  # Exit the loop after executing .s
+        }
+        
+        execute_word(word)
+    }
+}
+
+function execute_word(word) {
+    if (word ~ /^-?[0-9]+$/) {
+        push(word + 0)
+    } else if (word in dict) {
+        if (dict[word] ~ /^word /) {
+            # User-defined word
+            sequence = substr(dict[word], 6)
+            split(sequence, subwords, " ")
+            for (sw in subwords) {
+                if (subwords[sw] != "") {
+                    execute_word(subwords[sw])
+                }
+            }
+        } else {
+            # Built-in words
+            if (word == "+") math_add()
+            else if (word == "-") math_sub()
+            else if (word == "*") math_mul()
+            else if (word == "/") math_div()
+            else if (word == ".") stack_print()
+            else if (word == ".s") {
+                # print "Executing .s command"
+                stack_show()
+            }
+            else if (word == "dup") stack_dup()
+            else if (word == "drop") stack_drop()
+            else if (word == "swap") stack_swap()
+            else if (word == "over") stack_over()
+            else if (word == "rot") stack_rot()
+            else if (word == "=") compare_eq()
+            else if (word == "<") compare_lt()
+            else if (word == ">") compare_gt()
+            else if (word == "bye") exit_program()
+            else if (word == "words") list_words()
+            else if (word == "if") {
+                # Handle the if statement
+                if_condition = pop()
+                if (if_condition == 0) {
+                    # Skip to the next part until we find 'then' or 'else'
+                    skip_if = 1
+                }
+            }
+            else if (word == "else") {
+                # Handle the else statement
+                if (skip_if) {
+                    skip_if = 0  # Reset the skip flag
+                } else {
+                    # Skip to the next part until we find 'then'
+                    skip_else = 1
+                }
+            }
+            else if (word == "then") {
+                # End of the conditional
+                skip_if = 0
+                skip_else = 0
+            }
+        }
+    } else {
+        print "Error: Unknown word '" word "'"
+    }
+}
+
+function push(val) {
+    stack[stack_ptr++] = val
+}
+
+function pop() {
+    if (stack_ptr <= 0) {
+        print "Error: Stack underflow"
+        return 0
+    }
+    return stack[--stack_ptr]
+}
+
+function math_add() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a + b)
+}
+
+function math_sub() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a - b)
+}
+
+function math_mul() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a * b)
+}
+
+function math_div() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    if (b == 0) {
+        print "Error: Division by zero"
+        return
+    }
+    a = pop()
+    push(int(a / b))
+}
+
+function stack_print() {
+    if (stack_ptr < 1) {
+        print "Error: Stack underflow"
+        return
+    }
+    print pop()
+}
+
+function stack_show() {
+    print "<", stack_ptr, "> "
+    for (i = 0; i < stack_ptr; i++) {
+        printf "%s ", stack[i]
+    }
+    print ""
+    # print "Stack state after .s: "
+    # for (i = 0; i < stack_ptr; i++) {
+    #     print stack[i]
+    # }
+    # print ""
+}
+
+function stack_dup() {
+    if (stack_ptr < 1) {
+        print "Error: Stack underflow"
+        return
+    }
+    val = stack[stack_ptr - 1]
+    push(val)
+}
+
+function stack_drop() {
+    if (stack_ptr < 1) {
+        print "Error: Stack underflow"
+        return
+    }
+    pop()
+}
+
+function stack_swap() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(b)
+    push(a)
+}
+
+function stack_over() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a)
+    push(b)
+    push(a)
+}
+
+function stack_rot() {
+    if (stack_ptr < 3) {
+        print "Error: Stack underflow"
+        return
+    }
+    c = pop()
+    b = pop()
+    a = pop()
+    push(b)
+    push(c)
+    push(a)
+}
+
+function compare_eq() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a == b ? -1 : 0)
+}
+
+function compare_lt() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a < b ? -1 : 0)
+}
+
+function compare_gt() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
+    b = pop()
+    a = pop()
+    push(a > b ? -1 : 0)
+}
+
+function exit_program() {
+    print "Exiting program."
+    exit 0
+}
+
+function list_words() {
+    print "Available words:"
+    
+    # Separate arrays to hold built-in and user-defined words
+    split("", built_in_words)
+    split("", user_defined_words)
+    
+    for (w in dict) {
+        split(dict[w], parts, ": ")
+        if (parts[1] ~ /^word /) {
+            user_defined_words[w] = parts[2]
+        } else {
+            built_in_words[w] = parts[2]
+        }
+    }
+    
+    # Sort built-in words manually because I'm picky
+    n = 0
+    for (w in built_in_words) {
+        sorted_words[n++] = w
+    }
+    
+    for (i = 0; i < n; i++) {
+        for (j = i + 1; j < n; j++) {
+            if (sorted_words[i] > sorted_words[j]) {
+                temp = sorted_words[i]
+                sorted_words[i] = sorted_words[j]
+                sorted_words[j] = temp
+            }
+        }
+    }
+    
+    # First print the built-in words
+    for (i = 0; i < n; i++) {
+        print sorted_words[i] ": " built_in_words[sorted_words[i]]
+    }
+    
+    # Then print the user-defined words
+    for (w in user_defined_words) {
+        print w ": " user_defined_words[w] " ( User-defined )"
+    }
+}
\ No newline at end of file
diff --git a/awk/forth/old/f.awk b/awk/forth/old/f.awk
new file mode 100755
index 0000000..eed9774
--- /dev/null
+++ b/awk/forth/old/f.awk
@@ -0,0 +1,344 @@
+#!/usr/bin/awk -f
+
+# Forth interpreter in AWK
+
+BEGIN {
+    print "Welcome to the AWK Forth Interpreter!"
+    print "Type your commands below. Use 'bye' to quit."
+    # Initialize variables
+    top = -1  # Initialize stack pointer
+    
+    # Initialize the dictionary with basic words
+    words["+"] = "+"
+    words["-"] = "-"
+    words["*"] = "*"
+    words["/"] = "/"
+    words["dup"] = "dup"
+    words["over"] = "over"
+    words["swap"] = "swap"
+    words["."] = "."
+    words["bye"] = "bye"
+    words["rot"] = "rot"
+    words["drop"] = "drop"
+    words["nip"] = "nip"
+    words["tuck"] = "tuck"
+    words["roll"] = "roll"
+    words["pick"] = "pick"
+    words["negate"] = "negate"
+    words["abs"] = "abs"
+    words["max"] = "max"
+    words["min"] = "min"
+    words["mod"] = "mod"
+    words["="] = "="
+    words["see"] = "see"
+    words["if"] = "if"
+    words["then"] = "then"
+    words["else"] = "else"
+    words[">"] = ">"
+    words["<"] = "<"
+    
+    # Add handlers for all words
+    handlers["+"] = "add"
+    handlers["-"] = "subtract"
+    handlers["*"] = "multiply"
+    handlers["/"] = "divide"
+    handlers["dup"] = "dup"
+    handlers["over"] = "over"
+    handlers["swap"] = "swap"
+    handlers["."] = "print_top"
+    handlers["<"] = "less_than"
+    handlers[">"] = "greater_than"
+    handlers["rot"] = "rot"
+    handlers["drop"] = "drop"
+    handlers["nip"] = "nip"
+    handlers["tuck"] = "tuck"
+    handlers["roll"] = "roll"
+    handlers["pick"] = "pick"
+    handlers["negate"] = "negate"
+    handlers["abs"] = "abs"
+    handlers["max"] = "max"
+    handlers["min"] = "min"
+    handlers["mod"] = "mod"
+    handlers["="] = "equals"
+    handlers["if"] = "handle_if"
+    handlers["then"] = "handle_then"
+    handlers["else"] = "handle_else"
+    handlers["bye"] = "bye"
+    handlers["see"] = "see"
+
+    # Add descriptions for words
+    desc["+"] = "( n1 n2 -- sum ) Add top two numbers"
+    desc["-"] = "( n1 n2 -- diff ) Subtract top number from second"
+    desc["*"] = "( n1 n2 -- prod ) Multiply top two numbers"
+    desc["/"] = "( n1 n2 -- quot ) Divide second by top"
+    desc["dup"] = "( n -- n n ) Duplicate top of stack"
+    desc["over"] = "( n1 n2 -- n1 n2 n1 ) Copy second item to top"
+    desc["swap"] = "( n1 n2 -- n2 n1 ) Swap top two items"
+    desc["rot"] = "( n1 n2 n3 -- n2 n3 n1 ) Rotate top three items"
+    desc["drop"] = "( n -- ) Discard top item"
+    desc["nip"] = "( n1 n2 -- n2 ) Remove second item"
+    desc["tuck"] = "( n1 n2 -- n2 n1 n2 ) Copy top item below second"
+    desc["roll"] = "( nk ... n1 n0 k -- nk-1 ... n1 n0 nk ) Move kth item to top"
+    desc["pick"] = "( nk ... n1 n0 k -- nk ... n1 n0 nk ) Copy kth item to top"
+    desc["negate"] = "( n -- -n ) Negate number"
+    desc["abs"] = "( n -- |n| ) Absolute value"
+    desc["max"] = "( n1 n2 -- max ) Maximum of top two numbers"
+    desc["min"] = "( n1 n2 -- min ) Minimum of top two numbers"
+    desc["mod"] = "( n1 n2 -- rem ) Remainder of n1/n2"
+    desc["="] = "( n1 n2 -- flag ) Test if equal, leaves 1 if true, 0 if false"
+    desc["if"] = "( flag -- ) Begin conditional execution"
+    desc["then"] = "( -- ) End conditional execution"
+    desc["else"] = "( -- ) Execute if previous condition was false"
+    desc[">"] = "( n1 n2 -- flag ) Returns true if n1 is greater than n2"
+    desc["<"] = "( n1 n2 -- flag ) Returns true if n1 is less than n2"
+    desc["bye"] = "( -- ) Exit the interpreter"
+    desc["see"] = "( -- ) Show definition of a word"
+
+    # Initialize condition stack
+    cond_top = -1
+
+    # Mark these as compile-only words
+    compile_only["if"] = 1
+    compile_only["then"] = 1
+    compile_only["else"] = 1
+}
+
+# Stack operations
+function push(value) {
+    stack[++top] = value
+}
+
+function pop() {
+    if (top < 0) {
+        print "Error: Stack underflow"
+        return 0
+    }
+    return stack[top--]
+}
+
+function check_stack(min_items, error_msg) {
+    if (top < min_items - 1) {
+        print error_msg ? error_msg : "Error: Not enough values on stack"
+        return 0
+    }
+    return 1
+}
+
+# Binary operations
+function binary_op(operation) {
+    if (!check_stack(2)) return
+    second = pop()
+    first = pop()
+    if (operation == "+") push(first + second)
+    else if (operation == "-") push(first - second)
+    else if (operation == "*") push(first * second)
+    else if (operation == "/") {
+        if (second == 0) {
+            print "Error: Division by zero"
+            push(first)
+            push(second)
+            return
+        }
+        push(first / second)
+    }
+    else if (operation == "mod") push(first % second)
+    else if (operation == "=") push(first == second ? 1 : 0)
+    else if (operation == "<") push(first < second ? 1 : 0)
+    else if (operation == ">") push(first > second ? 1 : 0)
+}
+
+# Handler functions
+function add() { binary_op("+") }
+function subtract() { binary_op("-") }
+function multiply() { binary_op("*") }
+function divide() { binary_op("/") }
+function mod() { binary_op("mod") }
+function equals() { binary_op("=") }
+function less_than() { binary_op("<") }
+function greater_than() { binary_op(">") }
+
+function dup() {
+    if (!check_stack(1)) return
+    push(stack[top])
+}
+
+function over() {
+    if (!check_stack(2)) return
+    push(stack[top - 1])
+}
+
+function swap() {
+    if (!check_stack(2)) return
+    temp = pop()
+    second = pop()
+    push(temp)
+    push(second)
+}
+
+function rot() {
+    if (!check_stack(3)) return
+    third = pop()
+    second = pop()
+    first = pop()
+    push(second)
+    push(third)
+    push(first)
+}
+
+function drop() {
+    if (!check_stack(1)) return
+    top--
+}
+
+function nip() {
+    if (!check_stack(2)) return
+    temp = stack[top]
+    drop()
+    drop()
+    push(temp)
+}
+
+function tuck() {
+    if (!check_stack(2)) return
+    temp = pop()
+    second = pop()
+    push(temp)
+    push(second)
+    push(temp)
+}
+
+function roll() {
+    if (!check_stack(1)) return
+    n = int(pop())
+    if (!check_stack(n)) return
+    if (n <= 0) return
+
+    temp = stack[top - n + 1]
+    for (i = top - n + 1; i < top; i++) {
+        stack[i] = stack[i + 1]
+    }
+    stack[top] = temp
+}
+
+function pick() {
+    if (!check_stack(1)) return
+    n = int(pop())
+    if (!check_stack(n)) return
+    if (n < 0) return
+    push(stack[top - n])
+}
+
+function negate() {
+    if (!check_stack(1)) return
+    push(-pop())
+}
+
+function abs() {
+    if (!check_stack(1)) return
+    n = pop()
+    push(n < 0 ? -n : n)
+}
+
+function max() {
+    if (!check_stack(2)) return
+    b = pop()
+    a = pop()
+    push(a > b ? a : b)
+}
+
+function min() {
+    if (!check_stack(2)) return
+    b = pop()
+    a = pop()
+    push(a < b ? a : b)
+}
+
+function print_top() {
+    if (!check_stack(1)) return
+    print stack[top]
+    drop()
+}
+
+function bye() {
+    exit
+}
+
+function see(word) {
+    if (!(word in words)) {
+        print "Error: Word '" word "' not found"
+        return
+    }
+    if (word in desc) {
+        print desc[word]
+    }
+    if (word in raw_definitions) {
+        print ": " word " " raw_definitions[word] " ;"
+    }
+}
+
+# Main processing function
+function execute_word(word) {
+    if (word in handlers) {
+        handler = handlers[word]
+        if (handler == "bye") exit
+        else if (handler == "see") {
+            if (i + 1 <= NF) see($(++i))
+            else print "Error: see requires a word name"
+        }
+        else if (handler == "add") add()
+        else if (handler == "subtract") subtract()
+        else if (handler == "multiply") multiply()
+        else if (handler == "divide") divide()
+        else if (handler == "dup") dup()
+        else if (handler == "over") over()
+        else if (handler == "swap") swap()
+        else if (handler == "print_top") print_top()
+        else if (handler == "less_than") less_than()
+        else if (handler == "greater_than") greater_than()
+        else if (handler == "rot") rot()
+        else if (handler == "drop") drop()
+        else if (handler == "nip") nip()
+        else if (handler == "tuck") tuck()
+        else if (handler == "roll") roll()
+        else if (handler == "pick") pick()
+        else if (handler == "negate") negate()
+        else if (handler == "abs") abs()
+        else if (handler == "max") max()
+        else if (handler == "min") min()
+        else if (handler == "mod") mod()
+        else if (handler == "equals") equals()
+        else if (handler == "handle_if") handle_if()
+        else if (handler == "handle_then") handle_then()
+        else if (handler == "handle_else") handle_else()
+        else {
+            print "Error: Handler '" handler "' not implemented"
+            return 0
+        }
+        return 1
+    }
+    return 0
+}
+
+# Process each line of input
+{
+    if (NF > 0) {
+        # Remove comments and normalize whitespace
+        gsub(/\(.*\)/, "")
+        gsub(/^[[:space:]]+/, "")
+        gsub(/[[:space:]]+$/, "")
+        gsub(/[[:space:]]+/, " ")
+
+        # Process each token
+        for (i = 1; i <= NF; i++) {
+            if ($i ~ /^-?[0-9]+$/) {
+                push($i)
+            } else if ($i in words) {
+                if (!execute_word($i)) {
+                    print "Error: Failed to execute word '" $i "'"
+                }
+            } else {
+                print "Error: Unknown word '" $i "'"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/awk/forth/old/test.forth b/awk/forth/old/test.forth
new file mode 100644
index 0000000..a1f4f50
--- /dev/null
+++ b/awk/forth/old/test.forth
@@ -0,0 +1,44 @@
+( Basic arithmetic operations )
+2 3 + . ( expect: 5 )
+10 3 - . ( expect: 7 )
+4 5 * . ( expect: 20 )
+20 4 / . ( expect: 5 )
+7 3 mod . ( expect: 1 )
+
+( Stack manipulation operations )
+5 dup . . ( expect: 5 5 )
+1 2 swap . . ( expect: 2 1 )
+1 2 over . . . ( expect: 1 2 1 )
+1 2 3 rot . . . ( expect: 2 3 1 )
+1 2 3 4 2 roll . . . . ( expect: 1 3 4 2 )
+5 drop
+1 2 nip . ( expect: 2 )
+1 2 tuck . . . ( expect: 2 1 2 )
+
+( Comparison operations )
+5 3 > . ( expect: 1 )
+3 5 < . ( expect: 1 )
+4 4 = . ( expect: 1 )
+5 3 < . ( expect: 0 )
+3 5 > . ( expect: 0 )
+4 5 = . ( expect: 0 )
+
+( Math operations )
+5 negate . ( expect: -5 )
+-7 abs . ( expect: 7 )
+5 2 max . ( expect: 5 )
+5 2 min . ( expect: 2 )
+
+( Complex stack manipulations )
+1 2 3 4 5 \ Put 5 numbers on stack
+3 pick . ( expect: 2 )
+2 roll . ( expect: 4 )
+. . . . ( expect: 5 3 1 )
+
+( Error handling tests )
+drop drop drop drop drop \ Clear stack
+drop ( expect: Error: Stack underflow )
+. ( expect: Error: Stack underflow )
+5 0 / ( expect: Error: Division by zero )
+
+bye
\ No newline at end of file
diff --git a/awk/forth/test.forth b/awk/forth/test.forth
new file mode 100644
index 0000000..daa6943
--- /dev/null
+++ b/awk/forth/test.forth
@@ -0,0 +1,34 @@
+\ Test arithmetic operations
+10 5 + .          \ Should print 15
+10 5 - .          \ Should print 5
+10 5 * .          \ Should print 50
+10 5 / .          \ Should print 2
+
+\ Test stack manipulation
+1 2 3 .s          \ Should show 3 values: 1 2 3
+dup .             \ Should print 3 again
+drop .            \ Should print 2
+swap .s           \ Should show 2 1
+over .s           \ Should show 2 1 2
+rot .s            \ Should show 1 2 3
+
+\ Test comparisons
+5 5 = .           \ Should print -1 (true)
+5 3 < .          \ Should print 0 (false)
+3 5 > .          \ Should print 0 (false)
+
+\ Test conditionals within user-defined words
+: test_if 10 20 if .s then ;  \ Should print 1 2 (since the condition is true)
+: test_else 10 5 if .s else 1 then ;  \ Should print 1 (since the condition is false)
+
+\ Test user-defined words
+: square dup * ;   \ Define a word to square a number
+4 square .         \ Should print 16
+
+: add_three 1 2 + + ;  \ Define a word to add three numbers
+1 2 add_three .    \ Should print 6
+
+\ List all words
+words              \ Should list all available words
+
+bye                \ Exit the interpreter 
\ No newline at end of file
diff --git a/awk/retro/retro.awk b/awk/retro/retro.awk
new file mode 100755
index 0000000..2a14ff0
--- /dev/null
+++ b/awk/retro/retro.awk
@@ -0,0 +1,250 @@
+#!/usr/bin/awk -f
+
+# Constants and VM setup
+BEGIN {
+    IMAGE_SIZE = 524288    # Amount of simulated RAM
+    DATA_DEPTH = 8192      # Depth of data stack
+    ADDRESS_DEPTH = 32768  # Depth of the stacks
+    
+    # Initialize stacks
+    data_sp = 0
+    addr_sp = 0
+    
+    # VM state
+    ip = 0
+    
+    # Opcode definitions
+    OP_NOP = 0
+    OP_LIT = 1
+    OP_DUP = 2
+    OP_DROP = 3
+    OP_SWAP = 4
+    OP_PUSH = 5
+    OP_POP = 6
+    OP_JUMP = 7
+    OP_CALL = 8
+    OP_CCALL = 9
+    OP_RETURN = 10
+    OP_EQ = 11
+    OP_NEQ = 12
+    OP_LT = 13
+    OP_GT = 14
+    OP_FETCH = 15
+    OP_STORE = 16
+    OP_ADD = 17
+    OP_SUB = 18
+    OP_MUL = 19
+    OP_DIVMOD = 20
+    OP_AND = 21
+    OP_OR = 22
+    OP_XOR = 23
+    OP_SHIFT = 24
+    OP_ZERO_EXIT = 25
+    OP_HALT = 26
+    
+    # Initialize VM
+    prepare_vm()
+    
+    # Load and run test program
+    load_test_program()
+    execute(0)
+    
+    # Print results
+    print "Stack contents after execution:"
+    print_stack()
+}
+
+# Stack operations
+function stack_push(stack_name, value) {
+    if (stack_name == "data") {
+        data_sp++
+        data_stack[data_sp] = value
+    } else if (stack_name == "addr") {
+        addr_sp++
+        addr_stack[addr_sp] = value
+    }
+}
+
+function stack_pop(stack_name) {
+    if (stack_name == "data") {
+        if (data_sp > 0) {
+            value = data_stack[data_sp]
+            data_sp--
+            return value
+        }
+    } else if (stack_name == "addr") {
+        if (addr_sp > 0) {
+            value = addr_stack[addr_sp]
+            addr_sp--
+            return value
+        }
+    }
+    return 0
+}
+
+function stack_tos(stack_name) {
+    if (stack_name == "data" && data_sp > 0) {
+        return data_stack[data_sp]
+    }
+    return 0
+}
+
+function stack_nos(stack_name) {
+    if (stack_name == "data" && data_sp > 1) {
+        return data_stack[data_sp - 1]
+    }
+    return 0
+}
+
+# Bitwise operations
+function bitwise_and(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a == 1 && b == 1)
+            result += 2 ^ i
+    }
+    return result
+}
+
+function bitwise_or(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a == 1 || b == 1)
+            result += 2 ^ i
+    }
+    return result
+}
+
+function bitwise_xor(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a != b)
+            result += 2 ^ i
+    }
+    return result
+}
+
+# Helper functions
+function abs(x) {
+    return x < 0 ? -x : x
+}
+
+function lshift(x, n) {
+    return int(x * (2 ^ n))
+}
+
+function rshift(x, n) {
+    return int(x / (2 ^ n))
+}
+
+# VM core functions
+function process_opcode(opcode) {
+    if (opcode == OP_NOP) {
+        return
+    }
+    else if (opcode == OP_LIT) {
+        ip++
+        stack_push("data", image[ip])
+    }
+    else if (opcode == OP_DUP) {
+        stack_push("data", stack_tos("data"))
+    }
+    else if (opcode == OP_DROP) {
+        stack_pop("data")
+    }
+    else if (opcode == OP_SWAP) {
+        temp = stack_pop("data")
+        temp2 = stack_pop("data")
+        stack_push("data", temp)
+        stack_push("data", temp2)
+    }
+    else if (opcode == OP_ADD) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", x + y)
+    }
+    else if (opcode == OP_SUB) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", y - x)
+    }
+    else if (opcode == OP_MUL) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", x * y)
+    }
+    else if (opcode == OP_HALT) {
+        ip = IMAGE_SIZE
+    }
+}
+
+function check_stack() {
+    if (data_sp < 0 || addr_sp < 0 || 
+        data_sp > DATA_DEPTH || addr_sp > ADDRESS_DEPTH) {
+        ip = 0
+        data_sp = 0
+        addr_sp = 0
+    }
+}
+
+function process_packed_opcodes(packed) {
+    ops[0] = bitwise_and(packed, 255)
+    ops[1] = bitwise_and(rshift(packed, 8), 255)
+    ops[2] = bitwise_and(rshift(packed, 16), 255)
+    ops[3] = bitwise_and(rshift(packed, 24), 255)
+    
+    for (i = 0; i < 4; i++) {
+        if (ops[i] != 0) {
+            process_opcode(ops[i])
+        }
+    }
+}
+
+function execute(offset) {
+    addr_sp = 1
+    ip = offset
+    
+    while (ip < IMAGE_SIZE) {
+        opcode = image[ip]
+        process_packed_opcodes(opcode)
+        
+        if (addr_sp == 0)
+            ip = IMAGE_SIZE
+            
+        ip++
+    }
+}
+
+function prepare_vm() {
+    ip = 0
+    data_sp = 0
+    addr_sp = 0
+}
+
+# Test program loader
+function pack_opcodes(op1, op2, op3, op4) {
+    return op1 + (op2 * 256) + (op3 * 65536) + (op4 * 16777216)
+}
+
+function load_test_program() {
+    # Simple test program that adds 10 and 5
+    image[0] = pack_opcodes(OP_LIT, 0, 0, 0)  # Push literal
+    image[1] = 10                             # Value 10
+    image[2] = pack_opcodes(OP_LIT, 0, 0, 0)  # Push literal
+    image[3] = 5                              # Value 5
+    image[4] = pack_opcodes(OP_ADD, 0, 0, 0)  # Add them
+    image[5] = pack_opcodes(OP_HALT, 0, 0, 0) # Halt
+}
+
+# Debug helper
+function print_stack() {
+    for (i = 1; i <= data_sp; i++) {
+        print "Item", i ":", data_stack[i]
+    }
+}
\ No newline at end of file
diff --git a/awk/retro/test.awk b/awk/retro/test.awk
new file mode 100755
index 0000000..191fa5b
--- /dev/null
+++ b/awk/retro/test.awk
@@ -0,0 +1,52 @@
+#!/usr/bin/awk -f
+
+@include "vm.awk"
+
+# Complex test program
+BEGIN {
+    # Test program to calculate factorial of 5
+    i = 0
+    
+    # Push 5 onto stack
+    image[i++] = pack_opcodes(OP_LIT, 0, 0, 0)
+    image[i++] = 5
+    
+    # Push 1 onto stack (accumulator)
+    image[i++] = pack_opcodes(OP_LIT, 0, 0, 0)
+    image[i++] = 1
+    
+    # Start of multiplication loop
+    loop_start = i
+    
+    # Duplicate top number (counter)
+    image[i++] = pack_opcodes(OP_DUP, 0, 0, 0)
+    
+    # Test if counter is zero
+    image[i++] = pack_opcodes(OP_ZERO_EXIT, 0, 0, 0)
+    
+    # Multiply accumulator by counter
+    image[i++] = pack_opcodes(OP_MUL, 0, 0, 0)
+    
+    # Decrement counter
+    image[i++] = pack_opcodes(OP_LIT, 0, 0, 0)
+    image[i++] = 1
+    image[i++] = pack_opcodes(OP_SUB, 0, 0, 0)
+    
+    # Jump back to start of loop
+    image[i++] = pack_opcodes(OP_LIT, 0, 0, 0)
+    image[i++] = loop_start
+    image[i++] = pack_opcodes(OP_JUMP, 0, 0, 0)
+    
+    # Halt
+    image[i++] = pack_opcodes(OP_HALT, 0, 0, 0)
+    
+    # Execute program
+    execute(0)
+    
+    # Print result (should be 120 - factorial of 5)
+    print "Factorial of 5:", stack_tos("data")
+}
+
+function pack_opcodes(op1, op2, op3, op4) {
+    return op1 + (op2 * 256) + (op3 * 65536) + (op4 * 16777216)
+}
\ No newline at end of file
diff --git a/awk/retro/vm.awk b/awk/retro/vm.awk
new file mode 100755
index 0000000..cd894c5
--- /dev/null
+++ b/awk/retro/vm.awk
@@ -0,0 +1,364 @@
+#!/usr/bin/awk -f
+
+# Constants
+BEGIN {
+    IMAGE_SIZE = 524288    # Amount of simulated RAM
+    DATA_DEPTH = 8192      # Depth of data stack
+    ADDRESS_DEPTH = 32768  # Depth of the stacks
+    
+    # Initialize stacks
+    data_sp = 0
+    addr_sp = 0
+    
+    # VM state
+    ip = 0
+    
+    # Opcode definitions
+    OP_NOP = 0
+    OP_LIT = 1
+    OP_DUP = 2
+    OP_DROP = 3
+    OP_SWAP = 4
+    OP_PUSH = 5
+    OP_POP = 6
+    OP_JUMP = 7
+    OP_CALL = 8
+    OP_CCALL = 9
+    OP_RETURN = 10
+    OP_EQ = 11
+    OP_NEQ = 12
+    OP_LT = 13
+    OP_GT = 14
+    OP_FETCH = 15
+    OP_STORE = 16
+    OP_ADD = 17
+    OP_SUB = 18
+    OP_MUL = 19
+    OP_DIVMOD = 20
+    OP_AND = 21
+    OP_OR = 22
+    OP_XOR = 23
+    OP_SHIFT = 24
+    OP_ZERO_EXIT = 25
+    OP_HALT = 26
+    OP_IE = 27
+    OP_IQ = 28
+    OP_II = 29
+}
+
+# Stack operations
+function stack_push(stack_name, value) {
+    if (stack_name == "data") {
+        data_sp++
+        data_stack[data_sp] = value
+    } else if (stack_name == "addr") {
+        addr_sp++
+        addr_stack[addr_sp] = value
+    }
+}
+
+function stack_pop(stack_name) {
+    if (stack_name == "data") {
+        if (data_sp > 0) {
+            value = data_stack[data_sp]
+            data_sp--
+            return value
+        }
+    } else if (stack_name == "addr") {
+        if (addr_sp > 0) {
+            value = addr_stack[addr_sp]
+            addr_sp--
+            return value
+        }
+    }
+    return 0
+}
+
+function stack_tos(stack_name) {
+    if (stack_name == "data" && data_sp > 0) {
+        return data_stack[data_sp]
+    }
+    return 0
+}
+
+function stack_nos(stack_name) {
+    if (stack_name == "data" && data_sp > 1) {
+        return data_stack[data_sp - 1]
+    }
+    return 0
+}
+
+# Bitwise operation implementations
+function bitwise_and(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a == 1 && b == 1)
+            result += 2 ^ i
+    }
+    return result
+}
+
+function bitwise_or(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a == 1 || b == 1)
+            result += 2 ^ i
+    }
+    return result
+}
+
+function bitwise_xor(x, y,    i, result, a, b) {
+    result = 0
+    for (i = 0; i < 32; i++) {
+        a = int(x / (2 ^ i)) % 2
+        b = int(y / (2 ^ i)) % 2
+        if (a != b)
+            result += 2 ^ i
+    }
+    return result
+}
+
+function lshift(x, n) {
+    return int(x * (2 ^ n))
+}
+
+function rshift(x, n) {
+    return int(x / (2 ^ n))
+}
+
+# VM instruction implementations
+function process_opcode(opcode) {
+    if (opcode == OP_NOP) {
+        return
+    }
+    else if (opcode == OP_LIT) {
+        ip++
+        stack_push("data", image[ip])
+    }
+    else if (opcode == OP_DUP) {
+        stack_push("data", stack_tos("data"))
+    }
+    else if (opcode == OP_DROP) {
+        stack_pop("data")
+    }
+    else if (opcode == OP_SWAP) {
+        temp = stack_pop("data")
+        temp2 = stack_pop("data")
+        stack_push("data", temp)
+        stack_push("data", temp2)
+    }
+    else if (opcode == OP_PUSH) {
+        stack_push("addr", stack_pop("data"))
+    }
+    else if (opcode == OP_POP) {
+        stack_push("data", stack_pop("addr"))
+    }
+    else if (opcode == OP_JUMP) {
+        ip = stack_pop("data") - 1
+    }
+    else if (opcode == OP_CALL) {
+        stack_push("addr", ip)
+        ip = stack_pop("data") - 1
+    }
+    else if (opcode == OP_CCALL) {
+        a = stack_pop("data")
+        b = stack_pop("data")
+        if (b != 0) {
+            stack_push("addr", ip)
+            ip = a - 1
+        }
+    }
+    else if (opcode == OP_RETURN) {
+        ip = stack_pop("addr")
+    }
+    else if (opcode == OP_EQ) {
+        a = stack_pop("data")
+        b = stack_pop("data")
+        stack_push("data", (b == a) ? -1 : 0)
+    }
+    else if (opcode == OP_NEQ) {
+        a = stack_pop("data")
+        b = stack_pop("data")
+        stack_push("data", (b != a) ? -1 : 0)
+    }
+    else if (opcode == OP_LT) {
+        a = stack_pop("data")
+        b = stack_pop("data")
+        stack_push("data", (b < a) ? -1 : 0)
+    }
+    else if (opcode == OP_GT) {
+        a = stack_pop("data")
+        b = stack_pop("data")
+        stack_push("data", (b > a) ? -1 : 0)
+    }
+    else if (opcode == OP_FETCH) {
+        x = stack_pop("data")
+        if (x == -1)
+            stack_push("data", data_sp)
+        else if (x == -2)
+            stack_push("data", addr_sp)
+        else if (x == -3)
+            stack_push("data", IMAGE_SIZE)
+        else if (x == -4)
+            stack_push("data", -2147483648)
+        else if (x == -5)
+            stack_push("data", 2147483647)
+        else
+            stack_push("data", image[x])
+    }
+    else if (opcode == OP_STORE) {
+        addr = stack_pop("data")
+        value = stack_pop("data")
+        image[addr] = value
+    }
+    else if (opcode == OP_ADD) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", x + y)
+    }
+    else if (opcode == OP_SUB) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", y - x)
+    }
+    else if (opcode == OP_MUL) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", y * x)
+    }
+    else if (opcode == OP_DIVMOD) {
+        b = stack_pop("data")
+        a = stack_pop("data")
+        if (b == 0) {
+            ip = 0
+            data_sp = 0
+            addr_sp = 0
+        } else {
+            x = abs(b)
+            y = abs(a)
+            q = int(y / x)
+            r = y % x
+            if (a < 0 && b < 0)
+                r = r * -1
+            if (a > 0 && b < 0)
+                q = q * -1
+            if (a < 0 && b > 0) {
+                r = r * -1
+                q = q * -1
+            }
+            stack_push("data", r)
+            stack_push("data", q)
+        }
+    }
+    else if (opcode == OP_AND) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", bitwise_and(x, y))
+    }
+    else if (opcode == OP_OR) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", bitwise_or(x, y))
+    }
+    else if (opcode == OP_XOR) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        stack_push("data", bitwise_xor(x, y))
+    }
+    else if (opcode == OP_SHIFT) {
+        x = stack_pop("data")
+        y = stack_pop("data")
+        if (x < 0)
+            stack_push("data", lshift(y, -x))
+        else
+            stack_push("data", rshift(y, x))
+    }
+    else if (opcode == OP_ZERO_EXIT) {
+        if (stack_tos("data") == 0) {
+            stack_pop("data")
+            ip = stack_pop("addr")
+        }
+    }
+    else if (opcode == OP_HALT) {
+        ip = IMAGE_SIZE
+    }
+    
+    check_stack()
+}
+
+# Helper functions
+function abs(x) {
+    return x < 0 ? -x : x
+}
+
+function check_stack() {
+    if (data_sp < 0 || addr_sp < 0 || 
+        data_sp > DATA_DEPTH || addr_sp > ADDRESS_DEPTH) {
+        ip = 0
+        data_sp = 0
+        addr_sp = 0
+    }
+}
+
+function process_packed_opcodes(packed) {
+    ops[0] = bitwise_and(packed, 255)
+    ops[1] = bitwise_and(rshift(packed, 8), 255)
+    ops[2] = bitwise_and(rshift(packed, 16), 255)
+    ops[3] = bitwise_and(rshift(packed, 24), 255)
+    
+    for (i = 0; i < 4; i++) {
+        if (ops[i] != 0) {
+            process_opcode(ops[i])
+        }
+    }
+}
+
+# Main execution function
+function execute(offset) {
+    addr_sp = 1
+    ip = offset
+    
+    while (ip < IMAGE_SIZE) {
+        opcode = image[ip]
+        process_packed_opcodes(opcode)
+        
+        if (addr_sp == 0)
+            ip = IMAGE_SIZE
+            
+        ip++
+    }
+}
+
+# String handling functions
+function string_inject(str, buffer,    i, len) {
+    len = length(str)
+    for (i = 1; i <= len; i++) {
+        image[buffer + i - 1] = ord(substr(str, i, 1))
+        image[buffer + i] = 0
+    }
+}
+
+function string_extract(at,    str, i) {
+    str = ""
+    i = at
+    while (image[i] != 0) {
+        str = str chr(image[i])
+        i++
+    }
+    return str
+}
+
+# Initialize VM
+BEGIN {
+    prepare_vm()
+}
+
+function prepare_vm() {
+    ip = 0
+    data_sp = 0
+    addr_sp = 0
+}
\ No newline at end of file
diff --git a/awk/scheme/s.awk b/awk/scheme/s.awk
new file mode 100755
index 0000000..7c8bba6
--- /dev/null
+++ b/awk/scheme/s.awk
@@ -0,0 +1,139 @@
+#!/usr/bin/awk -f
+
+# Set debug mode
+DEBUG = 1  # Change to 0 to disable debug output
+
+# Environment to store variable bindings
+BEGIN {
+    print "Welcome to the AWK Scheme Interpreter!"
+    print "Type your Scheme expressions below (type 'exit' to quit):"
+    while (1) {
+        printf "> "
+        if (getline input <= 0) {
+            print "Error reading input. Exiting."
+            break
+        }
+        if (input == "exit") {
+            print "Exiting the interpreter."
+            exit
+        }
+        if (input == "") {
+            print "Empty input received, continuing..."
+            continue
+        }
+        
+        print "Input received: " input  # Echo the input
+        ast = parse(input)  # Parse the input
+        
+        # Print the entire AST for debugging
+        for (i = 1; i <= length(ast); i++) {
+            print "AST[" i "] = " ast[i]
+        }
+        
+        # Evaluate the AST
+        if (length(ast) > 0) {
+            result = eval(ast)  # Evaluate the AST
+            print "Result: " result  # Print the result
+        } else {
+            print "Parsed AST is empty."
+        }
+    }
+}
+
+# Function to parse input into an AST
+function parse(input) {
+    # Remove outer whitespace
+    gsub(/^\s+|\s+$/, "", input)
+    
+    # Check if input is empty after trimming
+    if (input == "") {
+        print "Input is empty after trimming"
+        return ""
+    }
+    
+    # Debugging: Print input before processing
+    print "Debug: Raw input for parsing: " input
+    
+    # Remove parentheses at start and end
+    if (substr(input, 1, 1) == "(") {
+        input = substr(input, 2)
+    }
+    if (substr(input, length(input), 1) == ")") {
+        input = substr(input, 1, length(input) - 1)
+    }
+    
+    # Debugging: Print input after removing outer parentheses
+    print "Debug: Input after removing outer parentheses: " input
+    
+    # Split the input into tokens
+    gsub(/\(/, " ( ", input)
+    gsub(/\)/, " ) ", input)
+    gsub(/\s+/, " ", input)  # normalize whitespace
+    gsub(/^\s+|\s+$/, "", input)  # trim
+    
+    # Debugging: Print input after tokenization
+    print "Debug: Input after tokenization: " input
+    
+    n = split(input, ast, " ")
+    
+    # Debugging: Print the number of tokens
+    print "Debug: Number of tokens: " n
+    
+    return ast
+}
+
+# Function to evaluate the AST
+function eval(ast,    i, result) {
+    # Debugging: Print the current AST being evaluated
+    print "Debug: Evaluating AST: " ast[1] " " ast[2] " " ast[3]
+    
+    # Handle numbers directly
+    if (ast[1] ~ /^[+-]?[0-9]+$/) {
+        print "Debug: Returning number: " ast[1]
+        return ast[1] + 0  # Convert string to number
+    }
+    
+    # Handle addition
+    if (ast[1] == "+") {
+        result = 0
+        for (i = 2; i <= length(ast); i++) {
+            print "Debug: Adding operand: " ast[i]
+            result += eval(ast[i])  # Recursively evaluate operands
+        }
+        return result
+    }
+    
+    # Handle subtraction
+    if (ast[1] == "-") {
+        result = eval(ast[2])  # Start with the first operand
+        for (i = 3; i <= length(ast); i++) {
+            print "Debug: Subtracting operand: " ast[i]
+            result -= eval(ast[i])  # Subtract subsequent operands
+        }
+        return result
+    }
+    
+    # Handle multiplication
+    if (ast[1] == "*") {
+        result = 1
+        for (i = 2; i <= length(ast); i++) {
+            print "Debug: Multiplying operand: " ast[i]
+            result *= eval(ast[i])  # Multiply operands
+        }
+        return result
+    }
+    
+    # Handle division
+    if (ast[1] == "/") {
+        result = eval(ast[2])  # Start with the first operand
+        for (i = 3; i <= length(ast); i++) {
+            print "Debug: Dividing by operand: " ast[i]
+            result /= eval(ast[i])  # Divide by subsequent operands
+        }
+        return result
+    }
+    
+    # If we reach here, the operation is not recognized
+    return "Error: Unknown operation " ast[1]
+}
+
diff --git a/awk/scheme/scheme/README.md b/awk/scheme/scheme/README.md
new file mode 100644
index 0000000..5dae265
--- /dev/null
+++ b/awk/scheme/scheme/README.md
@@ -0,0 +1,220 @@
+# Awk-Scheme
+
+## Overview
+A scheme interpreter implemented in AWK:
+
+- A compiler that translates scheme expressions to stack-based VM instructions
+- A virtual machine that executes the compiled code
+- Support for basic arithmetic, list operations, functions, and variable bindings
+- **Closure support** for nested function definitions and lexical scoping
+- Persistent global state between REPL sessions
+
+## Architecture
+
+### Components
+1. **Compiler** (`bin/compiler.awk`):
+   - Lexical analyzer for tokenizing input
+   - Recursive descent parser for scheme expressions
+   - Code generator that produces stack-based VM instructions
+   - Handles nested expressions and proper scoping
+   - **Generates closure creation code for lambda expressions**
+
+2. **Virtual Machine** (`bin/vm.awk`):
+   - Stack-based execution model
+   - Typed value system with runtime type checking
+   - Environment-based variable binding
+   - **Direct function execution** (no program array modification)
+   - **Closure support** with environment capture and restoration
+   - Heap memory for cons cells
+   - State persistence for globals and functions
+
+3. **REPL** (`bin/repl`):
+   - Interactive command line interface
+   - Multi-line input support
+   - State persistence between sessions
+   - Debug mode support
+
+### Data Types
+All values are tagged with their type:
+- `N:value` - Numbers (integers)
+- `B:value` - Booleans (0/1)
+- `P:index` - Pairs (cons cells)
+- `F:name` - Functions
+- `NIL:` - Empty list
+- `S:name` - Symbols
+- **`CLOSURE:func_name:env_id` - Closure objects (function + captured environment)**
+
+## Usage
+
+### Running the REPL
+```bash
+# Start interactive REPL
+./scheme
+
+# Run a Scheme file
+./scheme myprogram.scm
+
+# Enable debug output
+DEBUG=1 ./scheme
+```
+
+### Basic Operations
+
+1. **Arithmetic**:
+```scheme
+scheme> (+ 1 2 3)
+N:6
+scheme> (* 4 (- 10 5))
+N:20
+```
+
+2. **Comparisons**:
+```scheme
+scheme> (< 1 2)
+B:1
+scheme> (= 42 42)
+B:1
+```
+
+3. **Lists**:
+```scheme
+scheme> (cons 1 (cons 2 nil))
+P:1
+scheme> (car (cons 1 2))
+N:1
+```
+
+4. **Variables**:
+```scheme
+scheme> (define x 42)
+N:42
+scheme> x
+N:42
+```
+
+5. **Functions**:
+```scheme
+scheme> (define add (x y) (+ x y))
+scheme> (add 2 3)
+N:5
+```
+
+6. **Let Expressions**:
+```scheme
+scheme> (let ((x 10) (y 20)) (+ x y))
+N:30
+```
+
+7. **Lambda Functions**:
+```scheme
+scheme> ((lambda (x) (+ x 1)) 41)
+N:42
+scheme> ((lambda (x y) (+ x y)) 20 22)
+N:42
+```
+
+8. **Closures**:
+```scheme
+scheme> (let ((x 10)) ((lambda (y) (+ x y)) 32))
+N:42
+scheme> (let ((add1 (lambda (x) (+ x 1)))) (add1 41))
+N:42
+```
+
+**Note**: Nested lambda definitions (lambdas defined inside other lambdas) are not yet supported.
+
+## Implementation Details
+
+### Compiler Pipeline
+1. **Lexical Analysis**:
+   - Tokenizes input into numbers, symbols, and parentheses
+   - Handles whitespace and basic comments
+
+2. **Parsing**:
+   - Builds expression tree from tokens
+   - Validates syntax and expression structure
+
+3. **Code Generation**:
+   - Translates expressions to VM instructions
+   - Manages scope and variable bindings
+   - Handles function definitions
+   - **Generates closure creation code for lambda expressions**
+
+### Virtual Machine
+1. **Stack Operations**:
+   - PUSH_CONST: Push constant value
+   - POP: Remove top value
+   - STORE: Store variable binding
+   - LOOKUP: Retrieve variable value
+
+2. **Function Calls**:
+   - **Direct execution** of function code with proper program restoration
+   - Environment frame management
+   - **Closure support** with environment capture and restoration
+
+3. **Closure System**:
+   - **CAPTURE_ENV**: Captures current environment for closure creation
+   - **Environment restoration**: Restores captured environments on closure calls
+   - **Variable lookup enhancement**: Checks closure environments for variable resolution
+
+4. **Memory Management**:
+   - Stack-based evaluation
+   - Simple heap for cons cells
+   - Basic reference counting (not fully implemented)
+
+### State Persistence
+- Global variables and functions persist between sessions
+- State stored in `/tmp/scheme_vm.state` and `/tmp/scheme_vm.env`
+- Automatic state loading/saving
+- **Note**: State persistence is enabled by default in the REPL
+
+## Extending the System
+
+### Adding New Special Forms
+1. Add parsing in `compile_expr()`
+2. Implement code generation function
+3. Add corresponding VM instructions if needed
+
+### Adding New Data Types
+1. Define new type tag in VM
+2. Add type checking predicates
+3. Implement value construction/access
+4. Update relevant operations
+
+### Adding VM Instructions
+1. Add instruction handling in `execute()`
+2. Implement instruction logic
+3. Update compiler to generate new instruction
+
+### Debugging
+- Enable debug output: `DEBUG=1 ./scheme`
+- Debug messages show:
+  - Lexical analysis
+  - Parsing steps
+  - Code generation
+  - VM execution
+  - Stack operations
+  - Environment changes
+  - **Closure creation and restoration**
+- **Note**: Some debug output may be suppressed in the current implementation
+
+## Limitations
+Current implementation does not support:
+- **Nested lambda definitions** (lambdas defined inside other lambdas) - this causes "Undefined closure function" errors
+- Floating point numbers
+- Strings
+- Proper tail recursion
+- Garbage collection
+- Error recovery in REPL
+- Full numeric tower
+- Macros
+- Standard library
+
+## Future Enhancements
+1. **Nested lambda support** (complex but achievable)
+2. Proper tail call optimization
+3. Garbage collection
+4. Error recovery
+5. More data types
+6. Standard library
+7. Better debugging tools
\ No newline at end of file
diff --git a/awk/scheme/scheme/TODO.txt b/awk/scheme/scheme/TODO.txt
new file mode 100644
index 0000000..f576fba
--- /dev/null
+++ b/awk/scheme/scheme/TODO.txt
@@ -0,0 +1,70 @@
+Scheme Interpreter TODO
+=====================
+
+Current State:
+-------------
+- Basic arithmetic operations (+,-,*,/) are working
+- Let expressions with simple bindings are working
+- Function definitions (define) and lambda expressions are implemented (no nested lambdas)
+- Stack-based virtual machine with environment for variable bindings
+- Closures supported for top-level lambdas (not nested)
+- State persistence for globals and functions between REPL sessions
+
+Recent Changes:
+--------------
+1. Improved function table and environment handling
+2. Enhanced debug logging for function calls and environment
+3. Refined lambda compilation and closure creation
+4. Updated documentation and architectural notes
+
+Current Issues / Limitations:
+----------------------------
+1. **Nested Lambda Support**:
+   - Lambdas defined inside other lambdas are not supported ("Undefined closure function" errors)
+2. **Reference Counting**:
+   - Reference counting for heap objects (cons cells) is stubbed but not enforced
+3. **Error Handling**:
+   - Minimal error recovery, especially in the REPL
+4. **Tail Recursion**:
+   - No proper tail call optimization
+5. **Data Types**:
+   - No floating point, string, or full numeric tower support
+6. **Garbage Collection**:
+   - No GC; memory for cons cells is not reclaimed
+7. **Standard Library**:
+   - No standard library or macros
+
+Next Steps:
+-----------
+1. **Implement Nested Lambda Support**:
+   - Refactor closure environment capture and restoration
+   - Update compiler and VM to support nested closures
+2. **Improve Memory Management**:
+   - Implement or enforce reference counting
+   - Plan for future garbage collection
+3. **Enhance Error Handling**:
+   - Add better error messages and recovery in REPL and VM
+4. **Tail Call Optimization**:
+   - Investigate and implement proper tail recursion
+5. **Testing and Debugging**:
+   - Expand test suite for edge cases (especially closures and let/lambda)
+   - Continue using DEBUG=1 for tracing execution
+6. **Documentation and Code Quality**:
+   - Keep architectural notes and code comments up to date
+   - Document any new patterns or changes
+
+Technical Notes:
+---------------
+- Function calls use LOOKUP, GET_VALUE, and CALL instructions
+- Environment stack manages variable bindings and function parameters
+- Function code is stored in the FUNCTIONS table with unique names
+- Lambda functions use __lambda_N naming scheme; closures capture environment at creation
+- State is persisted to /tmp/scheme_vm.state and /tmp/scheme_vm.env
+
+Debugging Tips:
+--------------
+1. Enable DEBUG=1 to see detailed execution logs
+2. Check stack and environment contents before and after each operation
+3. Monitor closure creation and environment capture/restoration
+4. Verify function code storage and retrieval in the FUNCTIONS table
+5. Use and expand test cases for all supported features 
\ No newline at end of file
diff --git a/awk/scheme/scheme/bin/compiler.awk b/awk/scheme/scheme/bin/compiler.awk
new file mode 100755
index 0000000..94d6e99
--- /dev/null
+++ b/awk/scheme/scheme/bin/compiler.awk
@@ -0,0 +1,660 @@
+#!/usr/bin/awk -f
+
+# This is a Scheme-to-Assembly compiler implemented in AWK
+# It takes Scheme expressions as input and outputs assembly instructions
+# for a custom stack-based virtual machine
+
+BEGIN {
+    # Compiler maintains internal state for code generation
+    curr_token = ""      # Current token being processed by lexer
+    input_buffer = ""    # Buffer for input text being tokenized
+    next_label = 0       # Counter for generating unique labels
+    program = ""         # Accumulates the full program text
+    
+    # AWK FEATURE: ENVIRON is a built-in array containing environment variables
+    # Unlike JS process.env, this is automatically available in awk
+    DEBUG = (ENVIRON["DEBUG"] == "1") ? 1 : 0
+}
+
+# Debug logging helper function
+function debug(msg) {
+    # AWK FEATURE: printf with > "/dev/stderr" redirects output to stderr
+    # Unlike console.error() in JS, this is how awk handles stderr output
+    if (DEBUG) printf("[DEBUG] %s\n", msg) > "/dev/stderr"
+}
+
+# AWK FEATURE: Each line of input is automatically processed by this block
+# This is awk's main input processing loop - every line from stdin/files goes here
+# In JS, you'd need to explicitly read lines from a stream
+{
+    if (program != "") program = program "\n"
+    program = program $0  # $0 is the current line being processed
+}
+
+# AWK FEATURE: END block runs after all input has been processed
+# This is like a "finally" block that always executes after reading all input
+END {
+    debug("Raw program:\n" program)
+    if (program == "") exit
+    
+    # Parse and compile each expression in the program
+    split_expressions(program)
+}
+
+# Splits input into individual Scheme expressions
+# Handles nested parentheses and comments
+function split_expressions(prog, current, paren_count, i, c, expr, cleaned) {
+    current = ""
+    paren_count = 0
+    
+    # Clean up the input:
+    # 1. Remove comments (text between ; and next opening paren)
+    # 2. Normalize whitespace
+    # 3. Trim leading/trailing whitespace
+    cleaned = prog
+    # AWK FEATURE: gsub() is a built-in function for global substitution (like replaceAll in JS)
+    # gsub(pattern, replacement, target) - modifies target in place and returns count
+    gsub(/;[^(]*\(/, "(", cleaned)  # Remove comments before expressions
+    gsub(/\)[^)]*;/, ")", cleaned)  # Remove comments after expressions
+    gsub(/[ \t\n]+/, " ", cleaned)  # Normalize whitespace to single spaces
+    # AWK FEATURE: sub() is like gsub() but only replaces the first occurrence
+    sub(/^[ \t\n]+/, "", cleaned)   # Trim leading whitespace
+    sub(/[ \t\n]+$/, "", cleaned)   # Trim trailing whitespace
+    
+    debug("Cleaned program: [" cleaned "]")
+    
+    if (cleaned == "") return
+    
+    # Parse expressions by tracking parenthesis nesting
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    for (i = 1; i <= length(cleaned); i++) {
+        c = substr(cleaned, i, 1)
+        
+        if (c == "(") {
+            if (paren_count == 0) current = ""
+            paren_count++
+        }
+        
+        current = current c
+        
+        if (c == ")") {
+            paren_count--
+            if (paren_count == 0) {
+                # Complete expression found - compile it
+                expr = current
+                sub(/^\s+/, "", expr)
+                sub(/\s+$/, "", expr)
+                
+                debug("Processing expression: [" expr "]")
+                program = expr  # Set for parser
+                expr = parse_expr()
+                compile_expr(expr)
+                current = ""
+            }
+        }
+    }
+    
+    # Add final HALT instruction
+    print "HALT"
+}
+
+# Lexer helper functions for character classification
+# AWK FEATURE: String comparison with >= and <= works lexicographically
+# Unlike JS where you need to convert to numbers, awk can compare strings directly
+function is_digit(c) { return c >= "0" && c <= "9" }
+function is_whitespace(c) { return c == " " || c == "\t" || c == "\n" }
+
+# Lexical analyzer - converts input into tokens
+# Handles numbers, symbols, and parentheses
+function next_token() {
+    # Initialize input buffer on first call
+    if (input_buffer == "") input_buffer = program
+    
+    # Skip whitespace between tokens
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    while (length(input_buffer) > 0 && is_whitespace(substr(input_buffer, 1, 1)))
+        input_buffer = substr(input_buffer, 2)
+    
+    if (length(input_buffer) == 0) return "EOF"
+    
+    # Handle parentheses as single-character tokens
+    c = substr(input_buffer, 1, 1)
+    if (c == "(" || c == ")") {
+        input_buffer = substr(input_buffer, 2)
+        return c
+    }
+    
+    # Handle numbers (including negative numbers)
+    # AWK FEATURE: substr(string, start, length) extracts substring
+    # Unlike JS string.slice(), this is 1-indexed and requires explicit length
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    if (is_digit(c) || c == "-" && length(input_buffer) > 1 && is_digit(substr(input_buffer, 2, 1))) {
+        num = ""
+        # AWK FEATURE: length(string) returns the length of a string
+        # Unlike JS string.length, this is a function call, not a property
+        while (length(input_buffer) > 0) {
+            c = substr(input_buffer, 1, 1)
+            if (!is_digit(c) && c != "-") break
+            num = num c
+            input_buffer = substr(input_buffer, 2)
+        }
+        return num
+    }
+    
+    # Handle symbols (identifiers and operators)
+    sym = ""
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    while (length(input_buffer) > 0) {
+        c = substr(input_buffer, 1, 1)
+        if (is_whitespace(c) || c == "(" || c == ")") break
+        sym = sym c
+        input_buffer = substr(input_buffer, 2)
+    }
+    return sym
+}
+
+# Recursive descent parser for Scheme expressions
+# Returns parsed expression as a string
+function parse_expr(token, result) {
+    token = next_token()
+    if (token == "EOF") return ""
+    
+    if (token == "(") {
+        result = parse_list()
+        debug("Parsed list: " result)
+        return result
+    }
+    
+    debug("Parsed token: " token)
+    return token
+}
+
+# Parses a list expression (anything in parentheses)
+function parse_list(result, expr) {
+    result = ""
+    
+    while (1) {
+        expr = parse_expr()
+        if (expr == "" || expr == ")") break
+        
+        if (result != "") result = result " "
+        result = result expr
+    }
+    
+    if (expr == "") error("Unexpected end of input in list")
+    return "(" result ")"
+}
+
+# Splits an expression into operator and arguments
+# Handles nested expressions correctly
+function split_expr(expr, i, len, c, op, args, paren_count) {
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    len = length(expr)
+    paren_count = 0
+    
+    for (i = 1; i <= len; i++) {
+        c = substr(expr, i, 1)
+        if (c == " " && paren_count == 0) {
+            op = substr(expr, 1, i - 1)
+            args = substr(expr, i + 1)
+            break
+        }
+        if (c == "(") paren_count++
+        if (c == ")") paren_count--
+    }
+    
+    if (!op) {
+        op = expr
+        args = ""
+    }
+    
+    debug("Split expr: op=" op " args=" args)
+    # AWK FEATURE: SUBSEP is a built-in variable used as separator for array indices
+    # When you use array[key1,key2], awk internally stores it as array[key1 SUBSEP key2]
+    # This allows multi-dimensional arrays in awk (though they're really single-dimensional)
+    return op SUBSEP args
+}
+
+# Splits argument list handling nested parentheses
+function split_args(args, arg_array, len, i, c, current, paren_count, arg_count) {
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    len = length(args)
+    current = ""
+    paren_count = 0
+    arg_count = 0
+    
+    for (i = 1; i <= len; i++) {
+        c = substr(args, i, 1)
+        
+        if (c == "(") paren_count++
+        if (c == ")") paren_count--
+        
+        if (c == " " && paren_count == 0 && current != "") {
+            arg_array[++arg_count] = current
+            current = ""
+        } else if (c != " " || paren_count > 0) {
+            current = current c
+        }
+    }
+    
+    if (current != "") {
+        arg_array[++arg_count] = current
+    }
+    
+    return arg_count
+}
+
+# Code generation for numeric literals
+function compile_number(num) {
+    debug("Compiling number: " num)
+    print "PUSH_CONST N:" num
+}
+
+# Code generation for primitive operations (+, -, *, cons, etc)
+function compile_primitive_call(op, args, arg_array, nargs, i) {
+    debug("Primitive call: op=" op " args=" args)
+    nargs = split_args(args, arg_array)
+    
+    # Check if this is a lambda function call
+    # AWK FEATURE: ~ is the regex match operator (like /pattern/.test() in JS)
+    # The pattern is a regex literal, not a string
+    if (op ~ /^\(lambda /) {
+        # This is a lambda function call
+        # First compile all arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        
+        # Then compile the lambda function (this will push the function name)
+        compile_expr(op)
+        
+        # Call the function - the lambda name is now on top of stack
+        print "CALL"
+        return
+    }
+    
+    # Then emit appropriate operation
+    if (op == "+") {
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        for (i = 1; i < nargs; i++)
+            print "ADD"
+    }
+    else if (op == "-") {
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        if (nargs == 1) {
+            print "PUSH_CONST N:0"
+            print "SWAP"
+        }
+        for (i = 1; i < nargs; i++)
+            print "SUB"
+    }
+    else if (op == "*") {
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        for (i = 1; i < nargs; i++)
+            print "MUL"
+    }
+    else if (op == "cons") {
+        if (nargs != 2) error("cons requires 2 arguments")
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "CONS"
+    }
+    else if (op == "car") {
+        if (nargs != 1) error("car requires 1 argument")
+        # Compile argument
+        compile_expr(arg_array[1])
+        print "CAR"
+    }
+    else if (op == "cdr") {
+        if (nargs != 1) error("cdr requires 1 argument")
+        # Compile argument
+        compile_expr(arg_array[1])
+        print "CDR"
+    }
+    else if (op == "<") {
+        if (nargs != 2) error("< requires 2 arguments")
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LT"
+    }
+    else if (op == "=") {
+        if (nargs != 2) error("= requires 2 arguments")
+        # Compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "EQ"
+    }
+    else {
+        # Function call for user-defined functions
+        debug("Function call: " op)
+        # First compile arguments
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        # Then look up the function name
+        print "LOOKUP " op
+        # Get the actual function name
+        print "GET_VALUE"
+        # Call the function
+        print "CALL"
+    }
+}
+
+# Splits let bindings into individual variable/value pairs
+function split_bindings(bindings, binding_array, count, current, paren_count, i, c) {
+    count = 0
+    current = ""
+    paren_count = 0
+    
+    debug("split_bindings: parsing [" bindings "]")
+    
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    for (i = 1; i <= length(bindings); i++) {
+        c = substr(bindings, i, 1)
+        
+        # Track nested parentheses
+        if (c == "(") {
+            paren_count++
+            if (paren_count == 1) {
+                current = ""  # Start new binding
+                continue
+            }
+        }
+        if (c == ")") {
+            paren_count--
+            if (paren_count == 0) {
+                # End of binding
+                binding_array[++count] = current
+                debug("split_bindings: found binding [" current "]")
+                current = ""
+                continue
+            }
+        }
+        
+        # Add character if we're inside a binding
+        if (paren_count > 0) {
+            current = current c
+        }
+    }
+    
+    debug("split_bindings: found " count " bindings")
+    return count
+}
+
+# Compiles let expressions (local variable bindings)
+function compile_let(args, bindings, body, binding_array, nbindings, i, var, val, binding_parts) {
+    # Split into bindings and body
+    if (substr(args, 1, 1) != "(") error("Malformed let expression")
+    
+    # Find matching closing parenthesis for bindings
+    paren_count = 1
+    i = 2
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    while (paren_count > 0 && i <= length(args)) {
+        if (substr(args, i, 1) == "(") paren_count++
+        if (substr(args, i, 1) == ")") paren_count--
+        i++
+    }
+    if (paren_count > 0) error("Unmatched parenthesis in let bindings")
+    
+    bindings = substr(args, 2, i - 3)  # Remove outer parentheses
+    body = substr(args, i)
+    
+    # Trim whitespace from body
+    sub(/^[ \t\n]+/, "", body)
+    sub(/[ \t\n]+$/, "", body)
+    
+    debug("Let bindings: " bindings)
+    debug("Let body: " body)
+    
+    # Compile each binding
+    nbindings = split_bindings(bindings, binding_array)
+    for (i = 1; i <= nbindings; i++) {
+        debug("Processing binding: " binding_array[i])
+        
+        # Find the variable name (everything up to the first space)
+        var = binding_array[i]
+        sub(/ .*$/, "", var)
+        
+        # Find the value (everything after the first space)
+        val = binding_array[i]
+        sub(/^[^ ]+ /, "", val)
+        
+        debug("Binding var: " var " val: " val)
+        
+        # Compile the value
+        if (substr(val, 1, 1) == "(") {
+            # Handle lambda or other compound expressions
+            if (substr(val, 2, 6) == "lambda") {
+                # This is a lambda expression
+                # Pass the entire lambda expression to compile_lambda
+                compile_lambda(val)
+                # Store the function name in the environment
+                print "STORE " var
+            } else {
+                compile_expr(val)
+                print "STORE " var
+            }
+        } else {
+            compile_expr(val)
+            print "STORE " var
+        }
+    }
+    
+    # Compile the body
+    compile_expr(body)
+    
+    # Clean up bindings AFTER evaluating body
+    for (i = nbindings; i >= 1; i--) {
+        print "POP_ENV"
+    }
+}
+
+# Compiles define expressions (function/variable definitions)
+function compile_define(args, name, params, body, param_array, nparams, i, paren_start, paren_end) {
+    # Set flag for global definition
+    print "PUSH_CONST B:1"
+    print "STORE from_define"  # Must match exactly what vm_store checks for
+    
+    # Find the function name (everything up to the first space)
+    i = index(args, " ")
+    if (i == 0) error("Malformed define expression")
+    name = substr(args, 1, i - 1)
+    args = substr(args, i + 1)
+
+    # Check if it's a function or variable definition
+    if (substr(args, 1, 1) == "(") {
+        # It's a function definition
+        paren_count = 1
+        i = 2
+        while (paren_count > 0 && i <= length(args)) {
+            if (substr(args, i, 1) == "(") paren_count++
+            if (substr(args, i, 1) == ")") paren_count--
+            i++
+        }
+        if (paren_count > 0) error("Unmatched parenthesis in parameter list")
+
+        params = substr(args, 2, i - 3)  # Remove parentheses
+        body = substr(args, i + 1)
+
+        # Create function label
+        print "LABEL " name
+
+        # Process parameters
+        # AWK FEATURE: split(string, array, separator) splits string into array elements
+        # Unlike JS string.split() which returns an array, this populates an existing array
+        nparams = split(params, param_array, " ")
+        for (i = 1; i <= nparams; i++) {
+            print "STORE " param_array[i]
+        }
+
+        # Compile function body
+        compile_expr(body)
+
+        # Clean up parameters and return
+        for (i = nparams; i >= 1; i--) {
+            print "POP_ENV"
+        }
+        print "RETURN"
+    } else {
+        # Variable definition
+        debug("Defining variable: " name " with value: " args)
+        compile_expr(args)  # Compile the value
+        print "STORE " name  # Store the variable
+    }
+}
+
+# Compiles lambda expressions (anonymous functions)
+function compile_lambda(args, params, body, param_array, nparams, i, lambda_name) {
+    # Generate a unique name for the lambda function
+    lambda_name = "__lambda_" next_label++
+    
+    debug("compile_lambda: args = [" args "]")
+    
+    # Handle both full lambda expression and just the arguments part
+    if (substr(args, 1, 7) == "(lambda") {
+        debug("compile_lambda: detected full lambda expression")
+        # Full lambda expression: (lambda (params) body)
+        args = substr(args, 8)  # Remove "(lambda"
+        debug("compile_lambda: after removing (lambda: [" args "]")
+        # Find the closing parenthesis of the entire lambda expression
+        paren_count = 0
+        i = 1
+        while (i <= length(args)) {
+            c = substr(args, i, 1)
+            if (c == "(") paren_count++
+            if (c == ")") {
+                paren_count--
+                if (paren_count == -1) break  # Found the closing paren of the lambda
+            }
+            i++
+        }
+        if (paren_count != -1) error("Unmatched parenthesis in lambda")
+        args = substr(args, 1, i - 1)  # Remove the closing parenthesis
+        debug("compile_lambda: after removing closing paren: [" args "]")
+        # Remove leading whitespace
+        sub(/^[ \t\n]+/, "", args)
+        debug("compile_lambda: after removing leading whitespace: [" args "]")
+    }
+    
+    # Split into parameters and body
+    if (substr(args, 1, 1) != "(") error("Malformed lambda expression")
+    
+    # Find matching closing parenthesis for parameters
+    paren_count = 1
+    i = 2
+    # AWK FEATURE: length(string) returns the length of a string
+    # Unlike JS string.length, this is a function call, not a property
+    while (paren_count > 0 && i <= length(args)) {
+        if (substr(args, i, 1) == "(") paren_count++
+        if (substr(args, i, 1) == ")") paren_count--
+        i++
+    }
+    if (paren_count > 0) error("Unmatched parenthesis in lambda parameters")
+    
+    params = substr(args, 2, i - 3)  # Remove parentheses
+    body = substr(args, i)
+    
+    # Trim whitespace from body
+    sub(/^[ \t\n]+/, "", body)
+    sub(/[ \t\n]+$/, "", body)
+    
+    debug("Lambda parameters: " params)
+    debug("Lambda body: " body)
+    
+    # Create function label
+    print "LABEL " lambda_name
+    
+    # Process parameters
+    # AWK FEATURE: split(string, array, separator) splits string into array elements
+    # Unlike JS string.split() which returns an array, this populates an existing array
+    nparams = split(params, param_array, " ")
+    for (i = 1; i <= nparams; i++) {
+        print "STORE " param_array[i]
+    }
+    
+    # Compile function body
+    compile_expr(body)
+    
+    # Clean up parameters and return
+    for (i = nparams; i >= 1; i--) {
+        print "POP_ENV"
+    }
+    print "RETURN"
+    
+    # Create closure that captures current environment
+    print "CAPTURE_ENV " lambda_name
+    print "PUSH_CONST CLOSURE:" lambda_name ":ENV_ID"
+}
+
+# Main expression compiler - dispatches based on expression type
+function compile_expr(expr,    split_result, op, args) {
+    debug("Compiling expression: " expr)
+    
+    # Handle numeric literals
+    if (expr ~ /^-?[0-9]+$/) {
+        compile_number(expr)
+        return
+    }
+    
+    # Handle nil constant
+    if (expr == "nil") {
+        print "PUSH_CONST NIL:"
+        return
+    }
+    
+    # Handle variable lookup
+    if (expr ~ /^[a-zA-Z_][a-zA-Z0-9_]*$/) {
+        print "LOOKUP " expr
+        return
+    }
+    
+    # Handle compound expressions (lists)
+    if (substr(expr, 1, 1) == "(") {
+        expr = substr(expr, 2, length(expr) - 2)
+        split_result = split_expr(expr)
+        op = substr(split_result, 1, index(split_result, SUBSEP) - 1)
+        args = substr(split_result, index(split_result, SUBSEP) + 1)
+        
+        if (op == "define") {
+            compile_define(args)
+        } else if (op == "let") {
+            compile_let(args)
+        } else if (op == "lambda") {
+            compile_lambda(args)
+        } else {
+            compile_primitive_call(op, args)
+        }
+        return
+    }
+    
+    error("Unknown expression type: " expr)
+}
+
+# Error reporting helper
+function error(msg) {
+    print "Error: " msg > "/dev/stderr"
+    exit 1
+}
\ No newline at end of file
diff --git a/awk/scheme/scheme/bin/repl b/awk/scheme/scheme/bin/repl
new file mode 100755
index 0000000..1fce388
--- /dev/null
+++ b/awk/scheme/scheme/bin/repl
@@ -0,0 +1,161 @@
+#!/bin/bash
+
+# Enable debug tracing
+# BASH FEATURE: ${VAR:-default} provides a default value if VAR is unset or empty
+# Unlike JS where you'd use VAR || default, this only uses default if VAR is literally unset
+DEBUG=${DEBUG:-0}
+
+debug() {
+    if [ "$DEBUG" = "1" ]; then
+        # BASH FEATURE: >&2 redirects output to stderr (file descriptor 2)
+        # Unlike JS console.error(), this explicitly redirects to stderr
+        echo "[DEBUG] $*" >&2
+    fi
+}
+
+# Find the directory containing this script and the components
+# BASH FEATURE: ${BASH_SOURCE[0]} is the path to the current script
+# Unlike JS __filename, this works even when the script is sourced
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+COMPILER="$DIR/compiler.awk"
+VM="$DIR/vm.awk"
+
+debug "Using compiler: $COMPILER"
+debug "Using VM: $VM"
+
+# Verify components exist and are executable
+for component in "$COMPILER" "$VM"; do
+    if [ ! -f "$component" ]; then
+        echo "Error: Cannot find $component" >&2
+        echo "Please ensure all components are present" >&2
+        exit 1
+    fi
+    chmod +x "$component"
+done
+
+# Set up temporary files and state
+TMPDIR=$(mktemp -d)
+debug "Created temp dir: $TMPDIR"
+STATE_FILE="/tmp/scheme_vm.state"
+
+cleanup() {
+    debug "Cleaning up temp dir: $TMPDIR"
+    rm -rf "$TMPDIR"
+    # Temporarily disable state file deletion for debugging
+    # if [ "$1" != "keep_state" ]; then
+    #     rm -f "$STATE_FILE"
+    #     rm -f "/tmp/scheme_vm.env"
+    # fi
+}
+trap "cleanup" EXIT
+
+# Set up temporary files
+INPUT_FILE="$TMPDIR/input.scm"
+ASM_FILE="$TMPDIR/output.asm"
+DEBUG_FILE="$TMPDIR/debug.out"
+
+# Initialize/clear state files at REPL start
+# Temporarily disable state file clearing for debugging
+# if [ "$#" -eq 0 ]; then  # Only for interactive mode
+#     : > "/tmp/scheme_vm.state"
+#     : > "/tmp/scheme_vm.env"
+# fi
+
+# Function to handle evaluation
+evaluate_expression() {
+    local input="$1"
+    local result
+    
+    # Skip empty lines
+    if [ -z "$input" ]; then
+        return 0
+    fi
+    
+    debug "Evaluating expression: $input"
+    echo "$input" > "$INPUT_FILE"
+    debug "Input file contents:"
+    cat "$INPUT_FILE" >&2
+    
+    # Show compilation output even if it fails
+    debug "Running compiler..."
+    if awk -f "$COMPILER" "$INPUT_FILE" > "$ASM_FILE" 2> "$DEBUG_FILE"; then
+        debug "Compilation successful. Debug output:"
+        cat "$DEBUG_FILE" >&2
+        debug "Generated assembly:"
+        cat "$ASM_FILE" >&2
+        
+        debug "Running VM..."
+        # Use persistent VM state and pass debug flag
+        # BASH FEATURE: -v var=value passes variables to awk
+        # Unlike JS where you'd use process.env, this sets awk variables directly
+        result=$(awk -v PERSIST=1 -v DEBUG="$DEBUG" -f "$VM" "$ASM_FILE" 2>&1)
+        debug "VM output: $result"
+        if [ -n "$result" ]; then
+            echo "$result"
+        fi
+        return 0
+    else
+        echo "Compilation error" >&2
+        debug "Compiler output:"
+        cat "$DEBUG_FILE" >&2
+        return 1
+    fi
+}
+
+# Check if a file argument is provided
+if [ "$#" -gt 0 ]; then
+    if [ ! -f "$1" ]; then
+        echo "Error: File not found: $1" >&2
+        exit 1
+    fi
+    debug "Reading file: $1"
+    file_content=$(cat "$1" | tr '\n' ' ')
+    debug "File content: $file_content"
+    evaluate_expression "$file_content"
+    cleanup "keep_state"  # Keep state after file execution
+    exit 0
+fi
+
+# REPL state
+paren_count=0
+current_input=""
+
+# Print welcome message
+echo "Scheme REPL (Press Ctrl+D to exit)"
+echo
+
+# Main REPL loop
+while true; do
+    if [ $paren_count -eq 0 ]; then
+        printf "scheme> "
+    else
+        printf "... "
+    fi
+    
+    read -r line || exit 0
+    
+    # Skip empty lines
+    if [ -z "$line" ]; then
+        continue
+    fi
+    
+    # Count parentheses
+    # BASH FEATURE: $(command) is command substitution - runs command and captures output
+    # Unlike JS where you'd use require('child_process').execSync(), this is built-in
+    open_parens=$(echo "$line" | tr -cd '(' | wc -c)
+    close_parens=$(echo "$line" | tr -cd ')' | wc -c)
+    # BASH FEATURE: $((expression)) is arithmetic expansion
+    # Unlike JS where you'd use eval() or a math library, this evaluates arithmetic expressions
+    paren_count=$((paren_count + open_parens - close_parens))
+    
+    if [ -n "$current_input" ]; then
+        current_input="$current_input $line"
+    else
+        current_input="$line"
+    fi
+    
+    if [ $paren_count -eq 0 ]; then
+        evaluate_expression "$current_input"
+        current_input=""
+    fi
+done
\ No newline at end of file
diff --git a/awk/scheme/scheme/bin/vm.awk b/awk/scheme/scheme/bin/vm.awk
new file mode 100755
index 0000000..ea15884
--- /dev/null
+++ b/awk/scheme/scheme/bin/vm.awk
@@ -0,0 +1,997 @@
+#!/usr/bin/awk -f
+
+# This is a stack-based virtual machine for executing compiled Scheme code
+# It implements a simple instruction set with support for:
+# - Basic arithmetic operations
+# - Function calls and returns
+# - Variable bindings and lookups
+# - Cons cells and list operations
+
+BEGIN {
+    # Type system tags for runtime type checking
+    T_NUMBER = "N"    # Numbers (integers)
+    T_BOOLEAN = "B"   # Booleans (0/1)
+    T_SYMBOL = "S"    # Symbols (identifiers)
+    T_PAIR = "P"      # Cons cells (pairs)
+    T_FUNCTION = "F"  # Function references
+    T_NIL = "NIL"     # Empty list marker
+    T_CLOSURE = "CLOSURE"  # Closure objects (function + captured environment)
+
+    # Virtual machine registers
+    stack_ptr = 0     # Points to top of evaluation stack
+    heap_ptr = 0      # Points to next free heap location
+    pc = 0            # Program counter for instruction fetch
+    
+    # Original program storage for nested function definitions
+    # AWK FEATURE: delete array removes all elements from an array
+    # Unlike JS where you'd set array = [], this clears the array in place
+    delete original_program  # Stores the original program before function calls
+    
+    # AWK FEATURE: ENVIRON is a built-in array containing environment variables
+    DEBUG = (ENVIRON["DEBUG"] == "1") ? 1 : 0
+
+    # Environment for variable bindings
+    env_size = 0     # Current size of environment stack
+    
+    # Closure support - captured environments for nested lambdas
+    delete closure_envs      # Maps env_id to captured environment arrays
+    delete closure_env_names # Variable names in captured environments
+    delete closure_env_vals  # Variable values in captured environments
+    delete closure_env_sizes # Size of each captured environment
+    next_env_id = 1         # Counter for generating unique environment IDs
+    
+    # Function table for storing defined functions
+    delete func_def_names  # Function names
+    delete func_def_pc     # Entry points
+    delete func_def_code   # Function bodies
+    func_def_size = 0      # Number of defined functions
+    
+    # Call stack for function returns
+    call_stack_ptr = 0
+
+    # Global function registry - clear it first
+    delete FUNCTIONS       # Maps function names to implementations
+
+    # State persistence configuration
+    STATE_FILE = "/tmp/scheme_vm.state"
+    debug("STATE_FILE_PATH: " STATE_FILE)
+    debug("PERSIST_FLAG: " PERSIST)
+    if (PERSIST) {
+        debug("Loading state from: " STATE_FILE)
+        debug("LOADING_STATE: Attempting to read " STATE_FILE)
+        debug("LOADING_STATE: FUNCTIONS table size before loading: " length(FUNCTIONS))
+        # AWK FEATURE: getline is awk's file reading function
+        # getline var < file reads one line from file into var, returns 1 on success, 0 on EOF, -1 on error
+        # Unlike JS where you'd use fs.readFileSync(), this reads line by line
+        if ((getline line < STATE_FILE) >= 0) {  # Check if file exists and is readable
+            debug("LOADING_STATE: File opened successfully, first line: " line)
+            # AWK FEATURE: do-while loop syntax - the condition is checked at the end
+            do {
+                debug("LOADING_STATE: Processing line: " line)
+                if (line ~ /^FUNC /) {
+                    # Parse and load function definition
+                    # AWK FEATURE: sub() modifies the string in place and returns count of replacements
+                    sub(/^FUNC /, "", line)
+                    name = line
+                    sub(/ .*$/, "", name)
+                    code = line
+                    sub(/^[^ ]+ /, "", code)
+                    
+                    # Read the rest of the function code (until next FUNC or end of file)
+                    debug("LOADING_STATE: Reading function code for " name)
+                    while ((getline line < STATE_FILE) > 0) {
+                        debug("LOADING_STATE: Reading line: " line)
+                        if (line ~ /^FUNC /) {
+                            # Found next function, put the line back
+                            debug("LOADING_STATE: Found next function, stopping")
+                            break
+                        }
+                        code = code "\n" line
+                    }
+                    
+                    debug("Loaded function: " name)
+                    debug("Code: " code)
+                    
+                    # Store function in FUNCTIONS table
+                    FUNCTIONS[name] = code
+                    debug("LOADED_FUNCTION: " name " with code length " length(code))
+                    debug("LOADED_FUNCTION: FUNCTIONS table size after loading " name ": " length(FUNCTIONS))
+                    debug("LOADED_FUNCTION: Checking if " name " is in table: " (name in FUNCTIONS))
+                }
+            } while ((getline line < STATE_FILE) > 0)
+            # AWK FEATURE: close() closes a file handle
+            close(STATE_FILE)
+        }
+    }
+
+    # Function environment storage
+    delete func_env_names  # Variable names in function scope
+    delete func_env_vals   # Variable values in function scope
+    delete func_env_sizes  # Size of each function's environment
+
+    # Register built-in functions first
+    debug("REGISTERING_BUILTINS: " length(FUNCTIONS) " functions before")
+    FUNCTIONS["+"] = "add"
+    FUNCTIONS["-"] = "subtract"
+    FUNCTIONS["*"] = "multiply"
+    FUNCTIONS["/"] = "divide"
+    FUNCTIONS["="] = "equals"
+    FUNCTIONS["<"] = "less_than"
+    FUNCTIONS[">"] = "greater_than"
+    FUNCTIONS["add1"] = "add_one"
+    debug("REGISTERING_BUILTINS: " length(FUNCTIONS) " functions after")
+
+    # Environment persistence configuration
+    ENV_STATE_FILE = "/tmp/scheme_vm.env"
+    if (PERSIST) {
+        debug("Loading environment state from: " ENV_STATE_FILE)
+        if ((getline line < ENV_STATE_FILE) >= 0) {
+            do {
+                if (line ~ /^ENV /) {
+                    # Parse and load environment binding
+                    sub(/^ENV /, "", line)
+                    name = line
+                    sub(/ .*$/, "", name)
+                    val = line
+                    sub(/^[^ ]+ /, "", val)
+                    
+                    debug("Loaded env var: " name " = " val)
+                    
+                    # Store in environment
+                    env_name[env_size] = name
+                    env_val[env_size] = val
+                    env_size++
+                }
+            } while ((getline line < ENV_STATE_FILE) > 0)
+            close(ENV_STATE_FILE)
+        }
+    }
+
+    # Track if VM halted normally (vs error)
+    normal_exit = 0
+}
+
+# Debug output helper
+function debug(msg) {
+    if (DEBUG) printf("[DEBUG] %s\n", msg) > "/dev/stderr"
+}
+
+# Value constructors and accessors
+# Values are stored as type:value pairs for runtime type checking
+function makeValue(type, val) {
+    return type ":" val
+}
+
+function getType(val) {
+    # AWK FEATURE: substr(string, start, length) extracts substring
+    # Unlike JS string.slice(), this is 1-indexed and requires explicit length
+    # AWK FEATURE: index(string, substring) returns position of substring (1-indexed)
+    # Unlike JS string.indexOf(), this returns 0 if not found and is 1-indexed
+    type = substr(val, 1, index(val, ":") - 1)
+    debug("Get type: " type " from " val)
+    return type
+}
+
+function getValue(val) {
+    # AWK FEATURE: index() returns 1-indexed position, so we add 1 to get after the colon
+    value = substr(val, index(val, ":") + 1)
+    debug("Get value: " value " from " val)
+    return value
+}
+
+# Type checking predicates
+function isNumber(val) { return getType(val) == T_NUMBER }
+function isBoolean(val) { return getType(val) == T_BOOLEAN }
+function isSymbol(val) { return getType(val) == T_SYMBOL }
+function isPair(val) { return getType(val) == T_PAIR }
+function isFunction(val) { return getType(val) == T_FUNCTION }
+function isNil(val) { return getType(val) == T_NIL }
+function isClosure(val) { return getType(val) == T_CLOSURE }
+
+# Closure helper functions
+function makeClosure(func_name, env_id) {
+    return T_CLOSURE ":" func_name ":" env_id
+}
+
+function getClosureFunction(closure_val) {
+    # Extract function name from CLOSURE:func_name:env_id
+    return substr(closure_val, index(closure_val, ":") + 1, 
+                 index(substr(closure_val, index(closure_val, ":") + 1), ":") - 1)
+}
+
+function getClosureEnvId(closure_val) {
+    # Extract env_id from CLOSURE:func_name:env_id
+    first_colon = index(closure_val, ":")
+    second_colon = index(substr(closure_val, first_colon + 1), ":") + first_colon
+    return substr(closure_val, second_colon + 1)
+}
+
+# Environment capture for closures
+function captureEnvironment(env_id, i) {
+    debug("Capturing environment with ID: " env_id)
+    closure_env_sizes[env_id] = env_size
+    
+    # Copy current environment to closure environment
+    for (i = 0; i < env_size; i++) {
+        # Only capture non-global variables
+        if (env_name[i] !~ /^__global_/) {
+            closure_env_names[env_id, i] = env_name[i]
+            closure_env_vals[env_id, i] = env_val[i]
+            debug("Captured: " env_name[i] " = " env_val[i])
+        }
+    }
+    
+    debug("Captured environment size: " closure_env_sizes[env_id])
+}
+
+# VM instruction to capture environment
+function vm_capture_env(func_name) {
+    debug("Capturing environment for function: " func_name)
+    env_id = next_env_id++
+    captureEnvironment(env_id)
+    
+    # Replace the placeholder ENV_ID in the closure value
+    # Find the closure value on the stack and update it
+    if (stack_ptr > 0) {
+        closure_val = stack[stack_ptr]
+        if (closure_val ~ /^CLOSURE:/) {
+            # Replace ENV_ID with actual env_id
+            new_closure_val = "CLOSURE:" func_name ":" env_id
+            stack[stack_ptr] = new_closure_val
+            debug("Updated closure value: " new_closure_val)
+        }
+    }
+}
+
+# Environment restoration for closures
+function pushClosureEnvironment(env_id, i) {
+    debug("Pushing closure environment: " env_id)
+    if (env_id in closure_env_sizes) {
+        for (i = 0; i < closure_env_sizes[env_id]; i++) {
+            if ((env_id, i) in closure_env_names) {
+                env_name[env_size] = closure_env_names[env_id, i]
+                env_val[env_size] = closure_env_vals[env_id, i]
+                env_size++
+                debug("Restored: " closure_env_names[env_id, i] " = " closure_env_vals[env_id, i])
+            }
+        }
+    }
+}
+
+# Stack operations
+function push(val) {
+    stack[++stack_ptr] = val
+    debug("Push: " val " (SP: " stack_ptr ")")
+}
+
+function pop() {
+    if (stack_ptr < 1) error("Stack underflow")
+    val = stack[stack_ptr--]
+    debug("Pop: " val " (SP: " stack_ptr ")")
+    return val
+}
+
+function peek() {
+    if (stack_ptr < 1) error("Stack empty")
+    debug("Peek: " stack[stack_ptr])
+    return stack[stack_ptr]
+}
+
+# Heap operations for cons cells
+function allocate(val) {
+    heap[++heap_ptr] = val
+    refs[heap_ptr] = 1  # Reference counting (not fully implemented)
+    debug("Allocate: " val " at " heap_ptr)
+    return heap_ptr
+}
+
+function getHeap(idx) {
+    if (!(idx in heap)) {
+        error("Invalid heap access: " idx)
+        return ""
+    }
+    return heap[idx]
+}
+
+# Error handling
+function error(msg) {
+    print "Error at PC " pc ": " msg > "/dev/stderr"
+    exit 1
+}
+
+# Arithmetic instruction implementations
+function vm_add() {
+    if (stack_ptr < 2) error("ADD requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) 
+        error("ADD requires numeric operands")
+    result = getValue(val1) + getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_subtract() {
+    if (stack_ptr < 2) error("SUB requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("SUB requires numeric operands")
+    result = getValue(val1) - getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_multiply() {
+    if (stack_ptr < 2) error("MUL requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("MUL requires numeric operands")
+    result = getValue(val1) * getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_divide() {
+    if (stack_ptr < 2) error("DIV requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("DIV requires numeric operands")
+    if (getValue(val2) == 0)
+        error("Division by zero")
+    result = getValue(val1) / getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+# List operation implementations
+function vm_cons() {
+    if (stack_ptr < 2) error("CONS requires two operands")
+    val2 = pop()
+    val1 = pop()
+    pair_val = val1 "," val2
+    pair_idx = allocate(pair_val)
+    push(makeValue(T_PAIR, pair_idx))
+}
+
+function vm_car() {
+    if (stack_ptr < 1) error("CAR requires one operand")
+    val = pop()
+    if (!isPair(val)) error("CAR requires pair operand")
+    pair_idx = getValue(val)
+    pair = getHeap(pair_idx)
+    car_val = substr(pair, 1, index(pair, ",") - 1)
+    push(car_val)
+}
+
+function vm_cdr() {
+    if (stack_ptr < 1) error("CDR requires one operand")
+    val = pop()
+    if (!isPair(val)) error("CDR requires pair operand")
+    pair_idx = getValue(val)
+    pair = getHeap(pair_idx)
+    cdr_val = substr(pair, index(pair, ",") + 1)
+    push(cdr_val)
+}
+
+# Comparison operations
+function vm_equal() {
+    if (stack_ptr < 2) error("EQ requires two operands")
+    val2 = pop()
+    val1 = pop()
+    result = (val1 == val2) ? "1" : "0"
+    debug("Equal comparison: " val1 " == " val2 " -> " result)
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function vm_less_than() {
+    if (stack_ptr < 2) error("LT requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("LT requires numeric operands")
+    result = (getValue(val1) < getValue(val2)) ? "1" : "0"
+    debug("Less than comparison: " val1 " < " val2 " -> " result)
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Main instruction execution loop
+function execute(instr) {
+    # AWK FEATURE: split(string, array, separator) splits string into array elements
+    # Unlike JS string.split() which returns an array, this populates an existing array
+    split(instr, parts, " ")
+    op = parts[1]
+    debug("Execute: " instr)
+    
+    # Dispatch based on instruction opcode
+    if (op == "PUSH_CONST") {
+        push(parts[2])
+    }
+    else if (op == "POP") {
+        pop()
+    }
+    else if (op == "DUP") {
+        val = peek()
+        push(val)
+    }
+    else if (op == "SWAP") {
+        if (stack_ptr < 2) error("SWAP requires two operands")
+        val2 = pop()
+        val1 = pop()
+        val1 = pop()
+        push(val2)
+        push(val1)
+    }
+    else if (op == "ADD") {
+        vm_add()
+    }
+    else if (op == "SUB") {
+        vm_subtract()
+    }
+    else if (op == "MUL") {
+        vm_multiply()
+    }
+    else if (op == "DIV") {
+        vm_divide()
+    }
+    else if (op == "CONS") {
+        vm_cons()
+    }
+    else if (op == "CAR") {
+        vm_car()
+    }
+    else if (op == "CDR") {
+        vm_cdr()
+    }
+    else if (op == "EQ") {
+        vm_equal()
+    }
+    else if (op == "LT") {
+        vm_less_than()
+    }
+    else if (op == "PRINT") {
+        if (stack_ptr < 1) error("PRINT requires one operand")
+        print peek()
+    }
+    else if (op == "HALT") {
+        debug("EXECUTING_HALT")
+        normal_exit = 1
+        debug("HALT: Stack pointer = " stack_ptr)
+        if (stack_ptr > 0) {
+            result = peek()
+            debug("HALT: Result = " result)
+        } else {
+            debug("HALT: Stack is empty")
+        }
+        if (PERSIST) {
+            save_state()
+        }
+        if (result) {
+            debug("PRINTING_RESULT: " result)
+            print result
+        }
+        exit(0)
+    }
+    else if (op == "STORE") {
+        vm_store(parts[2])
+    }
+    else if (op == "POP_ENV") {
+        vm_pop_env()
+    }
+    else if (op == "LOOKUP") {
+        vm_lookup(parts[2])
+    }
+    else if (op == "LABEL") {
+        vm_define_function(parts[2], pc)
+    }
+    else if (op == "CALL") {
+        vm_call_function()
+    }
+    else if (op == "RETURN") {
+        debug("EXECUTING_RETURN")
+        # The call_stack_ptr is no longer used for return, so this instruction is effectively removed.
+        # The function execution itself handles the return.
+    }
+    else if (op == "GET_VALUE") {
+        vm_get_value()
+    }
+    else if (op == "CAPTURE_ENV") {
+        vm_capture_env(parts[2])
+    }
+    else {
+        error("Unknown instruction: " op)
+    }
+}
+
+# Load program instructions
+# AWK FEATURE: Each line of input is automatically processed by this block
+# NR is a built-in variable that contains the current record (line) number
+# Unlike JS where you'd need to track line numbers manually
+{
+    program[NR-1] = $0  # $0 is the current line being processed
+    original_program[NR-1] = $0  # Keep a copy of the original program
+}
+
+# AWK FEATURE: END block runs after all input has been processed
+# This is like a "finally" block that always executes after reading all input
+END {
+    # AWK FEATURE: length(array) returns the number of elements in an array
+    # Unlike JS array.length, this is a function call, not a property
+    while (pc < length(program)) {
+        # debug("EXECUTING_PC_" pc ": " program[pc])
+        execute(program[pc++])
+    }
+    
+    # Save state if we didn't halt normally
+    if (!normal_exit && PERSIST) {
+        save_state()
+    }
+}
+
+# Variable binding implementation
+function vm_store(name) {
+    debug("Storing " peek() " as " name " at env_size: " env_size)
+    
+    # Handle global definitions specially
+    if (lookup_no_error("from_define")) {
+        name = "__global_" name
+        # Clear the define flag
+        for (i = env_size - 1; i >= 0; i--) {
+            if (env_name[i] == "from_define") {
+                env_size--
+                break
+            }
+        }
+        
+        # Remove any previous definition of this global
+        for (i = env_size - 1; i >= 0; i--) {
+            if (env_name[i] == name) {
+                # Shift everything down
+                for (j = i; j < env_size - 1; j++) {
+                    env_name[j] = env_name[j + 1]
+                    env_val[j] = env_val[j + 1]
+                }
+                env_size--
+                break
+            }
+        }
+    }
+    
+    # Handle lambda functions
+    val = peek()
+    if (isSymbol(val)) {
+        func_name = getValue(val)
+        # AWK FEATURE: ~ is the regex match operator (like /pattern/.test() in JS)
+        # The pattern is a regex literal, not a string
+        if (func_name ~ /^__lambda_/) {
+            # Store the function code under the new name
+            FUNCTIONS[name] = FUNCTIONS[func_name]
+            # Store the new name in the environment
+            env_name[env_size] = name
+            env_val[env_size] = makeValue(T_SYMBOL, name)
+            env_size++
+            return
+        }
+    }
+    
+    # Add to environment
+    env_name[env_size] = name
+    env_val[env_size] = peek()
+    env_size++
+    
+    debug("Environment after store:")
+    dump_env()
+}
+
+# Remove top binding from environment
+function vm_pop_env() {
+    if (env_size <= 0) error("Environment underflow")
+    debug("Popping environment at size: " env_size)
+    
+    # Don't pop globals
+    if (env_name[env_size-1] ~ /^__global_/) {
+        debug("Keeping global definition: " env_name[env_size-1])
+        return
+    }
+    
+    debug("Removing: " env_name[env_size-1] " = " env_val[env_size-1])
+    env_size--
+}
+
+# Variable lookup implementation
+function vm_lookup(name, i, global_name, val) {
+    debug("Looking up " name " in environment of size: " env_size)
+    dump_env()
+
+    # Try global name first, then local
+    global_name = "__global_" name
+    debug("LOOKUP_ENV: Looking for " name " in environment of size " env_size)
+    for (i = env_size - 1; i >= 0; i--) {
+        debug("LOOKUP_ENV: Checking index " i ": " env_name[i] " = " env_val[i])
+        if (env_name[i] == global_name || env_name[i] == name) {
+            debug("Found " name " = " env_val[i] " at position " i)
+            push(env_val[i])
+            return
+        }
+    }
+
+    # Check if it's a function (built-in or user-defined)
+    debug("LOOKUP_CHECKING: " name " in FUNCTIONS table")
+    debug("FUNCTIONS_TABLE_SIZE: " length(FUNCTIONS))
+    debug("FUNCTIONS_IN_TABLE:")
+    # AWK FEATURE: for (var in array) iterates over array keys
+    # Unlike JS for...in which includes inherited properties, awk arrays don't have inheritance
+    for (f in FUNCTIONS) {
+        debug("  " f)
+    }
+    # AWK FEATURE: 'in' operator checks if key exists in array
+    # Unlike JS where you'd use array.hasOwnProperty(key) or 'key' in array
+    if (name in FUNCTIONS) {
+        debug("Found function: " name)
+        push(makeValue(T_SYMBOL, name))
+        return
+    }
+    debug("FUNCTION_LOOKUP_FAILED: " name)
+    error("Undefined variable: " name)
+}
+
+# Function definition implementation
+function vm_define_function(name, start_pc) {
+    debug("Defining function: " name " at " start_pc)
+    debug("call_stack_ptr: " call_stack_ptr)
+    
+    # Clear the from_define flag
+    for (i = env_size - 1; i >= 0; i--) {
+        if (env_name[i] == "from_define") {
+            debug("Clearing from_define flag")
+            env_size--
+            break
+        }
+    }
+    
+    # Build function code
+    code = ""
+    i = start_pc
+    
+    # If we're inside a function call, we need to find the corresponding position
+    # in the original program. For now, use a simple heuristic.
+    if (call_stack_ptr > 0) {
+        debug("Nested function definition - using current instruction")
+        # Just read from the current program position
+        # AWK FEATURE: length(array) returns the number of elements in an array
+        # Unlike JS array.length, this is a function call, not a property
+        while (i < length(program) && program[i] != "RETURN") {
+            if (code != "") code = code "\n"
+            code = code program[i]
+            i++
+        }
+    } else {
+        debug("Top-level function definition - using original program")
+        # Use original_program for top-level function definitions
+        # AWK FEATURE: length(array) returns the number of elements in an array
+        # Unlike JS array.length, this is a function call, not a property
+        while (i < length(original_program) && original_program[i] != "RETURN") {
+            if (code != "") code = code "\n"
+            code = code original_program[i]
+            i++
+        }
+    }
+    code = code "\nRETURN"
+    
+    # Store function
+    debug("Storing function: " name " = " code)
+    FUNCTIONS[name] = code
+    debug("Function stored. Total functions: " length(FUNCTIONS))
+    debug("FUNCTION_STORED: " name)
+    
+    pc = i + 1
+}
+
+# Function call implementation
+function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_name) {
+    # Get function name from stack
+    func_name = pop()
+    debug("Calling function: " func_name)
+    debug("CALLING_FUNCTION: " func_name)
+    
+    # If name is a symbol, get its value
+    if (isSymbol(func_name)) {
+        func_name = getValue(func_name)
+    }
+    
+    # Check if it's a built-in function first
+    if (func_name in FUNCTIONS) {
+        built_in_name = FUNCTIONS[func_name]
+        if (built_in_name == "add") {
+            debug("Calling built-in function: add")
+            add()
+            return
+        } else if (built_in_name == "subtract") {
+            debug("Calling built-in function: subtract")
+            subtract()
+            return
+        } else if (built_in_name == "multiply") {
+            debug("Calling built-in function: multiply")
+            multiply()
+            return
+        } else if (built_in_name == "divide") {
+            debug("Calling built-in function: divide")
+            divide()
+            return
+        } else if (built_in_name == "equals") {
+            debug("Calling built-in function: equals")
+            equals()
+            return
+        } else if (built_in_name == "less_than") {
+            debug("Calling built-in function: less_than")
+            less_than()
+            return
+        } else if (built_in_name == "greater_than") {
+            debug("Calling built-in function: greater_than")
+            greater_than()
+            return
+        } else if (built_in_name == "add_one") {
+            debug("Calling built-in function: add_one")
+            add_one()
+            return
+        }
+    }
+    
+    # Handle anonymous functions and closures
+    if (func_name ~ /^__lambda_/) {
+        if (!(func_name in FUNCTIONS)) {
+            error("Undefined lambda function: " func_name)
+        }
+    } else if (isClosure(func_name)) {
+        # This is a closure call
+        debug("Calling closure: " func_name)
+        closure_func = getClosureFunction(func_name)
+        closure_env_id = getClosureEnvId(func_name)
+        
+        if (!(closure_func in FUNCTIONS)) {
+            error("Undefined closure function: " closure_func)
+        }
+        
+        # Restore the captured environment
+        pushClosureEnvironment(closure_env_id)
+        
+        # Use the closure's function name for the rest of the call
+        func_name = closure_func
+    } else if (!(func_name in FUNCTIONS)) {
+        error("Undefined function: " func_name)
+    }
+    
+    saved_pc = pc
+    saved_env_size = env_size
+    
+    # AWK FEATURE: split(string, array, separator) splits string into array elements
+    # Unlike JS string.split() which returns an array, this populates an existing array
+    split(FUNCTIONS[func_name], code_lines, "\n")
+    
+    # Check if this is a parameterized function
+    if (code_lines[1] ~ /^STORE /) {
+        # This is a parameterized function (lambda)
+        # Get parameter name from STORE instruction
+        param_name = substr(code_lines[1], 7)
+        debug("Found parameter name: " param_name)
+        debug("FUNCTION_PARAM: " param_name)
+        
+        # Get argument from stack
+        arg = pop()
+        debug("Function argument: " arg)
+        debug("FUNCTION_ARG: " arg)
+        
+        # Create new environment frame
+        debug("Creating new environment frame at size: " env_size)
+        env_name[env_size] = param_name
+        env_val[env_size] = arg
+        env_size++
+        debug("FUNCTION_ENV_STORE: " param_name " = " arg " at index " (env_size-1))
+        
+        # Execute function code directly, skipping STORE and POP_ENV instructions
+        for (j = 2; j <= length(code_lines); j++) {
+            if (code_lines[j] != "" && code_lines[j] != "POP_ENV") {
+                debug("Executing function instruction: " code_lines[j])
+                execute(code_lines[j])
+            }
+        }
+        
+        # Clean up parameter
+        vm_pop_env()
+        
+        # Return to caller
+        debug("Function completed, returning to PC: " saved_pc)
+        pc = saved_pc
+        return
+    } else {
+        # This is a built-in function or non-parameterized function
+        debug("Calling non-parameterized function: " func_name)
+        
+        # Execute all function code directly
+        for (j in code_lines) {
+            if (code_lines[j] != "") {
+                debug("Executing function instruction: " code_lines[j])
+                execute(code_lines[j])
+            }
+        }
+        
+        # Return to caller
+        debug("Function completed, returning to PC: " saved_pc)
+        pc = saved_pc
+        return
+    }
+}
+
+# Function return implementation - no longer needed with direct execution
+# function vm_return() {
+#     debug("VM_RETURN: call_stack_ptr = " call_stack_ptr)
+#     if (call_stack_ptr > 0) {
+#         # Save return value
+#         ret_val = pop()
+#         debug("VM_RETURN: return value = " ret_val)
+#         
+#         # Restore environment
+#         while (env_size > env_stack[call_stack_ptr]) {
+#             debug("Popping environment at size: " env_size)
+#             vm_pop_env()
+#         }
+#         
+#         # Restore program counter
+#         pc = call_stack[call_stack_ptr--]
+#         debug("VM_RETURN: restored PC = " pc)
+#         
+#         # Restore the original program at the call position
+#         program[pc] = original_program_at_call[call_stack_ptr + 1]
+#         debug("Restored original program: " original_program_at_call[call_stack_ptr + 1])
+#         
+#         # Push return value
+#         push(ret_val)
+#         debug("VM_RETURN: pushed return value " ret_val)
+#         
+#         debug("Returned with value: " ret_val " and env_size: " env_size)
+#     }
+# }
+
+# Debug helper to dump environment contents
+function dump_env(    i) {
+    debug("Environment dump:")
+    for (i = 0; i < env_size; i++) {
+        # AWK FEATURE: sprintf() formats a string like printf but returns it instead of printing
+        # Unlike JS where you'd use template literals or String.format(), this is the awk way
+        debug(sprintf("  %d: %s = %s", i, env_name[i], env_val[i]))
+    }
+}
+
+# Helper for checking variable existence without error
+function lookup_no_error(name,    i) {
+    for (i = env_size - 1; i >= 0; i--) {
+        if (env_name[i] == name) {
+            return 1
+        }
+    }
+    return 0
+}
+
+# State persistence implementation
+function save_state() {
+    debug("SAVE_STATE_CALLED")
+    debug("Saving state to: " STATE_FILE)
+    # Save functions from FUNCTIONS table
+    debug("SAVE_STATE: Saving " length(FUNCTIONS) " functions")
+        for (func_name in FUNCTIONS) {
+        if (func_name !~ /^__lambda_/) {  # Don't save lambda functions
+            debug("Saving function: " func_name)
+            debug("SAVE_STATE: About to write function " func_name)
+            debug("SAVE_STATE: Function code length: " length(FUNCTIONS[func_name]))
+            # AWK FEATURE: printf with > file redirects output to a file
+            # Unlike JS where you'd use fs.writeFileSync(), this redirects from stdout to file
+            printf "FUNC %s %s\n", func_name, FUNCTIONS[func_name] > STATE_FILE
+            debug("SAVE_STATE: Saved function " func_name " to " STATE_FILE)
+        }
+    }
+    # AWK FEATURE: close() closes a file handle
+    close(STATE_FILE)
+
+    # Save environment state
+    debug("Saving environment state to: " ENV_STATE_FILE)
+    for (i = 0; i < env_size; i++) {
+        if (env_name[i] ~ /^__global_/) {  # Only save globals
+            debug("Saving env var: " env_name[i] " = " env_val[i])
+            # AWK FEATURE: print with > file redirects output to a file
+            # Unlike JS console.log() which always goes to stdout
+            print "ENV " env_name[i] " " env_val[i] > ENV_STATE_FILE
+        }
+    }
+    close(ENV_STATE_FILE)
+}
+
+# Built-in function implementations
+function equals() {
+    if (stack_ptr < 2) error("= requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("= requires numeric operands")
+    result = (getValue(val1) == getValue(val2)) ? 1 : 0
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function less_than() {
+    if (stack_ptr < 2) error("< requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("< requires numeric operands")
+    result = (getValue(val1) < getValue(val2)) ? 1 : 0
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function greater_than() {
+    if (stack_ptr < 2) error("> requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("> requires numeric operands")
+    result = (getValue(val1) > getValue(val2)) ? 1 : 0
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function add() {
+    if (stack_ptr < 2) error("+ requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("+ requires numeric operands")
+    result = getValue(val1) + getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function subtract() {
+    if (stack_ptr < 2) error("- requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("- requires numeric operands")
+    result = getValue(val1) - getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function multiply() {
+    if (stack_ptr < 2) error("* requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("* requires numeric operands")
+    result = getValue(val1) * getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function divide() {
+    if (stack_ptr < 2) error("/ requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("/ requires numeric operands")
+    if (getValue(val2) == 0) error("Division by zero")
+    result = getValue(val1) / getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function add_one() {
+    if (stack_ptr < 1) error("add1 requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("add1 requires numeric operand")
+    result = getValue(val) + 1
+    push(makeValue(T_NUMBER, result))
+}
+
+# Get value from top of stack
+function vm_get_value() {
+    val = pop()
+    if (isSymbol(val)) {
+        name = getValue(val)
+        # If it's a function name, just push the name directly
+        if (name in FUNCTIONS) {
+            push(name)
+        } else {
+            push(makeValue(T_SYMBOL, name))
+        }
+    } else if (isClosure(val)) {
+        # For closures, just push the closure value back
+        push(val)
+    } else {
+        # For other types, just push the value back
+        push(val)
+    }
+}
\ No newline at end of file
diff --git a/awk/scheme/scheme/diagram.md b/awk/scheme/scheme/diagram.md
new file mode 100644
index 0000000..689a44a
--- /dev/null
+++ b/awk/scheme/scheme/diagram.md
@@ -0,0 +1,91 @@
+# Awk-Scheme Architecture
+## Component Interaction Diagram
+
+```
++----------------+     Scheme Code      +----------------+    Assembly     +----------------+
+|                | ----------------->   |                | ------------->  |                |
+|      REPL      |   "(+ 1 2)"          |    Compiler    |  "PUSH_CONST    |       VM       |
+|   (bin/repl)   |   "(lambda (x) ...)" | compiler.awk   |   N:1           |    vm.awk      |
+|                |                      |                |   PUSH_CONST    |                |
+|  - Multi-line  |                      | - Lexer        |   N:2           | - Stack-based  |
+|  - Debug mode  |                      | - Parser       |   ADD           | - Type system  |
+|  - File input  |                      | - Code gen     |   HALT"         | - Environment  |
+|                |                      | - Closure gen  |   CAPTURE_ENV   | - Direct exec  |
+|                | <-----------------   |                | <-------------  |                |
+|                |  Output: "N:3"       |                |   Result        |                |
++----------------+                      +----------------+                 +----------------+
+       ^                                                                      |
+       |                                                                      v
+       |                                                              +----------------+
+       |                                                              |  Persistence   |
+       |                                                              | /tmp files:    |
+       +--------------------------------------------------------------+ - vm.state     |
+                                                                      | - vm.env       |
+                                                                      +----------------+
+
+Debug Flow (when DEBUG=1):
++----------------+     Debug Info      +----------------+    Debug Info    +----------------+
+|     REPL       | ----------------->  |   Compiler     | ------------->   |      VM        |
+|                |  [Input received]   |                | [Tokens found]   |                |
+| [Debug output] |                     | [Parsing tree] | [Stack ops]      | [Stack state]  |
+|     stderr     | <-----------------  |  [Gen code]    | [Closure info]   | [Environment]  |
++----------------+                     +----------------+                  +----------------+
+
+Execution Flow Example:
+┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
+│   Input:    │         │  Lexer/     │         │  Code Gen   │         │     VM      │
+│  (+ 1 2)    │ ------> │  Parser:    │ ------> │ PUSH_CONST  │ ------> │ Stack:      │
+│             │         │  (+         │         │   N:1       │         │  [N:1]      │
+│             │         │   1         │         │ PUSH_CONST  │         │  [N:1,N:2]  │
+│             │         │   2)        │         │   N:2       │         │  [N:3]      │
+│             │         │             │         │ ADD         │         │             │
+└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
+
+Closure Flow Example:
+┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
+│   Input:    │         │  Lexer/     │         │  Code Gen   │         │     VM      │
+│(let ((x 10))│ ------->│  Parser:    │ ------> │ STORE x     │ ------> │ Env: [x=10] │
+│  ((lambda   │         │  (let       │         │ LABEL λ     │         │             │
+│   (y) (+ x  │         │   ((x 10))  │         │ CAPTURE_ENV │         │ Closure:    │
+│   y)) 32))) │         │   (lambda   │         │ PUSH_CONST  │         │  λ+env_id   │
+│             │         │    (y) ...) │         │ CLOSURE:... │         │             │
+│             │         │             │         │ CALL        │         │ Result: 42  │
+└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
+
+State Management:
+┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
+│   Global    │         │ Environment │         │  Function   │         │  Closure    │
+│  Variables  │ ------> │   Stack     │ ------> │   Calls     │ ------> │ Environment │
+│ (persist)   │         │ (frames)    │         │ (direct)    │         │ (captured)  │
+└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
+
+Data Type System:
+┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
+│   Numbers   │    │  Booleans   │    │   Symbols   │    │   Closures  │
+│   N:value   │    │   B:value   │    │   S:name    │    │CLOSURE:fn:env_id│
+└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
+       │                   │                   │                   │
+       └───────────────────┼───────────────────┼───────────────────┘
+                           │                   │
+                    ┌─────────────┐    ┌─────────────┐
+                    │    Pairs    │    │     Nil     │
+                    │   P:index   │    │    NIL:     │
+                    └─────────────┘    └─────────────┘
+
+VM Instruction Set:
+┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
+│   Stack Ops     │    │  Environment    │    │   Functions     │
+│ PUSH_CONST val  │    │ STORE name      │    │ LABEL name      │
+│ POP             │    │ LOOKUP name     │    │ CALL            │
+│ ADD/SUB/MUL/DIV │    │ POP_ENV         │    │ RETURN          │
+│ GET_VALUE       │    │                 │    │                 │
+└─────────────────┘    └─────────────────┘    └─────────────────┘
+         │                       │                       │
+         └───────────────────────┼───────────────────────┘
+                                 │
+                    ┌─────────────────┐
+                    │    Closures     │
+                    │ CAPTURE_ENV fn  │
+                    │ PUSH_CONST      │
+                    │ CLOSURE:fn:env  │
+                    └─────────────────┘
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/cons.test.scm b/awk/scheme/scheme/examples/cons.test.scm
new file mode 100644
index 0000000..d1e3847
--- /dev/null
+++ b/awk/scheme/scheme/examples/cons.test.scm
@@ -0,0 +1,3 @@
+(cons (+ 1 2)
+      (cons (* 3 4)
+            nil))
diff --git a/awk/scheme/scheme/examples/define.test.scm b/awk/scheme/scheme/examples/define.test.scm
new file mode 100644
index 0000000..ec66b04
--- /dev/null
+++ b/awk/scheme/scheme/examples/define.test.scm
@@ -0,0 +1,2 @@
+(define add2 (x) (+ x 2))
+(add2 40) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/lambda.test.scm b/awk/scheme/scheme/examples/lambda.test.scm
new file mode 100644
index 0000000..1f2bb09
--- /dev/null
+++ b/awk/scheme/scheme/examples/lambda.test.scm
@@ -0,0 +1,12 @@
+; Test lambda function support
+((lambda (x) (+ x 1)) 41)  ; Should return 42
+
+; Test lambda with multiple parameters
+((lambda (x y) (+ x y)) 20 22)  ; Should return 42
+
+; Test lambda in let expression
+(let ((add1 (lambda (x) (+ x 1))))
+  (add1 41))  ; Should return 42
+
+; Test nested lambda
+((lambda (x) ((lambda (y) (+ x y)) 1)) 41)  ; Should return 42 
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/let-and-define.test.scm b/awk/scheme/scheme/examples/let-and-define.test.scm
new file mode 100644
index 0000000..fade30b
--- /dev/null
+++ b/awk/scheme/scheme/examples/let-and-define.test.scm
@@ -0,0 +1,9 @@
+; Let expression example
+(let ((x 5) (y 3))
+  (+ x y))
+
+; Function definition example
+(define add2 (x)
+  (+ x 2))
+
+(add2 40)  ; Returns 42
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/let.test.scm b/awk/scheme/scheme/examples/let.test.scm
new file mode 100644
index 0000000..2cdc3b8
--- /dev/null
+++ b/awk/scheme/scheme/examples/let.test.scm
@@ -0,0 +1,2 @@
+(let ((x 5))
+  (+ x 2))
diff --git a/awk/scheme/scheme/scheme b/awk/scheme/scheme/scheme
new file mode 100755
index 0000000..cec35d1
--- /dev/null
+++ b/awk/scheme/scheme/scheme
@@ -0,0 +1,3 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+exec "$DIR/bin/repl" "$@"
diff --git a/awk/scheme/scheme/scratch/arch-notes.md b/awk/scheme/scheme/scratch/arch-notes.md
new file mode 100644
index 0000000..060ca72
--- /dev/null
+++ b/awk/scheme/scheme/scratch/arch-notes.md
@@ -0,0 +1,115 @@
+# Awk-Scheme: Architectural Notes
+
+## Overview
+Awk-Scheme is a minimal Scheme interpreter implemented in AWK, composed of a compiler and a stack-based virtual machine (VM). The architecture is modular, with clear separation of concerns between parsing/compilation and execution. The design leverages several classic architectural patterns to achieve extensibility, maintainability, and clarity.
+
+---
+
+## 1. Program Flow: High-Level Pipeline
+
+1. **Input**: User provides Scheme code (via REPL or file).
+2. **Compilation**: The compiler (`bin/compiler.awk`) parses and compiles Scheme code into VM instructions.
+3. **Execution**: The VM (`bin/vm.awk`) executes the instructions, managing state, environment, and memory.
+
+---
+
+## 2. Compiler (`bin/compiler.awk`)
+
+### 2.1. Lexical Analysis (Lexer)
+- **Pattern**: *Lexer/Parser Separation* (classic compiler front-end)
+- **Why**: Decouples tokenization from parsing, making the code easier to reason about and extend.
+- **How**: The compiler tokenizes input into numbers, symbols, and parentheses, handling whitespace and comments.
+
+### 2.2. Parsing (Recursive Descent)
+- **Pattern**: *Recursive Descent Parser*
+- **Why**: Simple, direct mapping from grammar to code; easy to debug and extend for a small language.
+- **How**: The parser builds an expression tree from tokens, handling nested expressions and validating syntax.
+
+### 2.3. Code Generation
+- **Pattern**: *Visitor/Dispatcher* (for expression types)
+- **Why**: Each expression type (number, variable, list, special form) is handled by a dedicated function, improving maintainability.
+- **How**: The compiler emits stack-based VM instructions for each expression, handling special forms (define, let, lambda) and function calls.
+
+### 2.4. Closure Support
+- **Pattern**: *Closure Conversion* (from functional programming)
+- **Why**: Enables lexical scoping and first-class functions by capturing the environment at lambda creation.
+- **How**: The compiler emits instructions to capture the current environment and create closure objects.
+
+---
+
+## 3. Virtual Machine (`bin/vm.awk`)
+
+### 3.1. Stack-Based Execution
+- **Pattern**: *Stack Machine* (classic VM design)
+- **Why**: Simplicity and direct mapping from compiled instructions to execution; easy to implement in AWK.
+- **How**: The VM maintains an evaluation stack for operands and results, executing instructions sequentially.
+
+### 3.2. Typed Value System
+- **Pattern**: *Tagged Union* (Algebraic Data Type)
+- **Why**: Enables runtime type checking and safe operations on heterogeneous values.
+- **How**: All values are tagged (e.g., `N:`, `B:`, `P:`, `F:`, `CLOSURE:`) and checked at runtime.
+
+### 3.3. Environment Model
+- **Pattern**: *Environment Chain* (Lexical Scoping)
+- **Why**: Supports variable bindings, lexical scope, and closures.
+- **How**: The VM maintains an environment stack for variable bindings, with special handling for global and closure environments.
+
+### 3.4. Function and Closure Handling
+- **Pattern**: *Direct Function Execution* (no program array modification)
+- **Why**: Simplifies call/return logic and avoids mutation of the instruction stream.
+- **How**: Functions are stored as code blocks; calls execute code directly, with environment management for parameters and closures.
+
+### 3.5. Heap and Memory Management
+- **Pattern**: *Manual Heap with Reference Counting (partial)*
+- **Why**: Enables cons cell allocation and basic memory management.
+- **How**: The VM allocates cons cells on a heap array, with a placeholder for reference counting (not fully implemented).
+
+### 3.6. State Persistence
+- **Pattern**: *State Serialization*
+- **Why**: Allows global state and functions to persist across REPL sessions.
+- **How**: The VM serializes global variables and function definitions to files, loading them on startup.
+
+---
+
+## 4. Extensibility and Maintainability
+- **Pattern**: *Separation of Concerns*
+- **Why**: Compiler and VM are independent, making it easy to extend the language or change the execution model.
+- **Pattern**: *Table-Driven Dispatch* (for built-in functions)
+- **Why**: Adding new primitives or special forms is straightforward.
+
+---
+
+## 5. Notable Limitations
+- No support for nested lambdas (yet), proper tail recursion, or garbage collection.
+- Reference counting is stubbed but not enforced.
+- Error handling is minimal.
+
+---
+
+## 6. Summary Table: Patterns Used
+
+| Area                | Pattern(s) Used                  | Why?                                 |
+|---------------------|----------------------------------|--------------------------------------|
+| Lexing/Parsing      | Lexer/Parser, Recursive Descent  | Simplicity, extensibility            |
+| Code Generation     | Visitor/Dispatcher               | Maintainability, clarity             |
+| VM Execution        | Stack Machine, Tagged Union      | Simplicity, type safety              |
+| Environment         | Environment Chain, Closure Conv. | Lexical scoping, closures            |
+| Function Dispatch   | Table-Driven Dispatch            | Extensibility                        |
+| State Persistence   | State Serialization              | REPL continuity                      |
+| Memory Management   | Manual Heap, Ref Counting (stub) | List support, future GC              |
+
+---
+
+## 7. Architectural Choices: Rationale
+- **AWK as Implementation Language**: Chosen for portability and as a challenge; influences the use of arrays and string-based data structures.
+- **Stack Machine**: Maps well to AWK's capabilities and keeps the VM simple.
+- **Separation of Compiler/VM**: Enables clear boundaries and easier debugging.
+- **Explicit Typing**: Reduces runtime errors and clarifies value handling.
+
+---
+
+## 8. Flow Diagram (Textual)
+
+```
+User Input (Scheme) → [Compiler] → VM Instructions → [VM] → Result/State
+```
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/complex_test.scm.asm b/awk/scheme/scheme/scratch/complex_test.scm.asm
new file mode 100644
index 0000000..67870c3
--- /dev/null
+++ b/awk/scheme/scheme/scratch/complex_test.scm.asm
@@ -0,0 +1,44 @@
+# Test proper list construction (3 2 1)
+# Building the list in proper order: car points to value, cdr points to next pair
+
+# Start with empty list
+PUSH_CONST NIL:           # [nil]
+PRINT                     # Print nil
+
+# Build (1 . nil)
+PUSH_CONST NIL:          # [nil]
+PUSH_CONST N:1          # [nil 1]
+SWAP                    # [1 nil]
+CONS                    # [(1 . nil)]
+DUP
+PRINT                   # Print (1 . nil)
+
+# Build (2 . (1 . nil))
+PUSH_CONST N:2         # [(1.nil) 2]
+SWAP                   # [2 (1.nil)]
+CONS                   # [(2 . (1.nil))]
+DUP
+PRINT                  # Print (2 . (1.nil))
+
+# Build (3 . (2 . (1 . nil)))
+PUSH_CONST N:3        # [(2.(1.nil)) 3]
+SWAP                  # [3 (2.(1.nil))]
+CONS                  # [(3 . (2.(1.nil)))]
+DUP
+PRINT                 # Print full structure
+
+# Test CAR/CDR operations
+DUP                   # Keep a copy of the list for later
+DUP                   # Another copy for CAR
+CAR                   # Get first element (3)
+PRINT                 # Should print 3
+
+SWAP                  # Bring back our spare list copy
+CDR                   # Get rest of list ((2 . (1 . nil)))
+DUP
+PRINT                 # Print rest of list
+
+CAR                   # Get first of rest (2)
+PRINT                 # Should print 2
+
+HALT
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/ideas-for-string-support.md b/awk/scheme/scheme/scratch/ideas-for-string-support.md
new file mode 100644
index 0000000..0d81e5f
--- /dev/null
+++ b/awk/scheme/scheme/scratch/ideas-for-string-support.md
@@ -0,0 +1,556 @@
+# String Support Implementation Plan for Awk-Scheme
+
+## Overview
+This document outlines a comprehensive plan for adding string support to the Awk-Scheme interpreter. The implementation will follow the existing architecture patterns and maintain consistency with the current type system and execution model.
+
+## Current Architecture Analysis
+
+### Type System
+- Current types: `N:`, `B:`, `S:`, `P:`, `F:`, `NIL:`, `CLOSURE:`
+- All values use `type:value` format for runtime type checking
+- Type checking via `getType()` and `getValue()` functions
+- Type predicates: `isNumber()`, `isBoolean()`, `isSymbol()`, etc.
+
+### Compiler Pipeline
+1. **Lexer** (`next_token()`): Handles numbers, symbols, parentheses
+2. **Parser** (`parse_expr()`, `parse_list()`): Builds expression trees
+3. **Code Generator**: Emits VM instructions for different expression types
+4. **Expression Compiler** (`compile_expr()`): Dispatches based on expression type
+
+### VM Architecture
+- Stack-based execution with typed values
+- Environment-based variable binding
+- Built-in function registry (`FUNCTIONS` table)
+- Direct function execution (no program array modification)
+- State persistence for globals and functions
+
+## String Implementation Plan
+
+### Phase 1: Core String Type System
+
+#### 1.1 VM Type System Extensions
+**File: `bin/vm.awk`**
+
+```awk
+# Add to BEGIN block
+T_STRING = "STR"  # String type tag
+
+# Add type predicate
+function isString(val) { return getType(val) == T_STRING }
+
+# String value constructor
+function makeString(val) {
+    return T_STRING ":" val
+}
+```
+
+**Changes Required:**
+- Add `T_STRING` constant in BEGIN block
+- Add `isString()` predicate function
+- Add `makeString()` constructor function
+- Update type checking in existing operations where needed
+
+#### 1.2 String Storage Strategy
+**Options:**
+1. **Inline storage**: Store strings directly in the type:value format
+   - Pros: Simple, fast access
+   - Cons: Limited by awk string length, no escaping issues
+   
+2. **Heap storage**: Store strings in heap like cons cells
+   - Pros: Unlimited length, consistent with existing patterns
+   - Cons: More complex, requires string management
+
+**Recommendation**: Start with inline storage for simplicity, can migrate to heap later.
+
+### Phase 2: Compiler Extensions
+
+#### 2.1 Lexer String Support
+**File: `bin/compiler.awk`**
+
+**Current lexer handles:**
+- Numbers: `-?[0-9]+`
+- Symbols: `[a-zA-Z_][a-zA-Z0-9_]*`
+- Parentheses: `(`, `)`
+
+**New string tokenization:**
+```awk
+# Add to next_token() function
+# Handle string literals (double quotes)
+if (c == "\"") {
+    str = ""
+    input_buffer = substr(input_buffer, 2)  # Skip opening quote
+    
+    while (length(input_buffer) > 0) {
+        c = substr(input_buffer, 1, 1)
+        if (c == "\"") {
+            input_buffer = substr(input_buffer, 2)  # Skip closing quote
+            break
+        }
+        if (c == "\\") {
+            # Handle escape sequences
+            input_buffer = substr(input_buffer, 2)
+            if (length(input_buffer) > 0) {
+                c = substr(input_buffer, 1, 1)
+                if (c == "n") str = str "\n"
+                else if (c == "t") str = str "\t"
+                else if (c == "\\") str = str "\\"
+                else if (c == "\"") str = str "\""
+                else error("Invalid escape sequence: \\" c)
+                input_buffer = substr(input_buffer, 2)
+            }
+        } else {
+            str = str c
+            input_buffer = substr(input_buffer, 2)
+        }
+    }
+    return "\"" str "\""  # Return with quotes for identification
+}
+```
+
+**Escape Sequences to Support:**
+- `\"` - Literal double quote
+- `\\` - Literal backslash  
+- `\n` - Newline
+- `\t` - Tab
+- `\r` - Carriage return
+
+#### 2.2 Parser String Support
+**File: `bin/compiler.awk`**
+
+**Update `parse_expr()`:**
+```awk
+function parse_expr(token, result) {
+    token = next_token()
+    if (token == "EOF") return ""
+    
+    if (token == "(") {
+        result = parse_list()
+        debug("Parsed list: " result)
+        return result
+    }
+    
+    # Handle string literals
+    if (substr(token, 1, 1) == "\"") {
+        debug("Parsed string: " token)
+        return token
+    }
+    
+    debug("Parsed token: " token)
+    return token
+}
+```
+
+#### 2.3 Code Generation for Strings
+**File: `bin/compiler.awk`**
+
+**Add to `compile_expr()`:**
+```awk
+function compile_expr(expr, split_result, op, args) {
+    debug("Compiling expression: " expr)
+    
+    # Handle string literals
+    if (substr(expr, 1, 1) == "\"") {
+        compile_string(expr)
+        return
+    }
+    
+    # ... existing code for numbers, nil, variables, etc.
+}
+
+function compile_string(str) {
+    debug("Compiling string: " str)
+    # Remove outer quotes and emit string constant
+    content = substr(str, 2, length(str) - 2)
+    print "PUSH_CONST STR:" content
+}
+```
+
+### Phase 3: VM String Operations
+
+#### 3.1 String Built-in Functions
+**File: `bin/vm.awk`**
+
+**Add to BEGIN block (built-in registration):**
+```awk
+# String operations
+FUNCTIONS["string-length"] = "string_length"
+FUNCTIONS["string-append"] = "string_append"
+FUNCTIONS["string-ref"] = "string_ref"
+FUNCTIONS["substring"] = "substring"
+FUNCTIONS["string=?"] = "string_equal"
+FUNCTIONS["string<?"] = "string_less_than"
+FUNCTIONS["string>?"] = "string_greater_than"
+FUNCTIONS["string-ci=?"] = "string_ci_equal"
+FUNCTIONS["string-ci<?"] = "string_ci_less_than"
+FUNCTIONS["string-ci>?"] = "string_ci_greater_than"
+```
+
+**Add to function call dispatch in `vm_call_function()`:**
+```awk
+} else if (built_in_name == "string_length") {
+    debug("Calling built-in function: string_length")
+    string_length()
+    return
+} else if (built_in_name == "string_append") {
+    debug("Calling built-in function: string_append")
+    string_append()
+    return
+# ... etc for other string functions
+```
+
+#### 3.2 String Function Implementations
+**File: `bin/vm.awk`**
+
+```awk
+# String length
+function string_length() {
+    if (stack_ptr < 1) error("string-length requires one operand")
+    val = pop()
+    if (!isString(val)) error("string-length requires string operand")
+    str = getValue(val)
+    push(makeValue(T_NUMBER, length(str)))
+}
+
+# String concatenation
+function string_append() {
+    if (stack_ptr < 2) error("string-append requires at least two operands")
+    result = ""
+    # Pop all arguments and concatenate
+    while (stack_ptr > 0) {
+        val = pop()
+        if (!isString(val)) error("string-append requires string operands")
+        result = getValue(val) result
+    }
+    push(makeString(result))
+}
+
+# String character access (0-indexed)
+function string_ref() {
+    if (stack_ptr < 2) error("string-ref requires two operands")
+    index_val = pop()
+    str_val = pop()
+    if (!isNumber(index_val)) error("string-ref index must be a number")
+    if (!isString(str_val)) error("string-ref requires string operand")
+    
+    str = getValue(str_val)
+    idx = getValue(index_val) + 1  # Convert to 1-indexed
+    if (idx < 1 || idx > length(str)) error("string-ref index out of bounds")
+    
+    char = substr(str, idx, 1)
+    push(makeString(char))
+}
+
+# Substring extraction
+function substring() {
+    if (stack_ptr < 3) error("substring requires three operands")
+    end = pop()
+    start = pop()
+    str_val = pop()
+    
+    if (!isNumber(start) || !isNumber(end)) error("substring indices must be numbers")
+    if (!isString(str_val)) error("substring requires string operand")
+    
+    str = getValue(str_val)
+    start_idx = getValue(start) + 1  # Convert to 1-indexed
+    end_idx = getValue(end) + 1
+    
+    if (start_idx < 1 || end_idx > length(str) || start_idx > end_idx) {
+        error("substring indices out of bounds")
+    }
+    
+    result = substr(str, start_idx, end_idx - start_idx + 1)
+    push(makeString(result))
+}
+
+# String comparison (case-sensitive)
+function string_equal() {
+    if (stack_ptr < 2) error("string=? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string=? requires string operands")
+    result = (getValue(val1) == getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_less_than() {
+    if (stack_ptr < 2) error("string<? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string<? requires string operands")
+    result = (getValue(val1) < getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_greater_than() {
+    if (stack_ptr < 2) error("string>? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string>? requires string operands")
+    result = (getValue(val1) > getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Case-insensitive string comparison
+function string_ci_equal() {
+    if (stack_ptr < 2) error("string-ci=? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string-ci=? requires string operands")
+    # Convert to lowercase for comparison
+    str1 = tolower(getValue(val1))
+    str2 = tolower(getValue(val2))
+    result = (str1 == str2) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_ci_less_than() {
+    if (stack_ptr < 2) error("string-ci<? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string-ci<? requires string operands")
+    str1 = tolower(getValue(val1))
+    str2 = tolower(getValue(val2))
+    result = (str1 < str2) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_ci_greater_than() {
+    if (stack_ptr < 2) error("string-ci>? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string-ci>? requires string operands")
+    str1 = tolower(getValue(val1))
+    str2 = tolower(getValue(val2))
+    result = (str1 > str2) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+```
+
+### Phase 4: Enhanced String Operations
+
+#### 4.1 Additional String Functions
+```awk
+# String to number conversion
+function string_to_number() {
+    if (stack_ptr < 1) error("string->number requires one operand")
+    val = pop()
+    if (!isString(val)) error("string->number requires string operand")
+    str = getValue(val)
+    if (str ~ /^-?[0-9]+$/) {
+        push(makeValue(T_NUMBER, str))
+    } else {
+        push(makeValue(T_BOOLEAN, "0"))  # Return false for invalid numbers
+    }
+}
+
+# Number to string conversion
+function number_to_string() {
+    if (stack_ptr < 1) error("number->string requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("number->string requires number operand")
+    num = getValue(val)
+    push(makeString(num))
+}
+
+# String splitting
+function string_split() {
+    if (stack_ptr < 2) error("string-split requires two operands")
+    delimiter = pop()
+    str_val = pop()
+    if (!isString(delimiter) || !isString(str_val)) {
+        error("string-split requires string operands")
+    }
+    
+    str = getValue(str_val)
+    delim = getValue(delimiter)
+    
+    # Use awk's split function
+    split(str, parts, delim)
+    result = ""
+    for (i = 1; i <= length(parts); i++) {
+        if (result != "") result = result " "
+        result = result "\"" parts[i] "\""
+    }
+    push(makeString("(" result ")"))
+}
+```
+
+#### 4.2 String Formatting
+```awk
+# String formatting (simple version)
+function format() {
+    if (stack_ptr < 2) error("format requires at least two operands")
+    format_str = pop()
+    if (!isString(format_str)) error("format requires string format operand")
+    
+    # Simple implementation - replace ~a with arguments
+    fmt = getValue(format_str)
+    arg_count = 0
+    
+    while (stack_ptr > 0) {
+        val = pop()
+        arg_count++
+        # Replace ~a with the value
+        gsub(/~a/, val, fmt)
+    }
+    
+    push(makeString(fmt))
+}
+```
+
+### Phase 5: State Persistence for Strings
+
+#### 5.1 String State Management
+**File: `bin/vm.awk`**
+
+**Update `save_state()` and state loading:**
+- Strings stored in environment will be automatically persisted
+- No special handling needed since strings use inline storage
+- String literals in function definitions will be preserved
+
+**Considerations:**
+- Long strings may impact state file size
+- Escape sequences need proper handling in state files
+- String encoding consistency across sessions
+
+### Phase 6: Testing and Validation
+
+#### 6.1 Test Cases
+**Create test files:**
+
+```scheme
+; Basic string literals
+"hello world"
+""
+"\"quoted\""
+"line1\nline2"
+
+; String operations
+(string-length "hello")
+(string-append "hello" " " "world")
+(string-ref "hello" 0)
+(substring "hello world" 0 4)
+
+; String comparisons
+(string=? "hello" "hello")
+(string=? "hello" "world")
+(string<? "abc" "def")
+(string>? "xyz" "abc")
+
+; Case-insensitive comparisons
+(string-ci=? "Hello" "hello")
+(string-ci<? "ABC" "def")
+
+; Conversions
+(string->number "123")
+(number->string 456)
+(string->number "abc")
+
+; String in expressions
+(define greeting "Hello")
+(define name "World")
+(string-append greeting " " name)
+
+; Strings in functions
+(define (greet name) (string-append "Hello, " name "!"))
+(greet "Alice")
+```
+
+#### 6.2 Edge Cases to Test
+- Empty strings
+- Strings with special characters
+- Escape sequences
+- Very long strings
+- String operations on non-string types
+- String comparisons with different encodings
+- String persistence across REPL sessions
+
+### Phase 7: Performance and Optimization
+
+#### 7.1 Performance Considerations
+- **String concatenation**: Current `string-append` is O(n²) - consider optimization
+- **String storage**: Monitor memory usage with large strings
+- **String comparisons**: Consider early termination for long strings
+- **Escape sequence processing**: Optimize lexer for common cases
+
+#### 7.2 Potential Optimizations
+```awk
+# Optimized string concatenation (build in reverse)
+function string_append_optimized() {
+    if (stack_ptr < 2) error("string-append requires at least two operands")
+    
+    # Count arguments and pre-allocate
+    arg_count = 0
+    temp_stack[0] = stack_ptr
+    
+    # Pop all arguments to temp storage
+    while (stack_ptr > 0) {
+        val = pop()
+        if (!isString(val)) error("string-append requires string operands")
+        temp_stack[++arg_count] = getValue(val)
+    }
+    
+    # Concatenate in reverse order (more efficient)
+    result = ""
+    for (i = arg_count; i >= 1; i--) {
+        result = result temp_stack[i]
+    }
+    
+    push(makeString(result))
+}
+```
+
+### Phase 8: Documentation and Examples
+
+#### 8.1 Update README.md
+- Add string data type to type system documentation
+- Include string usage examples
+- Document all string built-in functions
+- Add string limitations and considerations
+
+#### 8.2 Update diagram.md
+- Add string type to data type diagram
+- Include string operations in VM instruction set
+- Show string flow in execution examples
+
+### Implementation Order and Risk Assessment
+
+#### High Priority (Core Functionality)
+1. **Type system extensions** - Low risk, foundational
+2. **Lexer string support** - Medium risk, affects parsing
+3. **Basic string operations** - Low risk, self-contained
+4. **String literals in expressions** - Medium risk, integration
+
+#### Medium Priority (Enhanced Features)
+5. **String comparisons** - Low risk, straightforward
+6. **String conversions** - Low risk, utility functions
+7. **State persistence** - Low risk, automatic
+
+#### Lower Priority (Advanced Features)
+8. **String formatting** - Medium risk, complex parsing
+9. **String splitting** - Low risk, utility function
+10. **Performance optimizations** - Low risk, optional
+
+#### Risk Mitigation
+- **Regression testing**: Ensure existing functionality unchanged
+- **Incremental implementation**: Add features one at a time
+- **Comprehensive testing**: Test all edge cases
+- **Backward compatibility**: Maintain existing API
+
+### Success Criteria
+1. String literals parse and compile correctly
+2. Basic string operations work as expected
+3. String state persists across REPL sessions
+4. No regression in existing functionality
+5. Performance remains acceptable
+6. Documentation is complete and accurate
+
+### Future Enhancements
+1. **Heap-based string storage** for very long strings
+2. **String interning** for memory efficiency
+3. **Unicode support** (complex, requires significant changes)
+4. **Regular expression support** for string matching
+5. **String formatting with more features** (like Common Lisp format)
+6. **String streams** for efficient string building
+
+This plan provides a comprehensive roadmap for implementing string support while maintaining the existing architecture and ensuring backward compatibility. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/random.txt b/awk/scheme/scheme/scratch/random.txt
new file mode 100644
index 0000000..20b3bcf
--- /dev/null
+++ b/awk/scheme/scheme/scratch/random.txt
@@ -0,0 +1,112 @@
+Other Uses for the Awk-Scheme VM
+================================
+
+The stack-based VM in Awk-Scheme is surprisingly versatile. Here are some realistic alternatives that could be implemented using the same VM architecture:
+
+## 1. Forth Implementation
+**Feasibility: High**
+
+Forth is a natural fit since it's already stack-based:
+- **Stack Operations**: VM already has PUSH_CONST, POP, DUP, SWAP
+- **Arithmetic**: ADD, SUB, MUL, DIV are perfect for Forth
+- **Memory**: Could extend heap for Forth's memory model
+- **Control Flow**: Would need to add conditional jumps and loops
+- **Words**: Could map Forth words to VM functions
+
+**Required Extensions:**
+- JMP, JZ (jump if zero), JNZ instructions
+- More stack operations (OVER, ROT, etc.)
+- Memory read/write operations
+- Input/output operations
+
+## 2. Simple Calculator Language
+**Feasibility: Very High**
+
+A basic calculator with variables and functions:
+- **Syntax**: `x = 5; y = x + 3; print y`
+- **Features**: Variables, basic math, simple functions
+- **VM Fit**: Perfect - already has arithmetic, variables, functions
+
+**Minimal Changes Needed:**
+- New parser for calculator syntax
+- Assignment operator handling
+- Print statement
+
+## 3. Configuration Language
+**Feasibility: High**
+
+A simple config language for key-value pairs and nested structures:
+- **Syntax**: `server { port = 8080; host = "localhost"; }`
+- **Features**: Nested objects, arrays, basic expressions
+- **VM Fit**: Good - can use cons cells for nested structures
+
+**Required Extensions:**
+- String support
+- Object/struct creation
+- Field access operations
+
+## 4. Simple Scripting Language
+**Feasibility: Medium**
+
+A basic scripting language with loops and conditionals:
+- **Syntax**: `if x > 0 { y = x * 2; } else { y = 0; }`
+- **Features**: Variables, conditionals, loops, functions
+- **VM Fit**: Good but needs control flow
+
+**Required Extensions:**
+- Conditional jumps
+- Loop constructs
+- Boolean logic operations
+
+## 5. Data Processing Language
+**Feasibility: Medium**
+
+A language for simple data transformations:
+- **Syntax**: `filter(x > 0) | map(x * 2) | sum()`
+- **Features**: Pipeline operations, list processing
+- **VM Fit**: Good - can use cons cells for lists
+
+**Required Extensions:**
+- List operations (map, filter, reduce)
+- Pipeline operator
+- More built-in functions
+
+## 6. Simple Logic/Constraint Language
+**Feasibility: High**
+
+A language for expressing simple constraints and rules:
+- **Syntax**: `rule: if age > 18 then can_vote = true`
+- **Features**: Rules, facts, simple inference
+- **VM Fit**: Good - boolean operations and variables
+
+**Required Extensions:**
+- Boolean logic (AND, OR, NOT)
+- Rule evaluation
+- Fact storage
+
+## VM Strengths for Alternative Languages:
+1. **Stack-based**: Natural for many languages
+2. **Typed values**: Good foundation for type safety
+3. **Environment model**: Supports variables and scoping
+4. **Function system**: Reusable for different syntaxes
+5. **Extensible**: Easy to add new instructions
+
+## VM Limitations for Alternative Languages:
+1. **Limited data types**: Only numbers, booleans, pairs, symbols
+2. **No strings**: Would need to add string support
+3. **Limited control flow**: Only function calls, no loops/conditionals
+4. **No I/O**: Would need file/console operations
+5. **Memory constraints**: Simple heap model
+
+## Most Realistic Next Steps:
+1. **Forth**: Natural progression, leverages existing stack operations
+2. **Calculator**: Minimal changes, good learning exercise
+3. **Config Language**: Practical use case, moderate complexity
+
+## Implementation Strategy:
+1. Keep the VM unchanged
+2. Write new compilers for different syntaxes
+3. Add minimal VM extensions as needed
+4. Reuse existing VM infrastructure (stack, environment, functions)
+
+The VM's simplicity is actually a strength - it's easy to understand and extend, making it a good foundation for experimenting with different language designs. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/run.sh b/awk/scheme/scheme/scratch/run.sh
new file mode 100755
index 0000000..0afdb41
--- /dev/null
+++ b/awk/scheme/scheme/scratch/run.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# Compile Scheme to VM instructions
+awk -f compiler.awk test.scm > test.asm
+# Run VM instructions
+awk -f vm.awk test.asm
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/test.asm b/awk/scheme/scheme/scratch/test.asm
new file mode 100644
index 0000000..8e7d8df
--- /dev/null
+++ b/awk/scheme/scheme/scratch/test.asm
@@ -0,0 +1,16 @@
+PUSH_CONST N:1
+PUSH_CONST N:2
+ADD
+PUSH_CONST N:3
+PUSH_CONST N:4
+MUL
+PUSH_CONST N:10
+PUSH_CONST N:2
+PUSH_CONST N:3
+ADD
+SUB
+PUSH_CONST NIL:
+CONS
+CONS
+CONS
+HALT
diff --git a/awk/scheme/scheme/scratch/test.scm b/awk/scheme/scheme/scratch/test.scm
new file mode 100644
index 0000000..a01b174
--- /dev/null
+++ b/awk/scheme/scheme/scratch/test.scm
@@ -0,0 +1,8 @@
+;; Build a list of calculated values
+(cons (+ 1 2)           ; First element: 1 + 2 = 3
+      (cons (* 3 4)     ; Second element: 3 * 4 = 12
+            (cons (- 10 
+                    (+ 2 3))  ; Third element: 10 - (2 + 3) = 5
+                  nil)))      ; End of list
+
+;; This should create a list: (3 12 5)
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/test.scm.asm b/awk/scheme/scheme/scratch/test.scm.asm
new file mode 100644
index 0000000..526e2b1
--- /dev/null
+++ b/awk/scheme/scheme/scratch/test.scm.asm
@@ -0,0 +1,7 @@
+PUSH_CONST N:5
+PUSH_CONST N:3
+ADD
+PUSH_CONST N:2
+MUL
+PRINT # should output N:16
+HALT
\ No newline at end of file
diff --git a/awk/vm/README.md b/awk/vm/README.md
new file mode 100644
index 0000000..83a35fd
--- /dev/null
+++ b/awk/vm/README.md
@@ -0,0 +1,91 @@
+# Stack-Based Virtual Machine in AWK
+
+A simple stack-based virtual machine implementation in AWK, inspired by Forth. The VM provides basic stack manipulation, arithmetic operations, register access, and memory operations.
+
+## Architecture
+
+The VM consists of:
+- A data stack (100 elements)
+- Main memory (1000 cells)
+- Three registers:
+  - A: General purpose register
+  - B: Often used as memory pointer
+  - P: Program pointer, used for sequential memory operations
+
+## Instruction Set
+
+### Stack Operations
+- `DROP` - Remove top item from stack
+- `DUP` - Duplicate top stack item
+- `OVER` - Copy second item to top of stack
+- `SWAP` - Exchange top two stack items
+- Numbers are automatically pushed onto the stack
+
+### Arithmetic Operations
+- `+` - Add top two stack items (a b -- a+b)
+- `*` - Multiply top two stack items (a b -- a*b)
+- `AND` - Bitwise AND of top two items
+- `XOR` - Bitwise XOR of top two items
+- `NOT` - Bitwise NOT of top item
+- `2*` - Multiply top item by 2 (shift left)
+- `2/` - Divide top item by 2 (shift right)
+
+### Register Operations
+- `A` - Push value of A register onto stack
+- `A!` - Store top stack value into A register
+- `B!` - Store top stack value into B register
+
+### Memory Operations
+- `@` - Fetch from memory address on stack (addr -- value)
+- `!` - Store to memory address on stack (value addr --)
+- `@+` - Fetch from memory at P, then increment P
+- `!+` - Store to memory at P, then increment P
+- `@B` - Fetch from memory address in B register
+- `!B` - Store to memory address in B register
+- `@P` - Fetch from memory address in P register
+- `!P` - Store to memory address in P register
+
+### Debug & Control
+- `.` - NO-OP (does nothing)
+- `BYE` - Exit program
+- `SHOW` - Display current machine state (stack, registers, memory)
+
+## Memory Model
+
+- Memory is zero-based
+- Each cell can hold a numeric value
+- Memory is accessed either directly (using @ and !) or through registers
+- P register is typically used for sequential memory operations
+- B register is typically used as a memory pointer
+
+## Example Programs
+
+### Store and retrieve a value
+```
+5 DUP 0 ! # Store 5 at address 0
+3 DUP 1 ! # Store 3 at address 1
+0 @ 1 @ + # Load both values and add them
+2 ! # Store result at address 2
+```
+
+### Using registers
+```
+42 A! # Store 42 in A register
+A # Push A's value onto stack
+100 B! # Set B to address 100
+42 !B # Store 42 at address 100
+@B # Read from address 100
+```
+
+## Usage
+
+```bash
+# Run a program directly
+echo "5 3 + SHOW" | awk -f vm.awk
+
+# Compile and run a program
+./compiler.py program.coffee | awk -f vm.awk
+
+# Run test suite
+./vm_tests.sh
+```
\ No newline at end of file
diff --git a/awk/vm/compiler.py b/awk/vm/compiler.py
new file mode 100755
index 0000000..a406779
--- /dev/null
+++ b/awk/vm/compiler.py
@@ -0,0 +1,172 @@
+#!/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'"""
+        # 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)
+        
+        print(f"# Compiling assignment: {var_name} = {expression}", file=sys.stderr)
+        
+        # First get the memory location
+        mem_loc = self.allocate_variable(var_name)
+        
+        # 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
+        
+        # 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
+    
+    def compile_expression(self, expr):
+        """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)
+            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 = {
+            '+': '+',
+            '*': '*',
+            '-': 'NOT +',
+        }
+        
+        # Try each operator
+        for op in ops:
+            if op in expr:
+                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'):
+            line = line.strip()
+            if not line or line.startswith('#'):
+                continue
+                
+            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)
+            
+        # Add final SHOW to see the result
+        output.append("SHOW")
+        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/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.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
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
new file mode 100755
index 0000000..67da3e7
--- /dev/null
+++ b/awk/vm/vm.awk
@@ -0,0 +1,254 @@
+#!/usr/bin/awk -f
+
+
+# Stack: DROP, DUP, OVER, PUSH, POP
+# Math:	+ AND XOR NOT 2* 2/ multiply-step
+# Call:	JUMP CALL RETURN IF -IF
+# Loop:	NEXT UNEXT
+# Register:	A A! B!
+# Memory: @ ! @+ !+ @B !B @P !P
+# NO-OP: .
+
+
+BEGIN {
+    # Initialize VM state
+    stack_pointer = 0    # Points to next free position
+    pc = 0               # Program counter
+    MAX_STACK = 100      # Maximum stack size
+    MAX_MEM = 1000       # Memory size
+    
+    # Initialize registers
+    A = 0              # A register
+    B = 0              # B register
+    P = 0              # P register (auxiliary pointer)
+    
+    # Stack operations
+    split("", stack)   # Initialize stack array
+    split("", memory)  # Initialize memory array
+}
+
+# Stack operations
+function push(value) {
+    if (stack_pointer >= MAX_STACK) {
+        print "Stack overflow!" > "/dev/stderr"
+        exit 1
+    }
+    printf "# DEBUG: Pushing %d onto stack\n", value > "/dev/stderr"
+    stack[stack_pointer++] = value
+}
+
+function pop() {
+    if (stack_pointer <= 0) {
+        print "Stack underflow!" > "/dev/stderr"
+        exit 1
+    }
+    value = stack[--stack_pointer]
+    printf "# DEBUG: Popping %d from stack\n", value > "/dev/stderr"
+    return value
+}
+
+# Basic stack manipulation
+function op_drop() {
+    pop()
+}
+
+function op_dup() {
+    if (stack_pointer <= 0) {
+        print "Stack underflow on DUP!" > "/dev/stderr"
+        exit 1
+    }
+    push(stack[stack_pointer - 1])
+}
+
+function op_over() {
+    if (stack_pointer <= 1) {
+        print "Stack underflow on OVER!" > "/dev/stderr"
+        exit 1
+    }
+    push(stack[stack_pointer - 2])
+}
+
+# Basic arithmetic operations
+function op_add() {
+    b = pop()
+    a = pop()
+    result = a + b
+    printf "# DEBUG: Adding %d + %d = %d\n", a, b, result > "/dev/stderr"
+    push(result)
+}
+
+function op_and() {
+    b = pop()
+    a = pop()
+    # For now, we'll just multiply as a placeholder
+    # In a real implementation, we'd need to implement proper bitwise AND
+    push(a * b)
+}
+
+function op_xor() {
+    b = pop()
+    a = pop()
+    # For now, we'll just add as a placeholder
+    # In a real implementation, we'd need to implement proper bitwise XOR
+    push(a + b)
+}
+
+function op_not() {
+    a = pop()
+    # For now, we'll just negate as a placeholder
+    # In a real implementation, we'd need to implement proper bitwise NOT
+    push(-a - 1)
+}
+
+function op_2times() {
+    a = pop()
+    push(a * 2)
+}
+
+function op_2div() {
+    a = pop()
+    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)
+}
+
+function op_astore() {
+    A = pop()
+}
+
+function op_bstore() {
+    B = pop()
+}
+
+# Memory operations
+function op_fetch() {
+    addr = pop()
+    value = memory[addr]
+    printf "# DEBUG: Fetching %d from memory[%d]\n", value, addr > "/dev/stderr"
+    push(value)
+}
+
+function op_store() {
+    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
+}
+
+function op_fetchplus() {
+    push(memory[P++])
+}
+
+function op_storeplus() {
+    memory[P++] = pop()
+}
+
+function op_fetchb() {
+    push(memory[B])
+}
+
+function op_storeb() {
+    memory[B] = pop()
+}
+
+function op_fetchp() {
+    push(memory[P])
+}
+
+function op_storep() {
+    memory[P] = pop()
+}
+
+function print_stack() {
+    printf "Stack: "
+    for (i = 0; i < stack_pointer; i++) {
+        printf "%d ", stack[i]
+    }
+    printf "\n"
+}
+
+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 "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) {
+    if (inst ~ /^[0-9]+$/) {
+        # Numbers are pushed onto the stack
+        push(int(inst))
+        return
+    }
+    
+    if (inst == "BYE")      { exit 0 } # not really in the minimal spec as set out by Chuck Moore, but useful for a graceful exit.
+    if (inst == "DROP")     { op_drop(); return }
+    if (inst == "DUP")      { op_dup(); return }
+    if (inst == "OVER")     { op_over(); return } # copy second item to top of stack
+    if (inst == "SWAP")     { op_swap(); return } # swap top two stack items
+    if (inst == "+")        { op_add(); return }
+    if (inst == "AND")      { op_and(); return }
+    if (inst == "XOR")      { op_xor(); return }
+    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
+    if (inst == "@")        { op_fetch(); return } # fetch from memory
+    if (inst == "!")        { op_store(); return } # store to memory
+    if (inst == "@+")       { op_fetchplus(); return } # fetch from memory at P+
+    if (inst == "!+")       { op_storeplus(); return } # store to memory at P+
+    if (inst == "@B")       { op_fetchb(); return } # fetch from memory at B
+    if (inst == "!B")       { op_storeb(); return } # store to memory at B
+    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 } # show state info
+    
+    print "Unknown instruction: " inst > "/dev/stderr"
+    exit 1
+}
+
+# Main execution loop
+{
+    # Remove comments (everything after #)
+    sub(/#.*$/, "")
+    
+    # Skip empty lines after comment removal
+    if (NF == 0) next
+    
+    # Split the input line into words
+    n = split($0, words)
+    for (i = 1; i <= n; i++) {
+        execute_instruction(words[i])
+    }
+}
diff --git a/awk/vm/vm_tests.sh b/awk/vm/vm_tests.sh
new file mode 100755
index 0000000..6244c51
--- /dev/null
+++ b/awk/vm/vm_tests.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+echo "Running VM tests..."
+echo
+
+echo "Test 1: Basic register A operations"
+echo "42 A! A A     # Store 42 in A, then read A twice" | awk -f vm.awk
+echo
+
+echo "Test 2: Register A and B with memory operations"
+echo "100 A! 200 B! 42 @B     # Store 100 in A, 200 in B, read from B's address" | awk -f vm.awk
+echo
+
+echo "Test 3: Sequential memory operations using P register"
+echo "0 !P 1 !+ 2 !+ 3 !+ 4 !+ 5 !+     # Store 1-5 sequentially using P" | awk -f vm.awk
+echo "0 !P @+ @+ @+ @+ @+     # Read back values using P" | awk -f vm.awk
+echo
+
+echo "Test 4: Complex register manipulation"
+echo "42 A! A DUP B! @B     # Store 42 in A, copy to B, read via B" | awk -f vm.awk
+echo
+
+echo "Test 5: Register arithmetic"
+echo "5 A! 3 B! A @B +     # Store 5 in A, 3 in B, add A + mem[B]" | awk -f vm.awk
+echo
+
+echo "Test 6: Memory pointer operations"
+echo "42 0 ! 1 !P @P     # Store 42 at addr 0, point P to 1, read P" | awk -f vm.awk
+echo
+
+echo "Test 7: Register and memory interaction"
+echo "10 A! 20 B! A @B !     # Store A's value at B's address" | awk -f vm.awk
+echo "@B     # Read from memory at B's address" | awk -f vm.awk
+echo
+
+echo "Test 8: Demonstrating B! vs !B"
+echo "100 B!     # Set B register to 100" | awk -f vm.awk
+echo "42 !B      # Store 42 at memory location 100" | awk -f vm.awk
+echo "@B         # Read from memory location 100" | awk -f vm.awk
+echo
+
+echo "Tests completed." 
\ No newline at end of file