1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-09-07 12:54:31 +00:00

Add bitwise operators and hex input/output

This commit is contained in:
David Schmenk 2024-07-19 12:32:42 -07:00
parent 58fc3a3025
commit 01a5f0d75b
7 changed files with 437 additions and 217 deletions

View File

@ -4,7 +4,6 @@ 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
- 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
However, the code is partitioned to allow for easy extension so some of these missing features could be implemented.
@ -17,6 +16,8 @@ However, the code is partitioned to allow for easy extension so some of these mi
- Optionally read LISP source file at startup
- The PROG feature now present!
- Arrays of up to four dimensions
- FUNCTION operation with bound variables
- Additional testing/looping construct: IF, FOR, WHILE, UNTIL
LISP is one of the earliest computer languages. As such, it holds a special place in the anals of computer science. I've always wanted to learn why LISP is held in such high regard by so many, so I went about learning LISP by actually implementing a LISP interpreter in PLASMA. PLASMA is well suited to implement other languages due to its rich syntax, performance and libraries.

View File

@ -16,6 +16,7 @@ import sexpr
const ARRAY_TYPE = $40
const MARK_BIT = $80
const MARK_MASK = $7F
const NULL_HACK = 1 // Hack so we can set elements to NULL
struc t_elem
word link
@ -46,7 +47,6 @@ import sexpr
predef new_int(intlo, inthi)#1
predef new_sym(symstr)#1
predef new_assoc(symptr, valptr)#0
predef set_assoc(symptr, valptr)#0
predef print_expr(expr)#0
predef parse_expr(evalptr, level, refill)#2
predef eval_expr(expr)#1
@ -59,7 +59,7 @@ import smath
end
var prog, prog_expr, prog_return // Current PROG expressions
var sym_cond, sym_fpint, sym_fpfrac
var sym_cond, sym_if, sym_fpint, sym_fpfrac
var pred_true
const FILEBUF_SIZE = 128
@ -99,6 +99,13 @@ def natv_prog(symptr, expr)
fin
cond_expr = cond_expr=>cdr
loop
elsif prog_car=>car == sym_if // Inline if() evaluation
cond_expr = prog_car=>cdr
if eval_expr(cond_expr=>car)
eval_expr(cond_expr=>cdr=>car) // Drop result
elsif cond_expr=>cdr=>cdr=>car
eval_expr(cond_expr=>cdr=>cdr=>car) // Drop result
fin
else
eval_expr(prog_car) // Drop result
fin
@ -108,8 +115,10 @@ def natv_prog(symptr, expr)
//
fin
loop
prog = prog_enter
return eval_expr(prog_return)
prog = prog_enter
expr = eval_expr(prog_return)
prog_return = FALSE
return expr
end
def natv_return(symptr, expr)
@ -136,21 +145,15 @@ end
//
def natv_fpint(symptr, expr)
var fmt
fmt_fpint = eval_int(expr)=>intval
fmt = new_int(fmt_fpint, 0)
set_assoc(sym_fpint, fmt)
return fmt
sym_fpint=>apval = fmt_fpint ^ NULL_HACK
return sym_fpint
end
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
sym_fpfrac=>apval = fmt_fpfrac ^ NULL_HACK
return sym_fpfrac
end
def natv_gc(symptr, expr)
@ -251,19 +254,20 @@ 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
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
sym_fpint=>apval = new_int(fmt_fpint, 0) ^ NULL_HACK
sym_fpfrac=>apval = new_int(fmt_fpfrac, 0) ^ NULL_HACK
sym_cond = new_sym("COND") // This should actually match COND
sym_if = new_sym("IF") // This should actually match IF
new_sym("PROG")=>natv = @natv_prog
new_sym("GO")=>natv = @natv_go
new_sym("RETURN")=>natv = @natv_return
new_sym("GC")=>natv = @natv_gc
new_sym("QUIT")=>natv = @natv_bye
new_sym("QUIT")=>natv = @natv_bye
parse_cmdline
while not quit

View File

@ -10,11 +10,11 @@
(PRINTLN 'TAIL)
(LOOP 1 100 LPRINT)
(PRINTLN 'FOR)
(PRINT 'FOR)
(FOR I 1 1 (< I 100) (PRINT I))
(PRINTLN 'WHILE)
(SETQ N 0)
(WHILE (< N 100) (PRINT N) (SETQ N (+ N 1)))
(PRINTLN 'UNTIL)
(SETQ N 1)
(UNTIL (> N 99) (PRINT N) (SETQ N (+ N 1)))
(PRINT 'WHILE)
(CSETQ I 0)
(WHILE (< I 100) (PRINT I) (CSETQ I (+ I 1)))
(PRINT 'UNTIL)
(CSETQ I 1)
(UNTIL (> I 99) (PRINT I) (CSETQ I (+ I 1)))

View File

@ -1,7 +1,7 @@
(define
(ydot
(lambda (x y)
(maplist x '(lambda (j) (cons (car j) y)))
(maplist x (function (lambda (j) (cons (car j) y))))
)
)
(maplist

View File

@ -1,11 +1,22 @@
(label length (lambda (l)
(prog (u v)
(setq v 0)
(setq u l)
a (cond ((null u),(return v)))
(setq u (cdr u))
(setq v (+ 1 v))
(go a)
)
(label lengthc (lambda (l)
(prog (u v)
(setq v 0)
(setq u l)
a (cond ((null u),(return v)))
(setq v (+ 1 v))
(setq u (cdr u))
(go a)
)
)
)
(label lengthi (lambda (l)
(prog (u v)
(setq v 0)
(setq u l)
a (if (null u) (return v) (setq v (+ 1 v)))
(setq u (cdr u))
(go a)
)
)
)

View File

@ -13,7 +13,6 @@ const NUM_TYPE = $30
const NUM_INT = $31
const NUM_FLOAT = $32
const ARRAY_TYPE = $40
const FUNC_TYPE = $50
const MARK_BIT = $80
const MARK_MASK = $7F
const NULL_HACK = 1 // Hack so we can set elements to NULL
@ -27,21 +26,14 @@ struc t_cons
word car
word cdr
end
struc t_func
struc t_sym
res[t_elem]
word natv
word lambda
end
struc t_sym
res[t_func]
word array
word apval
char name[0]
end
struc t_funcenv
res[t_func]
word environ
end
struc t_numint
res[t_elem]
word intval[2]
@ -62,19 +54,18 @@ const fmt_fp = FPSTR_FIXED|FPSTR_STRIP|FPSTR_FLEX
export var fmt_fpint = 6
export var fmt_fpfrac = 4
var assoc_list = NULL // Local SYM->value association list
var global_list = NULL // Global SYM->value association list
byte prhex = FALSE // Hex output flag for integers
var assoc_list = NULL // SYM->value association list
var cons_list = NULL
var cons_free = NULL
var int_list = NULL
var int_free = NULL
var float_list = NULL
var float_free = NULL
var func_list = NULL
var func_free = NULL
var sym_list = NULL
var sym_nil, sym_quote, sym_lambda, sym_set
var sym_nil, sym_quote, sym_lambda, sym_funarg, sym_set
var sym_cond, sym_if, sym_for, sym_space, sym_cr
res[t_elem] pred_true = 0, 0, BOOL_TRUE
predef print_expr(expr)#0
@ -82,6 +73,10 @@ predef eval_expr(expr)#1
//
// Garbage collector
// - note, anytime eval_expr is called there is the possibility of
// garbage collecting. If there are any in-flight elements (cons,
// int, float) they may be collected and returned to the free list.
// Use the sweep_stack to temporarily keep a reference to these elements.
//
const SWEEPSTACK_MAX = 64
@ -104,7 +99,6 @@ def mark_elems#0
mark_list(cons_list)
mark_list(int_list)
mark_list(float_list)
mark_list(func_list)
end
def sweep_expr(expr)#0
@ -123,7 +117,6 @@ end
def sweep_used#0
var symptr, i, memptr, size
sweep_expr(global_list)
sweep_expr(assoc_list)
sweep_expr(eval_last)
symptr = sym_list
@ -205,7 +198,6 @@ def collect_unused#0
cons_list, cons_free = collect_list(cons_list, cons_free)
int_list, int_free = collect_list(int_list, int_free)
float_list, float_free = collect_list(float_list, float_free)
func_list, func_free = collect_list(func_list, func_free)
end
export def gc#0
@ -272,25 +264,6 @@ export def new_float(extptr)#1
return floatptr
end
def new_func
var funcptr
if func_free
funcptr = func_free
func_free = func_free=>link
else
gc_pull++
funcptr = heapalloc(t_func)
fin
funcptr=>link = func_list
func_list = funcptr
funcptr->type = FUNC_TYPE
funcptr=>natv = NULL
funcptr=>lambda = NULL
funcptr=>environ = NULL
return funcptr
end
def new_array(dim0, dim1, dim2, dim3)
var ofst0, ofst1, ofst2, ofst3
var size, aptr, memptr
@ -390,8 +363,13 @@ def print_atom(atom)#0
is NUM_TYPE
when atom->type
is NUM_INT
if atom=>intval[1] >= 0; putc(' '); fin // Add space for pos
puti32(atom + intval)
if prhex
putc('$')
puth(atom=>intval[1]); puth(atom=>intval[0])
else
if atom=>intval[1] >= 0; putc(' '); fin // Add space for pos
puti32(atom + intval)
fin
break
is NUM_FLOAT
puts(ext2str(atom + floatval, @prstr, fmt_fpint, fmt_fpfrac, fmt_fp))
@ -439,14 +417,6 @@ def print_atom(atom)#0
next
puts("]\n")
break
is FUNC_TYPE
puts("FUNCTION:\n")
if atom=>natv; puts("NATV")
elsif atom=>lambda; print_expr(atom=>lambda)
else puts("???")
fin
puts("\nENVIRON:\n"); print_expr(atom=>environ); putln
break
otherwise
puts("Unknown atom type: $"); putb(atom->type); putln
wend
@ -485,6 +455,12 @@ end
def is_num(cptr)
if ^cptr == '-' or ^cptr == '+'; cptr++; fin
if ^cptr == '$'
cptr++
if toupper(^cptr) >= 'A' and toupper(^cptr) <= 'F'
return TRUE
fin
fin
return ^cptr >= '0' and ^cptr <= '9'
end
@ -495,7 +471,7 @@ end
def parse_num(evalptr)#2 // return evalptr, intptr
var startptr
var int[2], ext[5]
byte sign
byte sign, h
sign = FALSE
if ^evalptr == '-'
@ -504,34 +480,51 @@ def parse_num(evalptr)#2 // return evalptr, intptr
elsif ^evalptr == '+'
evalptr++
fin
startptr = evalptr
while ^evalptr >= '0' and ^evalptr <= '9'
if ^evalptr == '$'
evalptr++
loop
if (evalptr - startptr > 10) or ^evalptr == '.' or toupper(^evalptr) == 'E'
if ^evalptr == '.'
h = toupper(^evalptr)
zero32
while h >= '0' and h <= 'F'
if h > '9'
h = h - 'A' + 10
if h > 16; break; fin
else
h = h - '0'
fin
muli16(16); addi16(h)
evalptr++
while ^evalptr >= '0' and ^evalptr <= '9'
evalptr++
loop
fin
if toupper(^evalptr) == 'E'
h = toupper(^evalptr)
loop
else
startptr = evalptr
while ^evalptr >= '0' and ^evalptr <= '9'
evalptr++
if ^evalptr == '-' or ^evalptr == '+'; evalptr++; fin
while ^evalptr >= '0' and ^evalptr <= '9'
loop
if (evalptr - startptr > 10) or ^evalptr == '.' or toupper(^evalptr) == 'E'
if ^evalptr == '.'
evalptr++
loop
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
if sign; startptr--; fin
^(startptr - 1) = evalptr - startptr
str2ext(startptr - 1, @ext)
return evalptr, new_float(@ext)
zero32
while startptr <> evalptr
muli16(10); addi16(^startptr - '0')
startptr++
loop
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])
@ -653,27 +646,19 @@ end
//
export def new_assoc(symptr, valptr)#0
var pair, addlist
var pair, pairlist
if symptr and (symptr->type & TYPE_MASK <> SYM_TYPE)
puts("Not a SYM in new_assoc\n")
return
fin
pair = new_cons
pair=>car = symptr
pair=>cdr = valptr
if global_list // Add to end of global_list
addlist = global_list
while addlist=>cdr
addlist = addlist=>cdr
loop
addlist=>cdr = new_cons
addlist = addlist=>cdr
else // New list
global_list = new_cons
addlist = global_list
fin
addlist=>car = pair
pair = new_cons
pair=>car = symptr
pair=>cdr = valptr
pairlist = new_cons
pairlist=>car = pair
pairlist=>cdr = assoc_list
assoc_list = pairlist
end
def assoc_pair(symptr)
@ -689,20 +674,10 @@ def assoc_pair(symptr)
fin
pair = pair=>cdr
loop
//
// Search global association list for symbol
//
pair = global_list
while pair
if (pair=>car=>car == symptr)
return pair=>car
fin
pair = pair=>cdr
loop
return NULL // SYM not associated
end
export def set_assoc(symptr, valptr)#0
export def set_assoc(symptr, valptr)#1
var pair
//
@ -711,9 +686,8 @@ export def set_assoc(symptr, valptr)#0
pair = assoc_pair(symptr)
if pair
pair=>cdr = valptr // Update association
else
new_assoc(symptr, valptr) // Add global association if unknown
fin
return pair
end
def assoc(symptr)
@ -729,16 +703,6 @@ def assoc(symptr)
fin
pair = pair=>cdr
loop
//
// Search global association list for symbol
//
pair = global_list
while pair
if (pair=>car=>car == symptr)
return pair=>car=>cdr
fin
pair = pair=>cdr
loop
return NULL // SYM not associated
end
@ -746,8 +710,8 @@ end
// Evaluate expression
//
def enter_lambda(curl, expr, params)#2 // curl, expr
var args, arglist, pairlist, parambase
def apply_args(curl, expr, argvals)#2 // curl, expr
var argsyms, arglist, pairlist, argbase
if !expr or expr=>car <> sym_lambda
puts("Invalid LAMBDA expression: "); print_expr(expr); putln
@ -757,35 +721,35 @@ def enter_lambda(curl, expr, params)#2 // curl, expr
// Evaluate the parameters
// - manipulate sweep_stack directly for performance
//
parambase = sweep_stack_top
while params
sweep_stack[sweep_stack_top] = eval_expr(params=>car)
argbase = sweep_stack_top
while argvals
sweep_stack[sweep_stack_top] = eval_expr(argvals=>car)
sweep_stack_top++
if sweep_stack_top >= SWEEPSTACK_MAX
puts("Parameter overflow:"); print_expr(expr); putln
puts("Arg val overflow:"); print_expr(expr); putln
return NULL, NULL
fin
params = params=>cdr
argvals = argvals=>cdr
loop
args = expr=>cdr=>car
sweep_stack_top = parambase
argsyms = expr=>cdr=>car
sweep_stack_top = argbase
if curl == expr
//
// Set associations
//
arglist = assoc_list
while args
arglist=>car=>cdr = sweep_stack[parambase]
while argsyms
arglist=>car=>cdr = sweep_stack[argbase]
arglist = arglist=>cdr
args = args=>cdr
parambase++
argsyms = argsyms=>cdr
argbase++
loop
else
//
// Build arg list before prepending to assoc_list
//
arglist = NULL
while args
while argsyms
//
// Build argument/value pairs
//
@ -797,10 +761,10 @@ def enter_lambda(curl, expr, params)#2 // curl, expr
pairlist = arglist
fin
pairlist=>car = new_cons
pairlist=>car=>car = args=>car
pairlist=>car=>cdr = sweep_stack[parambase]
args = args=>cdr
parambase++
pairlist=>car=>car = argsyms=>car
pairlist=>car=>cdr = sweep_stack[argbase]
argsyms = argsyms=>cdr
argbase++
loop
if arglist
pairlist=>cdr = assoc_list
@ -810,12 +774,64 @@ def enter_lambda(curl, expr, params)#2 // curl, expr
return expr, expr=>cdr=>cdr=>car
end
def eval_funarg(funarg, argvals)
var funexpr, argsyms, arglist, pairlist, argbase
funexpr = funarg=>cdr=>car // Lambda expression
argsyms = funexpr=>cdr=>car
//
// Evaluate the parameters
// - manipulate sweep_stack directly for performance
//
argbase = sweep_stack_top
while argvals
sweep_stack[sweep_stack_top] = eval_expr(argvals=>car)
sweep_stack_top++
if sweep_stack_top >= SWEEPSTACK_MAX
puts("Parameter overflow:"); print_expr(funexpr); putln
return NULL
fin
argvals = argvals=>cdr
loop
sweep_stack_top = argbase
//
// Build arg list before prepending to new assoc_list
//
arglist = NULL
while argsyms
//
// Build argument/value pairs
//
if arglist
pairlist=>cdr = new_cons
pairlist = pairlist=>cdr
else
arglist = new_cons
pairlist = arglist
fin
pairlist=>car = new_cons
pairlist=>car=>car = argsyms=>car
pairlist=>car=>cdr = sweep_stack[argbase]
argsyms = argsyms=>cdr
argbase++
loop
push_sweep_stack(assoc_list)
assoc_list = funarg=>cdr=>cdr=>car // Swap associcate list pointer
if arglist
pairlist=>cdr = assoc_list
assoc_list = arglist
fin
funexpr = eval_expr(funexpr=>cdr=>cdr=>car)
funarg=>cdr=>cdr=>car = assoc_list // Save current environ
assoc_list = pop_sweep_stack
return funexpr
end
export def eval_expr(expr)#1
var alist_enter, curl, expr_car
var curl, expr_car
if gc_pull > GC_TRIGGER; gc; fin
curl = NULL // Current lambda
alist_enter = assoc_list
while expr
if expr->type == CONS_TYPE
//
@ -827,7 +843,7 @@ export def eval_expr(expr)#1
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)
curl, expr = apply_args(curl, expr_car=>lambda, expr=>cdr)
elsif expr_car == sym_cond // Inline cond() evaluation
expr = expr=>cdr
while expr
@ -847,11 +863,22 @@ export def eval_expr(expr)#1
expr = expr=>car
fin
fin
else // Symbol associated with lambda
curl, expr = enter_lambda(curl, assoc(expr_car), expr=>cdr)
else // Associated symbol
expr_car = assoc(expr_car)
if expr_car->type == CONS_TYPE
if expr_car=>car == sym_funarg
expr = eval_funarg(expr_car, expr=>cdr)
break
elsif expr_car=>car == sym_lambda
curl, expr = apply_args(NULL, expr_car, expr=>cdr)
else
puts("Unknown function:"); print_expr(expr); putln
expr = NULL
fin
fin
fin
elsif expr_car->type == CONS_TYPE and expr_car=>car == sym_lambda
curl, expr = enter_lambda(NULL, expr_car, expr=>cdr) // Inline lambda
curl, expr = apply_args(NULL, expr_car, expr=>cdr) // Inline lambda
fin
else
//
@ -871,7 +898,6 @@ export def eval_expr(expr)#1
break
fin
loop
assoc_list = alist_enter
return expr
end
@ -882,6 +908,37 @@ export def eval_quote(expr)#1
return expr
end
//
// Make a copy of an expr
//
def copy_expr(expr)
var copy
if expr and expr->type == CONS_TYPE
//
// Copy cons structure
//
copy = push_sweep_stack(new_cons)
while expr
if expr=>car and expr=>car->type == CONS_TYPE
copy=>car = copy_expr(expr=>car)
else
copy=>car = expr=>car
fin
if expr=>cdr and expr=>cdr->type == CONS_TYPE
copy=>cdr = new_cons
copy = copy=>cdr
expr = expr=>cdr
else // End of list
copy=>cdr = expr=>cdr
expr = NULL
fin
loop
return pop_sweep_stack
fin
return expr
end
//
// Base native functions
//
@ -985,18 +1042,35 @@ end
def natv_label(symptr, expr)
symptr = expr=>cdr=>car
set_assoc(expr=>car, symptr)
if !set_assoc(expr=>car, symptr)
new_assoc(expr=>car, symptr)
fin
return symptr
end
def natv_function(symptr, expr)
var funptr
funptr = new_cons
symptr = funptr
symptr=>car = sym_funarg
symptr=>cdr = new_cons
symptr = symptr=>cdr
symptr=>car = expr=>car
symptr=>cdr = new_cons
symptr = symptr=>cdr
symptr=>car = copy_expr(assoc_list)
return funptr
end
def natv_define(symptr, expr)
var funclist, funcptr
var deflist, funcptr
funclist = NULL
deflist = NULL
if expr
funclist = new_cons
funcptr = funclist
deflist = new_cons
funcptr = deflist
fin
while expr
symptr = expr=>car=>car
@ -1008,7 +1082,7 @@ def natv_define(symptr, expr)
funcptr = funcptr=>cdr
fin
loop
return funclist
return deflist
end
def eval_index(arrayptr, expr)
@ -1116,9 +1190,10 @@ def natv_setq(symptr, expr)
return symptr
end
def natv_print(symptr, expr)
def natv_pri(symptr, expr)
var result
result = NULL
while expr
if expr=>car == sym_space
result = sym_space
@ -1135,8 +1210,15 @@ def natv_print(symptr, expr)
return result
end
def natv_println(symptr, expr)
expr = natv_print(symptr, expr)
def natv_prhex(symptr, expr)
if expr
prhex = eval_expr(expr=>car)
fin
return bool_pred(prhex)
end
def natv_print(symptr, expr)
expr = natv_pri(symptr, expr)
putln
return expr
end
@ -1238,39 +1320,42 @@ end
// Install default functions
//
new_sym("T")=>apval = @pred_true ^ NULL_HACK
new_sym("F")=>apval = NULL_HACK
sym_space = new_sym("SPACE")
sym_cr = new_sym("CR")
sym_nil = new_sym("NIL")
sym_nil=>apval = NULL_HACK
sym_lambda = new_sym("LAMBDA")
sym_cond = new_sym("COND")
sym_if = new_sym("IF")
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("LIST")=>natv = @natv_list
new_sym("ATOM")=>natv = @natv_atom
new_sym("EQ")=>natv = @natv_eq
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("CSET")=>natv = @natv_cset
new_sym("CSETQ")=>natv = @natv_csetq
new_sym("SET")=>natv = @natv_set
new_sym("SETQ")=>natv = @natv_setq
new_sym("PRINT")=>natv = @natv_print
new_sym("PRINTLN")=>natv = @natv_println
new_sym("FOR")=>natv = @natv_for
new_sym("WHILE")=>natv = @natv_while
new_sym("UNTIL")=>natv = @natv_until
new_sym("T")=>apval = @pred_true ^ NULL_HACK
new_sym("F")=>apval = NULL_HACK
sym_space = new_sym("SPACE")
sym_cr = new_sym("CR")
sym_nil = new_sym("NIL")
sym_nil=>apval = NULL_HACK
sym_lambda = new_sym("LAMBDA")
sym_funarg = new_sym("FUNARG")
sym_cond = new_sym("COND")
sym_if = new_sym("IF")
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("LIST")=>natv = @natv_list
new_sym("ATOM")=>natv = @natv_atom
new_sym("EQ")=>natv = @natv_eq
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("FUNCTION")=>natv = @natv_function
new_sym("LABEL")=>natv = @natv_label
new_sym("DEFINE")=>natv = @natv_define
new_sym("ARRAY")=>natv = @natv_array
new_sym("CSET")=>natv = @natv_cset
new_sym("CSETQ")=>natv = @natv_csetq
new_sym("SET")=>natv = @natv_set
new_sym("SETQ")=>natv = @natv_setq
new_sym("PRI")=>natv = @natv_pri
new_sym("PRHEX")=>natv = @natv_prhex
new_sym("PRINT")=>natv = @natv_print
new_sym("FOR")=>natv = @natv_for
new_sym("WHILE")=>natv = @natv_while
new_sym("UNTIL")=>natv = @natv_until
return modkeep | modinitkeep
done

View File

@ -658,6 +658,119 @@ def natv_annuityY(symptr, expr)
return new_float(@ext)
end
//
// Bit-wise operations
//
def natv_bitnot(symptr, expr)
symptr = eval_int(expr)
return new_int(~symptr=>intval[0], ~symptr=>intval[1])
end
def natv_bitand(symptr, expr)
var[2] bitval
symptr = eval_int(expr)
bitval[0] = symptr=>intval[0]
bitval[1] = symptr=>intval[1]
symptr = eval_int(expr=>cdr)
return new_int(bitval[0] & symptr=>intval[0], bitval[1] & symptr=>intval[1])
end
def natv_bitor(symptr, expr)
var[2] bitval
symptr = eval_int(expr)
bitval[0] = symptr=>intval[0]
bitval[1] = symptr=>intval[1]
symptr = eval_int(expr=>cdr)
return new_int(bitval[0] | symptr=>intval[0], bitval[1] | symptr=>intval[1])
end
def natv_bitxor(symptr, expr)
var[2] bitval
symptr = eval_int(expr)
bitval[0] = symptr=>intval[0]
bitval[1] = symptr=>intval[1]
symptr = eval_int(expr=>cdr)
return new_int(bitval[0] ^ symptr=>intval[0], bitval[1] ^ symptr=>intval[1])
end
def natv_shift(symptr, expr)
var[2] bitval
var shift
symptr = eval_int(expr)
bitval[0] = symptr=>intval[0]
bitval[1] = symptr=>intval[1]
symptr = eval_int(expr=>cdr)
shift = symptr=>intval[0]
if shift < 0
//
// Shift right
//
while shift < 0
bitval[0] = bitval[0] >> 1
if bitval[1] & 1
bitval[0] = bitval[0] | $8000
else
bitval[0] = bitval[0] & $7FFF
fin
bitval[1] = bitval[1] >> 1
shift++
loop
else
//
// Shift left
//
while shift > 0
bitval[1] = bitval[1] << 1
if bitval[0] & $8000
bitval[1] = bitval[1] | 1
fin
bitval[0] = bitval[0] << 1
shift--
loop
fin
return new_int(bitval[0], bitval[1])
end
def natv_rotate(symptr, expr)
var[2] bitval
var rotate, wrap
symptr = eval_int(expr)
bitval[0] = symptr=>intval[0]
bitval[1] = symptr=>intval[1]
symptr = eval_int(expr=>cdr)
rotate = symptr=>intval[0]
if rotate < 0
while rotate < 0
wrap = bitval[0] & 1 ?? $8000 :: 0
bitval[0] = bitval[0] >> 1
if bitval[1] & 1
bitval[0] = bitval[0] | $8000
else
bitval[0] = bitval[0] & $7FFF
fin
bitval[1] = wrap | (bitval[1] >> 1)
rotate++
loop
else
while rotate > 0
wrap = bitval[1] & $8000 ?? 1 :: 0
bitval[1] = bitval[1] << 1
if bitval[0] & $8000
bitval[1] = bitval[1] | 1
fin
bitval[0] = wrap | (bitval[0] << 1)
rotate--
loop
fin
return new_int(bitval[0], bitval[1])
end
//
// Install math functions
//
@ -697,6 +810,12 @@ new_sym("POW_I")=>natv = @natv_powI
new_sym("POWY")=>natv = @natv_powY
new_sym("COMP")=>natv = @natv_compY
new_sym("ANNUITY")=>natv = @natv_annuityY
new_sym("BITNOT")=>natv = @natv_bitnot
new_sym("BITAND")=>natv = @natv_bitand
new_sym("BITOR")=>natv = @natv_bitor
new_sym("BITXOR")=>natv = @natv_bitxor
new_sym("SHIFT")=>natv = @natv_shift
new_sym("ROTATE")=>natv = @natv_rotate
fpu:reset()
return modkeep | modinitkeep
done