From: Sreedhar Reddy
Subject: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <7cc1d291.0308272327.6990841f@posting.google.com>
Hi,

Let us suppose say a function is defined as described below:

������� cl-user(1): (defun sayHello()
������������������������(print "Hello"))
������� SAYHELLO
������� 
������� cl-user(2):(fdefinition 'sayHello)
������� #<Interpreted Function SAYHELLO>
������� 
������� cl-user(3):
������� 
������� 
Now, I am interested to get the actual function definition (lisp
code),
which is similar to the functionality of "disassemble" (the
disassemble
returns the assembly code, I am interested to retrieve the lisp code).

��������cl-user(4): (disassemble 'sayHello)

��������������� ;; disassembly of #<Function (:ANONYMOUS-LAMBDA 0) @
��������������� #x715d1cd2>
��������������� ;; formals: 
��������������� ;; constant vector:
��������������� 0: "Hello"
��������������� 1: PRINT
��������������� 
��������������� ;; code start: #x715d1c8c:
������������������ 0: 55��������� pushl�ebp
������������������ 1: 8b ec������ movl��ebp,esp
������������������ 3: 56��������� pushl�esi
������������������ 4: 83 ec 24��� subl��esp,$36
������������������ 7: e3 02������ jcxz��11
������������������ 9: cd 61������ int���$97������������ ;
��������������� EXCL::TRAP-ARGERR
����������������� 11: 80 7f 97 00 cmpb��[edi-105],$0��� ;
��������������� SYS::C_INTERRUPT
����������������� 15: 74 02������ jz����19
����������������� 17: cd 64������ int���$100����������� ;
��������������� EXCL::TRAP-SIGNAL-HIT
����������������� 19: 8b 46 12��� movl��eax,[esi+18]��� ; "Hello"
����������������� 22: 8b 5e 16��� movl��ebx,[esi+22]��� ; PRINT
����������������� 25: b1 01������ movb��cl,$1
����������������� 27: ff d7������ call��*edi
����������������� 29: c9��������� leave
����������������� 30: 8b 75 fc��� movl��esi,[ebp-4]
����������������� 33: c3��������� ret
��������������� 
Is there any function or set of steps to get the lisp code?  I am
using Allegro CL 6.2.

Thanks,

-Sreedhar Reddy

From: Friedrich Dominicus
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <87ptiq1ao0.fsf@fbigm.here>
Have you tried a macroexpand on the code? 

Regards
Friedrich
From: Barry Margolin
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <9Vo3b.463$mD.118@news.level3.com>
In article <····························@posting.google.com>,
Sreedhar Reddy <············@yahoo.com> wrote:
>Now, I am interested to get the actual function definition (lisp
>code),
>which is similar to the functionality of "disassemble" (the
>disassemble
>returns the assembly code, I am interested to retrieve the lisp code).

Try FUNCTION-LAMBDA-EXPRESSION.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Sreedhar Reddy
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <7cc1d291.0308290258.3b3c391c@posting.google.com>
Thanks all for the responses to my mail.

I have used the standard function "function-lambda-expression" and
written function which will return the desired result.

The function is:

        ;;; Retrieves the defun definition
        (defun get-defun-def(fun-name)
        
         
          (let ((res "")
                (arg "")
                )
               (dolist (x (cddar (cddr (function-lambda-expression
        (fdefinition fun-name)))))
               (setf res (concatenate 'string res (format nil "~S" x))))
               (setf arg (format nil "~S" (excl::arglist fun-name)))
               (if (equal arg "NIL") (setf arg "()"))
               (concatenate 'string "( DEFUN " (symbol-name fun-name)
        arg " " res " )")
           )
        )
        
        
Sample runs:
============

Example-1:
    CL-USER(138): (defun sayHello()
                        (print "Hello"))
    SAYHELLO
   
   CL-USER(139): (get-defun-def 'sayHello)
   "( DEFUN SAYHELLO() (PRINT \"Hello\") )" 

Example-2:

CL-USER(143): (defun sayArgs(arg1 arg2)
(print arg1)
(print arg2))
SAYARGS

CL-USER(144): (get-defun-def 'sayArgs)
"( DEFUN SAYARGS(ARG1 ARG2) (PRINT ARG1)(PRINT ARG2) )"

Please note the attached file has the above code.

Thanks,

Manikanti Sreedhar Reddy



Barry Margolin <··············@level3.com> wrote in message news:<················@news.level3.com>...
> In article <····························@posting.google.com>,
> Sreedhar Reddy <············@yahoo.com> wrote:
> >Now, I am interested to get the actual function definition (lisp
> >code),
> >which is similar to the functionality of "disassemble" (the
> >disassemble
> >returns the assembly code, I am interested to retrieve the lisp code).
> 
> Try FUNCTION-LAMBDA-EXPRESSION.
From: Kaz Kylheku
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <cf333042.0308291422.6f911c5@posting.google.com>
············@yahoo.com (Sreedhar Reddy) wrote in message news:<····························@posting.google.com>...
> Thanks all for the responses to my mail.
> 
> I have used the standard function "function-lambda-expression" and
> written function which will return the desired result.
> 
> The function is:
> 
>         ;;; Retrieves the defun definition
>         (defun get-defun-def(fun-name)
>         
>          
>           (let ((res "")
>                 (arg "")
>                 )
>                (dolist (x (cddar (cddr (function-lambda-expression
>         (fdefinition fun-name)))))
>                (setf res (concatenate 'string res (format nil "~S" x))))
>                (setf arg (format nil "~S" (excl::arglist fun-name)))
>                (if (equal arg "NIL") (setf arg "()"))
>                (concatenate 'string "( DEFUN " (symbol-name fun-name)
>         arg " " res " )")
>            )
>         )

Here is a way of doing this, which avoids the cadavers, and the use of
string processing as a messy substitute for list processing:

   (defun get-function-as-string (function)
     (let ((lambda-expr (function-lambda-expression function)))
       (destructuring-bind (lambda-sym lambda-list &rest body)
lambda-expr
         (declare (ignore lambda-sym))
         ;; exercise for reader: parse body to remove any declarations
         ;; that were added by the DEFUN macro.
         (format nil "~S" `(defun ,lambda-list ,@body)))))

I don't understand why the source code must be a character string
rather than remain in list form. One chief advantage of Lisp is that
source code is represented as a data structure. Whenever possible, you
deal with the character form only at the input/output boundary.
From: Sreedhar Reddy
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <7cc1d291.0309020347.515b4836@posting.google.com>
Hi,

Taking the advantage of lisp representation, it is always better for
the function to return the result in the same form.

Thanks again,

-Sreedhar Reddy

···@ashi.footprints.net (Kaz Kylheku) wrote in message news:<···························@posting.google.com>...
> ············@yahoo.com (Sreedhar Reddy) wrote in message news:<····························@posting.google.com>...
> > Thanks all for the responses to my mail.
> > 
> > I have used the standard function "function-lambda-expression" and
> > written function which will return the desired result.
> > 
> > The function is:
> > 
> >         ;;; Retrieves the defun definition
> >         (defun get-defun-def(fun-name)
> >         
> >          
> >           (let ((res "")
> >                 (arg "")
> >                 )
> >                (dolist (x (cddar (cddr (function-lambda-expression
> >         (fdefinition fun-name)))))
> >                (setf res (concatenate 'string res (format nil "~S" x))))
> >                (setf arg (format nil "~S" (excl::arglist fun-name)))
> >                (if (equal arg "NIL") (setf arg "()"))
> >                (concatenate 'string "( DEFUN " (symbol-name fun-name)
> >         arg " " res " )")
> >            )
> >         )
> 
> Here is a way of doing this, which avoids the cadavers, and the use of
> string processing as a messy substitute for list processing:
> 
>    (defun get-function-as-string (function)
>      (let ((lambda-expr (function-lambda-expression function)))
>        (destructuring-bind (lambda-sym lambda-list &rest body)
> lambda-expr
>          (declare (ignore lambda-sym))
>          ;; exercise for reader: parse body to remove any declarations
>          ;; that were added by the DEFUN macro.
>          (format nil "~S" `(defun ,lambda-list ,@body)))))
> 
> I don't understand why the source code must be a character string
> rather than remain in list form. One chief advantage of Lisp is that
> source code is represented as a data structure. Whenever possible, you
> deal with the character form only at the input/output boundary.
From: Adam Warner
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <pan.2003.08.29.12.28.02.233661@consulting.net.nz>
Hi Sreedhar Reddy,

> Thanks all for the responses to my mail.
> 
> I have used the standard function "function-lambda-expression" and
> written function which will return the desired result.
> 
> The function is:
> 
>         ;;; Retrieves the defun definition
>         (defun get-defun-def(fun-name)
>         
>          
>           (let ((res "")
>                 (arg "")
>                 )
>                (dolist (x (cddar (cddr (function-lambda-expression
>         (fdefinition fun-name)))))
>                (setf res (concatenate 'string res (format nil "~S" x))))
>                (setf arg (format nil "~S" (excl::arglist fun-name)))
>                (if (equal arg "NIL") (setf arg "()"))
>                (concatenate 'string "( DEFUN " (symbol-name fun-name)
>         arg " " res " )")
>            )
>         )

Here's what the above code should look like formatted in a standard manner:

;;; Retrieves the defun definition
(defun get-defun-def (fun-name)
  (let ((res "")
        (arg ""))
    (dolist (x (cddar (cddr (function-lambda-expression
                             (fdefinition fun-name)))))
      (setf res (concatenate 'string res (format nil "~S" x))))
    (setf arg (format nil "~S" (excl::arglist fun-name)))
    (if (equal arg "NIL") (setf arg "()"))
    (concatenate 'string "( DEFUN " (symbol-name fun-name)
                 arg " " res " )")))

You will soon learn that regardless of the contents of this function it
doesn't appear to have the flow of a "good" function.

If you check out FUNCTION-LAMBDA-EXPRESSION in the HyperSpec you will
find that "The lambda expression may have been pre-processed in some ways,
but it should remain a suitable argument to compile or function. Any
implementation may legitimately return nil as the lambda-expression of any
function."

Thus you shouldn't expect that the information will always be around,
especially when loading a compiled file.

For example, put this into a file test.lisp:
(defun test ()
  (print "Hello"))

Now:
* (compile-file "test")
...
* (load "test")
...
* (test)

"Hello" 
"Hello"
* (function-lambda-expression #'test)

nil
t
test

The function's defining lambda expression has been lost. Compare this to
the approach of storing the information in the function's property list.
Put this into a file test2.lisp:
(defmacro defun-grab (name lambda-list &body body)
  (let ((defun-form `(defun ,name ,lambda-list ,@body)))
    `(progn
       ,defun-form
       (setf (get ',name 'source) ',defun-form))))

(defun-grab test ()
  (print "Hello"))

Now:

* (compile-file "test2")
...
* (load "test2")
...
* (get 'test 'source)

(defun test () (print "Hello"))

In this case we see the information is still available. To overcome the
previous limitation you could have tried storing the function's
defining lambda expression while it was still available (assuming it
ever was: "Any implementation may legitimately return nil")

Note that all my examples have been produced in the readtable case :invert
mode: (setf (readtable-case *readtable*) :invert)

In this case-distinguishing mode the reader inverts the case of
all-lowercase and all-uppercase strings. Mixed-case strings remain in
their original case. The case of all-lowercase and all-uppercase symbols
is inverted when printed. This provides a standards-compliant way to
preserve case information, refer to built-in symbols using lower case code
and print out symbols in their original case.

[Franz also provides images designed for a "modern" mode that are not
ANSI Common Lisp compatible]

Regards,
Adam
From: Adam Warner
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <pan.2003.08.29.13.48.57.84601@consulting.net.nz>
> Note that all my examples have been produced in the readtable case
> :invert mode: (setf (readtable-case *readtable*) :invert)
> 
> In this case-distinguishing mode the reader inverts the case of
> all-lowercase and all-uppercase strings. Mixed-case strings remain in
> their original case. The case of all-lowercase and all-uppercase symbols
> is inverted when printed. This provides a standards-compliant way to
> preserve case information, refer to built-in symbols using lower case
> code and print out symbols in their original case.

Improved paragraph (I want to remove the impression that "strings" are
inverted when I am in fact referring to the source code):

In this case-distinguishing mode the reader inverts the case of
all-lowercase and all-uppercase source when generating symbol names.
Symbols composed with mixed-case letters are left in their original case.
The case of all-lowercase and all-uppercase symbols is inverted when
printed. This provides a standards-compliant way to preserve case
information, refer to built-in symbols using lower case code and print out
symbols in their original case.

<http://www.lispworks.com/reference/HyperSpec/Body/f_rdtabl.htm>
<http://www.lispworks.com/reference/HyperSpec/Body/23_aba.htm>
<http://www.lispworks.com/reference/HyperSpec/Body/22_accba.htm>

So with the :invert mode and Sreedhar Reddy's sayHello example
(and ignoring package issues):

   (defun sayHello ()
     (print "Hello"))

defun is read in as the symbol DEFUN
sayHello is read in as the symbol sayHello
print is read in as the symbol PRINT

And as the symbols DEFUN, sayHello and PRINT are printed back as defun,
sayHello and print everything appears in its original case.

Final tip: mixed case symbols are generally bad Lisp style. sayHello
could instead be rewritten as say-hello. Being able to distinguish
between symbols that only differ by case may be useful when duplicating a
domain-specific language. LaTeX is a pathological example (e.g.
\large, \Large and \LARGE specify three different sizes of type).

It's also possible to escape characters to preserve a symbol's case
whatever the readtable mode.

Regards,
Adam
From: Adam Warner
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <pan.2003.08.28.08.52.56.474696@consulting.net.nz>
Hi Sreedhar Reddy,

> Now, I am interested to get the actual function definition (lisp code).

The original code is not required at runtime so you want a way to
explicitly store it. Macros to the rescue. Here's a quality solution
(improved as you can see by Martin Simmons):

;; From Martin Simmons, Xanalys Software Tools: "The defun won't be
;; evaluated if you quote the list.  Depending on how it will be used,
;; I would probably do it differently:"
(defmacro defun-grab (name lambda-list &body body)
  (let ((defun-form `(defun ,name ,lambda-list ,@body)))
    `(progn
       ,defun-form
       (setf (get ',name 'source) ',defun-form))))

* (defun-grab sayHello() (print "Hello"))

(defun sayHello () (print "Hello"))
* (sayHello)

"Hello" 
"Hello"
* (get 'sayHello 'source)

(defun sayHello () (print "Hello"))

The original source code is stored in the property list of the function.
If you want it to be completely transparent you could shadow the original
DEFUN.

Regards,
Adam
From: Adam Warner
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <pan.2003.08.28.10.47.41.477435@consulting.net.nz>
> (get 'sayHello 'source)
> 
> (defun sayHello () (print "Hello"))
> 
> The original source code is stored in the property list of the function.

To express this more accurately, the list structure of the source code is
being stored in the property list of the function after it has been
interpreted by the Lisp reader. Do not confuse this approach with storage
of the actual text/ASCII/Unicode input.

To see the difference consider this function:

* (defun-grab foo () #x1000)

(defun foo () 4096)

1000 in hexadecimal is 4096 in base 10. To Lisp both are the same integer
and are equivalent after they have been processed by the reader:

* (eql #x1000 4096)

t

And to emphasise that you are able to operate on the elements of the function
definition:

;;; A simple list walker and accumulator. This remarkable version was
;;; produced by Kent M Pitman in 1999.
(defun collapse-list (list)
  (loop for item in list
        when (atom item)
        collect item
        else nconc (collapse-list item)))

* (loop for element in (collapse-list (get 'sayHello 'source))
        do (format t "Element ~S is type ~S~%" element (type-of element)))
Element defun is type symbol
Element sayHello is type symbol
Element nil is type null
Element print is type symbol
Element "Hello" is type (simple-base-string 5)
nil

Regards,
Adam
From: Sreedhar Reddy
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <7cc1d291.0308290506.34fec033@posting.google.com>
This is what I defined:

(eval-when (load eval compile)
  (shadow '(defun))
    (defmacro DEFUN (&whole tot name &rest body)     
    `(eval-when (load eval compile)
       (setf (get ',name 'source) ',tot)
	 (format t "~%the name is : ~a" ',name)
	 (format t "~%The defun is : ~S " ,tot))
       (lisp:defun ,name ,@body))))

CL-USER(142): (defun sayHello(name)
  (print name))
the name is : SAYHELLO
The defun is : (DEFUN SAYHELLO (NAME) (PRINT NAME)) 
SAYHELLO
CL-USER(143): (sayHello "Manikanti")

"Manikanti" 
"Manikanti"
CL-USER(144): (get 'sayHello 'source)
(DEFUN SAYHELLO (NAME) (PRINT NAME))
CL-USER(145): 

Thanks for the help.

Manikanti Sreedhar Reddy


Adam Warner <······@consulting.net.nz> wrote in message news:<······························@consulting.net.nz>...
> > (get 'sayHello 'source)
> > 
> > (defun sayHello () (print "Hello"))
> > 
> > The original source code is stored in the property list of the function.
> 
> To express this more accurately, the list structure of the source code is
> being stored in the property list of the function after it has been
> interpreted by the Lisp reader. Do not confuse this approach with storage
> of the actual text/ASCII/Unicode input.
> 
> To see the difference consider this function:
> 
> * (defun-grab foo () #x1000)
> 
> (defun foo () 4096)
> 
> 1000 in hexadecimal is 4096 in base 10. To Lisp both are the same integer
> and are equivalent after they have been processed by the reader:
> 
> * (eql #x1000 4096)
> 
> t
> 
> And to emphasise that you are able to operate on the elements of the function
> definition:
> 
> ;;; A simple list walker and accumulator. This remarkable version was
> ;;; produced by Kent M Pitman in 1999.
> (defun collapse-list (list)
>   (loop for item in list
>         when (atom item)
>         collect item
>         else nconc (collapse-list item)))
> 
> * (loop for element in (collapse-list (get 'sayHello 'source))
>         do (format t "Element ~S is type ~S~%" element (type-of element)))
> Element defun is type symbol
> Element sayHello is type symbol
> Element nil is type null
> Element print is type symbol
> Element "Hello" is type (simple-base-string 5)
> nil
> 
> Regards,
> Adam
From: Sreedhar Reddy
Subject: Re: Getting Lisp code - similar to "disassemble"
Date: 
Message-ID: <7cc1d291.0308290240.4cc7055b@posting.google.com>
As suggested by Warner, I have written the code using shadow and works fine. :)

Here is the code:

(defmacro defun-grab (name lambda-list &body body)
  (let ((defun-form `(defun ,name ,lambda-list ,@body)))
    `(progn
       ,defun-form
       (setf (get ',name 'source) ',defun-form))))

CL-USER(142): (defun sayHello(name)
		(print name))
the name is : SAYHELLO
The defun is : (DEFUN SAYHELLO (NAME) (PRINT NAME)) 
SAYHELLO
CL-USER(143): (sayHello "Manikanti")

"Manikanti" 
"Manikanti"
CL-USER(144): (get 'sayHello 'source)
(DEFUN SAYHELLO (NAME) (PRINT NAME))
CL-USER(145): 

Thanks for the help.

Manikanti Sreedhar Reddy

Adam Warner <······@consulting.net.nz> wrote in message news:<······························@consulting.net.nz>...
> Hi Sreedhar Reddy,
> 
> > Now, I am interested to get the actual function definition (lisp code).
> 
> The original code is not required at runtime so you want a way to
> explicitly store it. Macros to the rescue. Here's a quality solution
> (improved as you can see by Martin Simmons):
> 
> ;; From Martin Simmons, Xanalys Software Tools: "The defun won't be
> ;; evaluated if you quote the list.  Depending on how it will be used,
> ;; I would probably do it differently:"
> (defmacro defun-grab (name lambda-list &body body)
>   (let ((defun-form `(defun ,name ,lambda-list ,@body)))
>     `(progn
>        ,defun-form
>        (setf (get ',name 'source) ',defun-form))))
> 
> * (defun-grab sayHello() (print "Hello"))
> 
> (defun sayHello () (print "Hello"))
> * (sayHello)
> 
> "Hello" 
> "Hello"
> * (get 'sayHello 'source)
> 
> (defun sayHello () (print "Hello"))
> 
> The original source code is stored in the property list of the function.
> If you want it to be completely transparent you could shadow the original
> DEFUN.
> 
> Regards,
> Adam