BSD 4_2 development
[unix-history] / usr / lisp / ch8.n
CommitLineData
3cdae440
C
1." $Header: ch8.n 1.4 83/07/27 15:12:22 layer Exp $
2.Lc Functions,\ Fclosures,\ and\ Macros 8
3.sh 2 valid\ function\ objects 8
4.pp
5There are many different objects which can occupy the function field of
6a symbol object.
7Table 8.1, on the following page,
8shows all of the possibilities, how to recognize them,
9and where to look for documentation.
10.(z
11.sp 1v
12.TS
13box center ;
14c | c | c .
15informal name object type documentation
16=
17interpreted list with \fIcar\fP 8.2
18lambda function \fIeq\fP to lambda
19_
20interpreted list with \fIcar\fP 8.2
21nlambda function \fIeq\fP to nlambda
22_
23interpreted list with \fIcar\fP 8.2
24lexpr function \fIeq\fP to lexpr
25_
26interpreted list with \fIcar\fP 8.3
27macro \fIeq\fP to macro
28_
29fclosure vector with \fIvprop\fP 8.4
30 \fIeq\fP to fclosure
31_
32compiled binary with discipline 8.2
33lambda or lexpr \fIeq\fP to lambda
34function
35_
36compiled binary with discipline 8.2
37nlambda function \fIeq\fP to nlambda
38_
39compiled binary with discipline 8.3
40macro \fIeq\fP to macro
41_
42foreign binary with discipline 8.5
43subroutine of \*(lqsubroutine\*(rq\*[\(dg\*]
44_
45foreign binary with discipline 8.5
46function of \*(lqfunction\*(rq\*[\(dg\*]
47_
48foreign binary with discipline 8.5
49integer function of \*(lqinteger-function\*(rq\*[\(dg\*]
50_
51foreign binary with discipline 8.5
52real function of \*(lqreal-function\*(rq\*[\(dg\*]
53_
54foreign binary with discipline 8.5
55C function of \*(lqc-function\*(rq\*[\(dg\*]
56_
57foreign binary with discipline 8.5
58double function of \*(lqdouble-c-function\*(rq\*[\(dg\*]
59_
60foreign binary with discipline 8.5
61structure function of \*(lqvector-c-function\*(rq\*[\(dg\*]
62_
63array array object 9
64.TE
65.tl ''Table 8.1''
66.(f
67\*[\(dg\*]Only the first character of the string is significant (i.e \*(lqs\*(rq
68is ok for \*(lqsubroutine\*(rq)
69.)f
70.)z
71.br
72.sh 2 functions
73.pp
74The basic Lisp function is the lambda function.
75When a lambda function is called, the actual arguments are
76evaluated from left to right and are lambda-bound to the
77formal parameters of the lambda function.
78.pp
79An nlambda function is usually used for functions which are invoked
80by the user at top level.
81Some built-in functions which evaluate their arguments in special ways are
82also nlambdas (e.g \fIcond\fP, \fIdo\fP, \fIor\fP).
83When an nlambda function is called, the list of unevaluated arguments
84is lambda bound to the single formal parameter of the nlambda function.
85.pp
86Some programmers will use an nlambda function
87when they are not sure how many arguments
88will be passed.
89Then, the first thing the nlambda function does is map \fIeval\fP over
90the list of unevaluated arguments it has been passed.
91This is usually the wrong thing to do, as it will not work compiled if
92any of the arguments are local variables.
93The solution is to use a lexpr.
94When a lexpr function is called, the arguments
95are evaluated and a fixnum whose value is
96the number of arguments is lambda-bound to the single
97formal parameter of the lexpr function.
98The lexpr can then access the arguments using the \fIarg\fP function.
99.pp
100When a function is compiled,
101.i special
102declarations may be needed to
103preserve its behavior.
104An argument is not lambda-bound to the name of
105the corresponding formal parameter
106unless that formal parameter has been declared
107.i special
108(see \(sc12.3.2.2).
109.pp
110Lambda and lexpr functions both compile into a binary object with
111a discipline of lambda.
112However, a compiled lexpr still acts like an interpreted lexpr.
113.sh 2 macros
114.pp
115An important feature of Lisp
116is its ability to manipulate programs as data.
117As a result of this, most Lisp implementations
118have very powerful macro facilities.
119The Lisp language's macro facility
120can be used to incorporate popular features of the other
121languages into Lisp.
122For example, there are macro packages
123which allow one to create records (ala Pascal)
124and refer to elements of those records by the field names.
125The
126.i struct
127package imported from Maclisp does this.
128Another popular use for macros is to create more readable control
129structures which expand into
130.i cond ,
131.i or
132and
133.i and .
134One such example is the If macro.
135It allows you to write
136.sp 1v
137.nf
138.ft I
139(If (equal numb 0) then (print 'zero) (terpr)
140\ elseif (equal numb 1) then (print 'one) (terpr)
141\ else (print '|I give up|))
142.ft P
143.sp 1v
144which expands to
145.sp 1v
146.ft I
147(cond
148\ \ \ \ ((equal numb 0) (print 'zero) (terpr))
149\ \ \ \ ((equal numb 1) (print 'one) (terpr))
150\ \ \ \ (t (print '|I give up|)))
151.ft P
152.sp 1v
153.fi
154.sh 3 macro\ forms
155.pp
156A macro is a function which accepts a Lisp expression as input and returns
157another Lisp expression.
158The action the macro takes is called macro expansion.
159Here is a simple example:
160.sp 1v
161.nf
162\-> \fI(def first (macro (x) (cons 'car (cdr x))))\fP
163first
164\-> \fI(first '(a b c))\fP
165a
166\-> \fI(apply 'first '(first '(a b c)))\fP
167(car '(a b c))
168.fi
169.sp 1v
170The first input line defines a macro called
171.i first .
172Notice that the macro has one formal parameter, \fIx\fP.
173On the second input line, we ask the interpreter to evaluate
174\fI(first\ '(a\ b\ c))\fP.
175.i Eval
176sees that
177.i first
178has a function definition of type macro, so it evaluates
179.i first 's
180definition,
181passing to
182.i first ,
183as an argument, the form
184.i eval
185itself
186was trying to
187evaluate: \fI(first\ '(a\ b\ c))\fP.
188The
189.i first
190macro chops off the car of the argument with
191.i cdr ,
192cons' a
193.i car
194at the beginning of the list and returns \fI(car\ '(a\ b\ c))\fP,
195which
196.i eval
197evaluates.
198The value
199.i a
200is returned as the value of \fI(first\ '(a\ b\ c))\fP.
201Thus whenever
202.i eval
203tries to evaluate a list whose car has a macro definition
204it ends up doing (at least) two operations, the first of which
205is a call to the macro
206to let it macro expand the form, and the other is the evaluation of the
207result of the macro.
208The result of the macro may be yet another call to a macro, so
209.i eval
210may have to do even more evaluations until it can finally determine
211the value of an expression.
212One way to see how a macro will expand is to use
213.i apply
214as shown on the third input line above.
215.sh +0 defmacro
216.pp
217The macro
218.i defmacro
219makes it easier to define macros because it allows you to name the arguments
220to the macro call.
221For example, suppose we find ourselves often writing code like
222\fI(setq\ stack\ (cons\ newelt\ stack)\fP.
223We could define a macro named \fIpush\fP to do this for us.
224One way to define it is:
225.nf
226.sp 1v
227\-> \fI(de\kAf push
228\h'|\nAu'(macro (x) (list 'setq (caddr x) (list 'cons (cadr x) (caddr x)))))\fP
229push
230.fi
231.sp 1v
232then \fI(push\ newelt\ stack)\fP will expand to the form mentioned above.
233The same macro written using defmacro would be:
234.nf
235.sp 1v
236\->\fI\kA (defmacro push (value stack)
237 \h'|\nAu'(list 'setq ,stack (list 'cons ,value ,stack)))\fP
238push
239.fi
240.sp 1v
241Defmacro allows you to name the arguments of the macro call, and makes the
242macro definition look more like a function definition.
243.sh +0 the\ backquote\ character\ macro
244.pp
245The default syntax for
246.Fr
247has four characters with associated character macros.
248One is semicolon for comments.
249Two others are the backquote and comma which are
250used by the backquote character
251macro.
252The fourth is the sharp sign macro described in the next section.
253.pp
254The backquote macro is used to create lists where many of the elements are
255fixed (quoted).
256This makes it very useful for creating macro definitions.
257In the simplest case, a backquote acts just like a single quote:
258.sp 1v
259.nf
260\->\fI`(a b c d e)\fP
261(a b c d e)
262.fi
263.sp 1v
264If a comma precedes an element of a backquoted list then that element is
265evaluated and its value is put in the list.
266.sp 1v
267.nf
268\->\fI(setq d '(x y z))\fP
269(x y z)
270\->\fI`(a b c ,d e)\fP
271(a b c (x y z) e)
272.fi
273.sp 1v
274If a comma followed by an at sign precedes an element in a backquoted list,
275then that element is evaluated and spliced into the list with
276.i append .
277.nf
278.sp 1v
279\->\fI`(a b c ,@d e)\fP
280(a b c x y z e)
281.sp 1v
282.fi
283Once a list begins with a backquote, the commas may appear anywhere in the
284list as this example shows:
285.nf
286.sp 1v
287\->\fI`(a b (c d ,(cdr d)) (e f (g h ,@(cddr d) ,@d)))\fP
288(a b (c d (y z)) (e f (g h z x y z)))
289.sp 1v
290.fi
291It is also possible and sometimes even useful to use the
292backquote macro within itself.
293As a final demonstration of the backquote macro, we shall define the
294first and push macros using all the power at our disposal: defmacro
295and the backquote macro.
296.sp 1v
297.nf
298\->\fI(defmacro first (list) `(car ,list))\fP
299first
300\->\fI(defmacro push (value stack) `(setq ,stack (cons ,value ,stack)))\fP
301stack
302.fi
303.sh +0 sharp\ sign\ character\ macro
304.pp
305The sharp sign macro can perform a number of
306different functions at read time.
307The character directly following the sharp sign determines which function
308will be done, and following Lisp s-expressions may serve as arguments.
309.sh +1 conditional\ inclusion
310.lp
311If you plan to run one source file in more than one environment then
312you may want to some pieces of code to be included or not included
313depending on the environment.
314The C language uses \*(lq#ifdef\*(lq and \*(lq#ifndef\*(rq for this
315purpose, and Lisp uses \*(lq#+\*(rq and \*(lq#\-\*(rq.
316The environment that the sharp sign macro checks is the
317\fI(status\ features)\fP list which is initialized when the Lisp
318system is built and which may be altered by
319\fI(sstatus\ feature\ foo)\fP and \fI(sstatus\ nofeature\ bar)\fP
320The form of conditional inclusion is
321.br
322.tl ''\fI#+when what\fP''
323where
324.i when
325is either a symbol or an expression involving symbols and the functions
326.i and ,
327.i or ,
328and
329.i not .
330The meaning is that
331.i what
332will only be read in if
333.i when
334is true.
335A symbol in
336.i when
337is true only if it appears in the
338.i (status\ features)
339list.
340.Eb
341; suppose we want to write a program which references a file
342; and which can run at ucb, ucsd and cmu where the file naming conventions
343; are different.
344;
345\-> \fI(de\kAfun howold (name)
346 \h'|\nAu'\kC(terpr)
347 \h'|\nCu'\kB(load #\kA+(or ucb ucsd) "/usr/lib/lisp/ages.l"
348 \h'|\nAu'#+cmu "/usr/lisp/doc/ages.l")
349 \h'|\nBu'\kA(patom name)
350 \h'|\nBu'\kA(patom " is ")
351 \h'|\nAu'\kB(print (cdr (assoc name agefile)))
352 \h'|\nBu'\kA(patom "years old")
353 \h'|\nAu'(terpr))\fP
354.Ee
355The form
356.br
357.tl ''\fI#\-when what\fP''
358is equivalent to
359.br
360.tl ''\fI#+(not when) what\fP''
361.sh +0 fixnum\ character\ equivalents
362.lp
363When working with fixnum equivalents of characters, it is often hard to
364remember the number corresponding to a character.
365The form
366.br
367.tl ''\fI#/c\fP''
368is equivalent to the fixnum representation of character c.
369.Eb
370; a function which returns t if the user types y else it returns nil.
371;
372\-> \fI(de\kBfun yesorno nil
373 \h'|\nBu'(progn \kA(ans)
374 \h'|\nAu'\kB(setq ans (tyi))
375 \h'|\nBu'(cond \kA((equal ans #/y) t)
376 \h'|\nAu'(t nil))))\fP
377.Ee
378.sh +0 read\ time\ evaluation
379.lp
380Occasionally you want to express a constant as a Lisp expression, yet you
381don't want to pay the penalty of evaluating this expression each time it
382is referenced.
383The form
384.br
385.tl ''\fI#.expression\fP''
386evaluates the expression at read time and returns its value.
387.Eb
388; a function to test if any of bits 1 3 or 12 are set in a fixnum.
389;
390\-> \fI(de\kCfun testit (num)
391 \h'|\nCu'(cond \kA(\kB(zerop (boole 1 num #.(+ (lsh 1 1) (lsh 1 3) (lsh 1 12))))
392 \h'|\nBu'nil)
393 \h'|\nAu'(t t)))\fP
394.Ee
395.sh 2 fclosures
396.pp
397Fclosures are a type of functional object.
398The purpose is to remember the values of some variables
399between invocations of the functional object and to protect this
400data from being inadvertently overwritten by other Lisp functions.
401Fortran programs usually exhibit this behavior for their variables.
402(In fact, some versions of Fortran would require the
403variables to be in COMMON).
404Thus it is easy to write a linear congruent random number generator
405in Fortran, merely by keeping the seed as a variable in the function.
406It is much more risky to do so in Lisp, since any special variable you
407picked, might be used by some other function.
408Fclosures are an attempt to provide most of the same functionality as
409closures in Lisp Machine Lisp, to users of
410.Fr .
411Fclosures are related to closures in this way:
412.br
413(fclosure '(a b) 'foo) <==>
414.br
415 (let ((a a) (b b)) (closure '(a b) 'foo))
416.sh 3 an\ example
417.sp 1v
418.in 0
419.nf
420.sz -2
421.hl
422% \fBlisp\fP
423Franz Lisp, Opus 38.60
424\->\fB(defun code (me count)
425 (print (list 'in x))
426 (setq x (+ 1 x))
427 (cond ((greaterp count 1) (funcall me me (sub1 count))))
428 (print (list 'out x)))\fP
429code
430\->\fB(defun tester (object count)
431 (funcall object object count) (terpri))\fP
432tester
433\->\fB(setq x 0)\fP
4340
435\->\fB(setq z (fclosure '(x) 'code))\fP
436fclosure[8]
437\->\fB (tester z 3)\fP
438(in 0)(in 1)(in 2)(out 3)(out 3)(out 3)
439nil
440\->\fBx\fP
4410
442.hl
443.fi
444.sz +2
445.sp 3v
446.pp
447The function \fIfclosure\fP creates a new object
448that we will call an fclosure,
449(although it is actually a vector).
450The fclosure contains a functional object, and a set of symbols and
451values for the symbols. In the above example, the fclosure functional
452object is the function code.
453The set of symbols and values just contains the symbol `x' and
454zero, the value of `x' when the fclosure was created.
455.lp
456When an fclosure is funcall'ed:
457.ip 1)
458The Lisp system lambda binds the symbols in the fclosure to their values in the fclosure.
459.ip 2)
460It continues the funcall on the functional object of the fclosure.
461.ip 3)
462Finally, it un-lambda binds the symbols in the fclosure and at the
463same time stores the current values of the symbols in the fclosure.
464.sp 1v
465.pp
466Notice that the fclosure is saving the value of the symbol `x'.
467Each time a fclosure is created, new space is allocated for saving
468the values of the symbols. Thus if we execute fclosure again, over
469the same function, we can have two independent counters:
470.sp 1v
471.in 0
472.nf
473.sz -2
474.hl
475\-> \fB(setq zz (fclosure '(x) 'code))\fP
476fclosure[1]
477\-> \fB(tester zz 2)\fP
478(in 0)(in 1)(out 2)(out 2)
479\-> \fB(tester zz 2)\fP
480(in 2)(in 3)(out 4)(out 4)
481\-> \fB(tester z 3)\fP
482(in 3)(in 4)(in 5)(out 6)(out 6)(out 6)
483.hl
484.fi
485.sz +2
486.sp 3v
487.sh 3 useful\ functions
488.pp
489Here are some quick some summaries of functions dealing with closures.
490They are more formally defined in \(sc2.8.4.
491To recap, fclosures are made by
492\fI(fclosure 'l_vars 'g_funcobj)\fP.
493l_vars is a list of symbols (not containing nil),
494g_funcobj is any object that can be funcalled.
495(Objects which can be funcalled, include compiled Lisp functions,
496lambda expressions, symbols, foreign functions, etc.)
497In general, if you want a compiled function to be closed over a
498variable, you must declare the variable to be special within the function.
499Another example would be:
500.(l
501 (fclosure '(a b) #'(lambda (x) (plus x a)))
502.)l
503Here, the #' construction will make the compiler compile the lambda expression.
504.pp
505There are times when you want to share variables between fclosures.
506This can be done if the fclosures are created at the same time using
507\fIfclosure-list\fP.
508The function \fIfclosure-alist\fP returns an assoc list giving
509the symbols and values in the fclosure. The predicate
510\fIfclosurep\fP returns t iff its argument is a fclosure.
511Other functions imported from Lisp Machine Lisp are
512.i symeval-in-fclosure,
513.i let-fclosed,
514and
515.i set-in-fclosure.
516Lastly, the function \fIfclosure-function\fP returns the function argument.
517.sh 3 internal\ structure
518.pp
519Currently, closures are implemented as vectors, with property being the
520symbol fclosure. The functional object is the first entry.
521The remaining entries are structures which point to the symbols
522and values for the closure, (with a reference count to determine
523if a recursive closure is active).
524.sh 2 foreign\ subroutines\ and\ functions
525.pp
526.Fr
527has the ability to dynamically load object files produced by other compilers
528and to call functions defined in those files.
529These functions are called
530.i foreign
531functions.*
532.(f
533*This topic is also discussed in Report PAM-124 of the Center for
534Pure and Applied Mathematics, UCB, entitled ``Parlez-Vous Franz?
535An Informal Introduction to Interfacing Foreign Functions to Franz LISP'',
536by James R. Larus
537.)f
538There are seven types of foreign functions.
539They are characterized by
540the type of result they return, and by differences in the interpretation
541of their arguments.
542They come from two families: a group suited for languages which pass
543arguments by reference (e.g. Fortran), and a group suited for languages
544which pass arguments by value (e.g. C).
545.sp 1v
546.lp
547There are four types in the first group:
548.ip \fBsubroutine\fP
549This does not return anything.
550The Lisp system
551always returns t after calling a subroutine.
552.ip \fBfunction\fP
553This returns whatever the function returns.
554This must be a valid Lisp object or it may cause the Lisp system to fail.
555.ip \fBinteger-function\fP
556This returns an integer which the Lisp system makes into a fixnum and returns.
557.ip \fBreal-function\fP
558This returns a double precision real number which the Lisp
559system makes into a flonum and returns.
560.sp 1v
561.lp
562There are three types in the second group:
563.ip \fBc-function\fP
564This is like an integer function, except for its different interpretation
565of arguments.
566.ip \fBdouble-c-function\fP
567This is like a real-function.
568.ip \fBvector-c-function\fP
569This is for C functions which return a structure.
570The first argument to such functions must be a vector (of type vectori),
571into which the result is stored.
572The second Lisp argument
573becomes the first argument to the C function, and so on
574.lp
575A foreign function is accessed through a binary object just like a
576compiled Lisp function.
577The difference is that the discipline field of a binary object
578for a foreign function is a string
579whose first character is given in the following table:
580.sp 1v
581.TS
582box center ;
583c | c .
584letter type
585=
586s subroutine
587_
588f function
589_
590i integer-function
591_
592r real-function.
593_
594c c-function
595_
596v vector-c-function
597_
598d double-c-function
599_
600.TE
601Two functions are provided for setting-up foreign functions.
602.i Cfasl
603loads an object file into the Lisp system and sets up one foreign
604function binary object.
605If there are more than one function in an object file,
606.i getaddress
607can be used to set up additional foreign function objects.
608.pp
609Foreign functions are called just like other functions, e.g
610\fI(funname\ arg1\ arg2)\fP.
611When a function in the Fortran group is called,
612the arguments are evaluated and then examined.
613List, hunk and symbol arguments are passed unchanged to
614the foreign function.
615Fixnum and flonum arguments are copied into a temporary location and
616a pointer to the value is passed (this is because Fortran uses call
617by reference and it is dangerous to modify the contents of a fixnum
618or flonum which something else might point to).
619If the argument is an array object,
620the data field of the array object is
621passed to the foreign function
622(This is the easiest way to send large
623amounts of data to and receive large amounts of data from a foreign
624function).
625If a binary object is an argument, the entry field of that object is
626passed to the foreign function (the entry field is the address of a function,
627so this amounts to passing a function as an argument).
628.pp
629When a function in the C group is called,
630fixnum and flownum arguments are passed by value.
631For almost all other arguments,
632the address is merely provided to the C routine.
633The only exception arises when you want to invoke a C routine
634which expects a ``structure'' argument. Recall that a (rarely used)
635feature of the C language is the ability to pass structures by value.
636This copies the structure onto the stack. Since the Franz's nearest
637equivalent to a C structure is a vector, we provide an escape clause
638to copy the contents of an immediate-type vector by value. If the
639property field of a vectori argument, is the symbol
640\*(lqvalue-structure-argument\*(rq,
641then the binary data of this immediate-type vector is copied
642into the argument list of the C routine.
643.pp
644The method a foreign function uses to access the arguments provided
645by Lisp is dependent on the language of the foreign function.
646The following scripts demonstrate how how Lisp can interact with three
647languages: C, Pascal and Fortran.
648C and Pascal have pointer types and the first script shows how to use
649pointers to extract information from Lisp objects.
650There are two functions defined for each language.
651The first (cfoo in C, pfoo in Pascal) is given four arguments, a
652fixnum, a flonum-block array, a hunk of at least two
653fixnums and a list of
654at least two fixnums.
655To demonstrate that the values were passed, each ?foo function prints
656its arguments (or parts of them).
657The ?foo function then modifies the second element of
658the flonum-block array and returns a 3 to Lisp.
659The second function (cmemq in C, pmemq in Pascal) acts just like the
660Lisp
661.i memq
662function (except it won't work for fixnums whereas the lisp
663.i memq
664will work for small fixnums).
665In the script, typed input is in
666.b bold ,
667computer output is in roman
668and comments are in
669.i italic.
670.in 0
671.nf
672.sp 2v
673.sz -2
674.hl
675\fIThese are the C coded functions \fP
676% \fBcat ch8auxc.c\fP
677/* demonstration of c coded foreign integer-function */
678
679/* the following will be used to extract fixnums out of a list of fixnums */
680struct listoffixnumscell
681{ struct listoffixnumscell *cdr;
682 int *fixnum;
683};
684
685struct listcell
686{ struct listcell *cdr;
687 int car;
688};
689
690cfoo(a,b,c,d)
691int *a;
692double b[];
693int *c[];
694struct listoffixnumscell *d;
695{
696 printf("a: %d, b[0]: %f, b[1]: %f\n", *a, b[0], b[1]);
697 printf(" c (first): %d c (second): %d\n",
698 *c[0],*c[1]);
699 printf(" ( %d %d ... )\n ", *(d->fixnum), *(d->cdr->fixnum));
700 b[1] = 3.1415926;
701 return(3);
702}
703
704struct listcell *
705cmemq(element,list)
706int element;
707struct listcell *list;
708{
709 for( ; list && element != list->car ; list = list->cdr);
710 return(list);
711}
712.sp 2v
713\fIThese are the Pascal coded functions \fP
714% \fBcat ch8auxp.p\fP
715type pinteger = ^integer;
716 realarray = array[0..10] of real;
717 pintarray = array[0..10] of pinteger;
718 listoffixnumscell = record
719 cdr : ^listoffixnumscell;
720 fixnum : pinteger;
721 end;
722 plistcell = ^listcell;
723 listcell = record
724 cdr : plistcell;
725 car : integer;
726 end;
727
728function pfoo ( var a : integer ;
729 var b : realarray;
730 var c : pintarray;
731 var d : listoffixnumscell) : integer;
732begin
733 writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]);
734 writeln(' c (first):', c[0]^,' c (second):', c[1]^);
735 writeln(' ( ', d.fixnum^, d.cdr^.fixnum^, ' ...) ');
736 b[1] := 3.1415926;
737 pfoo := 3
738end ;
739
740{ the function pmemq looks for the Lisp pointer given as the first argument
741 in the list pointed to by the second argument.
742 Note that we declare " a : integer " instead of " var a : integer " since
743 we are interested in the pointer value instead of what it points to (which
744 could be any Lisp object)
745}
746function pmemq( a : integer; list : plistcell) : plistcell;
747begin
748 while (list <> nil) and (list^.car <> a) do list := list^.cdr;
749 pmemq := list;
750end ;
751.sp 2v
752\fIThe files are compiled\fP
753% \fBcc -c ch8auxc.c\fP
7541.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
755% \fBpc -c ch8auxp.p\fP
7563.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w
757.sp 2v
758% \fBlisp\fP
759Franz Lisp, Opus 38.60
760.ft I
761.fi
762First the files are loaded and we set up one foreign function binary.
763We have two functions in each file so we must choose one to tell cfasl about.
764The choice is arbitrary.
765.ft P
766.br
767.nf
768\->\fB (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")\fP
769/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0 -lc
770#63000-"integer-function"
771\->\fB (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")\fP
772/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
773#63200-"integer-function"
774.ft I
775Here we set up the other foreign function binary objects
776.ft P
777\->\fB (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")\fP
778#6306c-"function"
779.ft I
780.fi
781We want to create and initialize an array to pass to the cfoo function.
782In this case we create an unnamed array and store it in the value cell of
783testarr.
784When we create an array to pass to the Pascal program we will use a named
785array just to demonstrate the different way that named and unnamed arrays
786are created and accessed.
787.br
788.nf
789.ft P
790\->\fB (setq testarr (array nil flonum-block 2))\fP
791array[2]
792\->\fB (store (funcall testarr 0) 1.234)\fP
7931.234
794\->\fB (store (funcall testarr 1) 5.678)\fP
7955.678
796\->\fB (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))\fP
797a: 385, b[0]: 1.234000, b[1]: 5.678000
798 c (first): 10 c (second): 11
799 ( 15 16 ... )
800 3
801.ft I
802.fi
803Note that cfoo has returned 3 as it should.
804It also had the side effect of changing the second value of the array to
8053.1415926 which check next.
806.br
807.nf
808.ft P
809\->\fB (funcall testarr 1)\fP
8103.1415926
811.sp 2v
812.fi
813.ft I
814In preparation for calling pfoo we create an array.
815.ft P
816.nf
817\->\fB (array test flonum-block 2)\fP
818array[2]
819\->\fB (store (test 0) 1.234)\fP
8201.234
821\->\fB (store (test 1) 5.678)\fP
8225.678
823\->\fB (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))\fP
824 a: 385 b[0]: 1.23400000000000E+00 b[1]: 5.67800000000000E+00
825 c (first): 10 c (second): 11
826 ( 15 16 ...)
8273
828\->\fB (test 1)\fP
8293.1415926
830.sp 1v
831\fI Now to test out the memq's
832\-> \fB(cmemq 'a '(b c a d e f))\fP
833(a d e f)
834\-> \fB(pmemq 'e '(a d f g a x))\fP
835nil
836.hl
837.fi
838.sz +2
839.sp 3v
840.pp
841The Fortran example will be much shorter since in Fortran
842you can't follow pointers
843as you can in other languages.
844The Fortran function ffoo is given three arguments: a fixnum, a
845fixnum-block array and a flonum.
846These arguments are printed out to verify that they made it and
847then the first value of the array is modified.
848The function returns a double precision value which is converted to a flonum
849by lisp and printed.
850Note that the entry point corresponding to the Fortran function ffoo is
851_ffoo_ as opposed to the C and Pascal convention of preceding the name with
852an underscore.
853.sp 1v
854.in 0
855.nf
856.sz -2
857.hl
858
859% \fBcat ch8auxf.f\fP
860 double precision function ffoo(a,b,c)
861 integer a,b(10)
862 double precision c
863 print 2,a,b(1),b(2),c
8642 format(' a=',i4,', b(1)=',i5,', b(2)=',i5,' c=',f6.4)
865 b(1) = 22
866 ffoo = 1.23456
867 return
868 end
869% \fBf77 -c ch8auxf.f\fP
870ch8auxf.f:
871 ffoo:
8720.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
873% \fBlisp\fP
874Franz Lisp, Opus 38.60
875\-> \fB(cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")\fP
876/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxf.o -e _ffoo_
877-o /tmp/Li11066.0 -lF77 -lI77 -lc
878#6307c-"real-function"
879.sp 1v
880\-> \fB(array test fixnum-block 2)\fP
881array[2]
882\->\fB (store (test 0) 10)\fP
88310
884\-> \fB(store (test 1) 11)\fP
88511
886\-> \fB(ffoo 385 (getd 'test) 5.678)\fP
887 a= 385, b(1)= 10, b(2)= 11 c=5.6780
8881.234559893608093
889\-> \fB(test 0)\fP
89022
891
892.hl