|The Revised Maclisp Manual||Page A-4|
|Read-Eval-Print Loop||Concept||Interpreter Interaction|
Normally, when Maclisp is invoked as a job, it presents the user with what is called a read-eval-print loop. The purpose of this loop is to read expressions typed by the user on the terminal, evaluate them, and type the results back on the terminal. Such expressions may be entered to see what value they return or to produce a side-effect on the global environment.
A close approximation to the behavior of this toplevel loop is given by the following functional description:
The actual read-eval-print loop of Maclisp is somewhat more complex than the simple one defined here because it provides a few extra features (such as upkeep of the variables *, +, and -, described later in this chapter). The important point is that the primitives required for writing a read-eval-print loop are all available to the user. Syntactically correct lisp expressions have a well-defined mapping into normal lisp data structures (the READ function accomplishes this mapping). Data structures can be evaluated as program in a well-defined way (the EVAL function does this). Data structures can be displayed in a way which could later be typed back in to the lisp reader (the PRINT function does this). Giving the user the power to invoke all of these operations from his code is a very powerful feature of Lisp which sets it apart from most other languages.
Here is a sample console session (note that the semicolon character makes the rest of a line an arbitrary comment which is ignored by the Lisp reader):
;; Set the input/output radix to base-10 (default is base-8). ;; An example of evaluation for side-effect on the global environment. (SETQ BASE 10. IBASE 10. *NOPOINT NIL) NIL ;; Define a function for later use. ;; Another example of evaluation for side-effect. (DEFUN CUBE (X) (EXPT X 3)) CUBE ;; Evaluate an expression. ;; An example of evaluation just to see the value returned. (CUBE 3) 27.
For Interactive Use
The value of this symbol is the result of the last evaluation performed at top level or in a break loop which was not deeper than the current break loop. It is bound locally in each break loop. If an error occurs before a value for the input form has been computed, this symbol retains its previous value.
(SETQ FOOBAR '(FOO BAR)) => (FOO BAR)
(DEFUN FOO-BAR (X) X) => FOO-BAR
The value of this symbol is the previous form read at Lisp top level or in a break loop which was not deeper than the current break loop. It is bound locally in each break loop.
(SETQ FOO-BAR-BAZ-QUUX '(FOO BAR)) => (FOO BAR)
FOO-BAR-BAZ-QUUX => (NEW VALUE)
The value of this symbol is the current form being evaluated at Lisp top level or in a break loop. It is of somewhat limited usefulness.
|*BREAK||Function||(*BREAK flag msg)|
A breakpoint or break-loop is a full recursive invocation of the read-eval-print loop. S-expressions typed in will be evaluated and the results of evaluation will be printed just as at Lisp top level. A breakpoint is run within an ERRSET so that errors occurring within the breakpoint do not cause an unintended return from the break. Also, the state of the I/O system is saved prior to invocation of a breakpoint and restored upon return.
If (RETURN form) is typed in, the break loop will evaluate form and return the resulting value. Here's an example:
Note that RETURN is not executed as a function in this case; rather, a form whose car is RETURN is special-cased in this way by the break loop handler just as is the token $P. Here's an example to illustrate that:
Another way to return from a break is to throw to the tag BREAK. e.g.,
*BREAK can be used to allow user intervention in a program when something unexpected happens. It is used in this way by the LISP error system.
|BREAK||Special Form||(BREAK msg [flag])|
[PDP-10 Only] The value of the variable $P is a symbol which if typed at the toplevel of a breakpoint, terminates the breakpoint and returns NIL to the caller of the break. On Multics, this variable doesn't exist; the symbol $P is looked for explicitly by the breakpoint handler.
The obscure name was taken from the DDT debugging program for the PDP-10, which uses the command $P to mean “proceed the current job.”
Note: In PDP-10 implementations, the “$” in $P is an altmode. On Multics, it is a dollarsign.
The PDP-10 operating system on which MACLISP was developed was ITS, which used a user command shell called DDT that was also a debugger (hence the name). It was possible, by typing Control-Z, to temporarily stop a running program and return to DDT; if one wanted to proceed again with running that program, the DDT command was $P. This name choice must surely seem obscure by modern standards, but it was easy to type and easy to remember for the community that developed it.
Read-Eval-Print Status Options
|TOPLEVEL||Status Option||(STATUS TOPLEVEL)|
Returns the evaluable expression which is taking the place of the normal Lisp top-level Read-Eval-Print operation, or NIL if the normal Lisp Read-Eval-Print loop is in effect.
|TOPLEVEL||SStatus Option||(SSTATUS TOPLEVEL exp)|
Evaluates and returns exp and sets the top level form to this value. For example, one could replace the Read-Eval-Print loop with a Read-Factorial-Print loop by defining an appropriate definition of FACTORIAL and then doing:
|BREAKLEVEL||Status Option||(STATUS BREAKLEVEL)|
|BREAKLEVEL||SStatus Option||(SSTATUS BREAKLEVEL form)|
Read-Eval-Print Control Variables
[PDP-10 Only] If the value of READ is not NIL, it should be a function of 0 to 2 args which has the same calling conventions as READ and which is to be called in place of READ in the Lisp Read-Eval-Print loop.
The internal functions used by the system's read-eval-print loop have names which are accessible to the user. They are functions of 0 or 1 arg named *-READ-EVAL-PRINT, READ-*-EVAL-PRINT, READ-EVAL-*-PRINT, and READ-EVAL-PRINT-*, and are described elsewhere in this manual. To allow the user some control over the communication between these various functions, a series of hook variables are provided. Each hook variable has the same name as the function which it precedes. A description of these hook variables follows.
[PDP-10 Only] If not NIL, this variable holds the name of a function of no arguments which is to be run prior to the READ part of each cycle through the read-eval-print loop. The function's return value is ignored.
[PDP-10 Only] If not NIL, this variable holds the name of a function of one argument which is to be run prior to the EVAL part of each cycle through the read-eval-print loop. Its argument is the form read by the *-READ-EVAL-PRINT part of the loop, and its return value becomes the argument to the READ-*-EVAL-PRINT function.
;; In an embedded language, one might want to call a different ;; evaluator. (defun dummy-eval (exp) (list 'dummy-result exp)) => DUMMY-EVAL ;; Test our `evaluator'... (dummy-eval '(f x 3)) => (DUMMY-RESULT (F X 3)) ;; Now set things up so that user gets prompted for input nicely and ;; everything he types is DUMMY-EVAL'd instead of Lisp EVAL'd. (setq read-*-eval-print #'(lambda (exp) `(dummy-eval ',exp)) *-read-eval-print #'(lambda nil (princ "> "))) => (LAMBDA NIL (PRINC "> ")) > (foo 3) => (DUMMY-RESULT (FOO 3))
[PDP-10 Only] If not NIL, this variable holds the name of a function of one argument which is to be run prior to the PRINT part of each cycle through the read-eval-print loop. Its argument is the evaluted form returned by the *-READ-EVAL-PRINT part of the loop, and its return value becomes the argument to the READ-EVAL-*-PRINT function.
;; Saving output lines (let ((temp (make-list 5))) ; We want to remember the last 5 forms (setq the-outputs (nconc temp temp) ; Make it a circular list read-eval-*-print #'(lambda (x) (setq the-outputs (nthcdr 4. the-outputs)) (rplaca the-outputs x) x)) (defun last-output (&optional (n 0)) (nth n the-outputs)) 'all-set) => ALL-SET (+ 3 4) => 7 (list (last-output) (last-output 1)) => (7 ALL-SET)
[PDP-10 Only] If not NIL, this variable holds the name of a function of no arguments and whose return value is ignored. It is to be run prior to a call to the READ-EVAL-PRINT-* subr, which performs the trailing part of each cycle through the read-eval-print loop.
|The Revised Maclisp Manual (Sunday Morning Edition)|
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.