2021-01-04 14:16:12 +01:00
|
|
|
#!/usr/bin/env python3
|
2021-01-03 15:59:45 +01:00
|
|
|
# planck -
|
|
|
|
# Copyright (C) 2021 nineties
|
|
|
|
#
|
|
|
|
|
|
|
|
import sys
|
|
|
|
CELL = 4
|
|
|
|
MEMORY_SIZE = 0x08000000
|
|
|
|
STACK_SIZE = 0x400
|
|
|
|
RSTACK_SIZE = 0x400
|
|
|
|
HERE_CELL = 0
|
|
|
|
LATEST_CELL = CELL
|
|
|
|
|
|
|
|
memory = bytearray(MEMORY_SIZE)
|
|
|
|
sp = MEMORY_SIZE
|
|
|
|
rp = MEMORY_SIZE - STACK_SIZE
|
|
|
|
ip = 0
|
|
|
|
pc = 0
|
|
|
|
|
2021-01-05 06:22:10 +01:00
|
|
|
def aligned(n):
|
|
|
|
return (n + CELL - 1) & ~(CELL - 1)
|
|
|
|
|
2021-01-03 15:59:45 +01:00
|
|
|
def read(addr):
|
|
|
|
return int.from_bytes(
|
|
|
|
memory[addr:addr+CELL], 'little', signed=True)
|
|
|
|
|
|
|
|
def write(addr, v):
|
|
|
|
memory[addr:addr+CELL] = v.to_bytes(4, 'little', signed=True)
|
|
|
|
|
|
|
|
def read_byte(addr):
|
|
|
|
return memory[addr]
|
|
|
|
|
|
|
|
def write_byte(addr, v):
|
|
|
|
memory[addr] = v
|
|
|
|
|
|
|
|
next_builtin_id = 1
|
|
|
|
def add_builtin(c):
|
|
|
|
global next_builtin_id
|
|
|
|
builtin_id = next_builtin_id
|
|
|
|
next_builtin_id += 1
|
|
|
|
|
|
|
|
here = read(HERE_CELL)
|
|
|
|
latest = read(LATEST_CELL)
|
|
|
|
write(here, latest)
|
|
|
|
write_byte(here + CELL, 1)
|
|
|
|
write_byte(here + CELL + 1, ord(c))
|
|
|
|
write(here + 2*CELL, builtin_id)
|
|
|
|
|
|
|
|
write(HERE_CELL, here + 3*CELL)
|
|
|
|
write(LATEST_CELL, here)
|
|
|
|
return builtin_id
|
|
|
|
|
|
|
|
def find(c):
|
|
|
|
it = read(LATEST_CELL)
|
|
|
|
while it != 0:
|
|
|
|
n = read_byte(it + CELL)
|
|
|
|
C = chr(read_byte(it + CELL + 1))
|
|
|
|
if (c == C and n == 1):
|
|
|
|
return it + 2*CELL
|
|
|
|
it = read(it)
|
|
|
|
raise Exception('Unknown word: {}'.format(c))
|
|
|
|
|
|
|
|
def push(v):
|
|
|
|
global sp
|
|
|
|
sp -= CELL
|
|
|
|
write(sp, v)
|
|
|
|
|
|
|
|
def pop():
|
|
|
|
global sp
|
|
|
|
v = read(sp)
|
|
|
|
sp += CELL
|
|
|
|
return v
|
|
|
|
|
|
|
|
def rpush(v):
|
|
|
|
global rp
|
|
|
|
rp -= CELL
|
|
|
|
write(rp, v)
|
|
|
|
|
|
|
|
def rpop():
|
|
|
|
global rp
|
|
|
|
v = read(rp)
|
|
|
|
rp += CELL
|
|
|
|
return v
|
|
|
|
|
|
|
|
write(HERE_CELL, 2*CELL)
|
|
|
|
write(LATEST_CELL, 0)
|
|
|
|
|
|
|
|
DOCOL_ = 0
|
|
|
|
QUIT = add_builtin('Q')
|
|
|
|
CELLSIZE = add_builtin('C')
|
|
|
|
HERE = add_builtin('h')
|
|
|
|
LATEST = add_builtin('l')
|
|
|
|
KEY = add_builtin('k')
|
|
|
|
EMIT = add_builtin('t')
|
|
|
|
JUMP = add_builtin('j')
|
|
|
|
JUMP0 = add_builtin('J')
|
|
|
|
FIND = add_builtin('f')
|
|
|
|
EXECUTE = add_builtin('x')
|
|
|
|
FETCH = add_builtin('@')
|
|
|
|
STORE = add_builtin('!')
|
|
|
|
CFETCH = add_builtin('?')
|
|
|
|
CSTORE = add_builtin('$')
|
|
|
|
DFETCH = add_builtin('d')
|
|
|
|
DSTORE = add_builtin('D')
|
|
|
|
RFETCH = add_builtin('r')
|
|
|
|
RSTORE = add_builtin('R')
|
|
|
|
DOCOL = add_builtin('i')
|
|
|
|
EXIT = add_builtin('e')
|
|
|
|
LIT = add_builtin('L')
|
|
|
|
LITSTRING = add_builtin('S')
|
|
|
|
ADD = add_builtin('+')
|
|
|
|
SUB = add_builtin('-')
|
|
|
|
MUL = add_builtin('*')
|
|
|
|
DIV = add_builtin('/')
|
|
|
|
MOD = add_builtin('%')
|
|
|
|
AND = add_builtin('&')
|
|
|
|
OR = add_builtin('|')
|
|
|
|
XOR = add_builtin('^')
|
|
|
|
LESS = add_builtin('<')
|
|
|
|
EQUAL = add_builtin('=')
|
|
|
|
|
|
|
|
here = read(HERE_CELL)
|
|
|
|
write(here, find('k'))
|
|
|
|
write(here + CELL, find('f'))
|
|
|
|
write(here + 2*CELL, find('x'))
|
|
|
|
write(here + 3*CELL, find('j'))
|
|
|
|
write(here + 4*CELL, -4*CELL)
|
|
|
|
write(HERE_CELL, here + 5*CELL)
|
|
|
|
|
|
|
|
pc = here
|
|
|
|
ip = read(pc)
|
|
|
|
pc += CELL
|
|
|
|
while True:
|
|
|
|
code = read(ip)
|
|
|
|
if code == DOCOL_:
|
|
|
|
rpush(pc)
|
|
|
|
pc = ip + CELL
|
|
|
|
elif code == QUIT:
|
|
|
|
exit(0)
|
|
|
|
elif code == CELLSIZE:
|
|
|
|
push(CELL)
|
|
|
|
elif code == HERE:
|
|
|
|
push(HERE_CELL)
|
|
|
|
elif code == LATEST:
|
|
|
|
push(LATEST_CELL)
|
|
|
|
elif code == KEY:
|
|
|
|
push(ord(sys.stdin.read(1)))
|
|
|
|
elif code == EMIT:
|
|
|
|
sys.stdout.write(chr(pop()))
|
|
|
|
elif code == JUMP:
|
|
|
|
pc += read(pc)
|
|
|
|
elif code == JUMP0:
|
|
|
|
if pop() == 0:
|
|
|
|
pc += read(pc)
|
|
|
|
else:
|
|
|
|
pc += CELL
|
|
|
|
elif code == FIND:
|
|
|
|
push(find(chr(pop())))
|
|
|
|
elif code == EXECUTE:
|
|
|
|
ip = pop()
|
|
|
|
continue
|
|
|
|
elif code == FETCH:
|
|
|
|
push(read(pop()))
|
|
|
|
elif code == STORE:
|
|
|
|
addr = pop()
|
|
|
|
write(addr, pop())
|
|
|
|
elif code == CFETCH:
|
|
|
|
push(read_byte(pop()))
|
|
|
|
elif code == CSTORE:
|
|
|
|
addr = pop()
|
|
|
|
write_byte(addr, pop())
|
|
|
|
elif code == DFETCH:
|
|
|
|
push(sp)
|
|
|
|
elif code == DSTORE:
|
|
|
|
sp = pop()
|
|
|
|
elif code == RFETCH:
|
|
|
|
push(rp)
|
|
|
|
elif code == RSTORE:
|
|
|
|
rp = pop()
|
|
|
|
elif code == DOCOL:
|
|
|
|
push(DOCOL_)
|
|
|
|
elif code == EXIT:
|
|
|
|
pc = rpop()
|
|
|
|
elif code == LIT:
|
|
|
|
push(read(pc))
|
|
|
|
pc += CELL
|
|
|
|
elif code == LITSTRING:
|
|
|
|
n = read(pc)
|
|
|
|
push(pc + CELL)
|
2021-01-05 06:22:10 +01:00
|
|
|
pc = aligned(pc + CELL + n)
|
2021-01-03 15:59:45 +01:00
|
|
|
elif code == ADD:
|
|
|
|
b = pop()
|
|
|
|
push(pop() + b)
|
|
|
|
elif code == SUB:
|
|
|
|
b = pop()
|
|
|
|
push(pop() - b)
|
|
|
|
elif code == MUL:
|
|
|
|
b = pop()
|
|
|
|
push(pop() * b)
|
|
|
|
elif code == DIV:
|
|
|
|
b = pop()
|
|
|
|
push(pop() // b)
|
|
|
|
elif code == MOD:
|
|
|
|
b = pop()
|
|
|
|
push(pop() % b)
|
|
|
|
elif code == AND:
|
|
|
|
b = pop()
|
|
|
|
push(pop() & b)
|
|
|
|
elif code == OR:
|
|
|
|
b = pop()
|
|
|
|
push(pop() | b)
|
|
|
|
elif code == XOR:
|
|
|
|
b = pop()
|
|
|
|
push(pop() ^ b)
|
|
|
|
elif code == LESS:
|
|
|
|
b = pop()
|
|
|
|
push(pop() < b)
|
|
|
|
elif code == EQUAL:
|
|
|
|
b = pop()
|
|
|
|
push(pop() == b)
|
|
|
|
else:
|
|
|
|
raise Exception('Invalid Code Pointer: {}'.format(code))
|
|
|
|
ip = read(pc)
|
|
|
|
pc += CELL
|