about summary refs log tree commit diff stats
path: root/awk/forth
diff options
context:
space:
mode:
Diffstat (limited to 'awk/forth')
-rwxr-xr-xawk/forth/f.awk774
-rwxr-xr-xawk/forth/old/f.awk344
-rw-r--r--awk/forth/old/test.forth44
-rw-r--r--awk/forth/test.forth191
4 files changed, 697 insertions, 656 deletions
diff --git a/awk/forth/f.awk b/awk/forth/f.awk
index 23bc9f0..16de171 100755
--- a/awk/forth/f.awk
+++ b/awk/forth/f.awk
@@ -1,593 +1,369 @@
 #!/usr/bin/awk -f
 
-# Forth interpreter in AWK
+# 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 {
-    print "Welcome to the AWK Forth Interpreter!"
-    print "Type your commands below. Use 'bye' to quit."
-    # Initialize variables
-    top = -1  # Initialize stack pointer
+    # Initialize stacks and dictionaries
+    stack_ptr = 0
+    dict_size = 0
     
-    # 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[">"] = ">"
-
-    # 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"
-
-    # Add variable-related words to dictionary
-    words["variable"] = "variable"
-    words["!"] = "!"
-    words["@"] = "@"
-    words["?"] = "?"
-
-    # Add descriptions for the new words
-    desc["variable"] = "( -- addr ) Create a variable"
-    desc["!"] = "( n addr -- ) Store n at addr"
-    desc["@"] = "( addr -- n ) Fetch contents of addr"
-    desc["?"] = "( addr -- ) Print contents of addr"
-
-    # Initialize test-related words
-    words["test"] = "test"
-    words["testing"] = "testing"
-    desc["test"] = "( n1 n2 -- ) Compare values and report test result"
-    desc["testing"] = "( -- ) Print test description"
-
-    # Initialize condition stack
-    cond_top = -1
-
-    # Mark these as compile-only words
-    compile_only["if"] = 1
-    compile_only["then"] = 1
-    compile_only["else"] = 1
-
-    # Add dot-quote to dictionary
-    words[".\""] = ".\""
-    desc[".\""] = "( -- ) Print following string up to closing quote"
-
-    # Handle file input
-    if (ARGC > 1) {
-        print "Loading file:", ARGV[1]
-        while ((getline < ARGV[1]) > 0) {
-            if ($0 ~ /^[[:space:]]*$/) continue  # Skip empty lines
-            print "> " $0
-            process_line()
-        }
-        close(ARGV[1])
-        exit
-    }
-
-    # Add to dictionary initialization
-    words["<"] = "<"
-    words[">"] = ">"
+    # 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."
     
-    # Add descriptions
-    desc["<"] = "( n1 n2 -- flag ) Returns true if n1 is less than n2"
-    desc[">"] = "( n1 n2 -- flag ) Returns true if n1 is greater than n2"
-
-    # Add handlers
-    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"
-
-    # Add variable handler
-    handlers["variable"] = "create_variable"
-    handlers["!"] = "store"
-    handlers["@"] = "fetch"
-    handlers["?"] = "print_var"
+    # State flags
+    compiling = 0
+    current_def = ""
+    def_name = ""
+    
+    # If an input file isn't specified, enter REPL mode
+    if (ARGC == 1) {
+        repl()
+    }
 }
 
-# Add these helper functions near the 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
+# Handle file input
+{
+    if (FILENAME ~ /\.forth$/) {
+        interpret($0)
     }
-    return 1
 }
 
-function check_underflow() {
-    return check_stack(1, "Error: Stack underflow")
+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 to define a new word
-function define_word(name, definition) {
-    # Store the raw definition
-    raw_definitions[name] = definition
-    print "DEBUG: Raw definition for " name ": " definition
-    
-    # Process the definition to handle conditionals
-    processed = process_definition(definition)
-    print "DEBUG: Processed definition for " name ": " processed
-    words[name] = processed
-}
+function interpret(line) {
+    gsub(/\(.*\)/, "", line)  # Remove everything from ( to )
+    gsub(/\\.*$/, "", line)   # Remove backslash comments, too
 
-function process_definition(definition) {
-    # Normalize whitespace in definition
-    gsub(/^[[:space:]]+/, "", definition)
-    gsub(/[[:space:]]+$/, "", definition)
-    gsub(/[[:space:]]+/, " ", definition)
-    
-    # Split definition into words
-    split(definition, def_words, " ")
-    processed = ""
-    in_string = 0
-    string_content = ""
+    n = split(line, words, /[ \t]+/)
     
-    for (i = 1; i <= length(def_words); i++) {
-        word = def_words[i]
+    for (i = 1; i <= n; i++) {
+        word = words[i]
+        if (word == "") continue
+        
+        # print "Processing word: " word
         
-        if (word == ".\"") {
-            # Start collecting string
-            in_string = 1
-            string_content = ""
+        if (word == ":") {
+            compiling = 1
+            i++
+            def_name = words[i]
+            current_def = ""
             continue
         }
         
-        if (in_string) {
-            # Check if this word contains the closing quote
-            if (word ~ /"$/) {
-                # End of string found
-                string_content = string_content (string_content == "" ? "" : " ") substr(word, 1, length(word)-1)
-                processed = processed " <string>" string_content "</string>"
-                in_string = 0
-            } else {
-                # Add to string content
-                string_content = string_content (string_content == "" ? "" : " ") word
+        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
         }
         
-        # Handle non-string words
-        if (word == "if") {
-            processed = processed " <if>"
-        } else if (word == "else") {
-            processed = processed " <else>"
-        } else if (word == "then") {
-            processed = processed " <then>"
+        # 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 {
-            processed = processed " " word
+            # 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 "'"
     }
-    
-    return processed
 }
 
-# Stack to hold values
-function push(value) {
-    stack[++top] = value
+function push(val) {
+    stack[stack_ptr++] = val
 }
 
 function pop() {
-    if (top < 0) {
+    if (stack_ptr <= 0) {
         print "Error: Stack underflow"
         return 0
     }
-    return stack[top--]
+    return stack[--stack_ptr]
 }
 
-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)
-}
-
-# Then simplify the operation 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 to duplicate the top value
-function dup() {
-    if (!check_stack(1)) return
-    push(stack[top])
-}
-
-# Function to copy the second value to the top
-function over() {
-    if (!check_stack(2)) return
-    push(stack[top - 1])
-}
-
-# Function to swap the top two values
-function swap() {
-    if (!check_stack(2)) return
-    temp = pop()
-    second = pop()
-    push(temp)
-    push(second)
-}
-
-function print_top() {
-    if (!check_stack(1)) return
-    print stack[top]
-}
-
-# Function to list all available words
-function list_words() {
-    print "Available words:"
-    for (word in words) {
-        print word
+function math_add() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
     }
+    b = pop()
+    a = pop()
+    push(a + b)
 }
 
-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]
+function math_sub() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
     }
-    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)
+    push(a - b)
 }
 
-function min() {
-    if (!check_stack(2)) return
+function math_mul() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
+    }
     b = pop()
     a = pop()
-    push(a < b ? a : b)
+    push(a * b)
 }
 
-function see(word) {
-    if (word in desc) {
-        print desc[word]
-    } else if (word in words) {
-        print ": " word " " words[word] " ;"
-    } else {
-        print "Word '" word "' not found"
+function math_div() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
     }
-}
-
-# Add these new functions for variable handling:
-
-# Function to create a new variable
-function create_variable(name) {
-    if (name == "") {
-        print "Error: Variable name required"
+    b = pop()
+    if (b == 0) {
+        print "Error: Division by zero"
         return
     }
-    variables[name] = 0  # Initialize variable to 0
-    # No need to push the variable name onto the stack
+    a = pop()
+    push(int(a / b))
 }
 
-# Function to store a value in a variable
-function check_variable(addr, error_msg) {
-    if (!(addr in variables)) {
-        print error_msg ? error_msg : "Error: Invalid variable '" addr "'"
-        return 0
+function stack_print() {
+    if (stack_ptr < 1) {
+        print "Error: Stack underflow"
+        return
     }
-    return 1
+    print pop()
 }
 
-function store() {
-    if (!check_stack(2)) return
-    addr = pop()
-    if (!check_variable(addr)) return
-    variables[addr] = pop()
-}
-
-# Function to fetch a value from a variable
-function fetch() {
-    if (!check_stack(1)) return
-    addr = pop()
-    if (!check_variable(addr)) return
-    push(variables[addr])
+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 to print a variable's value
-function print_var() {
-    if (top < 0) {
+function stack_dup() {
+    if (stack_ptr < 1) {
         print "Error: Stack underflow"
         return
     }
-    addr = pop()
-    if (!(addr in variables)) {
-        print "Error: Invalid variable '" addr "'"
+    val = stack[stack_ptr - 1]
+    push(val)
+}
+
+function stack_drop() {
+    if (stack_ptr < 1) {
+        print "Error: Stack underflow"
         return
     }
-    print variables[addr]
+    pop()
 }
 
-# Add these test-related functions:
-function run_test(expected) {
-    if (top < 0) {
-        print "❌ FAIL: Stack is empty"
+function stack_swap() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
         return
     }
-    actual = pop()
-    if (actual == expected) {
-        print "✓ PASS"
-    } else {
-        print "❌ FAIL: Expected", expected, "but got", actual
-    }
+    b = pop()
+    a = pop()
+    push(b)
+    push(a)
 }
 
-function print_test_description() {
-    if (NF < 2) {
-        print "Error: testing requires a description"
+function stack_over() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
         return
     }
-    # Collect all words after 'testing' as the description
-    test_desc = ""
-    for (i = 2; i <= NF; i++) {
-        test_desc = test_desc " " $i
-    }
-    print "\nTesting:" test_desc
+    b = pop()
+    a = pop()
+    push(a)
+    push(b)
+    push(a)
 }
 
-# Add these new functions for conditional handling:
-
-# Function to handle if statement
-function handle_if() {
-    if (top < 0) {
+function stack_rot() {
+    if (stack_ptr < 3) {
         print "Error: Stack underflow"
         return
     }
-    # Save condition without consuming it
-    cond_stack[++cond_top] = (stack[top] != 0)
+    c = pop()
+    b = pop()
+    a = pop()
+    push(b)
+    push(c)
+    push(a)
 }
 
-# Function to handle then statement
-function handle_then() {
-    if (cond_top < 0) {
-        print "Error: Unmatched then"
+function compare_eq() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
         return
     }
-    cond_top--  # Pop condition
+    b = pop()
+    a = pop()
+    push(a == b ? -1 : 0)
 }
 
-# Function to handle else statement
-function handle_else() {
-    if (cond_top < 0) {
-        print "Error: Unmatched else"
+function compare_lt() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
         return
     }
-    cond_stack[cond_top] = !cond_stack[cond_top]
+    b = pop()
+    a = pop()
+    push(a < b ? -1 : 0)
 }
 
-# Add this function
-function execute_word(word) {
-    if (word in handlers) {
-        if (handlers[word] == "add") add()
-        else if (handlers[word] == "subtract") subtract()
-        else if (handlers[word] == "multiply") multiply()
-        else if (handlers[word] == "divide") divide()
-        else if (handlers[word] == "dup") dup()
-        else if (handlers[word] == "over") over()
-        else if (handlers[word] == "swap") swap()
-        else if (handlers[word] == "print_top") print_top()
-        else if (handlers[word] == "create_variable") {
-            # Special handling for variable creation
-            if (i + 1 <= NF) {
-                create_variable($(++i))
-            } else {
-                print "Error: variable requires a name"
-            }
-        }
-        else if (handlers[word] == "store") store()
-        else if (handlers[word] == "fetch") fetch()
-        else if (handlers[word] == "print_var") print_var()
-        else {
-            print "Error: Handler '" handlers[word] "' not implemented"
-            return 0
-        }
-        return 1
+function compare_gt() {
+    if (stack_ptr < 2) {
+        print "Error: Stack underflow"
+        return
     }
-    return 0
+    b = pop()
+    a = pop()
+    push(a > b ? -1 : 0)
 }
 
-# Move the main command processing into a function
-function process_line() {
-    # Process input only if it's not empty
-    if (NF > 0) {
-        # Remove comments and normalize whitespace
-        gsub(/\(.*\)/, "")  # Remove everything from ( to )
-        gsub(/^[[:space:]]+/, "")  # Remove leading whitespace
-        gsub(/[[:space:]]+$/, "")  # Remove trailing whitespace
-        gsub(/[[:space:]]+/, " ")  # Normalize internal whitespace
-
-        # Special handling for testing command
-        if ($1 == "testing") {
-            # Collect the description string
-            if ($2 ~ /^".*"$/) {  # Check if the second token is a quoted string
-                test_desc = substr($2, 2, length($2) - 2)  # Remove quotes
-                print "\nTesting: " test_desc
-            } else {
-                print "Error: testing requires a description in quotes"
-            }
-            return
-        }
+function exit_program() {
+    print "Exiting program."
+    exit 0
+}
 
-        # Check for word definitions
-        if ($1 == ":") {
-            word_name = $2
-            definition = ""
-            in_definition = 1
-            # Remove : and word name from the input
-            for (i = 3; i <= NF; i++) {
-                definition = definition " " $i
-            }
-            # If we don't find a semicolon, keep reading lines
-            while (definition !~ /;$/) {  # Changed to match semicolon at end
-                if ((getline) <= 0) break
-                gsub(/\(.*\)/, "")  # Remove comments
-                gsub(/^[[:space:]]+/, "")
-                gsub(/[[:space:]]+$/, "")
-                definition = definition " " $0
-            }
-            # Remove the semicolon
-            sub(/[[:space:]]*;[[:space:]]*$/, "", definition)
-            
-            if (definition != "") {
-                define_word(word_name, definition)
-                print "Defined new word: " word_name
-            }
-            in_definition = 0
-            return
+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]
         }
-
-        # Process remaining input
-        for (i = 1; i <= NF; i++) {
-            if ($i ~ /^-?[0-9]+$/) {
-                push($i)
-            } else if ($i in variables) {  # Check if it's a variable
-                push(variables[$i])  # Push the value of the variable onto the stack
-            } else if ($i in words) {  # Check if it's a defined word
-                if (!in_definition && compile_only[$i]) {
-                    print "Error: '" $i "' is compile-only"
-                    return
-                }
-                if (!execute_word($i)) {
-                    print "Error: Unknown command '" $i "'"
-                }
-            } else if ($i != "") {  # Ignore empty tokens
-                print "Error: Unknown command '" $i "'"
+    }
+    
+    # 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
             }
         }
     }
-}
-
-# Main loop to read commands (for interactive mode)
-{
-    process_line()
-}
-
-# Add function to handle dot-quote
-function print_string(str) {
-    printf "%s", str
-}
+    
+    # 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
index d746e66..daa6943 100644
--- a/awk/forth/test.forth
+++ b/awk/forth/test.forth
@@ -1,157 +1,34 @@
-( Basic Forth test suite )
-
-testing "Basic stack operations"
-5 dup . . test 5 test 5
-
-testing "Addition"
-3 4 + test 7
-
-testing "Subtraction"
-10 3 - test 7
-
-testing "Multiplication"
-6 7 * test 42
-
-testing "Division"
-20 4 / test 5
-
-testing "Stack manipulation - rot"
-1 2 3 rot test 1
-
-testing "Stack manipulation - drop"
-1 2 3 drop test 2
-
-testing "Stack manipulation - nip"
-1 2 3 nip test 3
-
-testing "Stack manipulation - tuck"
-1 2 tuck test 2
-
-testing "Stack manipulation - over"
-1 2 over test 1
-
-testing "Variables"
-variable x
-5 x !
-x @ test 5
-10 x !
-x ? ( should print 10 )
-
-testing "Negate"
-5 negate test -5
-
-testing "Absolute value"
--7 abs test 7
-
-testing "Maximum"
-3 8 max test 8
-
-testing "Minimum"
-3 8 min test 3
-
-testing "Modulo"
-17 5 mod test 2
-
-testing "Equality"
-5 5 = test 1
-5 6 = test 0
-
-testing "Word definition"
-: square dup * ;
-5 square test 25
-
-testing "Complex word definition"
-variable counter
-: increment-counter counter @ 1 + counter ! ;
-5 counter !
-increment-counter
-counter @ test 6
-
-testing "Basic conditional - if/then"
-: test-if-1 ( n -- n ) dup 5 > if ." Greater than 5" then ;
-6 test-if-1 test 6 ( should print "Greater than 5" and leave 6 )
-4 test-if-1 test 4 ( should print nothing and leave 4 )
-
-testing "Basic conditional - if/else/then"
-: test-if-2 ( n -- n ) dup 5 > if ." Greater" else ." Less=" then ;
-6 test-if-2 test 6 ( should print "Greater" and leave 6 )
-4 test-if-2 test 4 ( should print "Less=" and leave 4 )
-5 test-if-2 test 5 ( should print "Less=" and leave 5 )
-
-testing "Nested conditionals"
-: test-if-3 ( n -- n ) 
-    dup 10 > if 
-        dup 20 > if 
-            ." >20 "
-        then
-        ." >10 "
-    then ;
-25 test-if-3 test 25 ( should print ">20 >10 " and leave 25 )
-15 test-if-3 test 15 ( should print ">10 " and leave 15 )
-5 test-if-3 test 5   ( should print nothing and leave 5 )
-
-testing "Conditional with stack operations"
-: test-if-4 ( n -- n n ) 
-    dup 5 > if 
-        dup 
-    then ;
-6 test-if-4 swap test 6 test 6 ( should leave 6 6 )
-4 test-if-4 test 4 ( should leave just 4 )
-
-testing "Complex nested conditionals"
-: test-if-5 ( n -- n )
-    dup 0 < if
-        ." negative "
-    else
-        dup 100 > if
-            ." big "
-        else 
-            dup 50 > if
-                ." medium "
-            else
-                ." small "
-            then
-        then
-    then ;
--5 test-if-5 test -5 ( should print "negative " )
-150 test-if-5 test 150 ( should print "big " )
-75 test-if-5 test 75 ( should print "medium " )
-25 test-if-5 test 25 ( should print "small " )
-
-testing "Conditionals in word definitions"
-: abs-test ( n -- |n| ) dup 0 < if negate then ;
--5 abs-test test 5
-5 abs-test test 5
-
-testing "Complex conditional word"
-: max-test ( n1 n2 -- max ) 
-    2dup > if 
-        drop 
-    else 
-        nip 
-    then ;
-5 3 max-test test 5
-3 5 max-test test 5
-
-( Try to use if outside of a definition - should error )
-testing "Compile-only words"
-5 4 > if 42 then ( should print error about compile-only word )
-
-testing "Comparison operators"
-5 3 > test 1  ( 5 > 3 is true )
-3 5 > test 0  ( 3 > 5 is false )
-3 5 < test 1  ( 3 < 5 is true )
-5 3 < test 0  ( 5 < 3 is false )
-5 5 < test 0  ( 5 < 5 is false )
-5 5 > test 0  ( 5 > 5 is false )
-
-testing "Comparison in conditionals"
-: test-compare ( n -- )
-dup 5 > if ." Greater than 5" else
-dup 5 < if ." Less than 5" else
-." Equal to 5" then then ;
-6 test-compare ( should print "Greater than 5" )
-4 test-compare ( should print "Less than 5" )
-5 test-compare ( should print "Equal to 5" )
-
-bye 
\ No newline at end of file
+\ 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