From 97c3aa1fff9857a2483f01c1397de815b85607c7 Mon Sep 17 00:00:00 2001 From: Russ Olsen Date: Sat, 18 Apr 2020 10:22:25 -0400 Subject: [PATCH] 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. --- sallyforth/kernel.py | 16 ++- sallyforth/lex.py | 6 +- sallyforth/startup.sf | 11 +++ sallyforth/words.py | 219 +++++++++++++++++++++++------------------- 4 files changed, 137 insertions(+), 115 deletions(-) diff --git a/sallyforth/kernel.py b/sallyforth/kernel.py index 74a9387..3d76b25 100644 --- a/sallyforth/kernel.py +++ b/sallyforth/kernel.py @@ -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) diff --git a/sallyforth/lex.py b/sallyforth/lex.py index 6c16487..0befec3 100644 --- a/sallyforth/lex.py +++ b/sallyforth/lex.py @@ -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 = '' diff --git a/sallyforth/startup.sf b/sallyforth/startup.sf index 9bb7860..c1accfa 100644 --- a/sallyforth/startup.sf +++ b/sallyforth/startup.sf @@ -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 diff --git a/sallyforth/words.py b/sallyforth/words.py index 45889d9..daf1282 100644 --- a/sallyforth/words.py +++ b/sallyforth/words.py @@ -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: ') - return 1 + return i+1