Open-source project
Robert-van-Engelen/tinylisp avatar
Robert-van-Engelen/tinylisp

Tinylisp: a compact C Lisp interpreter with optimized variants

Lisp in 99 lines of C and how to write one yourself. Includes 21 Lisp primitives, garbage collection and REPL. Includes tail-call optimized versions for speed and reduced memory use.

1,677 stars104 forksCBSD-3-Clause

At a glance

What is it?
Tinylisp fits a Lisp interpreter into 99 lines of C, with 21 primitives, a REPL, garbage collection, optional libraries, and tail-call-optimized variants. It suits readers studying interpreter construction or needing a small embedded Lisp rather than a general-purpose production runtime.
Who is it for?
Adopt Tinylisp when the goal is to study a small interpreter, add Lisp behavior directly in C, or run a constrained embedded dialect. Do not treat it as a drop-in general-purpose Lisp runtime without first checking required language features, object representation, error handling, memory needs, and platform constraints.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 57 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why Tinylisp fits inside 99 lines of C

Tinylisp solves the problem of demonstrating how much interpreter machinery can fit into a deliberately small C program. It is aimed at readers who want to understand or build a Lisp interpreter, including people adapting Lisp features to constrained C-like environments. The repository also targets the Sharp PC-G850 and PC-G850V/S pocket computers, where source size and direct execution with a native C compiler matter.

The main implementation is not merely a parser that prints expressions. According to the README, it supports static scoping, double-precision floating-point values, 21 Lisp primitives, a REPL, and simple garbage collection. Separate sources provide a single-precision version, a commented version, a version for the Sharp PC-G850 using BCD boxing, and tail-call-optimized versions described as using less memory and running faster.

That scope makes Tinylisp an educational interpreter with practical additions rather than a full Common Lisp implementation. The name refers to the approximately 99-line core, but the repository also contains optional extensions. Those extras add source loading, Readline support, input and output for Lisp expressions, exceptions, interrupt handling, macros, backquoting, and execution tracing. Their increased scope means that the 99-line figure should not be applied to every file in the repository.

How Tinylisp represents and evaluates forms

Tinylisp represents Lisp lists as chains of pairs ending in the empty list, `()`. The `(quote <expr>)` form and its shorthand protect an expression from evaluation, while `eval` evaluates a quoted expression. Pair construction is exposed through `cons`, and list access is handled by `car` and `cdr`. A dotted expression such as `'(1 . 2)` constructs a pair whose tail is not another list.

Values include double-precision numbers, including `inf`, `-inf`, and `nan`, with `nan` also acting as the error value. Symbols are sequences of non-space characters other than parentheses and quotation marks. A symbol normally resolves to its value when evaluated, whereas quoted symbols remain literal. The empty list is the false value, while every other value is treated as true. For convenience, the symbol `#t` evaluates to itself.

The optimized implementation includes tail-call optimization, while the unoptimized `src/tinylisp.c` is the double-precision baseline. The repository also points to a reference-counting garbage collector under `GC/README.md`, and the README describes that expanded version as more efficient in memory and processor use. This gives readers two distinct implementation choices to examine: a compact collector within the core source and a separate reference-counting approach.

Compiling Tinylisp and loading its Lisp libraries

The README gives this Linux or Unix build command for the tail-call-optimized double-precision version. Run it where `tinylisp-opt.c` is available, such as the repository's `src` directory, and the command should produce a file named `tinylisp`.

bash
cc -o tinylisp tinylisp-opt.c

The default allocation is `N=1024` cells, described as approximately 8 KB. To request more memory, the README instructs the user to increase `N` in the C source and recompile. There is no command-line configuration in the documented build for that change.

The repository also provides `common.lisp`, `list.lisp`, and `math.lisp`. The documented command concatenates them and sends the result to the interpreter:

bash
cat common.lisp list.lisp math.lisp | ./tinylisp

The README places an important condition before this workflow: the `look` function must be changed to reopen `/dev/tty`, as described in Section 7 of `tinylisp.pdf`. Without that change, following the pipe-based loading instruction does not cover the terminal-input requirement documented by the project.

A first Tinylisp evaluation through the REPL

After compiling and starting `./tinylisp`, the first documented evaluation can use `eval` on a quoted arithmetic form. This confirms parsing, quotation, symbol lookup for the primitive `+`, and numeric evaluation without requiring the optional Lisp libraries.

lisp
(eval '(+ 1 2))

The README states that this expression evaluates to `3`. It is a small smoke test rather than a complete tutorial for the language. A reader can then compare ordinary list construction with the dotted-pair form:

lisp
(cons 1 (cons 2 ()))

The README documents that construction as equivalent to the list `'(1 2)`. For a complete evaluation, the closing parenthesis is required.

For more involved material, `src/list.lisp` depends on definitions in `src/common.lisp`, while `src/math.lisp` supplies additional mathematical functions. Examples under `examples/` cover areas such as factorials, flatten, Hanoi, sorting, accounting, application, and square root, but their filenames alone do not establish which examples work with every source variant.

Choosing a Tinylisp source for C or PC-G850

The repository layout makes variant selection part of adoption rather than an incidental build choice. `src/tinylisp.c` is the double-precision core, and `src/tinylisp-commented.c` presents the same general implementation in a verbose C style. `src/tinylisp-opt.c` is the optimized double-precision version referenced by the build command. `src/tinylisp-float.c` and `src/tinylisp-float-opt.c` provide single-precision counterparts, with the latter identified as optimized.

For the Sharp PC-G850(V)(S), `src/lisp850.c` uses BCD boxing and `src/lisp850-opt.c` is its optimized version. The README documents an audio-cassette deployment sequence using `bas2img`, `bin2wav`, and playback through `play`. That path is specific to supported Sharp hardware and its transfer workflow, not a general Linux installation procedure.

The extras sources serve yet another purpose. `src/tinylisp-extras.c` requires linking with `-lreadline`, while `src/tinylisp-extras-expand.c` also includes the article's Section 17 hygienic macros and is likewise documented as requiring `-lreadline`. The project therefore offers a compact educational core and larger teaching variants. Its wrong-tool case is a workload needing a mature language runtime, extensive standard library coverage, or deployment controls that these intentionally compact sources do not document.

Tinylisp maintenance, portability, and BSD-3-Clause use

The repository is not archived, and its last push was on 2026-08-27. The project has no GitHub releases, so there is no documented release cadence or packaged upgrade path to compare against the `main` branch. Maintenance judgments should therefore be tied to the source and documentation rather than to release frequency.

Tinylisp is written primarily in C and includes variants targeting desktop-style C compilation and the Sharp PC-G850. Portability details such as supported compiler versions, operating-system matrix, and production memory limits are not documented in the README. Likewise, the project does not present a general error-handling contract for application code. The extras version adds exceptions and CTRL-C break support, but those features should not be assumed in the 99-line core.

The repository lists the BSD-3-Clause license in `LICENSE.txt`. That identifier defines the project's stated licensing terms, including redistribution and modification conditions. Code copied into a product should be checked against the actual license text and the status of any separately incorporated libraries. The README also mentions Readline, but it does not state the library version or its license implications for downstream builds. Reviewing `LICENSE.txt` and the build dependencies remains necessary for compliance and maintenance planning.

Editorial conclusion

Adopt Tinylisp when the goal is to study a small interpreter, add Lisp behavior directly in C, or run a constrained embedded dialect. Do not treat it as a drop-in general-purpose Lisp runtime without first checking required language features, object representation, error handling, memory needs, and platform constraints. Based on the repository, the most important first check is the selected C source variant, its garbage collection model, and the build target: `tinylisp.c`, `tinylisp-opt.c`, `lisp850.c`, or one of the extras implementations.

Frequently asked questions

How do I compile Tinylisp?

The README documents `cc -o tinylisp tinylisp-opt.c` for the optimized double-precision implementation. The command creates an executable named `tinylisp`.

How much memory does Tinylisp allocate by default?

The default is `N=1024` cells, which the README describes as approximately 8 KB. Increasing `N` in the C source and recompiling increases the allocation.

Does Tinylisp have a REPL and garbage collection?

Yes. The README states that the interpreter includes a REPL and simple garbage collection. It also identifies a separate reference-counting garbage collector under `GC/README.md`.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. README
  4. Robert-van-Engelen/tinylisp on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/robert-van-engelen-tinylisp.svg)](https://hysenlabs.com/projects/robert-van-engelen-tinylisp)

Was this useful?