blob: 6c18bfc1ca7fd16a4d17809b0112eb796c7d5dd1 (
plain) (
tree)
|
|
#!/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
}
}
|