1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2025-01-21 17:31:31 +00:00

Initial pass at arrays

This commit is contained in:
David Schmenk 2024-07-13 13:14:49 -07:00
parent b0c5f1c2e9
commit 45a7a44b69
4 changed files with 288 additions and 95 deletions

View File

@ -4,6 +4,7 @@ LISP interpreted on a bytecode VM running on a 1 MHz 6502 is going to be sssllll
## Missing features of LISP 1.5 in DRAWL ## Missing features of LISP 1.5 in DRAWL
- FUNCTION operation. Use QUOTE for functions that don't use higher up bound variables
- General recursion. The 6502 architecture limits recursion (but see tail recursion below), so don't expect too much here - General recursion. The 6502 architecture limits recursion (but see tail recursion below), so don't expect too much here
- Arrays not implemented - Arrays not implemented
@ -11,7 +12,7 @@ However, the code is partitioned to allow for easy extension so some of these mi
## Features of DRAWL ## Features of DRAWL
- 32 bit integers and 80 bir floating point with transcendental math operators - 32 bit integers and 80 bit floating point with transcendental math operators by way of the SANE library
- Tail recursion handles deep recursion. Check out [loop.lisp](https://github.com/dschmenk/PLASMA/blob/master/src/lisp/loop.lisp) - Tail recursion handles deep recursion. Check out [loop.lisp](https://github.com/dschmenk/PLASMA/blob/master/src/lisp/loop.lisp)
- Fully garbage collected behind the scenes - Fully garbage collected behind the scenes
- Optionally read LISP source file at startup - Optionally read LISP source file at startup

View File

@ -13,6 +13,7 @@ import sexpr
const NUM_TYPE = $30 const NUM_TYPE = $30
const NUM_INT = $31 const NUM_INT = $31
const NUM_FLOAT = $32 const NUM_FLOAT = $32
const ARRAY_TYPE = $40
const MARK_BIT = $80 const MARK_BIT = $80
const MARK_MASK = $7F const MARK_MASK = $7F
@ -29,8 +30,17 @@ import sexpr
res[t_elem] res[t_elem]
word natv word natv
word lambda word lambda
char[0] name word array
word apval
char name[0]
end end
struc t_numint
res[t_elem]
word intval[2]
end
var fmt_fpint
var fmt_fpfrac
predef gc#0 predef gc#0
predef print_expr(expr)#0 predef print_expr(expr)#0
@ -44,11 +54,12 @@ import sexpr
end end
import smath import smath
predef eval_int(expr)#1
end end
var prog, prog_expr, prog_return // Current PROG expressions var prog, prog_expr, prog_return // Current PROG expressions
var sym_cond // Symbol for cond() var sym_cond, sym_fpint, sym_fpfrac
var pred_true // Predicate for TRUE var pred_true
const FILEBUF_SIZE = 128 const FILEBUF_SIZE = 128
var readfn // Read input routine var readfn // Read input routine
@ -59,7 +70,7 @@ byte quit = FALSE // Quit interpreter flag
// (PROG ...) language extension // (PROG ...) language extension
// //
def natv_prog(expr) def natv_prog(symptr, expr)
var prog_enter, prog_car, cond_expr var prog_enter, prog_car, cond_expr
prog_expr = expr=>cdr prog_expr = expr=>cdr
@ -100,56 +111,68 @@ def natv_prog(expr)
return eval_expr(prog_return) return eval_expr(prog_return)
end end
def natv_return(expr) def natv_return(symptr, expr)
prog_return = expr=>car prog_return = expr=>car
return NULL // This value will be dropped in natv_prog return NULL // This value will be dropped in natv_prog
end end
def natv_go(expr) def natv_go(symptr, expr)
var label, go expr = expr=>car
symptr = prog // Scan prog list looking for matching SYM
expr = expr=>car while symptr
label = prog // Scan prog list looking for matching SYM if symptr=>car == expr
while label prog_expr = symptr=>cdr
if label=>car == expr
prog_expr = label=>cdr
return NULL return NULL
fin fin
label = label=>cdr symptr = symptr=>cdr
loop loop
puts("(GO ...) destination not found:"); print_expr(expr); putln puts("(GO ...) destination not found:"); print_expr(expr); putln
return NULL return NULL
end end
def natv_set(expr) def natv_set(symptr, expr)
var valptr symptr = eval_expr(expr=>cdr=>car)
set_assoc(eval_expr(expr=>car), symptr)
valptr = eval_expr(expr=>cdr=>car) return symptr
set_assoc(eval_expr(expr=>car), valptr)
return valptr
end end
def natv_setq(expr) def natv_setq(symptr, expr)
var valptr symptr = eval_expr(expr=>cdr=>car)
set_assoc(expr=>car, symptr)
valptr = eval_expr(expr=>cdr=>car) return symptr
set_assoc(expr=>car, valptr)
return valptr
end end
// //
// REPL native helper functions // REPL native helper functions
// //
def natv_bye(expr) def natv_fpint(symptr, expr)
quit = TRUE var fmt
return new_sym("GOODBYE!")
fmt_fpint = eval_int(expr)=>intval
fmt = new_int(fmt_fpint, 0)
set_assoc(sym_fpint, fmt)
return fmt
end end
def natv_memavail(expr) def natv_fpfrac(symptr, expr)
var fmt
fmt_fpfrac = eval_int(expr)=>intval
fmt = new_int(fmt_fpfrac, 0)
set_assoc(sym_fpfrac, fmt)
return fmt
end
def natv_memavail(symptr, expr)
return new_int(heapavail, 0) return new_int(heapavail, 0)
end end
def natv_bye(symptr, expr)
quit = TRUE
return new_sym("GOODBYE!")
end
// //
// Keyboard and file input routines // Keyboard and file input routines
// //
@ -220,7 +243,6 @@ end
def parse_cmdline#0 def parse_cmdline#0
var filename var filename
puts("DRAWL (LISP 1.5) symbolic processor\n")
readfn = @read_keybd readfn = @read_keybd
filename = argNext(argFirst) filename = argNext(argFirst)
if ^filename if ^filename
@ -239,15 +261,22 @@ end
// REPL // REPL
// //
pred_true = bool_pred(TRUE) // Capture value of TRUE puts("DRAWL (LISP 1.5) symbolic processor\n")
sym_cond = new_sym("COND") // This should actually match COND pred_true = bool_pred(TRUE) // Capture value of TRUE
sym_fpint = new_sym("FMTFPI")
sym_fpfrac = new_sym("FMTFPF")
sym_fpint=>natv = @natv_fpint
sym_fpfrac=>natv = @natv_fpfrac
new_assoc(sym_fpint, new_int(fmt_fpint, 0))
new_assoc(sym_fpfrac, new_int(fmt_fpfrac, 0))
sym_cond = new_sym("COND") // This should actually match COND
new_sym("PROG")=>natv = @natv_prog new_sym("PROG")=>natv = @natv_prog
new_sym("GO")=>natv = @natv_go new_sym("GO")=>natv = @natv_go
new_sym("RETURN")=>natv = @natv_return new_sym("RETURN")=>natv = @natv_return
new_sym("SET")=>natv = @natv_set new_sym("SET")=>natv = @natv_set
new_sym("SETQ")=>natv = @natv_setq new_sym("SETQ")=>natv = @natv_setq
new_sym("BYE")=>natv = @natv_bye new_sym("BYE")=>natv = @natv_bye
new_sym("MEM")=>natv = @natv_memavail
parse_cmdline parse_cmdline
while not quit while not quit
putln; print_expr(eval_expr(readfn())) putln; print_expr(eval_expr(readfn()))

View File

@ -12,6 +12,7 @@ const SYM_LEN = $0F
const NUM_TYPE = $30 const NUM_TYPE = $30
const NUM_INT = $31 const NUM_INT = $31
const NUM_FLOAT = $32 const NUM_FLOAT = $32
const ARRAY_TYPE = $40
const MARK_BIT = $80 const MARK_BIT = $80
const MARK_MASK = $7F const MARK_MASK = $7F
@ -28,22 +29,29 @@ struc t_sym
res[t_elem] res[t_elem]
word natv word natv
word lambda word lambda
char[0] name word array
word apval
char name[0]
end
struc t_array
res[t_elem]
word dimension[4]
word arraymem
end end
struc t_numint struc t_numint
res[t_elem] res[t_elem]
word[2] intval word intval[2]
end end
struc t_numfloat struc t_numfloat
res[t_elem] res[t_elem]
res[10] floatval res floatval[10]
end end
predef eval_expr(expr) predef eval_expr(expr)
var sym_quote, sym_lambda, sym_cond var sym_quote, sym_lambda, sym_cond, sym_set
res[t_elem] pred_true = 0, 0, BOOL_TRUE res[t_elem] pred_true = 0, 0, BOOL_TRUE
res[t_elem] pred_false = 0, 0, BOOL_FALSE res[t_elem] pred_nil = 0, 0, NIL
var cons_list = NULL var cons_list = NULL
var cons_free = NULL var cons_free = NULL
@ -54,6 +62,10 @@ var float_free = NULL
var sym_list = NULL var sym_list = NULL
var assoc_list = NULL // SYM->value association list var assoc_list = NULL // SYM->value association list
const fmt_fp = FPSTR_FIXED|FPSTR_STRIP|FPSTR_FLEX
export var fmt_fpint = 6
export var fmt_fpfrac = 4
// //
// Garbage collector // Garbage collector
// //
@ -92,6 +104,9 @@ def sweep_used#0
if symptr=>lambda if symptr=>lambda
sweep_expr(symptr=>lambda) sweep_expr(symptr=>lambda)
fin fin
if symptr=>apval
sweep_expr(symptr=>apval)
fin
symptr = symptr=>link symptr = symptr=>link
loop loop
end end
@ -224,6 +239,34 @@ export def new_float(extptr)#1
return floatptr return floatptr
end end
def new_array(dim0, dim1, dim2, dim3)
var size, aptr, memptr
size = dim0 * 2
if dim1; size = size * dim1; fin
if dim2; size = size * dim2; fin
if dim3; size = size * dim3; fin
if not size
puts("Zero sized array!\n")
return NULL
fin
memptr = heapalloc(size)
if not memptr
puts("Array too large!\n")
return NULL
fin
memset(memptr, NULL, size)
aptr = heapalloc(t_array)
aptr=>link = NULL
aptr->type = ARRAY_TYPE
aptr=>dimension[0] = dim0
aptr=>dimension[1] = dim1
aptr=>dimension[2] = dim2
aptr=>dimension[3] = dim3
aptr=>arraymem = memptr
return aptr
end
def match_sym(symstr) def match_sym(symstr)
var symptr var symptr
byte len, typelen, i byte len, typelen, i
@ -257,6 +300,8 @@ export def new_sym(symstr)#1
symptr->type = ^symstr | SYM_TYPE symptr->type = ^symstr | SYM_TYPE
symptr=>natv = NULL symptr=>natv = NULL
symptr=>lambda = NULL symptr=>lambda = NULL
symptr=>array = NULL
symptr=>apval = NULL
memcpy(symptr + name, symstr + 1, ^symstr) memcpy(symptr + name, symstr + 1, ^symstr)
return symptr return symptr
end end
@ -327,6 +372,7 @@ end
def print_atom(atom)#0 def print_atom(atom)#0
char prstr[32] char prstr[32]
var elemptr, d, i
if not atom if not atom
puts("NIL") puts("NIL")
@ -342,7 +388,7 @@ def print_atom(atom)#0
puti32(atom + intval) puti32(atom + intval)
break break
is NUM_FLOAT is NUM_FLOAT
puts(ext2str(atom + floatval, @prstr, 6, 4, FPSTR_FIXED|FPSTR_STRIP|FPSTR_FLEX)) puts(ext2str(atom + floatval, @prstr, fmt_fpint, fmt_fpfrac, fmt_fp))
break break
wend wend
break break
@ -351,6 +397,19 @@ def print_atom(atom)#0
memcpy(@prstr + 1, atom + name, prstr) memcpy(@prstr + 1, atom + name, prstr)
puts(@prstr) puts(@prstr)
break; break;
is ARRAY_TYPE
elemptr = atom=>arraymem
for d = 3 downto 0
if atom=>dimension[d]
puts("[ ")
for i = 1 to atom=>dimension[d]
print_atom(*elemptr); putc(' ')
elemptr = elemptr + 2
next
puts("]\n")
fin
next
break
otherwise otherwise
puts("Unkown atom type\n") puts("Unkown atom type\n")
wend wend
@ -615,7 +674,7 @@ export def eval_expr(expr)#1
expr_car = expr=>car expr_car = expr=>car
if expr_car->type & TYPE_MASK == SYM_TYPE if expr_car->type & TYPE_MASK == SYM_TYPE
if expr_car=>natv if expr_car=>natv
expr = expr_car=>natv(expr=>cdr) // Native function expr = expr_car=>natv(expr_car, expr=>cdr) // Native function
break break
elsif expr_car=>lambda // DEFINEd lambda S-expression elsif expr_car=>lambda // DEFINEd lambda S-expression
curl, expr = enter_lambda(curl, expr_car=>lambda, expr=>cdr) curl, expr = enter_lambda(curl, expr_car=>lambda, expr=>cdr)
@ -638,7 +697,15 @@ export def eval_expr(expr)#1
// //
// Atom // Atom
// //
if expr->type & TYPE_MASK == SYM_TYPE; expr = assoc(expr)=>cdr; fin if expr->type & TYPE_MASK == SYM_TYPE
if expr=>apval
expr = expr=>apval
elsif expr=>array
expr = expr=>array
else
expr = assoc(expr)=>cdr
fin
fin
break break
fin fin
loop loop
@ -651,77 +718,69 @@ end
// //
export def bool_pred(bool) export def bool_pred(bool)
return bool ?? @pred_true :: @pred_false return bool ?? @pred_true :: @pred_nil
end end
def natv_atom(expr) def natv_atom(symptr, expr)
var result symptr = eval_expr(expr=>car)
return bool_pred(!symptr or symptr->type <> CONS_TYPE))
result = eval_expr(expr=>car)
return bool_pred(!result or result->type <> CONS_TYPE))
end end
def natv_null(expr) def natv_null(symptr, expr)
var result symptr = eval_expr(expr=>car)
return bool_pred(!symptr or !symptr->type)
result = eval_expr(expr=>car)
return bool_pred(!result or !result->type)
end end
def natv_eq(expr) def natv_eq(symptr, expr)
return bool_pred(eval_expr(expr=>car) == eval_expr(expr=>cdr=>car)) return bool_pred(eval_expr(expr=>car) == eval_expr(expr=>cdr=>car))
end end
def natv_not(expr) def natv_not(symptr, expr)
return bool_pred(eval_expr(expr=>car) == @pred_false) return bool_pred(eval_expr(expr=>car) == @pred_nil)
end end
def natv_and(expr) def natv_and(symptr, expr)
while (expr and eval_expr(expr=>car) == @pred_true) while (expr and eval_expr(expr=>car) == @pred_true)
expr = expr=>cdr expr = expr=>cdr
loop loop
return bool_pred(!expr) return bool_pred(!expr)
end end
def natv_or(expr) def natv_or(symptr, expr)
while (expr and eval_expr(expr=>car) == @pred_false) while (expr and eval_expr(expr=>car) == @pred_nil)
expr = expr=>cdr expr = expr=>cdr
loop loop
return bool_pred(expr) return bool_pred(expr)
end end
def natv_cons(expr) def natv_cons(symptr, expr)
var consptr symptr = new_cons
symptr=>car = eval_expr(expr=>car)
consptr = new_cons symptr=>cdr = eval_expr(expr=>cdr=>car)
consptr=>car = eval_expr(expr=>car) return symptr
consptr=>cdr = eval_expr(expr=>cdr=>car)
return consptr
end end
def natv_car(expr) def natv_car(symptr, expr)
return eval_expr(expr=>car)=>car return eval_expr(expr=>car)=>car
end end
def natv_cdr(expr) def natv_cdr(symptr, expr)
return eval_expr(expr=>car)=>cdr return eval_expr(expr=>car)=>cdr
end end
def natv_quote(expr) def natv_quote(symptr, expr)
return expr=>car return expr=>car
end end
def natv_label(expr) def natv_label(symptr, expr)
var valptr symptr = expr=>cdr=>car
set_assoc(expr=>car, symptr)
valptr = expr=>cdr=>car return symptr
set_assoc(expr=>car, valptr)
return valptr
end end
def natv_define(expr) def natv_define(symptr, expr)
var symptr, funclist, funcptr var funclist, funcptr
funclist = NULL funclist = NULL
if expr if expr
@ -734,14 +793,98 @@ def natv_define(expr)
funcptr=>car = symptr funcptr=>car = symptr
expr = expr=>cdr expr = expr=>cdr
if expr if expr
funcptr=>cdr = new_cons funcptr=>cdr = new_cons
funcptr = funcptr=>cdr funcptr = funcptr=>cdr
fin fin
loop loop
return funclist return funclist
end end
def natv_print(expr) def eval_index(arrayptr, expr)
var idx[4], ii, index
idx[0] = 0
idx[1] = 0
idx[2] = 0
idx[3] = 0
ii = 0
while expr and ii < 4
index = eval_expr(expr=>car)
if index->type <> NUM_INT or isuge(index=>intval, arrayptr=>dimension[ii])
puts("Invalid array index: "); print_expr(expr=>car); putln
return NULL
fin
idx[ii] = index=>intval
expr = expr=>cdr
ii++
loop
index = 0
while ii
ii--
index = idx[ii] + index * arrayptr=>dimension[ii])
loop
return arrayptr=>arraymem + index * 2
end
def natv_index(symptr, expr)
var elemptr
if expr=>car == sym_set
elemptr = eval_index(symptr=>array, expr=>cdr=>car)
if elemptr; *elemptr = eval_expr(expr=>cdr=>cdr=>car); fin
else
elemptr = eval_index(symptr=>array, expr=>car)
fin
return elemptr ?? *elemptr :: NULL
end
def natv_array(symptr, expr)
var arraylist, aptr
var idx_expr, idx[4], ii, index
arraylist = NULL
if expr
arraylist = new_cons
aptr = arraylist
fin
while expr
symptr = expr=>car=>car
symptr=>natv = @natv_index
idx_expr = expr=>car=>cdr=>car
idx[0] = 0
idx[1] = 0
idx[2] = 0
idx[3] = 0
ii = 0
while idx_expr and ii < 4
index = eval_expr(idx_expr=>car)
if index->type <> NUM_INT
puts("Invalid array dimension\n"); print_expr(idx_expr=>car); putln
return NULL
fin
idx[ii] = index=>intval
idx_expr = idx_expr=>cdr
ii++
loop
symptr=>array = new_array(idx[0], idx[1], idx[2], idx[3])
aptr=>car = symptr
expr = expr=>cdr
if expr
aptr=>cdr = new_cons
aptr = aptr=>cdr
fin
loop
return arraylist
end
def natv_cset(symptr, expr)
symptr = eval_expr(expr=>cdr=>car)
expr=>car=>apval = symptr
// return symptr
return eval_expr(expr=>car)
end
def natv_print(symptr, expr)
expr = eval_expr(expr=>car) expr = eval_expr(expr=>car)
print_expr(expr) print_expr(expr)
putln putln
@ -752,24 +895,27 @@ end
// Install default functions // Install default functions
// //
new_assoc(new_sym("NIL"), NULL) new_sym("NIL")=>apval = @pred_nil)
new_assoc(new_sym("T"), @pred_true) new_sym("T")=>apval = @pred_true)
new_assoc(new_sym("F"), @pred_false) new_sym("F")=>apval = @pred_nil)
sym_lambda = new_sym("LAMBDA") sym_lambda = new_sym("LAMBDA")
sym_quote = new_sym("QUOTE") sym_quote = new_sym("QUOTE")
sym_cond = new_sym("COND") sym_cond = new_sym("COND")
sym_set = new_sym("SET")
sym_quote=>natv = @natv_quote sym_quote=>natv = @natv_quote
new_sym("CAR")=>natv = @natv_car new_sym("CAR")=>natv = @natv_car
new_sym("CDR")=>natv = @natv_cdr new_sym("CDR")=>natv = @natv_cdr
new_sym("CONS")=>natv = @natv_cons new_sym("CONS")=>natv = @natv_cons
new_sym("ATOM")=>natv = @natv_atom new_sym("ATOM")=>natv = @natv_atom
new_sym("EQ")=>natv = @natv_eq new_sym("EQ")=>natv = @natv_eq
new_sym("CSET")=>natv = @natv_cset
new_sym("NOT")=>natv = @natv_not new_sym("NOT")=>natv = @natv_not
new_sym("AND")=>natv = @natv_and new_sym("AND")=>natv = @natv_and
new_sym("OR")=>natv = @natv_or new_sym("OR")=>natv = @natv_or
new_sym("NULL")=>natv = @natv_null new_sym("NULL")=>natv = @natv_null
new_sym("LABEL")=>natv = @natv_label new_sym("LABEL")=>natv = @natv_label
new_sym("DEFINE")=>natv = @natv_define new_sym("DEFINE")=>natv = @natv_define
new_sym("ARRAY")=>natv = @natv_array
new_sym("PRINT")=>natv = @natv_print new_sym("PRINT")=>natv = @natv_print
return modkeep | modinitkeep return modkeep | modinitkeep
done done

View File

@ -13,6 +13,7 @@ import sexpr
const NUM_TYPE = $30 const NUM_TYPE = $30
const NUM_INT = $31 const NUM_INT = $31
const NUM_FLOAT = $32 const NUM_FLOAT = $32
const ARRAY_TYPE = $40
const MARK_BIT = $80 const MARK_BIT = $80
const MARK_MASK = $7F const MARK_MASK = $7F
@ -29,15 +30,17 @@ import sexpr
res[t_elem] res[t_elem]
word natv word natv
word lambda word lambda
char[0] name word array
word apval
char name[0]
end end
struc t_numint struc t_numint
res[t_elem] res[t_elem]
word[2] intval word intval[2]
end end
struc t_numfloat struc t_numfloat
res[t_elem] res[t_elem]
res[t_fpureg] floatval res floatval[10]
end end
predef new_sym(symstr)#1 predef new_sym(symstr)#1
@ -60,6 +63,20 @@ def eval_num(expr)
return @nan return @nan
end end
export def eval_int(expr)#1 // Always return an int
var result
var[2] int
result = eval_num(expr)
if result->type == NUM_FLOAT
fpu:pushExt(result + floatval)
fpu:pullInt(@int)
int[1] = int[0] < 0 ?? -1 :: 0
return new_int(int[0], int[1])
fin
return result
end
def push_int32(intptr)#0 def push_int32(intptr)#0
var[2] int var[2] int
byte isneg byte isneg
@ -97,7 +114,7 @@ def push_num(numptr)#0
fin fin
end end
def natv_add(expr) def natv_add(symptr, expr)
var num var num
var[2] intsum var[2] intsum
var[5] extsum var[5] extsum
@ -142,7 +159,7 @@ def natv_add(expr)
return new_int(intsum[0], intsum[1]) return new_int(intsum[0], intsum[1])
end end
def natv_sub(expr) def natv_sub(symptr, expr)
var num1, num2 var num1, num2
var[2] dif var[2] dif
var[5] ext var[5] ext
@ -162,7 +179,7 @@ def natv_sub(expr)
return new_float(@ext) return new_float(@ext)
end end
def natv_mul(expr) def natv_mul(symptr, expr)
var num1, num2 var num1, num2
var[2] mul var[2] mul
var[5] ext var[5] ext
@ -182,7 +199,7 @@ def natv_mul(expr)
return new_float(@ext) return new_float(@ext)
end end
def natv_div(expr) def natv_div(symptr, expr)
var num1, num2 var num1, num2
var[2] div var[2] div
var[5] ext var[5] ext
@ -202,7 +219,7 @@ def natv_div(expr)
return new_float(@ext) return new_float(@ext)
end end
def natv_rem(expr) def natv_rem(symptr, expr)
var num1, num2 var num1, num2
var[2] rem, div var[2] rem, div
var[5] ext var[5] ext
@ -221,7 +238,7 @@ def natv_rem(expr)
return new_float(@ext) return new_float(@ext)
end end
def natv_neg(expr) def natv_neg(symptr, expr)
var num var num
var[2] neg var[2] neg
var[5] ext var[5] ext
@ -239,7 +256,7 @@ def natv_neg(expr)
return new_float(@ext) return new_float(@ext)
end end
def natv_gt(expr) def natv_gt(symptr, expr)
var num1, num2 var num1, num2
var[5] ext var[5] ext
@ -256,7 +273,7 @@ def natv_gt(expr)
return bool_pred(ext[4] < 0) return bool_pred(ext[4] < 0)
end end
def natv_lt(expr) def natv_lt(symptr, expr)
var num1, num2 var num1, num2
var[5] ext var[5] ext