#!/usr/bin/awk -f BEGIN { # Initialize stacks and dictionaries stack_ptr = 0 dict_size = 0 # 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" # State flags compiling = 0 current_def = "" def_name = "" # If no input file specified, enter REPL mode if (ARGC == 1) { repl() } } # Handle file input { if (FILENAME ~ /\.forth$/) { interpret($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) } } function interpret(line) { # Remove comments from the line gsub(/\(.*\)/, "", line) # Remove everything from ( to ) 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 } if (compiling) { if (word == ";") { dict[def_name] = "word " current_def compiling = 0 continue } current_def = current_def " " word continue } execute_word(word) } } 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 "'" } } # Stack operations function push(val) { stack[stack_ptr++] = val } function pop() { if (stack_ptr <= 0) { print "Error: Stack underflow" return 0 } return stack[--stack_ptr] } # Math operations function math_add() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a + b) } function math_sub() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a - b) } function math_mul() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a * b) } 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)) } # Stack manipulation function stack_print() { if (stack_ptr < 1) { print "Error: Stack underflow" return } print pop() } function stack_show() { print "<", stack_ptr, "> " for (i = 0; i < stack_ptr; i++) { printf "%s ", stack[i] } print "" } function stack_dup() { if (stack_ptr < 1) { print "Error: Stack underflow" return } val = stack[stack_ptr - 1] push(val) } function stack_drop() { if (stack_ptr < 1) { print "Error: Stack underflow" return } pop() } function stack_swap() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(b) push(a) } function stack_over() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a) push(b) push(a) } function stack_rot() { if (stack_ptr < 3) { print "Error: Stack underflow" return } c = pop() b = pop() a = pop() push(b) push(c) push(a) } # Comparison operations function compare_eq() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a == b ? -1 : 0) } function compare_lt() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a < b ? -1 : 0) } function compare_gt() { if (stack_ptr < 2) { print "Error: Stack underflow" return } b = pop() a = pop() push(a > b ? -1 : 0) } # New function to handle exiting the program function exit_program() { print "Exiting program." exit 0 } # New function to list all available words function list_words() { print "Available words:" for (w in dict) { print w } }