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), 'nil': const_f(None),
'0': const_f(0), '0': const_f(0),
'1': const_f(1), '1': const_f(1),
'2': const_f(2), '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}
self.import_from_module(words, 'w_') self.import_from_module(words, 'w_')
@ -75,6 +56,7 @@ class Forth:
def execute_tokens(self, tokens): def execute_tokens(self, tokens):
for token in tokens: for token in tokens:
# print("token:", token)
if not self.compiling(): if not self.compiling():
self.execute_token(token) self.execute_token(token)
else: else:
@ -104,9 +86,7 @@ class Forth:
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)
word(self, 0) word(self, 0)
#print('after immediate word:', self, self.dictionary)
else: else:
self.compiler.add_instruction(self.dictionary[token]) self.compiler.add_instruction(self.dictionary[token])
return return

View file

@ -16,9 +16,13 @@ def tokenize(s):
#print(f'Loop state {state} token {token} ch {ch}') #print(f'Loop state {state} token {token} ch {ch}')
if state == 'start' and ch == '(': if state == 'start' and ch == '(':
state = 'comment' state = 'comment'
elif state == 'start' and ch == '\\':
state = 'line_comment'
elif state == 'line_comment' and ch == '\n':
state = 'start'
elif state == 'comment' and ch == ')': elif state == 'comment' and ch == ')':
state = 'start' state = 'start'
elif state == 'comment': elif state in ['comment', 'line_comment']:
continue continue
elif state == 'start' and is_space(ch): elif state == 'start' and is_space(ch):
continue continue

View file

@ -21,6 +21,9 @@ class Stack:
def peek(self): def peek(self):
return self.stack[self.top] return self.stack[self.top]
def reset(self):
self.top = -1
def __str__(self): def __str__(self):
result = '' result = ''
for i in range(self.top + 1): 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 "builtins" require
"time" require "time" require
@ -8,10 +10,48 @@
"os.path" require "os.path" require
"io" 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>) [ ] ; : [] ( -- <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 ; : px0 (mod fname -- result) [] px ;
: px1 (mod fname arg -- result) 1 ->list px ; : px1 (mod fname arg -- result) 1 ->list px ;
: px2 (mod fname arg arg -- result) 2 ->list px ; : px2 (mod fname arg arg -- result) 2 ->list px ;
@ -25,6 +65,8 @@
: >0 0 > ; : >0 0 > ;
: <0 0 < ; : <0 0 < ;
: >1 1 > ;
: <1 1 < ;
: p . nl ; : p . nl ;
: top dup p ; : top dup p ;
@ -35,7 +77,7 @@
: neg? (n -- bool) 0 < ; : neg? (n -- bool) 0 < ;
: zero? (n -- bool) 0 = ; : zero? (n -- bool) 0 = ;
: source-if-exists : source-if-exists (path --)
dup dup
1 ->list os.path.exists 1 ->list os.path.exists
if source else drop then if source else drop then
@ -44,8 +86,6 @@
: << [ ; : << [ ;
: >> ] @@ ; : >> ] @@ ;
: ! ( obj method args -- result ) rot stack ;
"init.sf" source-if-exists "init.sf" source-if-exists

View file

@ -2,6 +2,10 @@ from compiler import Compiler
import importlib import importlib
from inspect import isfunction, isbuiltin from inspect import isfunction, isbuiltin
class Unique:
def __str__(self):
return f'Unique[{id(self)}]'
def const_f(value): def const_f(value):
def x(f, i): def x(f, i):
f.stack.push(value) f.stack.push(value)
@ -30,6 +34,16 @@ 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_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): def w_require(f, i):
name = f.stack.pop() name = f.stack.pop()
m = importlib.import_module(name) m = importlib.import_module(name)
@ -81,8 +95,8 @@ def w_import(f, i):
return i+1 return i+1
def w_call(f, i): def w_call(f, i):
args = f.stack.pop()
func = f.stack.pop() func = f.stack.pop()
args = f.stack.pop()
print('f', f, 'args', args) print('f', f, 'args', args)
result = func(*args) result = func(*args)
print('result', result) print('result', result)
@ -103,6 +117,25 @@ def w_px(f, i):
f.stack.push(result) f.stack.push(result)
return i+1 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 def w_list(f, ip): # ->list
n = f.stack.pop() n = f.stack.pop()
l = [] l = []
@ -158,6 +191,14 @@ def w_endmap(f, ip): # }
f.stack.push(result) f.stack.push(result)
return ip+1 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): def w_get(f, i):
name = f.stack.pop() name = f.stack.pop()
m = f.stack.pop() m = f.stack.pop()
@ -176,7 +217,7 @@ 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 i+1 return i+1
def w_gt(f, i): def w_gt(f, i):
@ -233,6 +274,10 @@ def w_div(f, i):
f.stack.push(b/a) f.stack.push(b/a)
return i+1 return i+1
def w_reset(f, i):
a = f.stack.reset()
return i+1
def w_dot(f, i): def w_dot(f, i):
a = f.stack.pop() a = f.stack.pop()
print(a, end='') print(a, end='')