komplott / komplodin A tribute to: Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I (as found in paper/recursive.pdf ) A micro-subset of scheme / the original LISP in a single C file: komplott.c ! New in 2025! The LISP interpreter translated to Odin in komplodin.odin . More lines of code, but I am less familiar with the language and am translating directly from C, so there are probably ways to make it a cleaner solution. When I posted this to lobste.rs, gingerBill (creator of Odin) was kind enough to make a more direct translation of the C code into Odin, which can be viewed in this gist: komplott.odin. Since the lobste.rs posting, I have tweaked the Odin version a bit more, and so it differs from the C version quite a bit in the implementation details. I've tried to keep the output and functionality of the two programs the same though. Features Single file implementation. Less than 500 lines of code (~600 lines for the Odin version) Scheme-compliant enough for the test programs to be executable by GNU Guile (not sure if this is true anymore) Copying semi-space garbage collector based on Cheney's Algorithm. For more details on how it works, Andy Wingo has a great post about this kind of garbage collector on his blog (wingolog). Limited tail call optimization (not true TCO; see tests/true-tco.scm ). Near-zero error handling. Zero thread safety or security. Also includes: An implementation of the core of LISP 1.5 from 1962 Instructions To build the komplott executable, run make komplott . The only dependency aside from make is gcc . To build the Odin version ( komplodin ), run make komplodin . This depends on the Odin compiler. To run the LISP 1.5 interpreter and a couple of test cases, run make test . LISP 1.5 The version presented in the README is slightly tweaked from the one that can be found in tests/lisp15.scm in order to more closely resemble early LISP rather than scheme: #t and #f are written as t and nil . (define pairlis ( lambda (x y a) ( cond ((null? x) a) ( t ( cons ( cons ( car x) ( car y)) ( pairlis ( cdr x) ( cdr y) a)))))) (define assoc ( lambda (x a) ( cond ((equal? ( caar a) x) ( car a)) ( t ( assoc x ( cdr a)))))) (define atom? ( lambda (x) ( cond ((null? x) t ) ((atom? x) t ) ( t nil )))) (define evcon ( lambda (c a) ( cond (( eval ( caar c) a) ( eval ( cadar c) a)) ( t (evcon ( cdr c) a))))) (define evlis ( lambda (m a) ( cond ((null? m) nil ) ( t ( cons ( eval ( car m) a) (evlis ( cdr m) a)))))) (define apply ( lambda (fun x a) ( cond ((atom? fun) ( cond ((equal? fun ( quote CAR )) ( caar x)) ((equal? fun ( quote CDR )) ( cdar x)) ((equal? fun ( quote CONS )) ( cons ( car x) ( cadr x))) ((equal? fun ( quote ATOM )) (atom? ( car x))) ((equal? fun ( quote EQ )) (equal? ( car x) ( cadr x))) ( t ( apply ( eval fun a) x a)))) ((equal? ( car fun) ( quote LAMBDA )) ( eval ( caddr fun) ( pairlis ( cadr fun) x a))) ((equal? ( car fun) ( quote LABEL)) ( apply ( caddr fun) x ( cons ( cons ( cadr fun) ( caddr fun)) a)))))) (define eval ( lambda (e a) ( cond ((atom? e) ( cdr ( assoc e a))) ((atom? ( car e)) ( cond ((equal? ( car e) ( quote QUOTE)) ( cadr e)) ((equal? ( car e) ( quote COND )) (evcon ( cdr e) a)) ( t ( apply ( car e) (evlis ( cdr e) a) a)))) ( t ( apply ( car e) (evlis ( cdr e) a) a))))) (define evalquote ( lambda (fn x) ( apply fn x ( quote ())))) Here is an example of actual LISP 1.5 code: ((LABEL MAPCAR ( LAMBDA (FN SEQ) ( COND (( EQ NIL SEQ) NIL ) ( T ( CONS (FN ( CAR SEQ)) ( MAPCAR FN ( CDR SEQ))))))) DUP LST) ; where ; DUP -> (LAMBDA (X) (CONS X X)) ; LST -> (A B C) To prevent reading from continuing indefinitely, each packet should end with STOP followed by a large number of right parentheses. An unpaired right parenthesis will cause a read error and terminate reading.