Handwritten Lisp Compiler in Java


Click here to find out how I made this project

Introduction

I have a keen interest in compilers, programming languages and the Java Virtual Machine (JVM) in particular. Here I present my own implementation of the Lisp programming language, written completely from scratch in Java. Please read my writeup linked at the top of this page to learn the details of how I implemented my compiler.

Perhaps the most interesting aspect of my implementation is the fact my compiler compiles Lisp code directly to JVM bytecode meaning my Lisp can, in theory, reach Java-like levels of performance.

What follows are example programs written in my dialect of Lisp. You can run them in your browser by clicking the 'Run code' button. I encourage you to play with the examples and customise them.

When you click 'Run code' each program will be sent to a server which will call my compiler, compile your code, execute it in an instance of the JVM and send the result back to your browser.

Each example which follows demonstrates one feature of my Lisp implementation.

Example Code

The first step in learning any programming language is printing 'Hello World' to the screen. Here's how to do it in my version of Lisp.

                
This example shows how to add numbers together. Lisp is unusual compared to most languages because prefix rather than infix notation is used.

                
My Lisp supports comments, like most languages. You can create a single-line comment using the semicolon character.

                
Almost everything in Lisp is a list. A list is anything surrounded by parentheses.

                
The 'quote' special form is important in Lisp. It returns its argument, unevaluated. A surprisingly important and useful property in Lisp code.

                
My Lisp supports comparisons between values to see if they are equal using the '=' function.

                
My Lisp also supports the 'if' special form, meaning code branching is possible.

                
Variables are supported too. You can use the 'def' special form to create a variable. In the next example I create two variables, print their values and add them together.

                
Almost everything in Lisp is a list, specifically a linked list. You can move through lists using the builtin functions 'car' and 'cdr'. 'car' and 'cdr' are traditional Lisp functions, 'car' means return the head of the list and 'cdr' means return the tail of the list.

                
One of the best parts of Lisp are its macros. Lisp macros make it possible for a program to rewrite itself. We can use a macro to add support for infix notation to Lisp. This example shows how to create a macro which will rewrite an infix mathematical expression to the prefix notation Lisp requires.

                
My Lisp supports user-defined functions using the builtin 'func' macro, an implementation of the Fibonacci function is shown below.

                
My Lisp also supports defining functions within the list where they're used. This is done using the 'lambda' special form.

                
In common with many Lisps and functional languages, looping is possible using tail recursion.

                

Thank you for reading about my Lisp implementation, I hope you enjoyed playing with the example code. If you would like to learn more please read my writeup here.

You can find all of the source code for my Lisp implementation on my GitHub here https://github.com/FrancisMcN/fsp