about summary refs log tree commit diff stats
path: root/awk
diff options
context:
space:
mode:
Diffstat (limited to 'awk')
-rwxr-xr-xawk/forth/f.awk252
-rw-r--r--awk/forth/test.forth58
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