4
votes

I'm reviving an old LISP program from the early 1980s. (It's the Nelson-Oppen simplifier, an early proof system. This version was part of the Ford Pascal-F Verifier, and was running in Franz LISP in 1982.) Here's the entire program:

https://github.com/John-Nagle/pasv/tree/master/src/CPC4

I'm converting the code to run under clisp on Linux, and need some advice. Most of the problems are with macros. Here's today's question.

DEFSMAC and DEFMAC

More old Stanford AI Lab macros, to make macro definition easier before defmacro became part of the language. The macros, and their documentation, is here:

https://github.com/John-Nagle/pasv/blob/master/src/CPC4/defmac.l

These are macros which generate more macros.

;;; defmac (define macro) and defsmac (define simple macro) are like defun,
;;; but they define the function as a macro instead of as an expr.  They are
;;; less powerful then defining a macro directly (for example, they cannot be
;;; used to define macros with arbitrarily many arguments) but are easier to
;;; use.   For example,
;;; 
;;; (defsmac f (x y) (foo (bar x) (bar y)))
;;; 
;;; causes f to be defined as a macro in such a way that every call (f e1 e2)
;;; will expand to (foo (bar e1) (bar e2)) before it is evaluated.

(defun defsmac macro (args)
       (defsmac1 (cadr args) (caddr args) (cdddr args)))


(defun defsmac1 (name formals body)
       `(defun ,name macro (app) 
                     ,(defsmac2 formals
                                  (cond ((cdr body) (cons 'progn body)) 
                                        (t (car body))))))

(defun defsmac2 (formals body)
       `(sublis  ,(defsmac3 formals 1) (quote ,body)))

(defun defsmac3 (formals n)
       (cond ((null formals) nil)
             (`(cons (cons (quote ,(car formals)) (car ,(defsmac4 n)))
                           ,(defsmac3 (cdr formals) (1+ n))))))

(defun defsmac4 (n) (cond ((= n 0) 'app) ((list 'cdr (defsmac4 (1- n))))))

Straightforward conversion to "defmacro" doesn't work. I'm not clear on how the "defun with macro" thing worked. It's documented on page 46 of

http://www.softwarepreservation.org/projects/LISP/franz/Franz_Lisp_July_1983.pdf

but that's not too helpful. It's not clear how the argument list is handled. Taken literally, the old documentation seems to say that the ''number'' of arguments is passed in, not the args themselves. That can't be the right interpretation.

The above code seems to assume that the regular defun-defined functions are available during macro processing. But Common LISP doesn't allow that, does it?

I'm looking for a general way to convert old-style Franz LISP/MacLISP macros to modern Common LISP. Suggestions?

2
You can use (eval-when (:compile-toplevel) ...) to execute code in the compile-time environment. These functions can be used in macro processing.Barmar
Google "ftoc franz common lisp". Not sure you can still find it, though.Drew

2 Answers

2
votes

I got a useful answer from "pwd" on Hacker News:

(defmacro defsmac (name params &rest expr)
      `(defmacro ,name ,params
         `,(cons 'progn (sublis (mapcar 'cons ',params 
              (list ,@params))  ', expr))))

This seems to work.

1
votes

Use eval-when to define functions in the compiler environment, so they can be used during macro expansion.

(eval-when (:compile-toplevel :load-toplevel :execute)
    (defun defsmac1 (name formals body)
           `(defmacro ,name (app) 
                         ,(defsmac2 formals
                                      (cond ((cdr body) (cons 'progn body)) 
                                            (t (car body))))))

    (defun defsmac2 (formals body)
           `(sublis  ,(defsmac3 formals 1) (quote ,body)))

    (defun defsmac3 (formals n)
           (cond ((null formals) nil)
                 (`(cons (cons (quote ,(car formals)) (car ,(defsmac4 n)))
                               ,(defsmac3 (cdr formals) (1+ n))))))

    (defun defsmac4 (n) (cond ((= n 0) 'app) ((list 'cdr (defsmac4 (1- n))))))
)