The FRANZ LISP Manual by _J_o_h_n _K_. _F_o_d_e_r_a_r_o _K_e_i_t_h _L_. _S_k_l_o_w_e_r _K_e_v_i_n _L_a_y_e_r June 1983 A document in four movements 9 9 PS2:9-2 The Franz Lisp Manual _O_v_e_r_t_u_r_e _A _c_h_o_r_u_s _o_f _s_t_u_d_e_n_t_s _u_n_d_e_r _t_h_e _d_i_r_e_c_t_i_o_n _o_f _R_i_c_h_a_r_d _F_a_t_e_m_a_n _h_a_v_e _c_o_n_t_r_i_b_u_t_e_d _t_o _b_u_i_l_d_i_n_g _F_R_A_N_Z _L_I_S_P _f_r_o_m _a _m_e_r_e _m_e_l_o_d_y _i_n_t_o _a _f_u_l_l _s_y_m_p_h_o_n_y . _T_h_e _m_a_j_o_r _c_o_n_t_r_i_b_u_t_o_r_s _t_o _t_h_e _i_n_i_t_i_a_l _s_y_s_t_e_m _w_e_r_e _M_i_k_e _C_u_r_r_y, _J_o_h_n _B_r_e_e_d_l_o_v_e _a_n_d _J_e_f_f _L_e_v_i_n_s_k_y. _B_i_l_l _R_o_w_a_n _a_d_d_e_d _t_h_e _g_a_r_b_a_g_e _c_o_l_l_e_c_t_o_r _a_n_d _a_r_r_a_y _p_a_c_k_a_g_e. _T_o_m _L_o_n_d_o_n _w_o_r_k_e_d _o_n _a_n _e_a_r_l_y _c_o_m_p_i_l_e_r _a_n_d _h_e_l_p_e_d _i_n _o_v_e_r_a_l_l _s_y_s_t_e_m _d_e_s_i_g_n. _K_e_i_t_h _S_k_l_o_w_e_r _h_a_s _c_o_n_t_r_i_b_u_t_e_d _m_u_c_h _t_o _F_R_A_N_Z _L_I_S_P, _a_d_d_i_n_g _t_h_e _b_i_g_n_u_m _p_a_c_k_a_g_e _a_n_d _r_e_w_r_i_t_i_n_g _m_o_s_t _o_f _t_h_e _c_o_d_e _t_o _i_n_c_r_e_a_s_e _i_t_s _e_f_f_i_c_i_e_n_c_y _a_n_d _c_l_a_r_i_t_y. _K_i_p_p _H_i_c_k_m_a_n _a_n_d _C_h_a_r_l_e_s _K_o_e_s_t_e_r _a_d_d_e_d _h_u_n_k_s. _M_i_t_c_h _M_a_r_c_u_s _a_d_d_e_d *_r_s_e_t, _e_v_a_l_h_o_o_k _a_n_d _e_v_a_l_f_r_a_m_e. _D_o_n _C_o_h_e_n _a_n_d _o_t_h_e_r_s _a_t _C_a_r_n_e_g_i_e-_M_e_l_l_o_n _m_a_d_e _s_o_m_e _i_m_p_r_o_v_e_m_e_n_t_s _t_o _e_v_a_l_f_r_a_m_e _a_n_d _p_r_o_v_i_d_e_d _v_a_r_i_o_u_s _f_e_a_t_u_r_e_s _m_o_d_e_l_l_e_d _a_f_t_e_r _U_C_I/_C_M_U _P_D_P-_1_0 _L_i_s_p _a_n_d _I_n_t_e_r_l_i_s_p _e_n_v_i_r_o_n_m_e_n_t_s (_e_d_i_t_o_r, _d_e_b_u_g_g_e_r, _t_o_p- _l_e_v_e_l). _J_o_h_n _F_o_d_e_r_a_r_o _w_r_o_t_e _t_h_e _c_o_m_p_i_l_e_r, _a_d_d_e_d _a _f_e_w _f_u_n_c_t_i_o_n_s, _a_n_d _w_r_o_t_e _m_u_c_h _o_f _t_h_i_s _m_a_n_u_a_l. _O_f _c_o_u_r_s_e, _o_t_h_e_r _a_u_t_h_o_r_s _h_a_v_e _c_o_n_t_r_i_b_u_t_e_d _s_p_e_c_i_f_i_c _c_h_a_p_t_e_r_s _a_s _i_n_d_i_c_a_t_e_d. _K_e_v_i_n _L_a_y_e_r _m_o_d_i_f_i_e_d _t_h_e _c_o_m_p_i_l_e_r _t_o _p_r_o_d_u_c_e _c_o_d_e _f_o_r _t_h_e _M_o_t_o_r_o_l_a _6_8_0_0_0, _a_n_d _h_e_l_p_e_d _m_a_k_e _F_R_A_N_Z _L_I_S_P _p_a_s_s ``_L_i_n_t''. _T_h_i_s _m_a_n_u_a_l _m_a_y _b_e _s_u_p_p_l_e_m_e_n_t_e_d _o_r _s_u_p_p_l_a_n_t_e_d _b_y _l_o_c_a_l _c_h_a_p_t_e_r_s _r_e_p_r_e_s_e_n_t_i_n_g _a_l_t_e_r_a_t_i_o_n_s, _a_d_d_i_t_i_o_n_s _a_n_d _d_e_l_e_t_i_o_n_s. _W_e _a_t _U._C. _B_e_r_k_e_l_e_y _a_r_e _p_l_e_a_s_e_d _t_o _l_e_a_r_n _o_f _g_e_n_e_r_a_l_l_y _u_s_e_f_u_l _s_y_s_t_e_m _f_e_a_t_u_r_e_s, _b_u_g _f_i_x_e_s, _o_r _u_s_e_f_u_l _p_r_o_g_r_a_m _p_a_c_k_a_g_e_s, _a_n_d _w_e _w_i_l_l _a_t_t_e_m_p_t _t_o _r_e_d_i_s_t_r_i_b_u_t_e _s_u_c_h _c_o_n_t_r_i_b_u_t_i_o_n_s. 98c9 1980, 1981, 1983 by the Regents of the University of Cali- fornia. (exceptions: Chapters 13, 14 (first half), 15 and 16 have separate copyrights, as indicated. These are repro- duced by permission of the copyright holders.) Permission to copy without fee all or part of this material is granted provided that the copies are not made or distri- buted for direct commercial advantage, and the copyright notice of the Regents, University of California, is given. All rights reserved. 9 The Franz Lisp Manual PS2:9-3 Work reported herein was supported in part by the U. S. Department of Energy, Contract DE-AT03-76SF00034, Project Agreement DE-AS03-79ER10358, and the National Science Foun- dation under Grant No. MCS 7807291 UNIX is a trademark of Bell Laboratories. VAX and PDP are trademarks of Digital Equiptment Coporation. MC68000 is a trademark of Motorola Semiconductor Products, Inc. 9 9 PS2:9-4 The Franz Lisp Manual Score First Movement (_a_l_l_e_g_r_o _n_o_n _t_r_o_p_p_o) 1. FRANZ LISP _I_n_t_r_o_d_u_c_t_i_o_n _t_o _F_R_A_N_Z _L_I_S_P, _d_e_t_a_i_l_s _o_f _d_a_t_a _t_y_p_e_s, _a_n_d _d_e_s_c_r_i_p_t_i_o_n _o_f _n_o_t_a_t_i_o_n 2. Data Structure Access _F_u_n_c_t_i_o_n_s _f_o_r _t_h_e _c_r_e_a_t_i_o_n, _d_e_s_t_r_u_c_t_i_o_n _a_n_d _m_a_n_i_- _p_u_l_a_t_i_o_n _o_f _l_i_s_p _d_a_t_a _o_b_j_e_c_t_s. 3. Arithmetic Functions _F_u_n_c_t_i_o_n_s _t_o _p_e_r_f_o_r_m _a_r_i_t_h_m_e_t_i_c _o_p_e_r_a_t_i_o_n_s. 4. Special Functions _F_u_n_c_t_i_o_n_s _f_o_r _a_l_t_e_r_i_n_g _f_l_o_w _o_f _c_o_n_t_r_o_l. _F_u_n_c_t_i_o_n_s _f_o_r _m_a_p_p_i_n_g _o_t_h_e_r _f_u_n_c_t_i_o_n_s _o_v_e_r _l_i_s_t_s. 5. I/O Functions _F_u_n_c_t_i_o_n_s _f_o_r _r_e_a_d_i_n_g _a_n_d _w_r_i_t_i_n_g _f_r_o_m _p_o_r_t_s. _F_u_n_c_t_i_o_n_s _f_o_r _t_h_e _m_o_d_i_f_i_c_a_t_i_o_n _o_f _t_h_e _r_e_a_d_e_r'_s _s_y_n_t_a_x. 6. System Functions _F_u_n_c_t_i_o_n_s _f_o_r _s_t_o_r_a_g_e _m_a_n_a_g_e_m_e_n_t, _d_e_b_u_g_g_i_n_g, _a_n_d _f_o_r _t_h_e _r_e_a_d_i_n_g _a_n_d _s_e_t_t_i_n_g _o_f _g_l_o_b_a_l _L_i_s_p _s_t_a_t_u_s _v_a_r_i_a_b_l_e_s. _F_u_n_c_t_i_o_n_s _f_o_r _d_o_i_n_g _U_N_I_X-_s_p_e_c_i_f_i_c _t_a_s_k_s _s_u_c_h _a_s _p_r_o_c_e_s_s _c_o_n_t_r_o_l. Second Movement (_L_a_r_g_o) 7. The Reader _A _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _s_y_n_t_a_x _c_o_d_e_s _u_s_e_d _b_y _t_h_e _r_e_a_d_e_r. _A_n _e_x_p_l_a_n_a_t_i_o_n _o_f _c_h_a_r_a_c_t_e_r _m_a_c_r_o_s. 8. Functions, Fclosures, and Macros _A _d_e_s_c_r_i_p_t_i_o_n _o_f _v_a_r_i_o_u_s _t_y_p_e_s _o_f _f_u_n_c_t_i_o_n_a_l _o_b_j_e_c_t_s. _A_n _e_x_a_m_p_l_e _o_f _t_h_e _u_s_e _o_f _f_o_r_e_i_g_n _f_u_n_c_- _t_i_o_n_s. 9. Arrays and Vectors _A _d_e_t_a_i_l_e_d _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _p_a_r_t_s _o_f _a_n _a_r_r_a_y _a_n_d _o_f _M_a_c_l_i_s_p _c_o_m_p_a_t_i_b_l_e _a_r_r_a_y_s. 10. Exception Handling _A _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _e_r_r_o_r _h_a_n_d_l_i_n_g _s_e_q_u_e_n_c_e _a_n_d _o_f _a_u_t_o_l_o_a_d_i_n_g. 9 9 The Franz Lisp Manual PS2:9-5 Third Movement (_S_c_h_e_r_z_o) 11. The Joseph Lister Trace Package _A _d_e_s_c_r_i_p_t_i_o_n _o_f _a _v_e_r_y _u_s_e_f_u_l _d_e_b_u_g_g_i_n_g _a_i_d. 12. Liszt, the lisp compiler _A _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _o_p_e_r_a_t_i_o_n _o_f _t_h_e _c_o_m_p_i_l_e_r _a_n_d _h_i_n_t_s _f_o_r _m_a_k_i_n_g _f_u_n_c_t_i_o_n_s _c_o_m_p_i_l_a_b_l_e. 13. CMU Top Level and File Package _A _d_e_s_c_r_i_p_t_i_o_n _o_f _a _t_o_p _l_e_v_e_l _w_i_t_h _a _h_i_s_t_o_r_y _m_e_c_h_a_n_i_s_m _a_n_d _a _p_a_c_k_a_g_e _w_h_i_c_h _h_e_l_p_s _y_o_u _k_e_e_p _t_r_a_c_k _o_f _f_i_l_e_s _o_f _l_i_s_p _f_u_n_c_t_i_o_n_s. 14 Stepper _A _d_e_s_c_r_i_p_t_i_o_n _o_f _a _p_r_o_g_r_a_m _w_h_i_c_h _p_e_r_m_i_t_s _y_o_u _t_o _p_u_t _b_r_e_a_k_p_o_i_n_t_s _i_n _l_i_s_p _c_o_d_e _a_n_d _t_o _s_i_n_g_l_e _s_t_e_p _i_t. _A _d_e_s_c_r_i_p_t_i_o_n _o_f _t_h_e _e_v_a_l_h_o_o_k _a_n_d _f_u_n_c_a_l_l_h_o_o_k _m_e_c_h_a_n_i_s_m. 15 Fixit _A _p_r_o_g_r_a_m _w_h_i_c_h _p_e_r_m_i_t_s _y_o_u _t_o _e_x_a_m_i_n_e _a_n_d _m_o_d_i_f_y _e_v_a_l_u_a_t_i_o_n _s_t_a_c_k _i_n _o_r_d_e_r _t_o _f_i_x _b_u_g_s _o_n _t_h_e _f_l_y. 16 Lisp Editor _A _s_t_r_u_c_t_u_r_e _e_d_i_t_o_r _f_o_r _i_n_t_e_r_a_c_t_i_v_e _m_o_d_i_f_i_c_a_t_i_o_n _o_f _l_i_s_p _c_o_d_e. Final Movement (_a_l_l_e_g_r_o) Appendix A - Function Index Appendix B - List of Special Symbols Appendix C - Short Subjects _G_a_r_b_a_g_e _c_o_l_l_e_c_t_o_r, _D_e_b_u_g_g_i_n_g, _D_e_f_a_u_l_t _T_o_p _L_e_v_e_l 9 9 CHAPTER 1 FRANZ LISP _1._1. FRANZ LISP[|-] was created as a tool to further research in symbolic and algebraic manipulation, artificial intelligence, and programming languages at the University of California at Berkeley. Its roots are in a PDP-11 Lisp system which originally came from Harvard. As it grew it adopted features of Maclisp and Lisp Machine Lisp. Substantial compatibility with other Lisp dialects (Interlisp, UCILisp, CMULisp) is achieved by means of support packages and compiler switches. The heart of FRANZ LISP is written almost entirely in the programming language C. Of course, it has been greatly extended by additions written in Lisp. A small part is written in the assembly language for the current host machines, VAXen and a couple of flavors of 68000. Because FRANZ LISP is written in C, it is relatively portable and easy to comprehend. FRANZ LISP is capable of running large lisp pro- grams in a timesharing environment, has facilities for arrays and user defined structures, has a user con- trolled reader with character and word macro capabil- ities, and can interact directly with compiled Lisp, C, Fortran, and Pascal code. This document is a reference manual for the FRANZ LISP system. It is not a Lisp primer or introduction to the language. Some parts will be of interest pri- marily to those maintaining FRANZ LISP at their com- puter site. There is an additional document entitled _T_h_e _F_r_a_n_z _L_i_s_p _S_y_s_t_e_m, by John Foderaro, which par- tially describes the system implementation. FRANZ LISP, as delivered by Berkeley, includes all source code and machine readable version of this manual and system document. The system document is in a single ____________________ 9 [|-]It is rumored that this name has something to do with Franz Liszt [F_rants List] (1811-1886) a Hungarian composer and keyboard virtuoso. These allegations have never been proven. 9PS2:9-6 The Franz Lisp Manual The Franz Lisp Manual PS2:9-7 file named "franz.n" in the "doc" subdirectory. This document is divided into four Movements. In the first one we will attempt to describe the language of FRANZ LISP precisely and completely as it now stands (Opus 38.69, June 1983). In the second Move- ment we will look at the reader, function types, arrays and exception handling. In the third Movement we will look at several large support packages written to help the FRANZ LISP user, namely the trace package, compiler, fixit and stepping package. Finally the fourth movement contains an index into the other movements. In the rest of this chapter we shall exam- ine the data types of FRANZ LISP. The conventions used in the description of the FRANZ LISP functions will be given in 1.3 -- it is very important that these conventions are understood. _1._2. _D_a_t_a _T_y_p_e_s FRANZ LISP has fourteen data types. In this section we shall look in detail at each type and if a type is divisible we shall look inside it. There is a Lisp function _t_y_p_e which will return the type name of a lisp object. This is the official FRANZ LISP name for that type and we will use this name and this name only in the manual to avoid confus- ing the reader. The types are listed in terms of importance rather than alphabetically. _1._2._0. _l_i_s_p_v_a_l This is the name we use to describe any Lisp object. The function _t_y_p_e will never return `lispval'. _1._2._1. _s_y_m_b_o_l This object corresponds to a variable in most other programming languages. It may have a value or may be `unbound'. A symbol may be _l_a_m_b_d_a _b_o_u_n_d meaning that its current value is stored away somewhere and the symbol is given a new value for the duration of a certain context. When the Lisp processor leaves that context, the symbol's current value is thrown away and its old value is restored. 9 A symbol may also have a _f_u_n_c_t_i_o_n _b_i_n_d_i_n_g. This function binding is static; it cannot be lambda bound. Whenever the symbol is used in the func- tional position of a Lisp expression the function binding of the symbol is examined (see Chapter 4 9 PS2:9-8 The Franz Lisp Manual for more details on evaluation). 9 A symbol may also have a _p_r_o_p_e_r_t_y _l_i_s_t, another static data structure. The property list consists of a list of an even number of elements, considered to be grouped as pairs. The first element of the pair is the _i_n_d_i_c_a_t_o_r the second the _v_a_l_u_e of that indicator. 9 Each symbol has a print name (_p_n_a_m_e) which is how this symbol is accessed from input and referred to on (printed) output. 9 A symbol also has a hashlink used to link symbols together in the oblist -- this field is inaccessi- ble to the lisp user. 9 Symbols are created by the reader and by the func- tions _c_o_n_c_a_t, _m_a_k_n_a_m and their derivatives. Most symbols live on FRANZ LISP's sole _o_b_l_i_s_t, and therefore two symbols with the same print name are usually the exact same object (they are _e_q). Sym- bols which are not on the oblist are said to be _u_n_i_n_t_e_r_n_e_d. The function _m_a_k_n_a_m creates uninterned symbols while _c_o_n_c_a_t creates _i_n_t_e_r_n_e_d ones. 8 ____________________________________________________________ Subpart name Get value Set value Type 8 ________________________________________________________________________________________________________________________ value eval set lispval setq 8 ____________________________________________________________ property plist setplist list or nil list get putprop defprop 8 ____________________________________________________________ function getd putd array, binary, list binding def or nil 8 ____________________________________________________________ print name get_pname string 8 ____________________________________________________________ hash link 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| |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| _1._2._2. _l_i_s_t A list cell has two parts, called the car and cdr. List cells are created by the func- tion _c_o_n_s. 9 The Franz Lisp Manual PS2:9-9 8 ________________________________________________ Subpart name Get value Set value Type 8 ________________________________________________________________________________________________ car car rplaca lispval 8 ________________________________________________ cdr cdr rplacd lispval 8 ________________________________________________ 7 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 _1._2._3. _b_i_n_a_r_y This type acts as a function header for machine coded functions. It has two parts, a pointer to the start of the function and a symbol whose print name describes the argument _d_i_s_c_i_p_l_i_n_e. The discipline (if _l_a_m_b_d_a, _m_a_c_r_o or _n_l_a_m_b_d_a) deter- mines whether the arguments to this function will be evaluated by the caller before this function is called. If the discipline is a string (specifi- cally "_s_u_b_r_o_u_t_i_n_e", "_f_u_n_c_t_i_o_n", "_i_n_t_e_g_e_r-_f_u_n_c_t_i_o_n", "_r_e_a_l-_f_u_n_c_t_i_o_n", "_c-_f_u_n_c_t_i_o_n", "_d_o_u_b_l_e-_c-_f_u_n_c_t_i_o_n", or "_v_e_c_t_o_r-_c-_f_u_n_c_t_i_o_n" ) then this function is a foreign subroutine or function (see 8.5 for more details on this). Although the type of the _e_n_t_r_y field of a binary type object is usually string or other, the object pointed to is actually a sequence of machine instructions. Objects of type binary are created by _m_f_u_n_c_t_i_o_n, _c_f_a_s_l, and _g_e_t_a_d_d_r_e_s_s. 8 _________________________________________________________ Subpart name Get value Set value Type 8 __________________________________________________________________________________________________________________ entry getentry string or fixnum 8 _________________________________________________________ discipline getdisc putdisc symbol or fixnum 8 _________________________________________________________ 7 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 |8|7|7|7|7| 9 _1._2._4. _f_i_x_n_u_m A fixnum is an integer constant in the range -2[31] to 2[31]-1. Small fixnums (-1024 to 1023) are stored in a special table so they needn't be allocated each time one is needed. In principle, the range for fixnums is machine depen- dent, although all current implementations for franz have this range. 9 9 PS2:9-10 The Franz Lisp Manual _1._2._5. _f_l_o_n_u_m A flonum is a double precision real number. On the VAX, the range is +_2.9x10[-37] to +_1.7x10[38]. There are approximately sixteen decimal digits of precision. Other machines may have other ranges. _1._2._6. _b_i_g_n_u_m A bignum is an integer of potentially unbounded size. When integer arithmetic exceeds the limits of fixnums mentioned above, the calcula- tion is automatically done with bignums. Should calculation with bignums give a result which can be represented as a fixnum, then the fixnum represen- tation will be used[|-]. This contraction is known as _i_n_t_e_g_e_r _n_o_r_m_a_l_i_z_a_t_i_o_n. Many Lisp functions assume that integers are normalized. Bignums are composed of a sequence of _l_i_s_t cells and a cell known as an _s_d_o_t. The user should consider a _b_i_g_- _n_u_m structure indivisible and use functions such as _h_a_i_p_a_r_t, and _b_i_g_n_u_m-_l_e_f_t_s_h_i_f_t to extract parts of it. _1._2._7. _s_t_r_i_n_g A string is a null terminated sequence of characters. Most functions of symbols which operate on the symbol's print name will also work on strings. The default reader syntax is set so that a sequence of characters surrounded by dou- ble quotes is a string. _1._2._8. _p_o_r_t A port is a structure which the system I/O routines can reference to transfer data between the Lisp system and external media. Unlike other Lisp objects there are a very limited number of ports (20). Ports are allocated by _i_n_f_i_l_e and _o_u_t_- _f_i_l_e and deallocated by _c_l_o_s_e and _r_e_s_e_t_i_o. The _p_r_i_n_t function prints a port as a percent sign fol- lowed by the name of the file it is connected to (if the port was opened by _f_i_l_e_o_p_e_n, _i_n_f_i_l_e, _o_r _o_u_t_f_i_l_e). During initialization, FRANZ LISP binds the symbol piport to a port attached to the ____________________ 9 [|-]The current algorithms for integer arithmetic opera- tions will return (in certain cases) a result between +_2[30] and 2[31] as a bignum although this could be represented as a fixnum. 9 The Franz Lisp Manual PS2:9-11 standard input stream. This port prints as %$stdin. There are ports connected to the standard output and error streams, which print as %$stdout and %$stderr. This is discussed in more detail at the beginning of Chapter 5. _1._2._9. _v_e_c_t_o_r Vectors are indexed sequences of data. They can be used to implement a notion of user-defined types via their associated property list. They make hunks (see below) logically unnecessary, although hunks are very efficiently garbage collected. There is a second kind of vec- tor, called an immediate-vector, which stores binary data. The name that the function _t_y_p_e returns for immediate-vectors is vectori. Immediate-vectors could be used to implement strings and block-flonum arrays, for example. Vec- tors are discussed in chapter 9. The functions _n_e_w-_v_e_c_t_o_r, and _v_e_c_t_o_r, can be used to create vec- tors. 8 ________________________________________________ Subpart name Get value Set value Type 8 ________________________________________________________________________________________________ datum[_i] vref vset lispval 8 ________________________________________________ property vprop vsetprop lispval vputprop 8 ________________________________________________ size vsize - fixnum 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| _1._2._1_0. _a_r_r_a_y Arrays are rather complicated types and are fully described in Chapter 9. An array consists of a block of contiguous data, a function to access that data, and auxiliary fields for use by the accessing function. Since an array's accessing function is created by the user, an array can have any form the user chooses (e.g. n- dimensional, triangular, or hash table). Arrays are created by the function _m_a_r_r_a_y. 9 PS2:9-12 The Franz Lisp Manual 8 _______________________________________________________________ Subpart name Get value Set value Type 8 ______________________________________________________________________________________________________________________________ access function getaccess putaccess binary, list or symbol 8 _______________________________________________________________ auxiliary getaux putaux lispval 8 _______________________________________________________________ data arrayref replace block of contiguous set lispval 8 _______________________________________________________________ length getlength putlength fixnum 8 _______________________________________________________________ delta getdelta putdelta fixnum 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|7|7|7|7|7| |7|7|7|7|7|7|7|7|7|7|7| _1._2._1_1. _v_a_l_u_e A value cell contains a pointer to a lispval. This type is used mainly by arrays of general lisp objects. Value cells are created with the _p_t_r function. A value cell containing a pointer to the symbol `foo' is printed as `(ptr to)foo' _1._2._1_2. _h_u_n_k A hunk is a vector of from 1 to 128 lispvals. Once a hunk is created (by _h_u_n_k or _m_a_k_h_u_n_k) it cannot grow or shrink. The access time for an element of a hunk is slower than a list cell element but faster than an array. Hunks are really only allocated in sizes which are powers of two, but can appear to the user to be any size in the 1 to 128 range. Users of hunks must realize that (_n_o_t (_a_t_o_m '_l_i_s_p_v_a_l)) will return true if _l_i_s_p_v_a_l is a hunk. Most lisp systems do not have a direct test for a list cell and instead use the above test and assume that a true result means _l_i_s_p_v_a_l is a list cell. In FRANZ LISP you can use _d_t_p_r to check for a list cell. Although hunks are not list cells, you can still access the first two hunk ele- ments with _c_d_r and _c_a_r and you can access any hunk element with _c_x_r[|-]. You can set the value of the first two elements of a hunk with _r_p_l_a_c_d and _r_p_l_a_c_a and you can set the value of any element of the hunk with _r_p_l_a_c_x. A hunk is printed by printing ____________________ 9 [|-]In a hunk, the function _c_d_r references the first ele- ment and _c_a_r the second. The Franz Lisp Manual PS2:9-13 its contents surrounded by { and }. However a hunk cannot be read in in this way in the standard lisp system. It is easy to write a reader macro to do this if desired. _1._2._1_3. _o_t_h_e_r Occasionally, you can obtain a pointer to storage not allocated by the lisp sys- tem. One example of this is the entry field of those FRANZ LISP functions written in C. Such objects are classified as of type other. Foreign functions which call malloc to allocate their own space, may also inadvertantly create such objects. The garbage collector is supposed to ignore such objects. _1._3. _D_o_c_u_m_e_n_t_a_t_i_o_n The conventions used in the follow- ing chapters were designed to give a great deal of information in a brief space. The first line of a function description contains the function name in bold face and then lists the arguments, if any. The arguments all have names which begin with a letter or letters and an underscore. The letter(s) gives the allowable type(s) for that argument according to this table. 9 9 PS2:9-14 The Franz Lisp Manual 8 _______________________________________________________ Letter Allowable type(s) 8 ______________________________________________________________________________________________________________ g any type 8 _______________________________________________________ s symbol (although nil may not be allowed) 8 _______________________________________________________ t string 8 _______________________________________________________ l list (although nil may be allowed) 8 _______________________________________________________ n number (fixnum, flonum, bignum) 8 _______________________________________________________ i integer (fixnum, bignum) 8 _______________________________________________________ x fixnum 8 _______________________________________________________ b bignum 8 _______________________________________________________ f flonum 8 _______________________________________________________ u function type (either binary or lambda body) 8 _______________________________________________________ y binary 8 _______________________________________________________ v vector 8 _______________________________________________________ V vectori 8 _______________________________________________________ a array 8 _______________________________________________________ e value 8 _______________________________________________________ p port (or nil) 8 _______________________________________________________ h hunk 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|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|7|7| In the first line of a function description, those arguments preceded by a quote mark are evaluated (usu- ally before the function is called). The quoting con- vention is used so that we can give a name to the result of evaluating the argument and we can describe the allowable types. If an argument is not quoted it does not mean that that argument will not be evaluated, but rather that if it is evaluated, the time at which it is evaluated will be specifically mentioned in the function description. Optional argu- ments are surrounded by square brackets. An ellipsis (...) means zero or more occurrences of an argument of the directly preceding type. 9 CHAPTER 2 Data Structure Access The following functions allow one to create and manipulate the various types of lisp data structures. Refer to 1.2 for details of the data structures known to FRANZ LISP. _2._1. _L_i_s_t_s The following functions exist for the creation and manipulating of lists. Lists are composed of a linked list of objects called either 'list cells', 'cons cells' or 'dtpr cells'. Lists are normally ter- minated with the special symbol _n_i_l. _n_i_l is both a symbol and a representation for the empty list (). _2._1._1. _l_i_s_t _c_r_e_a_t_i_o_n (cons 'g_arg1 'g_arg2) RETURNS: a new list cell whose car is g_arg1 and whose cdr is g_arg2. (xcons 'g_arg1 'g_arg2) EQUIVALENT TO: (_c_o_n_s '_g__a_r_g_2 '_g__a_r_g_1) (ncons 'g_arg) EQUIVALENT TO: (_c_o_n_s '_g__a_r_g _n_i_l) (list ['g_arg1 ... ]) RETURNS: a list whose elements are the g_arg_i. 9 9The Franz Lisp Manual PS2:9-15 PS2:9-16 The Franz Lisp Manual (append 'l_arg1 'l_arg2) RETURNS: a list containing the elements of l_arg1 fol- lowed by l_arg2. NOTE: To generate the result, the top level list cells of l_arg1 are duplicated and the cdr of the last list cell is set to point to l_arg2. Thus this is an expensive operation if l_arg1 is large. See the descriptions of _n_c_o_n_c and _t_c_o_n_c for cheaper ways of doing the _a_p_p_e_n_d if the list l_arg1 can be altered. (append1 'l_arg1 'g_arg2) RETURNS: a list like l_arg1 with g_arg2 as the last element. NOTE: this is equivalent to (append 'l_arg1 (list 'g_arg2)). ____________________________________________________ ; A common mistake is using append to add one element to the end of a list -> (_a_p_p_e_n_d '(_a _b _c _d) '_e) (a b c d . e) ; The user intended to say: -> (_a_p_p_e_n_d '(_a _b _c _d) '(_e)) (_a _b _c _d _e) ; _b_e_t_t_e_r _i_s _a_p_p_e_n_d_1 -> (_a_p_p_e_n_d_1 '(_a _b _c _d) '_e) (_a _b _c _d _e) ____________________________________________________ (quote! [g_qform_i] ...[! 'g_eform_i] ... [!! 'l_form_i] ...) RETURNS: The list resulting from the splicing and insertion process described below. NOTE: _q_u_o_t_e! is the complement of the _l_i_s_t function. _l_i_s_t forms a list by evaluating each for in the argument list; evaluation is suppressed if the form is _q_u_o_t_eed. In _q_u_o_t_e!, each form is impli- citly _q_u_o_t_eed. To be evaluated, a form must be preceded by one of the evaluate operations ! and !!. ! g_eform evaluates g_form and the value is inserted in the place of the call; !! l_form evaluates l_form and the value is spliced into the place of the call. The Franz Lisp Manual PS2:9-17 `Splicing in' means that the parentheses sur- rounding the list are removed as the example below shows. Use of the evaluate operators can occur at any level in a form argument. Another way to get the effect of the _q_u_o_t_e! func- tion is to use the backquote character macro (see 8.3.3). ____________________________________________________ (_q_u_o_t_e! _c_o_n_s ! (_c_o_n_s _1 _2) _3) = (_c_o_n_s (_1 . _2) _3) (_q_u_o_t_e! _1 !! (_l_i_s_t _2 _3 _4) _5) = (_1 _2 _3 _4 _5) (_s_e_t_q _q_u_o_t_e_d '_e_v_a_l_e_d)(_q_u_o_t_e! ! ((_I _a_m ! _q_u_o_t_e_d))) = ((_I _a_m _e_v_a_l_e_d)) (_q_u_o_t_e! _t_r_y ! '(_t_h_i_s ! _o_n_e)) = (_t_r_y (_t_h_i_s ! _o_n_e)) ____________________________________________________ (bignum-to-list 'b_arg) RETURNS: A list of the fixnums which are used to represent the bignum. NOTE: the inverse of this function is _l_i_s_t-_t_o-_b_i_g_n_u_m. (list-to-bignum 'l_ints) WHERE: l_ints is a list of fixnums. RETURNS: a bignum constructed of the given fixnums. NOTE: the inverse of this function is _b_i_g_n_u_m-_t_o-_l_i_s_t. _2._1._2. _l_i_s_t _p_r_e_d_i_c_a_t_e_s 9 9 PS2:9-18 The Franz Lisp Manual (dtpr 'g_arg) RETURNS: t iff g_arg is a list cell. NOTE: that (dtpr '()) is nil. The name dtpr is a con- traction for ``dotted pair''. (listp 'g_arg) RETURNS: t iff g_arg is a list object or nil. (tailp 'l_x 'l_y) RETURNS: l_x, if a list cell _e_q to l_x is found by _c_d_ring down l_y zero or more times, nil other- wise. ____________________________________________________ -> (_s_e_t_q _x '(_a _b _c _d) _y (_c_d_d_r _x)) (c d) -> (_a_n_d (_d_t_p_r _x) (_l_i_s_t_p _x)) ; x and y are dtprs and lists t -> (_d_t_p_r '()) ; () is the same as nil and is not a dtpr nil -> (_l_i_s_t_p '()) ; however it is a list t -> (_t_a_i_l_p _y _x) (c d) ____________________________________________________ (length 'l_arg) RETURNS: the number of elements in the top level of list l_arg. _2._1._3. _l_i_s_t _a_c_c_e_s_s_i_n_g 9 9 The Franz Lisp Manual PS2:9-19 (car 'l_arg) (cdr 'l_arg) RETURNS: _c_o_n_s cell. (_c_a_r (_c_o_n_s x y)) is always x, (_c_d_r (_c_o_n_s x y)) is always y. In FRANZ LISP, the cdr portion is located first in memory. This is hardly noticeable, and we mention it pri- marily as a curiosity. (c..r 'lh_arg) WHERE: the .. represents any positive number of a's and d's. RETURNS: the result of accessing the list structure in the way determined by the function name. The a's and d's are read from right to left, a _d directing the access down the cdr part of the list cell and an _a down the car part. NOTE: lh_arg may also be nil, and it is guaranteed that the car and cdr of nil is nil. If lh_arg is a hunk, then (_c_a_r '_l_h__a_r_g) is the same as (_c_x_r _1 '_l_h__a_r_g) and (_c_d_r '_l_h__a_r_g) is the same as (_c_x_r _0 '_l_h__a_r_g). It is generally hard to read and understand the context of functions with large strings of _a's and _d's, but these functions are supported by rapid accessing and open-compiling (see Chapter 12). (nth 'x_index 'l_list) RETURNS: the nth element of l_list, assuming zero-based index. Thus (nth 0 l_list) is the same as (car l_list). _n_t_h is both a function, and a compiler macro, so that more efficient code might be generated than for _n_t_h_e_l_e_m (described below). NOTE: If x_arg1 is non-positive or greater than the length of the list, nil is returned. 9 9 PS2:9-20 The Franz Lisp Manual (nthcdr 'x_index 'l_list) RETURNS: the result of _c_d_ring down the list l_list x_index times. NOTE: If x_index is less than 0, then (_c_o_n_s _n_i_l '_l__l_i_s_t) is returned. (nthelem 'x_arg1 'l_arg2) RETURNS: The x_arg1'_s_t element of the list l_arg2. NOTE: This function comes from the PDP-11 Lisp system. (last 'l_arg) RETURNS: the last list cell in the list l_arg. EXAMPLE: _l_a_s_t does NOT return the last element of a list! (_l_a_s_t '(_a _b)) = (b) (ldiff 'l_x 'l_y) RETURNS: a list of all elements in l_x but not in l_y , i.e., the list difference of l_x and l_y. NOTE: l_y must be a tail of l_x, i.e., _e_q to the result of applying some number of _c_d_r's to l_x. Note that the value of _l_d_i_f_f is always new list structure unless l_y is nil, in which case (_l_d_i_f_f _l__x _n_i_l) is l_x itself. If l_y is not a tail of l_x, _l_d_i_f_f generates an error. EXAMPLE: (_l_d_i_f_f '_l__x (_m_e_m_b_e_r '_g__f_o_o '_l__x)) gives all elements in l_x up to the first g_foo. _2._1._4. _l_i_s_t _m_a_n_i_p_u_l_a_t_i_o_n (rplaca 'lh_arg1 'g_arg2) RETURNS: the modified lh_arg1. SIDE EFFECT: the car of lh_arg1 is set to g_arg2. If lh_arg1 is a hunk then the second element of the hunk is set to g_arg2. 9 9 The Franz Lisp Manual PS2:9-21 (rplacd 'lh_arg1 'g_arg2) RETURNS: the modified lh_arg1. SIDE EFFECT: the cdr of lh_arg2 is set to g_arg2. If lh_arg1 is a hunk then the first element of the hunk is set to g_arg2. (attach 'g_x 'l_l) RETURNS: l_l whose _c_a_r is now g_x, whose _c_a_d_r is the original (_c_a_r _l__l), and whose _c_d_d_r is the ori- ginal (_c_d_r _l__l). NOTE: what happens is that g_x is added to the begin- ning of list l_l yet maintaining the same list cell at the beginning of the list. (delete 'g_val 'l_list ['x_count]) RETURNS: the result of splicing g_val from the top level of l_list no more than x_count times. NOTE: x_count defaults to a very large number, thus if x_count is not given, all occurrences of g_val are removed from the top level of l_list. g_val is compared with successive _c_a_r's of l_list using the function _e_q_u_a_l. SIDE EFFECT: l_list is modified using rplacd, no new list cells are used. (delq 'g_val 'l_list ['x_count]) (dremove 'g_val 'l_list ['x_count]) RETURNS: the result of splicing g_val from the top level of l_list no more than x_count times. NOTE: _d_e_l_q (and _d_r_e_m_o_v_e) are the same as _d_e_l_e_t_e except that _e_q is used for comparison instead of _e_q_u_a_l. 9 9 PS2:9-22 The Franz Lisp Manual ____________________________________________________ ; note that you should use the value returned by _d_e_l_e_t_e or _d_e_l_q ; and not assume that g_val will always show the deletions. ; For example -> (_s_e_t_q _t_e_s_t '(_a _b _c _a _d _e)) (a b c a d e) -> (_d_e_l_e_t_e '_a _t_e_s_t) (b c d e) ; the value returned is what we would expect -> _t_e_s_t (a b c d e) ; but test still has the first a in the list! ____________________________________________________ (remq 'g_x 'l_l ['x_count]) (remove 'g_x 'l_l) RETURNS: a _c_o_p_y of l_l with all top level elements _e_q_u_a_l to g_x removed. _r_e_m_q uses _e_q instead of _e_q_u_a_l for comparisons. NOTE: remove does not modify its arguments like _d_e_l_e_t_e, and _d_e_l_q do. (insert 'g_object 'l_list 'u_comparefn 'g_nodups) RETURNS: a list consisting of l_list with g_object des- tructively inserted in a place determined by the ordering function u_comparefn. NOTE: (_c_o_m_p_a_r_e_f_n '_g__x '_g__y) should return something non-nil if g_x can precede g_y in sorted order, nil if g_y must precede g_x. If u_comparefn is nil, alphabetical order will be used. If g_nodups is non-nil, an element will not be inserted if an equal element is already in the list. _i_n_s_e_r_t does binary search to determine where to insert the new element. 9 9 The Franz Lisp Manual PS2:9-23 (merge 'l_data1 'l_data2 'u_comparefn) RETURNS: the merged list of the two input sorted lists l_data1 and l_data1 using binary comparison function u_comparefn. NOTE: (_c_o_m_p_a_r_e_f_n '_g__x '_g__y) should return something non-nil if g_x can precede g_y in sorted order, nil if g_y must precede g_x. If u_comparefn is nil, alphabetical order will be used. u_comparefn should be thought of as "less than or equal". _m_e_r_g_e changes both of its data argu- ments. (subst 'g_x 'g_y 'l_s) (dsubst 'g_x 'g_y 'l_s) RETURNS: the result of substituting g_x for all _e_q_u_a_l occurrences of g_y at all levels in l_s. NOTE: If g_y is a symbol, _e_q will be used for comparis- ons. The function _s_u_b_s_t does not modify l_s but the function _d_s_u_b_s_t (destructive substitution) does. (lsubst 'l_x 'g_y 'l_s) RETURNS: a copy of l_s with l_x spliced in for every occurrence of of g_y at all levels. Splicing in means that the parentheses surrounding the list l_x are removed as the example below shows. ____________________________________________________ -> (_s_u_b_s_t '(_a _b _c) '_x '(_x _y _z (_x _y _z) (_x _y _z))) ((a b c) y z ((a b c) y z) ((a b c) y z)) -> (_l_s_u_b_s_t '(_a _b _c) '_x '(_x _y _z (_x _y _z) (_x _y _z))) (a b c y z (a b c y z) (a b c y z)) ____________________________________________________ 9 9 PS2:9-24 The Franz Lisp Manual (subpair 'l_old 'l_new 'l_expr) WHERE: there are the same number of elements in l_old as l_new. RETURNS: the list l_expr with all occurrences of a object in l_old replaced by the corresponding one in l_new. When a substitution is made, a copy of the value to substitute in is not made. EXAMPLE: (_s_u_b_p_a_i_r '(_a _c)' (_x _y) '(_a _b _c _d)) = (_x _b _y _d) (nconc 'l_arg1 'l_arg2 ['l_arg3 ...]) RETURNS: A list consisting of the elements of l_arg1 followed by the elements of l_arg2 followed by l_arg3 and so on. NOTE: The _c_d_r of the last list cell of l_arg_i is changed to point to l_arg_i+_1. ____________________________________________________ ; _n_c_o_n_c is faster than _a_p_p_e_n_d because it doesn't allocate new list cells. -> (_s_e_t_q _l_i_s_1 '(_a _b _c)) (a b c) -> (_s_e_t_q _l_i_s_2 '(_d _e _f)) (d e f) -> (_a_p_p_e_n_d _l_i_s_1 _l_i_s_2) (a b c d e f) -> _l_i_s_1 (a b c) ; note that lis1 has not been changed by _a_p_p_e_n_d -> (_n_c_o_n_c _l_i_s_1 _l_i_s_2) (a b c d e f) ; _n_c_o_n_c returns the same value as _a_p_p_e_n_d -> _l_i_s_1 (a b c d e f) ; but in doing so alters lis1 ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-25 (reverse 'l_arg) (nreverse 'l_arg) RETURNS: the list l_arg with the elements at the top level in reverse order. NOTE: The function _n_r_e_v_e_r_s_e does the reversal in place, that is the list structure is modified. (nreconc 'l_arg 'g_arg) EQUIVALENT TO: (_n_c_o_n_c (_n_r_e_v_e_r_s_e '_l__a_r_g) '_g__a_r_g) _2._2. _P_r_e_d_i_c_a_t_e_s The following functions test for properties of data objects. When the result of the test is either 'false' or 'true', then nil will be returned for 'false' and something other than nil (often t) will be returned for 'true'. (arrayp 'g_arg) RETURNS: t iff g_arg is of type array. (atom 'g_arg) RETURNS: t iff g_arg is not a list or hunk object. NOTE: (_a_t_o_m '()) returns t. (bcdp 'g_arg) RETURNS: t iff g_arg is a data object of type binary. NOTE: This function is a throwback to the PDP-11 Lisp system. The name stands for binary code predi- cate. 9 9 PS2:9-26 The Franz Lisp Manual (bigp 'g_arg) RETURNS: t iff g_arg is a bignum. (dtpr 'g_arg) RETURNS: t iff g_arg is a list cell. NOTE: that (dtpr '()) is nil. (hunkp 'g_arg) RETURNS: t iff g_arg is a hunk. (listp 'g_arg) RETURNS: t iff g_arg is a list object or nil. (stringp 'g_arg) RETURNS: t iff g_arg is a string. (symbolp 'g_arg) RETURNS: t iff g_arg is a symbol. (valuep 'g_arg) RETURNS: t iff g_arg is a value cell (vectorp 'v_vector) RETURNS: t iff the argument is a vector. (vectorip 'v_vector) RETURNS: t iff the argument is an immediate-vector. (type 'g_arg) (typep 'g_arg) RETURNS: a symbol whose pname describes the type of g_arg. 9 9 The Franz Lisp Manual PS2:9-27 (signp s_test 'g_val) RETURNS: t iff g_val is a number and the given test s_test on g_val returns true. NOTE: The fact that _s_i_g_n_p simply returns nil if g_val is not a number is probably the most important reason that _s_i_g_n_p is used. The permitted values for s_test and what they mean are given in this table. 8 ____________________ s_test tested 8 ________________________________________ l g_val < 0 le g_val <_ 0 e g_val = 0 n g_val =/ 0 ge g_val >_ 0 g g_val > 0 8 ____________________ 7 |7|7|7|7|7|7|7|7| |7|7|7|7|7|7|7|7| (eq 'g_arg1 'g_arg2) RETURNS: t if g_arg1 and g_arg2 are the exact same lisp object. NOTE: _E_q simply tests if g_arg1 and g_arg2 are located in the exact same place in memory. Lisp objects which print the same are not necessarily _e_q. The only objects guaranteed to be _e_q are interned symbols with the same print name. [Unless a sym- bol is created in a special way (such as with _u_c_o_n_c_a_t or _m_a_k_n_a_m) it will be interned.] (neq 'g_x 'g_y) RETURNS: t if g_x is not _e_q to g_y, otherwise nil. 9 PS2:9-28 The Franz Lisp Manual (equal 'g_arg1 'g_arg2) (eqstr 'g_arg1 'g_arg2) RETURNS: t iff g_arg1 and g_arg2 have the same struc- ture as described below. NOTE: g_arg and g_arg2 are _e_q_u_a_l if (1) they are _e_q. (2) they are both fixnums with the same value (3) they are both flonums with the same value (4) they are both bignums with the same value (5) they are both strings and are identical. (6) they are both lists and their cars and cdrs are _e_q_u_a_l. ____________________________________________________ ; _e_q is much faster than _e_q_u_a_l, especially in compiled code, ; however you cannot use _e_q to test for equality of numbers outside ; of the range -1024 to 1023. _e_q_u_a_l will always work. -> (_e_q _1_0_2_3 _1_0_2_3) t -> (_e_q _1_0_2_4 _1_0_2_4) nil -> (_e_q_u_a_l _1_0_2_4 _1_0_2_4) t ____________________________________________________ (not 'g_arg) (null 'g_arg) RETURNS: t iff g_arg is nil. 9 9 The Franz Lisp Manual PS2:9-29 (member 'g_arg1 'l_arg2) (memq 'g_arg1 'l_arg2) RETURNS: that part of the l_arg2 beginning with the first occurrence of g_arg1. If g_arg1 is not in the top level of l_arg2, nil is returned. NOTE: _m_e_m_b_e_r tests for equality with _e_q_u_a_l, _m_e_m_q tests for equality with _e_q. _2._3. _S_y_m_b_o_l_s _a_n_d _S_t_r_i_n_g_s In many of the following functions the distinc- tion between symbols and strings is somewhat blurred. To remind ourselves of the difference, a string is a null terminated sequence of characters, stored as com- pactly as possible. Strings are used as constants in FRANZ LISP. They _e_v_a_l to themselves. A symbol has additional structure: a value, property list, function binding, as well as its external representation (or print-name). If a symbol is given to one of the string manipulation functions below, its print name will be used as the string. Another popular way to represent strings in Lisp is as a list of fixnums which represent characters. The suffix 'n' to a string manipulation function indi- cates that it returns a string in this form. _2._3._1. _s_y_m_b_o_l _a_n_d _s_t_r_i_n_g _c_r_e_a_t_i_o_n (concat ['stn_arg1 ... ]) (uconcat ['stn_arg1 ... ]) RETURNS: a symbol whose print name is the result of concatenating the print names, string charac- ters or numerical representations of the sn_arg_i. NOTE: If no arguments are given, a symbol with a null pname is returned. _c_o_n_c_a_t places the symbol created on the oblist, the function _u_c_o_n_c_a_t does the same thing but does not place the new symbol on the oblist. EXAMPLE: (_c_o_n_c_a_t '_a_b_c (_a_d_d _3 _4) "_d_e_f") = abc7def 9 9 PS2:9-30 The Franz Lisp Manual (concatl 'l_arg) EQUIVALENT TO: (_a_p_p_l_y '_c_o_n_c_a_t '_l__a_r_g) (implode 'l_arg) (maknam 'l_arg) WHERE: l_arg is a list of symbols, strings and small fixnums. RETURNS: The symbol whose print name is the result of concatenating the first characters of the print names of the symbols and strings in the list. Any fixnums are converted to the equivalent ascii character. In order to con- catenate entire strings or print names, use the function _c_o_n_c_a_t. NOTE: _i_m_p_l_o_d_e interns the symbol it creates, _m_a_k_n_a_m does not. (gensym ['s_leader]) RETURNS: a new uninterned atom beginning with the first character of s_leader's pname, or beginning with g if s_leader is not given. NOTE: The symbol looks like x0nnnnn where x is s_leader's first character and nnnnn is the number of times you have called gensym. (copysymbol 's_arg 'g_pred) RETURNS: an uninterned symbol with the same print name as s_arg. If g_pred is non nil, then the value, function binding and property list of the new symbol are made _e_q to those of s_arg. (ascii 'x_charnum) WHERE: x_charnum is between 0 and 255. RETURNS: a symbol whose print name is the single char- acter whose fixnum representation is x_charnum. 9 9 The Franz Lisp Manual PS2:9-31 (intern 's_arg) RETURNS: s_arg SIDE EFFECT: s_arg is put on the oblist if it is not already there. (remob 's_symbol) RETURNS: s_symbol SIDE EFFECT: s_symbol is removed from the oblist. (rematom 's_arg) RETURNS: t if s_arg is indeed an atom. SIDE EFFECT: s_arg is put on the free atoms list, effectively reclaiming an atom cell. NOTE: This function does _n_o_t check to see if s_arg is on the oblist or is referenced anywhere. Thus calling _r_e_m_a_t_o_m on an atom in the oblist may result in disaster when that atom cell is reused! _2._3._2. _s_t_r_i_n_g _a_n_d _s_y_m_b_o_l _p_r_e_d_i_c_a_t_e_s (boundp 's_name) RETURNS: nil if s_name is unbound: that is, it has never been given a value. If x_name has the value g_val, then (nil . g_val) is returned. See also _m_a_k_u_n_b_o_u_n_d. (alphalessp 'st_arg1 'st_arg2) RETURNS: t iff the `name' of st_arg1 is alphabetically less than the name of st_arg2. If st_arg is a symbol then its `name' is its print name. If st_arg is a string, then its `name' is the string itself. _2._3._3. _s_y_m_b_o_l _a_n_d _s_t_r_i_n_g _a_c_c_e_s_s_i_n_g 9 9 PS2:9-32 The Franz Lisp Manual (symeval 's_arg) RETURNS: the value of symbol s_arg. NOTE: It is illegal to ask for the value of an unbound symbol. This function has the same effect as _e_v_a_l, but compiles into much more efficient code. (get_pname 's_arg) RETURNS: the string which is the print name of s_arg. (plist 's_arg) RETURNS: the property list of s_arg. (getd 's_arg) RETURNS: the function definition of s_arg or nil if there is no function definition. NOTE: the function definition may turn out to be an array header. (getchar 's_arg 'x_index) (nthchar 's_arg 'x_index) (getcharn 's_arg 'x_index) RETURNS: the x_index_t_h character of the print name of s_arg or nil if x_index is less than 1 or greater than the length of s_arg's print name. NOTE: _g_e_t_c_h_a_r and _n_t_h_c_h_a_r return a symbol with a single character print name, _g_e_t_c_h_a_r_n returns the fixnum representation of the character. (substring 'st_string 'x_index ['x_length]) (substringn 'st_string 'x_index ['x_length]) RETURNS: a string of length at most x_length starting at x_index_t_h character in the string. NOTE: If x_length is not given, all of the characters for x_index to the end of the string are returned. If x_index is negative the string begins at the x_index_t_h character from the end. If x_index is out of bounds, nil is returned. NOTE: _s_u_b_s_t_r_i_n_g returns a list of symbols, _s_u_b_s_t_r_i_n_g_n returns a list of fixnums. If _s_u_b_s_t_r_i_n_g_n is given a 0 x_length argument then a single fixnum which is the x_index_t_h character is returned. 9 9 The Franz Lisp Manual PS2:9-33 _2._3._4. _s_y_m_b_o_l _a_n_d _s_t_r_i_n_g _m_a_n_i_p_u_l_a_t_i_o_n (set 's_arg1 'g_arg2) RETURNS: g_arg2. SIDE EFFECT: the value of s_arg1 is set to g_arg2. (setq s_atm1 'g_val1 [ s_atm2 'g_val2 ... ... ]) WHERE: the arguments are pairs of atom names and expressions. RETURNS: the last g_val_i. SIDE EFFECT: each s_atm_i is set to have the value g_val_i. NOTE: _s_e_t evaluates all of its arguments, _s_e_t_q does not evaluate the s_atm_i. (desetq sl_pattern1 'g_exp1 [... ...]) RETURNS: g_expn SIDE EFFECT: This acts just like _s_e_t_q if all the sl_pattern_i are symbols. If sl_pattern_i is a list then it is a template which should have the same structure as g_exp_i The symbols in sl_pattern are assigned to the corresponding parts of g_exp. (See also _s_e_t_f ) EXAMPLE: (_d_e_s_e_t_q (_a _b (_c . _d)) '(_1 _2 (_3 _4 _5))) sets a to 1, b to 2, c to 3, and d to (4 5). (setplist 's_atm 'l_plist) RETURNS: l_plist. SIDE EFFECT: the property list of s_atm is set to l_plist. 9 9 PS2:9-34 The Franz Lisp Manual (makunbound 's_arg) RETURNS: s_arg SIDE EFFECT: the value of s_arg is made `unbound'. If the interpreter attempts to evaluate s_arg before it is again given a value, an unbound variable error will occur. (aexplode 's_arg) (explode 'g_arg) (aexplodec 's_arg) (explodec 'g_arg) (aexploden 's_arg) (exploden 'g_arg) RETURNS: a list of the characters used to print out s_arg or g_arg. NOTE: The functions beginning with 'a' are internal functions which are limited to symbol arguments. The functions _a_e_x_p_l_o_d_e and _e_x_p_l_o_d_e return a list of characters which _p_r_i_n_t would use to print the argument. These characters include all necessary escape characters. Functions _a_e_x_p_l_o_d_e_c and _e_x_p_l_o_d_e_c return a list of characters which _p_a_t_o_m would use to print the argument (i.e. no escape characters). Functions _a_e_x_p_l_o_d_e_n and _e_x_p_l_o_d_e_n are similar to _a_e_x_p_l_o_d_e_c and _e_x_p_l_o_d_e_c except that a list of fixnum equivalents of characters are returned. ____________________________________________________ -> (_s_e_t_q _x '|_q_u_o_t_e _t_h_i_s _\| _o_k?|) |quote this \| ok?| -> (_e_x_p_l_o_d_e _x) (q u o t e |\\| | | t h i s |\\| | | |\\| |\|| |\\| | | o k ?) ; note that |\\| just means the single character: backslash. ; and |\|| just means the single character: vertical bar ; and | | means the single character: space -> (_e_x_p_l_o_d_e_c _x) (q u o t e | | t h i s | | |\|| | | o k ?) -> (_e_x_p_l_o_d_e_n _x) (113 117 111 116 101 32 116 104 105 115 32 124 32 111 107 63) ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-35 _2._4. _V_e_c_t_o_r_s See Chapter 9 for a discussion of vectors. They are less efficient that hunks but more efficient than arrays. _2._4._1. _v_e_c_t_o_r _c_r_e_a_t_i_o_n (new-vector 'x_size ['g_fill ['g_prop]]) RETURNS: A vector of length x_size. Each data entry is initialized to g_fill, or to nil, if the argu- ment g_fill is not present. The vector's pro- perty is set to g_prop, or to nil, by default. (new-vectori-byte 'x_size ['g_fill ['g_prop]]) (new-vectori-word 'x_size ['g_fill ['g_prop]]) (new-vectori-long 'x_size ['g_fill ['g_prop]]) RETURNS: A vectori with x_size elements in it. The actual memory requirement is two long words + x_size*(n bytes), where n is 1 for new- vector-byte, 2 for new-vector-word, or 4 for new-vectori-long. Each data entry is initial- ized to g_fill, or to zero, if the argument g_fill is not present. The vector's property is set to g_prop, or nil, by default. Vectors may be created by specifying multiple initial values: (vector ['g_val0 'g_val1 ...]) RETURNS: a vector, with as many data elements as there are arguments. It is quite possible to have a vector with no data elements. The vector's property will be a null list. 9 9 PS2:9-36 The Franz Lisp Manual (vectori-byte ['x_val0 'x_val2 ...]) (vectori-word ['x_val0 'x_val2 ...]) (vectori-long ['x_val0 'x_val2 ...]) RETURNS: a vectori, with as many data elements as there are arguments. The arguments are required to be fixnums. Only the low order byte or word is used in the case of vectori-byte and vectori-word. The vector's property will be null. _2._4._2. _v_e_c_t_o_r _r_e_f_e_r_e_n_c_e (vref 'v_vect 'x_index) (vrefi-byte 'V_vect 'x_bindex) (vrefi-word 'V_vect 'x_windex) (vrefi-long 'V_vect 'x_lindex) RETURNS: the desired data element from a vector. The indices must be fixnums. Indexing is zero- based. The vrefi functions sign extend the data. (vprop 'Vv_vect) RETURNS: The Lisp property associated with a vector. (vget 'Vv_vect 'g_ind) RETURNS: The value stored under g_ind if the Lisp pro- perty associated with 'Vv_vect is a disembo- died property list. (vsize 'Vv_vect) (vsize-byte 'V_vect) (vsize-word 'V_vect) RETURNS: the number of data elements in the vector. For immediate-vectors, the functions vsize- byte and vsize-word return the number of data elements, if one thinks of the binary data as being comprised of bytes or words. _2._4._3. _v_e_c_t_o_r _m_o_d_f_i_c_a_t_i_o_n 9 9 The Franz Lisp Manual PS2:9-37 (vset 'v_vect 'x_index 'g_val) (vseti-byte 'V_vect 'x_bindex 'x_val) (vseti-word 'V_vect 'x_windex 'x_val) (vseti-long 'V_vect 'x_lindex 'x_val) RETURNS: the datum. SIDE EFFECT: The indexed element of the vector is set to the value. As noted above, for vseti- word and vseti-byte, the index is con- strued as the number of the data element within the vector. It is not a byte address. Also, for those two functions, the low order byte or word of x_val is what is stored. (vsetprop 'Vv_vect 'g_value) RETURNS: g_value. This should be either a symbol or a disembodied property list whose _c_a_r is a sym- bol identifying the type of the vector. SIDE EFFECT: the property list of Vv_vect is set to g_value. (vputprop 'Vv_vect 'g_value 'g_ind) RETURNS: g_value. SIDE EFFECT: If the vector property of Vv_vect is a disembodied property list, then vputprop adds the value g_value under the indicator g_ind. Otherwise, the old vector property is made the first element of the list. _2._5. _A_r_r_a_y_s See Chapter 9 for a complete description of arrays. Some of these functions are part of a Maclisp array compatibility package representing only one sim- ple way of using the array structure of FRANZ LISP. _2._5._1. _a_r_r_a_y _c_r_e_a_t_i_o_n 9 9 PS2:9-38 The Franz Lisp Manual (marray 'g_data 's_access 'g_aux 'x_length 'x_delta) RETURNS: an array type with the fields set up from the above arguments in the obvious way (see 1.2.10). (*array 's_name 's_type 'x_dim1 ... 'x_dim_n) (array s_name s_type x_dim1 ... x_dim_n) WHERE: s_type may be one of t, nil, fixnum, flonum, fixnum-block and flonum-block. RETURNS: an array of type s_type with n dimensions of extents given by the x_dim_i. SIDE EFFECT: If s_name is non nil, the function defini- tion of s_name is set to the array struc- ture returned. NOTE: These functions create a Maclisp compatible array. In FRANZ LISP arrays of type t, nil, fix- num and flonum are equivalent and the elements of these arrays can be any type of lisp object. Fixnum-block and flonum-block arrays are res- tricted to fixnums and flonums respectively and are used mainly to communicate with foreign func- tions (see 8.5). NOTE: *_a_r_r_a_y evaluates its arguments, _a_r_r_a_y does not. _2._5._2. _a_r_r_a_y _p_r_e_d_i_c_a_t_e (arrayp 'g_arg) RETURNS: t iff g_arg is of type array. _2._5._3. _a_r_r_a_y _a_c_c_e_s_s_o_r_s 9 9 The Franz Lisp Manual PS2:9-39 (getaccess 'a_array) (getaux 'a_array) (getdelta 'a_array) (getdata 'a_array) (getlength 'a_array) RETURNS: the field of the array object a_array given by the function name. (arrayref 'a_name 'x_ind) RETURNS: the x_ind_t_h element of the array object a_name. x_ind of zero accesses the first ele- ment. NOTE: _a_r_r_a_y_r_e_f uses the data, length and delta fields of a_name to determine which object to return. (arraycall s_type 'as_array 'x_ind1 ... ) RETURNS: the element selected by the indices from the array a_array of type s_type. NOTE: If as_array is a symbol then the function binding of this symbol should contain an array object. s_type is ignored by _a_r_r_a_y_c_a_l_l but is included for compatibility with Maclisp. (arraydims 's_name) RETURNS: a list of the type and bounds of the array s_name. (listarray 'sa_array ['x_elements]) RETURNS: a list of all of the elements in array sa_array. If x_elements is given, then only the first x_elements are returned. 9 9 PS2:9-40 The Franz Lisp Manual ____________________________________________________ ; We will create a 3 by 4 array of general lisp objects -> (_a_r_r_a_y _e_r_n_i_e _t _3 _4) array[12] ; the array header is stored in the function definition slot of the ; symbol ernie -> (_a_r_r_a_y_p (_g_e_t_d '_e_r_n_i_e)) t -> (_a_r_r_a_y_d_i_m_s (_g_e_t_d '_e_r_n_i_e)) (t 3 4) ; store in ernie[2][2] the list (test list) -> (_s_t_o_r_e (_e_r_n_i_e _2 _2) '(_t_e_s_t _l_i_s_t)) (test list) ; check to see if it is there -> (_e_r_n_i_e _2 _2) (test list) ; now use the low level function _a_r_r_a_y_r_e_f to find the same element ; arrays are 0 based and row-major (the last subscript varies the fastest) ; thus element [2][2] is the 10th element , (starting at 0). -> (_a_r_r_a_y_r_e_f (_g_e_t_d '_e_r_n_i_e) _1_0) (ptr to)(test list) ; the result is a value cell (thus the (ptr to)) ____________________________________________________ _2._5._4. _a_r_r_a_y _m_a_n_i_p_u_l_a_t_i_o_n (putaccess 'a_array 'su_func) (putaux 'a_array 'g_aux) (putdata 'a_array 'g_arg) (putdelta 'a_array 'x_delta) (putlength 'a_array 'x_length) RETURNS: the second argument to the function. SIDE EFFECT: The field of the array object given by the function name is replaced by the second argument to the function. 9 9 The Franz Lisp Manual PS2:9-41 (store 'l_arexp 'g_val) WHERE: l_arexp is an expression which references an array element. RETURNS: g_val SIDE EFFECT: the array location which contains the ele- ment which l_arexp references is changed to contain g_val. (fillarray 's_array 'l_itms) RETURNS: s_array SIDE EFFECT: the array s_array is filled with elements from l_itms. If there are not enough ele- ments in l_itms to fill the entire array, then the last element of l_itms is used to fill the remaining parts of the array. _2._6. _H_u_n_k_s Hunks are vector-like objects whose size can range from 1 to 128 elements. Internally, hunks are allocated in sizes which are powers of 2. In order to create hunks of a given size, a hunk with at least that many elements is allocated and a distinguished symbol EMPTY is placed in those elements not requested. Most hunk functions respect those dis- tinguished symbols, but there are two (*_m_a_k_h_u_n_k and *_r_p_l_a_c_x) which will overwrite the distinguished sym- bol. _2._6._1. _h_u_n_k _c_r_e_a_t_i_o_n (hunk 'g_val1 ['g_val2 ... 'g_val_n]) RETURNS: a hunk of length n whose elements are initial- ized to the g_val_i. NOTE: the maximum size of a hunk is 128. EXAMPLE: (_h_u_n_k _4 '_s_h_a_r_p '_k_e_y_s) = {4 sharp keys} 9 9 PS2:9-42 The Franz Lisp Manual (makhunk 'xl_arg) RETURNS: a hunk of length xl_arg initialized to all nils if xl_arg is a fixnum. If xl_arg is a list, then we return a hunk of size (_l_e_n_g_t_h '_x_l__a_r_g) initialized to the elements in xl_arg. NOTE: (_m_a_k_h_u_n_k '(_a _b _c)) is equivalent to (_h_u_n_k '_a '_b '_c). EXAMPLE: (_m_a_k_h_u_n_k _4) = {_n_i_l _n_i_l _n_i_l _n_i_l} (*makhunk 'x_arg) RETURNS: a hunk of size 2[x_arg] initialized to EMPTY. NOTE: This is only to be used by such functions as _h_u_n_k and _m_a_k_h_u_n_k which create and initialize hunks for users. _2._6._2. _h_u_n_k _a_c_c_e_s_s_o_r (cxr 'x_ind 'h_hunk) RETURNS: element x_ind (starting at 0) of hunk h_hunk. (hunk-to-list 'h_hunk) RETURNS: a list consisting of the elements of h_hunk. _2._6._3. _h_u_n_k _m_a_n_i_p_u_l_a_t_o_r_s (rplacx 'x_ind 'h_hunk 'g_val) (*rplacx 'x_ind 'h_hunk 'g_val) RETURNS: h_hunk SIDE EFFECT: Element x_ind (starting at 0) of h_hunk is set to g_val. NOTE: _r_p_l_a_c_x will not modify one of the distinguished (EMPTY) elements whereas *_r_p_l_a_c_x will. 9 9 The Franz Lisp Manual PS2:9-43 (hunksize 'h_arg) RETURNS: the size of the hunk h_arg. EXAMPLE: (_h_u_n_k_s_i_z_e (_h_u_n_k _1 _2 _3)) = 3 _2._7. _B_c_d_s A bcd object contains a pointer to compiled code and to the type of function object the compiled code represents. (getdisc 'y_bcd) (getentry 'y_bcd) RETURNS: the field of the bcd object given by the func- tion name. (putdisc 'y_func 's_discipline) RETURNS: s_discipline SIDE EFFECT: Sets the discipline field of y_func to s_discipline. _2._8. _S_t_r_u_c_t_u_r_e_s There are three common structures constructed out of list cells: the assoc list, the property list and the tconc list. The functions below manipulate these structures. _2._8._1. _a_s_s_o_c _l_i_s_t An `assoc list' (or alist) is a common lisp data structure. It has the form ((key1 . value1) (key2 . value2) (key3 . value3) ... (keyn . valuen)) 9 9 PS2:9-44 The Franz Lisp Manual (assoc 'g_arg1 'l_arg2) (assq 'g_arg1 'l_arg2) RETURNS: the first top level element of l_arg2 whose _c_a_r is _e_q_u_a_l (with _a_s_s_o_c) or _e_q (with _a_s_s_q) to g_arg1. NOTE: Usually l_arg2 has an _a-_l_i_s_t structure and g_arg1 acts as key. (sassoc 'g_arg1 'l_arg2 'sl_func) RETURNS: the result of (_c_o_n_d ((_a_s_s_o_c '_g__a_r_g '_l__a_r_g_2) (_a_p_p_l_y '_s_l__f_u_n_c _n_i_l))) NOTE: sassoc is written as a macro. (sassq 'g_arg1 'l_arg2 'sl_func) RETURNS: the result of (_c_o_n_d ((_a_s_s_q '_g__a_r_g '_l__a_r_g_2) (_a_p_p_l_y '_s_l__f_u_n_c _n_i_l))) NOTE: sassq is written as a macro. ____________________________________________________ ; _a_s_s_o_c or _a_s_s_q is given a key and an assoc list and returns ; the key and value item if it exists, they differ only in how they test ; for equality of the keys. -> (_s_e_t_q _a_l_i_s_t '((_a_l_p_h_a . _a) ( (_c_o_m_p_l_e_x _k_e_y) . _b) (_j_u_n_k . _x))) ((alpha . a) ((complex key) . b) (junk . x)) ; we should use _a_s_s_q when the key is an atom -> (_a_s_s_q '_a_l_p_h_a _a_l_i_s_t) (alpha . a) ; but it may not work when the key is a list -> (_a_s_s_q '(_c_o_m_p_l_e_x _k_e_y) _a_l_i_s_t) nil ; however _a_s_s_o_c will always work -> (_a_s_s_o_c '(_c_o_m_p_l_e_x _k_e_y) _a_l_i_s_t) ((complex key) . b) ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-45 (sublis 'l_alst 'l_exp) WHERE: l_alst is an _a-_l_i_s_t. RETURNS: the list l_exp with every occurrence of key_i replaced by val_i. NOTE: new list structure is returned to prevent modifi- cation of l_exp. When a substitution is made, a copy of the value to substitute in is not made. _2._8._2. _p_r_o_p_e_r_t_y _l_i_s_t A property list consists of an alternating sequence of keys and values. Normally a property list is stored on a symbol. A list is a 'disembo- died' property list if it contains an odd number of elements, the first of which is ignored. (plist 's_name) RETURNS: the property list of s_name. (setplist 's_atm 'l_plist) RETURNS: l_plist. SIDE EFFECT: the property list of s_atm is set to l_plist. (get 'ls_name 'g_ind) RETURNS: the value under indicator g_ind in ls_name's property list if ls_name is a symbol. NOTE: If there is no indicator g_ind in ls_name's pro- perty list nil is returned. If ls_name is a list of an odd number of elements then it is a disem- bodied property list. _g_e_t searches a disembodied property list by starting at its _c_d_r, and compar- ing every other element with g_ind, using _e_q. 9 9 PS2:9-46 The Franz Lisp Manual (getl 'ls_name 'l_indicators) RETURNS: the property list ls_name beginning at the first indicator which is a member of the list l_indicators, or nil if none of the indicators in l_indicators are on ls_name's property list. NOTE: If ls_name is a list, then it is assumed to be a disembodied property list. (putprop 'ls_name 'g_val 'g_ind) (defprop ls_name g_val g_ind) RETURNS: g_val. SIDE EFFECT: Adds to the property list of ls_name the value g_val under the indicator g_ind. NOTE: _p_u_t_p_r_o_p evaluates it arguments, _d_e_f_p_r_o_p does not. ls_name may be a disembodied property list, see _g_e_t. (remprop 'ls_name 'g_ind) RETURNS: the portion of ls_name's property list begin- ning with the property under the indicator g_ind. If there is no g_ind indicator in ls_name's plist, nil is returned. SIDE EFFECT: the value under indicator g_ind and g_ind itself is removed from the property list of ls_name. NOTE: ls_name may be a disembodied property list, see _g_e_t. 9 9 The Franz Lisp Manual PS2:9-47 ____________________________________________________ -> (_p_u_t_p_r_o_p '_x_l_a_t_e '_a '_a_l_p_h_a) a -> (_p_u_t_p_r_o_p '_x_l_a_t_e '_b '_b_e_t_a) b -> (_p_l_i_s_t '_x_l_a_t_e) (alpha a beta b) -> (_g_e_t '_x_l_a_t_e '_a_l_p_h_a) a ; use of a disembodied property list: -> (_g_e_t '(_n_i_l _f_a_t_e_m_a_n _r_j_f _s_k_l_o_w_e_r _k_l_s _f_o_d_e_r_a_r_o _j_k_f) '_s_k_l_o_w_e_r) kls ____________________________________________________ _2._8._3. _t_c_o_n_c _s_t_r_u_c_t_u_r_e A tconc structure is a special type of list designed to make it easy to add objects to the end. It consists of a list cell whose _c_a_r points to a list of the elements added with _t_c_o_n_c or _l_c_o_n_c and whose _c_d_r points to the last list cell of the list pointed to by the _c_a_r. (tconc 'l_ptr 'g_x) WHERE: l_ptr is a tconc structure. RETURNS: l_ptr with g_x added to the end. (lconc 'l_ptr 'l_x) WHERE: l_ptr is a tconc structure. RETURNS: l_ptr with the list l_x spliced in at the end. 9 9 PS2:9-48 The Franz Lisp Manual ____________________________________________________ ; A _t_c_o_n_c structure can be initialized in two ways. ; nil can be given to _t_c_o_n_c in which case _t_c_o_n_c will generate ; a _t_c_o_n_c structure. ->(_s_e_t_q _f_o_o (_t_c_o_n_c _n_i_l _1)) ((1) 1) ; Since _t_c_o_n_c destructively adds to ; the list, you can now add to foo without using _s_e_t_q again. ->(_t_c_o_n_c _f_o_o _2) ((1 2) 2) ->_f_o_o ((1 2) 2) ; Another way to create a null _t_c_o_n_c structure ; is to use (_n_c_o_n_s _n_i_l). ->(_s_e_t_q _f_o_o (_n_c_o_n_s _n_i_l)) (nil) ->(_t_c_o_n_c _f_o_o _1) ((1) 1) ; now see what _l_c_o_n_c can do -> (_l_c_o_n_c _f_o_o _n_i_l) ((1) 1) ; no change -> (_l_c_o_n_c _f_o_o '(_2 _3 _4)) ((1 2 3 4) 4) ____________________________________________________ _2._8._4. _f_c_l_o_s_u_r_e_s An fclosure is a functional object which admits some data manipulations. They are discussed in 8.4. Internally, they are constructed from vec- tors. 9 9 The Franz Lisp Manual PS2:9-49 (fclosure 'l_vars 'g_funobj) WHERE: l_vars is a list of variables, g_funobj is any object that can be funcalled (including, fclo- sures). RETURNS: A vector which is the fclosure. (fclosure-alist 'v_fclosure) RETURNS: An association list representing the variables in the fclosure. This is a snapshot of the current state of the fclosure. If the bind- ings in the fclosure are changed, any previ- ously calculated results of _f_c_l_o_s_u_r_e-_a_l_i_s_t will not change. (fclosure-function 'v_fclosure) RETURNS: the functional object part of the fclosure. (fclosurep 'v_fclosure) RETURNS: t iff the argument is an fclosure. (symeval-in-fclosure 'v_fclosure 's_symbol) RETURNS: the current binding of a particular symbol in an fclosure. (set-in-fclosure 'v_fclosure 's_symbol 'g_newvalue) RETURNS: g_newvalue. SIDE EFFECT: The variable s_symbol is bound in the fclosure to g_newvalue. _2._9. _R_a_n_d_o_m _f_u_n_c_t_i_o_n_s The following functions don't fall into any of the classifications above. 9 9 PS2:9-50 The Franz Lisp Manual (bcdad 's_funcname) RETURNS: a fixnum which is the address in memory where the function s_funcname begins. If s_funcname is not a machine coded function (binary) then _b_c_d_a_d returns nil. (copy 'g_arg) RETURNS: A structure _e_q_u_a_l to g_arg but with new list cells. (copyint* 'x_arg) RETURNS: a fixnum with the same value as x_arg but in a freshly allocated cell. (cpy1 'xvt_arg) RETURNS: a new cell of the same type as xvt_arg with the same value as xvt_arg. (getaddress 's_entry1 's_binder1 'st_discipline1 [... ... ...]) RETURNS: the binary object which s_binder1's function field is set to. NOTE: This looks in the running lisp's symbol table for a symbol with the same name as s_entry_i. It then creates a binary object whose entry field points to s_entry_i and whose discipline is st_discipline_i. This binary object is stored in the function field of s_binder_i. If st_discipline_i is nil, then "subroutine" is used by default. This is especially useful for _c_f_a_s_l users. (macroexpand 'g_form) RETURNS: g_form after all macros in it are expanded. NOTE: This function will only macroexpand expressions which could be evaluated and it does not know about the special nlambdas such as _c_o_n_d and _d_o, thus it misses many macro expansions. 9 9 The Franz Lisp Manual PS2:9-51 (ptr 'g_arg) RETURNS: a value cell initialized to point to g_arg. (quote g_arg) RETURNS: g_arg. NOTE: the reader allows you to abbreviate (quote foo) as 'foo. (kwote 'g_arg) RETURNS: (_l_i_s_t (_q_u_o_t_e _q_u_o_t_e) _g__a_r_g). (replace 'g_arg1 'g_arg2) WHERE: g_arg1 and g_arg2 must be the same type of lispval and not symbols or hunks. RETURNS: g_arg2. SIDE EFFECT: The effect of _r_e_p_l_a_c_e is dependent on the type of the g_arg_i although one will notice a similarity in the effects. To understand what _r_e_p_l_a_c_e does to fixnum and flonum arguments, you must first under- stand that such numbers are `boxed' in FRANZ LISP. What this means is that if the symbol x has a value 32412, then in memory the value element of x's symbol structure contains the address of another word of memory (called a box) with 32412 in it. Thus, there are two ways of changing the value of x: the first is to change the value element of x's symbol structure to point to a word of memory with a different value. The second way is to change the value in the box which x points to. The former method is used almost all of the time, the latter is used very rarely and has the potential to cause great confu- sion. The function _r_e_p_l_a_c_e allows you to do the latter, i.e., to actually change the value in the box. You should watch out for these situations. If you do (_s_e_t_q _y _x), then both x and y will point to the same box. If you now (_r_e_p_l_a_c_e _x _1_2_3_4_5), then y will also have the value 12345. And, in fact, there may PS2:9-52 The Franz Lisp Manual be many other pointers to that box. Another problem with replacing fixnums is that some boxes are read-only. The fix- nums between -1024 and 1023 are stored in a read-only area and attempts to replace them will result in an "Illegal memory reference" error (see the description of _c_o_p_y_i_n_t* for a way around this problem). For the other valid types, the effect of _r_e_p_l_a_c_e is easy to understand. The fields of g_val1's structure are made eq to the corresponding fields of g_val2's struc- ture. For example, if x and y have lists as values then the effect of (_r_e_p_l_a_c_e _x _y) is the same as (_r_p_l_a_c_a _x (_c_a_r _y)) and (_r_p_l_a_c_d _x (_c_d_r _y)). (scons 'x_arg 'bs_rest) WHERE: bs_rest is a bignum or nil. RETURNS: a bignum whose first bigit is x_arg and whose higher order bigits are bs_rest. (setf g_refexpr 'g_value) NOTE: _s_e_t_f is a generalization of setq. Information may be stored by binding variables, replacing entries of arrays, and vectors, or being put on property lists, among others. Setf will allow the user to store data into some location, by mentioning the operation used to refer to the location. Thus, the first argument may be par- tially evaluated, but only to the extent needed to calculate a reference. _s_e_t_f returns g_value. (Compare to _d_e_s_e_t_q ) ____________________________________________________ (setf x 3) = (setq x 3) (setf (car x) 3) = (rplaca x 3) (setf (get foo 'bar) 3) = (putprop foo 3 'bar) (setf (vref vector index) value) = (vset vector index value) ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-53 (sort 'l_data 'u_comparefn) RETURNS: a list of the elements of l_data ordered by the comparison function u_comparefn. SIDE EFFECT: the list l_data is modified rather than allocated in new storage. NOTE: (_c_o_m_p_a_r_e_f_n '_g__x '_g__y) should return something non-nil if g_x can precede g_y in sorted order; nil if g_y must precede g_x. If u_comparefn is nil, alphabetical order will be used. (sortcar 'l_list 'u_comparefn) RETURNS: a list of the elements of l_list with the _c_a_r's ordered by the sort function u_comparefn. SIDE EFFECT: the list l_list is modified rather than copied. NOTE: Like _s_o_r_t, if u_comparefn is nil, alphabetical order will be used. 9 9 CHAPTER 3 Arithmetic Functions This chapter describes FRANZ LISP's functions for doing arithmetic. Often the same function is known by many names. For example, _a_d_d is also _p_l_u_s, and _s_u_m. This is caused by our desire to be compatible with other Lisps. The FRANZ LISP user should avoid using functions with names such as + and * unless their argu- ments are fixnums. The Lisp compiler takes advantage of these implicit declarations. An attempt to divide or to generate a floating point result outside of the range of floating point numbers will cause a floating exception signal from the UNIX operating system. The user can catch and process this interrupt if desired (see the description of the _s_i_g_n_a_l function). _3._1. _S_i_m_p_l_e _A_r_i_t_h_m_e_t_i_c _F_u_n_c_t_i_o_n_s (add ['n_arg1 ...]) (plus ['n_arg1 ...]) (sum ['n_arg1 ...]) (+ ['x_arg1 ...]) RETURNS: the sum of the arguments. If no arguments are given, 0 is returned. NOTE: if the size of the partial sum exceeds the limit of a fixnum, the partial sum will be converted to a bignum. If any of the arguments are flonums, the partial sum will be converted to a flonum when that argument is processed and the result will thus be a flonum. Currently, if in the pro- cess of doing the addition a bignum must be con- verted into a flonum an error message will result. 9 9PS2:9-54 The Franz Lisp Manual The Franz Lisp Manual PS2:9-55 (add1 'n_arg) (1+ 'x_arg) RETURNS: its argument plus 1. (diff ['n_arg1 ... ]) (difference ['n_arg1 ... ]) (- ['x_arg1 ... ]) RETURNS: the result of subtracting from n_arg1 all sub- sequent arguments. If no arguments are given, 0 is returned. NOTE: See the description of add for details on data type conversions and restrictions. (sub1 'n_arg) (1- 'x_arg) RETURNS: its argument minus 1. (minus 'n_arg) RETURNS: zero minus n_arg. (product ['n_arg1 ... ]) (times ['n_arg1 ... ]) (* ['x_arg1 ... ]) RETURNS: the product of all of its arguments. It returns 1 if there are no arguments. NOTE: See the description of the function _a_d_d for details and restrictions to the automatic data type coercion. (quotient ['n_arg1 ...]) (/ ['x_arg1 ...]) RETURNS: the result of dividing the first argument by succeeding ones. NOTE: If there are no arguments, 1 is returned. See the description of the function _a_d_d for details and restrictions of data type coercion. A divide by zero will cause a floating exception interrupt -- see the description of the _s_i_g_n_a_l function. 9 9 PS2:9-56 The Franz Lisp Manual (*quo 'i_x 'i_y) RETURNS: the integer part of i_x / i_y. (Divide 'i_dividend 'i_divisor) RETURNS: a list whose car is the quotient and whose cadr is the remainder of the division of i_dividend by i_divisor. NOTE: this is restricted to integer division. (Emuldiv 'x_fact1 'x_fact2 'x_addn 'x_divisor) RETURNS: a list of the quotient and remainder of this operation: ((x_fact1 * x_fact2) + (sign extended) x_addn) / x_divisor. NOTE: this is useful for creating a bignum arithmetic package in Lisp. _3._2. _p_r_e_d_i_c_a_t_e_s (numberp 'g_arg) (numbp 'g_arg) RETURNS: t iff g_arg is a number (fixnum, flonum or bignum). (fixp 'g_arg) RETURNS: t iff g_arg is a fixnum or bignum. (floatp 'g_arg) RETURNS: t iff g_arg is a flonum. (evenp 'x_arg) RETURNS: t iff x_arg is even. 9 9 The Franz Lisp Manual PS2:9-57 (oddp 'x_arg) RETURNS: t iff x_arg is odd. (zerop 'g_arg) RETURNS: t iff g_arg is a number equal to 0. (onep 'g_arg) RETURNS: t iff g_arg is a number equal to 1. (plusp 'n_arg) RETURNS: t iff n_arg is greater than zero. (minusp 'g_arg) RETURNS: t iff g_arg is a negative number. (greaterp ['n_arg1 ...]) (> 'fx_arg1 'fx_arg2) (>& 'x_arg1 'x_arg2) RETURNS: t iff the arguments are in a strictly decreas- ing order. NOTE: In functions _g_r_e_a_t_e_r_p and > the function _d_i_f_f_e_r_- _e_n_c_e is used to compare adjacent values. If any of the arguments are non-numbers, the error mes- sage will come from the _d_i_f_f_e_r_e_n_c_e function. The arguments to > must be fixnums or both flonums. The arguments to >& must both be fixnums. (lessp ['n_arg1 ...]) (< 'fx_arg1 'fx_arg2) (<& 'x_arg1 'x_arg2) RETURNS: t iff the arguments are in a strictly increas- ing order. NOTE: In functions _l_e_s_s_p and < the function _d_i_f_f_e_r_e_n_c_e is used to compare adjacent values. If any of the arguments are non numbers, the error message will come from the _d_i_f_f_e_r_e_n_c_e function. The arguments to < may be either fixnums or flonums but must be the same type. The arguments to <& must be fix- nums. 9 9 PS2:9-58 The Franz Lisp Manual (= 'fx_arg1 'fx_arg2) (=& 'x_arg1 'x_arg2) RETURNS: t iff the arguments have the same value. The arguments to = must be the either both fixnums or both flonums. The arguments to =& must be fixnums. _3._3. _T_r_i_g_n_o_m_e_t_r_i_c _F_u_n_c_t_i_o_n_s Some of these funtcions are taken from the host math library, and we take no further responsibility for their accuracy. (cos 'fx_angle) RETURNS: the (flonum) cosine of fx_angle (which is assumed to be in radians). (sin 'fx_angle) RETURNS: the sine of fx_angle (which is assumed to be in radians). (acos 'fx_arg) RETURNS: the (flonum) arc cosine of fx_arg in the range 0 to J. (asin 'fx_arg) RETURNS: the (flonum) arc sine of fx_arg in the range -J/2 to J/2. (atan 'fx_arg1 'fx_arg2) RETURNS: the (flonum) arc tangent of fx_arg1/fx_arg2 in the range -J to J. _3._4. _B_i_g_n_u_m/_F_i_x_n_u_m _M_a_n_i_p_u_l_a_t_i_o_n 9 9 The Franz Lisp Manual PS2:9-59 (haipart bx_number x_bits) RETURNS: a fixnum (or bignum) which contains the x_bits high bits of (_a_b_s _b_x__n_u_m_b_e_r) if x_bits is positive, otherwise it returns the (_a_b_s _x__b_i_t_s) low bits of (_a_b_s _b_x__n_u_m_b_e_r). (haulong bx_number) RETURNS: the number of significant bits in bx_number. NOTE: the result is equal to the least integer greater to or equal to the base two logarithm of one plus the absolute value of bx_number. (bignum-leftshift bx_arg x_amount) RETURNS: bx_arg shifted left by x_amount. If x_amount is negative, bx_arg will be shifted right by the magnitude of x_amount. NOTE: If bx_arg is shifted right, it will be rounded to the nearest even number. (sticky-bignum-leftshift 'bx_arg 'x_amount) RETURNS: bx_arg shifted left by x_amount. If x_amount is negative, bx_arg will be shifted right by the magnitude of x_amount and rounded. NOTE: sticky rounding is done this way: after shifting, the low order bit is changed to 1 if any 1's were shifted off to the right. _3._5. _B_i_t _M_a_n_i_p_u_l_a_t_i_o_n (boole 'x_key 'x_v1 'x_v2 ...) RETURNS: the result of the bitwise boolean operation as described in the following table. NOTE: If there are more than 3 arguments, then evalua- tion proceeds left to right with each partial result becoming the new value of x_v1. That is, (_b_o_o_l_e '_k_e_y '_v_1 '_v_2 '_v_3) =_ (_b_o_o_l_e '_k_e_y (_b_o_o_l_e '_k_e_y '_v_1 '_v_2) '_v_3). In the following table, * represents bitwise and, + represents bitwise or, O+ represents bitwise xor and _ represents bitwise negation and is the highest precedence operator. PS2:9-60 The Franz Lisp Manual 8____________________________________________________________________________________________ (boole 'key 'x 'y) 8________________________________________________________________________________________________________________________________________________________________________________________ key 0 1 2 3 4 5 6 7 result 0 x * y _ x * y y x * _ y x x O+ y x + y common names and bitclear xor or 8____________________________________________________________________________________________ key 8 9 10 11 12 13 14 15 result _ (x + y) _(x O+ y) _ x _ x + y _ y x + _ y _ x + _ y -1 common names nor equiv implies nand 8____________________________________________________________________________________________ 7|8|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| 9 (lsh 'x_val 'x_amt) RETURNS: x_val shifted left by x_amt if x_amt is posi- tive. If x_amt is negative, then _l_s_h returns x_val shifted right by the magnitude if x_amt. NOTE: This always returns a fixnum even for those numbers whose magnitude is so large that they would normally be represented as a bignum, i.e. shifter bits are lost. For more general bit shifters, see _b_i_g_n_u_m-_l_e_f_t_s_h_i_f_t and _s_t_i_c_k_y- _b_i_g_n_u_m-_l_e_f_t_s_h_i_f_t. (rot 'x_val 'x_amt) RETURNS: x_val rotated left by x_amt if x_amt is posi- tive. If x_amt is negative, then x_val is rotated right by the magnitude of x_amt. _3._6. _O_t_h_e_r _F_u_n_c_t_i_o_n_s As noted above, some of the following functions are inherited from the host math library, with all their virtues and vices. 9 9 The Franz Lisp Manual PS2:9-61 (abs 'n_arg) (absval 'n_arg) RETURNS: the absolute value of n_arg. (exp 'fx_arg) RETURNS: _e raised to the fx_arg power (flonum) . (expt 'n_base 'n_power) RETURNS: n_base raised to the n_power power. NOTE: if either of the arguments are flonums, the cal- culation will be done using _l_o_g and _e_x_p. (fact 'x_arg) RETURNS: x_arg factorial. (fixnum or bignum) (fix 'n_arg) RETURNS: a fixnum as close as we can get to n_arg. NOTE: _f_i_x will round down. Currently, if n_arg is a flonum larger than the size of a fixnum, this will fail. (float 'n_arg) RETURNS: a flonum as close as we can get to n_arg. NOTE: if n_arg is a bignum larger than the maximum size of a flonum, then a floating exception will occur. (log 'fx_arg) RETURNS: the natural logarithm of fx_arg. (max 'n_arg1 ... ) RETURNS: the maximum value in the list of arguments. 9 9 PS2:9-62 The Franz Lisp Manual (min 'n_arg1 ... ) RETURNS: the minimum value in the list of arguments. (mod 'i_dividend 'i_divisor) (remainder 'i_dividend 'i_divisor) RETURNS: the remainder when i_dividend is divided by i_divisor. NOTE: The sign of the result will have the same sign as i_dividend. (*mod 'x_dividend 'x_divisor) RETURNS: the balanced representation of x_dividend modulo x_divisor. NOTE: the range of the balanced representation is abs(x_divisor)/2 to (abs(x_divisor)/2) - x_divisor + 1. (random ['x_limit]) RETURNS: a fixnum between 0 and x_limit - 1 if x_limit is given. If x_limit is not given, any fix- num, positive or negative, might be returned. (sqrt 'fx_arg) RETURNS: the square root of fx_arg. 9 9 CHAPTER 4 Special Functions (and [g_arg1 ...]) RETURNS: the value of the last argument if all argu- ments evaluate to a non-nil value, otherwise _a_n_d returns nil. It returns t if there are no arguments. NOTE: the arguments are evaluated left to right and evaluation will cease with the first nil encoun- tered. (apply 'u_func 'l_args) RETURNS: the result of applying function u_func to the arguments in the list l_args. NOTE: If u_func is a lambda, then the (_l_e_n_g_t_h _l__a_r_g_s) should equal the number of formal parameters for the u_func. If u_func is a nlambda or macro, then l_args is bound to the single formal parame- ter. 9 9The Franz Lisp Manual PS2:9-63 PS2:9-64 The Franz Lisp Manual ____________________________________________________ ; _a_d_d_1 is a lambda of 1 argument -> (_a_p_p_l_y '_a_d_d_1 '(_3)) 4 ; we will define _p_l_u_s_1 as a macro which will be equivalent to _a_d_d_1 -> (_d_e_f _p_l_u_s_1 (_m_a_c_r_o (_a_r_g) (_l_i_s_t '_a_d_d_1 (_c_a_d_r _a_r_g)))) plus1 -> (_p_l_u_s_1 _3) 4 ; now if we _a_p_p_l_y a macro we obtain the form it changes to. -> (_a_p_p_l_y '_p_l_u_s_1 '(_p_l_u_s_1 _3)) (add1 3) ; if we _f_u_n_c_a_l_l a macro however, the result of the macro is _e_v_a_led ; before it is returned. -> (_f_u_n_c_a_l_l '_p_l_u_s_1 '(_p_l_u_s_1 _3)) 4 ; for this particular macro, the _c_a_r of the _a_r_g is not checked ; so that this too will work -> (_a_p_p_l_y '_p_l_u_s_1 '(_f_o_o _3)) (add1 3) ____________________________________________________ (arg ['x_numb]) RETURNS: if x_numb is specified then the x_numb'_t_h argument to the enclosing lexpr If x_numb is not specified then this returns the number of arguments to the enclosing lexpr. NOTE: it is an error to the interpreter if x_numb is given and out of range. 9 9 The Franz Lisp Manual PS2:9-65 (break [g_message ['g_pred]]) WHERE: if g_message is not given it is assumed to be the null string, and if g_pred is not given it is assumed to be t. RETURNS: the value of (*_b_r_e_a_k '_g__p_r_e_d '_g__m_e_s_s_a_g_e) (*break 'g_pred 'g_message) RETURNS: nil immediately if g_pred is nil, else the value of the next (return 'value) expression typed in at top level. SIDE EFFECT: If the predicate, g_pred, evaluates to non-null, the lisp system stops and prints out `Break ' followed by g_message. It then enters a break loop which allows one to interactively debug a program. To con- tinue execution from a break you can use the _r_e_t_u_r_n function. to return to top level or another break level, you can use _r_e_t_b_r_k or _r_e_s_e_t. (caseq 'g_key-form l_clause1 ...) WHERE: l_clause_i is a list of the form (g_comparator ['g_form_i ...]). The comparators may be sym- bols, small fixnums, a list of small fixnums or symbols. NOTE: The way caseq works is that it evaluates g_key- form, yielding a value we will call the selector. Each clause is examined until the selector is found consistent with the comparator. For a sym- bol, or a fixnum, this means the two must be _e_q. For a list, this means that the selector must be _e_q to some element of the list. The comparator consisting of the symbol t has special semantics: it matches anything, and con- sequently, should be the last comparator. In any case, having chosen a clause, _c_a_s_e_q evalu- ates each form within that clause and RETURNS: the value of the last form. If no comparators are matched, _c_a_s_e_q returns nil. 9 9 PS2:9-66 The Franz Lisp Manual ____________________________________________________ Here are two ways of defining the same function: ->(_d_e_f_u_n _f_a_t_e (_p_e_r_s_o_n_n_a) (_c_a_s_e_q _p_e_r_s_o_n_n_a (_c_o_w '(_j_u_m_p_e_d _o_v_e_r _t_h_e _m_o_o_n)) (_c_a_t '(_p_l_a_y_e_d _n_e_r_o)) ((_d_i_s_h _s_p_o_o_n) '(_r_a_n _a_w_a_y _w_i_t_h _e_a_c_h _o_t_h_e_r)) (_t '(_l_i_v_e_d _h_a_p_p_i_l_y _e_v_e_r _a_f_t_e_r)))) fate ->(_d_e_f_u_n _f_a_t_e (_p_e_r_s_o_n_n_a) (_c_o_n_d ((_e_q _p_e_r_s_o_n_n_a '_c_o_w) '(_j_u_m_p_e_d _o_v_e_r _t_h_e _m_o_o_n)) ((_e_q _p_e_r_s_o_n_n_a '_c_a_t) '(_p_l_a_y_e_d _n_e_r_o)) ((_m_e_m_q _p_e_r_s_o_n_n_a '(_d_i_s_h _s_p_o_o_n)) '(_r_a_n _a_w_a_y _w_i_t_h _e_a_c_h _o_t_h_e_r)) (_t '(_l_i_v_e_d _h_a_p_p_i_l_y _e_v_e_r _a_f_t_e_r)))) fate ____________________________________________________ (catch g_exp [ls_tag]) WHERE: if ls_tag is not given, it is assumed to be nil. RETURNS: the result of (*_c_a_t_c_h '_l_s__t_a_g _g__e_x_p) NOTE: catch is defined as a macro. (*catch 'ls_tag g_exp) WHERE: ls_tag is either a symbol or a list of sym- bols. RETURNS: the result of evaluating g_exp or the value thrown during the evaluation of g_exp. SIDE EFFECT: this first sets up a `catch frame' on the lisp runtime stack. Then it begins to evaluate g_exp. If g_exp evaluates nor- mally, its value is returned. If, how- ever, a value is thrown during the evalua- tion of g_exp then this *catch will return with that value if one of these cases is true: (1) the tag thrown to is ls_tag (2) ls_tag is a list and the tag thrown to is a member of this list The Franz Lisp Manual PS2:9-67 (3) ls_tag is nil. NOTE: Errors are implemented as a special kind of throw. A catch with no tag will not catch an error but a catch whose tag is the error type will catch that type of error. See Chapter 10 for more information. (comment [g_arg ...]) RETURNS: the symbol comment. NOTE: This does absolutely nothing. (cond [l_clause1 ...]) RETURNS: the last value evaluated in the first clause satisfied. If no clauses are satisfied then nil is returned. NOTE: This is the basic conditional `statement' in lisp. The clauses are processed from left to right. The first element of a clause is evaluated. If it evaluated to a non-null value then that clause is satisfied and all following elements of that clause are evaluated. The last value computed is returned as the value of the cond. If there is just one element in the clause then its value is returned. If the first element of a clause evaluates to nil, then the other ele- ments of that clause are not evaluated and the system moves to the next clause. (cvttointlisp) SIDE EFFECT: The reader is modified to conform with the Interlisp syntax. The character % is made the escape character and special meanings for comma, backquote and backslash are removed. Also the reader is told to con- vert upper case to lower case. 9 9 PS2:9-68 The Franz Lisp Manual (cvttofranzlisp) SIDE EFFECT: FRANZ LISP's default syntax is reinstated. One would run this function after having run any of the other _c_v_t_t_o- functions. Backslash is made the escape character, super-brackets work again, and the reader distinguishes between upper and lower case. (cvttomaclisp) SIDE EFFECT: The reader is modified to conform with Maclisp syntax. The character / is made the escape character and the special mean- ings for backslash, left and right bracket are removed. The reader is made case- insensitive. (cvttoucilisp) SIDE EFFECT: The reader is modified to conform with UCI Lisp syntax. The character / is made the escape character, tilde is made the com- ment character, exclamation point takes on the unquote function normally held by comma, and backslash, comma, semicolon become normal characters. Here too, the reader is made case-insensitive. (debug s_msg) SIDE EFFECT: Enter the Fixit package described in Chapter 15. This package allows you to examine the evaluation stack in detail. To leave the Fixit package type 'ok'. (debugging 'g_arg) SIDE EFFECT: If g_arg is non-null, Franz unlinks the transfer tables, does a (*_r_s_e_t _t) to turn on evaluation monitoring and sets the all-error catcher (ER%all) to be _d_e_b_u_g- _e_r_r-_h_a_n_d_l_e_r. If g_arg is nil, all of the above changes are undone. 9 9 The Franz Lisp Manual PS2:9-69 (declare [g_arg ...]) RETURNS: nil NOTE: this is a no-op to the evaluator. It has special meaning to the compiler (see Chapter 12). (def s_name (s_type l_argl g_exp1 ...)) WHERE: s_type is one of lambda, nlambda, macro or lexpr. RETURNS: s_name SIDE EFFECT: This defines the function s_name to the lisp system. If s_type is nlambda or macro then the argument list l_argl must contain exactly one non-nil symbol. (defmacro s_name l_arg g_exp1 ...) (defcmacro s_name l_arg g_exp1 ...) RETURNS: s_name SIDE EFFECT: This defines the macro s_name. _d_e_f_m_a_c_r_o makes it easy to write macros since it makes the syntax just like _d_e_f_u_n. Further information on _d_e_f_m_a_c_r_o is in 8.3.2. _d_e_f_c_m_a_c_r_o defines compiler-only macros, or cmacros. A cmacro is stored on the pro- perty list of a symbol under the indicator cmacro. Thus a function can have a normal definition and a cmacro definition. For an example of the use of cmacros, see the definitions of nthcdr and nth in /usr/lib/lisp/common2.l (defun s_name [s_mtype] ls_argl g_exp1 ... ) WHERE: s_mtype is one of fexpr, expr, args or macro. RETURNS: s_name SIDE EFFECT: This defines the function s_name. NOTE: this exists for Maclisp compatibility, it is just a macro which changes the defun form to the def form. An s_mtype of fexpr is converted to nlambda and of expr to lambda. Macro remains the same. If ls_arg1 is a non-nil symbol, then the type is assumed to be lexpr and ls_arg1 is the symbol which is bound to the number of args when the function is entered. PS2:9-70 The Franz Lisp Manual For compatibility with the Lisp Machine Lisp, there are three types of optional parameters that can occur in ls_argl: &_o_p_t_i_o_n_a_l declares that the following symbols are optional, and may or may not appear in the argument list to the func- tion, &_r_e_s_t _s_y_m_b_o_l declares that all forms in the function call that are not accounted for by pre- vious lambda bindings are to be assigned to _s_y_m_- _b_o_l, and &_a_u_x _f_o_r_m_1 ... _f_o_r_m_n declares that the _f_o_r_m_i are either symbols, in which case they are lambda bound to nil, or lists, in which case the first element of the list is lambda bound to the second, evaluated element. ____________________________________________________ ; _d_e_f and _d_e_f_u_n here are used to define identical functions ; you can decide for yourself which is easier to use. -> (_d_e_f _a_p_p_e_n_d_1 (_l_a_m_b_d_a (_l_i_s _e_x_t_r_a) (_a_p_p_e_n_d _l_i_s (_l_i_s_t _e_x_t_r_a)))) append1 -> (_d_e_f_u_n _a_p_p_e_n_d_1 (_l_i_s _e_x_t_r_a) (_a_p_p_e_n_d _l_i_s (_l_i_s_t _e_x_t_r_a))) append1 ; Using the & forms... -> (_d_e_f_u_n _t_e_s_t (_a _b &_o_p_t_i_o_n_a_l _c &_a_u_x (_r_e_t_v_a_l _0) &_r_e_s_t _z) (_i_f _c _t_h_e_m (_m_s_g "_O_p_t_i_o_n_a_l _a_r_g _p_r_e_s_e_n_t" _N "_c _i_s " _c _N)) (_m_s_g "_r_e_s_t _i_s " _z _N "_r_e_t_v_a_l _i_s " _r_e_t_v_a_l _N)) test -> (_t_e_s_t _1 _2 _3 _4) Optional arg present c is 3 rest is (4) retval is 0 ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-71 (defvar s_variable ['g_init]) RETURNS: s_variable. NOTE: This form is put at the top level in files, like _d_e_f_u_n. SIDE EFFECT: This declares s_variable to be special. If g_init is present and s_variable is unbound when the file is read in, s_variable will be set to the value of g_init. An advantage of `(defvar foo)' over `(declare (special foo))' is that if a file containing defvars is loaded (or fasl'ed) in during compilation, the vari- ables mentioned in the defvar's will be declared special. The only way to have that effect with `(declare (special foo))' is to _i_n_c_l_u_d_e the file. (do l_vrbs l_test g_exp1 ...) RETURNS: the last form in the cdr of l_test evaluated, or a value explicitly given by a return evaluated within the do body. NOTE: This is the basic iteration form for FRANZ LISP. l_vrbs is a list of zero or more var-init-repeat forms. A var-init-repeat form looks like: (s_name [g_init [g_repeat]]) There are three cases depending on what is present in the form. If just s_name is present, this means that when the do is entered, s_name is lambda-bound to nil and is never modified by the system (though the program is certainly free to modify its value). If the form is (s_name 'g_init) then the only difference is that s_name is lambda-bound to the value of g_init instead of nil. If g_repeat is also present then s_name is lambda-bound to g_init when the loop is entered and after each pass through the do body s_name is bound to the value of g_repeat. l_test is either nil or has the form of a cond clause. If it is nil then the do body will be evaluated only once and the do will return nil. Otherwise, before the do body is evaluated the car of l_test is evaluated and if the result is non-null, this signals an end to the looping. Then the rest of the forms in l_test are evaluated and the value of the last one is returned as the value of the do. If the cdr of l_test is nil, then nil is returned -- thus this is not exactly like a cond clause. PS2:9-72 The Franz Lisp Manual g_exp1 and those forms which follow constitute the do body. A do body is like a prog body and thus may have labels and one may use the func- tions go and return. The sequence of evaluations is this: (1) the init forms are evaluated left to right and stored in temporary locations. (2) Simultaneously all do variables are lambda bound to the value of their init forms or nil. (3) If l_test is non-null, then the car is evaluated and if it is non-null, the rest of the forms in l_test are evaluated and the last value is returned as the value of the do. (4) The forms in the do body are evaluated left to right. (5) If l_test is nil the do function returns with the value nil. (6) The repeat forms are evaluated and saved in tem- porary locations. (7) The variables with repeat forms are simultane- ously bound to the values of those forms. (8) Go to step 3. NOTE: there is an alternate form of do which can be used when there is only one do variable. It is described next. 9 9 The Franz Lisp Manual PS2:9-73 ____________________________________________________ ; this is a simple function which numbers the elements of a list. ; It uses a _d_o function with two local variables. -> (_d_e_f_u_n _p_r_i_n_t_e_m (_l_i_s) (_d_o ((_x_x _l_i_s (_c_d_r _x_x)) (_i _1 (_1+ _i))) ((_n_u_l_l _x_x) (_p_a_t_o_m "_a_l_l _d_o_n_e") (_t_e_r_p_r)) (_p_r_i_n_t _i) (_p_a_t_o_m ": ") (_p_r_i_n_t (_c_a_r _x_x)) (_t_e_r_p_r))) printem -> (_p_r_i_n_t_e_m '(_a _b _c _d)) 1: a 2: b 3: c 4: d all done nil -> ____________________________________________________ (do s_name g_init g_repeat g_test g_exp1 ...) NOTE: this is another, less general, form of do. It is evaluated by: (1) evaluating g_init (2) lambda binding s_name to value of g_init (3) g_test is evaluated and if it is not nil the do function returns with nil. (4) the do body is evaluated beginning at g_exp1. (5) the repeat form is evaluated and stored in s_name. (6) go to step 3. RETURNS: nil 9 9 PS2:9-74 The Franz Lisp Manual (environment [l_when1 l_what1 l_when2 l_what2 ...]) (environment-maclisp [l_when1 l_what1 l_when2 l_what2 ...]) (environment-lmlisp [l_when1 l_what1 l_when2 l_what2 ...]) WHERE: the when's are a subset of (eval compile load), and the symbols have the same meaning as they do in 'eval-when'. The what's may be (files file1 file2 ... fileN), which insure that the named files are loaded. To see if file_i is loaded, it looks for a 'version' property under file_i's property list. Thus to prevent multiple loading, you should put (putprop 'myfile t 'version), at the end of myfile.l. Another acceptable form for a what is (syntax type) Where type is either maclisp, intlisp, ucil- isp, franzlisp. SIDE EFFECT: _e_n_v_i_r_o_n_m_e_n_t-_m_a_c_l_i_s_p sets the environment to that which `liszt -m' would generate. _e_n_v_i_r_o_n_m_e_n_t-_l_m_l_i_s_p sets up the lisp machine environment. This is like maclisp but it has additional macros. For these specialized environments, only the files clauses are useful. (environment-maclisp (compile eval) (files foo bar)) RETURNS: the last list of files requested. (err ['s_value [nil]]) RETURNS: nothing (it never returns). SIDE EFFECT: This causes an error and if this error is caught by an _e_r_r_s_e_t then that _e_r_r_s_e_t will return s_value instead of nil. If the second arg is given, then it must be nil (MAClisp compatibility). 9 9 The Franz Lisp Manual PS2:9-75 (error ['s_message1 ['s_message2]]) RETURNS: nothing (it never returns). SIDE EFFECT: s_message1 and s_message2 are _p_a_t_o_med if they are given and then _e_r_r is called (with no arguments), which causes an error. (errset g_expr [s_flag]) RETURNS: a list of one element, which is the value resulting from evaluating g_expr. If an error occurs during the evaluation of g_expr, then the locus of control will return to the _e_r_r_s_e_t which will then return nil (unless the error was caused by a call to _e_r_r, with a non-null argument). SIDE EFFECT: S_flag is evaluated before g_expr is evaluated. If s_flag is not given, then it is assumed to be t. If an error occurs during the evaluation of g_expr, and s_flag evaluated to a non-null value, then the error message associated with the error is printed before control returns to the errset. (eval 'g_val ['x_bind-pointer]) RETURNS: the result of evaluating g_val. NOTE: The evaluator evaluates g_val in this way: If g_val is a symbol, then the evaluator returns its value. If g_val had never been assigned a value, then this causes an `Unbound Variable' error. If x_bind-pointer is given, then the variable is evaluated with respect to that pointer (see _e_v_a_l_f_r_a_m_e for details on bind- pointers). If g_val is of type value, then its value is returned. If g_val is of any other type than list, g_val is returned. If g_val is a list object then g_val is either a function call or array reference. Let g_car be the first element of g_val. We continually evaluate g_car until we end up with a symbol with a non-null function binding or a non-symbol. Call what we end up with: g_func. G_func must be one of three types: list, binary PS2:9-76 The Franz Lisp Manual or array. If it is a list then the first element of the list, which we shall call g_functype, must be either lambda, nlambda, macro or lexpr. If g_func is a binary, then its discipline, which we shall call g_functype, is either lambda, nlambda, macro or a string. If g_func is an array then this form is evaluated specially, see Chapter 9 on arrays. If g_func is a list or binary, then g_functype will determine how the arguments to this function, the cdr of g_val, are processed. If g_functype is a string, then this is a foreign function call (see 8.5 for more details). If g_functype is lambda or lexpr, the arguments are evaluated (by calling _e_v_a_l recursively) and stacked. If g_functype is nlambda then the argu- ment list is stacked. If g_functype is macro then the entire form, g_val is stacked. Next, the formal variables are lambda bound. The formal variables are the cadr of g_func. If g_functype is nlambda, lexpr or macro, there should only be one formal variable. The values on the stack are lambda bound to the formal vari- ables except in the case of a lexpr, where the number of actual arguments is bound to the formal variable. After the binding is done, the function is invoked, either by jumping to the entry point in the case of a binary or by evaluating the list of forms beginning at cddr g_func. The result of this function invocation is returned as the value of the call to eval. (evalframe 'x_pdlpointer) RETURNS: an evalframe descriptor for the evaluation frame just before x_pdlpointer. If x_pdlpointer is nil, it returns the evaluation frame of the frame just before the current call to _e_v_a_l_f_r_a_m_e. NOTE: An evalframe descriptor describes a call to _e_v_a_l, _a_p_p_l_y or _f_u_n_c_a_l_l. The form of the descriptor is (_t_y_p_e _p_d_l-_p_o_i_n_t_e_r _e_x_p_r_e_s_s_i_o_n _b_i_n_d-_p_o_i_n_t_e_r _n_p- _i_n_d_e_x _l_b_o_t-_i_n_d_e_x) where type is `eval' if this describes a call to _e_v_a_l or `apply' if this is a call to _a_p_p_l_y or _f_u_n_c_a_l_l. pdl-pointer is a number which describes this context. It can be passed to _e_v_a_l_- _f_r_a_m_e to obtain the next descriptor and can be passed to _f_r_e_t_u_r_n to cause a return from this The Franz Lisp Manual PS2:9-77 context. bind-pointer is the size of variable binding stack when this evaluation began. The bind-pointer can be given as a second argument to _e_v_a_l to order to evaluate variables in the same context as this evaluation. If type is `eval' then expression will have the form (_f_u_n_c_t_i_o_n- _n_a_m_e _a_r_g_1 ...). If type is `apply' then expres- sion will have the form (_f_u_n_c_t_i_o_n- _n_a_m_e (_a_r_g_1 ...)). np-index and lbot-index are pointers into the argument stack (also known as the _n_a_m_e_s_t_a_c_k array) at the time of call. lbot- index points to the first argument, np-index points one beyond the last argument. In order for there to be enough information for _e_v_a_l_f_r_a_m_e to return, you must call (*_r_s_e_t _t). EXAMPLE: (_p_r_o_g_n (_e_v_a_l_f_r_a_m_e _n_i_l)) returns (_e_v_a_l _2_1_4_7_4_7_8_6_0_0 (_p_r_o_g_n (_e_v_a_l_f_r_a_m_e _n_i_l)) _1 _8 _7) (evalhook 'g_form 'su_evalfunc ['su_funcallfunc]) RETURNS: the result of evaluating g_form after lambda binding `evalhook' to su_evalfunc and, if it is given, lambda binding `funcallhook' to su_funcallhook. NOTE: As explained in 14.4, the function _e_v_a_l may pass the job of evaluating a form to a user `hook' function when various switches are set. The hook function normally prints the form to be evaluated on the terminal and then evaluates it by calling _e_v_a_l_h_o_o_k. _E_v_a_l_h_o_o_k does the lambda binding mentioned above and then calls _e_v_a_l to evaluate the form after setting an internal switch to tell _e_v_a_l not to call the user's hook function just this one time. This allows the evaluation process to advance one step and yet insure that further calls to _e_v_a_l will cause traps to the hook function (if su_evalfunc is non-null). In order for _e_v_a_l_h_o_o_k to work, (*_r_s_e_t _t) and (_s_s_t_a_t_u_s _e_v_a_l_h_o_o_k _t) must have been done previ- ously. 9 9 PS2:9-78 The Franz Lisp Manual (exec s_arg1 ...) RETURNS: the result of forking and executing the com- mand named by concatenating the s_arg_i together with spaces in between. (exece 's_fname ['l_args ['l_envir]]) RETURNS: the error code from the system if it was unable to execute the command s_fname with arguments l_args and with the environment set up as specified in l_envir. If this function is successful, it will not return, instead the lisp system will be overlaid by the new com- mand. (freturn 'x_pdl-pointer 'g_retval) RETURNS: g_retval from the context given by x_pdl- pointer. NOTE: A pdl-pointer denotes a certain expression currently being evaluated. The pdl-pointer for a given expression can be obtained from _e_v_a_l_f_r_a_m_e. (frexp 'f_arg) RETURNS: a list cell (_e_x_p_o_n_e_n_t . _m_a_n_t_i_s_s_a) which represents the given flonum NOTE: The exponent will be a fixnum, the mantissa a 56 bit bignum. If you think of the the binary point occurring right after the high order bit of mantissa, then f_arg = 2[exponent] * mantissa. (funcall 'u_func ['g_arg1 ...]) RETURNS: the value of applying function u_func to the arguments g_arg_i and then evaluating that result if u_func is a macro. NOTE: If u_func is a macro or nlambda then there should be only one g_arg. _f_u_n_c_a_l_l is the function which the evaluator uses to evaluate lists. If _f_o_o is a lambda or lexpr or array, then (_f_u_n_c_a_l_l '_f_o_o '_a '_b '_c) is equivalent to (_f_o_o '_a '_b '_c). If _f_o_o is a nlambda then (_f_u_n_c_a_l_l '_f_o_o '(_a _b _c)) is equivalent to (_f_o_o _a _b _c). Finally, if _f_o_o is a macro then (_f_u_n_c_a_l_l '_f_o_o '(_f_o_o _a _b _c)) is equivalent to (_f_o_o _a _b _c). 9 9 The Franz Lisp Manual PS2:9-79 (funcallhook 'l_form 'su_funcallfunc ['su_evalfunc]) RETURNS: the result of _f_u_n_c_a_l_ling the (_c_a_r _l__f_o_r_m) on the already evaluated arguments in the (_c_d_r _l__f_o_r_m) after lambda binding `fun- callhook' to su_funcallfunc and, if it is given, lambda binding `evalhook' to su_evalhook. NOTE: This function is designed to continue the evalua- tion process with as little work as possible after a funcallhook trap has occurred. It is for this reason that the form of l_form is unortho- dox: its _c_a_r is the name of the function to call and its _c_d_r are a list of arguments to stack (without evaluating again) before calling the given function. After stacking the arguments but before calling _f_u_n_c_a_l_l an internal switch is set to prevent _f_u_n_c_a_l_l from passing the job of fun- calling to su_funcallfunc. If _f_u_n_c_a_l_l is called recursively in funcalling l_form and if su_funcallfunc is non-null, then the arguments to _f_u_n_c_a_l_l will actually be given to su_funcallfunc (a lexpr) to be funcalled. In order for _e_v_a_l_h_o_o_k to work, (*_r_s_e_t _t) and (_s_s_t_a_t_u_s _e_v_a_l_h_o_o_k _t) must have been done previ- ously. A more detailed description of _e_v_a_l_h_o_o_k and _f_u_n_c_a_l_l_h_o_o_k is given in Chapter 14. (function u_func) RETURNS: the function binding of u_func if it is an symbol with a function binding otherwise u_func is returned. (getdisc 'y_func) RETURNS: the discipline of the machine coded function (either lambda, nlambda or macro). (go g_labexp) WHERE: g_labexp is either a symbol or an expression. SIDE EFFECT: If g_labexp is an expression, that expres- sion is evaluated and should result in a symbol. The locus of control moves to just following the symbol g_labexp in the current prog or do body. NOTE: this is only valid in the context of a prog or do body. The interpreter and compiler will allow non-local _g_o's although the compiler won't allow PS2:9-80 The Franz Lisp Manual a _g_o to leave a function body. The compiler will not allow g_labexp to be an expression. (if 'g_a 'g_b) (if 'g_a 'g_b 'g_c ...) (if 'g_a then 'g_b [...] [elseif 'g_c then 'g_d ...] [else 'g_e [...]) (if 'g_a then 'g_b [...] [elseif 'g_c thenret] [else 'g_d [...]) NOTE: The various forms of _i_f are intended to be a more readable conditional statement, to be used in place of _c_o_n_d. There are two varieties of _i_f, with keywords, and without. The keyword-less variety is inherited from common Maclisp usage. A keyword-less, two argument _i_f is equivalent to a one-clause _c_o_n_d, i.e. (_c_o_n_d (a b)). Any other keyword-less _i_f must have at least three argu- ments. The first two arguments are the first clause of the equivalent _c_o_n_d, and all remaining arguments are shoved into a second clause begin- ning with t. Thus, the second form of _i_f is equivalent to (_c_o_n_d (a b) (t c ...)). The keyword variety has the following grouping of arguments: a predicate, a then-clause, and optional else-clause. The predicate is evaluated, and if the result is non-nil, the then-clause will be performed, in the sense described below. Otherwise, (i.e. the result of the predicate evaluation was precisely nil), the else-clause will be performed. Then-clauses will either consist entirely of the single keyword thenret, or will start with the keyword then, and be followed by at least one general expression. (These general expressions must not be one of the keywords.) To actuate a thenret means to cease further evaluation of the _i_f, and to return the value of the predicate just calculated. The performance of the longer clause means to evaluate each general expression in turn, and then return the last value calculated. The else-clause may begin with the keyword else and be followed by at least one general expres- sion. The rendition of this clause is just like that of a then-clause. An else-clause may begin alternatively with the keyword elseif, and be followed (recursively) by a predicate, then- clause, and optional else-clause. Evaluation of this clause, is just evaluation of an _i_f-form, The Franz Lisp Manual PS2:9-81 with the same predicate, then- and else-clauses. (I-throw-err 'l_token) WHERE: l_token is the _c_d_r of the value returned from a *_c_a_t_c_h with the tag ER%unwind-protect. RETURNS: nothing (never returns in the current context) SIDE EFFECT: The error or throw denoted by l_token is continued. NOTE: This function is used to implement _u_n_w_i_n_d-_p_r_o_t_e_c_t which allows the processing of a transfer of con- trol though a certain context to be interrupted, a user function to be executed and than the transfer of control to continue. The form of l_token is either (_t _t_a_g _v_a_l_u_e) for a throw or (_n_i_l _t_y_p_e _m_e_s_s_a_g_e _v_a_l_r_e_t _c_o_n_t_u_a_b _u_n_i_q_u_e_i_d [_a_r_g ...]) for an error. This function is not to be used for implementing throws or errors and is only documented here for completeness. (let l_args g_exp1 ... g_exprn) RETURNS: the result of evaluating g_exprn within the bindings given by l_args. NOTE: l_args is either nil (in which case _l_e_t is just like _p_r_o_g_n) or it is a list of binding objects. A binding object is a list (_s_y_m_b_o_l _e_x_p_r_e_s_s_i_o_n). When a _l_e_t is entered, all of the expressions are evaluated and then simultaneously lambda-bound to the corresponding symbols. In effect, a _l_e_t expression is just like a lambda expression except the symbols and their initial values are next to each other, making the expression easier to understand. There are some added features to the _l_e_t expression: A binding object can just be a symbol, in which case the expression corresponding to that symbol is `nil'. If a binding object is a list and the first element of that list is another list, then that list is assumed to be a binding template and _l_e_t will do a _d_e_s_e_t_q on it. 9 9 PS2:9-82 The Franz Lisp Manual (let* l_args g_exp1 ... g_expn) RETURNS: the result of evaluating g_exprn within the bindings given by l_args. NOTE: This is identical to _l_e_t except the expressions in the binding list l_args are evaluated and bound sequentially instead of in parallel. (lexpr-funcall 'g_function ['g_arg1 ...] 'l_argn) NOTE: This is a cross between funcall and apply. The last argument, must be a list (possibly empty). The element of list arg are stack and then the function is funcalled. EXAMPLE: (lexpr-funcall 'list 'a '(b c d)) is the same as (funcall 'list 'a 'b 'c 'd) (listify 'x_count) RETURNS: a list of x_count of the arguments to the current function (which must be a lexpr). NOTE: normally arguments 1 through x_count are returned. If x_count is negative then a list of last abs(x_count) arguments are returned. (map 'u_func 'l_arg1 ...) RETURNS: l_arg1 NOTE: The function u_func is applied to successive sub- lists of the l_arg_i. All sublists should have the same length. (mapc 'u_func 'l_arg1 ...) RETURNS: l_arg1. NOTE: The function u_func is applied to successive ele- ments of the argument lists. All of the lists should have the same length. 9 9 The Franz Lisp Manual PS2:9-83 (mapcan 'u_func 'l_arg1 ...) RETURNS: nconc applied to the results of the functional evaluations. NOTE: The function u_func is applied to successive ele- ments of the argument lists. All sublists should have the same length. (mapcar 'u_func 'l_arg1 ...) RETURNS: a list of the values returned from the func- tional application. NOTE: the function u_func is applied to successive ele- ments of the argument lists. All sublists should have the same length. (mapcon 'u_func 'l_arg1 ...) RETURNS: nconc applied to the results of the functional evaluation. NOTE: the function u_func is applied to successive sub- lists of the argument lists. All sublists should have the same length. (maplist 'u_func 'l_arg1 ...) RETURNS: a list of the results of the functional evaluations. NOTE: the function u_func is applied to successive sub- lists of the arguments lists. All sublists should have the same length. Readers may find the following summary table useful in remembering the differences between the six mapping functions: 8 ________________________________________________________________ Value returned is l_arg1 list of results _n_c_o_n_c of results 7 Argument to functional is 8 ________________________________________________________________ elements of list mapc mapcar mapcan sublists map maplist mapcon 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| 9 PS2:9-84 The Franz Lisp Manual (mfunction t_entry 's_disc) RETURNS: a lisp object of type binary composed of t_entry and s_disc. NOTE: t_entry is a pointer to the machine code for a function, and s_disc is the discipline (e.g. lambda). (oblist) RETURNS: a list of all symbols on the oblist. (or [g_arg1 ... ]) RETURNS: the value of the first non-null argument or nil if all arguments evaluate to nil. NOTE: Evaluation proceeds left to right and stops as soon as one of the arguments evaluates to a non- null value. (prog l_vrbls g_exp1 ...) RETURNS: the value explicitly given in a return form or else nil if no return is done by the time the last g_exp_i is evaluated. NOTE: the local variables are lambda-bound to nil, then the g_exp_i are evaluated from left to right. This is a prog body (obviously) and this means than any symbols seen are not evaluated, but are treated as labels. This also means that return's and go's are allowed. (prog1 'g_exp1 ['g_exp2 ...]) RETURNS: g_exp1 (prog2 'g_exp1 'g_exp2 ['g_exp3 ...]) RETURNS: g_exp2 NOTE: the forms are evaluated from left to right and the value of g_exp2 is returned. 9 9 The Franz Lisp Manual PS2:9-85 (progn 'g_exp1 ['g_exp2 ...]) RETURNS: the last g_exp_i. (progv 'l_locv 'l_initv g_exp1 ...) WHERE: l_locv is a list of symbols and l_initv is a list of expressions. RETURNS: the value of the last g_exp_i evaluated. NOTE: The expressions in l_initv are evaluated from left to right and then lambda-bound to the sym- bols in l_locv. If there are too few expressions in l_initv then the missing values are assumed to be nil. If there are too many expressions in l_initv then the extra ones are ignored (although they are evaluated). Then the g_exp_i are evaluated left to right. The body of a progv is like the body of a progn, it is _n_o_t a prog body. (C.f. _l_e_t) (purcopy 'g_exp) RETURNS: a copy of g_exp with new pure cells allocated wherever possible. NOTE: pure space is never swept up by the garbage col- lector, so this should only be done on expres- sions which are not likely to become garbage in the future. In certain cases, data objects in pure space become read-only after a _d_u_m_p_l_i_s_p and then an attempt to modify the object will result in an illegal memory reference. (purep 'g_exp) RETURNS: t iff the object g_exp is in pure space. (putd 's_name 'u_func) RETURNS: u_func SIDE EFFECT: this sets the function binding of symbol s_name to u_func. 9 9 PS2:9-86 The Franz Lisp Manual (return ['g_val]) RETURNS: g_val (or nil if g_val is not present) from the enclosing prog or do body. NOTE: this form is only valid in the context of a prog or do body. (selectq 'g_key-form [l_clause1 ...]) NOTE: This function is just like _c_a_s_e_q (see above), except that the symbol otherwise has the same semantics as the symbol t, when used as a com- parator. (setarg 'x_argnum 'g_val) WHERE: x_argnum is greater than zero and less than or equal to the number of arguments to the lexpr. RETURNS: g_val SIDE EFFECT: the lexpr's x_argnum'th argument is set to g-val. NOTE: this can only be used within the body of a lexpr. (throw 'g_val [s_tag]) WHERE: if s_tag is not given, it is assumed to be nil. RETURNS: the value of (*_t_h_r_o_w '_s__t_a_g '_g__v_a_l). (*throw 's_tag 'g_val) RETURNS: g_val from the first enclosing catch with the tag s_tag or with no tag at all. NOTE: this is used in conjunction with *_c_a_t_c_h to cause a clean jump to an enclosing context. 9 9 The Franz Lisp Manual PS2:9-87 (unwind-protect g_protected [g_cleanup1 ...]) RETURNS: the result of evaluating g_protected. NOTE: Normally g_protected is evaluated and its value remembered, then the g_cleanup_i are evaluated and finally the saved value of g_protected is returned. If something should happen when evaluating g_protected which causes control to pass through g_protected and thus through the call to the unwind-protect, then the g_cleanup_i will still be evaluated. This is useful if g_protected does something sensitive which must be cleaned up whether or not g_protected com- pletes. 9 9 CHAPTER 5 Input/Output The following functions are used to read from and write to external devices (e.g. files) and programs (through pipes). All I/O goes through the lisp data type called the port. A port may be open for either reading or writing, but usually not both simultaneously (see _f_i_l_e_o_p_e_n ). There are only a limited number of ports (20) and they will not be reclaimed unless they are _c_l_o_s_ed. All ports are reclaimed by a _r_e_s_e_t_i_o call, but this drastic step won't be necessary if the program closes what it uses. If a port argument is not supplied to a function which requires one, or if a bad port argument (such as nil) is given, then FRANZ LISP will use the default port according to this scheme: If input is being done then the default port is the value of the symbol _p_i_p_o_r_t and if output is being done then the default port is the value of the symbol _p_o_p_o_r_t. Furthermore, if the value of piport or poport is not a valid port, then the standard input or standard output will be used, respec- tively. The standard input and standard output are usually the keyboard and terminal display unless your job is running in the background and its input or output is connected to a pipe. All output which goes to the standard output will also go to the port _p_t_p_o_r_t if it is a valid port. Output destined for the standard out- put will not reach the standard output if the symbol ^_w is non nil (although it will still go to _p_t_p_o_r_t if _p_t_p_o_r_t is a valid port). Some of the functions listed below reference files directly. FRANZ LISP has borrowed a convenient short- hand notation from /_b_i_n/_c_s_h, concerning naming files. If a file name begins with ~ (tilde), and the symbol _t_i_l_d_e-_e_x_p_a_n_s_i_o_n is bound to something other than nil, then FRANZ LISP expands the file name. It takes the string of charac- ters between the leading tilde, and the first slash as a user-name. Then, that initial segment of the filename is replaced by the home directory of the user. The null username is taken to be the current user. 9 9PS2:9-88 The Franz Lisp Manual The Franz Lisp Manual PS2:9-89 FRANZ LISP keeps a cache of user home directory information, to minimize searching the password file. Tilde-expansion is performed in the following func- tions: _c_f_a_s_l, _c_h_d_i_r, _f_a_s_l, _f_f_a_s_l, _f_i_l_e_o_p_e_n, _i_n_f_i_l_e, _l_o_a_d, _o_u_t_f_i_l_e, _p_r_o_b_e_f, _s_y_s:_a_c_c_e_s_s, _s_y_s:_u_n_l_i_n_k. (cfasl 'st_file 'st_entry 'st_funcname ['st_disc ['st_library]]) RETURNS: t SIDE EFFECT: This is used to load in a foreign function (see 8.4). The object file st_file is loaded into the lisp system. St_entry should be an entry point in the file just loaded. The function binding of the sym- bol s_funcname will be set to point to st_entry, so that when the lisp function s_funcname is called, st_entry will be run. st_disc is the discipline to be given to s_funcname. st_disc defaults to "subroutine" if it is not given or if it is given as nil. If st_library is non- null, then after st_file is loaded, the libraries given in st_library will be searched to resolve external references. The form of st_library should be something like "-lm". The C library (" -lc " ) is always searched so when loading in a C file you probably won't need to specify a library. For Fortran files, you should specify "-lF77" and if you are doing any I/O, the library entry should be "-lI77 -lF77". For Pascal files "-lpc" is required. NOTE: This function may be used to load the output of the assembler, C compiler, Fortran compiler, and Pascal compiler but NOT the lisp compiler (use _f_a_s_l for that). If a file has more than one entry point, then use _g_e_t_a_d_d_r_e_s_s to locate and setup other foreign functions. It is an error to load in a file which has a glo- bal entry point of the same name as a global entry point in the running lisp. As soon as you load in a file with _c_f_a_s_l, its global entry points become part of the lisp's entry points. Thus you cannot _c_f_a_s_l in the same file twice unless you use _r_e_m_o_v_e_a_d_d_r_e_s_s to change certain global entry points to local entry points. 9 9 PS2:9-90 The Franz Lisp Manual (close 'p_port) RETURNS: t SIDE EFFECT: the specified port is drained and closed, releasing the port. NOTE: The standard defaults are not used in this case since you probably never want to close the stan- dard output or standard input. (cprintf 'st_format 'xfst_val ['p_port]) RETURNS: xfst_val SIDE EFFECT: The UNIX formatted output function printf is called with arguments st_format and xfst_val. If xfst_val is a symbol then its print name is passed to printf. The format string may contain characters which are just printed literally and it may con- tain special formatting commands preceded by a percent sign. The complete set of formatting characters is described in the UNIX manual. Some useful ones are %d for printing a fixnum in decimal, %f or %e for printing a flonum, and %s for printing a character string (or print name of a sym- bol). EXAMPLE: (_c_p_r_i_n_t_f "_P_i _e_q_u_a_l_s %_f" _3._1_4_1_5_9) prints `Pi equals 3.14159' (drain ['p_port]) RETURNS: nil SIDE EFFECT: If this is an output port then the charac- ters in the output buffer are all sent to the device. If this is an input port then all pending characters are flushed. The default port for this function is the default output port. 9 9 The Franz Lisp Manual PS2:9-91 (ex [s_filename]) (vi [s_filename]) (exl [s_filename]) (vil [s_filename]) RETURNS: nil SIDE EFFECT: The lisp system starts up an editor on the file named as the argument. It will try appending .l to the file if it can't find it. The functions _e_x_l and _v_i_l will load the file after you finish editing it. These functions will also remember the name of the file so that on subsequent invocations, you don't need to provide the argument. NOTE: These functions do not evaluate their argument. (fasl 'st_name ['st_mapf ['g_warn]]) WHERE: st_mapf and g_warn default to nil. RETURNS: t if the function succeeded, nil otherwise. SIDE EFFECT: this function is designed to load in an object file generated by the lisp compiler Liszt. File names for object files usu- ally end in `.o', so _f_a_s_l will append `.o' to st_name (if it is not already present). If st_mapf is non nil, then it is the name of the map file to create. _F_a_s_l writes in the map file the names and addresses of the functions it loads and defines. Nor- mally the map file is created (i.e. trun- cated if it exists), but if (_s_s_t_a_t_u_s _a_p_p_e_n_d_m_a_p _t) is done then the map file will be appended. If g_warn is non nil and if a function is loaded from the file which is already defined, then a warning message will be printed. NOTE: _f_a_s_l only looks in the current directory for the file to load. The function _l_o_a_d looks through a user-supplied search path and will call _f_a_s_l if it finds a file with the same root name and a `.o' extension. In most cases the user would be better off using the function _l_o_a_d rather than calling _f_a_s_l directly. 9 9 PS2:9-92 The Franz Lisp Manual (ffasl 'st_file 'st_entry 'st_funcname ['st_discipline ['st_library]]) RETURNS: the binary object created. SIDE EFFECT: the Fortran object file st_file is loaded into the lisp system. St_entry should be an entry point in the file just loaded. A binary object will be created and its entry field will be set to point to st_entry. The discipline field of the binary will be set to st_discipline or "subroutine" by default. If st_library is present and non-null, then after st_file is loaded, the libraries given in st_library will be searched to resolve external references. The form of st_library should be something like "-lS -ltermcap". In any case, the standard Fortran libraries will be searched also to resolve external references. NOTE: in F77 on Unix, the entry point for the fortran function foo is named `_foo_'. (filepos 'p_port ['x_pos]) RETURNS: the current position in the file if x_pos is not given or else x_pos if x_pos is given. SIDE EFFECT: If x_pos is given, the next byte to be read or written to the port will be at position x_pos. (filestat 'st_filename) RETURNS: a vector containing various numbers which the UNIX operating system assigns to files. if the file doesn't exist, an error is invoked. Use _p_r_o_b_e_f to determine if the file exists. NOTE: The individual entries can be accesed by mnemonic functions of the form filestat:_f_i_e_l_d, where field may be any of atime, ctime, dev, gid, ino, mode,mtime, nlink, rdev, size, type, uid. See the UNIX programmers manual for a more detailed description of these quantities. 9 9 The Franz Lisp Manual PS2:9-93 (flatc 'g_form ['x_max]) RETURNS: the number of characters required to print g_form using _p_a_t_o_m. If x_max is given and if _f_l_a_t_c determines that it will return a value greater than x_max, then it gives up and returns the current value it has computed. This is useful if you just want to see if an expression is larger than a certain size. (flatsize 'g_form ['x_max]) RETURNS: the number of characters required to print g_form using _p_r_i_n_t. The meaning of x_max is the same as for flatc. NOTE: Currently this just _e_x_p_l_o_d_e's g_form and checks its length. (fileopen 'st_filename 'st_mode) RETURNS: a port for reading or writing (depending on st_mode) the file st_name. SIDE EFFECT: the given file is opened (or created if opened for writing and it doesn't yet exist). NOTE: this function call provides a direct interface to the operating system's fopen function. The mode may be more than just "r" for read, "w" for write or "a" for append. The modes "r+", "w+" and "a+" permit both reading and writing on a port pro- vided that _f_s_e_e_k is done between changes in direction. See the UNIX manual description of fopen for more details. This routine does not look through a search path for a given file. (fseek 'p_port 'x_offset 'x_flag) RETURNS: the position in the file after the function is performed. SIDE EFFECT: this function positions the read/write pointer before a certain byte in the file. If x_flag is 0 then the pointer is set to x_offset bytes from the beginning of the file. If x_flag is 1 then the pointer is set to x_offset bytes from the current location in the file. If x_flag is 2 then the pointer is set to x_offset bytes from the end of the file. 9 9 PS2:9-94 The Franz Lisp Manual (infile 's_filename) RETURNS: a port ready to read s_filename. SIDE EFFECT: this tries to open s_filename and if it cannot or if there are no ports available it gives an error message. NOTE: to allow your program to continue on a file-not- found error, you can use something like: (_c_o_n_d ((_n_u_l_l (_s_e_t_q _m_y_p_o_r_t (_c_a_r (_e_r_r_s_e_t (_i_n_f_i_l_e _n_a_m_e) _n_i_l)))) (_p_a_t_o_m '"_c_o_u_l_d_n'_t _o_p_e_n _t_h_e _f_i_l_e"))) which will set myport to the port to read from if the file exists or will print a message if it couldn't open it and also set myport to nil. To simply determine if a file exists, use _p_r_o_b_e_f. (load 's_filename ['st_map ['g_warn]]) RETURNS: t NOTE: The function of _l_o_a_d has changed since previous releases of FRANZ LISP and the following descrip- tion should be read carefully. SIDE EFFECT: _l_o_a_d now serves the function of both _f_a_s_l and the old _l_o_a_d. _L_o_a_d will search a user defined search path for a lisp source or object file with the filename s_filename (with the extension .l or .o added as appropriate). The search path which _l_o_a_d uses is the value of (_s_t_a_t_u_s _l_o_a_d-_s_e_a_r_c_h- _p_a_t_h). The default is (|.| /usr/lib/lisp) which means look in the current directory first and then /usr/lib/lisp. The file which _l_o_a_d looks for depends on the last two characters of s_filename. If s_filename ends with ".l" then _l_o_a_d will only look for a file name s_filename and will assume that this is a FRANZ LISP source file. If s_filename ends with ".o" then _l_o_a_d will only look for a file named s_filename and will assume that this is a FRANZ LISP object file to be _f_a_s_led in. Otherwise, _l_o_a_d will first look for s_filename.o, then s_filename.l and finally s_filename itself. If it finds s_filename.o it will assume that this is an object file, otherwise it will assume that it is a source file. An object file is loaded using _f_a_s_l and a source file is loaded by reading and evaluating each form The Franz Lisp Manual PS2:9-95 in the file. The optional arguments st_map and g_warn are passed to _f_a_s_l should _f_a_s_l be called. NOTE: _l_o_a_d requires a port to open the file s_filename. It then lambda binds the symbol piport to this port and reads and evaluates the forms. (makereadtable ['s_flag]) WHERE: if s_flag is not present it is assumed to be nil. RETURNS: a readtable equal to the original readtable if s_flag is non-null, or else equal to the current readtable. See chapter 7 for a description of readtables and their uses. (msg [l_option ...] ['g_msg ...]) NOTE: This function is intended for printing short mes- sages. Any of the arguments or options presented can be used any number of times, in any order. The messages themselves (g_msg) are evaluated, and then they are transmitted to _p_a_t_o_m. Typi- cally, they are strings, which evaluate to them- selves. The options are interpreted specially: ____________________________________________________ _m_s_g _O_p_t_i_o_n _S_u_m_m_a_r_y (_P _p__p_o_r_t_n_a_m_e) causes subsequent output to go to the port p_portname (port should be opened previously) _B print a single blank. (_B '_n__b) evaluate n_b and print that many blanks. _N print a single by calling _t_e_r_p_r. (_N '_n__n) evaluate n_n and transmit that many newlines to the stream. _D _d_r_a_i_n the current port. ____________________________________________________ 9 9 PS2:9-96 The Franz Lisp Manual (nwritn ['p_port]) RETURNS: the number of characters in the buffer of the given port but not yet written out to the file or device. The buffer is flushed automati- cally when filled, or when _t_e_r_p_r is called. (outfile 's_filename ['st_type]) RETURNS: a port or nil SIDE EFFECT: this opens a port to write s_filename. If st_type is given and if it is a symbol or string whose name begins with `a', then the file will be opened in append mode, that is the current contents will not be lost and the next data will be written at the end of the file. Otherwise, the file opened is truncated by _o_u_t_f_i_l_e if it existed beforehand. If there are no free ports, outfile returns nil. If one cannot write on s_filename, an error is sig- nalled. (patom 'g_exp ['p_port]) RETURNS: g_exp SIDE EFFECT: g_exp is printed to the given port or the default port. If g_exp is a symbol or string, the print name is printed without any escape characters around special char- acters in the print name. If g_exp is a list then _p_a_t_o_m has the same effect as _p_r_i_n_t. (pntlen 'xfs_arg) RETURNS: the number of characters needed to print xfs_arg. (portp 'g_arg) RETURNS: t iff g_arg is a port. 9 9 The Franz Lisp Manual PS2:9-97 (pp [l_option] s_name1 ...) RETURNS: t SIDE EFFECT: If s_name_i has a function binding, it is pretty-printed, otherwise if s_name_i has a value then that is pretty-printed. Nor- mally the output of the pretty-printer goes to the standard output port poport. The options allow you to redirect it. ____________________________________________________ _P_P _O_p_t_i_o_n _S_u_m_m_a_r_y (_F _s__f_i_l_e_n_a_m_e) direct future printing to s_filename (_P _p__p_o_r_t_n_a_m_e) causes output to go to the port p_portname (port should be opened previously) (_E _g__e_x_p_r_e_s_s_i_o_n) evaluate g_expression and don't print ____________________________________________________ (princ 'g_arg ['p_port]) EQUIVALENT TO: patom. (print 'g_arg ['p_port]) RETURNS: nil SIDE EFFECT: prints g_arg on the port p_port or the default port. (probef 'st_file) RETURNS: t iff the file st_file exists. NOTE: Just because it exists doesn't mean you can read it. 9 9 PS2:9-98 The Franz Lisp Manual (pp-form 'g_form ['p_port]) RETURNS: t SIDE EFFECT: g_form is pretty-printed to the port p_port (or poport if p_port is not given). This is the function which _p_p uses. _p_p- _f_o_r_m does not look for function defini- tions or values of variables, it just prints out the form it is given. NOTE: This is useful as a top-level-printer, c.f. _t_o_p- _l_e_v_e_l in Chapter 6. (ratom ['p_port ['g_eof]]) RETURNS: the next atom read from the given or default port. On end of file, g_eof (default nil) is returned. (read ['p_port ['g_eof]]) RETURNS: the next lisp expression read from the given or default port. On end of file, g_eof (default nil) is returned. NOTE: An error will occur if the reader is given an ill formed expression. The most common error is too many right parentheses (note that this is not considered an error in Maclisp). (readc ['p_port ['g_eof]]) RETURNS: the next character read from the given or default port. On end of file, g_eof (default nil) is returned. (readlist 'l_arg) RETURNS: the lisp expression read from the list of characters in l_arg. 9 9 The Franz Lisp Manual PS2:9-99 (removeaddress 's_name1 ['s_name2 ...]) RETURNS: nil SIDE EFFECT: the entries for the s_name_i in the Lisp symbol table are removed. This is useful if you wish to _c_f_a_s_l or _f_f_a_s_l in a file twice, since it is illegal for a symbol in the file you are loading to already exist in the lisp symbol table. (resetio) RETURNS: nil SIDE EFFECT: all ports except the standard input, out- put and error are closed. (setsyntax 's_symbol 's_synclass ['ls_func]) RETURNS: t SIDE EFFECT: this sets the code for s_symbol to sx_code in the current readtable. If s_synclass is _m_a_c_r_o or _s_p_l_i_c_i_n_g then ls_func is the associated function. See Chapter 7 on the reader for more details. (sload 's_file) SIDE EFFECT: the file s_file (in the current directory) is opened for reading and each form is read, printed and evaluated. If the form is recognizable as a function definition, only its name will be printed, otherwise the whole form is printed. NOTE: This function is useful when a file refuses to load because of a syntax error and you would like to narrow down where the error is. (tab 'x_col ['p_port]) SIDE EFFECT: enough spaces are printed to put the cur- sor on column x_col. If the cursor is beyond x_col to start with, a _t_e_r_p_r is done first. 9 9 PS2:9-100 The Franz Lisp Manual (terpr ['p_port]) RETURNS: nil SIDE EFFECT: a terminate line character sequence is sent to the given port or the default port. This will also drain the port. (terpri ['p_port]) EQUIVALENT TO: terpr. (tilde-expand 'st_filename) RETURNS: a symbol whose pname is the tilde-expansion of the argument, (as discussed at the beginning of this chapter). If the argument does not begin with a tilde, the argument itself is returned. (tyi ['p_port]) RETURNS: the fixnum representation of the next charac- ter read. On end of file, -1 is returned. (tyipeek ['p_port]) RETURNS: the fixnum representation of the next charac- ter to be read. NOTE: This does not actually read the character, it just peeks at it. (tyo 'x_char ['p_port]) RETURNS: x_char. SIDE EFFECT: the character whose fixnum representation is x_code, is printed as a on the given output port or the default output port. (untyi 'x_char ['p_port]) SIDE EFFECT: x_char is put back in the input buffer so a subsequent _t_y_i or _r_e_a_d will read it first. NOTE: a maximum of one character may be put back. 9 9 The Franz Lisp Manual PS2:9-101 (username-to-dir 'st_name) RETURNS: the home directory of the given user. The result is stored, to avoid unnecessarily searching the password file. (zapline) RETURNS: nil SIDE EFFECT: all characters up to and including the line termination character are read and discarded from the last port used for input. NOTE: this is used as the macro function for the semi- colon character when it acts as a comment charac- ter. 9 9 CHAPTER 6 System Functions This chapter describes the functions used to interact with internal components of the Lisp system and operating system. (allocate 's_type 'x_pages) WHERE: s_type is one of the FRANZ LISP data types described in 1.3. RETURNS: x_pages. SIDE EFFECT: FRANZ LISP attempts to allocate x_pages of type s_type. If there aren't x_pages of memory left, no space will be allocated and an error will occur. The storage that is allocated is not given to the caller, instead it is added to the free storage list of s_type. The functions _s_e_g_m_e_n_t and _s_m_a_l_l-_s_e_g_m_e_n_t allocate blocks of storage and return it to the caller. (argv 'x_argnumb) RETURNS: a symbol whose pname is the x_argnumb_t_h argu- ment (starting at 0) on the command line which invoked the current lisp. NOTE: if x_argnumb is less than zero, a fixnum whose value is the number of arguments on the command line is returned. (_a_r_g_v _0) returns the name of the lisp you are running. (baktrace) RETURNS: nil SIDE EFFECT: the lisp runtime stack is examined and the name of (most) of the functions currently in execution are printed, most active first. NOTE: this will occasionally miss the names of compiled lisp functions due to incomplete information on the stack. If you are tracing compiled code, then _b_a_k_t_r_a_c_e won't be able to interpret the PS2:9-102 The Franz Lisp Manual The Franz Lisp Manual PS2:9-103 stack unless (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l) was done. See the function _s_h_o_w_s_t_a_c_k for another way of printing the lisp runtime stack. This misspel- ling is from Maclisp. (chdir 's_path) RETURNS: t iff the system call succeeds. SIDE EFFECT: the current directory set to s_path. Among other things, this will affect the default location where the input/output functions look for and create files. NOTE: _c_h_d_i_r follows the standard UNIX conventions, if s_path does not begin with a slash, the default path is changed to the current path with s_path appended. _C_h_d_i_r employs tilde-expansion (dis- cussed in Chapter 5). (command-line-args) RETURNS: a list of the arguments typed on the command line, either to the lisp interpreter, or saved lisp dump, or application compiled with the autorun option (liszt -r). (deref 'x_addr) RETURNS: The contents of x_addr, when thought of as a longword memory location. NOTE: This may be useful in constructing arguments to C functions out of `dangerous' areas of memory. (dumplisp s_name) RETURNS: nil SIDE EFFECT: the current lisp is dumped to the named file. When s_name is executed, you will be in a lisp in the same state as when the dumplisp was done. NOTE: dumplisp will fail if one tries to write over the current running file. UNIX does not allow you to modify the file you are running. 9 9 PS2:9-104 The Franz Lisp Manual (eval-when l_time g_exp1 ...) SIDE EFFECT: l_time may contain any combination of the symbols _l_o_a_d, _e_v_a_l, and _c_o_m_p_i_l_e. The effects of load and compile is discussed in 12.3.2.1 compiler. If eval is present however, this simply means that the expressions g_exp1 and so on are evaluated from left to right. If eval is not present, the forms are not evaluated. (exit ['x_code]) RETURNS: nothing (it never returns). SIDE EFFECT: the lisp system dies with exit code x_code or 0 if x_code is not specified. (fake 'x_addr) RETURNS: the lisp object at address x_addr. NOTE: This is intended to be used by people debugging the lisp system. (fork) RETURNS: nil to the child process and the process number of the child to the parent. SIDE EFFECT: A copy of the current lisp system is made in memory and both lisp systems now begin to run. This function can be used interactively to temporarily save the state of Lisp (as shown below), but you must be careful that only one of the lisp's interacts with the terminal after the fork. The _w_a_i_t function is useful for this. 9 9 The Franz Lisp Manual PS2:9-105 ____________________________________________________ -> (_s_e_t_q _f_o_o '_b_a_r) ;; set a variable bar -> (_c_o_n_d ((_f_o_r_k)(_w_a_i_t))) ;; duplicate the lisp system and nil ;; make the parent wait -> _f_o_o ;; check the value of the variable bar -> (_s_e_t_q _f_o_o '_b_a_z) ;; give it a new value baz -> _f_o_o ;; make sure it worked baz -> (_e_x_i_t) ;; exit the child (5274 . 0) ;; the _w_a_i_t function returns this -> _f_o_o ;; we check to make sure parent was bar ;; not modified. ____________________________________________________ (gc) RETURNS: nil SIDE EFFECT: this causes a garbage collection. NOTE: The function _g_c_a_f_t_e_r is not called automatically after this function finishes. Normally the user doesn't have to call _g_c since garbage collection occurs automatically whenever internal free lists are exhausted. (gcafter s_type) WHERE: s_type is one of the FRANZ LISP data types listed in 1.3. NOTE: this function is called by the garbage collector after a garbage collection which was caused by running out of data type s_type. This function should determine if more space need be allocated and if so should allocate it. There is a default gcafter function but users who want control over space allocation can define their own -- but note that it must be an nlambda. 9 9 PS2:9-106 The Franz Lisp Manual (getenv 's_name) RETURNS: a symbol whose pname is the value of s_name in the current UNIX environment. If s_name doesn't exist in the current environment, a symbol with a null pname is returned. (hashtabstat) RETURNS: a list of fixnums representing the number of symbols in each bucket of the oblist. NOTE: the oblist is stored a hash table of buckets. Ideally there would be the same number of symbols in each bucket. (help [sx_arg]) SIDE EFFECT: If sx_arg is a symbol then the portion of this manual beginning with the description of sx_arg is printed on the terminal. If sx_arg is a fixnum or the name of one of the appendicies, that chapter or appendix is printed on the terminal. If no argu- ment is provided, _h_e_l_p prints the options that it recognizes. The program `more' is used to print the manual on the terminal; it will stop after each page and will con- tinue after the space key is pressed. (include s_filename) RETURNS: nil SIDE EFFECT: The given filename is _l_o_a_ded into the lisp. NOTE: this is similar to load except the argument is not evaluated. Include means something special to the compiler. (include-if 'g_predicate s_filename) RETURNS: nil SIDE EFFECT: This has the same effect as include, but is only actuated if the predicate is non- nil. 9 9 The Franz Lisp Manual PS2:9-107 (includef 's_filename) RETURNS: nil SIDE EFFECT: this is the same as _i_n_c_l_u_d_e except the argument is evaluated. (includef-if 'g_predicate s_filename) RETURNS: nil SIDE EFFECT: This has the same effect as includef, but is only actuated if the predicate is non- nil. (maknum 'g_arg) RETURNS: the address of its argument converted into a fixnum. (monitor ['xs_maxaddr]) RETURNS: t SIDE EFFECT: If xs_maxaddr is t then profiling of the entire lisp system is begun. If xs_maxaddr is a fixnum then profiling is done only up to address xs_maxaddr. If xs_maxaddr is not given, then profiling is stopped and the data obtained is written to the file 'mon.out' where it can be analyzed with the UNIX 'prof' program. NOTE: this function only works if the lisp system has been compiled in a special way, otherwise, an error is invoked. (opval 's_arg ['g_newval]) RETURNS: the value associated with s_arg before the call. SIDE EFFECT: If g_newval is specified, the value asso- ciated with s_arg is changed to g_newval. NOTE: _o_p_v_a_l keeps track of storage allocation. If s_arg is one of the data types then _o_p_v_a_l will return a list of three fixnums representing the number of items of that type in use, the number of pages allocated and the number of items of that type per page. You should never try to change the value _o_p_v_a_l associates with a data type using _o_p_v_a_l. PS2:9-108 The Franz Lisp Manual If s_arg is _p_a_g_e_l_i_m_i_t then _o_p_v_a_l will return (and set if g_newval is given) the maximum amount of lisp data pages it will allocate. This limit should remain small unless you know your program requires lots of space as this limit will catch programs in infinite loops which gobble up memory. (*process 'st_command ['g_readp ['g_writep]]) RETURNS: either a fixnum if one argument is given, or a list of two ports and a fixnum if two or three arguments are given. NOTE: *_p_r_o_c_e_s_s starts another process by passing st_command to the shell (it first tries /bin/csh, then it tries /bin/sh if /bin/csh doesn't exist). If only one argument is given to *_p_r_o_c_e_s_s, *_p_r_o_- _c_e_s_s waits for the new process to die and then returns the exit code of the new process. If more two or three arguments are given, *_p_r_o_c_e_s_s starts the process and then returns a list which, depending on the value of g_readp and g_writep, may contain i/o ports for communcating with the new process. If g_writep is non-null, then a port will be created which the lisp program can use to send characters to the new process. If g_readp is non-null, then a port will be created which the lisp program can use to read characters from the new process. The value returned by *_p_r_o_c_e_s_s is (readport writeport pid) where read- port and writeport are either nil or a port based on the value of g_readp and g_writep. Pid is the process id of the new process. Since it is hard to remember the order of g_readp and g_writep, the functions *_p_r_o_c_e_s_s-_s_e_n_d and *_p_r_o_c_e_s_s-_r_e_c_e_i_v_e were written to perform the common functions. (*process-receive 'st_command) RETURNS: a port which can be read. SIDE EFFECT: The command st_command is given to the shell and it is started running in the background. The output of that command is available for reading via the port returned. The input of the command pro- cess is set to /dev/null. 9 9 The Franz Lisp Manual PS2:9-109 (*process-send 'st_command) RETURNS: a port which can be written to. SIDE EFFECT: The command st_command is given to the shell and it is started runing in the background. The lisp program can provide input for that command by sending charac- ters to the port returned by this func- tion. The output of the command process is set to /dev/null. (process s_pgrm [s_frompipe s_topipe]) RETURNS: if the optional arguments are not present a fixnum which is the exit code when s_prgm dies. If the optional arguments are present, it returns a fixnum which is the process id of the child. NOTE: This command is obsolete. New programs should use one of the *_p_r_o_c_e_s_s commands given above. SIDE EFFECT: If s_frompipe and s_topipe are given, they are bound to ports which are pipes which direct characters from FRANZ LISP to the new process and to FRANZ LISP from the new process respectively. _P_r_o_c_e_s_s forks a process named s_prgm and waits for it to die iff there are no pipe arguments given. (ptime) RETURNS: a list of two elements. The first is the amount of processor time used by the lisp sys- tem so far, and the second is the amount of time used by the garbage collector so far. NOTE: the time is measured in those units used by the _t_i_m_e_s(2) system call, usually 60_t_hs of a second. The first number includes the second number. The amount of time used by garbage collection is not recorded until the first call to ptime. This is done to prevent overhead when the user is not interested in garbage collection times. 9 9 PS2:9-110 The Franz Lisp Manual (reset) SIDE EFFECT: the lisp runtime stack is cleared and the system restarts at the top level by exe- cuting a (_f_u_n_c_a_l_l _t_o_p-_l_e_v_e_l _n_i_l). (restorelisp 's_name) SIDE EFFECT: this reads in file s_name (which was created by _s_a_v_e_l_i_s_p) and then does a (_r_e_s_e_t). NOTE: This is only used on VMS systems where _d_u_m_p_l_i_s_p cannot be used. (retbrk ['x_level]) WHERE: x_level is a small integer of either sign. SIDE EFFECT: The default error handler keeps a notion of the current level of the error caught. If x_level is negative, control is thrown to this default error handler whose level is that many less than the present, or to _t_o_p-_l_e_v_e_l if there aren't enough. If x_level is non-negative, control is passed to the handler at that level. If x_level is not present, the value -1 is taken by default. (*rset 'g_flag) RETURNS: g_flag SIDE EFFECT: If g_flag is non nil then the lisp system will maintain extra information about calls to _e_v_a_l and _f_u_n_c_a_l_l. This record keeping slows down the evaluation but this is required for the functions _e_v_a_l_h_o_o_k, _f_u_n_c_a_l_l_h_o_o_k, and _e_v_a_l_f_r_a_m_e to work. To debug compiled lisp code the transfer tables should be unlinked: (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l) 9 9 The Franz Lisp Manual PS2:9-111 (savelisp 's_name) RETURNS: t SIDE EFFECT: the state of the Lisp system is saved in the file s_name. It can be read in by _r_e_s_t_o_r_e_l_i_s_p. NOTE: This is only used on VMS systems where _d_u_m_p_l_i_s_p cannot be used. (segment 's_type 'x_size) WHERE: s_type is one of the data types given in 1.3 RETURNS: a segment of contiguous lispvals of type s_type. NOTE: In reality, _s_e_g_m_e_n_t returns a new data cell of type s_type and allocates space for x_size - 1 more s_type's beyond the one returned. _S_e_g_m_e_n_t always allocates new space and does so in 512 byte chunks. If you ask for 2 fixnums, segment will actually allocate 128 of them thus wasting 126 fixnums. The function _s_m_a_l_l-_s_e_g_m_e_n_t is a smarter space allocator and should be used when- ever possible. (shell) RETURNS: the exit code of the shell when it dies. SIDE EFFECT: this forks a new shell and returns when the shell dies. (showstack) RETURNS: nil SIDE EFFECT: all forms currently in evaluation are printed, beginning with the most recent. For compiled code the most that showstack will show is the function name and it may miss some functions. 9 9 PS2:9-112 The Franz Lisp Manual (signal 'x_signum 's_name) RETURNS: nil if no previous call to signal has been made, or the previously installed s_name. SIDE EFFECT: this declares that the function named s_name will handle the signal number x_signum. If s_name is nil, the signal is ignored. Presently only four UNIX signals are caught. They and their numbers are: Interrupt(2), Floating exception(8), Alarm(14), and Hang-up(1). (sizeof 'g_arg) RETURNS: the number of bytes required to store one object of type g_arg, encoded as a fixnum. (small-segment 's_type 'x_cells) WHERE: s_type is one of fixnum, flonum and value. RETURNS: a segment of x_cells data objects of type s_type. SIDE EFFECT: This may call _s_e_g_m_e_n_t to allocate new space or it may be able to fill the request on a page already allocated. The value returned by _s_m_a_l_l-_s_e_g_m_e_n_t is usually stored in the data subpart of an array object. (sstatus g_type g_val) RETURNS: g_val SIDE EFFECT: If g_type is not one of the special sstatus codes described in the next few pages this simply sets g_val as the value of status type g_type in the system status property list. 9 9 The Franz Lisp Manual PS2:9-113 (sstatus appendmap g_val) RETURNS: g_val SIDE EFFECT: If g_val is non-null when _f_a_s_l is told to create a load map, it will append to the file name given in the _f_a_s_l command, rather than creating a new map file. The initial value is nil. (sstatus automatic-reset g_val) RETURNS: g_val SIDE EFFECT: If g_val is non-null when an error occurs which no one wants to handle, a _r_e_s_e_t will be done instead of entering a primitive internal break loop. The initial value is t. (sstatus chainatom g_val) RETURNS: g_val SIDE EFFECT: If g_val is non nil and a _c_a_r or _c_d_r of a symbol is done, then nil will be returned instead of an error being signaled. This only affects the interpreter, not the com- piler. The initial value is nil. (sstatus dumpcore g_val) RETURNS: g_val SIDE EFFECT: If g_val is nil, FRANZ LISP tells UNIX that a segmentation violation or bus error should cause a core dump. If g_val is non nil then FRANZ LISP will catch those errors and print a message advising the user to reset. NOTE: The initial value for this flag is nil, and only those knowledgeable of the innards of the lisp system should ever set this flag non nil. 9 9 PS2:9-114 The Franz Lisp Manual (sstatus dumpmode x_val) RETURNS: x_val SIDE EFFECT: All subsequent _d_u_m_p_l_i_s_p's will be done in mode x_val. x_val may be either 413 or 410 (decimal). NOTE: the advantage of mode 413 is that the dumped Lisp can be demand paged in when first started, which will make it start faster and disrupt other users less. The initial value is 413. (sstatus evalhook g_val) RETURNS: g_val SIDE EFFECT: When g_val is non nil, this enables the evalhook and funcallhook traps in the evaluator. See 14.4 for more details. (sstatus feature g_val) RETURNS: g_val SIDE EFFECT: g_val is added to the (_s_t_a_t_u_s _f_e_a_t_u_r_e_s) list, (sstatus gcstrings g_val) RETURNS: g_val SIDE EFFECT: if g_val is non-null, and if string gar- bage collection was enabled when the lisp system was compiled, string space will be garbage collected. NOTE: the default value for this is nil since in most applications garbage collecting strings is a waste of time. (sstatus ignoreeof g_val) RETURNS: g_val SIDE EFFECT: If g_val is non-null when an end of file (CNTL-D on UNIX) is typed to the standard top-level interpreter, it will be ignored rather then cause the lisp system to exit. If the the standard input is a file or pipe then this has no effect, an EOF will always cause lisp to exit. The initial value is nil. The Franz Lisp Manual PS2:9-115 (sstatus nofeature g_val) RETURNS: g_val SIDE EFFECT: g_val is removed from the status features list if it was present. (sstatus translink g_val) RETURNS: g_val SIDE EFFECT: If g_val is nil then all transfer tables are cleared and further calls through the transfer table will not cause the fast links to be set up. If g_val is the sym- bol _o_n then all possible transfer table entries will be linked and the flag will be set to cause fast links to be set up dynamically. Otherwise all that is done is to set the flag to cause fast links to be set up dynamically. The initial value is nil. NOTE: For a discussion of transfer tables, see 12.8. (sstatus uctolc g_val) RETURNS: g_val SIDE EFFECT: If g_val is not nil then all unescaped capital letters in symbols read by the reader will be converted to lower case. NOTE: This allows FRANZ LISP to be compatible with sin- gle case lisp systems (e.g. Maclisp, Interlisp and UCILisp). (status g_code) RETURNS: the value associated with the status code g_code if g_code is not one of the special cases given below 9 9 PS2:9-116 The Franz Lisp Manual (status ctime) RETURNS: a symbol whose print name is the current time and date. EXAMPLE: (_s_t_a_t_u_s _c_t_i_m_e) = |Sun Jun 29 16:51:26 1980| NOTE: This has been made obsolete by _t_i_m_e-_s_t_r_i_n_g, described below. (status feature g_val) RETURNS: t iff g_val is in the status features list. (status features) RETURNS: the value of the features code, which is a list of features which are present in this system. You add to this list with (_s_s_t_a_t_u_s _f_e_a_t_u_r_e '_g__v_a_l) and test if feature g_feat is present with (_s_t_a_t_u_s _f_e_a_t_u_r_e '_g__f_e_a_t). (status isatty) RETURNS: t iff the standard input is a terminal. (status localtime) RETURNS: a list of fixnums representing the current time. EXAMPLE: (_s_t_a_t_u_s _l_o_c_a_l_t_i_m_e) = (3 51 13 31 6 81 5 211 1) means 3_r_d second, 51_s_t minute, 13_t_h hour (1 p.m), 31_s_t day, month 6 (0 = January), year 81 (0 = 1900), day of the week 5 (0 = Sunday), 211_t_h day of the year and daylight savings time is in effect. (status syntax s_char) NOTE: This function should not be used. See the description of _g_e_t_s_y_n_t_a_x (in Chapter 7) for a replacement. 9 9 The Franz Lisp Manual PS2:9-117 (status undeffunc) RETURNS: a list of all functions which transfer table entries point to but which are not defined at this point. NOTE: Some of the undefined functions listed could be arrays which have yet to be created. (status version) RETURNS: a string which is the current lisp version name. EXAMPLE: (_s_t_a_t_u_s _v_e_r_s_i_o_n) = "Franz Lisp, Opus 38.61" (syscall 'x_index ['xst_arg1 ...]) RETURNS: the result of issuing the UNIX system call number x_index with arguments xst_arg_i. NOTE: The UNIX system calls are described in section 2 of the UNIX Programmer's manual. If xst_arg_i is a fixnum, then its value is passed as an argument, if it is a symbol then its pname is passed and finally if it is a string then the string itself is passed as an argument. Some useful syscalls are: (_s_y_s_c_a_l_l _2_0) returns process id. (_s_y_s_c_a_l_l _1_3) returns the number of seconds since Jan 1, 1970. (_s_y_s_c_a_l_l _1_0 '_f_o_o) will unlink (delete) the file foo. (sys:access 'st_filename 'x_mode) (sys:chmod 'st_filename 'x_mode) (sys:gethostname) (sys:getpid) (sys:getpwnam 'st_username) (sys:link 'st_oldfilename 'st_newfilename) (sys:time) (sys:unlink 'st_filename) NOTE: We have been warned that the actual system call numbers may vary among different UNIX systems. Users concerned about portability may wish to use this group of functions. Another advantage is that tilde-expansion is performed on all filename arguments. These functions do what is described in the system call section of your UNIX manual. _s_y_s:_g_e_t_p_w_n_a_m returns a vector of four entries from the password file, being the user name, user PS2:9-118 The Franz Lisp Manual id, group id, and home directory. (time-string ['x_seconds]) RETURNS: an ascii string giving the time and date which was x_seconds after UNIX's idea of creation (Midnight, Jan 1, 1970 GMT). If no argument is given, time-string returns the current date. This supplants (_s_t_a_t_u_s _c_t_i_m_e), and may be used to make the results of _f_i_l_e_s_t_a_t more intelligible. (top-level) RETURNS: nothing (it never returns) NOTE: This function is the top-level read-eval-print loop. It never returns any value. Its main utility is that if you redefine it, and do a (reset) then the redefined (top-level) is then invoked. The default top-level for Franz, allow one to specify his own printer or reader, by binding the symbols top-level-printer and top- level-reader. One can let the default top-level do most of the drudgery in catching _r_e_s_e_t's, and reading in .lisprc files, by binding the symbol user-top-level, to a routine that concerns itself only with the read-eval-print loop. (wait) RETURNS: a dotted pair (_p_r_o_c_e_s_s_i_d . _s_t_a_t_u_s) when the next child process dies. 9 9 CHAPTER 7 The Lisp Reader _7._1. _I_n_t_r_o_d_u_c_t_i_o_n The _r_e_a_d function is responsible for converting a stream of characters into a Lisp expression. _R_e_a_d is table driven and the table it uses is called a _r_e_a_d_t_- _a_b_l_e. The _p_r_i_n_t function does the inverse of _r_e_a_d; it converts a Lisp expression into a stream of charac- ters. Typically the conversion is done in such a way that if that stream of characters were read by _r_e_a_d, the result would be an expression equal to the one _p_r_i_n_t was given. _P_r_i_n_t must also refer to the readt- able in order to determine how to format its output. The _e_x_p_l_o_d_e function, which returns a list of charac- ters rather than printing them, must also refer to the readtable. A readtable is created with the _m_a_k_e_r_e_a_d_t_a_b_l_e function, modified with the _s_e_t_s_y_n_t_a_x function and interrogated with the _g_e_t_s_y_n_t_a_x function. The struc- ture of a readtable is hidden from the user - a readtable should only be manipulated with the three functions mentioned above. There is one distinguished readtable called the _c_u_r_r_e_n_t _r_e_a_d_t_a_b_l_e whose value determines what _r_e_a_d, _p_r_i_n_t and _e_x_p_l_o_d_e do. The current readtable is the value of the symbol _r_e_a_d_t_a_b_l_e. Thus it is possible to rapidly change the current syntax by lambda binding a different readtable to the symbol _r_e_a_d_t_a_b_l_e. When the binding is undone, the syntax reverts to its old form. _7._2. _S_y_n_t_a_x _C_l_a_s_s_e_s The readtable describes how each of the 128 ascii characters should be treated by the reader and printer. Each character belongs to a _s_y_n_t_a_x _c_l_a_s_s which has three properties: character class - Tells what the reader should do when it sees this The Franz Lisp Manual PS2:9-119 PS2:9-120 The Franz Lisp Manual character. There are a large number of character classes. They are described below. separator - Most types of tokens the reader constructs are one character long. Four token types have an arbitrary length: number (1234), symbol print name (franz), escaped symbol print name (|franz|), and string ("franz"). The reader can easily determine when it has come to the end of one of the last two types: it just looks for the matching delimiter (| or "). When the reader is reading a number or symbol print name, it stops reading when it comes to a character with the _s_e_p_a_r_a_t_o_r property. The separator character is pushed back into the input stream and will be the first character read when the reader is called again. escape - Tells the printer when to put escapes in front of, or around, a symbol whose print name contains this character. There are three possibilities: always escape a symbol with this character in it, only escape a symbol if this is the only charac- ter in the symbol, and only escape a symbol if this is the first character in the symbol. [note: The printer will always escape a symbol which, if printed out, would look like a valid number.] When the Lisp system is built, Lisp code is added to a C-coded kernel and the result becomes the stan- dard lisp system. The readtable present in the C- coded kernel, called the _r_a_w _r_e_a_d_t_a_b_l_e, contains the bare necessities for reading in Lisp code. During the construction of the complete Lisp system, a copy is made of the raw readtable and then the copy is modi- fied by adding macro characters. The result is what is called the _s_t_a_n_d_a_r_d _r_e_a_d_t_a_b_l_e. When a new readt- able is created with _m_a_k_e_r_e_a_d_t_a_b_l_e, a copy is made of either the raw readtable or the current readtable (which is likely to be the standard readtable). _7._3. _R_e_a_d_e_r _O_p_e_r_a_t_i_o_n_s The reader has a very simple algorithm. It is either _s_c_a_n_n_i_n_g for a token, _c_o_l_l_e_c_t_i_n_g a token, or _p_r_o_c_e_s_s_i_n_g a token. Scanning involves reading charac- ters and throwing away those which don't start tokens (such as blanks and tabs). Collecting means gathering The Franz Lisp Manual PS2:9-121 the characters which make up a token into a buffer. Processing may involve creating symbols, strings, lists, fixnums, bignums or flonums or calling a user written function called a character macro. The components of the syntax class determine when the reader switches between the scanning, collecting and processing states. The reader will continue scan- ning as long as the character class of the characters it reads is _c_s_e_p_a_r_a_t_o_r. When it reads a character whose character class is not _c_s_e_p_a_r_a_t_o_r it stores that character in its buffer and begins the collecting phase. If the character class of that first character is _c_c_h_a_r_a_c_t_e_r, _c_n_u_m_b_e_r, _c_p_e_r_i_o_d, or _c_s_i_g_n. then it will continue collecting until it runs into a character whose syntax class has the _s_e_p_a_r_a_t_o_r property. (That last character will be pushed back into the input buffer and will be the first character read next time.) Now the reader goes into the processing phase, checking to see if the token it read is a number or symbol. It is important to note that after the first character is collected the component of the syntax class which tells the reader to stop collecting is the _s_e_p_a_r_a_t_o_r property, not the character class. If the character class of the character which stopped the scanning is not _c_c_h_a_r_a_c_t_e_r, _c_n_u_m_b_e_r, _c_p_e_r_i_o_d, or _c_s_i_g_n. then the reader processes that character immediately. The character classes _c_s_i_n_g_l_e-_m_a_c_r_o, _c_s_i_n_g_l_e-_s_p_l_i_c_i_n_g-_m_a_c_r_o, and _c_s_i_n_g_l_e- _i_n_f_i_x-_m_a_c_r_o will act like _c_c_h_a_r_a_c_t_e_r if the following token is not a _s_e_p_a_r_a_t_o_r. The processing which is done for a given character class is described in detail in the next section. _7._4. _C_h_a_r_a_c_t_e_r _C_l_a_s_s_e_s _c_c_h_a_r_a_c_t_e_r raw readtable:A-Z a-z ^H !#$%&*,/:;<=>?@^_`{}~ standard readtable:A-Z a-z ^H !$%&*/:;<=>?@^_{}~ A normal character. _c_n_u_m_b_e_r raw readtable:0-9 standard readtable:0-9 This type is a digit. The syntax for an integer (fix- num or bignum) is a string of _c_n_u_m_b_e_r characters optionally followed by a _c_p_e_r_i_o_d. If the digits are not followed by a _c_p_e_r_i_o_d, then they are interpreted PS2:9-122 The Franz Lisp Manual in base _i_b_a_s_e which must be eight or ten. The syntax for a floating point number is either zero or more _c_n_u_m_b_e_r's followed by a _c_p_e_r_i_o_d and then followed by one or more _c_n_u_m_b_e_r's. A floating point number may also be an integer or floating point number followed by 'e' or 'd', an optional '+' or '-' and then zero or more _c_n_u_m_b_e_r's. _c_s_i_g_n raw readtable:+- standard readtable:+- A leading sign for a number. No other characters should be given this class. _c_l_e_f_t_-_p_a_r_e_n raw readtable:( standard readtable:( A left parenthesis. Tells the reader to begin forming a list. _c_r_i_g_h_t_-_p_a_r_e_n raw readtable:) standard readtable:) A right parenthesis. Tells the reader that it has reached the end of a list. _c_l_e_f_t_-_b_r_a_c_k_e_t raw readtable:[ standard readtable:[ A left bracket. Tells the reader that it should begin forming a list. See the description of _c_r_i_g_h_t-_b_r_a_c_k_e_t for the difference between cleft-bracket and cleft- paren. _c_r_i_g_h_t_-_b_r_a_c_k_e_t raw readtable:] standard readtable:] A right bracket. A _c_r_i_g_h_t-_b_r_a_c_k_e_t finishes the forma- tion of the current list and all enclosing lists until it finds one which begins with a _c_l_e_f_t-_b_r_a_c_k_e_t or until it reaches the top level list. _c_p_e_r_i_o_d raw readtable:. standard readtable:. The period is used to separate element of a cons cell [e.g. (a . (b . nil)) is the same as (a b)]. _c_p_e_r_i_o_d is also used in numbers as described above. _c_s_e_p_a_r_a_t_o_r raw readtable:^I-^M esc space standard readtable:^I-^M esc space Separates tokens. When the reader is scanning, these The Franz Lisp Manual PS2:9-123 character are passed over. Note: there is a differ- ence between the _c_s_e_p_a_r_a_t_o_r character class and the _s_e_p_a_r_a_t_o_r property of a syntax class. _c_s_i_n_g_l_e_-_q_u_o_t_e raw readtable:' standard readtable:' This causes _r_e_a_d to be called recursively and the list (quote ) to be returned. _c_s_y_m_b_o_l_-_d_e_l_i_m_i_t_e_r raw readtable:| standard readtable:| This causes the reader to begin collecting characters and to stop only when another identical _c_s_y_m_b_o_l- _d_e_l_i_m_i_t_e_r is seen. The only way to escape a _c_s_y_m_b_o_l- _d_e_l_i_m_i_t_e_r within a symbol name is with a _c_e_s_c_a_p_e char- acter. The collected characters are converted into a string which becomes the print name of a symbol. If a symbol with an identical print name already exists, then the allocation is not done, rather the existing symbol is used. _c_e_s_c_a_p_e raw readtable:\ standard readtable:\ This causes the next character to read in to be treated as a _v_c_h_a_r_a_c_t_e_r. A character whose syntax class is _v_c_h_a_r_a_c_t_e_r has a character class _c_c_h_a_r_a_c_t_e_r and does not have the _s_e_p_a_r_a_t_o_r property so it will not separate symbols. _c_s_t_r_i_n_g_-_d_e_l_i_m_i_t_e_r raw readtable:" standard readtable:" This is the same as _c_s_y_m_b_o_l-_d_e_l_i_m_i_t_e_r except the result is returned as a string instead of a symbol. _c_s_i_n_g_l_e_-_c_h_a_r_a_c_t_e_r_-_s_y_m_b_o_l raw readtable:none standard readtable:none This returns a symbol whose print name is the the sin- gle character which has been collected. _c_m_a_c_r_o raw readtable:none standard readtable:`, The reader calls the macro function associated with this character and the current readtable, passing it no arguments. The result of the macro is added to the structure the reader is building, just as if that form were directly read by the reader. More details on macros are provided below. PS2:9-124 The Franz Lisp Manual _c_s_p_l_i_c_i_n_g_-_m_a_c_r_o raw readtable:none standard readtable:#; A _c_s_p_l_i_c_i_n_g-_m_a_c_r_o differs from a _c_m_a_c_r_o in the way the result is incorporated in the structure the reader is building. A _c_s_p_l_i_c_i_n_g-_m_a_c_r_o must return a list of forms (possibly empty). The reader acts as if it read each element of the list itself without the surround- ing parenthesis. _c_s_i_n_g_l_e_-_m_a_c_r_o raw readtable:none standard readtable:none This causes to reader to check the next character. If it is a _c_s_e_p_a_r_a_t_o_r then this acts like a _c_m_a_c_r_o. Oth- erwise, it acts like a _c_c_h_a_r_a_c_t_e_r. _c_s_i_n_g_l_e_-_s_p_l_i_c_i_n_g_-_m_a_c_r_o raw readtable:none standard readtable:none This is triggered like a _c_s_i_n_g_l_e-_m_a_c_r_o however the result is spliced in like a _c_s_p_l_i_c_i_n_g-_m_a_c_r_o. _c_i_n_f_i_x_-_m_a_c_r_o raw readtable:none standard readtable:none This is differs from a _c_m_a_c_r_o in that the macro func- tion is passed a form representing what the reader has read so far. The result of the macro replaces what the reader had read so far. _c_s_i_n_g_l_e_-_i_n_f_i_x_-_m_a_c_r_o raw readtable:none standard readtable:none This differs from the _c_i_n_f_i_x-_m_a_c_r_o in that the macro will only be triggered if the character following the _c_s_i_n_g_l_e-_i_n_f_i_x-_m_a_c_r_o character is a _c_s_e_p_a_r_a_t_o_r. _c_i_l_l_e_g_a_l raw readtable:^@-^G^N-^Z^\-^_rubout standard readtable:^@-^G^N-^Z^\-^_rubout The characters cause the reader to signal an error if read. _7._5. _S_y_n_t_a_x _C_l_a_s_s_e_s The readtable maps each character into a syntax class. The syntax class contains three pieces of information: the character class, whether this is a separator, and the escape properties. The first two properties are used by the reader, the last by the printer (and _e_x_p_l_o_d_e). The initial lisp system has The Franz Lisp Manual PS2:9-125 the following syntax classes defined. The user may add syntax classes with _a_d_d-_s_y_n_t_a_x-_c_l_a_s_s. For each syntax class, we list the properties of the class and which characters have this syntax class by default. More information about each syntax class can be found under the description of the syntax class's character class. vcharacter raw readtable:A-Z a-z ^H !#$%&*,/:;<=>?@^_`{}~ _c_c_h_a_r_a_c_t_e_r standard readtable:A-Z a-z ^H !$%&*/:;<=>?@^_{}~ vnumber raw readtable:0-9 _c_n_u_m_b_e_r standard readtable:0-9 vsign raw readtable:+- _c_s_i_g_n standard readtable:+- vleft-paren raw readtable:( _c_l_e_f_t-_p_a_r_e_n standard readtable:( _e_s_c_a_p_e-_a_l_w_a_y_s vright-paren raw readtable:) _c_r_i_g_h_t-_p_a_r_e_n standard readtable:) _e_s_c_a_p_e-_a_l_w_a_y_s vleft-bracket raw readtable:[ _c_l_e_f_t-_b_r_a_c_k_e_t standard readtable:[ _e_s_c_a_p_e-_a_l_w_a_y_s vright-bracket raw readtable:] _c_r_i_g_h_t-_b_r_a_c_k_e_t standard readtable:] _e_s_c_a_p_e-_a_l_w_a_y_s 9 9 PS2:9-126 The Franz Lisp Manual vperiod raw readtable:. _c_p_e_r_i_o_d standard readtable:. _e_s_c_a_p_e-_w_h_e_n-_u_n_i_q_u_e vseparator raw readtable:^I-^M esc space _c_s_e_p_a_r_a_t_o_r standard readtable:^I-^M esc space _e_s_c_a_p_e-_a_l_w_a_y_s vsingle-quote raw readtable:' _c_s_i_n_g_l_e-_q_u_o_t_e standard readtable:' _e_s_c_a_p_e-_a_l_w_a_y_s vsymbol-delimiter raw readtable:| _c_s_i_n_g_l_e-_d_e_l_i_m_i_t_e_r standard readtable:| _e_s_c_a_p_e-_a_l_w_a_y_s vescape raw readtable:\ _c_e_s_c_a_p_e standard readtable:\ _e_s_c_a_p_e-_a_l_w_a_y_s vstring-delimiter raw readtable:" _c_s_t_r_i_n_g-_d_e_l_i_m_i_t_e_r standard readtable:" _e_s_c_a_p_e-_a_l_w_a_y_s vsingle-character-symbol raw readtable:none _c_s_i_n_g_l_e-_c_h_a_r_a_c_t_e_r-_s_y_m_b_o_l standard readtable:none _s_e_p_a_r_a_t_o_r vmacro raw readtable:none _c_m_a_c_r_o standard readtable:`, _e_s_c_a_p_e-_a_l_w_a_y_s vsplicing-macro raw readtable:none _c_s_p_l_i_c_i_n_g-_m_a_c_r_o standard readtable:#; _e_s_c_a_p_e-_a_l_w_a_y_s 9 9 The Franz Lisp Manual PS2:9-127 vsingle-macro raw readtable:none _c_s_i_n_g_l_e-_m_a_c_r_o standard readtable:none _e_s_c_a_p_e-_w_h_e_n-_u_n_i_q_u_e vsingle-splicing-macro raw readtable:none _c_s_i_n_g_l_e-_s_p_l_i_c_i_n_g-_m_a_c_r_o standard readtable:none _e_s_c_a_p_e-_w_h_e_n-_u_n_i_q_u_e vinfix-macro raw readtable:none _c_i_n_f_i_x-_m_a_c_r_o standard readtable:none _e_s_c_a_p_e-_a_l_w_a_y_s vsingle-infix-macro raw readtable:none _c_s_i_n_g_l_e-_i_n_f_i_x-_m_a_c_r_o standard readtable:none _e_s_c_a_p_e-_w_h_e_n-_u_n_i_q_u_e villegal raw readtable:^@-^G^N-^Z^\-^_rubout _c_i_l_l_e_g_a_l standard readtable:^@-^G^N-^Z^\-^_rubout _e_s_c_a_p_e-_a_l_w_a_y_s _7._6. _C_h_a_r_a_c_t_e_r _M_a_c_r_o_s Character macros are user written functions which are executed during the reading process. The value returned by a character macro may or may not be used by the reader, depending on the type of macro and the value returned. Character macros are always attached to a single character with the _s_e_t_s_y_n_t_a_x function. _7._6._1. _T_y_p_e_s There are three types of character macros: normal, splicing and infix. These types differ in the arguments they are given or in what is done with the result they return. _7._6._1._1. _N_o_r_m_a_l A normal macro is passed no arguments. The value returned by a normal macro is simply used PS2:9-128 The Franz Lisp Manual by the reader as if it had read the value itself. Here is an example of a macro which returns the abbreviation for a given state. ____________________________________________________ ->(_d_e_f_u_n _s_t_a_t_e_a_b_b_r_e_v _n_i_l (_c_d_r (_a_s_s_q (_r_e_a_d) '((_c_a_l_i_f_o_r_n_i_a . _c_a) (_p_e_n_n_s_y_l_v_a_n_i_a . _p_a))))) stateabbrev -> (_s_e_t_s_y_n_t_a_x '_\! '_v_m_a_c_r_o '_s_t_a_t_e_a_b_b_r_e_v) t -> '( ! _c_a_l_i_f_o_r_n_i_a ! _w_y_o_m_i_n_g ! _p_e_n_n_s_y_l_v_a_n_i_a) (ca nil pa) ____________________________________________________ Notice what happened to ! _w_y_o_m_i_n_g. Since it wasn't in the table, the associated function returned nil. The creator of the macro may have wanted to leave the list alone, in such a case, but couldn't with this type of reader macro. The splicing macro, described next, allows a character macro function to return a value that is ignored. _7._6._1._2. _S_p_l_i_c_i_n_g The value returned from a splicing macro must be a list or nil. If the value is nil, then the value is ignored, otherwise the reader acts as if it read each object in the list. Usually the list only contains one element. If the reader is reading at the top level (i.e. not collecting elements of list), then it is illegal for a splicing macro to return more then one element in the list. The major advantage of a splicing macro over a normal macro is the abil- ity of the splicing macro to return nothing. The comment character (usually ;) is a splicing macro bound to a function which reads to the end of the line and always returns nil. Here is the previous example written as a splicing macro 9 9 The Franz Lisp Manual PS2:9-129 ____________________________________________________ -> (_d_e_f_u_n _s_t_a_t_e_a_b_b_r_e_v _n_i_l ((_l_a_m_b_d_a (_v_a_l_u_e) (_c_o_n_d (_v_a_l_u_e (_l_i_s_t _v_a_l_u_e)) (_t _n_i_l))) (_c_d_r (_a_s_s_q (_r_e_a_d) '((_c_a_l_i_f_o_r_n_i_a . _c_a) (_p_e_n_n_s_y_l_v_a_n_i_a . _p_a)))))) -> (_s_e_t_s_y_n_t_a_x '! '_v_s_p_l_i_c_i_n_g-_m_a_c_r_o '_s_t_a_t_e_a_b_b_r_e_v) -> '(!_p_e_n_n_s_y_l_v_a_n_i_a ! _f_o_o !_c_a_l_i_f_o_r_n_i_a) (pa ca) -> '!_f_o_o !_b_a_r !_p_e_n_n_s_y_l_v_a_n_i_a pa -> ____________________________________________________ _7._6._1._3. _I_n_f_i_x Infix macros are passed a _c_o_n_c structure representing what has been read so far. Briefly, a tconc structure is a single list cell whose car points to a list and whose cdr points to the last list cell in that list. The interpretation by the reader of the value returned by an infix macro depends on whether the macro is called while the reader is con- structing a list or whether it is called at the top level of the reader. If the macro is called while a list is being constructed, then the value returned should be a tconc structure. The car of that structure replaces the list of elements that the reader has been collecting. If the macro is called at top level, then it will be passed the value nil, and the value it returns should either be nil or a tconc struc- ture. If the macro returns nil, then the value is ignored and the reader continues to read. If the macro returns a tconc structure of one ele- ment (i.e. whose car is a list of one element), then that single element is returned as the value of _r_e_a_d. If the macro returns a tconc structure of more than one element, then that list of elements is returned as the value of read. 9 9 PS2:9-130 The Franz Lisp Manual ____________________________________________________ -> (_d_e_f_u_n _p_l_u_s_o_p (_x) (_c_o_n_d ((_n_u_l_l _x) (_t_c_o_n_c _n_i_l '_\+)) (_t (_l_c_o_n_c _n_i_l (_l_i_s_t '_p_l_u_s (_c_a_a_r _x) (_r_e_a_d)))))) plusop -> (_s_e_t_s_y_n_t_a_x '_\+ '_v_i_n_f_i_x-_m_a_c_r_o '_p_l_u_s_o_p) t -> '(_a + _b) (plus a b) -> '+ |+| -> ____________________________________________________ _7._6._2. _I_n_v_o_c_a_t_i_o_n_s There are three different circumstances in which you would like a macro function to be trig- gered. _A_l_w_a_y_s - Whenever the macro character is seen, the macro should be invoked. This is accomplished by using the character classes _c_m_a_c_r_o, _c_s_p_l_i_c_i_n_g-_m_a_c_r_o, or _c_i_n_f_i_x-_m_a_c_r_o, and by using the _s_e_p_a_r_a_t_o_r property. The syntax classes _v_m_a_c_r_o, _v_s_p_l_i_c_i_n_g-_m_a_c_r_o, and _v_s_i_n_g_l_e-_m_a_c_r_o are defined this way. _W_h_e_n _f_i_r_s_t - The macro should only be triggered when the macro character is the first character found after the scanning process. A syntax class for a _w_h_e_n _f_i_r_s_t macro would be defined using _c_m_a_c_r_o, _c_s_p_l_i_c_i_n_g-_m_a_c_r_o, or _c_i_n_f_i_x-_m_a_c_r_o and not including the _s_e_p_a_r_a_t_o_r property. _W_h_e_n _u_n_i_q_u_e - The macro should only be triggered when the macro character is the only character col- lected in the token collection phase of the reader, i.e the macro character is preceeded by zero or more _c_s_e_p_a_r_a_t_o_rs and followed by a _s_e_p_a_r_a_t_o_r. A syntax class for a _w_h_e_n _u_n_i_q_u_e macro would be defined using _c_s_i_n_g_l_e-_m_a_c_r_o, The Franz Lisp Manual PS2:9-131 _c_s_i_n_g_l_e-_s_p_l_i_c_i_n_g-_m_a_c_r_o, or _c_s_i_n_g_l_e-_i_n_f_i_x-_m_a_c_r_o and not including the _s_e_p_a_r_a_t_o_r property. The syntax classes so defined are _v_s_i_n_g_l_e-_m_a_c_r_o, _v_s_i_n_g_l_e-_s_p_l_i_c_i_n_g-_m_a_c_r_o, and _v_s_i_n_g_l_e-_i_n_f_i_x- _m_a_c_r_o. _7._7. _F_u_n_c_t_i_o_n_s (setsyntax 's_symbol 's_synclass ['ls_func]) WHERE: ls_func is the name of a function or a lambda body. RETURNS: t SIDE EFFECT: S_symbol should be a symbol whose print name is only one character. The syntax class for that character is set to s_synclass in the current readtable. If s_synclass is a class that requires a character macro, then ls_func must be sup- plied. NOTE: The symbolic syntax codes are new to Opus 38. For compatibility, s_synclass can be one of the fixnum syntax codes which appeared in older ver- sions of the FRANZ LISP Manual. This compatibil- ity is only temporary: existing code which uses the fixnum syntax codes should be converted. (getsyntax 's_symbol) RETURNS: the syntax class of the first character of s_symbol's print name. s_symbol's print name must be exactly one character long. NOTE: This function is new to Opus 38. It supercedes (_s_t_a_t_u_s _s_y_n_t_a_x) which no longer exists. (add-syntax-class 's_synclass 'l_properties) RETURNS: s_synclass SIDE EFFECT: Defines the syntax class s_synclass to have properties l_properties. The list l_properties should contain a character classes mentioned above. l_properties may contain one of the escape properties: _e_s_c_a_p_e-_a_l_w_a_y_s, _e_s_c_a_p_e-_w_h_e_n-_u_n_i_q_u_e, or _e_s_c_a_p_e-_w_h_e_n-_f_i_r_s_t. l_properties may con- tain the _s_e_p_a_r_a_t_o_r property. After a PS2:9-132 The Franz Lisp Manual syntax class has been defined with _a_d_d- _s_y_n_t_a_x-_c_l_a_s_s, the _s_e_t_s_y_n_t_a_x function can be used to give characters that syntax class. ____________________________________________________ ; Define a non-separating macro character. ; This type of macro character is used in UCI-Lisp, and ; it corresponds to a FIRST MACRO in Interlisp -> (_a_d_d-_s_y_n_t_a_x-_c_l_a_s_s '_v_u_c_i-_m_a_c_r_o '(_c_m_a_c_r_o _e_s_c_a_p_e-_w_h_e_n-_f_i_r_s_t)) vuci-macro -> ____________________________________________________ 9 9 CHAPTER 8 Functions, Fclosures, and Macros _8._1. _v_a_l_i_d _f_u_n_c_t_i_o_n _o_b_j_e_c_t_s 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. _f_u_n_c_t_i_o_n_s 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 The Franz Lisp Manual PS2:9-133 PS2:9-134 The Franz Lisp Manual 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____________________ 9 [|-]Only the first character of the string is significant (i.e "s" is ok for "subroutine") The Franz Lisp Manual PS2:9-135 declared _s_p_e_c_i_a_l (see 12.3.2.2). 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. _m_a_c_r_o_s 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. _m_a_c_r_o _f_o_r_m_s 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. PS2:9-136 The Franz Lisp Manual Notice that the macro has one formal parameter, _x. On the second input line, we ask the interpreter to 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. _d_e_f_m_a_c_r_o 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 The Franz Lisp Manual PS2:9-137 _8._3._3. _t_h_e _b_a_c_k_q_u_o_t_e _c_h_a_r_a_c_t_e_r _m_a_c_r_o 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 PS2:9-138 The Franz Lisp Manual _8._3._4. _s_h_a_r_p _s_i_g_n _c_h_a_r_a_c_t_e_r _m_a_c_r_o 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. _c_o_n_d_i_t_i_o_n_a_l _i_n_c_l_u_s_i_o_n 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 The Franz Lisp Manual PS2:9-139 _#_-_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. _f_i_x_n_u_m _c_h_a_r_a_c_t_e_r _e_q_u_i_v_a_l_e_n_t_s 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. _r_e_a_d _t_i_m_e _e_v_a_l_u_a_t_i_o_n 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 PS2:9-140 The Franz Lisp Manual ____________________________________________________ ; 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. _f_c_l_o_s_u_r_e_s 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. _a_n _e_x_a_m_p_l_e ____________________________________________________________ % 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)) The Franz Lisp Manual PS2:9-141 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) PS2:9-142 The Franz Lisp Manual (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. _u_s_e_f_u_l _f_u_n_c_t_i_o_n_s 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. _i_n_t_e_r_n_a_l _s_t_r_u_c_t_u_r_e 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 The Franz Lisp Manual PS2:9-143 active). _8._5. _f_o_r_e_i_g_n _s_u_b_r_o_u_t_i_n_e_s _a_n_d _f_u_n_c_t_i_o_n_s 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 PS2:9-144 The Franz Lisp Manual 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 9 The Franz Lisp Manual PS2:9-145 and receive large amounts of data from a foreign func- tion). If a binary object is an argument, the entry 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 _b_o_l_d, 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 PS2:9-146 The Franz Lisp Manual { struct listoffixnumscell *cdr; int *fixnum; }; 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 The Franz Lisp Manual PS2:9-147 writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]); writeln(' c (first):', c[0]^,' c (second):', c[1]^); 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 PS2:9-148 The Franz Lisp Manual -> (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17)) a: 385, b[0]: 1.234000, b[1]: 5.678000 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. ____________________________________________________________ 9 9 The Franz Lisp Manual PS2:9-149 % cat ch8auxf.f 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 CHAPTER 9 Arrays and Vectors Arrays and vectors are two means of expressing aggregate data objects in FRANZ LISP. Vectors may be thought of as sequences of data. They are intended as a vehicle for user-defined data types. This use of vectors is still experimental and subject to revision. As a simple data structure, they are similar to hunks and strings. Vectors are used to implement closures, and are useful to communicate with foreign functions. Both of these topics were discussed in Chapter 8. Later in this chapter, we describe the current imple- mentation of vectors, and will advise the user what is most likely to change. Arrays in FRANZ LISP provide a programmable data structure access mechanism. One possible use for FRANZ LISP arrays is to implement Maclisp style arrays which are simple vectors of fixnums, flonums or gen- eral lisp values. This is described in more detail in 9.3 but first we will describe how array references are handled by the lisp system. The structure of an array object is given in 1.3.10 and reproduced here for your convenience. 8 _______________________________________________________________ Subpart name Get value Set value Type 8 ______________________________________________________________________________________________________________________________ access function getaccess putaccess binary, list or symbol 8 _______________________________________________________________ auxiliary getaux putaux lispval 8 _______________________________________________________________ data arrayref replace block of contiguous set lispval 8 _______________________________________________________________ length getlength putlength fixnum 8 _______________________________________________________________ delta getdelta putdelta fixnum 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|7|7|7|7|7| |7|7|7|7|7|7|7|7|7|7|7| 9PS2:9-150 The Franz Lisp Manual The Franz Lisp Manual PS2:9-151 _9._1. _g_e_n_e_r_a_l _a_r_r_a_y_s Suppose the evaluator is told to evaluate (_f_o_o _a _b) and the function cell of the symbol foo contains an array object (which we will call foo_arr_obj). First the evaluator will evaluate and stack the values of _a and _b. Next it will stack the array object foo_arr_obj. Finally it will call the access function of foo_arr_obj. The access function should be a lexpr[|-] or a symbol whose function cell contains a lexpr. The access function is responsible for locating and returning a value from the array. The array access function is free to interpret the arguments as it wishes. The Maclisp compatible array access function which is provided in the standard FRANZ LISP system interprets the arguments as sub- scripts in the same way as languages like Fortran and Pascal. The array access function will also be called upon to store elements in the array. For example, (_s_t_o_r_e (_f_o_o _a _b) _c) will automatically expand to (foo c a b) and when the evaluator is called to evaluate this, it will evaluate the arguments _c, _b and _a. Then it will stack the array object (which is stored in the function cell of foo) and call the array access func- tion with (now) four arguments. The array access function must be able to tell this is a store opera- tion, which it can do by checking the number of argu- ments it has been given (a lexpr can do this very easily). _9._2. _s_u_b_p_a_r_t_s _o_f _a_n _a_r_r_a_y _o_b_j_e_c_t An array is created by allocating an array object with _m_a_r_r_a_y and filling in the fields. Certain lisp functions interpret the values of the subparts of the array object in special ways as described in the following text. Placing illegal values in these subparts may cause the lisp system to fail. _9._2._1. _a_c_c_e_s_s _f_u_n_c_t_i_o_n The purpose of the access function has been described above. The contents of the access function should be a lexpr, either a binary (compiled function) or a list (interpreted function). It may also be a symbol whose function ____________________ 9 [|-]A lexpr is a function which accepts any number of ar- guments which are evaluated before the function is called. 9 PS2:9-152 The Franz Lisp Manual cell contains a function definition. This subpart is used by _e_v_a_l, _f_u_n_c_a_l_l, and _a_p_p_l_y when evaluating array references. _9._2._2. _a_u_x_i_l_i_a_r_y This can be used for any purpose. If it is a list and the first element of that list is the symbol unmarked_array then the data subpart will not be marked by the garbage collector (this is used in the Maclisp compatible array package and has the potential for causing strange errors if used incorrectly). _9._2._3. _d_a_t_a This is either nil or points to a block of data space allocated by _s_e_g_m_e_n_t or _s_m_a_l_l- _s_e_g_m_e_n_t. _9._2._4. _l_e_n_g_t_h This is a fixnum whose value is the number of elements in the data block. This is used by the garbage collector and by _a_r_r_a_y_r_e_f to deter- mine if your index is in bounds. _9._2._5. _d_e_l_t_a This is a fixnum whose value is the number of bytes in each element of the data block. This will be four for an array of fixnums or value cells, and eight for an array of flonums. This is used by the garbage collector and _a_r_r_a_y_r_e_f as well. _9._3. _T_h_e _M_a_c_l_i_s_p _c_o_m_p_a_t_i_b_l_e _a_r_r_a_y _p_a_c_k_a_g_e A Maclisp style array is similar to what is known as arrays in other languages: a block of homogeneous data elements which is indexed by one or more integers called subscripts. The data elements can be all fix- nums, flonums or general lisp objects. An array is created by a call to the function _a_r_r_a_y or *_a_r_r_a_y. The only difference is that *_a_r_r_a_y evaluates its argu- ments. This call: (_a_r_r_a_y _f_o_o _t _3 _5) sets up an array called foo of dimensions 3 by 5. The subscripts are zero based. The first element is (_f_o_o _0 _0), the next is (_f_o_o _0 _1) and so on up to (_f_o_o _2 _4). The t indi- cates a general lisp object array which means each element of foo can be any type. Each element can be any type since all that is stored in the array is a The Franz Lisp Manual PS2:9-153 pointer to a lisp object, not the object itself. _A_r_r_a_y does this by allocating an array object with _m_a_r_r_a_y and then allocating a segment of 15 consecutive value cells with _s_m_a_l_l-_s_e_g_m_e_n_t and storing a pointer to that segment in the data subpart of the array object. The length and delta subpart of the array object are filled in (with 15 and 4 respectively) and the access function subpart is set to point to the appropriate array access function. In this case there is a special access function for two dimensional value cell arrays called arrac-twoD, and this access function is used. The auxiliary subpart is set to (t 3 5) which describes the type of array and the bounds of the subscripts. Finally this array object is placed in the function cell of the symbol foo. Now when (_f_o_o _1 _3) is evaluated, the array access function is invoked with three arguments: 1, 3 and the array object. From the auxiliary field of the array object it gets a description of the particular array. It then determines which element (_f_o_o _1 _3) refers to and uses arrayref to extract that element. Since this is an array of value cells, what arrayref returns is a value cell whose value is what we want, so we evaluate the value cell and return it as the value of (_f_o_o _1 _3). In Maclisp the call (_a_r_r_a_y _f_o_o _f_i_x_n_u_m _2_5) returns an array whose data object is a block of 25 memory words. When fixnums are stored in this array, the actual numbers are stored instead of pointers to the numbers as is done in general lisp object arrays. This is efficient under Maclisp but inefficient in FRANZ LISP since every time a value was referenced from an array it had to be copied and a pointer to the copy returned to prevent aliasing[|-]. Thus t, fixnum and flonum arrays are all implemented in the same manner. This should not affect the compatibility of Maclisp and FRANZ LISP. If there is an application where a block of fixnums or flonums is required, then the exact same effect of fixnum and flonum arrays in Maclisp can be achieved by using fixnum-block and flonum-block arrays. Such arrays are required if you ____________________ 9 [|-]Aliasing is when two variables are share the same storage location. For example if the copying mentioned weren't done then after (_s_e_t_q _x (_f_o_o _2)) was done, the value of x and (foo 2) would share the same location. Then should the value of (foo 2) change, x's value would change as well. This is considered dangerous and as a result pointers are never returned into the data space of arrays. 9 PS2:9-154 The Franz Lisp Manual want to pass a large number of arguments to a Fortran or C coded function and then get answers back. The Maclisp compatible array package is just one example of how a general array scheme can be imple- mented. Another type of array you could implement would be hashed arrays. The subscript could be any- thing, not just a number. The access function would hash the subscript and use the result to select an array element. With the generality of arrays also comes extra cost; if you just want a simple aggregate of (less than 128) general lisp objects you would be wise to look into using hunks. _9._4. _v_e_c_t_o_r_s Vectors were invented to fix two shortcommings with hunks. They can be longer than 128 elements. They also have a tag associated with them, which is intended to say, for example, "Think of me as an _B_l_o_b_i_t." Thus a vector is an arbitrary sized hunk with a property list. Continuing the example, the lisp kernel may not know how to print out or evaluate _b_l_o_b_i_t_s, but this is information which will be common to all _b_l_o_b_i_t_s. On the other hand, for each individual blobits there are particulars which are likely to change, (height, weight, eye-color). This is the part that would pre- viously have been stored in the individual entries in the hunk, and are stored in the data slots of the vec- tor. Once again we summarize the structure of a vec- tor in tabular form: 8 ________________________________________________ Subpart name Get value Set value Type 8 ________________________________________________________________________________________________ datum[_i] vref vset lispval 8 ________________________________________________ property vprop vsetprop lispval vputprop 8 ________________________________________________ size vsize - fixnum 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| Vectors are created specifying size and optional fill value using the function (_n_e_w-_v_e_c_t_o_r 'x_size ['g_fill ['g_prop]]), or by initial values: (_v_e_c_t_o_r ['g_val ...]). 9 The Franz Lisp Manual PS2:9-155 _9._5. _a_n_a_t_o_m_y _o_f _v_e_c_t_o_r_s There are some technical details about vectors, that the user should know: _9._5._1. _s_i_z_e The user is not free to alter this. It is noted when the vector is created, and is used by the garbage collector. The garbage collector will coallesce two free vectors, which are neighbors in the heap. Internally, this is kept as the number of bytes of data. Thus, a vector created by (_v_e_c_- _t_o_r 'foo), has a size of 4. _9._5._2. _p_r_o_p_e_r_t_y Currently, we expect the property to be either a symbol, or a list whose first entry is a symbol. The symbols fclosure and structure- value-argument are magic, and their effect is described in Chapter 8. If the property is a (non-null) symbol, the vector will be printed out as []. Another case is if the pro- perty is actually a (disembodied) property-list, which contains a value for the indicator print. The value is taken to be a Lisp function, which the printer will invoke with two arguments: the vector and the current output port. Otherwise, the vector will be printed as vector[]. We have vague (as yet unimplemented) ideas about similar mechan- isms for evaluation properties. Users are cau- tioned against putting anything other than nil in the property entry of a vector. _9._5._3. _i_n_t_e_r_n_a_l _o_r_d_e_r In memory, vectors start with a longword containing the size (which is immediate data within the vector). The next cell contains a pointer to the property. Any remaining cells (if any) are for data. Vectors are handled differently from any other object in FRANZ LISP, in that a pointer to a vector is pointer to the first data cell, i.e. a pointer to the _t_h_i_r_d longword of the structure. This was done for efficiency in com- piled code and for uniformity in referencing immediate-vectors (described below). The user should never return a pointer to any other part of a vector, as this may cause the garbage collector to follow an invalid pointer. 9 9 PS2:9-156 The Franz Lisp Manual _9._6. _i_m_m_e_d_i_a_t_e-_v_e_c_t_o_r_s Immediate-vectors are similar to vectors. They differ, in that binary data are stored in space directly within the vector. Thus the garbage collector will preserve the vector itself (if used), and will only traverse the property cell. The data may be referenced as longwords, shortwords, or even bytes. Shorts and bytes are returned sign- extended. The compiler open-codes such references, and will avoid boxing the resulting integer data, where possible. Thus, immediate vectors may be used for efficiently processing character data. They are also useful in storing results from functions written in other languages. 8 __________________________________________________ Subpart name Get value Set value Type 8 ____________________________________________________________________________________________________ datum[_i] vrefi-byte vseti-byte fixnum vrefi-word vseti-word fixnum vrefi-long vseti-long fixnum 8 __________________________________________________ property vprop vsetprop lispval vputprop 8 __________________________________________________ size vsize - fixnum vsize-byte fixnum vsize-word fixnum 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|7|7|7|7|7| |7|7|7|7|7|7|7|7|7|7|7| To create immediate vectors specifying size and fill data, you can use the functions _n_e_w-_v_e_c_t_o_r_i-_b_y_t_e, _n_e_w-_v_e_c_t_o_r_i-_w_o_r_d, or _n_e_w-_v_e_c_t_o_r_i-_l_o_n_g. You can also use the functions _v_e_c_t_o_r_i-_b_y_t_e, _v_e_c_t_o_r_i-_w_o_r_d, or _v_e_c_t_o_r_i-_l_o_n_g. All of these functions are described in chapter 2. 9 CHAPTER 10 Exception Handling _1_0._1. _E_r_r_s_e_t _a_n_d _E_r_r_o_r _H_a_n_d_l_e_r _F_u_n_c_t_i_o_n_s FRANZ LISP allows the user to handle in a number of ways the errors which arise during computation. One way is through the use of the _e_r_r_s_e_t function. If an error occurs during the evaluation of the _e_r_r_s_e_t's first argument, then the locus of control will return to the errset which will return nil (except in special cases, such as _e_r_r). The other method of error han- dling is through an error handler function. When an error occurs, the error handler is called and is given as an argument a description of the error which just occurred. The error handler may take one of the fol- lowing actions: (1) it could take some drastic action like a _r_e_s_e_t or a _t_h_r_o_w. (2) it could, assuming that the error is continu- able, return to the function which noticed the error. The error handler indicates that it wants to return a value from the error by returning a list whose _c_a_r is the value it wants to return. (3) it could decide not to handle the error and return a non-list to indicate this fact. _1_0._2. _T_h_e _A_n_a_t_o_m_y _o_f _a_n _e_r_r_o_r Each error is described by a list of these items: (1) error type - This is a symbol which indicates the general classification of the error. This classification may determine which function handles this error. (2) unique id - This is a fixnum unique to this error. 9 9The Franz Lisp Manual PS2:9-157 PS2:9-158 The Franz Lisp Manual (3) continuable - If this is non-nil then this error is continuable. There are some who feel that every error should be continuable and the reason that some (in fact most) errors in FRANZ LISP are not continuable is due to the laziness of the programmers. (4) message string - This is a symbol whose print name is a message describing the error. (5) data - There may be from zero to three lisp values which help describe this particular error. For example, the unbound variable error contains one datum value, the symbol whose value is unbound. The list describing that error might look like: (ER%misc 0 t |Unbound Variable:| foobar) _1_0._3. _E_r_r_o_r _h_a_n_d_l_i_n_g _a_l_g_o_r_i_t_h_m This is the sequence of operations which is done when an error occurs: (1) If the symbol _E_R%_a_l_l has a non nil value then this value is the name of an error handler function. That function is called with a description of the error. If that function returns (and of course it may choose not to) and the value is a list and this error is con- tinuable, then we return the _c_a_r of the list to the function which called the error. Presum- ably the function will use this value to retry the operation. On the other hand, if the error handler returns a non list, then it has chosen not to handle this error, so we go on to step (2). Something special happens before we call the _E_R%_a_l_l error handler which does not happen in any of the other cases we will describe below. To help insure that we don't get infin- itely recursive errors if _E_R%_a_l_l is set to a bad value, the value of _E_R%_a_l_l is set to nil before the handler is called. Thus it is the responsibility of the _E_R%_a_l_l handler to `reen- able' itself by storing its name in _E_R%_a_l_l. (2) Next the specific error handler for the type of error which just occurred is called (if one exists) to see if it wants to handle the error. The names of the handlers for the specific types of errors are stored as the values of the symbols whose names are the types. For example The Franz Lisp Manual PS2:9-159 the handler for miscellaneous errors is stored as the value of _E_R%_m_i_s_c. Of course, if _E_R%_m_i_s_c has a value of nil, then there is no error handler for this type of error. Appendix B contains list of all error types. The process of classifying the errors is not complete and thus most errors are lumped into the ER%misc category. Just as in step (1), the error handler function may choose not to handle the error by returning a non-list, and then we go to step (3). (3) Next a check is made to see if there is an _e_r_r_s_e_t surrounding this error. If so the second argument to the _e_r_r_s_e_t call is examined. If the second argument was not given or is non nil then the error message associated with this error is printed. Finally the stack is popped to the context of the _e_r_r_s_e_t and then the _e_r_r_s_e_t returns nil. If there was no _e_r_r_s_e_t we go to step (4). (4) If the symbol _E_R%_t_p_l has a value then it is the name of an error handler which is called in a manner similar to that discussed above. If it chooses not to handle the error, we go to step (5). (5) At this point it has been determined that the user doesn't want to handle this error. Thus the error message is printed out and a _r_e_s_e_t is done to send the flow of control to the top- level. To summarize the error handling system: When an error occurs, you have two chances to handle it before the search for an _e_r_r_s_e_t is done. Then, if there is no _e_r_r_s_e_t, you have one more chance to handle the error before control jumps to the top level. Every error handler works in the same way: It is given a description of the error (as described in the previous section). It may or may not return. If it returns, then it returns either a list or a non-list. If it returns a list and the error is continuable, then the _c_a_r of the list is returned to the function which noticed the error. Otherwise the error handler has decided not to handle the error and we go on to some- thing else. 9 9 PS2:9-160 The Franz Lisp Manual _1_0._4. _D_e_f_a_u_l_t _a_i_d_s There are two standard error handlers which will probably handle the needs of most users. One of these is the lisp coded function _b_r_e_a_k-_e_r_r-_h_a_n_d_l_e_r which is the default value of _E_R%_t_p_l. Thus when all other handlers have ignored an error, _b_r_e_a_k-_e_r_r-_h_a_n_d_l_e_r will take over. It will print out the error message and go into a read-eval-print loop. The other standard error handler is _d_e_b_u_g-_e_r_r-_h_a_n_d_l_e_r. This handler is designed to be connected to _E_R%_a_l_land is useful if your program uses _e_r_r_s_e_t and you want to look at the error before it is thrown up to the _e_r_r_s_e_t. _1_0._5. _A_u_t_o_l_o_a_d_i_n_g When _e_v_a_l, _a_p_p_l_y or _f_u_n_c_a_l_l are told to call an undefined function, an ER%undef error is signaled. The default handler for this error is _u_n_d_e_f-_f_u_n_c- _h_a_n_d_l_e_r. This function checks the property list of the undefined function for the indicator autoload. If present, the value of that indicator should be the name of the file which contains the definition of the undefined function. _U_n_d_e_f-_f_u_n_c-_h_a_n_d_l_e_r will load the file and check if it has defined the function which caused the error. If it has, the error handler will return and the computation will continue as if the error did not occur. This provides a way for the user to tell the lisp system about the location of commonly used functions. The trace package sets up an autoload property to point to /usr/lib/lisp/trace. _1_0._6. _I_n_t_e_r_r_u_p_t _p_r_o_c_e_s_s_i_n_g The UNIX operating system provides one user interrupt character which defaults to ^C.[|-] The user may select a lisp function to run when an interrupt occurs. Since this interrupt could occur at any time, and in particular could occur at a time when the internal stack pointers were in an inconsistent state, the processing of the interrupt may be delayed until a safe time. When the first ^C is typed, the lisp sys- tem sets a flag that an interrupt has been requested. ____________________ 9 [|-]Actually there are two but the lisp system does not allow you to catch the QUIT interrupt. 9 The Franz Lisp Manual PS2:9-161 This flag is checked at safe places within the inter- preter and in the _q_l_i_n_k_e_r function. If the lisp sys- tem doesn't respond to the first ^C, another ^C should be typed. This will cause all of the transfer tables to be cleared forcing all calls from compiled code to go through the _q_l_i_n_k_e_r function where the interrupt flag will be checked. If the lisp system still doesn't respond, a third ^C will cause an immediate interrupt. This interrupt will not necessarily be in a safe place so the user should _r_e_s_e_t the lisp system as soon as possible. 9 9 CHAPTER 11 The Joseph Lister Trace Package The Joseph Lister[|-] Trace package is an impor- tant tool for the interactive debugging of a Lisp pro- gram. It allows you to examine selected calls to a function or functions, and optionally to stop execu- tion of the Lisp program to examine the values of variables. The trace package is a set of Lisp programs located in the Lisp program library (usually in the file /usr/lib/lisp/trace.l). Although not normally loaded in the Lisp system, the package will be loaded in when the first call to _t_r_a_c_e is made. (trace [ls_arg1 ...]) WHERE: the form of the ls_arg_i is described below. RETURNS: a list of the function sucessfully modified for tracing. If no arguments are given to _t_r_a_c_e, a list of all functions currently being traced is returned. SIDE EFFECT: The function definitions of the functions to trace are modified. The ls_arg_i can have one of the following forms: foo - when foo is entered and exited, the trace informa- tion will be printed. (foo break) - when foo is entered and exited the trace information will be printed. Also, just after the trace information for foo is printed upon entry, you will be put in a special break loop. The prompt is `T>' and you may type any Lisp expression, and see its value printed. The _ith argument to the function ____________________ 9 [|-]_L_i_s_t_e_r, _J_o_s_e_p_h 1st Baron Lister of Lyme Regis, 1827-1912; English surgeon: introduced antiseptic surgery. 9PS2:9-162 The Franz Lisp Manual The Franz Lisp Manual PS2:9-163 just called can be accessed as (arg _i). To leave the trace loop, just type ^D or (tracereturn) and execu- tion will continue. Note that ^D will work only on UNIX systems. (foo if expression) - when foo is entered and the expres- sion evaluates to non-nil, then the trace information will be printed for both exit and entry. If expres- sion evaluates to nil, then no trace information will be printed. (foo ifnot expression) - when foo is entered and the expression evaluates to nil, then the trace informa- tion will be printed for both entry and exit. If both if and _i_f_n_o_t are specified, then the _i_f expres- sion must evaluate to non nil AND the _i_f_n_o_t expres- sion must evaluate to nil for the trace information to be printed out. (foo evalin expression) - when foo is entered and after the entry trace information is printed, expression will be evaluated. Exit trace information will be printed when foo exits. (foo evalout expression) - when foo is entered, entry trace information will be printed. When foo exits, and before the exit trace information is printed, expression will be evaluated. (foo evalinout expression) - this has the same effect as (trace (foo evalin expression evalout expression)). (foo lprint) - this tells _t_r_a_c_e to use the level printer when printing the arguments to and the result of a call to foo. The level printer prints only the top levels of list structure. Any structure below three levels is printed as a &. This allows you to trace functions with massive arguments or results. The following trace options permit one to have greater control over each action which takes place when a function is traced. These options are only meant to be used by people who need special hooks into the trace package. Most people should skip reading this section. 9 9 PS2:9-164 The Franz Lisp Manual (foo traceenter tefunc) - this tells _t_r_a_c_e that the func- tion to be called when foo is entered is tefunc. tefunc should be a lambda of two arguments, the first argument will be bound to the name of the function being traced, foo in this case. The second argument will be bound to the list of arguments to which foo should be applied. The function tefunc should print some sort of "entering foo" message. It should not apply foo to the arguments, however. That is done later on. (foo traceexit txfunc) - this tells _t_r_a_c_e that the func- tion to be called when foo is exited is txfunc. txfunc should be a lambda of two arguments, the first argument will be bound to the name of the function being traced, foo in this case. The second argument will be bound to the result of the call to foo. The function txfunc should print some sort of "exiting foo" message. (foo evfcn evfunc) - this tells _t_r_a_c_e that the form evfunc should be evaluated to get the value of foo applied to its arguments. This option is a bit different from the other special options since evfunc will usually be an expression, not just the name of a function, and that expression will be specific to the evalua- tion of function foo. The argument list to be applied will be available as T-arglist. (foo printargs prfunc) - this tells _t_r_a_c_e to used prfunc to print the arguments to be applied to the function foo. prfunc should be a lambda of one argument. You might want to use this option if you wanted a print function which could handle circular lists. This option will work only if you do not specify your own _t_r_a_c_e_e_n_t_e_r function. Specifying the option _l_p_r_i_n_t is just a simple way of changing the printargs function to the level printer. (foo printres prfunc) - this tells _t_r_a_c_e to use prfunc to print the result of evaluating foo. prfunc should be a lambda of one argument. This option will work only if you do not specify your own _t_r_a_c_e_e_x_i_t function. Specifying the option _l_p_r_i_n_t changes printres to the level printer. 9 9 The Franz Lisp Manual PS2:9-165 You may specify more than one option for each function traced. For example: (_t_r_a_c_e (_f_o_o _i_f (_e_q _3 (_a_r_g _1)) _b_r_e_a_k _l_p_r_i_n_t) (_b_a_r _e_v_a_l_i_n (_p_r_i_n_t _x_y_z_z_y))) This tells _t_r_a_c_e to trace two more functions, foo and bar. Should foo be called with the first argument _e_q to 3, then the entering foo message will be printed with the level printer. Next it will enter a trace break loop, allowing you to evaluate any lisp expres- sions. When you exit the trace break loop, foo will be applied to its arguments and the resulting value will be printed, again using the level printer. Bar is also traced, and each time bar is entered, an entering bar message will be printed and then the value of xyzzy will be printed. Next bar will be applied to its argu- ments and the result will be printed. If you tell _t_r_a_c_e to trace a function which is already traced, it will first _u_n_t_r_a_c_e it. Thus if you want to specify more than one trace option for a function, you must do it all at once. The following is _n_o_t equivalent to the preceding call to _t_r_a_c_e for foo: (_t_r_a_c_e (_f_o_o _i_f (_e_q _3 (_a_r_g _1))) (_f_o_o _b_r_e_a_k) (_f_o_o _l_p_r_i_n_t)) In this example, only the last option, lprint, will be in effect. If the symbol $tracemute is given a non nil value, printing of the function name and arguments on entry and exit will be surpressed. This is particularly use- ful if the function you are tracing fails after many calls to it. In this case you would tell _t_r_a_c_e to trace the function, set $tracemute to t, and begin the computation. When an error occurs you can use _t_r_a_- _c_e_d_u_m_p to print out the current trace frames. Generally the trace package has its own internal names for the the lisp functions it uses, so that you can feel free to trace system functions like _c_o_n_d and not worry about adverse interaction with the actions of the trace package. You can trace any type of function: lambda, nlambda, lexpr or macro whether compiled or interpreted and you can even trace array references (however you should not attempt to store in an array which has been traced). When tracing compiled code keep in mind that many function calls are translated directly to machine language or other equivalent function calls. A full list of open coded functions is listed at the beginning PS2:9-166 The Franz Lisp Manual of the liszt compiler source. _T_r_a_c_e will do a (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l) to insure that the new traced definitions it defines are called instead of the old untraced ones. You may notice that compiled code will run slower after this is done. (traceargs s_func [x_level]) WHERE: if x_level is missing it is assumed to be 1. RETURNS: the arguments to the x_level_t_h call to traced function s_func are returned. (tracedump) SIDE EFFECT: the currently active trace frames are printed on the terminal. returns a list of functions untraced. (untrace [s_arg1 ...]) RETURNS: a list of the functions which were untraced. NOTE: if no arguments are given, all functions are untraced. SIDE EFFECT: the old function definitions of all traced functions are restored except in the case where it appears that the current defini- tion of a function was not created by trace. 9 9 CHAPTER 12 Liszt - the lisp compiler _1_2._1. _G_e_n_e_r_a_l _s_t_r_a_t_e_g_y _o_f _t_h_e _c_o_m_p_i_l_e_r The purpose of the lisp compiler, Liszt, is to create an object module which when brought into the lisp system using _f_a_s_l will have the same effect as bringing in the corresponding lisp coded source module with _l_o_a_d with one important exception, functions will be defined as sequences of machine language instruc- tions, instead of lisp S-expressions. Liszt is not a function compiler, it is a _f_i_l_e compiler. Such a file can contain more than function definitions; it can contain other lisp S-expressions which are evaluated at load time. These other S-expressions will also be stored in the object module produced by Liszt and will be evaluated at fasl time. As is almost universally true of Lisp compilers, the main pass of Liszt is written in Lisp. A subse- quent pass is the assembler, for which we use the standard UNIX assembler. _1_2._2. _R_u_n_n_i_n_g _t_h_e _c_o_m_p_i_l_e_r The compiler is normally run in this manner: % liszt foo will compile the file foo.l or foo (the preferred way to indicate a lisp source file is to end the file name with `.l'). The result of the compilation will be placed in the file foo.o if no fatal errors were detected. All messages which Liszt generates go to the standard output. Normally each function name is printed before it is compiled (the -q option suppresses this). _1_2._3. _S_p_e_c_i_a_l _f_o_r_m_s Liszt makes one pass over the source file. It processes each form in this way: 9 9The Franz Lisp Manual PS2:9-167 PS2:9-168 The Franz Lisp Manual _1_2._3._1. _m_a_c_r_o _e_x_p_a_n_s_i_o_n If the form is a macro invocation (i.e it is a list whose car is a symbol whose function binding is a macro), then that macro invocation is expanded. This is repeated until the top level form is not a macro invocation. When Liszt begins, there are already some macros defined, in fact some functions (such as defun) are actually macros. The user may define his own macros as well. For a macro to be used it must be defined in the Lisp system in which Liszt runs. _1_2._3._2. _c_l_a_s_s_i_f_i_c_a_t_i_o_n After all macro expansion is done, the form is classified according to its _c_a_r (if the form is not a list, then it is classified as an _o_t_h_e_r). _1_2._3._2._1. _e_v_a_l-_w_h_e_n The form of eval-when is (_e_v_a_l- _w_h_e_n (_t_i_m_e_1 _t_i_m_e_2 ...) _f_o_r_m_1 _f_o_r_m_2 ...) where the time_i are one of _e_v_a_l, _c_o_m_p_i_l_e, or _l_o_a_d. The compiler examines the form_i in sequence and the action taken depends on what is in the time list. If _c_o_m_p_i_l_e is in the list then the com- piler will invoke _e_v_a_l on each form_i as it exam- ines it. If _l_o_a_d is in the list then the com- pile will recursively call itself to compile each form_i as it examines it. Note that if _c_o_m_- _p_i_l_e and _l_o_a_d are in the time list, then the compiler will both evaluate and compile each form. This is useful if you need a function to be defined in the compiler at both compile time (perhaps to aid macro expansion) and at run time (after the file is _f_a_s_led in). _1_2._3._2._2. _d_e_c_l_a_r_e Declare is used to provide information about functions and variables to the compiler. It is (almost) equivalent to (_e_v_a_l- _w_h_e_n (_c_o_m_p_i_l_e) ...). You may declare functions to be one of three types: lambda (*expr), nlambda (*fexpr), lexpr (*lexpr). The names in parenthesis are the Maclisp names and are The Franz Lisp Manual PS2:9-169 accepted by the compiler as well (and not just when the compiler is in Maclisp mode). Func- tions are assumed to be lambdas until they are declared otherwise or are defined differently. The compiler treats calls to lambdas and lexprs equivalently, so you needn't worry about declar- ing lexprs either. It is important to declare nlambdas or define them before calling them. Another attribute you can declare for a function is localf which makes the function `local'. A local function's name is known only to the func- tions defined within the file itself. The advantage of a local function is that is can be entered and exited very quickly and it can have the same name as a function in another file and there will be no name conflict. Variables may be declared special or unspe- cial. When a special variable is lambda bound (either in a lambda, prog or do expression), its old value is stored away on a stack for the duration of the lambda, prog or do expression. This takes time and is often not necessary. Therefore the default classification for vari- ables is unspecial. Space for unspecial vari- ables is dynamically allocated on a stack. An unspecial variable can only be accessed from within the function where it is created by its presence in a lambda, prog or do expression variable list. It is possible to declare that all variables are special as will be shown below. You may declare any number of things in each declare statement. A sample declaration is (_d_e_c_l_a_r_e (_l_a_m_b_d_a _f_u_n_c_1 _f_u_n_c_2) (*_f_e_x_p_r _f_u_n_c_3) (*_l_e_x_p_r _f_u_n_c_4) (_l_o_c_a_l_f _f_u_n_c_5) (_s_p_e_c_i_a_l _v_a_r_1 _v_a_r_2 _v_a_r_3) (_u_n_s_p_e_c_i_a_l _v_a_r_4)) You may also declare all variables to be special with (_d_e_c_l_a_r_e (_s_p_e_c_i_a_l_s _t)). You may declare that macro definitions should be com- piled as well as evaluated at compile time by (_d_e_c_l_a_r_e (_m_a_c_r_o_s _t)). In fact, as was mentioned above, declare is much like (_e_v_a_l- _w_h_e_n (_c_o_m_p_i_l_e) ...). Thus if the compiler sees (_d_e_c_l_a_r_e (_f_o_o _b_a_r)) and foo is defined, then it will evaluate (_f_o_o _b_a_r). If foo is not defined then an undefined declare attribute warning will PS2:9-170 The Franz Lisp Manual be issued. _1_2._3._2._3. (_p_r_o_g_n '_c_o_m_p_i_l_e form1 form2 ... formn) When the compiler sees this it simply com- piles form1 through formn as if they too were seen at top level. One use for this is to allow a macro at top-level to expand into more than one function definition for the compiler to com- pile. _1_2._3._2._4. _i_n_c_l_u_d_e/_i_n_c_l_u_d_e_f _I_n_c_l_u_d_e and _i_n_c_l_u_d_e_f cause another file to be read and compiled by the compiler. The result is the same as if the included file were textually inserted into the original file. The only difference between _i_n_c_l_u_d_e and _i_n_c_l_u_d_e_f is that include doesn't evaluate its argument and includef does. Nested includes are allowed. _1_2._3._2._5. _d_e_f A def form is used to define a function. The macros _d_e_f_u_n and _d_e_f_m_a_c_r_o expand to a def form. If the function being defined is a lambda, nlambda or lexpr then the compiler con- verts the lisp definition to a sequence of machine language instructions. If the function being defined is a macro, then the compiler will evaluate the definition, thus defining the macro withing the running Lisp compiler. Furthermore, if the variable _m_a_c_r_o_s is set to a non nil value, then the macro definition will also be translated to machine language and thus will be defined when the object file is fasled in. The variable _m_a_c_r_o_s is set to t by (_d_e_c_l_a_r_e (_m_a_c_r_o_s _t)). When a function or macro definition is com- piled, macro expansion is done whenever possi- ble. If the compiler can determine that a form would be evaluated if this function were inter- preted then it will macro expand it. It will not macro expand arguments to a nlambda unless the characteristics of the nlambda is known (as is the case with _c_o_n_d). The map functions ( The Franz Lisp Manual PS2:9-171 _m_a_p, _m_a_p_c, _m_a_p_c_a_r, and so on) are expanded to a _d_o statement. This allows the first argument to the map function to be a lambda expression which references local variables of the function being defined. _1_2._3._2._6. _o_t_h_e_r _f_o_r_m_s All other forms are simply stored in the object file and are evaluated when the file is _f_a_s_led in. _1_2._4. _U_s_i_n_g _t_h_e _c_o_m_p_i_l_e_r The previous section describes exactly what the compiler does with its input. Generally you won't have to worry about all that detail as files which work interpreted will work compiled. Following is a list of steps you should follow to insure that a file will compile correctly. [1] Make sure all macro definitions precede their use in functions or other macro definitions. If you want the macros to be around when you _f_a_s_l in the object file you should include this statement at the beginning of the file: (_d_e_c_l_a_r_e (_m_a_c_r_o_s _t)) [2] Make sure all nlambdas are defined or declared before they are used. If the compiler comes across a call to a function which has not been defined in the current file, which does not currently have a function binding, and whose type has not been declared then it will assume that the function needs its arguments evaluated (i.e. it is a lambda or lexpr) and will generate code accordingly. This means that you do not have to declare nlambda functions like _s_t_a_t_u_s since they have an nlambda function binding. [3] Locate all variables which are used for communi- cating values between functions. These variables must be declared special at the beginning of a file. In most cases there won't be many special declarations but if you fail to declare a vari- able special that should be, the compiled code could fail in mysterious ways. Let's look at a common problem, assume that a file contains just these three lines: 9 9 PS2:9-172 The Franz Lisp Manual (_d_e_f _a_a_a (_l_a_m_b_d_a (_g_l_o_b _l_o_c) (_b_b_b _l_o_c))) (_d_e_f _b_b_b (_l_a_m_b_d_a (_m_y_l_o_c) (_a_d_d _g_l_o_b _m_y_l_o_c))) (_d_e_f _c_c_c (_l_a_m_b_d_a (_g_l_o_b _l_o_c) (_b_b_b _l_o_c))) We can see that if we load in these two defini- tions then (aaa 3 4) is the same as (add 3 4) and will give us 7. Suppose we compile the file con- taining these definitions. When Liszt compiles aaa, it will assume that both glob and loc are local variables and will allocate space on the temporary stack for their values when aaa is called. Thus the values of the local variables glob and loc will not affect the values of the symbols glob and loc in the Lisp system. Now Liszt moves on to function bbb. Myloc is assumed to be local. When it sees the add statement, it find a reference to a variable called glob. This variable is not a local variable to this function and therefore glob must refer to the value of the symbol glob. Liszt will automatically declare glob to be special and it will print a warning to that effect. Thus subsequent uses of glob will always refer to the symbol glob. Next Liszt com- piles ccc and treats glob as a special and loc as a local. When the object file is _f_a_s_l'ed in, and (ccc 3 4) is evaluated, the symbol glob will be lambda bound to 3 bbb will be called and will return 7. However (aaa 3 4) will fail since when bbb is called, glob will be unbound. What should be done here is to put (_d_e_c_l_a_r_e (_s_p_e_c_i_a_l _g_l_o_b) at the beginning of the file. [4] Make sure that all calls to _a_r_g are within the lexpr whose arguments they reference. If _f_o_o is a compiled lexpr and it calls _b_a_r then _b_a_r cannot use _a_r_g to get at _f_o_o's arguments. If both _f_o_o and _b_a_r are interpreted this will work however. The macro _l_i_s_t_i_f_y can be used to put all of some of a lexprs arguments in a list which then can be passed to other functions. _1_2._5. _C_o_m_p_i_l_e_r _o_p_t_i_o_n_s The compiler recognizes a number of options which are described below. The options are typed anywhere on the command line preceded by a minus sign. The entire command line is scanned and all options recorded before any action is taken. Thus % liszt -mx foo % liszt -m -x foo The Franz Lisp Manual PS2:9-173 % liszt foo -mx are all equivalent. Before scanning the command line for options, liszt looks for in the environment for the variable LISZT, and if found scans its value as if it was a string of options. The meaning of the options are: C The assembler language output of the compiler is commented. This is useful when debugging the compiler and is not normally done since it slows down compilation. I The next command line argument is taken as a filename, and loaded prior to compilation. e Evaluate the next argument on the command line before starting compilation. For example % liszt -e '(setq foobar "foo string")' foo will evaluate the above s-expression. Note that the shell requires that the arguments be sur- rounded by single quotes. i Compile this program in interlisp compatibility mode. This is not implemented yet. m Compile this program in Maclisp mode. The reader syntax will be changed to the Maclisp syntax and a file of macro definitions will be loaded in (usually named /usr/lib/lisp/machacks). This switch brings us sufficiently close to Maclisp to allow us to compile Macsyma, a large Maclisp pro- gram. However Maclisp is a moving target and we can't guarantee that this switch will allow you to compile any given program. o Select a different object or assembler language file name. For example % liszt foo -o xxx.o will compile foo and into xxx.o instead of the default foo.o, and % liszt bar -S -o xxx.s will compile to assembler language into xxx.s instead of bar.s. p place profiling code at the beginning of each non-local function. If the lisp system is also created with profiling in it, this allows func- tion calling frequency to be determined (see _p_r_o_f(_1)) q Run in quiet mode. The names of functions being compiled and various "Note"'s are not printed. 9 9 PS2:9-174 The Franz Lisp Manual Q print compilation statistics and warn of strange constructs. This is the inverse of the q switch and is the default. r place bootstrap code at the beginning of the object file, which when the object file is exe- cuted will cause a lisp system to be invoked and the object file _f_a_s_led in. This is known as `autorun' and is described below. S Create an assembler language file only. % liszt -S foo will create the file assembler language file foo.s and will not attempt to assemble it. If this option is not specified, the assembler language file will be put in the temporary disk area under a automatically generated name based on the lisp compiler's process id. Then if there are no compilation errors, the assembler will be invoked to assemble the file. T Print the assembler language output on the stan- dard output file. This is useful when debugging the compiler. u Run in UCI-Lisp mode. The character syntax is changed to that of UCI-Lisp and a UCI-Lisp compa- tibility package of macros is read in. w Suppress warning messages. x Create an cross reference file. % liszt -x foo not only compiles foo into foo.o but also gen- erates the file foo.x . The file foo.x is lisp readable and lists for each function all func- tions which that function could call. The pro- gram lxref reads one or more of these ".x" files and produces a human readable cross reference listing. _1_2._6. _a_u_t_o_r_u_n The object file which liszt writes does not con- tain all the functions necessary to run the lisp pro- gram which was compiled. In order to use the object file, a lisp system must be started and the object file _f_a_s_led in. When the -r switch is given to liszt, the object file created will contain a small piece of bootstrap code at the beginning, and the object file will be made executable. Now, when the name of the The Franz Lisp Manual PS2:9-175 object file is given to the UNIX command interpreter (shell) to run, the bootstrap code at the beginning of the object file will cause a lisp system to be started and the first action the lisp system will take is to _f_a_s_l in the object file which started it. In effect the object file has created an environment in which it can run. Autorun is an alternative to _d_u_m_p_l_i_s_p. The advantage of autorun is that the object file which starts the whole process is typically small, whereas the minimum _d_u_m_p_l_i_s_ped file is very large (one half megabyte). The disadvantage of autorun is that the file must be _f_a_s_led into a lisp each time it is used whereas the file which _d_u_m_p_l_i_s_p creates can be run as is. liszt itself is a _d_u_m_p_l_i_s_ped file since it is used so often and is large enough that too much time would be wasted _f_a_s_ling it in each time it was used. The lisp cross reference program, lxref, uses _a_u_t_o_r_u_n since it is a small and rarely used program. In order to have the program _f_a_s_led in begin exe- cution (rather than starting a lisp top level), the value of the symbol user-top-level should be set to the name of the function to get control. An example of this is shown next. 9 9 PS2:9-176 The Franz Lisp Manual ____________________________________________________ _w_e _w_a_n_t _t_o _r_e_p_l_a_c_e _t_h_e _u_n_i_x _d_a_t_e _p_r_o_g_r_a_m _w_i_t_h _o_n_e _w_r_i_t_t_e_n _i_n _l_i_s_p. % cat lispdate.l (defun mydate nil (patom "The date is ") (patom (status ctime)) (terpr) (exit 0)) (setq user-top-level 'mydate) % liszt -r lispdate Compilation begins with Lisp Compiler 5.2 source: lispdate.l, result: lispdate.o mydate %Note: lispdate.l: Compilation complete %Note: lispdate.l: Time: Real: 0:3, CPU: 0:0.28, GC: 0:0.00 for 0 gcs %Note: lispdate.l: Assembly begins %Note: lispdate.l: Assembly completed successfully 3.0u 2.0s 0:17 29% _W_e _c_h_a_n_g_e _t_h_e _n_a_m_e _t_o _r_e_m_o_v_e _t_h_e "._o", (_t_h_i_s _i_s_n'_t _n_e_c_e_s_s_a_r_y) % mv lispdate.o lispdate _N_o_w _w_e _t_e_s_t _i_t _o_u_t % lispdate The date is Sat Aug 1 16:58:33 1981 % ____________________________________________________ _1_2._7. _p_u_r_e _l_i_t_e_r_a_l_s Normally the quoted lisp objects (literals) which appear in functions are treated as constants. Consider this function: (_d_e_f _f_o_o (_l_a_m_b_d_a _n_i_l (_c_o_n_d ((_n_o_t (_e_q '_a (_c_a_r (_s_e_t_q _x '(_a _b))))) (_p_r_i_n_t '_i_m_p_o_s_s_i_b_l_e!!)) (_t (_r_p_l_a_c_a _x '_d))))) At first glance it seems that the first cond clause will never be true, since the _c_a_r of (_a _b) should always be _a. However if you run this function twice, it will print 'impossible!!' the second time. This is The Franz Lisp Manual PS2:9-177 because the following clause modifies the 'constant' list (_a _b) with the _r_p_l_a_c_a function. Such modifica- tion of literal lisp objects can cause programs to behave strangely as the above example shows, but more importantly it can cause garbage collection problems if done to compiled code. When a file is _f_a_s_led in, if the symbol $purcopylits is non nil, the literal lisp data is put in 'pure' space, that is it put in space which needn't be looked at by the garabage col- lector. This reduces the work the garbage collector must do but it is dangerous since if the literals are modified to point to non pure objects, the marker may not mark the non pure objects. If the symbol $pur- copylits is nil then the literal lisp data is put in impure space and the compiled code will act like the interpreted code when literal data is modified. The default value for $purcopylits is t. _1_2._8. _t_r_a_n_s_f_e_r _t_a_b_l_e_s A transfer table is setup by _f_a_s_l when the object file is loaded in. There is one entry in the transfer table for each function which is called in that object file. The entry for a call to the function _f_o_o has two parts whose contents are: [1] function address - This will initially point to the internal function _q_l_i_n_k_e_r. It may some time in the future point to the function _f_o_o if cer- tain conditions are satisfied (more on this below). [2] function name - This is a pointer to the symbol _f_o_o. This will be used by _q_l_i_n_k_e_r. When a call is made to the function _f_o_o the call will actually be made to the address in the transfer table entry and will end up in the _q_l_i_n_k_e_r function. _Q_l_i_n_k_e_r will determine that _f_o_o was the function being called by locating the function name entry in the transfer table[|-]. If the function being called is ____________________ 9 [|-]_Q_l_i_n_k_e_r does this by tracing back the call stack until it finds the _c_a_l_l_s machine instruction which called it. The address field of the _c_a_l_l_s contains the address of the transfer table entry. 9 PS2:9-178 The Franz Lisp Manual not compiled then _q_l_i_n_k_e_r just calls _f_u_n_c_a_l_l to per- form the function call. If _f_o_o is compiled and if (_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k) is non nil, then _q_l_i_n_k_e_r will modify the function address part of the transfer table to point directly to the function _f_o_o. Finally _q_l_i_n_k_e_r will call _f_o_o directly . The next time a call is made to _f_o_o the call will go directly to _f_o_o and not through _q_l_i_n_k_e_r. This will result in a substan- tial speedup in compiled code to compiled code transfers. A disadvantage is that no debugging infor- mation is left on the stack, so _s_h_o_w_s_t_a_c_k and _b_a_k_t_r_a_c_e are useless. Another disadvantage is that if you redefine a compiled function either through loading in a new version or interactively defining it, then the old version may still be called from compiled code if the fast linking described above has already been done. The solution to these problems is to use (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _v_a_l_u_e). If value is _n_i_l All transfer tables will be cleared, i.e. all function addresses will be set to point to _q_l_i_n_k_e_r. This means that the next time a func- tion is called _q_l_i_n_k_e_r will be called and will look at the current definition. Also, no fast links will be set up since (_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k) will be nil. The end result is that _s_h_o_w_s_t_a_c_k and _b_a_k_t_r_a_c_e will work and the function defini- tion at the time of call will always be used. _o_n This causes the lisp system to go through all transfer tables and set up fast links wherever possible. This is normally used after you have _f_a_s_led in all of your files. Furthermore since (_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k) is not nil, _q_l_i_n_k_e_r will make new fast links if the situation arises (which isn't likely unless you _f_a_s_l in another file). _t This or any other value not previously mentioned will just make (_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k) be non nil, and as a result fast links will be made by _q_l_i_n_k_e_r if the called function is compiled. _1_2._9. _F_i_x_n_u_m _f_u_n_c_t_i_o_n_s The compiler will generate inline arithmetic code for fixnum only functions. Such functions include +, -, *, /, \, 1+ and 1-. The code generated will be much faster than using _a_d_d, _d_i_f_f_e_r_e_n_c_e, etc. However it will only work if the arguments to and results of the functions are fixnums. No type checking is done. 9 9 CHAPTER 13 The CMU User Toplevel and the File Package This documentation was written by Don Cohen, and the functions described below were imported from PDP-10 CMULisp. _N_o_n _C_M_U _u_s_e_r_s _n_o_t_e: this is not the default top level for your Lisp system. In order to start up this top level, you should type (_l_o_a_d '_c_m_u_e_n_v). _1_3._1. _U_s_e_r _C_o_m_m_a_n_d _I_n_p_u_t _T_o_p _L_e_v_e_l The top-level is the function that reads what you type, evaluates it and prints the result. The _n_e_w_l_i_s_p top-level was inspired by the CMULisp top-level (which was inspired by interlisp) but is much simpler. The top-level is a function (of zero arguments) that can be called by your program. If you prefer another top-level, just redefine the top-level function and type "(reset)" to start running it. The current top- level simply calls the functions tlread, tleval and tlprint to read, evaluate and print. These are sup- posed to be replaceable by the user. The only one that would make sense to replace is tlprint, which currently uses a function that refuses to go below a certain level and prints "...]" when it finds itself printing a circular list. One might want to pretty- print the results instead. The current top-level numbers the lines that you type to it, and remembers the last n "events" (where n can be set but is defaulted to 25). One can refer to these events in the following "top-level commands": 9 9The Franz Lisp Manual PS2:9-179 PS2:9-180 The Franz Lisp Manual ____________________________________________________ _T_O_P_L_E_V_E_L _C_O_M_M_A_N_D _S_U_M_M_A_R_Y ?? prints events - both the input and the result. If you just type "??" you will see all of the recorded events. "?? 3" will show only event 3, and "?? 3 6" will show events 3 through 6. redo pretends that you typed the same thing that was typed before. If you type "redo 3" event number 3 is redone. "redo -3" redoes the thing 3 events ago. "redo" is the same as "redo -1". ed calls the editor and then does whatever the editor returns. Thus if you want to do event 5 again except for some small change, you can type "ed 5", make the change and leave the editor. "ed -3" and "ed" are analogous to redo. ____________________________________________________ Finally, you can get the value of event 7 with the function (valueof 7). The other interesting feature of the top-level is that it makes outermost parentheses superfluous for the most part. This works the same way as in CMULisp, so you can use the help for an explanation. If you're not sure and don't want to risk it you can always just include the parentheses. (top-level) SIDE EFFECT: _t_o_p-_l_e_v_e_l is the LISP top level function. As well as being the top level function with which the user interacts, it can be called recursively by the user or any function. Thus, the top level can be invoked from inside the editor, break package, or a user function to make its commands available to the user. NOTE: The CMU FRANZ LISP top-level uses _l_i_n_e_r_e_a_d rather than _r_e_a_d. The difference will not usu- ally be noticeable. The principal thing to be careful about is that input to the function or system being called cannot appear on the same line as the top-level call. For example, typing (_e_d_i_t_f _f_o_o)_f_P _o_n _o_n_e _l_i_n_e _w_i_l_l _e_d_i_t _f_o_o _a_n_d _e_v_a_l_u_a_t_e _P, _n_o_t _e_d_i_t _f_o_o _a_n_d _e_x_e_c_u_t_e _t_h_e _p _c_o_m_- _m_a_n_d _i_n _t_h_e _e_d_i_t_o_r. _t_o_p-_l_e_v_e_l _s_p_e_c_i_a_l_l_y _r_e_c_o_g_- _n_i_z_e_s _t_h_e _f_o_l_l_o_w_i_n_g _c_o_m_m_a_n_d_s: 9 9 The Franz Lisp Manual PS2:9-181 (valueof '_g__e_v_e_n_t_s_p_e_c) RETURNS: the value(s) of the event(s) specified by g_eventspec. If a single event is specified, its value will be returned. If more than one event is specified, or an event has more than one subevent (as for _r_e_d_o, etc), a list of vlaues will be returned. _1_3._2. _T_h_e _F_i_l_e _P_a_c_k_a_g_e Users typically define functions in lisp and then want to save them for the next session. If you do (_c_h_a_n_g_e_s), a list of the functions that are newly defined or changed will be printed. When you type (_d_s_k_o_u_t_s), the functions associated with files will be saved in the new versions of those files. In order to associate functions with files you can either add them to the _f_i_l_e_f_n_s list of an existing file or create a new file to hold them. This is done with the _f_i_l_e function. If you type (_f_i_l_e _n_e_w) the system will create a variable called _n_e_w_f_n_s. You may add the names of the functions to go into that file to _n_e_w_f_n_s. After you do (_c_h_a_n_g_e_s), the functions which are in no other file are stored in the value of the atom _c_h_a_n_g_e_s. To put these all in the new file, (_s_e_t_q _n_e_w_f_n_s (_a_p_p_e_n_d _n_e_w_f_n_s _c_h_a_n_g_e_s)). Now if you do (_c_h_a_n_g_e_s), all of the changed functions should be associated with files. In order to save the changes on the files, do (_d_s_k_o_u_t_s). All of the changed files (such as NEW) will be written. To recover the new functions the next time you run FRANZ LISP, do (_d_s_k_i_n _n_e_w). 9 9 PS2:9-182 The Franz Lisp Manual ____________________________________________________ Script started on Sat Mar 14 11:50:32 1981 $ newlisp Welcome to newlisp... 1.(defun square (x) (* x x)) ; define a new function square 2.(changes) ; See, this function is associated ; with no file. (square)nil 3.(file 'new) ; So let's declare file NEW. new 4.newfns ; It doesn't have anything on it yet. nil 5.(setq newfns '(square)) ; Add the function associated (square) ; with no file to file NEW. 6.(changes) ; CHANGES magically notices this fact. new (square)nil 7.(dskouts) ; We write the file. creating new (new) 8.(dskin new) ; We read it in! (new) 14.Bye $ script done on Sat Mar 14 11:51:48 1981 ____________________________________________________ (changes s_flag) RETURNS: Changes computes a list containing an entry for each file which defines atoms that have been marked changed. The entry contains the file name and the changed atoms defined therein. There is also a special entry for changes to atoms which are not defined in any known file. The global variable _f_i_l_e_l_s_t con- tains the list of "known" files. If no flag is passed this result is printed in human readable form and the value returned is t if there were any changes and nil if not. Other- wise nothing is printed and the computer list is returned. The global variable _c_h_a_n_g_e_s con- tains the atoms which are marked changed but not yet associated with any file. The _c_h_a_n_g_e_s function attempts to associate these names The Franz Lisp Manual PS2:9-183 with files, and any that are not found are considered to belong to no file. The _c_h_a_n_g_e_s property is the means by which changed func- tions are associated with files. When a file is read in or written out its _c_h_a_n_g_e_s property is removed. (dc s_word s_id [ g_descriptor1 ... ] ) RETURNS: _d_c defines comments. It is exceptional in that its behavior is very context dependent. When _d_c is executed from _d_s_k_i_n it simply records the fact that the comment exists. It is expected that in interactive mode comments will be found via _g_e_t_d_e_f - this allows large comments which do not take up space in your core image. When _d_c is executed from the ter- minal it expects you to type a comment. _d_s_k_o_u_t will write out the comments that you define and also copy the comments on the old version of the file, so that the new version will keep the old comments even though they were never actually brought into core. The optional id is a mechanism for distinguishing among several comments associated with the same word. It defaults to nil. However if you define two comments with the same id, the second is considered to be a replacement for the first. The behavior of _d_c is determined by the value of the global variable _d_e_f-_c_o_m_m_e_n_t. _d_e_f-_c_o_m_m_e_n_t contains the name of a function that is run. Its arguments are the word, id and attribute list. _d_e_f-_c_o_m_m_e_n_t is initially _d_c-_d_e_f_i_n_e. Other functions rebind it to _d_c- _h_e_l_p, _d_c-_u_s_e_r_h_e_l_p, and the value of _d_s_k_i_n- _c_o_m_m_e_n_t. The comment property of an atom is a list of entries, each representing one com- ment. Atomic entries are assumed to be iden- tifiers of comments on a file but not in core. In-core comments are represented by a list of the id, the attribute list and the comment text. The comment text is an uninterned atom. Comments may be deleted or reordered by edit- ing the comment property. 9 9 PS2:9-184 The Franz Lisp Manual (dskin l_filenames) SIDE EFFECT: READ-EVAL-PRINTs the contents of the given files. This is the function to use to read files created by _d_s_k_o_u_t. _d_s_k_i_n also declares the files that it reads (if a _f_i_l_e-_f_n_s list is defined and the file is otherwise declarable by _f_i_l_e ), so that changes to it can be recorded. (dskout s_file1 ...) SIDE EFFECT: For each file specified, _d_s_k_o_u_t assumes the list named filenameFNS (i.e., the file name, excluding extension, con- catenated with _f_n_s ) contains a list of function names, etc., to be loaded Any previous version of the file will be renamed to have extension ".back". (dskouts s_file1 ...) SIDE EFFECT: applies _d_s_k_o_u_t to and prints the name of each s_filei (with no additional arguments, assuming filenameFNS to be a list to be loaded) for which s_file_i is either not in _f_i_l_e_l_s_t (meaning it is a new file not previously declared by _f_i_l_e or given as an argument to _d_s_k_i_n, _d_s_k_o_u_t_s, or _d_s_k_o_u_t_s) or is in _f_i_l_e_l_s_t and has some recorded changes to definitions of atoms in filenameFNS, as recorded by _m_a_r_k!_c_h_a_n_g_e_d and noted by changes. If _f_i_l_ei is not specified, _f_i_l_e_l_s_t will be used. This is the most common way of using dskouts. Typing (_d_s_k_o_u_t_s) will save every file reported by (_c_h_a_n_g_e_s) to have changed definitions. (dv s_atom g_value) EQUIVALENT TO: (_s_e_t_q _a_t_o_m '_v_a_l_u_e). _d_v calls _m_a_r_k!_c_h_a_n_g_e_d. 9 9 The Franz Lisp Manual PS2:9-185 (file 's_file) SIDE EFFECT: declares its argument to be a file to be used for reporting and saving changes to functions by adding the file name to a list of files, _f_i_l_e_l_s_t. _f_i_l_e is called for each file argument of _d_s_k_i_n, _d_s_k_o_u_t, and _d_s_k_o_u_t_s. (file-fns 's_file) RETURNS: the name of the fileFNS list for its file argument s_file. (getdef 's_file ['s_i1 ...]) SIDE EFFECT: selectively executes definitions for atoms s_i1 ... from the specified file. Any of the words to be defined which end with "@" will be treated as patterns in which the @ matchs any suffix (just like the editor). _g_e_t_d_e_f is driven by _g_e_t_d_e_f_t_a_b_l_e (and thus may be programmed). It looks for lines in the file that start with a word in the table. The first character must be a "(" or "[" followed by the word, followed by a space, return or something else that will not be considered as part of the identif- ier by _r_e_a_d, e.g., "(" is unacceptable. When one is found the next word is read. If it matches one of the identifiers in the call to _g_e_t_d_e_f then the table entry is executed. The table entry is a function of the expression starting in this line. Output from _d_s_k_o_u_t is in acceptable format for _g_e_t_d_e_f. _g_e_t_d_e_f RETURNS: a list of the words which match the ones it looked for, for which it found (but, depending on the table, perhaps did not execute) in the file. NOTE: _g_e_t_d_e_f_t_a_b_l_e is the table that drives _g_e_t_d_e_f. It is in the form of an association list. Each ele- ment is a dotted pair consisting of the name of a function for which _g_e_t_d_e_f searches and a function of one argument to be executed when it is found. 9 9 PS2:9-186 The Franz Lisp Manual (mark!changed 's_f) SIDE EFFECT: records the fact that the definition of s_f has been changed. It is automatically called by _d_e_f, _d_e_f_u_n, _d_e, _d_f, _d_e_f_p_r_o_p, _d_m, _d_v, and the editor when a definition is altered. 9 9 CHAPTER 14 The LISP Stepper _1_4._1. _S_i_m_p_l_e _U_s_e _O_f _S_t_e_p_p_i_n_g (step s_arg1...) NOTE: The LISP "stepping" package is intended to give the LISP programmer a facility analogous to the Instruction Step mode of running a machine language program. The user interface is through the function (fexpr) step, which sets switches to put the LISP interpreter in and out of "stepping" mode. The most common _s_t_e_p invocations follow. These invocations are usually typed at the top- level, and will take effect immediately (i.e. the next S-expression typed in will be evaluated in stepping mode). ____________________________________________________ (_s_t_e_p _t) ; Turn on stepping mode. (_s_t_e_p _n_i_l) ; Turn off stepping mode. ____________________________________________________ SIDE EFFECT: In stepping mode, the LISP evaluator will print out each S-exp to be evaluated before evaluation, and the returned value after evaluation, calling itself recur- sively to display the stepped evaluation of each argument, if the S-exp is a func- tion call. In stepping mode, the evalua- tor will wait after displaying each S-exp before evaluation for a command character from the console. 9 9The Franz Lisp Manual PS2:9-187 PS2:9-188 The Franz Lisp Manual ____________________________________________________ _S_T_E_P _C_O_M_M_A_N_D _S_U_M_M_A_R_Y Continue stepping recursively. c Show returned value from this level only, and continue stepping upward. e Only step interpreted code. g Turn off stepping mode. (but continue evaluation without stepping). n Step through evaluations without stopping p Redisplay current form in full (i.e. rebind prinlevel and prinlength to nil) b Get breakpoint q Quit d Call debug ____________________________________________________ _1_4._2. _A_d_v_a_n_c_e_d _F_e_a_t_u_r_e_s _1_4._2._1. _S_e_l_e_c_t_i_v_e_l_y _T_u_r_n_i_n_g _O_n _S_t_e_p_p_i_n_g. If (_s_t_e_p _f_o_o_1 _f_o_o_2 ...) is typed at top level, stepping will not commence immediately, but rather when the evaluator first encounters an S-expression whose car is one of _f_o_o_1, _f_o_o_2, etc. This form will then display at the console, and the evaluator will be in stepping mode waiting for a command character. Normally the stepper intercepts calls to _f_u_n_- _c_a_l_l and _e_v_a_l. When _f_u_n_c_a_l_l is intercepted, the arguments to the function have already been evaluated but when _e_v_a_l is intercepted, the The Franz Lisp Manual PS2:9-189 arguments have not been evaluated. To differen- tiate the two cases, when printing the form in evaluation, the stepper preceded intercepted calls to _f_u_n_c_a_l_l with "f:". Calls to _f_u_n_c_a_l_l are nor- mally caused by compiled lisp code calling other functions, whereas calls to _e_v_a_l usually occur when lisp code is interpreted. To step only calls to eval use: (_s_t_e_p _e) _1_4._2._2. _S_t_e_p_p_i_n_g _W_i_t_h _B_r_e_a_k_p_o_i_n_t_s. For the moment, step is turned off inside of error breaks, but not by the break function. Upon exiting the error, step is reenabled. However, executing (_s_t_e_p _n_i_l) inside a error loop will turn off stepping globally, i.e. within the error loop, and after return has be made from the loop. _1_4._3. _O_v_e_r_h_e_a_d _o_f _S_t_e_p_p_i_n_g. If stepping mode has been turned off by (_s_t_e_p _n_i_l), the execution overhead of having the stepping packing in your LISP is identically nil. If one stops stepping by typing "g", every call to eval incurs a small overhead--several machine instructions, corresponding to the compiled code for a simple cond and one function pushdown. Running with (_s_t_e_p _f_o_o_1 _f_o_o_2 ...) can be more expensive, since a member of the car of the current form into the list (_f_o_o_1 _f_o_o_2 ...) is required at each call to eval. _1_4._4. _E_v_a_l_h_o_o_k _a_n_d _F_u_n_c_a_l_l_h_o_o_k There are hooks in the FRANZ LISP interpreter to permit a user written function to gain control of the evaluation process. These hooks are used by the Step package just described. There are two hooks and they have been strategically placed in the two key func- tions in the interpreter: _e_v_a_l (which all interpreted code goes through) and _f_u_n_c_a_l_l (which all compiled code goes through if (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l) has been done). The hook in _e_v_a_l is compatible with Maclisp, but there is no Maclisp equivalent of the hook in _f_u_n_- _c_a_l_l. 9 9 PS2:9-190 The Franz Lisp Manual To arm the hooks two forms must be evaluated: (*_r_s_e_t _t) and (_s_s_t_a_t_u_s _e_v_a_l_h_o_o_k _t). Once that is done, _e_v_a_l and _f_u_n_c_a_l_l do a special check when they enter. If _e_v_a_l is given a form to evaluate, say (_f_o_o _b_a_r), and the symbol `evalhook' is non nil, say its value is `ehook', then _e_v_a_l will lambda bind the symbols `evalhook' and `funcallhook' to nil and will call ehook passing (_f_o_o _b_a_r) as the argument. It is ehook's responsibility to evaluate (_f_o_o _b_a_r) and return its value. Typically ehook will call the func- tion `evalhook' to evaluate (_f_o_o _b_a_r). Note that `evalhook' is a symbol whose function binding is a system function described in Chapter 4, and whose value binding, if non nil, is the name of a user writ- ten function (or a lambda expression, or a binary object) which will gain control whenever eval is called. `evalhook' is also the name of the _s_t_a_t_u_s tag which must be set for all of this to work. If _f_u_n_c_a_l_l is given a function, say foo, and a set of already evaluated arguments, say barv and bazv, and if the symbol `funcallhook' has a non nil value, say `fhook', then _f_u_n_c_a_l_l will lambda bind `evalhook' and `funcallhook' to nil and will call fhook with arguments barv, bazv and foo. Thus fhook must be a lexpr since it may be given any number of arguments. The function to call, foo in this case, will be the _l_a_s_t of the arguments given to fhook. It is fhooks responsibility to do the function call and return the value. Typically fhook will call the function _f_u_n_- _c_a_l_l_h_o_o_k to do the funcall. This is an example of a funcallhook function which just prints the arguments on each entry to funcall and the return value. 9 9 The Franz Lisp Manual PS2:9-191 ____________________________________________________ -> (_d_e_f_u_n _f_h_o_o_k _n (_l_e_t ((_f_o_r_m (_c_o_n_s (_a_r_g _n) (_l_i_s_t_i_f_y (_1- _n)))) (_r_e_t_v_a_l)) (_p_a_t_o_m "_c_a_l_l_i_n_g ")(_p_r_i_n_t _f_o_r_m)(_t_e_r_p_r) (_s_e_t_q _r_e_t_v_a_l (_f_u_n_c_a_l_l_h_o_o_k _f_o_r_m '_f_h_o_o_k)) (_p_a_t_o_m "_r_e_t_u_r_n_s ")(_p_r_i_n_t _r_e_t_v_a_l)(_t_e_r_p_r) _r_e_t_v_a_l)) fhook -> (*_r_s_e_t _t) (_s_s_t_a_t_u_s _e_v_a_l_h_o_o_k _t) (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l) -> (_s_e_t_q _f_u_n_c_a_l_l_h_o_o_k '_f_h_o_o_k) calling (print fhook) ;; now all compiled code is traced fhookreturns nil calling (terpr) returns nil calling (patom "-> ") -> returns "-> " calling (read nil Q00000) (_a_r_r_a_y _f_o_o _t _1_0) ;; to test it, we see what happens when returns (array foo t 10) ;; we make an array calling (eval (array foo t 10)) calling (append (10) nil) returns (10) calling (lessp 1 1) returns nil calling (apply times (10)) returns 10 calling (small-segment value 10) calling (boole 4 137 127) returns 128 ... there is plenty more ... ____________________________________________________ 9 9 CHAPTER 15 The FIXIT Debugger _1_5._1. _I_n_t_r_o_d_u_c_t_i_o_n FIXIT is a debugging environment for FRANZ LISP users doing program development. This documentation and FIXIT were written by David S. Touretzky of Carnegie-Mellon University for MACLisp, and adapted to FRANZ LISP by Mitch Marcus of Bell Labs. One of FIXIT's goals is to get the program run- ning again as quickly as possible. The user is assisted in making changes to his functions "on the fly", i.e. in the midst of execution, and then compu- tation is resumed. To enter the debugger type (_d_e_b_u_g). The debugger goes into its own read-eval-print loop. Like the top-level, the debugger understands certain special commands. One of these is help, which prints a list of the available commands. The basic idea is that you are somewhere in a stack of calls to eval. The com- mand "bka" is probably the most appropriate for look- ing at the stack. There are commands to move up and down. If you want to know the value of "x" as of some place in the stack, move to that place and type "x" (or (cdr x) or anything else that you might want to evaluate). All evaluation is done as of the current stack position. You can fix the problem by changing the values of variables, editing functions or expres- sions in the stack etc. Then you can continue from the current stack position (or anywhere else) with the "redo" command. Or you can simply return the right answer with the "return" command. When it is not immediately obvious why an error has occurred or how the program got itself into its current state, FIXIT comes to the rescue by providing a powerful debugging loop in which the user can: - examine the stack - evaluate expressions in context - enter stepping mode - restart the computation at any point 9 9PS2:9-192 The Franz Lisp Manual The Franz Lisp Manual PS2:9-193 The result is that program errors can be located and fixed extremely rapidly, and with a minimum of frus- tration. The debugger can only work effectively when extra information is kept about forms in evaluation by the lisp system. Evaluating (*_r_s_e_t _t) tells the lisp sys- tem to maintain this information. If you are debugging compiled code you should also be sure that the com- piled code to compiled code linkage tables are unlinked, i.e do (_s_s_t_a_t_u_s _t_r_a_n_s_l_i_n_k _n_i_l). (debug [ s_msg ]) NOTE: Within a program, you may enter a debug loop directly by putting in a call to _d_e_b_u_g where you would normally put a call to _b_r_e_a_k. Also, within a break loop you may enter FIXIT by typing _d_e_b_u_g. If an argument is given to DEBUG, it is treated as a message to be printed before the debug loop is entered. Thus you can put (_d_e_b_u_g |_j_u_s_t _b_e_f_o_r_e _l_o_o_p|) into a program to indicate what part of the program is being debugged. 9 9 PS2:9-194 The Franz Lisp Manual ____________________________________________________ _F_I_X_I_T _C_o_m_m_a_n_d _S_u_m_m_a_r_y TOP go to top of stack (latest expression) BOT go to bottom of stack (first expression) P show current expression (with ellipsis) PP show current expression in full WHERE give current stack position HELP types the abbreviated command summary found in /usr/lisp/doc/fixit.help. H and ? work too. U go up one stack frame U n go up n stack frames U f go up to the next occurrence of function f U n f go up n occurrences of function f UP go up to the next user-written function UP n go up n user-written functions ...the DN and DNFN commands are similar, but go down ...instead of up. OK resume processing; continue after an error or debug loop REDO restart the computation with the current stack frame. The OK command is equivalent to TOP followed by REDO. REDO f restart the computation with the last call to function f. (The stack is searched downward from the current position.) STEP restart the computation at the current stack frame, but first turn on stepping mode. (Assumes Rich stepper is loaded.) RETURN e return from the current position in the computation with the value of expression e. BK.. print a backtrace. There are many backtrace commands, formed by adding suffixes to the BK command. "BK" gives a backtrace showing only user-written functions, and uses ellipsis. The BK command may be suffixed by one or more of the following modifiers: ..F.. show function names instead of expressions ..A.. show all functions/expressions, not just user-written ones ..V.. show variable bindings as well as functions/expressions ..E.. show everything in the expression, i.e. don't use ellipsis ..C.. go no further than the current position on the stack Some of the more useful combinations are BKFV, BKFA, and BKFAV. BK.. n show only n levels of the stack (starting at the top). (BK n counts only user functions; BKA n counts all functions.) BK.. f show stack down to first call of function f BK.. n f show stack down to nth call of function f ____________________________________________________ 9 9 The Franz Lisp Manual PS2:9-195 _1_5._2. _I_n_t_e_r_a_c_t_i_o_n _w_i_t_h _t_r_a_c_e FIXIT knows about the standard Franz trace package, and tries to make trac- ing invisible while in the debug loop. However, because of the way _t_r_a_c_e works, it may sometimes be the case that the functions on the stack are really un_i_n_t_e_r_ned atoms that have the same name as a traced function. (This only happens when a function is traced WHEREIN another one.) FIXIT will call atten- tion to _t_r_a_c_e'_s hackery by printing an appropriate tag next to these stack entries. _1_5._3. _I_n_t_e_r_a_c_t_i_o_n _w_i_t_h _s_t_e_p The _s_t_e_p function may be invoked from within FIXIT via the STEP command. FIXIT initially turns off stepping when the debug loop is entered. If you step through a function and get an error, FIXIT will still be invoked normally. At any time during stepping, you may explicitly enter FIXIT via the "D" (debug) command. _1_5._4. _M_u_l_t_i_p_l_e _e_r_r_o_r _l_e_v_e_l_s FIXIT will evaluate arbi- trary LISP expressions in its debug loop. The evalua- tion is not done within an _e_r_r_s_e_t, so, if an error occurs, another invocation of the debugger can be made. When there are multiple errors on the stack, FIXIT displays a barrier symbol between each level that looks something like <------------UDF-->. The UDF in this case stands for UnDefined Function. Thus, the upper level debug loop was invoked by an undefined function error that occurred while in the lower loop. 9 9 CHAPTER 16 The LISP Editor _1_6._1. _T_h_e _E_d_i_t_o_r_s It is quite possible to use VI, Emacs or other stan- dard editors to edit your lisp programs, and many peo- ple do just that. However there is a lisp structure editor which is particularly good for the editing of lisp programs, and operates in a rather different fashion, namely within a lisp environment. applica- tion. It is handy to know how to use it for fixing problems without exiting from the lisp system (e.g. from the debugger so you can continue to execute rather than having to start over.) The editor is not quite like the top-level and debugger, in that it expects you to type editor commands to it. It will not evaluate whatever you happen to type. (There is an editor command to evaluate things, though.) The editor is available (assuming your system is set up correctly with a lisp library) by typing (load 'cmufncs) and (load 'cmuedit). The most frequent use of the editor is to change function definitions by starting the editor with one of the commands described in section 16.14. (see _e_d_i_t_f), values (_e_d_i_t_v), properties (_e_d_i_t_p), and expressions (_e_d_i_t_e). The beginner is advised to start with the following (very basic) commands: _o_k, _u_n_d_o, _p, #, under which are explained two different basic commands which start with numbers, and f. This documentation, and the editor, were imported from PDP-10 CMULisp by Don Cohen. PDP-10 CMULisp is based on UCILisp, and the editor itself was derived from an early version of Interlisp. Lars Ericson, the author of this section, has provided this very concise sum- mary. Tutorial examples and implementation details may be found in the Interlisp Reference Manual, where a similar editor is described. 9 9PS2:9-196 The Franz Lisp Manual The Franz Lisp Manual PS2:9-197 _1_6._2. _S_c_o_p_e _o_f _A_t_t_e_n_t_i_o_n Attention-changing commands allow you to look at a different part of a Lisp expression you are editing. The sub-structure upon which the editor's attention is centered is called "the current expression". Chang- ing the current expression means shifting attention and not actually modifying any structure. ____________________________________________________________ _S_C_O_P_E _O_F _A_T_T_E_N_T_I_O_N _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _n (_n>_0) . Makes the nth element of the current expression be the new current expression. -_n (_n>_0). Makes the nth element from the end of the current expression be the new current expression. _0. Makes the next higher expression be the new correct expression. If the intention is to go back to the next higher left parenthesis, use the command !0. _u_p . If a p command would cause the editor to type ... before typing the current expression, (the current expres- sion is a tail of the next higher expression) then has no effect; else, up makes the old current expression the first element in the new current expression. !_0 . Goes back to the next higher left parenthesis. ^ . Makes the top level expression be the current expres- sion. _n_x . Makes the current expression be the next expression. (_n_x _n) equivalent to n nx commands. !_n_x . Makes current expression be the next expression at a higher level. Goes through any number of right parentheses to get to the next expression. _b_k . Makes the current expression be the previous expres- sion in the next higher expression. (_n_t_h _n) _n>_0 . Makes the list starting with the nth element of the current expression be the current expression. (_n_t_h $) - _g_e_n_e_r_a_l_i_z_e_d _n_t_h _c_o_m_m_a_n_d. nth locates $, and then backs up to the current level, where the new current expres- sion is the tail whose first element contains, however dee- ply, the expression that was the terminus of the location operation. PS2:9-198 The Franz Lisp Manual :: . (pattern :: . $) e.g., (cond :: return). finds a cond that contains a return, at any depth. (_b_e_l_o_w _c_o_m _x) . The below command is useful for locating a substructure by specifying something it contains. (below cond) will cause the cond clause containing the current expression to become the new current expression. Suppose you are editing a list of lists, and want to find a sublist that contains a foo (at any depth). Then simply executes f foo (below ). (_n_e_x _x) . same as (_b_e_l_o_w _x) followed by nx. For example, if you are deep inside of a selectq clause, you can advance to the next clause with (_n_e_x _s_e_l_e_c_t_q). _n_e_x. The atomic form of _n_e_x is useful if you will be performing repeated executions of (_n_e_x _x). By simply marking the chain corresponding to x, you can use _n_e_x to step through the sublists. ____________________________________________________________ _1_6._3. _P_a_t_t_e_r_n _M_a_t_c_h_i_n_g _C_o_m_m_a_n_d_s Many editor commands that search take patterns. A pattern _p_a_t matches with x if: ____________________________________________________________ _P_A_T_T_E_R_N _S_P_E_C_I_F_I_C_A_T_I_O_N _S_U_M_M_A_R_Y - _p_a_t is _e_q to x. - _p_a_t is &. - _p_a_t is a number and equal to x. - if (car _p_a_t) is the atom *any*, (cdr _p_a_t) is a list of patterns, and _p_a_t matches x if and only if one of the pat- terns on (cdr _p_a_t) matches x. - if _p_a_t is a literal atom or string, and (nthchar _p_a_t -1) is @, then _p_a_t matches with any literal atom or string which has the same initial characters as _p_a_t, e.g. ver@ matches with verylongatom, as well as "verylongstring". - if (car _p_a_t) is the atom --, _p_a_t matches x if (a) (cdr _p_a_t)=nil, i.e. _p_a_t=(--), e.g., (a --) matches (a) (a b c) and (a . b) in other words, -- can match any tail of a list. (b) (cdr _p_a_t) matches with some tail of x, e.g. (a The Franz Lisp Manual PS2:9-199 -- (&)) will match with (a b c (d)), but not (a b c d), or (a b c (d) e). however, note that (a -- (&) --) will match with (a b c (d) e). in other words, -- will match any inte- rior segment of a list. - if (car _p_a_t) is the atom ==, _p_a_t matches x if and only if (cdr _p_a_t) is _e_q to x. (this pattern is for use by programs that call the editor as a subroutine, since any non-atomic expression in a command typed in by the user obviously can- not be _e_q to existing structure.) - otherwise if x is a list, _p_a_t matches x if (car _p_a_t) matches (car x), and (cdr _p_a_t) matches (cdr x). - when searching, the pattern matching routine is called only to match with elements in the structure, unless the pattern begins with :::, in which case cdr of the pattern is matched against tails in the structure. (in this case, the tail does not have to be a proper tail, e.g. (::: a --) will match with the element (a b c) as well as with cdr of (x a b c), since (a b c) is a tail of (a b c).) ____________________________________________________________ _1_6._3._1. _C_o_m_m_a_n_d_s _T_h_a_t _S_e_a_r_c_h ____________________________________________________________ _S_E_A_R_C_H _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _f _p_a_t_t_e_r_n . f informs the editor that the next command is to be interpreted as a pattern. If no pattern is given on the same line as the f then the last pattern is used. f pattern means find the next instance of pattern. (_f _p_a_t_t_e_r_n _n). Finds the next instance of pattern. (_f _p_a_t_t_e_r_n _t). similar to f pattern, except, for example, if the current expression is (cond ..), f cond will look for the next cond, but (f cond t) will 'stay here'. (_f _p_a_t_t_e_r_n _n) _n>_0. Finds the nth place that pattern matches. If the current expression is (foo1 foo2 foo3), (f f00@ 3) will find foo3. (_f _p_a_t_t_e_r_n) _o_r (_f _p_a_t_t_e_r_n _n_i_l). only matches with elements at the top level of the current expression. If the current expression is (_p_r_o_g _n_i_l (_s_e_t_q _x (_c_o_n_d & &)) (_c_o_n_d &) ...) f (cond --) will find the cond inside the setq, whereas (f (cond --)) will find the top level cond, i.e., the second one. PS2:9-200 The Franz Lisp Manual (_s_e_c_o_n_d . $) . same as (lc . $) followed by another (lc . $) except that if the first succeeds and second fails, no change is made to the edit chain. (_t_h_i_r_d . $) . Similar to second. (_f_s _p_a_t_t_e_r_n_1 ... _p_a_t_t_e_r_n_n) . equivalent to f pattern1 fol- lowed by f pattern2 ... followed by f pattern n, so that if f pattern m fails, edit chain is left at place pattern m-1 matched. (_f= _e_x_p_r_e_s_s_i_o_n _x) . Searches for a structure eq to expres- sion. (_o_r_f _p_a_t_t_e_r_n_1 ... _p_a_t_t_e_r_n_n) . Searches for an expression that is matched by either pattern1 or ... patternn. _b_f _p_a_t_t_e_r_n . backwards find. If the current expression is (_p_r_o_g _n_i_l (_s_e_t_q _x (_s_e_t_q _y (_l_i_s_t _z))) (_c_o_n_d ((_s_e_t_q _w --) --)) --) f list followed by bf setq will leave the current expression as (setq y (list z)), as will f cond followed by bf setq (_b_f _p_a_t_t_e_r_n _t). backwards find. Search always includes current expression, i.e., starts at end of current expres- sion and works backward, then ascends and backs up, etc. ____________________________________________________________ _1_6._3._1._1. _L_o_c_a_t_i_o_n _S_p_e_c_i_f_i_c_a_t_i_o_n_s Many editor commands use a method of specifying position called a location specification. The meta- symbol $ is used to denote a location specifica- tion. $ is a list of commands interpreted as described above. $ can also be atomic, in which case it is interpreted as (list $). a location specification is a list of edit commands that are executed in the normal fashion with two exceptions. first, all commands not recognized by the editor are interpreted as though they had been preceded by f. The location specification (cond 2 3) specifies the 3rd element in the first clause of the next cond. the if command and the ## function provide a way of using in location specifications arbitrary predicates applied to elements in the current expression. In insert, delete, replace and change, if $ is The Franz Lisp Manual PS2:9-201 nil (empty), the corresponding operation is per- formed on the current edit chain, i.e. (replace with (car x)) is equivalent to (:(car x)). for added readability, here is also permitted, e.g., (insert (print x) before here) will insert (print x) before the current expression (but not change the edit chain). It is perfectly legal to ascend to insert, replace, or delete. for example (insert (_r_e_t_u_r_n) after ^ prog -1) will go to the top, find the first prog, and insert a (_r_e_t_u_r_n) at its end, and not change the current edit chain. The a, b, and : commands all make special checks in e1 thru em for expressions of the form (## . coms). In this case, the expression used for inserting or replacing is a copy of the current expression after executing coms, a list of edit commands. (insert (## f cond -1 -1) after3) will make a copy of the last form in the last clause of the next cond, and insert it after the third element of the current expres- sion. $. In descriptions of the editor, the meta- symbol $ is used to denote a location specifica- tion. $ is a list of commands interpreted as described above. $ can also be atomic. ____________________________________________________________ _L_O_C_A_T_I_O_N _C_O_M_M_A_N_D _S_U_M_M_A_R_Y (_l_c . $) . Provides a way of explicitly invoking the loca- tion operation. (lc cond 2 3) will perform search. (_l_c_l . $) . Same as lc except search is confined to current expression. To find a cond containing a _r_e_t_u_r_n, one might use the location specification (cond (lcl _r_e_t_u_r_n) ) where the would reverse the effects of the lcl command, and make the final current expression be the cond. ____________________________________________________________ _1_6._3._2. _T_h_e _E_d_i_t _C_h_a_i_n The edit-chain is a list of which the first element is the the one you are now editing ("current expression"), the next element is what would become the current expression if you were to do a 0, etc., until the last element which is the expression that was passed to the editor. PS2:9-202 The Franz Lisp Manual ____________________________________________________________ _E_D_I_T _C_H_A_I_N _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _m_a_r_k . Adds the current edit chain to the front of the list marklst. _ . Makes the new edit chain be (car marklst). (_ _p_a_t_t_e_r_n) . Ascends the edit chain looking for a link which matches pattern. for example: __ . Similar to _ but also erases the mark. \ . Makes the edit chain be the value of unfind. unfind is set to the current edit chain by each command that makes a "big jump", i.e., a command that usually performs more than a single ascent or descent, namely ^, _, __, !nx, all com- mands that involve a search, e.g., f, lc, ::, below, et al and and themselves. if the user types f cond, and then f car, would take him back to the cond. another would take him back to the car, etc. \_p . Restores the edit chain to its state as of the last print operation. If the edit chain has not changed since the last printing, \p restores it to its state as of the printing before that one. If the user types p followed by 3 2 1 p, \p will return to the first p, i.e., would be equivalent to 0 0 0. Another \p would then take him back to the second p. ____________________________________________________________ _1_6._4. _P_r_i_n_t_i_n_g _C_o_m_m_a_n_d_s ____________________________________________________________ _P_R_I_N_T_I_N_G _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _p Prints current expression in abbreviated form. (p m) prints mth element of current expression in abbreviated form. (p m n) prints mth element of current expression as though printlev were given a depth of n. (p 0 n) prints current expression as though printlev were given a depth of n. (p cond 3) will work. ? . prints the current expression as though printlev were given a depth of 100. 9 9 The Franz Lisp Manual PS2:9-203 _p_p . pretty-prints the current expression. _p_p*. is like pp, but forces comments to be shown. ____________________________________________________________ _1_6._5. _S_t_r_u_c_t_u_r_e _M_o_d_i_f_i_c_a_t_i_o_n _C_o_m_m_a_n_d_s All structure modification commands are undoable. See _u_n_d_o. ____________________________________________________________ _S_T_R_U_C_T_U_R_E _M_O_D_I_F_I_C_A_T_I_O_N _C_O_M_M_A_N_D _S_U_M_M_A_R_Y # [_e_d_i_t_o_r _c_o_m_m_a_n_d_s] (n) n>1 deletes the corresponding ele- ment from the current expression. (_n _e_1 ... _e_m) _n,_m>_1 replaces the nth element in the current expression with e1 ... em. (-_n _e_1 ... _e_m) _n,_m>_1 inserts e1 ... em before the n ele- ment in the current expression. (_n _e_1 ... _e_m) (the letter "n" for "next" or "nconc", not a number) m>1 attaches e1 ... em at the end of the current expression. (_a _e_1 ... _e_m) . inserts e1 ... em after the current expression (or after its first element if it is a tail). (_b _e_1 ... _e_m) . inserts e1 ... em before the current expression. to insert foo before the last element in the current expression, perform -1 and then (b foo). (: _e_1 ... _e_m) . replaces the current expression by e1 ... em. If the current expression is a tail then replace its first element. _d_e_l_e_t_e _o_r (:) . deletes the current expression, or if the current expression is a tail, deletes its first element. (_d_e_l_e_t_e . $). does a (lc . $) followed by delete. current edit chain is not changed. (_i_n_s_e_r_t _e_1 ... _e_m _b_e_f_o_r_e . $) . similar to (lc. $) fol- lowed by (b e1 ... em). (_i_n_s_e_r_t _e_1 ... _e_m _a_f_t_e_r . $). similar to insert before PS2:9-204 The Franz Lisp Manual except uses a instead of b. (_i_n_s_e_r_t _e_1 ... _e_m _f_o_r . $). similar to insert before except uses : for b. (_r_e_p_l_a_c_e $ _w_i_t_h _e_1 ... _e_m) . here $ is the segment of the command between replace and with. (_c_h_a_n_g_e $ _t_o _e_1 ... _e_m) . same as replace with. ____________________________________________________________ _1_6._6. _E_x_t_r_a_c_t_i_o_n _a_n_d _E_m_b_e_d_d_i_n_g _C_o_m_m_a_n_d_s ____________________________________________________________ _E_X_T_R_A_C_T_I_O_N _A_N_D _E_M_B_E_D_D_I_N_G _C_O_M_M_A_N_D _S_U_M_M_A_R_Y (_x_t_r . $) . replaces the original current expression with the expression that is current after performing (lcl . $). (_m_b_d _x) . x is a list, substitutes the current expression for all instances of the atom * in x, and replaces the current expression with the result of that substitution. (mbd x) : x atomic, same as (mbd (x *)). (_e_x_t_r_a_c_t $_1 _f_r_o_m $_2) . extract is an editor command which replaces the current expression with one of its subexpres- sions (from any depth). ($1 is the segment between extract and from.) example: if the current expression is (print (cond ((null x) y) (t z))) then following (extract y from cond), the current expression will be (print y). (extract 2 -1 from cond), (extract y from 2), (extract 2 -1 from 2) will all produce the same result. (_e_m_b_e_d $ _i_n . _x) . embed replaces the current expression with a new expression which contains it as a subexpression. ($ is the segment between embed and in.) example: (embed print in setq x), (embed 3 2 in _r_e_t_u_r_n), (embed cond 3 1 in (or * (null x))). ____________________________________________________________ _1_6._7. _M_o_v_e _a_n_d _C_o_p_y _C_o_m_m_a_n_d_s 9 9 The Franz Lisp Manual PS2:9-205 ____________________________________________________________ _M_O_V_E _A_N_D _C_O_P_Y _C_O_M_M_A_N_D _S_U_M_M_A_R_Y (_m_o_v_e $_1 _t_o _c_o_m . $_2) . ($1 is the segment between move and to.) where com is before, after, or the name of a list com- mand, e.g., :, n, etc. If $2 is nil, or (here), the current position specifies where the operation is to take place. If $1 is nil, the move command allows the user to specify some place the current expression is to be moved to. if the current expression is (a b d c), (move 2 to after 4) will make the new current expression be (a c d b). (_m_v _c_o_m . $) . is the same as (move here to com . $). (_c_o_p_y $_1 _t_o _c_o_m . $_2) is like move except that the source expression is not deleted. (_c_p _c_o_m . $). is like mv except that the source expression is not deleted. ____________________________________________________________ _1_6._8. _P_a_r_e_n_t_h_e_s_e_s _M_o_v_i_n_g _C_o_m_m_a_n_d_s The commands presented in this section permit modification of the list structure itself, as opposed to modifying com- ponents thereof. their effect can be described as inserting or removing a single left or right parenthesis, or pair of left and right parentheses. ____________________________________________________________ _P_A_R_E_N_T_H_E_S_E_S _M_O_V_I_N_G _C_O_M_M_A_N_D _S_U_M_M_A_R_Y (_b_i _n _m) . both in. inserts parentheses before the nth element and after the mth element in the current expression. example: if the current expression is (a b (c d e) f g), then (bi 2 4) will modify it to be (a (b (c d e) f) g). (bi n) : same as (bi n n). example: if the current expression is (a b (c d e) f g), then (bi -2) will modify it to be (a b (c d e) (f) g). (_b_o _n) . both out. removes both parentheses from the nth element. example: if the current expression is (a b (c d e) f g), then (bo d) will modify it to be (a b c d e f g). (_l_i _n) . left in. inserts a left parenthesis before the nth element (and a matching right parenthesis at the end of the current expression). example: if the current expres- sion is (a b (c d e) f g), then (li 2) will modify it to be PS2:9-206 The Franz Lisp Manual (a (b (c d e) f g)). (_l_o _n) . left out. removes a left parenthesis from the nth element. all elements following the nth element are deleted. example: if the current expression is (a b (c d e) f g), then (lo 3) will modify it to be (a b c d e). (_r_i _n _m) . right in. move the right parenthesis at the end of the nth element in to after the mth element. inserts a right parenthesis after the mth element of the nth ele- ment. The rest of the nth element is brought up to the level of the current expression. example: if the current expression is (a (b c d e) f g), (ri 2 2) will modify it to be (a (b c) d e f g). (_r_o _n) . right out. move the right parenthesis at the end of the nth element out to the end of the current expres- sion. removes the right parenthesis from the nth element, moving it to the end of the current expression. all elements following the nth element are moved inside of the nth element. example: if the current expression is (a b (c d e) f g), (ro 3) will modify it to be (a b (c d e f g)). (_r _x _y) replaces all instances of x by y in the current expression, e.g., (r caadr cadar). x can be the s- expression (or atom) to be substituted for, or can be a pat- tern which specifies that s-expression (or atom). (_s_w _n _m) switches the nth and mth elements of the current expression. for example, if the current expression is (list (cons (car x) (car y)) (cons (cdr y))), (sw 2 3) will modify it to be (list (cons (cdr x) (cdr y)) (cons (car x) (car y))). (sw car cdr) would produce the same result. ____________________________________________________________ _1_6._8._1. _U_s_i_n_g _t_o _a_n_d _t_h_r_u to, thru, extract, embed, delete, replace, and move can be made to operate on several contiguous ele- ments, i.e., a segment of a list, by using the to or thru command in their respective location specifications. thru and to are intended to be used in conjunction with extract, embed, delete, replace, and move. to and thru can also be used directly with xtr (which takes after a location specification), as in (xtr (2 thru 4)) (from the current expression). 9 9 The Franz Lisp Manual PS2:9-207 ____________________________________________________________ _T_O _A_N_D _T_H_R_U _C_O_M_M_A_N_D _S_U_M_M_A_R_Y ($_1 _t_o $_2) . same as thru except last element not included. ($_1 _t_o). same as ($1 thru -1) ($_1 _t_h_r_u $_2) . If the current expression is (a (b (c d) (e) (f g h) i) j k), following (c thru g), the current expression will be ((c d) (e) (f g h)). If both $1 and $2 are numbers, and $2 is greater than $1, then $2 counts from the beginning of the current expression, the same as $1. in other words, if the current expression is (a b c d e f g), (3 thru 4) means (c thru d), not (c thru f). in this case, the corresponding bi command is (bi 1 $2-$1+1). ($_1 _t_h_r_u). same as ($_1 _t_h_r_u -_1). ____________________________________________________________ _1_6._9. _U_n_d_o_i_n_g _C_o_m_m_a_n_d_s each command that causes struc- ture modification automatically adds an entry to the front of undolst containing the information required to restore all pointers that were changed by the com- mand. The undo command undoes the last, i.e., most recent such command. ____________________________________________________________ _U_N_D_O _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _u_n_d_o . the undo command undoes most recent, structure modification command that has not yet been undone, and prints the name of that command, e.g., mbd undone. The edit chain is then exactly what it was before the 'undone' com- mand had been performed. !_u_n_d_o . undoes all modifications performed during this editing session, i.e., this call to the editor. _u_n_b_l_o_c_k . removes an undo-block. If executed at a non- blocked state, i.e., if undo or !undo could operate, types not blocked. _t_e_s_t . adds an undo-block at the front of undolst. note that test together with !undo provide a 'tentative' mode for editing, i.e., the user can perform a number of changes, and then undo all of them with a single !undo PS2:9-208 The Franz Lisp Manual command. _u_n_d_o_l_s_t [_v_a_l_u_e]. each editor command that causes structure modification automatically adds an entry to the front of undolst containing the information required to restore all pointers that were changed by the command. ?? prints the entries on undolst. The entries are listed most recent entry first. ____________________________________________________________ _1_6._1_0. _C_o_m_m_a_n_d_s _t_h_a_t _E_v_a_l_u_a_t_e ____________________________________________________________ _E_V_A_L_U_A_T_I_O_N _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _e . only when typed in, (i.e., (insert d before e) will treat e as a pattern) causes the editor to call the lisp interpreter giving it the next input as argument. (_e _x) evaluates x, and prints the result. (e x t) same as (e x) but does not print. (_i _c _x_1 ... _x_n) same as (c y1 ... yn) where yi=(eval xi). example: (i 3 (cdr foo)) will replace the 3rd element of the current expression with the cdr of the value of foo. (i n foo (car fie)) will attach the value of foo and car of the value of fie to the end of the current expression. (i f= foo t) will search for an expression eq to the value of foo. If c is not an atom, it is evaluated as well. (_c_o_m_s _x_1 ... _x_n) . each xi is evaluated and its value executed as a command. The i command is not very convenient for computing an entire edit command for execution, since it computes the command name and its arguments separately. also, the i command cannot be used to compute an atomic command. The coms and comsq commands provide more gen- eral ways of computing commands. (coms (cond (x (list 1 x)))) will replace the first element of the current expres- sion with the value of x if non-nil, otherwise do nothing. (nil as a command is a nop.) (_c_o_m_s_q _c_o_m_1 ... _c_o_m_n) . executes com1 ... comn. comsq is mainly useful in conjunction with the coms command. for example, suppose the user wishes to compute an entire list of commands for evaluation, as opposed to computing each command one at a time as does the coms command. he would then write (coms (cons (quote comsq) x)) where x computed The Franz Lisp Manual PS2:9-209 the list of commands, e.g., (coms (cons (quote comsq) (get foo (quote commands)))) ____________________________________________________________ _1_6._1_1. _C_o_m_m_a_n_d_s _t_h_a_t _T_e_s_t ____________________________________________________________ _T_E_S_T_I_N_G _C_O_M_M_A_N_D _S_U_M_M_A_R_Y (_i_f _x) generates an error unless the value of (eval x) is non-nil, i.e., if (eval x) causes an error or (eval x)=nil, if will cause an error. (if x coms1 coms2) if (eval x) is non-nil, execute coms1; if (eval x) causes an error or is equal to nil, execute coms2. (if x coms1) if (eval x) is non-nil, execute coms1; otherwise generate an error. (_l_p . _c_o_m_s) . repeatedly executes coms, a list of commands, until an error occurs. (lp f print (n t)) will attach a t at the end of every print expression. (lp f print (if (## 3) nil ((n t)))) will attach a t at the end of each print expression which does not already have a second argument. (i.e. the form (## 3) will cause an error if the edit command 3 causes an error, thereby select- ing ((n t)) as the list of commands to be executed. The if could also be written as (if (cddr (##)) nil ((n t))).). (_l_p_q . _c_o_m_s) same as lp but does not print n occurrences. (_o_r_r _c_o_m_s_1 ... _c_o_m_s_n) . orr begins by executing coms1, a list of commands. If no error occurs, orr is finished. otherwise, orr restores the edit chain to its original value, and continues by executing coms2, etc. If none of the command lists execute without errors, i.e., the orr "drops off the end", orr generates an error. otherwise, the edit chain is left as of the completion of the first command list which executes without error. ____________________________________________________________ _1_6._1_2. _E_d_i_t_o_r _M_a_c_r_o_s Many of the more sophisticated branching commands in the editor, such as orr, if, etc., are most often used in conjunction with edit macros. The macro feature permits the user to define new commands and PS2:9-210 The Franz Lisp Manual thereby expand the editor's repertoire. (however, built in commands always take precedence over mac- ros, i.e., the editor's repertoire can be expanded, but not modified.) macros are defined by using the m command. (_m _c . _c_o_m_s) for c an atom, m defines c as an atomic command. (if a macro is redefined, its new defini- tion replaces its old.) executing c is then the same as executing the list of commands coms. macros can also define list commands, i.e., commands that take arguments. (m (c) (arg[1] ... arg[n]) . coms) c an atom. m defines c as a list command. executing (c e1 ... en) is then performed by substituting e1 for arg[1], ... en for arg[n] throughout coms, and then executing coms. a list command can be defined via a macro so as to take a fixed or indefinite number of 'arguments'. The form given above specified a macro with a fixed number of argu- ments, as indicated by its argument list. if the of arguments. (m (c) args . coms) c, args both atoms, defines c as a list command. executing (c e1 ... en) is performed by substituting (e1 ... en), i.e., cdr of the command, for args throughout coms, and then executing coms. (m bp bk up p) will define bp as an atomic command which does three things, a bk, an up, and a p. note that macros can use commands defined by macros as well as built in commands in their definitions. for example, suppose z is defined by (m z -1 (if (null (##)) nil (p))), i.e. z does a -1, and then if the current expression is not nil, a p. now we can define zz by (m zz -1 z), and zzz by (m zzz -1 -1 z) or (m zzz -1 zz). we could define a more general bp by (m (bp) (n) (bk n) up p). (bp 3) would perform (bk 3), followed by an up, followed by a p. The com- mand second can be defined as a macro by (m (2nd) x (orr ((lc . x) (lc . x)))). Note that for all editor commands, 'built in' com- mands as well as commands defined by macros, atomic definitions and list definitions are completely independent. in other words, the existence of an atomic definition for c in no way affects the treat- ment of c when it appears as car of a list command, and the existence of a list definition for c in no way affects the treatment of c when it appears as an atom. in particular, c can be used as the name of either an atomic command, or a list command, or both. in the latter case, two entirely different defini- tions can be used. note also that once c is defined as an atomic command via a macro definition, The Franz Lisp Manual PS2:9-211 it will not be searched for when used in a location specification, unless c is preceded by an f. (insert -- before bp) would not search for bp, but instead perform a bk, an up, and a p, and then do the inser- tion. The corresponding also holds true for list com- mands. (_b_i_n_d . _c_o_m_s) bind is an edit command which is useful mainly in macros. it binds three dummy vari- ables #1, #2, #3, (initialized to nil), and then exe- cutes the edit commands coms. note that these bindings are only in effect while the commands are being executed, and that bind can be used recursively; it will rebind #1, #2, and #3 each time it is invoked. _u_s_e_r_m_a_c_r_o_s [_v_a_l_u_e]. this variable contains the users editing macros . if you want to save your mac- ros then you should save usermacros. you should probably also save editcomsl. _e_d_i_t_c_o_m_s_l [_v_a_l_u_e]. editcomsl is the list of "list commands" recognized by the editor. (these are the ones of the form (command arg1 arg2 ...).) _1_6._1_3. _M_i_s_c_e_l_l_a_n_e_o_u_s _E_d_i_t_o_r _C_o_m_m_a_n_d_s ____________________________________________________________ _M_I_S_C_E_L_L_A_N_E_O_U_S _E_D_I_T_O_R _C_O_M_M_A_N_D _S_U_M_M_A_R_Y _o_k . Exits from the editor. _n_i_l . Unless preceded by f or bf, is always a null opera- tion. _t_t_y: . Calls the editor recursively. The user can then type in commands, and have them executed. The tty: command is completed when the user exits from the lower editor (with ok or stop). the tty: command is extremely use- ful. it enables the user to set up a complex operation, and perform interactive attention-changing commands part way through it. for example the command (move 3 to after cond 3 p tty:) allows the user to interact, in effect, within the move command. he can verify for himself that the correct location has been found, or complete the specification "by hand". in effect, tty: says "I'll tell you what you should do when you get there." _s_t_o_p . exits from the editor with an error. mainly for use PS2:9-212 The Franz Lisp Manual in conjunction with tty: commands that the user wants to abort. since all of the commands in the editor are errset protected, the user must exit from the editor via a command. stop provides a way of distinguishing between a successful and unsuccessful (from the user's standpoint) editing ses- sion. _t_l . tl calls (top-level). to return to the editor just use the _r_e_t_u_r_n top-level command. _r_e_p_a_c_k . permits the 'editing' of an atom or string. (_r_e_p_a_c_k $) does (lc . $) followed by repack, e.g. (repack this@). (_m_a_k_e_f_n _f_o_r_m _a_r_g_s _n _m) . makes (car form) an expr with the nth through mth elements of the current expression with each occurrence of an element of (cdr form) replaced by the corresponding element of args. The nth through mth elements are replaced by form. (_m_a_k_e_f_n _f_o_r_m _a_r_g_s _n). same as (makefn form args n n). (_s _v_a_r . $) . sets var (using setq) to the current expres- sion after performing (lc . $). (s foo) will set foo to the current expression, (s foo -1 1) will set foo to the first element in the last element of the current expres- sion. ____________________________________________________________ _1_6._1_4. _E_d_i_t_o_r _F_u_n_c_t_i_o_n_s (editf s_x1 ...) SIDE EFFECT: edits a function. s_x1 is the name of the function, any additional arguments are an optional list of commands. RETURNS: s_x1. NOTE: if s_x1 is not an editable function, editf gen- erates an fn not editable error. 9 9 The Franz Lisp Manual PS2:9-213 (edite l_expr l_coms s_atm)) edits an expression. its value is the last element of (editl (list l_expr) l_coms s_atm nil nil). (editracefn s_com) is available to help the user debug complex edit macros, or subroutine calls to the editor. editracefn is to be defined by the user. whenever the value of editracefn is non-nil, the editor calls the function editracefn before executing each command (at any level), giving it that command as its argument. editracefn is initially equal to nil, and undefined. (editv s_var [ g_com1 ... ]) SIDE EFFECT: similar to editf, for editing values. editv sets the variable to the value returned. RETURNS: the name of the variable whose value was edited. (editp s_x) SIDE EFFECT: similar to editf for editing property lists. used if x is nil. RETURNS: the atom whose property list was edited. (editl coms atm marklst mess) SIDE EFFECT: editl is the editor. its first argument is the edit chain, and its value is an edit chain, namely the value of l at the time editl is exited. (l is a special variable, and so can be examined or set by edit commands. ^ is equivalent to (e (setq l(last l)) t).) coms is an optional list of commands. for interactive edit- ing, coms is nil. in this case, editl types edit and then waits for input from the teletype. (if mess is not nil editl types it instead of edit. for example, the tty: command is essentially (setq l (editl l nil nil nil (quote tty:))).) exit occurs only via an ok, stop, or save command. If coms is not nil, no message is typed, and each member of coms is treated as a command and executed. If an PS2:9-214 The Franz Lisp Manual error occurs in the execution of one of the commands, no error message is printed , the rest of the commands are ignored, and editl exits with an error, i.e., the effect is the same as though a stop com- mand had been executed. If all commands execute successfully, editl returns the current value of l. marklst is the list of marks. on calls from editf, atm is the name of the function being edited; on calls from editv, the name of the vari- able, and calls from editp, the atom of which some property of its property list is being edited. The property list of atm is used by the save command for saving the state of the edit. save will not save anything if atm=nil i.e., when editing arbitrary expressions via edite or editl directly. (editfns s_x [ g_coms1 ... ]) fsubr function, used to perform the same editing operations on several functions. editfns maps down the list of func- tions, prints the name of each function, and calls the edi- tor (via editf) on that function. EXAMPLE: editfns foofns (r fie fum)) will change every fie to fum in each of the functions on foofns. NOTE: the call to the editor is errset protected, so that if the editing of one function causes an error, editfns will proceed to the next func- tion. in the above example, if one of the functions did not contain a fie, the r command would cause an error, but editing would con- tinue with the next function. The value of editfns is nil. (edit4e pat y) SIDE EFFECT: is the pattern match routine. RETURNS: t if pat matches y. see edit-match for defini- tion of 'match'. NOTE: before each search operation in the editor begins, the entire pattern is scanned for atoms or strings that end in at-signs. These are replaced by patterns of the form (cons (quote /@) (explodec atom)). from the The Franz Lisp Manual PS2:9-215 standpoint of edit4e, pattern type 5, atoms or strings ending in at-signs, is really "if car[pat] is the atom @ (at-sign), pat will match with any literal atom or string whose ini- tial character codes (up to the @) are the same as those in cdr[pat]." if the user wishes to call edit4e directly, he must therefore convert any patterns which contain atoms or strings ending in at-signs to the form recognized by edit4e. this can be done via the function editfpat. (editfpat pat flg) makes a copy of pat with all patterns of type 5 (see edit- match) converted to the form expected by edit4e. flg should be passed as nil (flg=t is for internal use by the editor). (editfindp x pat flg) NOTE: Allows a program to use the edit find command as a pure predicate from outside the editor. x is an expression, pat a pattern. The value of edit- findp is t if the command f pat would succeed, nil otherwise. editfindp calls editfpat to con- vert pat to the form expected by edit4e, unless flg=t. if the program is applying editfindp to several different expressions using the same pat- tern, it will be more efficient to call editfpat once, and then call editfindp with the converted pattern and flg=t. (## g_com1 ...) RETURNS: what the current expression would be after executing the edit commands com1 ... starting from the present edit chain. generates an error if any of comi cause errors. The current edit chain is never changed. example: (i r (quote x) (## (cons ..z))) replaces all x's in the current expression by the first cons containing a z. 9 9 CHAPTER 17 Hash Tables _1_7._1. _O_v_e_r_v_i_e_w A hash table is an object that can efficiently map a given object to another. Each hash table is a collection of entries, each of which associates a unique _k_e_y with a _v_a_l_u_e. There are elemental func- tions to add, delete, and find entries based on a par- ticular key. Finding a value in a hash table is rela- tively fast compared to looking up values in, for example, an assoc list or property list. Adding a key to a hash table modifies the hash table, and so it is a descructive operation. There are two different kinds of hash tables: those that use the function _e_q_u_a_l for the comparing of keys, and those that use _e_q, the default. If a key is "eq" to another object, then a match is assumed. Likewise with "equal". _1_7._2. _F_u_n_c_t_i_o_n_s (makeht 'x_size ['s_test]) RETURNS: A hash table of x_size hash buckets. If present, s_test is used as the test to compare keys in the hash table, the default being eq. _E_q_u_a_l might be used to create a hash table where the keys are to be lists (or any lisp object). NOTE: At this time, hash tables are implemented on top of vectors. 9 9PS2:9-216 The Franz Lisp Manual The Franz Lisp Manual PS2:9-217 (hash-table-p 'H_arg) RETURNS: t if H_arg is a hash table. NOTE: Since hash tables are really vectors, the lisp type of a hash table is a vector, so that given a vector, this function will return t. (gethash 'g_key 'H_htable ['g_default]) RETURNS: the value associated the key g_key in hash table H_htable. If there is not an entry given by the key and g_default is specified, then g_default is returned, otherwise, a sym- bol that is unbound is returned. This is so that nil can be a associated with a key. NOTE: _s_e_t_f may be used to set the value assocaited with a key. (remhash 'g_key 'H_htable) RETURNS: t if there was an entry for g_key in the hash table H_htable, nil otherwise. In the case of a match, the entry and associated object are removed from the hash table. (maphash 'u_func 'H_htable) RETURNS: nil. NOTE: The function u_func is applied to every element in the hash table H_htable. The function is called with two arguments: the key and value of an element. The mapped function should not add or delete object from the table because the results would be unpredicable. (clrhash 'H_htable) RETURNS: the hash table cleared of all entries. 9 9 PS2:9-218 The Franz Lisp Manual (hash-table-count 'H_htable) RETURNS: the number of entries in H_htable. Given a new hash table with no entries, this function returns zero. 9 9 The Franz Lisp Manual PS2:9-219 ____________________________________________________ ; make a vanilla hash table using "eq" to compare items... -> (setq black-box (makeht 20)) hash-table[26] -> (hash-table-p black-box) t -> (hash-table-count black-box) 0 -> (setf (gethash 'key black-box) '(the value associated with the key)) key -> (gethash 'key black-box) (the value associated with the key) -> (hash-table-count black-box) 1 -> (addhash 'composer black-box 'franz) composer -> (gethash 'composer black-box) franz -> (maphash '(lambda (key val) (msg "key " key " value " val N)) black-box) key composer value franz key key value (the value associated with the key) nil -> (clrhash black-box) hash-table[26] -> (hash-table-count black-box) 0 -> (maphash '(lambda (key val) (msg "key " key " value " val N)) black-box) nil ; here is an example using "equal" as the comparator -> (setq ht (makeht 10 'equal)) hash-table[16] -> (setf (gethash '(this is a key) ht) '(and this is the value)) (this is a key) -> (gethash '(this is a key) ht) (and this is the value) ; the reader makes a new list each time you type it... -> (setq x '(this is a key)) (this is a key) -> (setq y '(this is a key)) (this is a key) ; so these two lists are really different lists that compare "equal" ; not "eq" -> (eq x y) nil ; but since we are using "equal" to compare keys, we are OK... -> (gethash x ht) (and this is the value) -> (gethash y ht) (and this is the value) ____________________________________________________ PS2:9-220 The Franz Lisp Manual 9 9