about summary refs log blame commit diff stats
path: root/awk/forth/f.awk
blob: 6c18bfc1ca7fd16a4d17809b0112eb796c7d5dd1 (plain) (tree)
1
2
3
4
5
6
7

                 
       


                                        
    
















                                                         
    








                                                 

 



                                
     

 





                                                                               
     

 
                          


                                                             











                                    
         











                                                    
     

 


































                                                               

 


                            

 





                                      

 








                                      

 







                                      

 







                                      

 











                                       

 




                                      
     
               

 





                                     

 






                                      

 





                                      

 




                                      

             

           

 




                                      

             


           

 










                                      

 








                                      

 


                                      

              


                        

 



                                      
     


                        

 




                                            
 




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