rforth/rforth.py

277 lines
6.5 KiB
Python
Executable File

#!/usr/bin/python3
import argparse
stack = []
heap = [0] * 100
next_heap = 0
compiling = False
reading_string = False
words = {}
word_name = ""
def get_next(input_string):
if len(input_string) > 1:
return input_string[1:len(input_string)]
else:
return []
def get_input():
i = input()
return i
def parse_input(input_string, say_ok=True):
while len(input_string) > 0:
string = str(input_string[0])
if not compiling and not reading_string:
if string.isnumeric():
add_to_stack(string)
elif string == "stack":
show_stack()
elif string == "+":
add()
elif string == "-":
subtract()
elif string == ".":
output()
elif string == "bye":
exit()
elif string == "emit":
emit()
elif string == ":":
start_compiling()
elif string in words:
parse_input(words[string].split(" "), False)
elif string == "words":
show_words()
elif string == ">":
greater_than()
elif string == "<":
less_than()
elif string == "=":
equals()
elif string == "if":
input_string = _if(input_string)
elif string == "dup":
dup()
elif string == "swap":
swap()
elif string == "rot":
rot()
elif string == "and":
_and()
elif string == "or":
_or()
elif string == "!":
store()
elif string == "@":
fetch()
elif string == "heap":
dump_heap()
elif string == "alloc":
alloc()
elif string == 's"':
start_reading_string()
elif reading_string:
if string == '"':
stop_reading_string()
else:
add_new_word_to_string(string)
elif compiling and not reading_string:
if string == ";":
stop_compiling()
else:
add_to_new_word(string)
input_string = get_next(input_string)
if say_ok:
print("ok.")
def add_new_word_to_string(string):
for char in string[::-1]:
stack.insert(0, ord(char))
def dump_heap():
print(heap)
def alloc():
global next_heap
heap[next_heap] = 0
stack.insert(0, next_heap)
next_heap += 1
def store():
k = stack.pop(0)
v = stack.pop(0)
heap[k] = v
def fetch():
k = stack.pop(0)
v = heap[k]
stack.insert(0, v)
def rot():
a = stack.pop(0)
b = stack.pop(0)
c = stack.pop(0)
stack.insert(0,b)
stack.insert(0,a)
stack.insert(0,c)
def swap():
a = stack.pop(0)
b = stack.pop(0)
stack.insert(0,a)
stack.insert(0,b)
def _if(input_string):
a = stack.pop(0)
if int(a) == -1:
then_index = scan_for_then(input_string)
else_index = scan_for_else(input_string[0:then_index], then_index)
if else_index == -1:
return input_string[0:then_index]
else:
return input_string[0: else_index] + input_string[then_index : len(input_string)]
else:
then_index = scan_for_then(input_string)
else_index = scan_for_else(input_string[0:then_index], then_index)
if else_index == -1:
return input_string[then_index: len(input_string)]
else:
return input_string[else_index : len(input_string)]
return input_string
def scan_for_else(input_string, then_index):
for index in reversed(range(0, then_index)):
if input_string[index] == "else":
return index
return -1
def scan_for_then(input_string):
for index in reversed(range(0, len(input_string))):
if input_string[index] == "then":
return index
return -1
def dup():
a = stack.pop(0)
stack.insert(0,a)
stack.insert(0,a)
def greater_than():
a = stack.pop(0)
b = stack.pop(0)
if a > b:
stack.insert(0,-1)
else:
stack.insert(0,0)
def less_than():
a = stack.pop(0)
b = stack.pop(0)
if a < b:
stack.insert(0,-1)
else:
stack.insert(0,0)
def equals():
a = stack.pop(0)
b = stack.pop(0)
if a == b:
stack.insert(0,-1)
else:
stack.insert(0,0)
def show_words():
print(words)
def add_to_new_word(value):
global word_name
if word_name == "":
word_name = value
words[word_name] = ""
else:
words[word_name] = words[word_name] + value + " "
def start_reading_string():
global reading_string
reading_string = True
def stop_reading_string():
global reading_string
reading_string = False
def start_compiling():
global compiling
compiling = True
def stop_compiling():
global compiling
global word_name
compiling = False
words[word_name] = words[word_name].strip()
word_name = ""
def emit():
a = stack.pop(0)
print(chr(a),end='')
def exit():
print("l8r sk8r")
quit()
def output():
a = stack.pop(0)
print(a)
def subtract():
a = stack.pop(0)
b = stack.pop(0)
stack.insert(0, a-b)
def add():
a = stack.pop(0)
b = stack.pop(0)
stack.insert(0, a+b)
def _and():
a = stack.pop(0)
b = stack.pop(0)
if a == -1 and b == -1:
stack.insert(0, -1)
else:
stack.insert(0,0)
def _or():
a = stack.pop(0)
b = stack.pop(0)
if a == -1 or b == -1:
stack.insert(0, -1)
else:
stack.insert(0,0)
def show_stack():
print(stack)
def add_to_stack(value):
stack.insert(0, int(value))
def main(args):
if args.preload != None:
f = open(args.preload, "r")
file_data = f.readlines()
preload = []
for line in file_data:
split_line = line.split(' ')
for word in split_line:
preload.append(word)
parse_input(preload, False)
f.close()
print("Welcome to rforth!")
while True:
i = get_input()
parse_input(i.split(' '))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='A weird little Forth implementation')
parser.add_argument('-p', '--preload', default="standard-library.f", type=str, help='A file to preload')
args = parser.parse_args()
main(args)