While regular languages expose compiler/interpreter as a single black box (text in, executable out), Lisp exposes two black boxes: reader and evaluator.
The reader defines how strings are translated into Lisp objects (s-expressions). The evaluator defines the semantics of Lisp forms that are built out of s-expressions.
This has multiple consequences:
- s-expressions can be used as a data serialization format (not necessarily code)
because semantics are defined in terms of Lisp objects, it’s easier to generate code within the language than to generate code as text.
- you can easily generate code by manipulating data and that is the basis of Lisp macros