[comp.lang.scheme.c] Macros in MIT-Scheme

gary@milo.mcs.clarkson.edu (Gary Levin) (01/26/89)

Does anyone have a description of the macro facilities of MIT-Scheme?
It appears that you make changes in the syntax-tables, but I have been
unable to find any definitions of the facilities in the distribution
that I FTP'ed.

In particular, what environments are used when in the macro expansion
phase?  I have some code that is distributed with TI-Scheme that I
would like to port to MIT-Scheme, but the macro conventions are
different.  The problem I seem to face is that one of the macros in
the code expands to a macro definition and the body is being evaluated
in the wrong environment.

Along related lines, does anyone have the extend-syntax commands
written for MIT-Scheme.  This is the code I am trying to port
(originally written by Dybvig, included in the TI distribution).
Eventually I would like to see a proper definition of MIT-Scheme's
macros, but with extend-syntax, I'd be able to do most of what is
needed anyway.

For those who have not seen extend-syntax, or who don't recognize it
by name, here is a famous example.

   (extend-syntax (let)
      ( (let ( (v e) ... )   b1 b2 ...)
        ( (lambda (v ...) b1 b2 ...) e ...)
   )  )

This defines `let' as an application of a lambda expression.  The
ellipsis is part of the syntax.  Nice feature.
--
Gary Levin/Dept of Math & CS/Clarkson Univ/Potsdam, NY 13676/(315) 268-2384
BitNet: gary@clutx   Internet: gary@clutx.clarkson.edu

jinx@CHAMARTIN.AI.MIT.EDU (Guillermo J. Rozas) (01/28/89)

    Does anyone have a description of the macro facilities of MIT-Scheme?
    It appears that you make changes in the syntax-tables, but I have been
    unable to find any definitions of the facilities in the distribution
    that I FTP'ed.

    In particular, what environments are used when in the macro expansion
    phase?

The following description matches release 6.2.2.  There probably won't
be many user visible changes for release 7.

The interpreter interprets a language called "Scode".  The syntaxer
(invoked with the procedure SYNTAX) translates list structure
representing Scheme expressions to Scode.  The syntaxer is guided in
this process by a structure called a "syntax table", which defines the
transformations between various special forms and Scode.  A list whose
first element is not a keyword defined in the syntax table is assumed
to be a procedure application, and is translated accordingly.
Individual symbols are assumed to represent variable references.

The basic operations on syntax tables are:

(MAKE-SYNTAX-TABLE #!optional parent-syntax-table)
(SYNTAX-TABLE-REF syntax-table keyword)
(SYNTAX-TABLE-DEFINE syntax-table keyword expander)

The expander must be a procedure taking S-expressions as input and
producing Scode.  For convenience there is a macro called MACRO
similar to LAMBDA which wraps the body of the expander in the
appropriate code to translate into Scode.  For example,

(syntax-table-define <some syntax table> 'FOO
  (macro (x y z)
    `(list ,z (+ ,x ,y))))

adds a new keyword (FOO) to <some syntax table> with the obvious meaning.
Note that

(syntax-table-define <some syntax table> 'FOO
  (lambda (x y z)
    `(list ,z (+ ,x ,y))))

would not have the same effect, since there is no translation to Scode
here, and lists are not necessarily valid Scode.

The base syntax table is the value of the variable
SYSTEM-GLOBAL-SYNTAX-TABLE.  The syntax table of the read eval print
loop (usually a child of SYSTEM-GLOBAL-SYNTAX-TABLE) is returned by
the procedure named REP-SYNTAX-TABLE.  Therefore, a way to install a
"macro" in the syntax table used to translate keyboard input is to
type

(syntax-table-define (rep-syntax-table) 'FOO
  (macro (x y z)
    `(list ,z (+ ,x ,y))))

Note that the expression producing the expander is evaluated in the
same environment where the whole expression is evaluated, since
SYNTAX-TABLE-DEFINE is not a special form keyword.

The recommended way of extending syntax tables is to have a bunch of
SYNTAX-TABLE-DEFINE expressions in a file, and this file can be loaded
into any appropriate environment.

Since files are, theoretically, translated as a unit before they are
evaluated, and SYNTAX-TABLE-DEFINE is not a special form keyword, a
SYNTAX-TABLE-DEFINE expression appearing in a file should have no
effect on the rest of the file.

The syntax table according to which an expression (or a file) is
translated can be manipulated by using the following special forms:

(USING-SYNTAX <some syntax table>
  . <forms>)

<some syntax table> is evaluated at translation time in a special
enviroment (called syntax-environment) and should produce a valid
syntax table.  The rest of the form is translated according to this
syntax table.

(LET-SYNTAX ((<keyword1> <expander1>)
             (<keyword2> <expander2>) ...)
  . <forms>)

LET-SYNTAX makes a new syntax table with the bindings expressed by the
<keyword> <expander> pairs.  This new syntax table has as its parent
the syntax table used to expand the LET-SYNTAX itself.  The forms are
then expanded in this syntax table.  Note that the expanders are just
like the expanders given to SYNTAX-TABLE-DEFINE, and are therefore
usually created by using the MACRO special form.  They are evaluated
(closed) in the syntaxer environment.

Some suggestions:

LET-SYNTAX should be used only for relatively trivial things.  For
more complicated things, the code should be split into two files.  One
file should contain the code that creates and modifies syntax tables
to provide the new syntactic features.  The other file should contain
the desired code with the relevant parts surrounded by appropriate
USING-SYNTAX forms.

In this way the file that defines the syntactic extensions has
convenient control of the environment, since it contains "normal"
Scheme code (a bunch of definitions, usually).

Note also that the expression producing the syntax table in a
USING-SYNTAX expression is evaluated in the syntaxer environment,
which does not have the usual user environment as its parent,
therefore a good way to reference user defined sytnax tables is to use
the idioms

(using-syntax (access my-syntax-table user-initial-environment)
  . <forms>)

(using-syntax (access my-syntax-table (rep-environment))
  . <forms>)