mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-01-21 17:31:31 +00:00
Add source with reference counting. Super slow. Ouch
This commit is contained in:
parent
d8ec9f9709
commit
713b6ea7fa
295
src/lisp/drawl.ref
Normal file
295
src/lisp/drawl.ref
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
include "inc/cmdsys.plh"
|
||||||
|
include "inc/args.plh"
|
||||||
|
include "inc/fileio.plh"
|
||||||
|
|
||||||
|
import sexpr
|
||||||
|
const TYPE_MASK = $70
|
||||||
|
const NIL = $00
|
||||||
|
const BOOL_FALSE = $00
|
||||||
|
const BOOL_TRUE = $01
|
||||||
|
const CONS_TYPE = $10
|
||||||
|
const SYM_TYPE = $20
|
||||||
|
const SYM_LEN = $0F
|
||||||
|
const NUM_TYPE = $30
|
||||||
|
const NUM_INT = $31
|
||||||
|
const NUM_FLOAT = $32
|
||||||
|
const ARRAY_TYPE = $40
|
||||||
|
|
||||||
|
struc t_elem
|
||||||
|
word link
|
||||||
|
byte type
|
||||||
|
byte refcnt
|
||||||
|
end
|
||||||
|
struc t_cons
|
||||||
|
res[t_elem]
|
||||||
|
word car
|
||||||
|
word cdr
|
||||||
|
end
|
||||||
|
struc t_sym
|
||||||
|
res[t_elem]
|
||||||
|
word natv
|
||||||
|
word lambda
|
||||||
|
word array
|
||||||
|
word apval
|
||||||
|
char name[0]
|
||||||
|
end
|
||||||
|
struc t_numint
|
||||||
|
res[t_elem]
|
||||||
|
word intval[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
var fmt_fpint
|
||||||
|
var fmt_fpfrac
|
||||||
|
|
||||||
|
predef ref(expr)#1
|
||||||
|
predef deref(expr)#1
|
||||||
|
predef print_expr(expr)#1
|
||||||
|
predef parse_expr(evalptr, level, refill)#2
|
||||||
|
predef eval_expr(expr)#1
|
||||||
|
predef bool_pred(bool)#1
|
||||||
|
predef new_int(intlo, inthi)#1
|
||||||
|
predef new_sym(symstr)#1
|
||||||
|
predef new_assoc(symptr, valptr)#0
|
||||||
|
predef set_assoc(symptr, valptr)#0
|
||||||
|
end
|
||||||
|
|
||||||
|
import smath
|
||||||
|
predef eval_int(expr)#1
|
||||||
|
end
|
||||||
|
|
||||||
|
var prog, prog_expr, prog_return // Current PROG expressions
|
||||||
|
var sym_cond, sym_fpint, sym_fpfrac
|
||||||
|
var pred_true
|
||||||
|
|
||||||
|
const FILEBUF_SIZE = 128
|
||||||
|
var readfn // Read input routine
|
||||||
|
var fileref, filebuf // File read vars
|
||||||
|
byte quit = FALSE // Quit interpreter flag
|
||||||
|
|
||||||
|
//
|
||||||
|
// (PROG ...) language extension
|
||||||
|
//
|
||||||
|
|
||||||
|
def natv_prog(symptr, expr)
|
||||||
|
var prog_enter, prog_car, cond_expr
|
||||||
|
|
||||||
|
prog_expr = expr=>cdr
|
||||||
|
prog = prog_expr // Update current PROG expression
|
||||||
|
prog_enter = prog // Save current prog
|
||||||
|
expr = expr=>car // Set up local variables
|
||||||
|
while expr
|
||||||
|
new_assoc(expr=>car, NULL)
|
||||||
|
expr = expr=>cdr
|
||||||
|
loop
|
||||||
|
prog_return = NULL
|
||||||
|
while prog_expr and not prog_return
|
||||||
|
prog_car = prog_expr=>car
|
||||||
|
prog_expr = prog_expr=>cdr // Assume continuation
|
||||||
|
if prog_car->type == CONS_TYPE
|
||||||
|
//
|
||||||
|
// List - check for (COND (...))
|
||||||
|
//
|
||||||
|
if prog_car=>car == sym_cond // Inline cond() evaluation
|
||||||
|
cond_expr = prog_car=>cdr
|
||||||
|
while cond_expr
|
||||||
|
if deref(eval_expr(cond_expr=>car=>car)) == pred_true
|
||||||
|
deref(eval_expr(cond_expr=>car=>cdr=>car)) // Drop result
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
cond_expr = cond_expr=>cdr
|
||||||
|
loop
|
||||||
|
else
|
||||||
|
deref(eval_expr(prog_car)) // Drop result
|
||||||
|
fin
|
||||||
|
//else
|
||||||
|
//
|
||||||
|
// Atom - skip, i.e. (GO ) destination
|
||||||
|
//
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
prog = prog_enter
|
||||||
|
return eval_expr(prog_return)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_return(symptr, expr)
|
||||||
|
prog_return = expr=>car
|
||||||
|
return NULL // This value will be dropped in natv_prog
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_go(symptr, expr)
|
||||||
|
expr = expr=>car
|
||||||
|
symptr = prog // Scan prog list looking for matching SYM
|
||||||
|
while symptr
|
||||||
|
if symptr=>car == expr
|
||||||
|
prog_expr = symptr=>cdr
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
symptr = symptr=>cdr
|
||||||
|
loop
|
||||||
|
puts("(GO ...) destination not found:"); print_expr(expr); putln
|
||||||
|
return NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_set(symptr, expr)
|
||||||
|
symptr = eval_expr(expr=>cdr=>car)
|
||||||
|
set_assoc(deref(eval_expr(expr=>car)), symptr)
|
||||||
|
return ref(symptr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_setq(symptr, expr)
|
||||||
|
symptr = eval_expr(expr=>cdr=>car)
|
||||||
|
set_assoc(expr=>car, symptr)
|
||||||
|
return ref(symptr)
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// REPL native helper functions
|
||||||
|
//
|
||||||
|
|
||||||
|
def natv_fpint(symptr, expr)
|
||||||
|
var fmt
|
||||||
|
|
||||||
|
fmt_fpint = eval_int(expr)=>intval
|
||||||
|
deref(expr)
|
||||||
|
fmt = new_int(fmt_fpint, 0)
|
||||||
|
set_assoc(sym_fpint, fmt)
|
||||||
|
return fmt
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_fpfrac(symptr, expr)
|
||||||
|
var fmt
|
||||||
|
|
||||||
|
fmt_fpfrac = eval_int(expr)=>intval
|
||||||
|
deref(expr)
|
||||||
|
fmt = new_int(fmt_fpfrac, 0)
|
||||||
|
set_assoc(sym_fpfrac, fmt)
|
||||||
|
return fmt
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_memavail(symptr, expr)
|
||||||
|
return new_int(heapavail, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_bye(symptr, expr)
|
||||||
|
quit = TRUE
|
||||||
|
return ref(new_sym("GOODBYE!")) // (QUOTE GOODBYE!)
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Keyboard and file input routines
|
||||||
|
//
|
||||||
|
|
||||||
|
def refill_keybd
|
||||||
|
var readline
|
||||||
|
|
||||||
|
repeat
|
||||||
|
readline = gets('>'|$80)
|
||||||
|
^(readline + ^readline + 1) = 0
|
||||||
|
until ^readline
|
||||||
|
return readline + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_keybd
|
||||||
|
var readline, expr
|
||||||
|
|
||||||
|
repeat
|
||||||
|
readline = gets('?'|$80)
|
||||||
|
^(readline + ^readline + 1) = 0
|
||||||
|
until ^readline
|
||||||
|
drop, expr = parse_expr(readline + 1, 0, @refill_keybd)
|
||||||
|
//print_expr(expr); putln // DEBUG - print parsed expression
|
||||||
|
return expr
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_fileline
|
||||||
|
var len
|
||||||
|
|
||||||
|
repeat
|
||||||
|
len = fileio:read(fileref, filebuf, FILEBUF_SIZE-1)
|
||||||
|
if len
|
||||||
|
if ^(filebuf + len - 1) == $0D
|
||||||
|
len-- // Remove trailing carriage return
|
||||||
|
fin
|
||||||
|
^(filebuf + len) = 0 // NULL terminate
|
||||||
|
else
|
||||||
|
fileio:close(fileref)
|
||||||
|
readfn = @read_keybd
|
||||||
|
return FALSE
|
||||||
|
fin
|
||||||
|
until len
|
||||||
|
return TRUE
|
||||||
|
end
|
||||||
|
|
||||||
|
def refill_file
|
||||||
|
if not read_fileline
|
||||||
|
puts("File input prematurely ended\n")
|
||||||
|
return refill_keybd
|
||||||
|
fin
|
||||||
|
return filebuf
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_file
|
||||||
|
var expr
|
||||||
|
|
||||||
|
if not read_fileline
|
||||||
|
return read_keybd
|
||||||
|
fin
|
||||||
|
drop, expr = parse_expr(filebuf, 0, @refill_file)
|
||||||
|
return expr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Handle command line options
|
||||||
|
//
|
||||||
|
|
||||||
|
def parse_cmdline#0
|
||||||
|
var filename
|
||||||
|
|
||||||
|
readfn = @read_keybd
|
||||||
|
filename = argNext(argFirst)
|
||||||
|
if ^filename
|
||||||
|
fileref = fileio:open(filename)
|
||||||
|
if fileref
|
||||||
|
fileio:newline(fileref, $7F, $0D)
|
||||||
|
readfn = @read_file
|
||||||
|
filebuf = heapalloc(FILEBUF_SIZE)
|
||||||
|
else
|
||||||
|
puts("Unable to open: "); puts(filename); putln
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// REPL
|
||||||
|
//
|
||||||
|
|
||||||
|
def rep#0
|
||||||
|
var expr, eval
|
||||||
|
|
||||||
|
expr = readfn()
|
||||||
|
eval = eval_expr(expr)
|
||||||
|
deref(print_expr(eval)); putln
|
||||||
|
if eval and eval <> expr; deref(expr); fin
|
||||||
|
end
|
||||||
|
|
||||||
|
puts("DRAWL (LISP 1.5) symbolic processor\n")
|
||||||
|
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("GO")=>natv = @natv_go
|
||||||
|
new_sym("RETURN")=>natv = @natv_return
|
||||||
|
new_sym("SET")=>natv = @natv_set
|
||||||
|
new_sym("SETQ")=>natv = @natv_setq
|
||||||
|
new_sym("MEM")=>natv = @natv_memavail
|
||||||
|
new_sym("BYE")=>natv = @natv_bye
|
||||||
|
|
||||||
|
parse_cmdline
|
||||||
|
while not quit; rep; loop
|
||||||
|
putln
|
||||||
|
done
|
979
src/lisp/s-expr.ref
Normal file
979
src/lisp/s-expr.ref
Normal file
@ -0,0 +1,979 @@
|
|||||||
|
include "inc/cmdsys.plh"
|
||||||
|
include "inc/int32.plh"
|
||||||
|
include "inc/fpstr.plh"
|
||||||
|
|
||||||
|
const TYPE_MASK = $70
|
||||||
|
const NIL = $00
|
||||||
|
const BOOL_FALSE = $00
|
||||||
|
const BOOL_TRUE = $01
|
||||||
|
const CONS_TYPE = $10
|
||||||
|
const SYM_TYPE = $20
|
||||||
|
const SYM_LEN = $0F
|
||||||
|
const NUM_TYPE = $30
|
||||||
|
const NUM_INT = $31
|
||||||
|
const NUM_FLOAT = $32
|
||||||
|
const ARRAY_TYPE = $40
|
||||||
|
const NULL_HACK = 1 // Hack so we can set elements to NULL
|
||||||
|
|
||||||
|
struc t_elem
|
||||||
|
word link
|
||||||
|
byte type
|
||||||
|
byte refcnt
|
||||||
|
end
|
||||||
|
struc t_cons
|
||||||
|
res[t_elem]
|
||||||
|
word car
|
||||||
|
word cdr
|
||||||
|
end
|
||||||
|
struc t_sym
|
||||||
|
res[t_elem]
|
||||||
|
word natv
|
||||||
|
word lambda
|
||||||
|
word array
|
||||||
|
word apval
|
||||||
|
char name[0]
|
||||||
|
end
|
||||||
|
struc t_array
|
||||||
|
res[t_elem]
|
||||||
|
word dimension[4]
|
||||||
|
word offset[4]
|
||||||
|
word arraymem
|
||||||
|
end
|
||||||
|
struc t_numint
|
||||||
|
res[t_elem]
|
||||||
|
word intval[2]
|
||||||
|
end
|
||||||
|
struc t_numfloat
|
||||||
|
res[t_elem]
|
||||||
|
res floatval[10]
|
||||||
|
end
|
||||||
|
|
||||||
|
predef eval_expr(expr)#1
|
||||||
|
predef print_expr(expr)#1
|
||||||
|
|
||||||
|
var sym_nil, sym_quote, sym_lambda, sym_cond, sym_set
|
||||||
|
res[t_elem] pred_true = 0, 0, BOOL_TRUE, 1
|
||||||
|
|
||||||
|
var sym_list = NULL
|
||||||
|
var cons_free = NULL
|
||||||
|
var int_free = NULL
|
||||||
|
var float_free = NULL
|
||||||
|
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
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reference manager
|
||||||
|
//
|
||||||
|
|
||||||
|
export def ref(expr)#1
|
||||||
|
var refexpr
|
||||||
|
|
||||||
|
puts("REF:"); print_expr(expr); putln
|
||||||
|
refexpr = expr
|
||||||
|
while expr
|
||||||
|
if expr->refcnt == 255; puts("Ref overflow:"); print_expr(expr); putln; return refexpr; fin
|
||||||
|
expr->refcnt++
|
||||||
|
if expr->type == CONS_TYPE
|
||||||
|
ref(expr=>car)
|
||||||
|
expr = expr=>cdr
|
||||||
|
else
|
||||||
|
return refexpr
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
return refexpr
|
||||||
|
end
|
||||||
|
|
||||||
|
export def deref(expr)#1
|
||||||
|
var refexpr, expr_next
|
||||||
|
|
||||||
|
puts("DEREF:"); print_expr(expr); putln
|
||||||
|
refexpr = expr
|
||||||
|
while expr
|
||||||
|
expr_next = NULL
|
||||||
|
if expr->refcnt == 0; puts("Ref underflow:"); print_expr(expr); putln; return NULL; fin
|
||||||
|
if expr->type == CONS_TYPE
|
||||||
|
deref(expr=>car)
|
||||||
|
expr_next = expr=>cdr
|
||||||
|
fin
|
||||||
|
expr->refcnt--
|
||||||
|
if expr->refcnt == 0
|
||||||
|
when expr->type
|
||||||
|
is CONS_TYPE
|
||||||
|
//puts("Free CONS\n")
|
||||||
|
expr=>link = cons_free
|
||||||
|
cons_free = expr
|
||||||
|
break
|
||||||
|
is NUM_INT
|
||||||
|
//puts("Free INT:"); print_expr(expr); putln
|
||||||
|
expr=>link = int_free
|
||||||
|
int_free = expr
|
||||||
|
break
|
||||||
|
is NUM_FLOAT
|
||||||
|
//puts("Free FLOAT:"); print_expr(expr); putln
|
||||||
|
expr=>link = float_free
|
||||||
|
float_free = expr
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
// Do nothing
|
||||||
|
puts("0 ref count:"); print_expr(expr); putln
|
||||||
|
wend
|
||||||
|
fin
|
||||||
|
expr = expr_next
|
||||||
|
loop
|
||||||
|
return refexpr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Build ATOMS
|
||||||
|
//
|
||||||
|
|
||||||
|
export def new_cons#1
|
||||||
|
var consptr
|
||||||
|
|
||||||
|
if cons_free
|
||||||
|
consptr = cons_free
|
||||||
|
cons_free = cons_free=>link
|
||||||
|
else
|
||||||
|
consptr = heapalloc(t_cons)
|
||||||
|
fin
|
||||||
|
consptr->type = CONS_TYPE
|
||||||
|
consptr->refcnt = 1
|
||||||
|
consptr=>car = NULL
|
||||||
|
consptr=>cdr = NULL
|
||||||
|
return consptr
|
||||||
|
end
|
||||||
|
|
||||||
|
export def new_int(intlo, inthi)#1
|
||||||
|
var intptr
|
||||||
|
|
||||||
|
if int_free
|
||||||
|
intptr = int_free
|
||||||
|
int_free = int_free=>link
|
||||||
|
else
|
||||||
|
intptr = heapalloc(t_numint)
|
||||||
|
fin
|
||||||
|
intptr->type = NUM_INT
|
||||||
|
intptr->refcnt = 1
|
||||||
|
intptr=>intval[0] = intlo
|
||||||
|
intptr=>intval[1] = inthi
|
||||||
|
return intptr
|
||||||
|
end
|
||||||
|
|
||||||
|
export def new_float(extptr)#1
|
||||||
|
var floatptr
|
||||||
|
|
||||||
|
if float_free
|
||||||
|
floatptr = float_free
|
||||||
|
float_free = float_free=>link
|
||||||
|
else
|
||||||
|
floatptr = heapalloc(t_numfloat)
|
||||||
|
fin
|
||||||
|
floatptr->type = NUM_FLOAT
|
||||||
|
floatptr->refcnt = 1
|
||||||
|
memcpy(floatptr + floatval, extptr, 10)
|
||||||
|
return floatptr
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_array(dim0, dim1, dim2, dim3)
|
||||||
|
var ofst0, ofst1, ofst2, ofst3
|
||||||
|
var size, aptr, memptr
|
||||||
|
|
||||||
|
if dim3
|
||||||
|
ofst3 = 2
|
||||||
|
ofst2 = dim3 * 2
|
||||||
|
ofst1 = ofst2 * dim2
|
||||||
|
ofst0 = ofst1 * dim1
|
||||||
|
elsif dim2
|
||||||
|
ofst2 = 2
|
||||||
|
ofst1 = dim2 * 2
|
||||||
|
ofst0 = ofst1 * dim1
|
||||||
|
elsif dim1
|
||||||
|
ofst1 = 2
|
||||||
|
ofst0 = dim1 * 2
|
||||||
|
else
|
||||||
|
ofst0 = 2
|
||||||
|
fin
|
||||||
|
size = dim0 * ofst0
|
||||||
|
memptr = heapalloc(size)
|
||||||
|
if not memptr
|
||||||
|
puts("Array too large!\n")
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
memset(memptr, NULL, size)
|
||||||
|
aptr = heapalloc(t_array)
|
||||||
|
aptr->type = ARRAY_TYPE
|
||||||
|
aptr->refcnt = 1
|
||||||
|
aptr=>dimension[0] = dim0
|
||||||
|
aptr=>dimension[1] = dim1
|
||||||
|
aptr=>dimension[2] = dim2
|
||||||
|
aptr=>dimension[3] = dim3
|
||||||
|
aptr=>offset[0] = ofst0
|
||||||
|
aptr=>offset[1] = ofst1
|
||||||
|
aptr=>offset[2] = ofst2
|
||||||
|
aptr=>offset[3] = ofst3
|
||||||
|
aptr=>arraymem = memptr
|
||||||
|
return aptr
|
||||||
|
end
|
||||||
|
|
||||||
|
def match_sym(symstr)
|
||||||
|
var symptr
|
||||||
|
byte len, typelen, i
|
||||||
|
|
||||||
|
len = ^symstr
|
||||||
|
typelen = SYM_TYPE | len
|
||||||
|
len--; symstr++
|
||||||
|
symptr = sym_list
|
||||||
|
while symptr
|
||||||
|
if symptr->type == typelen
|
||||||
|
for i = 0 to len
|
||||||
|
if symptr->name[i] <> symstr->[i]; break; fin
|
||||||
|
next
|
||||||
|
if i > len
|
||||||
|
symptr->refcnt++
|
||||||
|
return symptr
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
symptr = symptr=>link
|
||||||
|
loop
|
||||||
|
return NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
export def new_sym(symstr)#1
|
||||||
|
var symptr
|
||||||
|
|
||||||
|
symptr = match_sym(symstr)
|
||||||
|
if symptr; return symptr; fin // Return already existing symbol
|
||||||
|
symptr = heapalloc(t_sym + ^symstr)
|
||||||
|
symptr=>link = sym_list
|
||||||
|
sym_list = symptr
|
||||||
|
symptr->type = ^symstr | SYM_TYPE
|
||||||
|
symptr->refcnt = 1
|
||||||
|
symptr=>natv = NULL
|
||||||
|
symptr=>lambda = NULL
|
||||||
|
symptr=>array = NULL
|
||||||
|
symptr=>apval = NULL
|
||||||
|
memcpy(symptr + name, symstr + 1, ^symstr)
|
||||||
|
return symptr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Build/set association between symbols and values
|
||||||
|
//
|
||||||
|
|
||||||
|
def assoc_pair(symptr)
|
||||||
|
var pair
|
||||||
|
|
||||||
|
if symptr->type & TYPE_MASK == SYM_TYPE
|
||||||
|
//
|
||||||
|
// Search association list for symbol
|
||||||
|
//
|
||||||
|
pair = assoc_list
|
||||||
|
while pair
|
||||||
|
if (pair=>car=>car == symptr)
|
||||||
|
return pair=>car
|
||||||
|
fin
|
||||||
|
pair = pair=>cdr
|
||||||
|
loop
|
||||||
|
fin
|
||||||
|
return NULL // SYM not associated
|
||||||
|
end
|
||||||
|
|
||||||
|
def assoc(symptr)
|
||||||
|
var pair
|
||||||
|
|
||||||
|
pair = assoc_pair(symptr)
|
||||||
|
return pair ?? pair=>cdr :: NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
export def new_assoc(symptr, valptr)#0
|
||||||
|
var pair, addlist
|
||||||
|
|
||||||
|
if symptr and (symptr->type & TYPE_MASK <> SYM_TYPE)
|
||||||
|
puts("Not a SYM in new_assoc\n")
|
||||||
|
return
|
||||||
|
fin
|
||||||
|
pair = new_cons
|
||||||
|
pair=>car = ref(symptr)
|
||||||
|
pair=>cdr = ref(valptr)
|
||||||
|
if assoc_list // Add to end of assoc_list
|
||||||
|
addlist = assoc_list
|
||||||
|
while addlist=>cdr
|
||||||
|
addlist = addlist=>cdr
|
||||||
|
loop
|
||||||
|
addlist=>cdr = new_cons
|
||||||
|
addlist = addlist=>cdr
|
||||||
|
else // New list
|
||||||
|
assoc_list = new_cons
|
||||||
|
addlist = assoc_list
|
||||||
|
fin
|
||||||
|
addlist=>car = pair
|
||||||
|
end
|
||||||
|
|
||||||
|
export def set_assoc(symptr, valptr)#0
|
||||||
|
var pair
|
||||||
|
|
||||||
|
//
|
||||||
|
// Search association list for symbol
|
||||||
|
//
|
||||||
|
pair = assoc_pair(symptr)
|
||||||
|
if pair
|
||||||
|
ref(valptr)
|
||||||
|
deref(pair=>cdr)
|
||||||
|
pair=>cdr = valptr // update association
|
||||||
|
else
|
||||||
|
new_assoc(symptr, valptr) // add association if unknown
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print textual representation of S-expression
|
||||||
|
//
|
||||||
|
|
||||||
|
def print_atom(atom)#0
|
||||||
|
char prstr[32]
|
||||||
|
var elemptr, i, j, k, l
|
||||||
|
|
||||||
|
if not atom
|
||||||
|
puts("NIL")
|
||||||
|
else
|
||||||
|
when atom->type & TYPE_MASK
|
||||||
|
is NIL
|
||||||
|
putc(atom->type ?? 'T' :: 'F')
|
||||||
|
break
|
||||||
|
is NUM_TYPE
|
||||||
|
when atom->type
|
||||||
|
is NUM_INT
|
||||||
|
if atom=>intval[1] >= 0; putc(' '); fin // Add space for pos
|
||||||
|
puti32(atom + intval)
|
||||||
|
break
|
||||||
|
is NUM_FLOAT
|
||||||
|
puts(ext2str(atom + floatval, @prstr, fmt_fpint, fmt_fpfrac, fmt_fp))
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
break
|
||||||
|
is SYM_TYPE
|
||||||
|
prstr = atom->type & SYM_LEN
|
||||||
|
memcpy(@prstr + 1, atom + name, prstr)
|
||||||
|
puts(@prstr)
|
||||||
|
break;
|
||||||
|
is ARRAY_TYPE
|
||||||
|
elemptr = atom=>arraymem
|
||||||
|
puts("[ ")
|
||||||
|
for i = 1 to atom=>dimension[0]
|
||||||
|
if atom=>dimension[1]
|
||||||
|
puts("\n[ ")
|
||||||
|
for j = 1 to atom=>dimension[1]
|
||||||
|
if atom=>dimension[2]
|
||||||
|
puts("\n[ ")
|
||||||
|
for k = 1 to atom=>dimension[2]
|
||||||
|
if atom=>dimension[3]
|
||||||
|
puts("\n[ ")
|
||||||
|
for l = 1 to atom=>dimension[3]
|
||||||
|
print_atom(*elemptr); putc(' ')
|
||||||
|
elemptr = elemptr + 2
|
||||||
|
next
|
||||||
|
puts("]")
|
||||||
|
else
|
||||||
|
print_atom(*elemptr); putc(' ')
|
||||||
|
elemptr = elemptr + 2
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
puts("]")
|
||||||
|
else
|
||||||
|
print_atom(*elemptr); putc(' ')
|
||||||
|
elemptr = elemptr + 2
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
puts("]")
|
||||||
|
else
|
||||||
|
print_atom(*elemptr); putc(' ')
|
||||||
|
elemptr = elemptr + 2
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
puts("]\n")
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
puts("Unkown atom type\n")
|
||||||
|
wend
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
export def print_expr(expr)#1
|
||||||
|
var prexpr
|
||||||
|
|
||||||
|
prexpr = expr
|
||||||
|
if not expr
|
||||||
|
puts("NIL")
|
||||||
|
else
|
||||||
|
if expr->type == CONS_TYPE
|
||||||
|
putc('(')
|
||||||
|
while expr and expr->type == CONS_TYPE
|
||||||
|
print_expr(expr=>car)
|
||||||
|
expr = expr=>cdr
|
||||||
|
if expr
|
||||||
|
if expr->type <> CONS_TYPE
|
||||||
|
putc('.')
|
||||||
|
print_atom(expr)
|
||||||
|
expr = NULL
|
||||||
|
else
|
||||||
|
putc(' ')
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
putc(')')
|
||||||
|
else
|
||||||
|
print_atom(expr)
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
return prexpr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse textual representation of S-expression
|
||||||
|
//
|
||||||
|
|
||||||
|
def is_num(cptr)
|
||||||
|
if ^cptr == '-' or ^cptr == '+'; cptr++; fin
|
||||||
|
return ^cptr >= '0' and ^cptr <= '9'
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_alphasym(c)
|
||||||
|
return (c >= '*' and c <= 'z') and (c <> '.') and (c <> ',')
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_num(evalptr)#2 // return evalptr, intptr
|
||||||
|
var startptr
|
||||||
|
var int[2], ext[5]
|
||||||
|
byte sign
|
||||||
|
|
||||||
|
sign = FALSE
|
||||||
|
if ^evalptr == '-'
|
||||||
|
sign = TRUE
|
||||||
|
evalptr++
|
||||||
|
elsif ^evalptr == '+'
|
||||||
|
evalptr++
|
||||||
|
fin
|
||||||
|
startptr = evalptr
|
||||||
|
while ^evalptr >= '0' and ^evalptr <= '9'
|
||||||
|
evalptr++
|
||||||
|
loop
|
||||||
|
if (evalptr - startptr > 10) or ^evalptr == '.' or toupper(^evalptr) == 'E'
|
||||||
|
if ^evalptr == '.'
|
||||||
|
evalptr++
|
||||||
|
while ^evalptr >= '0' and ^evalptr <= '9'
|
||||||
|
evalptr++
|
||||||
|
loop
|
||||||
|
fin
|
||||||
|
if toupper(^evalptr) == 'E'
|
||||||
|
evalptr++
|
||||||
|
if ^evalptr == '-' or ^evalptr == '+'; evalptr++; fin
|
||||||
|
while ^evalptr >= '0' and ^evalptr <= '9'
|
||||||
|
evalptr++
|
||||||
|
loop
|
||||||
|
fin
|
||||||
|
if sign; startptr--; fin
|
||||||
|
^(startptr - 1) = evalptr - startptr
|
||||||
|
str2ext(startptr - 1, @ext)
|
||||||
|
return evalptr, new_float(@ext)
|
||||||
|
fin
|
||||||
|
zero32
|
||||||
|
while startptr <> evalptr
|
||||||
|
muli16(10); addi16(^startptr - '0')
|
||||||
|
startptr++
|
||||||
|
loop
|
||||||
|
if sign; neg32; fin
|
||||||
|
store32(@int)
|
||||||
|
return evalptr, new_int(int[0], int[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_sym(evalptr)#2 // return evalptr, symptr
|
||||||
|
var symstr
|
||||||
|
|
||||||
|
symstr = evalptr - 1
|
||||||
|
while is_alphasym(^evalptr)
|
||||||
|
^evalptr = toupper(^evalptr)
|
||||||
|
evalptr++
|
||||||
|
loop
|
||||||
|
^symstr = evalptr - symstr - 1
|
||||||
|
if ^symstr > 31; ^symstr = 31; fin
|
||||||
|
return evalptr, new_sym(symstr)
|
||||||
|
end
|
||||||
|
|
||||||
|
export def parse_expr(evalptr, level, refill)#2 // return evalptr, exprptr
|
||||||
|
var exprptr, consptr, elemptr, quotecons
|
||||||
|
|
||||||
|
exprptr = NULL
|
||||||
|
consptr = NULL
|
||||||
|
while TRUE
|
||||||
|
//
|
||||||
|
// Parse textual S-expression
|
||||||
|
//
|
||||||
|
elemptr = NULL
|
||||||
|
when ^evalptr
|
||||||
|
is 0
|
||||||
|
if level
|
||||||
|
evalptr = refill() // Refill input buffer
|
||||||
|
else
|
||||||
|
return evalptr, exprptr
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is ' '
|
||||||
|
is ','
|
||||||
|
evalptr++
|
||||||
|
break
|
||||||
|
is ')'
|
||||||
|
if not exprptr
|
||||||
|
exprptr = ref(sym_nil)
|
||||||
|
fin
|
||||||
|
return evalptr + 1, exprptr
|
||||||
|
is '('
|
||||||
|
evalptr++
|
||||||
|
if level == 0
|
||||||
|
level++
|
||||||
|
else
|
||||||
|
evalptr, elemptr = parse_expr(evalptr, 1, refill)
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is '\''
|
||||||
|
evalptr++
|
||||||
|
evalptr, elemptr = parse_expr(evalptr, 0, refill)
|
||||||
|
quotecons = new_cons
|
||||||
|
quotecons=>car = ref(sym_quote)
|
||||||
|
quotecons=>cdr = new_cons
|
||||||
|
quotecons=>cdr=>car = elemptr
|
||||||
|
elemptr = quotecons
|
||||||
|
if level == 0
|
||||||
|
return evalptr, elemptr
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is '.'
|
||||||
|
evalptr++
|
||||||
|
evalptr, elemptr = parse_expr(evalptr, 0, refill)
|
||||||
|
//
|
||||||
|
// Add expression to CDR
|
||||||
|
//
|
||||||
|
if not (consptr and consptr=>car)
|
||||||
|
puts("Invalid . operator\n")
|
||||||
|
return evalptr, exprptr
|
||||||
|
fin
|
||||||
|
consptr=>cdr = elemptr
|
||||||
|
elemptr = NULL
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
if is_num(evalptr)
|
||||||
|
evalptr, elemptr = parse_num(evalptr)
|
||||||
|
elsif is_alphasym(^evalptr)
|
||||||
|
evalptr, elemptr = parse_sym(evalptr)
|
||||||
|
else
|
||||||
|
putc('\\')
|
||||||
|
putc(^evalptr)
|
||||||
|
evalptr++
|
||||||
|
fin
|
||||||
|
if level == 0
|
||||||
|
return evalptr, elemptr
|
||||||
|
fin
|
||||||
|
wend
|
||||||
|
if elemptr
|
||||||
|
//
|
||||||
|
// Add element to S-expression
|
||||||
|
//
|
||||||
|
if not consptr
|
||||||
|
consptr = new_cons
|
||||||
|
exprptr = consptr
|
||||||
|
else
|
||||||
|
if consptr=>cdr
|
||||||
|
puts("Improperly formed .\n")
|
||||||
|
return evalptr, exprptr
|
||||||
|
fin
|
||||||
|
consptr=>cdr = new_cons
|
||||||
|
consptr = consptr=>cdr
|
||||||
|
fin
|
||||||
|
//
|
||||||
|
// Add element to CAR
|
||||||
|
//
|
||||||
|
consptr=>car = elemptr
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
return evalptr, exprptr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Evaluate expression
|
||||||
|
//
|
||||||
|
|
||||||
|
def enter_lambda(curl, expr, params)#2 // curl, expr
|
||||||
|
var args, arglist, pairlist, pair
|
||||||
|
|
||||||
|
if !expr or expr=>car <> sym_lambda
|
||||||
|
puts("Invalid LAMBDA expression: ")
|
||||||
|
print_expr(expr)
|
||||||
|
return NULL, NULL
|
||||||
|
fin
|
||||||
|
args = expr=>cdr=>car
|
||||||
|
if curl == expr
|
||||||
|
//
|
||||||
|
// Update current associations during tail recursion
|
||||||
|
//
|
||||||
|
while args
|
||||||
|
pair = assoc_pair(args=>car)
|
||||||
|
arglist = pair=>cdr
|
||||||
|
pair=>cdr = eval_expr(params=>car)
|
||||||
|
deref(arglist)
|
||||||
|
args = args=>cdr
|
||||||
|
params = params=>cdr
|
||||||
|
loop
|
||||||
|
else
|
||||||
|
//
|
||||||
|
// Build arg list before prepending to assoc_list
|
||||||
|
//
|
||||||
|
arglist = NULL
|
||||||
|
while args
|
||||||
|
if arglist
|
||||||
|
pairlist=>cdr = new_cons
|
||||||
|
pairlist = pairlist=>cdr
|
||||||
|
else
|
||||||
|
arglist = new_cons
|
||||||
|
pairlist = arglist
|
||||||
|
fin
|
||||||
|
pair = new_cons
|
||||||
|
pair=>car = ref(args=>car)
|
||||||
|
pair=>cdr = eval_expr(params=>car)
|
||||||
|
pairlist=>car = pair
|
||||||
|
args = args=>cdr
|
||||||
|
params = params=>cdr
|
||||||
|
loop
|
||||||
|
if arglist
|
||||||
|
pairlist=>cdr = assoc_list
|
||||||
|
assoc_list = arglist
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
return expr, expr=>cdr=>cdr=>car
|
||||||
|
end
|
||||||
|
|
||||||
|
def exit_lambda(alist)#0
|
||||||
|
var args
|
||||||
|
|
||||||
|
if alist <> assoc_list
|
||||||
|
args = assoc_list
|
||||||
|
while args=>cdr <> alist
|
||||||
|
args = args=>cdr
|
||||||
|
loop
|
||||||
|
args=>cdr = NULL
|
||||||
|
deref(assoc_list)
|
||||||
|
assoc_list = alist
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
export def eval_expr(expr)#1
|
||||||
|
var alist_enter, curl, expr_car
|
||||||
|
|
||||||
|
curl = NULL // Current lambda
|
||||||
|
alist_enter = assoc_list
|
||||||
|
while expr
|
||||||
|
if expr->type == CONS_TYPE
|
||||||
|
//
|
||||||
|
// List - first element better be a function
|
||||||
|
//
|
||||||
|
expr_car = expr=>car
|
||||||
|
if expr_car->type & TYPE_MASK == SYM_TYPE
|
||||||
|
if expr_car=>natv
|
||||||
|
expr = expr_car=>natv(expr_car, expr=>cdr) // Native function
|
||||||
|
break
|
||||||
|
elsif expr_car=>lambda // DEFINEd lambda S-expression
|
||||||
|
curl, expr = enter_lambda(curl, expr_car=>lambda, expr=>cdr)
|
||||||
|
elsif expr_car == sym_cond // Inline cond() evaluation
|
||||||
|
expr = expr=>cdr
|
||||||
|
while expr
|
||||||
|
if deref(eval_expr(expr=>car=>car)) == @pred_true
|
||||||
|
expr = expr=>car=>cdr=>car
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
expr = expr=>cdr
|
||||||
|
loop
|
||||||
|
else // Symbol associated with lambda
|
||||||
|
curl, expr = enter_lambda(curl, assoc(expr_car), expr=>cdr)
|
||||||
|
fin
|
||||||
|
elsif expr_car->type == CONS_TYPE and expr_car=>car == sym_lambda
|
||||||
|
curl, expr = enter_lambda(NULL, expr_car, expr=>cdr) // Inline lambda
|
||||||
|
fin
|
||||||
|
else
|
||||||
|
//
|
||||||
|
// Atom
|
||||||
|
//
|
||||||
|
if expr->type & TYPE_MASK == SYM_TYPE
|
||||||
|
if expr=>apval
|
||||||
|
expr = expr=>apval ^ NULL_HACK
|
||||||
|
elsif expr=>array
|
||||||
|
expr = expr=>array
|
||||||
|
else
|
||||||
|
expr = assoc(expr)
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
ref(expr)
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
if curl; exit_lambda(alist_enter); fin
|
||||||
|
return expr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Base native functions
|
||||||
|
//
|
||||||
|
|
||||||
|
export def bool_pred(bool)
|
||||||
|
return bool ?? ref(@pred_true) :: NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_atom(symptr, expr)
|
||||||
|
symptr = deref(eval_expr(expr=>car))
|
||||||
|
return bool_pred(!symptr or symptr->type <> CONS_TYPE))
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_null(symptr, expr)
|
||||||
|
return bool_pred(!deref(eval_expr(expr=>car)))
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_eq(symptr, expr)
|
||||||
|
byte iseq, i
|
||||||
|
|
||||||
|
iseq = FALSE
|
||||||
|
symptr = eval_expr(expr=>car)
|
||||||
|
expr = eval_expr(expr=>cdr=>car)
|
||||||
|
if symptr == expr
|
||||||
|
iseq = TRUE
|
||||||
|
elsif symptr->type == NUM_INT and expr->type == NUM_INT
|
||||||
|
iseq = symptr=>intval[0] == expr=>intval[0]
|
||||||
|
if iseq
|
||||||
|
iseq = symptr=>intval[1] == expr=>intval[1]
|
||||||
|
fin
|
||||||
|
elsif symptr->type == NUM_FLOAT and expr->type == NUM_FLOAT
|
||||||
|
iseq = TRUE
|
||||||
|
for i = 0 to 9
|
||||||
|
if symptr->floatval[i] <> expr->floatval[i]
|
||||||
|
iseq = FALSE
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
fin
|
||||||
|
deref(symptr)
|
||||||
|
deref(expr)
|
||||||
|
return bool_pred(iseq)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_and(symptr, expr)
|
||||||
|
while expr
|
||||||
|
symptr = eval_expr(expr=>car)
|
||||||
|
if !symptr; return NULL; fin
|
||||||
|
deref(symptr)
|
||||||
|
expr = expr=>cdr
|
||||||
|
loop
|
||||||
|
return ref(@pred_true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_or(symptr, expr)
|
||||||
|
while expr
|
||||||
|
symptr = deref(eval_expr(expr=>car))
|
||||||
|
if symptr; return ref(@pred_true); fin
|
||||||
|
expr = expr=>cdr
|
||||||
|
loop
|
||||||
|
return NULL
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_cons(symptr, expr)
|
||||||
|
symptr = ref(new_cons)
|
||||||
|
symptr=>car = eval_expr(expr=>car)
|
||||||
|
symptr=>cdr = eval_expr(expr=>cdr=>car)
|
||||||
|
return symptr
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_car(symptr, expr)
|
||||||
|
return eval_expr(expr=>car)=>car
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_cdr(symptr, expr)
|
||||||
|
return eval_expr(expr=>car)=>cdr
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_quote(symptr, expr)
|
||||||
|
return ref(expr=>car)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_label(symptr, expr)
|
||||||
|
symptr = expr=>cdr=>car
|
||||||
|
set_assoc(expr=>car, symptr)
|
||||||
|
return ref(symptr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_define(symptr, expr)
|
||||||
|
|
||||||
|
var funclist, funcptr
|
||||||
|
|
||||||
|
funclist = NULL
|
||||||
|
if expr
|
||||||
|
funclist = new_cons
|
||||||
|
funcptr = funclist
|
||||||
|
fin
|
||||||
|
while expr
|
||||||
|
symptr = expr=>car=>car
|
||||||
|
deref(symptr=>lambda)
|
||||||
|
symptr=>lambda = expr=>car=>cdr=>car
|
||||||
|
ref(symptr=>lambda)
|
||||||
|
funcptr=>car = symptr
|
||||||
|
expr = expr=>cdr
|
||||||
|
if expr
|
||||||
|
funcptr=>cdr = new_cons
|
||||||
|
funcptr = funcptr=>cdr
|
||||||
|
fin
|
||||||
|
loop
|
||||||
|
return ref(funclist)
|
||||||
|
end
|
||||||
|
|
||||||
|
def eval_index(arrayptr, expr)
|
||||||
|
var idx[4], i, ii, index
|
||||||
|
|
||||||
|
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
|
||||||
|
deref(index)
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
idx[ii] = index=>intval
|
||||||
|
deref(index)
|
||||||
|
expr = expr=>cdr
|
||||||
|
ii++
|
||||||
|
loop
|
||||||
|
index = 0
|
||||||
|
while ii
|
||||||
|
ii--
|
||||||
|
index = index + idx[ii] * arrayptr=>offset[ii]
|
||||||
|
loop
|
||||||
|
return arrayptr=>arraymem + index
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_index(symptr, expr)
|
||||||
|
var elemptr
|
||||||
|
|
||||||
|
if expr=>car == sym_set
|
||||||
|
elemptr = eval_index(symptr=>array, expr=>cdr=>cdr)
|
||||||
|
if elemptr; *elemptr = eval_expr(expr=>cdr=>car); fin
|
||||||
|
else
|
||||||
|
elemptr = eval_index(symptr=>array, expr)
|
||||||
|
fin
|
||||||
|
return elemptr ?? ref(*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
|
||||||
|
deref(index)
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
idx[ii] = index=>intval
|
||||||
|
deref(index)
|
||||||
|
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 ref(arraylist)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_cset(symptr, expr)
|
||||||
|
symptr = deref(eval_expr(expr=>car))
|
||||||
|
if symptr->type & TYPE_MASK <> SYM_TYPE
|
||||||
|
puts("CSET: Not a SYM\n")
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
if symptr=>apval
|
||||||
|
puts("Constant already set:"); print_expr(symptr); putln
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
expr = eval_expr(expr=>cdr=>car)
|
||||||
|
symptr=>apval = expr ^ NULL_HACK
|
||||||
|
return ref(expr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_csetq(symptr, expr)
|
||||||
|
symptr = expr=>car
|
||||||
|
if symptr->type & TYPE_MASK <> SYM_TYPE
|
||||||
|
puts("CSETQ: Not a SYM\n")
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
if symptr=>apval
|
||||||
|
puts("Constant already set:"); print_expr(symptr); putln
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
expr = eval_expr(expr=>cdr=>car)
|
||||||
|
symptr=>apval = expr ^ NULL_HACK
|
||||||
|
return ref(expr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_print(symptr, expr)
|
||||||
|
expr = eval_expr(expr=>car)
|
||||||
|
print_expr(expr)
|
||||||
|
putln
|
||||||
|
return expr
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install default functions
|
||||||
|
//
|
||||||
|
|
||||||
|
new_sym("T")=>apval = @pred_true ^ NULL_HACK
|
||||||
|
new_sym("F")=>apval = NULL_HACK
|
||||||
|
sym_nil = new_sym("NIL")
|
||||||
|
sym_nil=>apval = NULL_HACK
|
||||||
|
sym_lambda = new_sym("LAMBDA")
|
||||||
|
sym_cond = new_sym("COND")
|
||||||
|
sym_set = new_sym("SET")
|
||||||
|
sym_quote = new_sym("QUOTE")
|
||||||
|
sym_quote=>natv = @natv_quote
|
||||||
|
new_sym("CAR")=>natv = @natv_car
|
||||||
|
new_sym("CDR")=>natv = @natv_cdr
|
||||||
|
new_sym("CONS")=>natv = @natv_cons
|
||||||
|
new_sym("ATOM")=>natv = @natv_atom
|
||||||
|
new_sym("EQ")=>natv = @natv_eq
|
||||||
|
new_sym("CSET")=>natv = @natv_cset
|
||||||
|
new_sym("CSETQ")=>natv = @natv_csetq
|
||||||
|
new_sym("NOT")=>natv = @natv_null
|
||||||
|
new_sym("AND")=>natv = @natv_and
|
||||||
|
new_sym("OR")=>natv = @natv_or
|
||||||
|
new_sym("NULL")=>natv = @natv_null
|
||||||
|
new_sym("LABEL")=>natv = @natv_label
|
||||||
|
new_sym("DEFINE")=>natv = @natv_define
|
||||||
|
new_sym("ARRAY")=>natv = @natv_array
|
||||||
|
new_sym("PRINT")=>natv = @natv_print
|
||||||
|
return modkeep | modinitkeep
|
||||||
|
done
|
342
src/lisp/s-math.ref
Normal file
342
src/lisp/s-math.ref
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
include "inc/cmdsys.plh"
|
||||||
|
include "inc/int32.plh"
|
||||||
|
include "inc/fpu.plh"
|
||||||
|
|
||||||
|
import sexpr
|
||||||
|
const TYPE_MASK = $70
|
||||||
|
const NIL = $00
|
||||||
|
const BOOL_FALSE = $00
|
||||||
|
const BOOL_TRUE = $01
|
||||||
|
const CONS_TYPE = $10
|
||||||
|
const SYM_TYPE = $20
|
||||||
|
const SYM_LEN = $0F
|
||||||
|
const NUM_TYPE = $30
|
||||||
|
const NUM_INT = $31
|
||||||
|
const NUM_FLOAT = $32
|
||||||
|
const ARRAY_TYPE = $40
|
||||||
|
|
||||||
|
struc t_elem
|
||||||
|
word link
|
||||||
|
byte type
|
||||||
|
byte refcnt
|
||||||
|
end
|
||||||
|
struc t_cons
|
||||||
|
res[t_elem]
|
||||||
|
word car
|
||||||
|
word cdr
|
||||||
|
end
|
||||||
|
struc t_sym
|
||||||
|
res[t_elem]
|
||||||
|
word natv
|
||||||
|
word lambda
|
||||||
|
word array
|
||||||
|
word apval
|
||||||
|
char name[0]
|
||||||
|
end
|
||||||
|
struc t_numint
|
||||||
|
res[t_elem]
|
||||||
|
word intval[2]
|
||||||
|
end
|
||||||
|
struc t_numfloat
|
||||||
|
res[t_elem]
|
||||||
|
res floatval[10]
|
||||||
|
end
|
||||||
|
|
||||||
|
predef ref(expr)#1
|
||||||
|
predef deref(expr)#1
|
||||||
|
predef new_sym(symstr)#1
|
||||||
|
predef new_int(intlo, inthi)#1
|
||||||
|
predef new_float(extptr)#1
|
||||||
|
predef eval_expr(expr)#1
|
||||||
|
predef bool_pred(bool)#1
|
||||||
|
end
|
||||||
|
|
||||||
|
res[t_numint] nan = 0, 0, NUM_INT, 0, 0, 0, 128 // NaN
|
||||||
|
|
||||||
|
def eval_num(expr)
|
||||||
|
var result
|
||||||
|
|
||||||
|
result = eval_expr(expr=>car)
|
||||||
|
if result and (result->type & TYPE_MASK == NUM_TYPE)
|
||||||
|
return result
|
||||||
|
fin
|
||||||
|
puts("Not an number\n")
|
||||||
|
deref(result)
|
||||||
|
return NULL
|
||||||
|
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)
|
||||||
|
deref(result)
|
||||||
|
int[1] = int[0] < 0 ?? -1 :: 0
|
||||||
|
return new_int(int[0], int[1])
|
||||||
|
fin
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
def push_int32(intptr)#0
|
||||||
|
var[2] int
|
||||||
|
byte isneg
|
||||||
|
|
||||||
|
isneg = FALSE
|
||||||
|
if intptr=>[1] < 0
|
||||||
|
load32(intptr)
|
||||||
|
isneg = TRUE
|
||||||
|
neg32
|
||||||
|
store32(@int)
|
||||||
|
else
|
||||||
|
int[0] = intptr=>[0]
|
||||||
|
int[1] = intptr=>[1]
|
||||||
|
fin
|
||||||
|
fpu:pushInt(@int[1])
|
||||||
|
fpu:scalebXInt(16)
|
||||||
|
fpu:pushInt(@int[0])
|
||||||
|
fpu:addXY()
|
||||||
|
if isneg
|
||||||
|
fpu:negX()
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
def push_num(numptr)#0
|
||||||
|
var int
|
||||||
|
|
||||||
|
if numptr->type == NUM_FLOAT
|
||||||
|
fpu:pushExt(numptr + floatval)
|
||||||
|
elsif numptr->type == NUM_INT
|
||||||
|
push_int32(numptr + intval)
|
||||||
|
else
|
||||||
|
puts("Pushing non number!\n")
|
||||||
|
int = 0
|
||||||
|
fpu:pushInt(@int)
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_add(symptr, expr)
|
||||||
|
var num
|
||||||
|
var[2] intsum
|
||||||
|
var[5] extsum
|
||||||
|
|
||||||
|
intsum[0] = 0
|
||||||
|
intsum[1] = 0
|
||||||
|
num = eval_num(expr)
|
||||||
|
expr = expr=>cdr
|
||||||
|
if num->type == NUM_INT
|
||||||
|
//
|
||||||
|
// Sum as integers unless a float is encountered
|
||||||
|
//
|
||||||
|
intsum[0] = num=>intval[0]
|
||||||
|
intsum[1] = num=>intval[1]
|
||||||
|
deref(num)
|
||||||
|
while expr
|
||||||
|
num = eval_num(expr)
|
||||||
|
expr = expr=>cdr
|
||||||
|
if num->type == NUM_FLOAT
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
load32(@intsum)
|
||||||
|
add32(num + intval)
|
||||||
|
store32(@intsum)
|
||||||
|
deref(num)
|
||||||
|
loop
|
||||||
|
fin
|
||||||
|
if num->type == NUM_FLOAT
|
||||||
|
//
|
||||||
|
// Sum as floating point numbers
|
||||||
|
//
|
||||||
|
push_int32(@intsum)
|
||||||
|
push_num(num)
|
||||||
|
fpu:addXY()
|
||||||
|
deref(num)
|
||||||
|
while expr
|
||||||
|
num = eval_num(expr)
|
||||||
|
push_num(num)
|
||||||
|
fpu:addXY()
|
||||||
|
deref(num)
|
||||||
|
expr = expr=>cdr
|
||||||
|
loop
|
||||||
|
fpu:pullExt(@extsum)
|
||||||
|
return new_float(@extsum)
|
||||||
|
fin
|
||||||
|
return new_int(intsum[0], intsum[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_sub(symptr, expr)
|
||||||
|
var num1, num2
|
||||||
|
var[2] dif
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
sub32(num2 + intval)
|
||||||
|
store32(@dif)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_int(dif[0], dif[1])
|
||||||
|
fin
|
||||||
|
push_num(num1)
|
||||||
|
push_num(num2)
|
||||||
|
fpu:subXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_float(@ext)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_mul(symptr, expr)
|
||||||
|
var num1, num2
|
||||||
|
var[2] mul
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
mul32(num2 + intval)
|
||||||
|
store32(@mul)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_int(mul[0], mul[1])
|
||||||
|
fin
|
||||||
|
push_num(num1)
|
||||||
|
push_num(num2)
|
||||||
|
fpu:mulXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_float(@ext)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_div(symptr, expr)
|
||||||
|
var num1, num2
|
||||||
|
var[2] div
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
div32(num2 + intval)
|
||||||
|
store32(@div)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_int(div[0], div[1])
|
||||||
|
fin
|
||||||
|
push_num(num1)
|
||||||
|
push_num(num2)
|
||||||
|
fpu:divXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_float(@ext)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_rem(symptr, expr)
|
||||||
|
var num1, num2
|
||||||
|
var[2] rem, div
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
rem[1], rem[0] = div32(num2 + intval)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_int(rem[0], rem[1])
|
||||||
|
fin
|
||||||
|
push_num(num1)
|
||||||
|
push_num(num2)
|
||||||
|
fpu:remXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return new_float(@ext)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_neg(symptr, expr)
|
||||||
|
var num
|
||||||
|
var[2] neg
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num = ref(eval_num(expr))
|
||||||
|
if num=>type == NUM_INT
|
||||||
|
load32(num + intval)
|
||||||
|
deref(num)
|
||||||
|
neg32
|
||||||
|
store32(@neg)
|
||||||
|
return new_int(neg[0], neg[1])
|
||||||
|
fin
|
||||||
|
push_num(num)
|
||||||
|
fpu:negX()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num)
|
||||||
|
return new_float(@ext)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_gt(symptr, expr)
|
||||||
|
var num1, num2, bool
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
bool = isgt32(num2 + intval)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return bool_pred(bool)
|
||||||
|
fin
|
||||||
|
push_num(num2)
|
||||||
|
push_num(num1)
|
||||||
|
fpu:subXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return bool_pred(ext[4] < 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def natv_lt(symptr, expr)
|
||||||
|
var num1, num2, bool
|
||||||
|
var[5] ext
|
||||||
|
|
||||||
|
num1 = eval_num(expr)
|
||||||
|
num2 = eval_num(expr=>cdr)
|
||||||
|
if num1->type == NUM_INT and num2->type == NUM_INT
|
||||||
|
load32(num1 + intval)
|
||||||
|
bool = islt32(num2 + intval)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return bool_pred(bool)
|
||||||
|
fin
|
||||||
|
push_num(num1)
|
||||||
|
push_num(num2)
|
||||||
|
fpu:subXY()
|
||||||
|
fpu:pullExt(@ext)
|
||||||
|
deref(num1)
|
||||||
|
deref(num2)
|
||||||
|
return bool_pred(ext[4] < 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install math functions
|
||||||
|
//
|
||||||
|
|
||||||
|
new_sym("+")=>natv = @natv_add
|
||||||
|
new_sym("-")=>natv = @natv_sub
|
||||||
|
new_sym("*")=>natv = @natv_mul
|
||||||
|
new_sym("/")=>natv = @natv_div
|
||||||
|
new_sym("REM")=>natv = @natv_rem
|
||||||
|
new_sym("NEG")=>natv = @natv_neg
|
||||||
|
new_sym(">")=>natv = @natv_gt
|
||||||
|
new_sym("<")=>natv = @natv_lt
|
||||||
|
fpu:reset()
|
||||||
|
return modkeep | modinitkeep
|
||||||
|
done
|
Loading…
x
Reference in New Issue
Block a user