about summary refs log tree commit diff stats
path: root/awk
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-01-09 16:57:05 -0500
committerelioat <elioat@tilde.institute>2025-01-09 16:57:05 -0500
commit662c3ceae2a4ffc598a8b99690a0cfdc0b4f47a8 (patch)
tree22c03fefb86b314341fbea70afaa95d91c7e7bbe /awk
parentb9440ce32de013237d61d2cccab229537ba19caa (diff)
downloadtour-662c3ceae2a4ffc598a8b99690a0cfdc0b4f47a8.tar.gz
*
Diffstat (limited to 'awk')
-rwxr-xr-xawk/forth/f.awk449
-rw-r--r--awk/forth/test.forth201
2 files changed, 144 insertions, 506 deletions
diff --git a/awk/forth/f.awk b/awk/forth/f.awk
index 23bc9f0..eed9774 100755
--- a/awk/forth/f.awk
+++ b/awk/forth/f.awk
@@ -35,6 +35,36 @@ BEGIN {
     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"
@@ -60,24 +90,9 @@ BEGIN {
     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"
+    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
@@ -86,127 +101,9 @@ BEGIN {
     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[">"] = ">"
-    
-    # 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"
-}
-
-# 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
-    }
-    return 1
-}
-
-function check_underflow() {
-    return check_stack(1, "Error: Stack underflow")
-}
-
-# 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 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 = ""
-    
-    for (i = 1; i <= length(def_words); i++) {
-        word = def_words[i]
-        
-        if (word == ".\"") {
-            # Start collecting string
-            in_string = 1
-            string_content = ""
-            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
-            }
-            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>"
-        } else {
-            processed = processed " " word
-        }
-    }
-    
-    return processed
 }
 
-# Stack to hold values
+# Stack operations
 function push(value) {
     stack[++top] = value
 }
@@ -219,6 +116,15 @@ function pop() {
     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()
@@ -241,7 +147,7 @@ function binary_op(operation) {
     else if (operation == ">") push(first > second ? 1 : 0)
 }
 
-# Then simplify the operation functions:
+# Handler functions
 function add() { binary_op("+") }
 function subtract() { binary_op("-") }
 function multiply() { binary_op("*") }
@@ -251,19 +157,16 @@ 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()
@@ -272,19 +175,6 @@ function swap() {
     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 rot() {
     if (!check_stack(3)) return
     third = pop()
@@ -363,147 +253,65 @@ function min() {
     push(a < b ? 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"
-    }
-}
-
-# Add these new functions for variable handling:
-
-# Function to create a new variable
-function create_variable(name) {
-    if (name == "") {
-        print "Error: Variable name required"
-        return
-    }
-    variables[name] = 0  # Initialize variable to 0
-    # No need to push the variable name onto the stack
-}
-
-# 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
-    }
-    return 1
-}
-
-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() {
+function print_top() {
     if (!check_stack(1)) return
-    addr = pop()
-    if (!check_variable(addr)) return
-    push(variables[addr])
-}
-
-# Function to print a variable's value
-function print_var() {
-    if (top < 0) {
-        print "Error: Stack underflow"
-        return
-    }
-    addr = pop()
-    if (!(addr in variables)) {
-        print "Error: Invalid variable '" addr "'"
-        return
-    }
-    print variables[addr]
+    print stack[top]
+    drop()
 }
 
-# Add these test-related functions:
-function run_test(expected) {
-    if (top < 0) {
-        print "❌ FAIL: Stack is empty"
-        return
-    }
-    actual = pop()
-    if (actual == expected) {
-        print "✓ PASS"
-    } else {
-        print "❌ FAIL: Expected", expected, "but got", actual
-    }
+function bye() {
+    exit
 }
 
-function print_test_description() {
-    if (NF < 2) {
-        print "Error: testing requires a description"
-        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
-}
-
-# Add these new functions for conditional handling:
-
-# Function to handle if statement
-function handle_if() {
-    if (top < 0) {
-        print "Error: Stack underflow"
+function see(word) {
+    if (!(word in words)) {
+        print "Error: Word '" word "' not found"
         return
     }
-    # Save condition without consuming it
-    cond_stack[++cond_top] = (stack[top] != 0)
-}
-
-# Function to handle then statement
-function handle_then() {
-    if (cond_top < 0) {
-        print "Error: Unmatched then"
-        return
+    if (word in desc) {
+        print desc[word]
     }
-    cond_top--  # Pop condition
-}
-
-# Function to handle else statement
-function handle_else() {
-    if (cond_top < 0) {
-        print "Error: Unmatched else"
-        return
+    if (word in raw_definitions) {
+        print ": " word " " raw_definitions[word] " ;"
     }
-    cond_stack[cond_top] = !cond_stack[cond_top]
 }
 
-# Add this function
+# Main processing 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"
-            }
+        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 (handlers[word] == "store") store()
-        else if (handlers[word] == "fetch") fetch()
-        else if (handlers[word] == "print_var") print_var()
+        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 '" handlers[word] "' not implemented"
+            print "Error: Handler '" handler "' not implemented"
             return 0
         }
         return 1
@@ -511,83 +319,26 @@ function execute_word(word) {
     return 0
 }
 
-# Move the main command processing into a function
-function process_line() {
-    # Process input only if it's not empty
+# Process each line of input
+{
     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
+        gsub(/\(.*\)/, "")
+        gsub(/^[[:space:]]+/, "")
+        gsub(/[[:space:]]+$/, "")
+        gsub(/[[:space:]]+/, " ")
 
-        # 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
-        }
-
-        # 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
-        }
-
-        # Process remaining input
+        # Process each token
         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
-                }
+            } else if ($i in words) {
                 if (!execute_word($i)) {
-                    print "Error: Unknown command '" $i "'"
+                    print "Error: Failed to execute word '" $i "'"
                 }
-            } else if ($i != "") {  # Ignore empty tokens
-                print "Error: Unknown command '" $i "'"
+            } else {
+                print "Error: Unknown word '" $i "'"
             }
         }
     }
-}
-
-# Main loop to read commands (for interactive mode)
-{
-    process_line()
-}
-
-# Add function to handle dot-quote
-function print_string(str) {
-    printf "%s", str
-}
+}
\ No newline at end of file
diff --git a/awk/forth/test.forth b/awk/forth/test.forth
index d746e66..a1f4f50 100644
--- a/awk/forth/test.forth
+++ b/awk/forth/test.forth
@@ -1,157 +1,44 @@
-( 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
+( 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