1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2025-01-07 00:29:34 +00:00

Added PROG feature through s-expr extension mechanism. Really easy

This commit is contained in:
David Schmenk 2024-07-12 11:59:51 -07:00
parent b4536f98ba
commit 0ddec876ac
6 changed files with 93 additions and 16 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
- The PROG feature isn't present. Programming is limited to interpreting lambda S-expressions
- Number values are limited to 32 bit integers, no floating point
- General recursion. The 6502 architecture limits recursion (but see tail recursion below), so don't expect too much here
- Arrays not implemented
@ -17,7 +16,7 @@ However, the code is partitioned to allow for easy extension so some of these mi
- Tail recursion handles handles deep recursion. Check out [loop.lisp](https://github.com/dschmenk/PLASMA/blob/master/src/lisp/loop.lisp)
- Fully garbage collected behind the scenes
- Optionally read LISP source file at startup
- SET and SETQ implemented for setting variables
- The PROG feature now present!
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.

Binary file not shown.

View File

@ -49,16 +49,85 @@ import sexpr
end
//
// REPL interface to S-expression evaluator
// REPL and extension interface to S-expression evaluator
//
var prog, prog_expr, prog_return // Current PROG expressions
var sym_cond // Symbol for cond()
var pred_true // Predicate for TRUE
const FILEBUF_SIZE = 128
var readfn // read input routine
var fileref, filebuf // file read vars
byte quit = FALSE // quit interpreter flag
var readfn // Read input routine
var fileref, filebuf // File read vars
byte quit = FALSE // Quit interpreter flag
//
// Native functions
// (PROG ...) language extension
//
def natv_prog(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 eval_expr(cond_expr=>car=>car) == pred_true
eval_expr(cond_expr=>car=>cdr=>car) // Drop result
break
fin
cond_expr = cond_expr=>cdr
loop
else
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(expr)
prog_return = expr=>car
return NULL // This value will be dropped in natv_prog
end
def natv_go(expr)
var label, go
expr = expr=>car
label = prog // Scan prog list looking for matching SYM
while label
if label=>car == expr
prog_expr = label=>cdr
return NULL
fin
label = label=>cdr
loop
puts("(GO ...) destination not found:"); print_expr(expr); putln
return NULL
end
//
// REPL native helper functions
//
def natv_bye(expr)
@ -149,6 +218,8 @@ def parse_cmdline#0
fileio:newline(fileref, $7F, $0D)
readfn = @read_file
filebuf = heapalloc(FILEBUF_SIZE)
else
puts("Unable to open: "); puts(filename); putln
fin
fin
end
@ -157,9 +228,14 @@ end
// REPL
//
pred_true = eval_expr(new_sym("T")) // Capture value of TRUE
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("BYE")=>natv = @natv_bye
new_sym("MEM")=>natv = @natv_memavail
parse_cmdline
new_sym("BYE")=>natv = @natv_bye
new_sym("MEM")=>natv = @natv_memavail
while not quit
putln; print_expr(eval_expr(readfn()))
gc

View File

@ -541,13 +541,13 @@ export def eval_expr(expr)#1
curl, expr = enter_lambda(curl, expr_car=>lambda, expr=>cdr)
elsif expr_car == sym_cond // Inline cond() evaluation
expr = expr=>cdr
while expr
if eval_expr(expr=>car=>car) == @pred_true
expr = expr=>car=>cdr=>car
break
fin
expr = expr=>cdr
loop
while expr
if 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)=>cdr, expr=>cdr)
fin

View File

@ -24,3 +24,4 @@ cat lisp/maplist.lisp | ./ac.jar -ptx DRAWL.po lisp/MAPLIST.LISP TX
cat lisp/gcd.lisp | ./ac.jar -ptx DRAWL.po lisp/GCD.LISP TXT
cat lisp/fact.lisp | ./ac.jar -ptx DRAWL.po lisp/FACT.LISP TXT
cat lisp/loop.lisp | ./ac.jar -ptx DRAWL.po lisp/LOOP.LISP TXT
cat lisp/prog.lisp | ./ac.jar -ptx DRAWL.po lisp/PROG.LISP TXT

View File

@ -184,6 +184,7 @@ cp lisp/maplist.lisp prodos/bld/lisp/MAPLIST.LISP.TXT
cp lisp/gcd.lisp prodos/bld/lisp/GCD.LISP.TXT
cp lisp/fact.lisp prodos/bld/lisp/FACT.LISP.TXT
cp lisp/loop.lisp prodos/bld/lisp/LOOP.LISP.TXT
cp lisp/prog.lisp prodos/bld/lisp/PROG.LISP.TXT
#mkdir prodos/bld/examples
#cp samplesrc/examples/ex.1.pla prodos/bld/examples/EX.1.PLA.TXT