Rabbit: A Compiler for Scheme/Chapter 2

[Page 25]

15 Z. The Source Language - SCHEME The basic language processed by RABBIT is a subset of the SCHEME language as described in [SCHEME] and [Revised Report], the primary restrictions being that the first argument to  must be quoted and that the multiprocessing primitives are not accommodated. This subset is summarized here.

SCHEME is essentially a lexically scoped ("full funarg") dialect of LISP.

Interpreted programs are represented by S-expressions in the usual manner.

Numbers represent themselves. Atomic symbols are used as identifiers (with the conventional exception of  and , which are conceptually treated as constants). All other constructs are represented as lists.

In order to distinguish the various other constructs, SCHEME follows the usual convention that a list whose car is one of a set of distinguished atomic symbols is treated as directed by a rule associated with that symbol. All other lists (those with non-atomic cars, or with undistinguished-atoms in their cars) are combinations, or function calls. All subforms of the list are uniformly evaluated in an unspecified order, and then the value of the first (the function) is applied to the values of all the others (the arguments). Notice that the function position is evaluated in the same way as the argument positions (unlike most other LISP systems). (In order to be able to refer to MacLISP functions, global identifiers evaluate to a special kind of functional object if they have definitions as MacLISP functions of the,  , or   varieties. Thus   evaluates to   because the values of the subforms are  ,  , and  ; and applying the first to the other two causes invocation of the MacLISP primitive  .) The atomic symbols which distinguish special constructs are as follows:

LAMBDA This denotes a function. A form

[Page 26]

IF QUOTE LABELS ASET'

16 will evaluate to a function of n arguments. The parameters  are identifiers (atomic symbols) which may be used in the body to refer to the respective arguments when the function is invoked. Note that a -expression is not a function, but evaluates to one, a crucial distinction.

This denotes a conditional form. evaluates the predicate, producing, a value  ; if   is non- , then the consequent   is evaluated, and otherwise the alternative. If  is omitted,   is assumed.

As in all LISP systems, this provides a way to specify any S-expression as a constant. evaluates to the S-expression. This may be abbreviated to, thanks to the MacLISP read-macro-character feature.

This primitive permits the local definition of one or more mutually recursive functions. The format is:

This evaluates the body in an environment in which the names refer to the respective functions, which are themselves closed in that same environment. Thus references to these names in the bodies of the -expressions will refer to the labelled functions. (Note Generalized ) This is the primitive side-effect on variables. evaluates the body, assigns the resulting value to the variable, and returns that value. {Note Non-quoted ) For implementation-dependent reasons, it is forbidden by RABBIT to use   on a global

[Page 27]

CATCH Macros 17 variable which is the name of a primitive MacLISP function, or cur a variable bound by. ( is actually used very seldom in practice anyway, and all these restrictions are "good programming practice". RABBIT could be altered to lift these restrictions, at some expense and labor.) This provides an escape operator facility. [Landin] [Reynolds]  evaluates the , which may refer to the variable  , which will denote an 'escape function' of one argument which, when called, will return from the  -form with the given argument as the value of the  -form. Note that it is entirely possible to return from the -form several times. This raises a difficulty with optimization which will be discussed later.

Any atomic symbol which has been defined in one of various ways to be a macro distinguishes a special construct whose meaning is determined by a macro function. This function has the responsibility of rewriting the form and returning a new form to be evaluated in place of the old one. In this way complex syntactic constructs can be expressed in terms of simpler ones.