mirror of
https://github.com/russolsen/sallyforth
synced 2024-12-25 21:58:18 +01:00
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:
parent
0f63796331
commit
97c3aa1fff
4 changed files with 137 additions and 115 deletions
|
@ -14,12 +14,6 @@ def to_number(token):
|
|||
except ValueError:
|
||||
return None
|
||||
|
||||
def push_value_f(value):
|
||||
def x(f):
|
||||
f.stack.push(value)
|
||||
return 1
|
||||
return x
|
||||
|
||||
class Forth:
|
||||
def __init__(self, startup=None):
|
||||
self.stack = Stack()
|
||||
|
@ -38,6 +32,8 @@ class Forth:
|
|||
']': w_endlist,
|
||||
'{': w_startmap,
|
||||
'}': w_endmap,
|
||||
'@@': w_lookup,
|
||||
'!!': w_call,
|
||||
'+': w_add,
|
||||
'+': w_add,
|
||||
'-': w_sub,
|
||||
|
@ -102,14 +98,14 @@ class Forth:
|
|||
return
|
||||
|
||||
if is_string(token):
|
||||
self.compiler.add_instruction(push_value_f(token[1::]))
|
||||
self.compiler.add_instruction(const_f(token[1::]))
|
||||
return
|
||||
|
||||
if token in self.dictionary:
|
||||
word = self.dictionary[token]
|
||||
if 'immediate' in word.__dict__:
|
||||
#print('before immediate word:', self, self.dictionary)
|
||||
word(self)
|
||||
word(self, 0)
|
||||
#print('after immediate word:', self, self.dictionary)
|
||||
else:
|
||||
self.compiler.add_instruction(self.dictionary[token])
|
||||
|
@ -120,7 +116,7 @@ class Forth:
|
|||
self.compiler = None
|
||||
print(f'{token}? Compile terminated.')
|
||||
else:
|
||||
self.compiler.add_instruction(push_value_f(n))
|
||||
self.compiler.add_instruction(const_f(n))
|
||||
|
||||
def execute_token(self, token):
|
||||
if is_string(token):
|
||||
|
@ -128,7 +124,7 @@ class Forth:
|
|||
return
|
||||
|
||||
if token in self.dictionary:
|
||||
self.dictionary[token](self)
|
||||
self.dictionary[token](self, 0)
|
||||
return
|
||||
|
||||
n = to_number(token)
|
||||
|
|
|
@ -31,15 +31,11 @@ def tokenize(s):
|
|||
elif state == 'start':
|
||||
token = ch
|
||||
state = 'word'
|
||||
elif state == 's_string' and ch == "'":
|
||||
tokens.append(token)
|
||||
state = 'start'
|
||||
token = ''
|
||||
elif state == 'string' and ch == '"':
|
||||
tokens.append(token)
|
||||
state = 'start'
|
||||
token = ''
|
||||
elif state == 'word' and is_space(ch):
|
||||
elif (state in ['word', 's_string']) and is_space(ch):
|
||||
tokens.append(token)
|
||||
state = 'start'
|
||||
token = ''
|
||||
|
|
|
@ -29,12 +29,23 @@
|
|||
: p . nl ;
|
||||
: 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
|
||||
dup
|
||||
1 ->list os.path.exists
|
||||
if source else drop then
|
||||
;
|
||||
|
||||
: << [ ;
|
||||
: >> ] @@ ;
|
||||
|
||||
: ! ( obj method args -- result ) rot stack ;
|
||||
|
||||
"init.sf" source-if-exists
|
||||
|
||||
|
||||
|
|
|
@ -3,17 +3,17 @@ import importlib
|
|||
from inspect import isfunction, isbuiltin
|
||||
|
||||
def const_f(value):
|
||||
def x(f):
|
||||
def x(f, i):
|
||||
f.stack.push(value)
|
||||
return 1
|
||||
return i + 1
|
||||
return x
|
||||
|
||||
def native_function_handler(func):
|
||||
def handle(forth):
|
||||
def handle(forth, i):
|
||||
args = forth.stack.pop()
|
||||
result = func(*args)
|
||||
forth.stack.push(result)
|
||||
return 1
|
||||
return i + 1
|
||||
return handle
|
||||
|
||||
def import_native_module(forth, m, alias=None, excludes=[]):
|
||||
|
@ -30,55 +30,66 @@ def import_native_module(forth, m, alias=None, excludes=[]):
|
|||
else:
|
||||
forth.dictionary[localname] = const_f(val)
|
||||
|
||||
def w_require(f):
|
||||
def w_require(f, i):
|
||||
name = f.stack.pop()
|
||||
m = importlib.import_module(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()
|
||||
f.execute_file(path)
|
||||
return 1
|
||||
return i + 1
|
||||
|
||||
def execute_f(name, instructions):
|
||||
# print('execute_f:', len(instructions))
|
||||
def inner(forth, debug=False):
|
||||
# print('inner f:', name)
|
||||
# print('inner f:', len(instructions))
|
||||
i = 0
|
||||
while i >= 0:
|
||||
# print(i, '=>', instructions[i])
|
||||
delta = instructions[i](forth)
|
||||
i += delta
|
||||
return 1
|
||||
#print('execute_f:', name, len(instructions))
|
||||
def inner(forth, i, debug=False):
|
||||
#print('inner f:', name)
|
||||
#print('inner f:', len(instructions))
|
||||
j = 0
|
||||
while j >= 0:
|
||||
#print(j, '=>', instructions[j])
|
||||
j = instructions[j](forth, j)
|
||||
return i + 1
|
||||
return inner
|
||||
|
||||
def ifnot_jump_f(n):
|
||||
def ifnot_jump(forth):
|
||||
def ifnot_jump(forth, i):
|
||||
# print('If not jump:')
|
||||
x = forth.stack.pop()
|
||||
# print('==>value:', x)
|
||||
if not x:
|
||||
# print('==>', x, ' is false')
|
||||
# print('==>returning', n)
|
||||
return n
|
||||
return i+n
|
||||
# print('==>returning 1')
|
||||
return 1
|
||||
return i+1
|
||||
return ifnot_jump
|
||||
|
||||
def jump_f(n):
|
||||
def do_jump(forth):
|
||||
return n
|
||||
def do_jump(forth, i):
|
||||
return n+i
|
||||
return do_jump
|
||||
|
||||
def w_import(f):
|
||||
def w_recur(f, i):
|
||||
return 0
|
||||
|
||||
def w_import(f, i):
|
||||
name = f.stack.pop()
|
||||
m = importlib.import_module(name)
|
||||
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()
|
||||
#print('args', args)
|
||||
name = f.stack.pop()
|
||||
|
@ -90,24 +101,32 @@ def w_px(f):
|
|||
result = func(*args)
|
||||
#print('result', result)
|
||||
f.stack.push(result)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_list(f):
|
||||
def w_list(f, ip): # ->list
|
||||
n = f.stack.pop()
|
||||
l = []
|
||||
for i in range(n):
|
||||
l.append(f.stack.pop())
|
||||
#print(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()
|
||||
|
||||
def w_startlist(f): # [
|
||||
def w_startlist(f, i): # [
|
||||
f.stack.push(ListMarker)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_endlist(f): # ]
|
||||
def w_endlist(f, i): # ]
|
||||
l = []
|
||||
x = f.stack.pop()
|
||||
while x != ListMarker:
|
||||
|
@ -115,15 +134,15 @@ def w_endlist(f): # ]
|
|||
x = f.stack.pop()
|
||||
l.reverse()
|
||||
f.stack.push(l)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
MapMarker = object()
|
||||
|
||||
def w_startmap(f): # {
|
||||
def w_startmap(f, i): # {
|
||||
f.stack.push(MapMarker)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_endmap(f): # }
|
||||
def w_endmap(f, ip): # }
|
||||
l = []
|
||||
x = f.stack.pop()
|
||||
while x != MapMarker:
|
||||
|
@ -131,154 +150,154 @@ def w_endmap(f): # }
|
|||
x = f.stack.pop()
|
||||
if (len(l) % 2) != 0:
|
||||
print('Maps need even number of entries.')
|
||||
return 1
|
||||
return i+1
|
||||
l.reverse()
|
||||
result = {}
|
||||
for i in range(0, len(l), 2):
|
||||
result[l[i]] = l[i+1]
|
||||
f.stack.push(result)
|
||||
return 1
|
||||
return ip+1
|
||||
|
||||
def w_get(f):
|
||||
def w_get(f, i):
|
||||
name = f.stack.pop()
|
||||
m = f.stack.pop()
|
||||
result = m[name]
|
||||
f.stack.push(result)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_getattribute(f):
|
||||
def w_getattribute(f, i):
|
||||
name = f.stack.pop()
|
||||
x = f.stack.pop()
|
||||
result = x.__getattribute__(name)
|
||||
f.stack.push(result)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_def(f):
|
||||
def w_def(f, i):
|
||||
value = f.stack.pop()
|
||||
name = f.stack.pop()
|
||||
f.defvar(name, value)
|
||||
#print('name', name, 'value', value)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_gt(f):
|
||||
def w_gt(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b > a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_lt(f):
|
||||
def w_lt(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b < a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_eq(f):
|
||||
def w_eq(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(a==b)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_le(f):
|
||||
def w_le(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b<=a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_ge(f):
|
||||
def w_ge(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b>=a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_add(f):
|
||||
def w_add(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b+a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_mul(f):
|
||||
def w_mul(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b*a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_sub(f):
|
||||
def w_sub(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b-a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_div(f):
|
||||
def w_div(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(b/a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_dot(f):
|
||||
def w_dot(f, i):
|
||||
a = f.stack.pop()
|
||||
print(a, end='')
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_dup(f):
|
||||
def w_dup(f, i):
|
||||
x = f.stack.peek()
|
||||
f.stack.push(x)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_rot(f):
|
||||
def w_rot(f, i):
|
||||
c = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
a = f.stack.pop()
|
||||
f.stack.push(b)
|
||||
f.stack.push(c)
|
||||
f.stack.push(a)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_drop(f):
|
||||
def w_drop(f, i):
|
||||
f.stack.pop()
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_swap(f):
|
||||
def w_swap(f, i):
|
||||
a = f.stack.pop()
|
||||
b = f.stack.pop()
|
||||
f.stack.push(a)
|
||||
f.stack.push(b)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_nl(f):
|
||||
def w_nl(f, i):
|
||||
print()
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_return(f):
|
||||
return -9999999999
|
||||
def w_return(f, i):
|
||||
return -9999;
|
||||
|
||||
def w_colon(f):
|
||||
def w_colon(f, i):
|
||||
f.compiler = Compiler()
|
||||
|
||||
def w_semi(forth):
|
||||
def w_semi(forth, i):
|
||||
forth.compiler.add_instruction(w_return)
|
||||
name = forth.compiler.name
|
||||
word_f = execute_f(name, forth.compiler.instructions)
|
||||
forth.dictionary[name] = word_f
|
||||
forth.compiler = None
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_semi.__dict__['immediate'] = True
|
||||
|
||||
def w_should_not_happen(forth):
|
||||
def w_should_not_happen(forth, i):
|
||||
print('Should not execute this word!')
|
||||
raise ValueError
|
||||
|
||||
def w_if(forth):
|
||||
def w_if(forth, i):
|
||||
#print('w_if')
|
||||
compiler = forth.compiler
|
||||
compiler.push_offset()
|
||||
compiler.push_offset()
|
||||
compiler.add_instruction(w_should_not_happen)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_if.__dict__['immediate'] = True
|
||||
|
||||
def w_then(forth):
|
||||
def w_then(forth, i):
|
||||
compiler = forth.compiler
|
||||
else_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)
|
||||
else_delta = then_offset - else_offset
|
||||
compiler.instructions[else_offset] = jump_f(else_delta)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_then.__dict__['immediate'] = True
|
||||
|
||||
|
||||
def w_else(forth):
|
||||
def w_else(forth, i):
|
||||
compiler = forth.compiler
|
||||
compiler.pop_offset()
|
||||
compiler.push_offset()
|
||||
compiler.add_instruction(w_should_not_happen)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_else.__dict__['immediate'] = True
|
||||
|
||||
def w_do(forth):
|
||||
def w_do(forth, i):
|
||||
#print('w_do')
|
||||
compiler = forth.compiler
|
||||
compiler.push_offset()
|
||||
compiler.add_instruction(w_should_not_happen)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_do.__dict__['immediate'] = True
|
||||
|
||||
def w_while(forth):
|
||||
def w_while(forth, i):
|
||||
compiler = forth.compiler
|
||||
do_offset = compiler.pop_offset()
|
||||
while_offset = compiler.offset()
|
||||
delta = do_offset - while_offset
|
||||
compiler.instructions[if_offset] = ifnot_jump_f(delta)
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_while.__dict__['immediate'] = True
|
||||
|
||||
def w_begin(forth):
|
||||
def w_begin(forth, i):
|
||||
compiler = forth.compiler
|
||||
compiler.push_offset()
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_begin.__dict__['immediate'] = True
|
||||
|
||||
def w_until(forth):
|
||||
def w_until(forth, i):
|
||||
compiler = forth.compiler
|
||||
begin_offset = compiler.pop_offset()
|
||||
until_offset = compiler.offset()
|
||||
delta = begin_offset - until_offset
|
||||
#print('Delta:', delta)
|
||||
compiler.instructions.append(ifnot_jump_f(delta))
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
|
||||
w_until.__dict__['immediate'] = True
|
||||
|
||||
|
||||
def w_dump(f):
|
||||
def w_dump(f, i):
|
||||
f.dump()
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
def w_idump(f):
|
||||
def w_idump(f, i):
|
||||
f.dump()
|
||||
return 1
|
||||
return i+1
|
||||
|
||||
w_idump.__dict__['immediate'] = True
|
||||
|
||||
def w_stack(f):
|
||||
def w_stack(f, i):
|
||||
print(f'Stack: <B[{f.stack}]T>')
|
||||
return 1
|
||||
return i+1
|
||||
|
|
Loading…
Reference in a new issue