diff options
Diffstat (limited to 'awk')
-rwxr-xr-x | awk/forth/f.awk | 252 | ||||
-rw-r--r-- | awk/forth/test.forth | 58 |
2 files changed, 297 insertions, 13 deletions
diff --git a/awk/forth/f.awk b/awk/forth/f.awk index 52df3a2..4d59dfc 100755 --- a/awk/forth/f.awk +++ b/awk/forth/f.awk @@ -31,6 +31,10 @@ BEGIN { 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" @@ -52,6 +56,10 @@ BEGIN { 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" @@ -71,6 +79,18 @@ BEGIN { 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] @@ -82,11 +102,80 @@ BEGIN { 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" } # Function to define a new word function define_word(name, definition) { - words[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 = "" + skip_level = 0 + 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 if (word == ";") { + processed = processed " ;" + } else { + processed = processed " " word + } + } + + return processed } # Stack to hold values @@ -427,36 +516,85 @@ function print_test_description() { 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" + return + } + cond_stack[++cond_top] = pop() # Save condition +} + +# Function to handle then statement +function handle_then() { + if (cond_top < 0) { + print "Error: Unmatched then" + return + } + cond_top-- # Pop condition +} + +# Function to handle else statement +function handle_else() { + if (cond_top < 0) { + print "Error: Unmatched else" + return + } + cond_stack[cond_top] = !cond_stack[cond_top] # Invert condition +} + # Move the main command processing into a function function process_line() { # Process input only if it's not empty if (NF > 0) { - # Remove comments + # 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 # 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++) { - if ($i == ";") { - define_word(word_name, definition) - print "Defined new word: " word_name - break - } else { - definition = definition " " $i - } + definition = definition " " $i + } + # If we don't find a semicolon, keep reading lines + while (definition !~ /;/) { + if ((getline) <= 0) break + gsub(/\(.*\)/, "") # Remove comments + gsub(/^[[:space:]]+/, "") + gsub(/[[:space:]]+$/, "") + definition = definition " " $0 } + # Remove the semicolon + sub(/[[:space:]]*;.*$/, "", definition) + + if (definition != "") { + define_word(word_name, definition) + print "Defined new word: " word_name + } + in_definition = 0 return } # Process remaining input for (i = 1; i <= NF; i++) { - if ($i ~ /^-?[0-9]+$/) { # Modified to handle negative numbers - push($i) # Push numbers onto the stack - } else if ($i in variables) { # Check for variables BEFORE words - push($i) # Push variable name onto stack + if ($i ~ /^-?[0-9]+$/) { + push($i) + } else if ($i in variables) { + push($i) } else if ($i in words) { + # Only check for compile-only words when not in a definition + if (!in_definition && compile_only[$i]) { + print "Error: '" $i "' is compile-only" + return + } # If the word is defined, execute its definition if (words[$i] == "+") add() else if (words[$i] == "-") subtract() @@ -511,6 +649,17 @@ function process_line() { print_test_description() return } + else if (words[$i] == "if") { + handle_if() + } + else if (words[$i] == "then") { + handle_then() + } + else if (words[$i] == "else") { + handle_else() + } + else if (words[$i] == "<") less_than() + else if (words[$i] == ">") greater_than() else { # Execute user-defined word split(words[$i], cmd, " ") @@ -543,6 +692,56 @@ function process_line() { print "Error: see requires a word name" } } + else if (command == "<if>") { + handle_if() + if (!cond_stack[cond_top]) { + # Skip until matching then/else + skip_level = 1 + while (skip_level > 0 && j < length(cmd)) { + j++ + if (cmd[j] == "<if>") { + skip_level++ + print "DEBUG: Nested if, level=" skip_level + } + if (cmd[j] == "<then>") { + skip_level-- + print "DEBUG: Found then, level=" skip_level + } + if (cmd[j] == "<else>" && skip_level == 1) { + skip_level = 0 + print "DEBUG: Found matching else" + break + } + } + } + } + else if (command == "<else>") { + handle_else() + if (cond_stack[cond_top]) { + # Skip until matching then + skip_level = 1 + while (skip_level > 0 && j < length(cmd)) { + j++ + if (cmd[j] == "<if>") skip_level++ + if (cmd[j] == "<then>") skip_level-- + } + } + } + else if (command == "<then>") { + handle_then() + } + else if (command == "<string>") { + j++ + str = "" + while (j < length(cmd) && cmd[j] != "</string>") { + str = str (str == "" ? "" : " ") cmd[j] + j++ + } + print_string(str) + j++ # Skip past </string> + } + else if (words[command] == "<") less_than() + else if (words[command] == ">") greater_than() } } } @@ -577,3 +776,30 @@ function process_line() { { process_line() } + +# Add function to handle dot-quote +function print_string(str) { + printf "%s", str +} + +# Add these new functions for comparisons: + +function less_than() { + if (top < 1) { + print "Error: Not enough values on stack" + return + } + second = pop() + first = pop() + push(first < second ? 1 : 0) +} + +function greater_than() { + if (top < 1) { + print "Error: Not enough values on stack" + return + } + second = pop() + first = pop() + push(first > second ? 1 : 0) +} diff --git a/awk/forth/test.forth b/awk/forth/test.forth index c743478..ef8a4c7 100644 --- a/awk/forth/test.forth +++ b/awk/forth/test.forth @@ -67,4 +67,62 @@ variable counter increment-counter counter @ test 6 +testing Conditionals - basic if/then +: test-if-1 ( n -- ) 5 > if ." Greater than 5" then ; +6 test-if-1 ( should print "Greater than 5" ) +4 test-if-1 ( should print nothing ) + +testing Conditionals - if/else/then +: test-if-2 ( n -- ) 5 > if ." Greater than 5" else ." Less than or equal to 5" then ; +6 test-if-2 ( should print "Greater than 5" ) +4 test-if-2 ( should print "Less than or equal to 5" ) + +testing Conditionals - nested if/then +: test-if-3 ( n -- ) + dup 10 > if + dup 20 > if + ." Greater than 20" + then + ." Greater than 10" + then ; +25 test-if-3 ( should print "Greater than 20Greater than 10" ) +15 test-if-3 ( should print "Greater than 10" ) +5 test-if-3 ( should print nothing ) + +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 |