From 502f120d7b34d5208e7f66dc3b1a2ec6ca856c9f Mon Sep 17 00:00:00 2001 From: Russ Olsen Date: Sat, 18 Apr 2020 12:12:10 -0400 Subject: [PATCH] Added builtin alias word, which means we can define most of the built-in words with non-Python comparible names (think . and +) in sallyforth instead of Python. Also added backslash comments and stack reset work. --- sallyforth/kernel.py | 24 ++------------------- sallyforth/lex.py | 6 +++++- sallyforth/stack.py | 3 +++ sallyforth/startup.sf | 50 ++++++++++++++++++++++++++++++++++++++----- sallyforth/words.py | 49 ++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 102 insertions(+), 30 deletions(-) diff --git a/sallyforth/kernel.py b/sallyforth/kernel.py index 3d76b25..73019c2 100644 --- a/sallyforth/kernel.py +++ b/sallyforth/kernel.py @@ -24,26 +24,7 @@ class Forth: 'nil': const_f(None), '0': const_f(0), '1': const_f(1), - '2': const_f(2), - ';': w_semi, - ':': w_colon, - '->list': w_list, - '[': w_startlist, - ']': w_endlist, - '{': w_startmap, - '}': w_endmap, - '@@': w_lookup, - '!!': w_call, - '+': w_add, - '+': w_add, - '-': w_sub, - '/': w_div, - '>': w_gt, - '<': w_lt, - '<=': w_le, - '>=': w_ge, - '=': w_eq, - '.': w_dot} + '2': const_f(2) } self.import_from_module(words, 'w_') @@ -75,6 +56,7 @@ class Forth: def execute_tokens(self, tokens): for token in tokens: + # print("token:", token) if not self.compiling(): self.execute_token(token) else: @@ -104,9 +86,7 @@ class Forth: if token in self.dictionary: word = self.dictionary[token] if 'immediate' in word.__dict__: - #print('before immediate word:', self, self.dictionary) word(self, 0) - #print('after immediate word:', self, self.dictionary) else: self.compiler.add_instruction(self.dictionary[token]) return diff --git a/sallyforth/lex.py b/sallyforth/lex.py index 0befec3..d630f50 100644 --- a/sallyforth/lex.py +++ b/sallyforth/lex.py @@ -16,9 +16,13 @@ def tokenize(s): #print(f'Loop state {state} token {token} ch {ch}') if state == 'start' and ch == '(': state = 'comment' + elif state == 'start' and ch == '\\': + state = 'line_comment' + elif state == 'line_comment' and ch == '\n': + state = 'start' elif state == 'comment' and ch == ')': state = 'start' - elif state == 'comment': + elif state in ['comment', 'line_comment']: continue elif state == 'start' and is_space(ch): continue diff --git a/sallyforth/stack.py b/sallyforth/stack.py index ca27995..5b19828 100644 --- a/sallyforth/stack.py +++ b/sallyforth/stack.py @@ -21,6 +21,9 @@ class Stack: def peek(self): return self.stack[self.top] + def reset(self): + self.top = -1 + def __str__(self): result = '' for i in range(self.top + 1): diff --git a/sallyforth/startup.sf b/sallyforth/startup.sf index c1accfa..0e105b6 100644 --- a/sallyforth/startup.sf +++ b/sallyforth/startup.sf @@ -1,4 +1,6 @@ -"Executing " . *source* . nl +"Executing " dot *source* dot nl + +\ Pull in libs. "builtins" require "time" require @@ -8,10 +10,48 @@ "os.path" require "io" require -: *prompt* "SF> " ; +\ Basic aliases + +'dot '. alias +'colon ': alias +'semi '; alias +'bounded_list '[list] alias +'list '->list alias +'list_to_map 'list->map alias +'lookup '@@ alias +'call '!! alias +'add '+ alias +'sub '- alias +'mul '* alias +'div '/ alias +'gt '> alias +'lt '< alias +'le '<= alias +'ge '>= alias +'eq '= alias + +: *prompt* "Sally> " ; + +'list-marker unique def +: [ list-marker ; +: ] list-marker [list] ; : [] ( -- ) [ ] ; +'map-marker unique def +: { map-marker ; +: } map-marker [list] list->map ; + +'set-marker unique def +: {{ set-marker ; +: }} + set-marker [list] \ Turn elements into list + set-marker swap set-marker [list] \ Nest list in argument list + builtins.set !! \ Call set with 1 argument +; + +: type (x -- type-of-x) 1 ->list builtins.type !! ; + : px0 (mod fname -- result) [] px ; : px1 (mod fname arg -- result) 1 ->list px ; : px2 (mod fname arg arg -- result) 2 ->list px ; @@ -25,6 +65,8 @@ : >0 0 > ; : <0 0 < ; +: >1 1 > ; +: <1 1 < ; : p . nl ; : top dup p ; @@ -35,7 +77,7 @@ : neg? (n -- bool) 0 < ; : zero? (n -- bool) 0 = ; -: source-if-exists +: source-if-exists (path --) dup 1 ->list os.path.exists if source else drop then @@ -44,8 +86,6 @@ : << [ ; : >> ] @@ ; -: ! ( obj method args -- result ) rot stack ; - "init.sf" source-if-exists diff --git a/sallyforth/words.py b/sallyforth/words.py index daf1282..bcddbe4 100644 --- a/sallyforth/words.py +++ b/sallyforth/words.py @@ -2,6 +2,10 @@ from compiler import Compiler import importlib from inspect import isfunction, isbuiltin +class Unique: + def __str__(self): + return f'Unique[{id(self)}]' + def const_f(value): def x(f, i): f.stack.push(value) @@ -30,6 +34,16 @@ def import_native_module(forth, m, alias=None, excludes=[]): else: forth.dictionary[localname] = const_f(val) +def w_forth(f, i): + f.stack.push(f) + return i+1 + +def w_alias(f, i): + new_name = f.stack.pop() + old_name = f.stack.pop() + f.dictionary[new_name] = f.dictionary[old_name] + return i + 1 + def w_require(f, i): name = f.stack.pop() m = importlib.import_module(name) @@ -81,8 +95,8 @@ def w_import(f, i): return i+1 def w_call(f, i): - args = f.stack.pop() func = f.stack.pop() + args = f.stack.pop() print('f', f, 'args', args) result = func(*args) print('result', result) @@ -103,6 +117,25 @@ def w_px(f, i): f.stack.push(result) return i+1 +def w_unique(f, ip): # pushes a uique object. + f.stack.push(Unique()) + return ip+1 + +def w_bounded_list(f, ip): + """Create a list from delimted values on the stack. + [list] + (marker a b c marker -- [a b c] + """ + marker = f.stack.pop() + l = [] + x = f.stack.pop() + while x != marker: + l.append(x) + x = f.stack.pop() + l.reverse() + f.stack.push(l) + return ip+1 + def w_list(f, ip): # ->list n = f.stack.pop() l = [] @@ -158,6 +191,14 @@ def w_endmap(f, ip): # } f.stack.push(result) return ip+1 +def w_list_to_map(f, ip): # list->map + l = f.stack.pop() + result = {} + for i in range(0, len(l), 2): + result[l[i]] = l[i+1] + f.stack.push(result) + return ip+1 + def w_get(f, i): name = f.stack.pop() m = f.stack.pop() @@ -176,7 +217,7 @@ def w_def(f, i): value = f.stack.pop() name = f.stack.pop() f.defvar(name, value) - #print('name', name, 'value', value) + print('name', name, 'value', value) return i+1 def w_gt(f, i): @@ -233,6 +274,10 @@ def w_div(f, i): f.stack.push(b/a) return i+1 +def w_reset(f, i): + a = f.stack.reset() + return i+1 + def w_dot(f, i): a = f.stack.pop() print(a, end='')