diff options
author | elioat <elioat@tilde.institute> | 2025-01-09 16:57:05 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-01-09 16:57:05 -0500 |
commit | 662c3ceae2a4ffc598a8b99690a0cfdc0b4f47a8 (patch) | |
tree | 22c03fefb86b314341fbea70afaa95d91c7e7bbe /awk/forth/f.awk | |
parent | b9440ce32de013237d61d2cccab229537ba19caa (diff) | |
download | tour-662c3ceae2a4ffc598a8b99690a0cfdc0b4f47a8.tar.gz |
*
Diffstat (limited to 'awk/forth/f.awk')
-rwxr-xr-x | awk/forth/f.awk | 449 |
1 files changed, 100 insertions, 349 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 |