about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-01-19 14:48:20 -0500
committerelioat <elioat@tilde.institute>2025-01-19 14:48:20 -0500
commitc70daa13c1dc3b996c4b92cfc79be1f533a1e780 (patch)
treedc7ec565eca784e74ef2f3e3beb64d62982f0980
parentebb50d6472b6eff661022de9b50c35e293b7326d (diff)
downloadtour-c70daa13c1dc3b996c4b92cfc79be1f533a1e780.tar.gz
*
-rwxr-xr-xawk/scheme/scheme/bin/compiler.awk253
-rwxr-xr-xawk/scheme/scheme/bin/repl124
-rwxr-xr-xawk/scheme/scheme/bin/vm.awk264
-rw-r--r--awk/scheme/scheme/docs/awk-scheme-prompt.md189
-rw-r--r--awk/scheme/scheme/docs/awk-vm-implementation-prompt.md226
-rw-r--r--awk/scheme/scheme/docs/scheme-compilation-examples.md222
-rw-r--r--awk/scheme/scheme/docs/scheme-compiler-impl.md307
-rw-r--r--awk/scheme/scheme/docs/scheme-vm-prompt.md112
-rw-r--r--awk/scheme/scheme/docs/scheme-vm-spec.md130
-rw-r--r--awk/scheme/scheme/docs/test-program.md48
-rw-r--r--awk/scheme/scheme/examples/test.scm3
-rwxr-xr-xawk/scheme/scheme/scheme3
-rw-r--r--awk/scheme/scheme/scratch/complex_test.scm.asm44
-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
17 files changed, 1961 insertions, 0 deletions
diff --git a/awk/scheme/scheme/bin/compiler.awk b/awk/scheme/scheme/bin/compiler.awk
new file mode 100755
index 0000000..b1a2a10
--- /dev/null
+++ b/awk/scheme/scheme/bin/compiler.awk
@@ -0,0 +1,253 @@
+#!/usr/bin/awk -f
+
+BEGIN {
+    # Compiler state
+    curr_token = ""
+    input_buffer = ""
+    next_label = 0
+    program = ""
+    
+    # Debug mode
+    DEBUG = 1
+}
+
+function debug(msg) {
+    if (DEBUG) print "[DEBUG] " msg > "/dev/stderr"
+}
+
+# Clean line by removing comments
+function clean_line(line) {
+    # Remove everything after and including semicolon
+    sub(/;.*$/, "", line)
+    # Trim whitespace
+    sub(/^[ \t]+/, "", line)
+    sub(/[ \t]+$/, "", line)
+    return line
+}
+
+# Process input line
+{
+    line = clean_line($0)
+    if (line != "") {
+        if (program != "") program = program " "
+        program = program line
+    }
+}
+
+END {
+    debug("Input program after cleaning: " program)
+    if (program == "") exit
+    
+    # Parse and compile the program
+    expr = parse_expr()
+    debug("Parsed expression: " expr)
+    compile_expr(expr)
+    print "HALT"
+}
+
+# Lexer functions
+function is_digit(c) { return c >= "0" && c <= "9" }
+function is_whitespace(c) { return c == " " || c == "\t" || c == "\n" }
+
+function next_token() {
+    # Initialize input_buffer if this is first call
+    if (input_buffer == "") input_buffer = program
+    
+    # Skip whitespace
+    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"
+    
+    c = substr(input_buffer, 1, 1)
+    if (c == "(" || c == ")") {
+        input_buffer = substr(input_buffer, 2)
+        return c
+    }
+    
+    # Handle numbers
+    if (is_digit(c) || c == "-" && length(input_buffer) > 1 && is_digit(substr(input_buffer, 2, 1))) {
+        num = ""
+        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
+    sym = ""
+    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
+}
+
+# Parser functions
+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
+}
+
+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 ")"
+}
+
+# Split expression into operator and arguments
+function split_expr(expr,    i, len, c, op, args, paren_count) {
+    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)
+    return op SUBSEP args
+}
+
+# Split arguments handling nested parentheses
+function split_args(args, arg_array,    len, i, c, current, paren_count, arg_count) {
+    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 functions
+function compile_number(num) {
+    debug("Compiling number: " num)
+    print "PUSH_CONST N:" num
+}
+
+function compile_primitive_call(op, args,    arg_array, nargs, i) {
+    debug("Primitive call: op=" op " args=" args)
+    nargs = split_args(args, arg_array)
+    
+    # Compile each argument
+    for (i = 1; i <= nargs; i++) {
+        compile_expr(arg_array[i])
+    }
+    
+    if (op == "+") {
+        for (i = 1; i < nargs; i++)
+            print "ADD"
+    }
+    else if (op == "-") {
+        if (nargs == 1) {
+            print "PUSH_CONST N:0"
+            print "SWAP"
+        }
+        for (i = 1; i < nargs; i++)
+            print "SUB"
+    }
+    else if (op == "*") {
+        for (i = 1; i < nargs; i++)
+            print "MUL"
+    }
+    else if (op == "cons") {
+        if (nargs != 2) error("cons requires 2 arguments")
+        print "CONS"
+    }
+    else if (op == "car") {
+        if (nargs != 1) error("car requires 1 argument")
+        print "CAR"
+    }
+    else if (op == "cdr") {
+        if (nargs != 1) error("cdr requires 1 argument")
+        print "CDR"
+    }
+    else {
+        error("Unknown operator: " op)
+    }
+}
+
+function compile_expr(expr,    split_result, op, args) {
+    debug("Compiling expression: " expr)
+    
+    if (expr ~ /^-?[0-9]+$/) {
+        compile_number(expr)
+        return
+    }
+    
+    if (expr == "nil") {
+        print "PUSH_CONST NIL:"
+        return
+    }
+    
+    if (substr(expr, 1, 1) == "(") {
+        # Strip outer parentheses
+        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)
+        
+        debug("Split expression: op=" op " args=" args)
+        compile_primitive_call(op, args)
+        return
+    }
+    
+    error("Unknown expression type: " expr)
+}
+
+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..a3f66fe
--- /dev/null
+++ b/awk/scheme/scheme/bin/repl
@@ -0,0 +1,124 @@
+#!/bin/bash
+
+# Enable debug tracing
+DEBUG=0
+
+debug() {
+    if [ "$DEBUG" = "1" ]; then
+        echo "[DEBUG] $*" >&2
+    fi
+}
+
+# Find the directory containing this script and the components
+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 [ ! -x "$component" ]; then
+        echo "Error: Cannot execute $component" >&2
+        echo "Please ensure all components are present and executable" >&2
+        exit 1
+    fi
+done
+
+# Create temporary directory for our work
+TMPDIR=$(mktemp -d)
+debug "Created temp dir: $TMPDIR"
+
+cleanup() {
+    debug "Cleaning up temp dir: $TMPDIR"
+    rm -rf "$TMPDIR"
+}
+trap cleanup EXIT
+
+# Set up temporary files
+INPUT_FILE="$TMPDIR/input.scm"
+ASM_FILE="$TMPDIR/output.asm"
+
+# Function to handle evaluation
+evaluate_expression() {
+    local input="$1"
+    local result
+    
+    debug "Evaluating expression: $input"
+    
+    # Write to input file
+    echo "$input" > "$INPUT_FILE"
+    debug "Wrote to input file: $INPUT_FILE"
+    
+    # Show compilation command
+    debug "Running compiler: $COMPILER $INPUT_FILE > $ASM_FILE"
+    
+    # Compile and show the generated assembly
+    if "$COMPILER" "$INPUT_FILE" > "$ASM_FILE" 2>/dev/null; then
+        debug "Compilation successful"
+        debug "Generated assembly:"
+        debug "$(cat "$ASM_FILE")"
+        
+        debug "Running VM: $VM $ASM_FILE"
+        result=$("$VM" "$ASM_FILE")
+        debug "VM output: '$result'"
+        
+        # Only print if there's a result
+        if [ -n "$result" ]; then
+            echo "$result"
+        else
+            debug "No output from VM"
+        fi
+        return 0
+    else
+        echo "Compilation error" >&2
+        return 1
+    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
+    # Show appropriate prompt
+    if [ $paren_count -eq 0 ]; then
+        printf "scheme> "
+    else
+        printf "... "
+    fi
+    
+    # Read a line
+    read -r line || exit 0
+    
+    # Skip empty lines
+    if [ -z "$line" ]; then
+        continue
+    fi
+    
+    # Count parentheses
+    open_parens=$(echo "$line" | tr -cd '(' | wc -c)
+    close_parens=$(echo "$line" | tr -cd ')' | wc -c)
+    paren_count=$((paren_count + open_parens - close_parens))
+    
+    debug "Paren count: $paren_count"
+    
+    # Append to current input
+    if [ -n "$current_input" ]; then
+        current_input="$current_input $line"
+    else
+        current_input="$line"
+    fi
+    
+    # If we have a complete expression, evaluate it
+    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..ce81bbe
--- /dev/null
+++ b/awk/scheme/scheme/bin/vm.awk
@@ -0,0 +1,264 @@
+#!/usr/bin/awk -f
+
+# VM State Initialization
+BEGIN {
+    # Type tags
+    T_NUMBER = "N"
+    T_BOOLEAN = "B"
+    T_SYMBOL = "S"
+    T_PAIR = "P"
+    T_FUNCTION = "F"
+    T_NIL = "NIL"
+
+    # VM registers
+    stack_ptr = 0    # Stack pointer
+    heap_ptr = 0     # Heap pointer
+    pc = 0           # Program counter
+    
+    # Debug mode
+    DEBUG = 0
+}
+
+# Debug output function
+function debug(msg) {
+    if (DEBUG) {
+        printf("[DEBUG] %s\n", msg) > "/dev/stderr"
+    }
+}
+
+# Value construction and access
+function makeValue(type, val) {
+    return type ":" val
+}
+
+function getType(val) {
+    return substr(val, 1, index(val, ":") - 1)
+}
+
+function getValue(val) {
+    return substr(val, index(val, ":") + 1)
+}
+
+# Type checking
+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 }
+
+# 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")
+    return stack[stack_ptr]
+}
+
+# Heap operations
+function allocate(val) {
+    heap[++heap_ptr] = val
+    refs[heap_ptr] = 1
+    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 operations
+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 operations
+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"
+    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"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Instruction execution
+function execute(instr) {
+    split(instr, parts, " ")
+    op = parts[1]
+    debug("Execute: " instr)
+    
+    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()
+        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") {
+        if (stack_ptr > 0) {
+            print peek()
+        }
+        exit(0)
+    }
+    else {
+        error("Unknown instruction: " op)
+    }
+}
+
+# Program loading
+{
+    # Store each line as an instruction
+    program[NR-1] = $0
+}
+
+# Program execution
+END {
+    # Execute program
+    while (pc < length(program)) {
+        execute(program[pc++])
+    }
+    
+    # Print final result if any and we haven't HALTed
+    if (stack_ptr > 0) {
+        print peek()
+    }
+}
\ No newline at end of file
diff --git a/awk/scheme/scheme/docs/awk-scheme-prompt.md b/awk/scheme/scheme/docs/awk-scheme-prompt.md
new file mode 100644
index 0000000..f7e0414
--- /dev/null
+++ b/awk/scheme/scheme/docs/awk-scheme-prompt.md
@@ -0,0 +1,189 @@
+# Implementation Request for AWK-based Scheme Virtual Machine
+
+I need help implementing a stack-based virtual machine for a minimal Scheme implementation in AWK. The implementation should work with standard AWK (gawk features optional).
+
+## Core Data Structures
+
+### Value Representation
+Values in AWK will be represented as strings with type tags. Each value should be a string with format "TYPE:VALUE" where:
+- Numbers: "N:123.45"
+- Booleans: "B:1" or "B:0"
+- Symbols: "S:symbol-name"
+- Pairs: "P:car_idx,cdr_idx" (indices into heap array)
+- Functions: "F:addr,env_idx" (instruction address and environment index)
+- Nil: "NIL:"
+
+### Memory Model
+Using AWK's associative arrays:
+```awk
+# Stack - numeric indexed array
+stack[stack_ptr]
+
+# Heap - numeric indexed array for allocated objects
+heap[heap_ptr]
+
+# Environments - numeric indexed array of frames
+env[env_ptr]
+
+# Each environment frame is stored as concatenated strings:
+# "name1:val1,name2:val2,..."
+```
+
+### Instruction Format
+Instructions stored in array with format:
+```awk
+instr[addr] = "OPCODE OPERAND1 OPERAND2..."
+```
+
+## Core Components Needed
+
+1. Value Handling
+```awk
+# Type checking
+function isNumber(val) { return substr(val, 1, 2) == "N:" }
+function isSymbol(val) { return substr(val, 1, 2) == "S:" }
+# etc.
+
+# Value extraction
+function getValue(val) { return substr(val, 3) }
+```
+
+2. Memory Management
+- Simple reference counting using an additional array
+- Object allocation through heap_ptr increment
+- Basic sweep of unreferenced heap cells
+
+3. Stack Operations
+```awk
+# Push and pop
+function push(val) { stack[++stack_ptr] = val }
+function pop() { return stack[stack_ptr--] }
+```
+
+4. Environment Management
+- Environment represented as chain of frames in env[] array
+- Each frame is a string of name:value pairs
+- Lookup walks the chain for variable resolution
+
+## Implementation Steps
+
+1. Parser/Tokenizer:
+   - Read instruction format from input file
+   - Parse into instruction array
+   - Handle basic syntax for immediate values
+
+2. Value System:
+   - Type tag handling
+   - Value construction
+   - Type checking
+   - Value extraction
+
+3. Core VM:
+   - Instruction dispatch
+   - Stack manipulation
+   - Basic arithmetic
+   - Flow control
+
+4. Memory Management:
+   - Heap allocation
+   - Reference counting
+   - Basic garbage collection
+
+5. Function Handling:
+   - Call frames
+   - Return handling
+   - Tail call optimization
+
+## Initial Implementation Structure
+
+```awk
+BEGIN {
+    # Initialize VM state
+    stack_ptr = 0
+    heap_ptr = 0
+    env_ptr = 0
+    pc = 0  # Program counter
+}
+
+# Main instruction dispatch
+function execute(instr) {
+    split(instr, parts, " ")
+    op = parts[1]
+    
+    if (op == "PUSH_CONST")
+        push(parts[2])
+    else if (op == "ADD") {
+        b = pop()
+        a = pop()
+        push(add(a, b))
+    }
+    # etc.
+}
+
+# Main execution loop
+{
+    # Load instruction into array
+    instr[$1] = $0
+}
+
+END {
+    # Execute loaded program
+    while (pc < length(instr)) {
+        execute(instr[pc++])
+    }
+}
+```
+
+## Testing Strategy
+
+1. Input File Format:
+```
+0 PUSH_CONST N:5
+1 PUSH_CONST N:3
+2 ADD
+3 HALT
+```
+
+2. Test Cases:
+- Basic arithmetic
+- Stack operations
+- Function calls
+- Error handling
+- Memory management
+
+## AWK-Specific Considerations
+
+1. String Operations:
+- Use split() for parsing
+- substr() for type tags
+- string concatenation for compound values
+
+2. Limitations:
+- No native types besides numbers and strings
+- No recursive function calls in AWK
+- Limited stack size
+- Memory management needs care
+
+3. Advantages:
+- Associative arrays simplify environment handling
+- Built-in string operations help with parsing
+- Line-oriented processing suits instruction loading
+
+## Style Guidelines
+
+1. Use clear function names:
+   - makeNumber(n)
+   - makeSymbol(s)
+   - etc.
+
+2. Consistent error handling:
+   - Set ERRNO
+   - Print to STDERR
+   - Exit codes
+
+3. Document array usage:
+   - Purpose of each array
+   - Format of entries
+   - Lifetime management
+
+Please start with implementing the value type system and basic stack operations, showing how to represent and manipulate Scheme values in AWK's string-based environment.
diff --git a/awk/scheme/scheme/docs/awk-vm-implementation-prompt.md b/awk/scheme/scheme/docs/awk-vm-implementation-prompt.md
new file mode 100644
index 0000000..6596589
--- /dev/null
+++ b/awk/scheme/scheme/docs/awk-vm-implementation-prompt.md
@@ -0,0 +1,226 @@
+# AWK-based Scheme VM Implementation Guide
+
+I need help implementing a stack-based virtual machine in AWK that will support a minimal Scheme implementation. Please focus on AWK-specific approaches and limitations.
+
+## VM Architecture Overview
+
+The VM should be stack-based with these key components:
+1. An instruction array storing the program
+2. A value stack using numeric-indexed arrays
+3. A heap for pairs and closures using associative arrays
+4. An environment chain for variable lookup
+
+## Core Data Types
+
+Each value should be represented as a string with format "TYPE:VALUE":
+
+```awk
+# Examples
+"N:42"      # Number
+"B:1"       # Boolean true
+"B:0"       # Boolean false
+"S:x"       # Symbol 'x'
+"P:1,2"     # Pair (cons cell) with heap indices
+"F:100,1"   # Function (instruction addr, env index)
+"NIL:"      # Empty list
+```
+
+## Instruction Set
+
+### Stack Operations
+```
+PUSH_CONST val   # Push constant onto stack
+                 # Example: "PUSH_CONST N:42"
+
+POP             # Remove top value from stack
+
+DUP             # Duplicate top stack value
+                # Before: [a]
+                # After:  [a a]
+
+SWAP            # Swap top two stack values
+                # Before: [a b]
+                # After:  [b a]
+```
+
+### Memory Operations
+```
+LOAD_LOCAL idx  # Load local variable at index
+                # Example: "LOAD_LOCAL 0"
+
+STORE_LOCAL idx # Store into local variable
+                # Example: "STORE_LOCAL 1"
+
+MAKE_ENV n      # Create new environment frame with n slots
+                # Example: "MAKE_ENV 2"
+
+LOAD_FREE idx   # Load from closure's environment
+                # Example: "LOAD_FREE 0"
+
+STORE_FREE idx  # Store into closure's environment
+                # Example: "STORE_FREE 1"
+```
+
+### Function Operations
+```
+CALL n          # Call function with n arguments
+                # Example: "CALL 2"
+
+TAIL_CALL n     # Tail-call with n arguments
+                # Example: "TAIL_CALL 1"
+
+RETURN          # Return from function
+
+MAKE_FUNCTION addr # Create function object
+                  # Example: "MAKE_FUNCTION 100"
+```
+
+### List Operations
+```
+CONS            # Create pair from two stack values
+                # Before: [a b]
+                # After:  [(a . b)]
+
+CAR             # Get first element of pair
+                # Before: [(a . b)]
+                # After:  [a]
+
+CDR             # Get second element of pair
+                # Before: [(a . b)]
+                # After:  [b]
+```
+
+### Arithmetic Operations
+```
+ADD             # Add top two numbers
+                # Before: [N:3 N:4]
+                # After:  [N:7]
+
+SUB             # Subtract
+MUL             # Multiply
+DIV             # Divide
+```
+
+### Comparison Operations
+```
+EQ              # Generic equality test
+NUM_LT          # Numeric less than
+NUM_GT          # Numeric greater than
+```
+
+### Control Flow
+```
+JUMP offset     # Unconditional jump
+                # Example: "JUMP 100"
+
+JUMP_IF_FALSE offset  # Jump if top of stack is false
+                     # Example: "JUMP_IF_FALSE 200"
+```
+
+## Implementation Requirements
+
+1. Instruction Format:
+```awk
+# Each instruction stored as string in instr[] array
+instr[addr] = "OPCODE [operand1] [operand2]..."
+```
+
+2. Value Handling:
+```awk
+# Type checking functions
+function isNumber(val) { return substr(val, 1, 2) == "N:" }
+function isPair(val) { return substr(val, 1, 2) == "P:" }
+# etc.
+
+# Value constructors
+function makeNumber(n) { return "N:" n }
+function makePair(car_idx, cdr_idx) { return "P:" car_idx "," cdr_idx }
+# etc.
+```
+
+3. Stack Operations:
+```awk
+# Basic stack manipulation
+function push(val) { stack[++stack_ptr] = val }
+function pop() { if (stack_ptr < 1) error("stack underflow"); return stack[stack_ptr--] }
+```
+
+4. Memory Management:
+```awk
+# Heap allocation
+function allocate(val) {
+    heap[++heap_ptr] = val
+    refs[heap_ptr] = 1
+    return heap_ptr
+}
+
+# Reference counting
+function incref(idx) { if (idx > 0) refs[idx]++ }
+function decref(idx) { if (idx > 0 && --refs[idx] == 0) free_cell(idx) }
+```
+
+## Starting Implementation
+
+Please help implement this VM following these steps:
+
+1. Core VM loop:
+```awk
+BEGIN {
+    # Initialize VM state
+    stack_ptr = 0
+    heap_ptr = 0
+    pc = 0
+}
+
+# Load program
+{
+    instr[NR-1] = $0
+}
+
+END {
+    # Main execution loop
+    while (pc < length(instr)) {
+        execute(instr[pc++])
+    }
+}
+```
+
+2. Instruction execution:
+```awk
+function execute(instr) {
+    split(instr, parts, " ")
+    op = parts[1]
+    
+    if (op == "PUSH_CONST")
+        push(parts[2])
+    else if (op == "ADD") {
+        b = pop()
+        a = pop()
+        push(add(a, b))
+    }
+    # etc.
+}
+```
+
+Please start by implementing:
+1. The basic VM loop
+2. Stack operations
+3. Arithmetic operations
+4. Simple control flow
+
+Then we can move on to:
+1. Function calls and returns
+2. Environment handling
+3. Cons cells and list operations
+4. Garbage collection
+
+Focus on AWK's strengths:
+- Associative arrays for memory management
+- String operations for value handling
+- Line-oriented processing for instruction loading
+
+And handle AWK's limitations:
+- No native complex types
+- Limited recursion
+- String-based value representation
+- Memory management constraints
diff --git a/awk/scheme/scheme/docs/scheme-compilation-examples.md b/awk/scheme/scheme/docs/scheme-compilation-examples.md
new file mode 100644
index 0000000..43bae3a
--- /dev/null
+++ b/awk/scheme/scheme/docs/scheme-compilation-examples.md
@@ -0,0 +1,222 @@
+# Scheme to VM Instruction Examples
+
+## Basic Arithmetic
+
+### Simple Addition
+```scheme
+(+ 1 2)
+```
+```awk
+# VM Instructions
+0 PUSH_CONST N:1
+1 PUSH_CONST N:2
+2 ADD
+```
+
+### Nested Arithmetic
+```scheme
+(+ (* 3 4) (- 10 5))
+```
+```awk
+# VM Instructions
+0 PUSH_CONST N:3
+1 PUSH_CONST N:4
+2 MUL           # Stack now has 12
+3 PUSH_CONST N:10
+4 PUSH_CONST N:5
+5 SUB           # Stack now has 5
+6 ADD           # Final result 17
+```
+
+## Variable Binding and Use
+
+### Let Expression
+```scheme
+(let ((x 5))
+  (+ x 1))
+```
+```awk
+# VM Instructions
+0 MAKE_ENV 1        # Create environment with 1 slot
+1 PUSH_CONST N:5    # Push initial value
+2 STORE_LOCAL 0     # Store into x's slot
+3 LOAD_LOCAL 0      # Load x
+4 PUSH_CONST N:1
+5 ADD
+```
+
+### Nested Let
+```scheme
+(let ((x 5))
+  (let ((y (+ x 1)))
+    (* x y)))
+```
+```awk
+# VM Instructions
+0 MAKE_ENV 1        # Environment for x
+1 PUSH_CONST N:5
+2 STORE_LOCAL 0     # Store x
+3 MAKE_ENV 1        # Environment for y
+4 LOAD_LOCAL 0      # Load x
+5 PUSH_CONST N:1
+6 ADD
+7 STORE_LOCAL 0     # Store y
+8 LOAD_LOCAL 1      # Load x (from outer env)
+9 LOAD_LOCAL 0      # Load y
+10 MUL
+```
+
+## Function Definition and Call
+
+### Simple Function
+```scheme
+(define (add1 x)
+  (+ x 1))
+```
+```awk
+# VM Instructions
+0 MAKE_FUNCTION 2   # Create function pointing to instruction 2
+1 STORE_GLOBAL 0    # Store in global env slot for add1
+2 MAKE_ENV 1        # Function body starts here
+3 LOAD_LOCAL 0      # Load parameter x
+4 PUSH_CONST N:1
+5 ADD
+6 RETURN
+```
+
+### Function Call
+```scheme
+(add1 5)
+```
+```awk
+# VM Instructions
+0 PUSH_CONST N:5    # Push argument
+1 LOAD_GLOBAL 0     # Load add1 function
+2 CALL 1            # Call with 1 argument
+```
+
+## List Operations
+
+### List Construction
+```scheme
+(cons 1 (cons 2 '()))
+```
+```awk
+# VM Instructions
+0 PUSH_CONST N:1
+1 PUSH_CONST N:2
+2 PUSH_CONST NIL:
+3 CONS            # Creates (2 . nil)
+4 CONS            # Creates (1 . (2 . nil))
+```
+
+### List Operations
+```scheme
+(car (cons 1 2))
+```
+```awk
+# VM Instructions
+0 PUSH_CONST N:1
+1 PUSH_CONST N:2
+2 CONS
+3 CAR
+```
+
+## Conditionals
+
+### If Expression
+```scheme
+(if (< x 0)
+    (- 0 x)
+    x)
+```
+```awk
+# VM Instructions
+0 LOAD_LOCAL 0      # Load x
+1 PUSH_CONST N:0
+2 NUM_LT           # Compare x < 0
+3 JUMP_IF_FALSE 7  # Skip to else branch if false
+4 PUSH_CONST N:0
+5 LOAD_LOCAL 0     # Load x again
+6 SUB             # Compute 0 - x
+7 JUMP 9          # Skip else branch
+8 LOAD_LOCAL 0    # Else branch: just load x
+9 NOP             # Continue here
+```
+
+## Closures
+
+### Create Closure
+```scheme
+(let ((x 1))
+  (lambda (y) (+ x y)))
+```
+```awk
+# VM Instructions
+0 MAKE_ENV 1        # Environment for x
+1 PUSH_CONST N:1
+2 STORE_LOCAL 0     # Store x
+3 MAKE_FUNCTION 5   # Create function
+4 MAKE_CLOSURE 1    # Capture current env
+5 MAKE_ENV 1        # Function body starts here
+6 LOAD_FREE 0       # Load captured x
+7 LOAD_LOCAL 0      # Load parameter y
+8 ADD
+9 RETURN
+```
+
+## Recursive Function
+
+### Factorial
+```scheme
+(define (factorial n)
+  (if (= n 0)
+      1
+      (* n (factorial (- n 1)))))
+```
+```awk
+# VM Instructions
+0 MAKE_FUNCTION 2    # Create factorial function
+1 STORE_GLOBAL 0     # Store in global env
+2 MAKE_ENV 1         # Function body starts
+3 LOAD_LOCAL 0       # Load n
+4 PUSH_CONST N:0
+5 NUM_EQ            # Compare n = 0
+6 JUMP_IF_FALSE 9   # Skip to else branch
+7 PUSH_CONST N:1    # Return 1 for base case
+8 RETURN
+9 LOAD_LOCAL 0      # Load n
+10 LOAD_LOCAL 0     # Load n again
+11 PUSH_CONST N:1
+12 SUB             # Compute n - 1
+13 LOAD_GLOBAL 0   # Load factorial function
+14 TAIL_CALL 1     # Tail call factorial(n-1)
+15 MUL             # Multiply n * factorial(n-1)
+16 RETURN
+```
+
+## Implementation Notes
+
+1. Environment Chain
+- Each MAKE_ENV creates a new frame
+- LOAD_LOCAL counts down the chain for outer references
+- STORE_LOCAL works similarly
+
+2. Closure Creation
+- MAKE_CLOSURE captures current environment
+- LOAD_FREE accesses captured variables
+
+3. Tail Calls
+- TAIL_CALL reuses current stack frame
+- Essential for recursive functions
+
+4. Memory Management
+- CONS allocates in heap
+- Reference counting needed for heap objects
+- Environment frames need reference counting too
+
+These examples show typical compilation patterns. The actual compiler would need to:
+1. Track variable locations
+2. Manage label generation
+3. Detect tail call positions
+4. Handle lexical scoping properly
diff --git a/awk/scheme/scheme/docs/scheme-compiler-impl.md b/awk/scheme/scheme/docs/scheme-compiler-impl.md
new file mode 100644
index 0000000..db8a204
--- /dev/null
+++ b/awk/scheme/scheme/docs/scheme-compiler-impl.md
@@ -0,0 +1,307 @@
+# Scheme Compiler Implementation in AWK
+
+## Basic Compiler Structure
+
+We'll implement the compiler as a recursive descent processor that converts Scheme expressions into VM instructions. Here's the core structure:
+
+```awk
+# Global state
+BEGIN {
+    next_label = 0      # For generating unique labels
+    next_address = 0    # Current instruction address
+    depth = 0           # Current environment depth
+}
+
+# Main compile function
+function compile(expr,    parts, len) {
+    if (isAtom(expr))
+        return compileAtom(expr)
+    
+    split(expr, parts, " ")
+    len = length(parts)
+    
+    # Strip parentheses
+    parts[1] = substr(parts[1], 2)      # Remove leading (
+    parts[len] = substr(parts[len], 1, length(parts[len])-1)  # Remove trailing )
+    
+    # Dispatch based on first element
+    if (parts[1] == "+")
+        return compileAdd(parts, len)
+    else if (parts[1] == "let")
+        return compileLet(parts, len)
+    else if (parts[1] == "lambda")
+        return compileLambda(parts, len)
+    else if (parts[1] == "if")
+        return compileIf(parts, len)
+    else
+        return compileCall(parts, len)
+}
+
+# Utility functions
+function isAtom(expr) {
+    return substr(expr, 1, 1) != "("
+}
+
+function newLabel() {
+    return "L" next_label++
+}
+
+function emit(instr) {
+    program[next_address++] = instr
+}
+```
+
+## Compilation Patterns
+
+### 1. Basic Arithmetic
+
+```awk
+function compileAdd(parts, len,    i) {
+    # Compile each argument
+    for (i = 2; i <= len; i++)
+        compile(parts[i])
+    
+    # Emit adds between each value
+    for (i = 3; i <= len; i++)
+        emit("ADD")
+    
+    return next_address - 1
+}
+
+# Example usage:
+# Input: (+ 1 2 3)
+# Output:
+# PUSH_CONST N:1
+# PUSH_CONST N:2
+# ADD
+# PUSH_CONST N:3
+# ADD
+```
+
+### 2. Let Expressions
+
+```awk
+function compileLet(parts, len,    bindings, body, i, num_bindings) {
+    # Parse let structure
+    bindings = parts[2]
+    body = parts[3]
+    
+    # Count bindings
+    split(bindings, binding_parts, " ")
+    num_bindings = (length(binding_parts) - 2) / 2  # Account for parentheses
+    
+    # Create new environment frame
+    emit("MAKE_ENV " num_bindings)
+    
+    # Compile each binding value and store
+    for (i = 1; i <= num_bindings; i++) {
+        compile(binding_parts[i * 2])
+        emit("STORE_LOCAL " (i - 1))
+    }
+    
+    # Compile body in new environment
+    depth++
+    compile(body)
+    depth--
+    
+    return next_address - 1
+}
+
+# Example usage:
+# Input: (let ((x 5)) (+ x 1))
+# Output:
+# MAKE_ENV 1
+# PUSH_CONST N:5
+# STORE_LOCAL 0
+# LOAD_LOCAL 0
+# PUSH_CONST N:1
+# ADD
+```
+
+### 3. Lambda Expressions
+
+```awk
+function compileLambda(parts, len,    param_list, body, label_start, label_end) {
+    label_start = newLabel()
+    label_end = newLabel()
+    
+    # Emit jump around function body
+    emit("JUMP " label_end)
+    
+    # Mark function start
+    emit(label_start ":")
+    
+    # Parse parameters
+    param_list = parts[2]
+    body = parts[3]
+    
+    # Compile function body
+    depth++
+    compile(body)
+    emit("RETURN")
+    depth--
+    
+    # Mark function end
+    emit(label_end ":")
+    
+    # Create function object
+    emit("MAKE_FUNCTION " label_start)
+    
+    return next_address - 1
+}
+
+# Example usage:
+# Input: (lambda (x) (+ x 1))
+# Output:
+# JUMP L1
+# L0:
+# LOAD_LOCAL 0
+# PUSH_CONST N:1
+# ADD
+# RETURN
+# L1:
+# MAKE_FUNCTION L0
+```
+
+### 4. If Expressions
+
+```awk
+function compileIf(parts, len,    condition, true_branch, false_branch, label_else, label_end) {
+    label_else = newLabel()
+    label_end = newLabel()
+    
+    # Compile condition
+    compile(parts[2])
+    
+    # Jump to else if false
+    emit("JUMP_IF_FALSE " label_else)
+    
+    # Compile true branch
+    compile(parts[3])
+    emit("JUMP " label_end)
+    
+    # Compile false branch
+    emit(label_else ":")
+    if (len > 4)  # If there is an else branch
+        compile(parts[4])
+    
+    emit(label_end ":")
+    
+    return next_address - 1
+}
+
+# Example usage:
+# Input: (if (< x 0) (- 0 x) x)
+# Output:
+# LOAD_LOCAL 0
+# PUSH_CONST N:0
+# NUM_LT
+# JUMP_IF_FALSE L0
+# PUSH_CONST N:0
+# LOAD_LOCAL 0
+# SUB
+# JUMP L1
+# L0:
+# LOAD_LOCAL 0
+# L1:
+```
+
+### 5. Function Calls
+
+```awk
+function compileCall(parts, len,    i, num_args) {
+    num_args = len - 1
+    
+    # Compile each argument
+    for (i = 2; i <= len; i++)
+        compile(parts[i])
+    
+    # Compile function reference
+    compile(parts[1])
+    
+    # Emit call instruction
+    emit("CALL " num_args)
+    
+    return next_address - 1
+}
+
+# Example usage:
+# Input: (add1 5)
+# Output:
+# PUSH_CONST N:5
+# LOAD_GLOBAL 0
+# CALL 1
+```
+
+## Symbol Table Management
+
+```awk
+# Track variables and their locations
+function enterScope() {
+    scope_depth++
+    next_local = 0
+}
+
+function leaveScope() {
+    scope_depth--
+}
+
+function addLocal(name) {
+    symbols[scope_depth "," name] = next_local++
+}
+
+function findVariable(name,    i) {
+    for (i = scope_depth; i >= 0; i--)
+        if ((i "," name) in symbols)
+            return "LOCAL " i "," symbols[i "," name]
+    return "GLOBAL " name
+}
+```
+
+## Example Usage
+
+Here's how to use the compiler:
+
+```awk
+BEGIN {
+    # Initialize compiler
+    next_label = 0
+    next_address = 0
+    depth = 0
+    
+    # Compile some example code
+    expr = "(let ((x 5)) (+ x 1))"
+    compile(expr)
+    
+    # Print generated code
+    for (i = 0; i < next_address; i++)
+        print i ": " program[i]
+}
+```
+
+## Implementation Notes
+
+1. Variable Resolution
+   - Track scope depth for proper variable lookup
+   - Generate appropriate LOAD/STORE instructions
+   - Handle closure captures
+
+2. Label Generation
+   - Use unique labels for control flow
+   - Track label addresses for jumps
+
+3. Environment Management
+   - Track environment depth
+   - Generate correct frame sizes
+   - Handle nested scopes
+
+4. Error Handling
+   - Check for syntax errors
+   - Validate number of arguments
+   - Report meaningful errors
+
+5. Optimization Opportunities
+   - Tail call detection
+   - Constant folding
+   - Peephole optimization
+   - Dead code elimination
diff --git a/awk/scheme/scheme/docs/scheme-vm-prompt.md b/awk/scheme/scheme/docs/scheme-vm-prompt.md
new file mode 100644
index 0000000..7463494
--- /dev/null
+++ b/awk/scheme/scheme/docs/scheme-vm-prompt.md
@@ -0,0 +1,112 @@
+# Implementation Request for Scheme Virtual Machine
+
+I need help implementing a stack-based virtual machine for a minimal Scheme implementation in JavaScript. The implementation should follow these requirements:
+
+## Core Data Structures
+
+### Value Representation
+Please help me implement a tagged union type for Scheme values with these cases:
+- Numbers (using JavaScript numbers)
+- Booleans (using JavaScript booleans)
+- Symbols (as strings)
+- Pairs (cons cells)
+- Functions (closures)
+- Nil
+
+Each value should include a type tag and the actual value data. The implementation should be memory efficient while still being easy to debug.
+
+### Stack Frame
+Design a stack frame structure that includes:
+- An array for local variables
+- An operand stack (array)
+- Return address (number)
+- Previous frame pointer
+- Captured environment reference (for closures)
+
+### Instruction Format
+Each instruction should be represented as an object with:
+- opcode (string or number)
+- operands (if any)
+- source position (for debugging)
+
+## Core Components Needed
+
+1. Value Constructor/Accessors
+- Functions to create each type of value
+- Type predicates (isNumber, isPair, etc.)
+- Safe accessors that check types
+
+2. Memory Management
+- A simple mark-and-sweep garbage collector
+- Root set scanning of VM stack and global environment
+- Object allocation interface
+
+3. Environment Management
+- Environment chain implementation
+- Closure creation and variable capture
+- Variable lookup and storage
+
+4. Instruction Interpreter
+- Main instruction dispatch loop
+- Stack manipulation helpers
+- Error handling with meaningful messages
+- Debugging support (stack traces)
+
+## Initial Implementation Steps
+
+Please help me implement these components in this order:
+
+1. Value type system and basic operations
+2. Stack frame and basic stack operations
+3. Main instruction interpreter loop
+4. Simple arithmetic and comparison operations
+5. Function calls and returns
+6. Closure creation and environment handling
+7. Cons cells and list operations
+8. Basic garbage collection
+
+## Starting Point
+
+Please start by showing me how to implement:
+
+1. The tagged value type system
+2. Basic stack operations (push, pop)
+3. A simple instruction interpreter that can handle:
+   - PUSH_CONST
+   - POP
+   - ADD
+   - RETURN
+
+The code should be in a functional style, avoiding mutation where practical, and should use modern JavaScript features. Please include basic error checking and type safety.
+
+## Testing Approach
+
+For each component, I'd like to see:
+1. Basic unit tests
+2. Example instruction sequences
+3. Error cases to handle
+4. Edge cases to consider
+
+The implementation should prioritize correctness and clarity over performance initially.
+
+## Additional Considerations
+
+Please also consider:
+1. How to handle tail calls efficiently
+2. Debug information tracking
+3. Error recovery strategies
+4. Performance bottlenecks to watch for
+5. Future extensibility
+
+## Style Preferences
+
+The implementation should:
+- Use functional programming patterns where appropriate
+- Minimize state mutation
+- Use clear naming conventions
+- Include detailed comments explaining non-obvious code
+- Use TypeScript-style JSDoc comments for better tooling support
+- Target modern browsers without external dependencies
+- Use ES modules for code organization
+
+Please start with the value type system implementation, showing how to create and manipulate Scheme values in a type-safe way.
diff --git a/awk/scheme/scheme/docs/scheme-vm-spec.md b/awk/scheme/scheme/docs/scheme-vm-spec.md
new file mode 100644
index 0000000..424602e
--- /dev/null
+++ b/awk/scheme/scheme/docs/scheme-vm-spec.md
@@ -0,0 +1,130 @@
+# Scheme Virtual Machine Specification
+
+## Stack and Memory Model
+The VM uses a stack-based architecture with a separate heap for storing longer-lived objects. Each stack frame contains:
+- Local variable space
+- Operand stack
+- Return address
+
+## Data Types
+- Numbers (implemented as JavaScript numbers)
+- Booleans
+- Symbols (interned strings)
+- Pairs (cons cells)
+- Functions (closures)
+- Nil
+
+## Instructions
+
+### Stack Operations
+- PUSH_CONST value    ; Push constant onto stack
+- POP                 ; Remove top value from stack
+- DUP                 ; Duplicate top stack value
+- SWAP                ; Swap top two stack values
+
+### Environment Operations
+- LOAD_LOCAL idx      ; Load local variable at index
+- STORE_LOCAL idx     ; Store into local variable
+- MAKE_CLOSURE n      ; Create closure with n free variables
+- LOAD_FREE idx       ; Load from closure's environment
+- STORE_FREE idx      ; Store into closure's environment
+
+### Function Operations
+- CALL n              ; Call function with n arguments
+- TAIL_CALL n         ; Tail-call with n arguments
+- RETURN              ; Return from function
+- MAKE_FUNCTION addr  ; Create function object
+
+### Pair Operations
+- CONS                ; Create pair from two stack values
+- CAR                 ; Get first element of pair
+- CDR                ; Get second element of pair
+- SET_CAR            ; Set first element of pair
+- SET_CDR            ; Set second element of pair
+
+### Arithmetic Operations
+- ADD                ; Add top two numbers
+- SUB                ; Subtract
+- MUL                ; Multiply
+- DIV                ; Divide
+- REMAINDER          ; Modulo operation
+
+### Comparison Operations
+- EQ                 ; Generic equality test
+- NUM_EQ             ; Numeric equality
+- NUM_LT             ; Less than
+- NUM_GT             ; Greater than
+
+### Control Flow
+- JUMP offset        ; Unconditional jump
+- JUMP_IF_FALSE offset ; Conditional jump
+- JUMP_IF_TRUE offset  ; Conditional jump
+
+### Type Operations
+- TYPE_OF            ; Get type of value
+- IS_PAIR            ; Test if value is pair
+- IS_NUMBER          ; Test if value is number
+- IS_SYMBOL          ; Test if value is symbol
+
+## Example Instruction Sequences
+
+### Function Definition
+```scheme
+(define (add1 x) (+ x 1))
+```
+Compiles to:
+```
+MAKE_FUNCTION L1
+STORE_LOCAL 0
+JUMP L2
+L1:
+  LOAD_LOCAL 0     ; Load x
+  PUSH_CONST 1
+  ADD
+  RETURN
+L2:
+```
+
+### List Creation
+```scheme
+(cons 1 (cons 2 '()))
+```
+Compiles to:
+```
+PUSH_CONST 1
+PUSH_CONST 2
+PUSH_CONST nil
+CONS
+CONS
+```
+
+### Closure Creation
+```scheme
+(let ((x 1))
+  (lambda (y) (+ x y)))
+```
+Compiles to:
+```
+PUSH_CONST 1      ; Push initial value of x
+MAKE_FUNCTION L1  ; Create function body
+MAKE_CLOSURE 1    ; Create closure capturing x
+JUMP L2
+L1:
+  LOAD_FREE 0     ; Load captured x
+  LOAD_LOCAL 0    ; Load parameter y
+  ADD
+  RETURN
+L2:
+```
+
+## Implementation Notes
+
+1. The VM should implement proper tail-call optimization using the TAIL_CALL instruction.
+
+2. Garbage collection can be implemented using a simple mark-and-sweep collector, scanning the stack and heap for reachable objects.
+
+3. For efficiency, common constants (small integers, nil, etc.) can be preallocated and shared.
+
+4. The environment model uses static scope, with closures capturing their creation environment.
+
+5. Function calls maintain their own stack frame with local variables and operand stack.
diff --git a/awk/scheme/scheme/docs/test-program.md b/awk/scheme/scheme/docs/test-program.md
new file mode 100644
index 0000000..ee20e32
--- /dev/null
+++ b/awk/scheme/scheme/docs/test-program.md
@@ -0,0 +1,48 @@
+# Test Program
+
+Save this as `test.scm.asm`:
+```
+PUSH_CONST N:5
+PUSH_CONST N:3
+ADD
+PUSH_CONST N:2
+SUB
+HALT
+```
+
+Run with:
+```bash
+awk -f vm.awk test.scm.asm
+```
+
+Expected output:
+```
+Result: N:6
+```
+
+# Additional Test Cases
+
+## List Operations
+```
+PUSH_CONST N:1
+PUSH_CONST N:2
+CONS
+PUSH_CONST N:3
+CONS
+CAR
+HALT
+```
+
+## Error Cases
+```
+# Stack underflow
+POP
+POP
+HALT
+
+# Type error
+PUSH_CONST S:hello
+PUSH_CONST N:1
+ADD
+HALT
+```
diff --git a/awk/scheme/scheme/examples/test.scm b/awk/scheme/scheme/examples/test.scm
new file mode 100644
index 0000000..d1e3847
--- /dev/null
+++ b/awk/scheme/scheme/examples/test.scm
@@ -0,0 +1,3 @@
+(cons (+ 1 2)
+      (cons (* 3 4)
+            nil))
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/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/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