tLISP is a small lisp implementation in c. The main purpose was to learn lisp and learn how to build an interpreter and compiler.

Data Storage

Cells

All data is built up of cells. A cell is a piece of memory big enough to store a pointer. Only even number of cells can be allocated because type information is stored in the least significant three bits.

Cons

One of the most common data types is the cons. This is a pair of cells both storing data. This data can be accessed by the functions car and cdr.

+-----+-----+
| car | cdr |
+-----+-----+

Vectors

Another data type is the vector, this is a fixed length list. The first cell stores the length and the consequent cells store data. As cells can only be allocated in even numbers even length vectors need a dummy cell after the data.

+-----+------+------+
| len | data | .... |
+-----+------+------+

Data Types

Type information is stored in the 3 lsb of a pointer. Some data types aren’t pointer but store data in the pointer.

The data types are:

  • ERR

    The error type, used for returning and handling errors.

  • CONS

    The cons type, as explained above.

  • TEST: unused
  • INT

    The pointer in this cell points to a 64 bit integer stored in a cons.

  • SYM

    The pointer in this cell is an index into the symbol table.

  • FLT

    The pointer in this cell references a double stored in a cons cell.

  • SINT

    A 29 bit integer stored in this cell.

  • VEC

    This cell points to a vector.

Garbage Collector

Every lisp needs a garbage collector, tLISP uses a simple mark and sweep GC. All cells are allocated at startup and aranged in a continuous linked free-list.

Environment

The environment is a linked key value list containing pairs of (symbol . value).

cur-env is a cons, the car is the parent env, the cdr is a pointer to the current environment.

Bytecode

  • PUSH: pushes operand to stack
  • PUSH_VAR: pushes variable associated with operands symbol to stack
  • POP_VAR: pops the stack into a new variable
  • POP_SET: pops the stack into an existing variable
  • CALL: calls the function with operand args
  • PUSH_ENV: pushes the current env to the stack and creates a new one with the current env as top
  • POP_ENV: pops an environment of the stack and sets current.
  • RET: returns from function
  • JMP: jumps to offset in code
  • JF: jumps to offset if top of stack is nil