diff options
author | elioat <elioat@tilde.institute> | 2025-01-11 21:53:17 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-01-11 21:53:17 -0500 |
commit | 4825666a8086801df1577e0e54b5f85f7b6cf175 (patch) | |
tree | ba019b86492319292196b97269c52c731c35e8c1 | |
parent | a9aa0889034ff0cf40b47c4110b6948d4bec2470 (diff) | |
download | tour-4825666a8086801df1577e0e54b5f85f7b6cf175.tar.gz |
*
-rwxr-xr-x | awk/forth/f.awk | 510 | ||||
-rwxr-xr-x | awk/forth/old/f.awk | 344 | ||||
-rw-r--r-- | awk/forth/old/test.forth (renamed from awk/forth/test.forth) | 0 |
3 files changed, 572 insertions, 282 deletions
diff --git a/awk/forth/f.awk b/awk/forth/f.awk index eed9774..cf50dcf 100755 --- a/awk/forth/f.awk +++ b/awk/forth/f.awk @@ -1,344 +1,290 @@ #!/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 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[">"] = ">" - words["<"] = "<" + # Built-in words are stored with their function names + dict["+"] = "math_add" + dict["-"] = "math_sub" + dict["*"] = "math_mul" + dict["/"] = "math_div" + dict["."] = "stack_print" + dict[".s"] = "stack_show" + dict["dup"] = "stack_dup" + dict["drop"] = "stack_drop" + dict["swap"] = "stack_swap" + dict["over"] = "stack_over" + dict["rot"] = "stack_rot" + dict["="] = "compare_eq" + dict["<"] = "compare_lt" + dict[">"] = "compare_gt" + dict["bye"] = "exit_program" + dict["words"] = "list_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 + # State flags + compiling = 0 + current_def = "" + def_name = "" + + # If no input file specified, enter REPL mode + if (ARGC == 1) { + repl() + } } -function pop() { - if (top < 0) { - print "Error: Stack underflow" - return 0 +# Handle file input +{ + if (FILENAME ~ /\.forth$/) { + interpret($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 +function repl() { + print "Welcome to the f.awk, a naive forth interpreter. Use 'bye' to exit." + while (1) { + printf "f> " + if (getline input < "/dev/tty" <= 0) break + interpret(input) } - 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 +function interpret(line) { + n = split(line, words, /[ \t]+/) + + for (i = 1; i <= n; i++) { + word = words[i] + if (word == "") continue + + if (word == ":") { + compiling = 1 + i++ + def_name = words[i] + current_def = "" + continue } - push(first / second) + + if (compiling) { + if (word == ";") { + dict[def_name] = "word " current_def + compiling = 0 + continue + } + current_def = current_def " " word + continue + } + + execute_word(word) } - 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 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 { + # Built-in word + if (dict[word] == "math_add") math_add() + else if (dict[word] == "math_sub") math_sub() + else if (dict[word] == "math_mul") math_mul() + else if (dict[word] == "math_div") math_div() + else if (dict[word] == "stack_print") stack_print() + else if (dict[word] == "stack_show") stack_show() + else if (dict[word] == "stack_dup") stack_dup() + else if (dict[word] == "stack_drop") stack_drop() + else if (dict[word] == "stack_swap") stack_swap() + else if (dict[word] == "stack_over") stack_over() + else if (dict[word] == "stack_rot") stack_rot() + else if (dict[word] == "compare_eq") compare_eq() + else if (dict[word] == "compare_lt") compare_lt() + else if (dict[word] == "compare_gt") compare_gt() + else if (word == "bye") exit_program() + else if (word == "words") list_words() + } + } else { + print "Error: Unknown word '" word "'" + } } -function over() { - if (!check_stack(2)) return - push(stack[top - 1]) +# Stack operations +function push(val) { + stack[stack_ptr++] = val } -function swap() { - if (!check_stack(2)) return - temp = pop() - second = pop() - push(temp) - push(second) +function pop() { + if (stack_ptr <= 0) { + print "Error: Stack underflow" + return 0 + } + return stack[--stack_ptr] } -function rot() { - if (!check_stack(3)) return - third = pop() - second = pop() - first = pop() - push(second) - push(third) - push(first) +# Math operations +function math_add() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } + b = pop() + a = pop() + push(a + b) } -function drop() { - if (!check_stack(1)) return - top-- +function math_sub() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } + b = pop() + a = pop() + push(a - b) } -function nip() { - if (!check_stack(2)) return - temp = stack[top] - drop() - drop() - push(temp) +function math_mul() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } + b = pop() + a = pop() + push(a * b) } -function tuck() { - if (!check_stack(2)) return - temp = pop() - second = pop() - push(temp) - push(second) - push(temp) +function math_div() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } + b = pop() + if (b == 0) { + print "Error: Division by zero" + return + } + a = pop() + push(int(a / b)) } -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 manipulation +function stack_print() { + if (stack_ptr < 1) { + print "Error: Stack underflow" + return } - stack[top] = temp + print pop() } -function pick() { - if (!check_stack(1)) return - n = int(pop()) - if (!check_stack(n)) return - if (n < 0) return - push(stack[top - n]) +function stack_show() { + print "<", stack_ptr, "> " + for (i = 0; i < stack_ptr; i++) { + printf "%s ", stack[i] + } + print "" } -function negate() { - if (!check_stack(1)) return - push(-pop()) +function stack_dup() { + if (stack_ptr < 1) { + print "Error: Stack underflow" + return + } + val = stack[stack_ptr - 1] + push(val) } -function abs() { - if (!check_stack(1)) return - n = pop() - push(n < 0 ? -n : n) +function stack_drop() { + if (stack_ptr < 1) { + print "Error: Stack underflow" + return + } + pop() } -function max() { - if (!check_stack(2)) return +function stack_swap() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } b = pop() a = pop() - push(a > b ? a : b) + push(b) + push(a) } -function min() { - if (!check_stack(2)) return +function stack_over() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } b = pop() a = pop() - push(a < b ? a : b) + push(a) + push(b) + push(a) } -function print_top() { - if (!check_stack(1)) return - print stack[top] - drop() +function stack_rot() { + if (stack_ptr < 3) { + print "Error: Stack underflow" + return + } + c = pop() + b = pop() + a = pop() + push(b) + push(c) + push(a) } -function bye() { - exit +# Comparison operations +function compare_eq() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return + } + b = pop() + a = pop() + push(a == b ? -1 : 0) } -function see(word) { - if (!(word in words)) { - print "Error: Word '" word "' not found" +function compare_lt() { + if (stack_ptr < 2) { + print "Error: Stack underflow" return } - if (word in desc) { - print desc[word] - } - if (word in raw_definitions) { - print ": " word " " raw_definitions[word] " ;" - } + b = pop() + a = pop() + push(a < b ? -1 : 0) } -# 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 +function compare_gt() { + if (stack_ptr < 2) { + print "Error: Stack underflow" + return } - return 0 + b = pop() + a = pop() + push(a > b ? -1 : 0) } -# Process each line of input -{ - if (NF > 0) { - # Remove comments and normalize whitespace - gsub(/\(.*\)/, "") - gsub(/^[[:space:]]+/, "") - gsub(/[[:space:]]+$/, "") - gsub(/[[:space:]]+/, " ") +# New function to handle exiting the program +function exit_program() { + print "Exiting program." + exit 0 +} - # 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 "'" - } - } +# New function to list all available words +function list_words() { + print "Available words:" + for (w in dict) { + print w } } \ 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/test.forth b/awk/forth/old/test.forth index a1f4f50..a1f4f50 100644 --- a/awk/forth/test.forth +++ b/awk/forth/old/test.forth |