Lisra
Synopsis
A Lisp interpreter in Rascal.
Description
Writing a Lisp interpreter is a classical challenge. Popular word has that all large applications evolve until they include a Lisp interpreter. (A variant says the same about including an email client in every large application).
We will closely follow and reuse parts of Peter Norvig's excellent page on Lispy, a Lisp interpreter written in Python. The Lisp variant to be implemented is the following subset of the Scheme language:
Form | Syntax | Semantics and Example |
---|---|---|
variable reference | var | A symbol is interpreted as a variable name; its value is the variable's value. Example: x |
constant literal | number | A number evaluates to itself. Example: 12 |
quotation | (quote exp) | Return the exp literally; do not evaluate it. Example: (quote (a b c)) =>; (a b c) |
conditional | (if _test conseq alt_) | Evaluate test; if true, evaluate and return conseq; otherwise evaluate and return alt. Example: (if (< 10 20) (+ 1 1) (+ 3 3)) => 2 |
assignment | (set! _var exp_) | Evaluate exp and assign that value to var, which must have been previously defined (with a define or as a parameter to an enclosing procedure). |
definition | (define var exp) | Define a new variable in the innermost environment and give it the value of evaluating the expression exp. Examples: (define r 3) or (define square (lambda (x) (* x x))) |
procedure | (lambda (_var..._) exp) | Create a procedure with parameter(s) named var... and the expression as the body. Example: (lambda (r) (* r r)) |
sequencing | (begin _exp..._) | Evaluate each of the expressions in left-to-right order, and return the final value. Example: `(begin (set! x 1) (set! x (+ x 1)) (* x 2)) => 4 |
procedure call | (_proc exp..._) | If proc is anything other than one of the symbols if , set! , define , lambda , begin , or quote then it is treated as a procedure. It is evaluated using the same rules defined here. All the expressions are evaluated as well, and then the procedure is called with the list of expressions as arguments. Example: <`(square 12) => 144 |
In this table, var must be a symbol--an identifier such as x or square--and number must be an integer number, while the other italicized words can be any expression. The notation exp... means zero or more repetitions of exp.
A Lisp interpreter consists of the following parts:
- A parser that reads a Lisp program in text form and converts it to a runtime representation that is suitable for the interpreter.
- The interpreter itself that executes the program in runtime representation and computes its outcome.
- A pretty printer that converts the outcome in internal representation back to text.
- Finally, an interactive console is needed that interact with the user.
We discuss all these aspects: