blob: eed9774c7bf85ba917707941b91d84a4ca28530a (
plain) (
tree)
|
|
#!/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 "'"
}
}
}
}
|