#!/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 "'" } } } }