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.

This commit is contained in:
Russ Olsen 2020-04-18 12:12:10 -04:00
parent 97c3aa1fff
commit 502f120d7b
5 changed files with 102 additions and 30 deletions

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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] ;
: [] ( -- <empty 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

View file

@ -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='')