My attempt on writing LISP interpreter in C.
- Tokenizer
- Parser
- Calculator
- Environment
- Lambdas
- Garbage Collector
- Conditions
- Lists
- Mutators
- Read from file
- Error handling
$ make
$ ./repl
$ make check
$ ./test
Interpreter supports basic arithmetic operations.
> (+ 1 (- 2 3) (* 4 5) (/ 6 2))
23
Functions are define by assigning lambda to variable
> (define a (+ 1 2))
> a
3
> (define square (lambda (n) (* n n)))
> (square 3)
9
> (if (< 2 4) (+ 41 1) (+ 68 1))
42
Closures are procedures executed in environment they were defined.
> (define counter
(lambda (n)
(lambda () (begin (set! n (+ 1 n)) n))))
> (define c1 (counter 10))
> (define c2 (counter 20))
> (c1)
11
> (c2)
21
Lists are sequences of pairs (conses).
> (cons 1 2)
(1 . 2)
> (define l (cons 1 (cons 2 (cons 3 null))))
> l
(1 2 3)
> (car (cdr l))
2
> (set-car! l 4)
> l
(4 2 3)
Interpreter may be opened with preloaded files.
$ ./repl -f examples/lists.scm
Scheme interpreter:
> (map (lambda (n) (* n n)) (list 1 2 3 4))
(1 4 9 16)
Garbage collection is implemented in a tracing way (specifically with a mark-and-sweep algorithm), when value or environment created its reference is registered in GC pool. After each REPL GC traces each accessible value and environment from a root enironment, marks them. Then it goes throug each reference in a list, and if it is marked its reference is copied to new GC pool, else it is freed.
Interpreter supports several types of error handling.
> (+ b 4)
ERROR: b variable not bound
> ((+ 2 3) (- 2 3))
ERROR: integer is not a procedure
> ((lambda (a b) (+ a b)) 5)
ERROR: procedure expects 2 arguments, not 1