Switched the word function xface so that words now return the new ip instead of a delta. This simplifies the interpreter allows recur to simply return 0. Also changed the tokenizer so that 'foo produces a string w/o the need for a closing quote, good for symbols.

This commit is contained in:
Russ Olsen 2020-04-18 10:22:25 -04:00
parent 0f63796331
commit 97c3aa1fff
4 changed files with 137 additions and 115 deletions

View file

@ -14,12 +14,6 @@ def to_number(token):
except ValueError: except ValueError:
return None return None
def push_value_f(value):
def x(f):
f.stack.push(value)
return 1
return x
class Forth: class Forth:
def __init__(self, startup=None): def __init__(self, startup=None):
self.stack = Stack() self.stack = Stack()
@ -38,6 +32,8 @@ class Forth:
']': w_endlist, ']': w_endlist,
'{': w_startmap, '{': w_startmap,
'}': w_endmap, '}': w_endmap,
'@@': w_lookup,
'!!': w_call,
'+': w_add, '+': w_add,
'+': w_add, '+': w_add,
'-': w_sub, '-': w_sub,
@ -102,14 +98,14 @@ class Forth:
return return
if is_string(token): if is_string(token):
self.compiler.add_instruction(push_value_f(token[1::])) self.compiler.add_instruction(const_f(token[1::]))
return return
if token in self.dictionary: if token in self.dictionary:
word = self.dictionary[token] word = self.dictionary[token]
if 'immediate' in word.__dict__: if 'immediate' in word.__dict__:
#print('before immediate word:', self, self.dictionary) #print('before immediate word:', self, self.dictionary)
word(self) word(self, 0)
#print('after immediate word:', self, self.dictionary) #print('after immediate word:', self, self.dictionary)
else: else:
self.compiler.add_instruction(self.dictionary[token]) self.compiler.add_instruction(self.dictionary[token])
@ -120,7 +116,7 @@ class Forth:
self.compiler = None self.compiler = None
print(f'{token}? Compile terminated.') print(f'{token}? Compile terminated.')
else: else:
self.compiler.add_instruction(push_value_f(n)) self.compiler.add_instruction(const_f(n))
def execute_token(self, token): def execute_token(self, token):
if is_string(token): if is_string(token):
@ -128,7 +124,7 @@ class Forth:
return return
if token in self.dictionary: if token in self.dictionary:
self.dictionary[token](self) self.dictionary[token](self, 0)
return return
n = to_number(token) n = to_number(token)

View file

@ -31,15 +31,11 @@ def tokenize(s):
elif state == 'start': elif state == 'start':
token = ch token = ch
state = 'word' state = 'word'
elif state == 's_string' and ch == "'":
tokens.append(token)
state = 'start'
token = ''
elif state == 'string' and ch == '"': elif state == 'string' and ch == '"':
tokens.append(token) tokens.append(token)
state = 'start' state = 'start'
token = '' token = ''
elif state == 'word' and is_space(ch): elif (state in ['word', 's_string']) and is_space(ch):
tokens.append(token) tokens.append(token)
state = 'start' state = 'start'
token = '' token = ''

View file

@ -29,12 +29,23 @@
: p . nl ; : p . nl ;
: top dup p ; : top dup p ;
: -- ( n -- n-1 ) -1 + ;
: ++ ( n -- n+1 ) 1 + ;
: pos? (n -- bool) 0 > ;
: neg? (n -- bool) 0 < ;
: zero? (n -- bool) 0 = ;
: source-if-exists : source-if-exists
dup dup
1 ->list os.path.exists 1 ->list os.path.exists
if source else drop then if source else drop then
; ;
: << [ ;
: >> ] @@ ;
: ! ( obj method args -- result ) rot stack ;
"init.sf" source-if-exists "init.sf" source-if-exists

View file

@ -3,17 +3,17 @@ import importlib
from inspect import isfunction, isbuiltin from inspect import isfunction, isbuiltin
def const_f(value): def const_f(value):
def x(f): def x(f, i):
f.stack.push(value) f.stack.push(value)
return 1 return i + 1
return x return x
def native_function_handler(func): def native_function_handler(func):
def handle(forth): def handle(forth, i):
args = forth.stack.pop() args = forth.stack.pop()
result = func(*args) result = func(*args)
forth.stack.push(result) forth.stack.push(result)
return 1 return i + 1
return handle return handle
def import_native_module(forth, m, alias=None, excludes=[]): def import_native_module(forth, m, alias=None, excludes=[]):
@ -30,55 +30,66 @@ def import_native_module(forth, m, alias=None, excludes=[]):
else: else:
forth.dictionary[localname] = const_f(val) forth.dictionary[localname] = const_f(val)
def w_require(f): def w_require(f, i):
name = f.stack.pop() name = f.stack.pop()
m = importlib.import_module(name) m = importlib.import_module(name)
import_native_module(f, m, name) import_native_module(f, m, name)
return 1 return i + 1
def w_source(f): def w_source(f, i):
path = f.stack.pop() path = f.stack.pop()
f.execute_file(path) f.execute_file(path)
return 1 return i + 1
def execute_f(name, instructions): def execute_f(name, instructions):
# print('execute_f:', len(instructions)) #print('execute_f:', name, len(instructions))
def inner(forth, debug=False): def inner(forth, i, debug=False):
# print('inner f:', name) #print('inner f:', name)
# print('inner f:', len(instructions)) #print('inner f:', len(instructions))
i = 0 j = 0
while i >= 0: while j >= 0:
# print(i, '=>', instructions[i]) #print(j, '=>', instructions[j])
delta = instructions[i](forth) j = instructions[j](forth, j)
i += delta return i + 1
return 1
return inner return inner
def ifnot_jump_f(n): def ifnot_jump_f(n):
def ifnot_jump(forth): def ifnot_jump(forth, i):
# print('If not jump:') # print('If not jump:')
x = forth.stack.pop() x = forth.stack.pop()
# print('==>value:', x) # print('==>value:', x)
if not x: if not x:
# print('==>', x, ' is false') # print('==>', x, ' is false')
# print('==>returning', n) # print('==>returning', n)
return n return i+n
# print('==>returning 1') # print('==>returning 1')
return 1 return i+1
return ifnot_jump return ifnot_jump
def jump_f(n): def jump_f(n):
def do_jump(forth): def do_jump(forth, i):
return n return n+i
return do_jump return do_jump
def w_import(f): def w_recur(f, i):
return 0
def w_import(f, i):
name = f.stack.pop() name = f.stack.pop()
m = importlib.import_module(name) m = importlib.import_module(name)
f.dictionary[name] = const_f(m) f.dictionary[name] = const_f(m)
return 1 return i+1
def w_px(f): def w_call(f, i):
args = f.stack.pop()
func = f.stack.pop()
print('f', f, 'args', args)
result = func(*args)
print('result', result)
f.stack.push(result)
return i+1
def w_px(f, i):
args = f.stack.pop() args = f.stack.pop()
#print('args', args) #print('args', args)
name = f.stack.pop() name = f.stack.pop()
@ -90,24 +101,32 @@ def w_px(f):
result = func(*args) result = func(*args)
#print('result', result) #print('result', result)
f.stack.push(result) f.stack.push(result)
return 1 return i+1
def w_list(f): def w_list(f, ip): # ->list
n = f.stack.pop() n = f.stack.pop()
l = [] l = []
for i in range(n): for i in range(n):
l.append(f.stack.pop()) l.append(f.stack.pop())
#print(l) #print(l)
f.stack.push(l) f.stack.push(l)
return 1 return ip+1
def w_lookup(f, i): # @@
l = f.stack.pop()
value = l[0]
for field in l[1::]:
value = getattr(value, field)
f.stack.push(value)
return i+1
ListMarker = object() ListMarker = object()
def w_startlist(f): # [ def w_startlist(f, i): # [
f.stack.push(ListMarker) f.stack.push(ListMarker)
return 1 return i+1
def w_endlist(f): # ] def w_endlist(f, i): # ]
l = [] l = []
x = f.stack.pop() x = f.stack.pop()
while x != ListMarker: while x != ListMarker:
@ -115,15 +134,15 @@ def w_endlist(f): # ]
x = f.stack.pop() x = f.stack.pop()
l.reverse() l.reverse()
f.stack.push(l) f.stack.push(l)
return 1 return i+1
MapMarker = object() MapMarker = object()
def w_startmap(f): # { def w_startmap(f, i): # {
f.stack.push(MapMarker) f.stack.push(MapMarker)
return 1 return i+1
def w_endmap(f): # } def w_endmap(f, ip): # }
l = [] l = []
x = f.stack.pop() x = f.stack.pop()
while x != MapMarker: while x != MapMarker:
@ -131,154 +150,154 @@ def w_endmap(f): # }
x = f.stack.pop() x = f.stack.pop()
if (len(l) % 2) != 0: if (len(l) % 2) != 0:
print('Maps need even number of entries.') print('Maps need even number of entries.')
return 1 return i+1
l.reverse() l.reverse()
result = {} result = {}
for i in range(0, len(l), 2): for i in range(0, len(l), 2):
result[l[i]] = l[i+1] result[l[i]] = l[i+1]
f.stack.push(result) f.stack.push(result)
return 1 return ip+1
def w_get(f): def w_get(f, i):
name = f.stack.pop() name = f.stack.pop()
m = f.stack.pop() m = f.stack.pop()
result = m[name] result = m[name]
f.stack.push(result) f.stack.push(result)
return 1 return i+1
def w_getattribute(f): def w_getattribute(f, i):
name = f.stack.pop() name = f.stack.pop()
x = f.stack.pop() x = f.stack.pop()
result = x.__getattribute__(name) result = x.__getattribute__(name)
f.stack.push(result) f.stack.push(result)
return 1 return i+1
def w_def(f): def w_def(f, i):
value = f.stack.pop() value = f.stack.pop()
name = f.stack.pop() name = f.stack.pop()
f.defvar(name, value) f.defvar(name, value)
#print('name', name, 'value', value) #print('name', name, 'value', value)
return 1 return i+1
def w_gt(f): def w_gt(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b > a) f.stack.push(b > a)
return 1 return i+1
def w_lt(f): def w_lt(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b < a) f.stack.push(b < a)
return 1 return i+1
def w_eq(f): def w_eq(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(a==b) f.stack.push(a==b)
return 1 return i+1
def w_le(f): def w_le(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b<=a) f.stack.push(b<=a)
return 1 return i+1
def w_ge(f): def w_ge(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b>=a) f.stack.push(b>=a)
return 1 return i+1
def w_add(f): def w_add(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b+a) f.stack.push(b+a)
return 1 return i+1
def w_mul(f): def w_mul(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b*a) f.stack.push(b*a)
return 1 return i+1
def w_sub(f): def w_sub(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b-a) f.stack.push(b-a)
return 1 return i+1
def w_div(f): def w_div(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(b/a) f.stack.push(b/a)
return 1 return i+1
def w_dot(f): def w_dot(f, i):
a = f.stack.pop() a = f.stack.pop()
print(a, end='') print(a, end='')
return 1 return i+1
def w_dup(f): def w_dup(f, i):
x = f.stack.peek() x = f.stack.peek()
f.stack.push(x) f.stack.push(x)
return 1 return i+1
def w_rot(f): def w_rot(f, i):
c = f.stack.pop() c = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
a = f.stack.pop() a = f.stack.pop()
f.stack.push(b) f.stack.push(b)
f.stack.push(c) f.stack.push(c)
f.stack.push(a) f.stack.push(a)
return 1 return i+1
def w_drop(f): def w_drop(f, i):
f.stack.pop() f.stack.pop()
return 1 return i+1
def w_swap(f): def w_swap(f, i):
a = f.stack.pop() a = f.stack.pop()
b = f.stack.pop() b = f.stack.pop()
f.stack.push(a) f.stack.push(a)
f.stack.push(b) f.stack.push(b)
return 1 return i+1
def w_nl(f): def w_nl(f, i):
print() print()
return 1 return i+1
def w_return(f): def w_return(f, i):
return -9999999999 return -9999;
def w_colon(f): def w_colon(f, i):
f.compiler = Compiler() f.compiler = Compiler()
def w_semi(forth): def w_semi(forth, i):
forth.compiler.add_instruction(w_return) forth.compiler.add_instruction(w_return)
name = forth.compiler.name name = forth.compiler.name
word_f = execute_f(name, forth.compiler.instructions) word_f = execute_f(name, forth.compiler.instructions)
forth.dictionary[name] = word_f forth.dictionary[name] = word_f
forth.compiler = None forth.compiler = None
return 1 return i+1
w_semi.__dict__['immediate'] = True w_semi.__dict__['immediate'] = True
def w_should_not_happen(forth): def w_should_not_happen(forth, i):
print('Should not execute this word!') print('Should not execute this word!')
raise ValueError raise ValueError
def w_if(forth): def w_if(forth, i):
#print('w_if') #print('w_if')
compiler = forth.compiler compiler = forth.compiler
compiler.push_offset() compiler.push_offset()
compiler.push_offset() compiler.push_offset()
compiler.add_instruction(w_should_not_happen) compiler.add_instruction(w_should_not_happen)
return 1 return i+1
w_if.__dict__['immediate'] = True w_if.__dict__['immediate'] = True
def w_then(forth): def w_then(forth, i):
compiler = forth.compiler compiler = forth.compiler
else_offset = compiler.pop_offset() else_offset = compiler.pop_offset()
if_offset = compiler.pop_offset() if_offset = compiler.pop_offset()
@ -291,69 +310,69 @@ def w_then(forth):
compiler.instructions[if_offset] = ifnot_jump_f(if_delta) compiler.instructions[if_offset] = ifnot_jump_f(if_delta)
else_delta = then_offset - else_offset else_delta = then_offset - else_offset
compiler.instructions[else_offset] = jump_f(else_delta) compiler.instructions[else_offset] = jump_f(else_delta)
return 1 return i+1
w_then.__dict__['immediate'] = True w_then.__dict__['immediate'] = True
def w_else(forth): def w_else(forth, i):
compiler = forth.compiler compiler = forth.compiler
compiler.pop_offset() compiler.pop_offset()
compiler.push_offset() compiler.push_offset()
compiler.add_instruction(w_should_not_happen) compiler.add_instruction(w_should_not_happen)
return 1 return i+1
w_else.__dict__['immediate'] = True w_else.__dict__['immediate'] = True
def w_do(forth): def w_do(forth, i):
#print('w_do') #print('w_do')
compiler = forth.compiler compiler = forth.compiler
compiler.push_offset() compiler.push_offset()
compiler.add_instruction(w_should_not_happen) compiler.add_instruction(w_should_not_happen)
return 1 return i+1
w_do.__dict__['immediate'] = True w_do.__dict__['immediate'] = True
def w_while(forth): def w_while(forth, i):
compiler = forth.compiler compiler = forth.compiler
do_offset = compiler.pop_offset() do_offset = compiler.pop_offset()
while_offset = compiler.offset() while_offset = compiler.offset()
delta = do_offset - while_offset delta = do_offset - while_offset
compiler.instructions[if_offset] = ifnot_jump_f(delta) compiler.instructions[if_offset] = ifnot_jump_f(delta)
return 1 return i+1
w_while.__dict__['immediate'] = True w_while.__dict__['immediate'] = True
def w_begin(forth): def w_begin(forth, i):
compiler = forth.compiler compiler = forth.compiler
compiler.push_offset() compiler.push_offset()
return 1 return i+1
w_begin.__dict__['immediate'] = True w_begin.__dict__['immediate'] = True
def w_until(forth): def w_until(forth, i):
compiler = forth.compiler compiler = forth.compiler
begin_offset = compiler.pop_offset() begin_offset = compiler.pop_offset()
until_offset = compiler.offset() until_offset = compiler.offset()
delta = begin_offset - until_offset delta = begin_offset - until_offset
#print('Delta:', delta) #print('Delta:', delta)
compiler.instructions.append(ifnot_jump_f(delta)) compiler.instructions.append(ifnot_jump_f(delta))
return 1 return i+1
w_until.__dict__['immediate'] = True w_until.__dict__['immediate'] = True
def w_dump(f): def w_dump(f, i):
f.dump() f.dump()
return 1 return i+1
def w_idump(f): def w_idump(f, i):
f.dump() f.dump()
return 1 return i+1
w_idump.__dict__['immediate'] = True w_idump.__dict__['immediate'] = True
def w_stack(f): def w_stack(f, i):
print(f'Stack: <B[{f.stack}]T>') print(f'Stack: <B[{f.stack}]T>')
return 1 return i+1