Newsgroups: comp.lang.scheme
Path: cantaloupe.srv.cs.cmu.edu!rochester!cornellcs!newsfeed.cit.cornell.edu!newsstand.cit.cornell.edu!news.kei.com!hookup!nstn.ns.ca!news.cs.indiana.edu!dyb@cs.indiana.edu
From: "R. Kent Dybvig" <dyb@cs.indiana.edu>
Subject: Re: syntatic sugar or language extensions -- how to construct?
Message-ID: <199511090310.WAA05898@garbo.cs.indiana.edu>
Organization: Computer Science, Indiana University
References: <m2g2g11cjl.fsf@namaste.sps.mot.com>
Date: Wed, 8 Nov 1995 22:10:44 -0500 (EST)
Lines: 73

norton@namaste.sps.mot.com (Joe Norton) writes:

>I'm trying to implement a slightly modified version of SICP's digital
>simulator example.  I would like to be able to parse and handle a
>hierarchical circuit description.  For example, I would like to
>express a single subcircuit as follows:

This can be defined as a syntactic extension using syntax-case.  The
code below implements at least an approximation of what you want.  I
extrapolated from your example to the general case, and I may have
extrapolated improperly in places.  If so, this can likely be fixed
easily enough.  I took the liberty of changing the input syntax
slightly, (1) to remove the quotes, which aren't necessary when
defining syntactic extensions, and (2) to make the internal variable x
used in your code an explicit part of the syntax.  If you really want
to hardwire it to x, that can be done easily enough as well.  Here's
how your sample input looks using the modified syntax:

(subckt nor2 x (a b c) (wp: 32 lp: 4 wn: 16 ln: 4)
        (pmos m1 (vdd a x vdd) (:l lp :w wp))
        (pmos m2 (x b c vdd) (:l lp :w wp))
        (nmos m3 (c a vss vss) (:l ln :w wn))
        (nmos m4 (c b vss vss) (:l ln :w wn)))

With the definition for subckt below, this expands into the definition
shown in your note.

(define-syntax subckt
  (lambda (x)
    (define uncolonize
      (lambda (id)
        (datum->syntax-object id
          (string->symbol
            (list->string
              (remv #\:
                (string->list
                  (symbol->string (syntax-object->datum id)))))))))
    (define parse-keys
      (lambda (keys)
        (syntax-case keys ()
          (() (syntax ()))
          ((id: val more ...)
           (with-syntax ((id (uncolonize (syntax id:))))
             (cons (syntax (id (get-keyword id: props val)))
                   (parse-keys (syntax (more ...)))))))))
    (syntax-case x ()
      ((_ subcurcuit-name node-name (id ...) keys 
            (kind mn (a ...) (b ...)) ...)
       (with-syntax (((binding ...) (parse-keys (syntax keys))))
         (syntax
           (define (subcurcuit-name path id ... . props)
             (let (binding ...)
               (let ((node-name (make-node path 'node-name)))
                 (kind (cons 'mn path) a ... b ...) ...)))))))))

The definition uses the local procedure parse-keys to parse the key,
value pairs in keys.  parse-keys uses uncolonize, in turn, to strip
the colons from the keywords.  If the set of keywords is fixed and
known to subckt, we could look for and replace them directly with
syntax-case in parse-keys.  In fact, we could then write subckt with
the less general syntax-rules, although the definition would be less
straigthforward.

Since syntax-case preserves lexical scoping, the introduced local
variables path and props cannot be captured inadvertantly even if
subcircuit-name, node-name, or any of the other visible identifiers
happens to be named path or props.

Kent

R. Kent Dybvig                 | Computer Science Department
dyb@cs.indiana.edu             | Indiana University
812/855-8653                   | Bloomington, IN 47405 USA
