277 lines
6.5 KiB
Python
Executable File
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)
|