4.3BSD/usr/lib/lisp/manual/ch8.r








                         CHAPTER  8


              Functions, Fclosures, and Macros






   8.1.  valid function objects

           There are many different objects which can occupy
      the  function field of a symbol object.  Table 8.1, on
      the following page, shows all  of  the  possibilities,
      how  to recognize them, and where to look for documen-
      tation.



   8.2.  functions

           The basic Lisp function is the  lambda  function.
      When a lambda function is called, the actual arguments
      are evaluated from left to right and are  lambda-bound
      to the formal parameters of the lambda function.

           An nlambda function is usually used for functions
      which  are  invoked  by  the  user at top level.  Some
      built-in functions which evaluate their  arguments  in
      special  ways  are  also  nlambdas (e.g _c_o_n_d, _d_o, _o_r).
      When an  nlambda  function  is  called,  the  list  of
      unevaluated  arguments  is  lambda bound to the single
      formal parameter of the nlambda function.

           Some programmers will  use  an  nlambda  function
      when  they  are  not  sure  how many arguments will be
      passed.  Then, the first thing  the  nlambda  function
      does  is  map  _e_v_a_l over the list of unevaluated argu-
      ments it has been passed.  This is usually  the  wrong
      thing  to  do,  as it will not work compiled if any of
      the arguments are local variables. The solution is  to
      use  a  lexpr.   When  a lexpr function is called, the
      arguments are evaluated and a fixnum  whose  value  is
      the  number of arguments is lambda-bound to the single
      formal parameter of the lexpr function.  The lexpr can
      then access the arguments using the _a_r_g function.

           When a function is compiled, _s_p_e_c_i_a_l declarations
      may  be  needed to preserve its behavior.  An argument
      is not lambda-bound to the name of  the  corresponding
      formal parameter unless that formal parameter has been
      declared _s_p_e_c_i_a_l (see 12.3.2.2).


Functions, Fclosures, and Macros                         8-1







Functions, Fclosures, and Macros                         8-2





8_________________________________________________________________
   informal name             object type          documentation
8__________________________________________________________________________________________________________________________________
    interpreted             list with _c_a_r              8.2
  lambda function           _e_q to lambda
8_________________________________________________________________
    interpreted             list with _c_a_r              8.2
  nlambda function          _e_q to nlambda
8_________________________________________________________________
    interpreted             list with _c_a_r              8.2
   lexpr function            _e_q to lexpr
8_________________________________________________________________
    interpreted             list with _c_a_r              8.3
       macro                 _e_q to macro
8_________________________________________________________________
      fclosure            vector with _v_p_r_o_p            8.4
                           _e_q to fclosure
8_________________________________________________________________
      compiled         binary with discipline          8.2
  lambda or lexpr           _e_q to lambda
      function
8_________________________________________________________________
      compiled         binary with discipline          8.2
  nlambda function          _e_q to nlambda
8_________________________________________________________________
      compiled         binary with discipline          8.3
       macro                 _e_q to macro
8_________________________________________________________________
      foreign          binary with discipline          8.5
     subroutine          of "subroutine"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
      function            of "function"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
  integer function    of "integer-function"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
   real function        of "real-function"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
     C function          of "c-function"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
  double function     of "double-c-function"[|-]
8_________________________________________________________________
      foreign          binary with discipline          8.5
 structure function   of "vector-c-function"[|-]
8_________________________________________________________________
       array                array object                9
8_________________________________________________________________
7|8|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|







































9                   |8|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|







































9                                               |8|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|







































9                                                                |8|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|7|









































9                         Table 8.1

____________________
9   [|-]Only the first character of the string is significant (i.e "s"
is ok for "subroutine")



9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-3


           Lambda and lexpr functions both  compile  into  a
      binary object with a discipline of lambda.  However, a
      compiled lexpr still acts like an interpreted lexpr.



   8.3.  macros

           An important feature of Lisp is  its  ability  to
      manipulate  programs  as  data.   As a result of this,
      most Lisp implementations  have  very  powerful  macro
      facilities.  The Lisp language's macro facility can be
      used to incorporate  popular  features  of  the  other
      languages  into  Lisp.   For  example, there are macro
      packages which allow one to create records  (ala  Pas-
      cal)  and  refer  to  elements of those records by the
      field names.  The _s_t_r_u_c_t package imported from Maclisp
      does  this.   Another  popular  use  for  macros is to
      create more readable control structures  which  expand
      into  _c_o_n_d,  _o_r  and  _a_n_d.  One such example is the If
      macro.  It allows you to write

      (_I_f (_e_q_u_a_l _n_u_m_b _0) _t_h_e_n (_p_r_i_n_t '_z_e_r_o) (_t_e_r_p_r)
       _e_l_s_e_i_f (_e_q_u_a_l _n_u_m_b _1) _t_h_e_n (_p_r_i_n_t '_o_n_e) (_t_e_r_p_r)
       _e_l_s_e (_p_r_i_n_t '|_I _g_i_v_e _u_p|))

      which expands to

      (_c_o_n_d
          ((_e_q_u_a_l _n_u_m_b _0) (_p_r_i_n_t '_z_e_r_o) (_t_e_r_p_r))
          ((_e_q_u_a_l _n_u_m_b _1) (_p_r_i_n_t '_o_n_e) (_t_e_r_p_r))
          (_t (_p_r_i_n_t '|_I _g_i_v_e _u_p|)))




      8.3.1.  macro forms

              A macro is a function  which  accepts  a  Lisp
         expression   as  input  and  returns  another  Lisp
         expression.  The action the macro takes  is  called
         macro expansion.  Here is a simple example:

         -> (_d_e_f _f_i_r_s_t (_m_a_c_r_o (_x) (_c_o_n_s '_c_a_r (_c_d_r _x))))
         first
         -> (_f_i_r_s_t '(_a _b _c))
         a
         -> (_a_p_p_l_y '_f_i_r_s_t '(_f_i_r_s_t '(_a _b _c)))
         (car '(a b c))

         The first input line defines a macro called  _f_i_r_s_t.
         Notice  that the macro has one formal parameter, _x.
         On the second input line, we ask the interpreter to


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-4


         evaluate  (_f_i_r_s_t '(_a _b _c)).   _E_v_a_l  sees that _f_i_r_s_t
         has a function definition  of  type  macro,  so  it
         evaluates  _f_i_r_s_t's definition, passing to _f_i_r_s_t, as
         an argument, the form _e_v_a_l  itself  was  trying  to
         evaluate:  (_f_i_r_s_t '(_a _b _c)).  The _f_i_r_s_t macro chops
         off the car of the argument with _c_d_r, cons'  a  _c_a_r
         at   the   beginning   of   the  list  and  returns
         (_c_a_r '(_a _b _c)), which _e_v_a_l evaluates.  The value  _a
         is returned as the value of (_f_i_r_s_t '(_a _b _c)).  Thus
         whenever _e_v_a_l tries to evaluate a  list  whose  car
         has  a macro definition it ends up doing (at least)
         two operations, the first of which is a call to the
         macro  to  let  it  macro  expand the form, and the
         other is the evaluation of the result of the macro.
         The  result of the macro may be yet another call to
         a macro, so _e_v_a_l may have to do even  more  evalua-
         tions  until it can finally determine the  value of
         an expression.  One way to see  how  a  macro  will
         expand  is to use _a_p_p_l_y as shown on the third input
         line above.



      8.3.2.  defmacro

              The macro _d_e_f_m_a_c_r_o makes it easier  to  define
         macros  because it allows you to name the arguments
         to the macro call.  For example,  suppose  we  find
         ourselves      often      writing     code     like
         (_s_e_t_q _s_t_a_c_k (_c_o_n_s _n_e_w_e_l_t _s_t_a_c_k).  We could define a
         macro  named  _p_u_s_h  to  do this for us.  One way to
         define it is:

         -> (_d_e_f _p_u_s_h
               (_m_a_c_r_o (_x) (_l_i_s_t '_s_e_t_q (_c_a_d_d_r _x) (_l_i_s_t '_c_o_n_s (_c_a_d_r _x) (_c_a_d_d_r _x)))))
         push

         then (_p_u_s_h _n_e_w_e_l_t _s_t_a_c_k) will expand  to  the  form
         mentioned above.  The same macro written using def-
         macro would be:

         -> (_d_e_f_m_a_c_r_o _p_u_s_h (_v_a_l_u_e _s_t_a_c_k)
           (_l_i_s_t '_s_e_t_q ,_s_t_a_c_k (_l_i_s_t '_c_o_n_s ,_v_a_l_u_e ,_s_t_a_c_k)))
         push

         Defmacro allows you to name the  arguments  of  the
         macro  call,  and  makes  the macro definition look
         more like a function definition.




9

9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-5


      8.3.3.  the backquote character macro

              The default syntax for  FRANZ  LISP  has  four
         characters  with  associated character macros.  One
         is semicolon for  comments.   Two  others  are  the
         backquote and comma which are used by the backquote
         character macro.  The  fourth  is  the  sharp  sign
         macro described in the next section.

              The backquote macro is used  to  create  lists
         where many of the elements are fixed (quoted). This
         makes it very useful  for  creating  macro  defini-
         tions.  In the simplest case, a backquote acts just
         like a single quote:

         ->`(_a _b _c _d _e)
         (a b c d e)

         If a comma precedes an element of a backquoted list
         then that element is evaluated and its value is put
         in the list.

         ->(_s_e_t_q _d '(_x _y _z))
         (x y z)
         ->`(_a _b _c ,_d _e)
         (a b c (x y z) e)

         If a comma followed by an at sign precedes an  ele-
         ment  in  a  backquoted  list, then that element is
         evaluated and spliced into the list with _a_p_p_e_n_d.

         ->`(_a _b _c ,@_d _e)
         (a b c x y z e)

         Once a list begins with a backquote, the commas may
         appear anywhere in the list as this example shows:

         ->`(_a _b (_c _d ,(_c_d_r _d)) (_e _f (_g _h ,@(_c_d_d_r _d) ,@_d)))
         (a b (c d (y z)) (e f (g h z x y z)))

         It is also possible and sometimes  even  useful  to
         use  the backquote macro within itself.  As a final
         demonstration of  the  backquote  macro,  we  shall
         define  the  first  and  push  macros using all the
         power at our disposal: defmacro and  the  backquote
         macro.

         ->(_d_e_f_m_a_c_r_o _f_i_r_s_t (_l_i_s_t) `(_c_a_r ,_l_i_s_t))
         first
         ->(_d_e_f_m_a_c_r_o _p_u_s_h (_v_a_l_u_e _s_t_a_c_k) `(_s_e_t_q ,_s_t_a_c_k (_c_o_n_s ,_v_a_l_u_e ,_s_t_a_c_k)))
         stack

9

9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-6


      8.3.4.  sharp sign character macro

              The sharp sign macro can perform a  number  of
         different  functions   at read time.  The character
         directly following the sharp sign determines  which
         function  will  be  done,  and  following  Lisp  s-
         expressions may serve as arguments.



         8.3.4.1.  conditional inclusion

            If you plan to run one source file in more  than
            one environment then you may want to some pieces
            of code to be included  or not included  depend-
            ing  on  the  environment.  The  C language uses
            "#ifdef" and "#ifndef"  for  this  purpose,  and
            Lisp  uses  "#+" and "#-".  The environment that
            the   sharp   sign   macro   checks    is    the
            (_s_t_a_t_u_s _f_e_a_t_u_r_e_s) list which is initialized when
            the Lisp system  is  built   and  which  may  be
            altered     by     (_s_s_t_a_t_u_s _f_e_a_t_u_r_e _f_o_o)     and
            (_s_s_t_a_t_u_s _n_o_f_e_a_t_u_r_e _b_a_r) The form  of conditional
            inclusion is
                        _#_+_w_h_e_n _w_h_a_t
            where _w_h_e_n is either a symbol or  an  expression
            involving symbols and the functions _a_n_d, _o_r, and
            _n_o_t.  The meaning is that _w_h_a_t will only be read
            in  if  _w_h_e_n  is true.  A symbol in _w_h_e_n is true
            only if  it  appears  in  the  (_s_t_a_t_u_s _f_e_a_t_u_r_e_s)
            list.


    ____________________________________________________

    ; suppose we want to write a program which references a file
    ; and which can run at ucb, ucsd and cmu where the file naming conventions
    ; are different.
    ;
    -> (_d_e_f_u_n _h_o_w_o_l_d (_n_a_m_e)
          (_t_e_r_p_r)
          (_l_o_a_d #+(_o_r _u_c_b _u_c_s_d) "/_u_s_r/_l_i_b/_l_i_s_p/_a_g_e_s._l"
                 #+_c_m_u "/_u_s_r/_l_i_s_p/_d_o_c/_a_g_e_s._l")
          (_p_a_t_o_m _n_a_m_e)
          (_p_a_t_o_m " _i_s ")
          (_p_r_i_n_t (_c_d_r (_a_s_s_o_c _n_a_m_e _a_g_e_f_i_l_e)))
          (_p_a_t_o_m "_y_e_a_r_s _o_l_d")
          (_t_e_r_p_r))
    ____________________________________________________



The form


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-7


                        _#_-_w_h_e_n _w_h_a_t
is equivalent to
                     _#_+_(_n_o_t _w_h_e_n_) _w_h_a_t



         8.3.4.2.  fixnum character equivalents

            When working with fixnum equivalents of  charac-
            ters,  it  is  often hard to remember the number
            corresponding to a character.  The form
                            _#_/_c
            is equivalent to the  fixnum  representation  of
            character c.


    ____________________________________________________

    ; a function which returns t if the user types y else it returns nil.
    ;
    -> (_d_e_f_u_n _y_e_s_o_r_n_o _n_i_l
          (_p_r_o_g_n (_a_n_s)
                 (_s_e_t_q _a_n_s (_t_y_i))
                 (_c_o_n_d ((_e_q_u_a_l _a_n_s #/_y) _t)
                       (_t _n_i_l))))
    ____________________________________________________






         8.3.4.3.  read time evaluation

            Occasionally you want to express a constant as a
            Lisp  expression,  yet you don't want to pay the
            penalty of evaluating this expression each  time
            it is referenced.  The form
                        _#_._e_x_p_r_e_s_s_i_o_n
            evaluates  the  expression  at  read  time   and
            returns its value.











9

9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-8



    ____________________________________________________

    ; a function to test if any of bits 1 3 or 12 are set in a fixnum.
    ;
    -> (_d_e_f_u_n _t_e_s_t_i_t (_n_u_m)
          (_c_o_n_d ((_z_e_r_o_p (_b_o_o_l_e _1 _n_u_m #.(+ (_l_s_h _1 _1) (_l_s_h _1 _3) (_l_s_h _1 _1_2))))
                 _n_i_l)
                (_t _t)))
    ____________________________________________________






   8.4.  fclosures

           Fclosures are a type of functional  object.   The
      purpose  is  to  remember the values of some variables
      between invocations of the functional  object  and  to
      protect this data from being inadvertently overwritten
      by other Lisp  functions.   Fortran  programs  usually
      exhibit  this behavior for their variables.  (In fact,
      some versions of Fortran would require  the  variables
      to  be  in COMMON).  Thus it is easy to write a linear
      congruent random number generator in  Fortran,  merely
      by keeping the seed as a variable in the function.  It
      is much more risky to do so in Lisp, since any special
      variable you picked, might be used by some other func-
      tion.  Fclosures are an attempt to provide most of the
      same  functionality  as closures in Lisp Machine Lisp,
      to users of FRANZ LISP.  Fclosures are related to clo-
      sures in this way:
      (fclosure '(a b) 'foo) <==>
              (let ((a a) (b b)) (closure '(a b) 'foo))



      8.4.1.  an example

____________________________________________________________

% lisp
Franz Lisp, Opus 38.60
->(defun code (me count)
  (print (list 'in x))
  (setq x (+ 1 x))
  (cond ((greaterp count 1) (funcall me me (sub1 count))))
  (print (list 'out x)))
code
->(defun tester (object count)
  (funcall object object count) (terpri))


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                         8-9


tester
->(setq x 0)
0
->(setq z (fclosure '(x) 'code))
fclosure[8]
-> (tester z 3)
(in 0)(in 1)(in 2)(out 3)(out 3)(out 3)
nil
->x
0
____________________________________________________________





              The function _f_c_l_o_s_u_r_e  creates  a  new  object
         that  we  will  call  an  fclosure, (although it is
         actually a vector).  The fclosure contains a  func-
         tional  object, and a set of symbols and values for
         the symbols.  In the above  example,  the  fclosure
         functional object is the function code.  The set of
         symbols and values just contains the symbol `x' and
         zero,  the  value  of  `x'  when  the  fclosure was
         created.

         When an fclosure is funcall'ed:

         1)   The Lisp system lambda binds  the  symbols  in
              the fclosure to their values in the fclosure.

         2)   It continues the  funcall  on  the  functional
              object of the fclosure.

         3)   Finally, it un-lambda binds the symbols in the
              fclosure  and  at  the  same  time  stores the
              current values of the symbols in the fclosure.


              Notice that the fclosure is saving  the  value
         of  the  symbol  `x'.   Each  time  a  fclosure  is
         created, new space  is  allocated  for  saving  the
         values  of the symbols. Thus if we execute fclosure
         again, over the same  function,  we  can  have  two
         independent counters:

____________________________________________________________

-> (setq zz (fclosure '(x) 'code))
fclosure[1]
-> (tester zz 2)
(in 0)(in 1)(out 2)(out 2)
-> (tester zz 2)


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-10


(in 2)(in 3)(out 4)(out 4)
-> (tester z 3)
(in 3)(in 4)(in 5)(out 6)(out 6)(out 6)
____________________________________________________________







      8.4.2.  useful functions

              Here are some quick some  summaries  of  func-
         tions  dealing  with  closures.  They are more for-
         mally defined in 2.8.4.  To  recap,  fclosures  are
         made by (_f_c_l_o_s_u_r_e '_l__v_a_r_s '_g__f_u_n_c_o_b_j).  l_vars is a
         list of symbols (not containing nil), g_funcobj  is
         any  object  that can be funcalled.  (Objects which
         can be funcalled, include compiled Lisp  functions,
         lambda  expressions,  symbols,  foreign  functions,
         etc.) In general, if you want a  compiled  function
         to  be closed over a variable, you must declare the
         variable  to  be  special  within   the   function.
         Another example would be:

                     (fclosure '(a b) #'(lambda (x) (plus x a)))

         Here, the #' construction will  make  the  compiler
         compile the lambda expression.

              There are times when you want to  share  vari-
         ables  between  fclosures.  This can be done if the
         fclosures  are  created  at  the  same  time  using
         _f_c_l_o_s_u_r_e-_l_i_s_t.  The function _f_c_l_o_s_u_r_e-_a_l_i_s_t returns
         an assoc list giving the symbols and values in  the
         fclosure.   The  predicate  _f_c_l_o_s_u_r_e_p returns t iff
         its  argument  is  a  fclosure.   Other   functions
         imported  from  Lisp  Machine  Lisp are _s_y_m_e_v_a_l-_i_n-
         _f_c_l_o_s_u_r_e,   _l_e_t-_f_c_l_o_s_e_d,    and    _s_e_t-_i_n-_f_c_l_o_s_u_r_e.
         Lastly,  the function _f_c_l_o_s_u_r_e-_f_u_n_c_t_i_o_n returns the
         function argument.



      8.4.3.  internal structure

              Currently, closures are  implemented  as  vec-
         tors, with property being the symbol fclosure.  The
         functional object is the first entry.  The  remain-
         ing  entries are structures which point to the sym-
         bols and values for the closure, (with a  reference
         count  to  determine  if  a  recursive  closure  is


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-11


         active).



   8.5.  foreign subroutines and functions

           FRANZ LISP has the ability  to  dynamically  load
      object  files  produced by other compilers and to call
      functions defined in those files.  These functions are
      called _f_o_r_e_i_g_n functions.* There are  seven  types  of
      foreign functions.  They are characterized by the type
      of result they  return,  and  by  differences  in  the
      interpretation of their arguments.  They come from two
      families: a group  suited  for  languages  which  pass
      arguments  by  reference  (e.g.  Fortran), and a group
      suited for languages which  pass  arguments  by  value
      (e.g. C).


      There are four types in the first group:

      subroutine
           This does not return anything.  The  Lisp  system
           always returns t after calling a subroutine.

      function
           This returns whatever the function returns.  This
           must  be  a valid Lisp object or it may cause the
           Lisp system to fail.

      integer-function
           This returns an integer  which  the  Lisp  system
           makes into a fixnum and returns.

      real-function
           This returns a double precision real number which
           the Lisp system makes into a flonum and returns.


      There are three types in the second group:

      c-function
           This is like an integer function, except for  its
           different interpretation of arguments.


____________________
9   *This topic is also discussed in Report  PAM-124  of  the
Center  for  Pure  and  Applied  Mathematics,  UCB, entitled
``Parlez-Vous Franz?  An Informal Introduction to  Interfac-
ing Foreign Functions to Franz LISP'', by James R. Larus



9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-12


      double-c-function
           This is like a real-function.

      vector-c-function
           This is for C functions which return a structure.
           The  first  argument  to such functions must be a
           vector (of type vectori), into which  the  result
           is  stored.  The second Lisp argument becomes the
           first argument to the C function, and so on

      A foreign function is accessed through a binary object
      just like a compiled Lisp function.  The difference is
      that the discipline field of a  binary  object  for  a
      foreign  function is a string whose first character is
      given in the following table:


8                   ____________________________
                    letter         type
8                   ________________________________________________________
                      s         subroutine
8                   ____________________________
                      f          function
8                   ____________________________
                      i      integer-function
8                   ____________________________
                      r       real-function.
8                   ____________________________
                      c         c-function
8                   ____________________________
                      v      vector-c-function
8                   ____________________________
                      d      double-c-function
8                   ____________________________
7                  |7|7|7|7|7|7|7|7|7|7|7|










                          |7|7|7|7|7|7|7|7|7|7|7|










                                              |7|7|7|7|7|7|7|7|7|7|7|












      Two functions  are  provided  for  setting-up  foreign
      functions.   _C_f_a_s_l  loads an object file into the Lisp
      system and sets up one foreign function binary object.
      If there are more than one function in an object file,
      _g_e_t_a_d_d_r_e_s_s can be used to set  up  additional  foreign
      function objects.

           Foreign  functions are  called  just  like  other
      functions,  e.g  (_f_u_n_n_a_m_e _a_r_g_1 _a_r_g_2).  When a function
      in the Fortran group  is  called,  the  arguments  are
      evaluated  and  then  examined.  List, hunk and symbol
      arguments are passed unchanged to  the  foreign  func-
      tion.   Fixnum  and flonum arguments are copied into a
      temporary location and  a  pointer  to  the  value  is
      passed (this is because Fortran uses call by reference
      and it is dangerous to modify the contents of a fixnum
      or  flonum  which  something else might point to).  If
      the argument is an array object, the data field of the
      array  object  is passed to the foreign function (This
      is the easiest way to send large amounts  of  data  to
      and receive large amounts of data from a foreign func-
      tion).  If a binary object is an argument,  the  entry


9                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-13


      field of that object is passed to the foreign function
      (the entry field is the address of a function, so this
      amounts to passing a function as an argument).

           When a function in the C group is called,  fixnum
      and flownum arguments are passed by value.  For almost
      all other arguments, the address is merely provided to
      the  C  routine.   The  only exception arises when you
      want to invoke a C routine which  expects  a  ``struc-
      ture''  argument.  Recall that a (rarely used) feature
      of the C language is the ability to pass structures by
      value.   This  copies  the  structure  onto the stack.
      Since the Franz's nearest equivalent to a C  structure
      is  a  vector, we provide an escape clause to copy the
      contents of an immediate-type vector by value.  If the
      property  field  of  a vectori argument, is the symbol
      "value-structure-argument", then the  binary  data  of
      this immediate-type vector is copied into the argument
      list of the C routine.

           The method a foreign function uses to access  the
      arguments   provided  by  Lisp  is  dependent  on  the
      language  of  the  foreign  function.   The  following
      scripts  demonstrate  how  how  Lisp can interact with
      three languages: C, Pascal and Fortran.  C and  Pascal
      have  pointer  types and the first script shows how to
      use pointers to extract information from Lisp objects.
      There  are  two  functions  defined for each language.
      The first (cfoo in C, pfoo in Pascal)  is  given  four
      arguments,  a  fixnum, a flonum-block array, a hunk of
      at least two fixnums and a list of at least  two  fix-
      nums.   To  demonstrate  that  the values were passed,
      each ?foo function prints its arguments (or  parts  of
      them).   The  ?foo  function  then modifies the second
      element of the flonum-block array and returns a  3  to
      Lisp.   The second function (cmemq in C, pmemq in Pas-
      cal) acts just like the Lisp _m_e_m_q function (except  it
      won't work for fixnums whereas the lisp _m_e_m_q will work
      for small fixnums).  In the script, typed input is  in
      bold,  computer output is in roman and comments are in
      _i_t_a_l_i_c.


____________________________________________________________

_T_h_e_s_e _a_r_e _t_h_e _C _c_o_d_e_d _f_u_n_c_t_i_o_n_s
% cat ch8auxc.c
/* demonstration of c coded foreign integer-function */

/* the following will be used to extract fixnums out of a list of fixnums */
struct listoffixnumscell
{    struct listoffixnumscell *cdr;
     int *fixnum;


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-14


};

struct listcell
{       struct listcell *cdr;
        int car;
};

cfoo(a,b,c,d)
int *a;
double b[];
int *c[];
struct listoffixnumscell *d;
{
    printf("a: %d, b[0]: %f, b[1]: %f0, *a, b[0], b[1]);
    printf(" c (first): %d   c (second): %d0,
               *c[0],*c[1]);
    printf(" ( %d %d ... ) ", *(d->fixnum), *(d->cdr->fixnum));
    b[1] = 3.1415926;
    return(3);
}

struct listcell *
cmemq(element,list)
int element;
struct listcell *list;
{
   for( ; list && element != list->car ;  list = list->cdr);
   return(list);
}


_T_h_e_s_e _a_r_e _t_h_e _P_a_s_c_a_l _c_o_d_e_d _f_u_n_c_t_i_o_n_s
% cat ch8auxp.p
type    pinteger = ^integer;
        realarray = array[0..10] of real;
        pintarray = array[0..10] of pinteger;
        listoffixnumscell = record
                                cdr  : ^listoffixnumscell;
                                fixnum : pinteger;
                            end;
        plistcell = ^listcell;
        listcell = record
                      cdr : plistcell;
                      car : integer;
                   end;

function pfoo ( var a : integer ;
                var b : realarray;
                var c : pintarray;
                var d : listoffixnumscell) : integer;
begin
   writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]);
   writeln(' c (first):', c[0]^,' c (second):', c[1]^);


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-15


   writeln(' ( ', d.fixnum^, d.cdr^.fixnum^, ' ...) ');
   b[1] := 3.1415926;
   pfoo := 3
end ;

{ the function pmemq looks for the Lisp pointer given as the first argument
  in the list pointed to by the second argument.
  Note that we declare " a : integer " instead of " var a : integer " since
  we are interested in the pointer value instead of what it points to (which
  could be any Lisp object)
}
function pmemq( a : integer; list : plistcell) : plistcell;
begin
 while (list <> nil) and (list^.car <> a) do list := list^.cdr;
 pmemq := list;
end ;


_T_h_e _f_i_l_e_s _a_r_e _c_o_m_p_i_l_e_d
% cc -c ch8auxc.c
1.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
% pc -c ch8auxp.p
3.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w


% lisp
Franz Lisp, Opus 38.60
_F_i_r_s_t _t_h_e _f_i_l_e_s _a_r_e _l_o_a_d_e_d _a_n_d _w_e _s_e_t _u_p _o_n_e  _f_o_r_e_i_g_n  _f_u_n_c_-
_t_i_o_n  _b_i_n_a_r_y.  _W_e _h_a_v_e _t_w_o _f_u_n_c_t_i_o_n_s _i_n _e_a_c_h _f_i_l_e _s_o _w_e _m_u_s_t
_c_h_o_o_s_e _o_n_e _t_o _t_e_l_l _c_f_a_s_l _a_b_o_u_t.  _T_h_e _c_h_o_i_c_e _i_s _a_r_b_i_t_r_a_r_y.
-> (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")
/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0  -lc
#63000-"integer-function"
-> (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")
/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
#63200-"integer-function"
_H_e_r_e _w_e _s_e_t _u_p _t_h_e _o_t_h_e_r _f_o_r_e_i_g_n _f_u_n_c_t_i_o_n _b_i_n_a_r_y _o_b_j_e_c_t_s
-> (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")
#6306c-"function"
_W_e _w_a_n_t _t_o _c_r_e_a_t_e _a_n_d _i_n_i_t_i_a_l_i_z_e _a_n _a_r_r_a_y  _t_o  _p_a_s_s  _t_o  _t_h_e
_c_f_o_o  _f_u_n_c_t_i_o_n.  _I_n _t_h_i_s _c_a_s_e _w_e _c_r_e_a_t_e _a_n _u_n_n_a_m_e_d _a_r_r_a_y _a_n_d
_s_t_o_r_e _i_t _i_n _t_h_e _v_a_l_u_e _c_e_l_l _o_f _t_e_s_t_a_r_r.  _W_h_e_n  _w_e  _c_r_e_a_t_e  _a_n
_a_r_r_a_y  _t_o  _p_a_s_s  _t_o  _t_h_e  _P_a_s_c_a_l _p_r_o_g_r_a_m _w_e _w_i_l_l _u_s_e _a _n_a_m_e_d
_a_r_r_a_y _j_u_s_t _t_o _d_e_m_o_n_s_t_r_a_t_e _t_h_e _d_i_f_f_e_r_e_n_t _w_a_y _t_h_a_t  _n_a_m_e_d  _a_n_d
_u_n_n_a_m_e_d _a_r_r_a_y_s _a_r_e _c_r_e_a_t_e_d _a_n_d _a_c_c_e_s_s_e_d.
-> (setq testarr (array nil flonum-block 2))
array[2]
-> (store (funcall testarr 0) 1.234)
1.234
-> (store (funcall testarr 1) 5.678)
5.678
-> (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))
a: 385, b[0]: 1.234000, b[1]: 5.678000


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-16


 c (first): 10   c (second): 11
 ( 15 16 ... )
 3
_N_o_t_e _t_h_a_t _c_f_o_o _h_a_s _r_e_t_u_r_n_e_d _3 _a_s _i_t _s_h_o_u_l_d.  _I_t _a_l_s_o _h_a_d _t_h_e
_s_i_d_e  _e_f_f_e_c_t  _o_f  _c_h_a_n_g_i_n_g  _t_h_e _s_e_c_o_n_d _v_a_l_u_e _o_f _t_h_e _a_r_r_a_y _t_o
_3._1_4_1_5_9_2_6  _w_h_i_c_h _c_h_e_c_k _n_e_x_t.
-> (funcall testarr 1)
3.1415926


_I_n _p_r_e_p_a_r_a_t_i_o_n _f_o_r _c_a_l_l_i_n_g _p_f_o_o _w_e _c_r_e_a_t_e _a_n _a_r_r_a_y.
-> (array test flonum-block 2)
array[2]
-> (store (test 0) 1.234)
1.234
-> (store (test 1) 5.678)
5.678
-> (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))
 a:       385 b[0]:  1.23400000000000E+00 b[1]:  5.67800000000000E+00
 c (first):        10 c (second):        11
 (         15        16 ...)
3
-> (test 1)
3.1415926

 _N_o_w _t_o _t_e_s_t _o_u_t _t_h_e _m_e_m_q'_s
-> (cmemq 'a '(b c a d e f))
(_a _d _e _f)
-> (pmemq 'e '(a d f g a x))
_n_i_l
____________________________________________________________





           The Fortran example will be much shorter since in
      Fortran  you can't follow pointers as you can in other
      languages.  The Fortran function ffoo is  given  three
      arguments:  a  fixnum, a fixnum-block array and a flo-
      num.  These arguments are printed out to  verify  that
      they  made it and then the first value of the array is
      modified.  The function  returns  a  double  precision
      value  which  is  converted  to  a  flonum by lisp and
      printed.  Note that the entry point  corresponding  to
      the  Fortran function ffoo is _ffoo_ as opposed to the
      C and Pascal convention of preceding the name with  an
      underscore.

____________________________________________________________


% cat ch8auxf.f


                                   Printed: January 31, 1984







Functions, Fclosures, and Macros                        8-17


        double precision function ffoo(a,b,c)
        integer a,b(10)
        double precision c
        print 2,a,b(1),b(2),c
2       format(' a=',i4,', b(1)=',i5,', b(2)=',i5,' c=',f6.4)
        b(1) = 22
        ffoo = 1.23456
        return
        end
% f77 -c ch8auxf.f
ch8auxf.f:
   ffoo:
0.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
% lisp
Franz Lisp, Opus 38.60
-> (cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")
/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxf.o -e _ffoo_
-o /tmp/Li11066.0 -lF77 -lI77 -lc
#6307c-"real-function"

-> (array test fixnum-block 2)
array[2]
-> (store (test 0) 10)
10
-> (store (test 1) 11)
11
-> (ffoo 385 (getd 'test) 5.678)
 a= 385, b(1)=   10, b(2)=   11 c=5.6780
1.234559893608093
-> (test 0)
22

____________________________________________________________



















9

9                                   Printed: January 31, 1984