We assume here that read and the various printing operations are available as primitive machine operations, which is useful for our simulation, but completely unrealistic in practice. These are actually extremely complex operations. In practice, they would be implemented using low-level input-output operations such as transferring single characters to and from a device.

To support the get_global_environment operation we define

const the_global_environment = setup_environment();

function get_global_environment() {
    return the_global_environment;

[2] There are other errors that we would like the interpreter to handle, but these are not so simple. See exercise 5.30.
[3] We could perform the stack initialization only after errors, but doing it in the driver loop will be convenient for monitoring the evaluator's performance, as described below.
[4] Regrettably, this is the normal state of affairs in conventional compiler-based language systems such as C. In UNIX$^{\textrm{TM}}$ the system dumps core, and in DOS/Windows$^{\textrm{TM}}$ it becomes catatonic. The Macintosh$^{\textrm{TM}}$ displays a picture of an exploding bomb and offers you the opportunity to reboot the computer—if you're lucky.
5.4.4 Running the Evaluator