Kyoto Common Lisp Report Taiichi Yuasa and Masami Hagiya Research Institute for Mathematical Sciences, Kyoto University Copyright (c) 1985 by the authors. All rights reserved. Preface Kyoto Common Lisp (KCL for short) is a full implementation of the Common Lisp language described in the Common Lisp Reference Manual: Common Lisp: The Language. by Guy L. Steele et al. Digital Press, 1984 All Common Lisp functions, macros, and special forms are defined in KCL, though a few of them have slightly different meanings from those described in the Common Lisp Reference Manual. All such differences are described in this report: If a Common Lisp function (or macro or special form) does not work as described in the Common Lisp Reference Manual and if this report does not describe the difference explicitly, then there must be a bug in KCL. All Common Lisp variables and constants are defined in KCL exactly as described in the Common Lisp Reference Manual. Currently, there are four major versions of KCL: 1. KCL/AOS, under the AOS/VS operating system for Data General's ECLIPSE MV series machines. 2. KCL/VAX, under the Unix 4.2 bsd operating system for Digital Equipment Corporation's VAX 11 series machines. 3. KCL/SUN, under the Unix 4.2 bsd operating system for Sun Microsystems' Sun Workstation. 4. KCL/UST, under the Unix V (Uniplus' version) operating system for Sumitomo Electric Industries and Digital Computer Laboratory's Ustation E15. KCL/AOS is the original version of KCL, which was developed at the Research Institute for Mathematical Sciences (RIMS), Kyoto University, with the cooperation of Nippon Data General Corporation. The other three versions, which are collectively called KCL on Unix, are transplanted versions of KCL/AOS. This report is intended to complement the Common Lisp Reference Manual. This report describes deviations of KCL from Common Lisp, those features specific to KCL, and the implementation-dependent functions of Common Lisp. Acknowledgements The project of KCL was supported by many people affiliated with many institutions. We are very grateful especially to the following people for their contributions to the KCL project. First of all, we are grateful to the contributors to the design of Common Lisp. Prof. Reiji Nakajima at RIMS, Kyoto University, provided us with considerable encouragement and moral support. Nippon Data General Corporation (NDG) helped us implement KCL/AOS. Mr. Teruo Yabe and Mr. Toshiyasu Harada joined us during the first stage of the KCL project and did a lot of coding. Mr. Takashi Suzuki and Mr. Kibo Kurokawa arranged the joint project. NDG is now supporting the distribution of KCL/AOS. Data General Corporation in the United States sent us materials necessary to implement a Common Lisp system, such as the preliminary drafts of the Common Lisp reference manual and benchmark tests for Common Lisp. For the benchmark tests we are indebted to Dr. Richard Gabriel at Stanford University. Dr. Daniel Weinreb at Symbolics answered most of our questions about the language specification. He also sent us the definition of r a t i o n a l i z e written by Dr. Skef Wholey at CMU. We use this definition in KCL without any change. Dr. Carl Hoffman at Symbolics checked the top-level of KCL and gave us advice for improving KCL. He also found some bugs in KCL and fixed them for us. Mr. Naruhiko Kawamura at RIMS developed a Prolog system using the earliest version of KCL/AOS. That was one of the first big projects with KCL and he found many bugs. Mr. Takashi Sakuragawa at RIMS hacked with KCL/AOS and gave us much advice concerning those features specific to KCL. Mr. Tatsuya Hagino at Edinburgh University developed Micro EMACS on which FeCl2, the full-screen editor embedded in KCL/AOS, is based. Mr. Kunihiko Nakamura at Kagawa University converted the assembly language version of Micro EMACS into the C language, which happened to become the prototype of FeCl2. Prof. Akinori Yonezawa at Tokyo Institute of Technology encouraged us to port KCL/AOS to the VAX 11. Mr. Etsuya Shibayama at Tokyo Institute of Technology helped us while we were working with the VAX 11 at the Institute. Hagiwara Laboratory at Kyoto University offered (and is offering) their VAX 11 for finishing transplantation and maintaining KCL/VAX. We got also technical advice from people at Hagiwara Laboratory. Prof. Shuji Doshita at Kyoto University offered the SUN Workstation at his Laboratory and gave us a lot of advice for transplantation to the SUN Workstation. Mr. Takashi Hattori at RIMS gave us useful information about the Motorola 68000, the CPU chip of SUN Workstation. NDG helped us build up the KROFF (K yoto ROFF) system, with which this report was produced. They offered the character font sets from which the font sets used in KROFF were constructed. We also received some technical advice from NDG about the output device of KROFF, i.e., NDG's 5880 series laser beam printers. Incidentally, all the programs that constitute the KROFF system, including tools to maintain KROFF font sets, are written in the Common Lisp language and are running under KCL. Table of Contents Preface Acknowledgements Table of Contents Chapter 1. How to Start and End a KCL Session Chapter 2. Data Types 2.1. Numbers 2.1.1. Integers 2.1.2. Ratios 2.1.3. Floating-point Numbers 2.1.4. Complex Numbers 2.2. Characters 2.2.1. Standard Characters 2.2.2. Line Divisions 2.2.3. Non-standard Characters 2.2.4. Character Attributes 2.2.5. String Characters 2.3. Symbols 2.4. Lists and Conses 2.5. Arrays 2.5.1. Vectors 2.5.2. Strings 2.5.3. Bit-Vectors 2.6. Hash Tables 2.7. Readtables 2.8. Packages 2.9. Pathnames 2.10. Streams 2.11. Random-States 2.12. Structures 2.13. Functions 2.14. Unreadable Data Objects 2.15. Overlap, Inclusion, and Disjointness of Types Chapter 3. Input and Output 3.1. Read Macros 3.2. Input and Output Functions Chapter 4. Memory Management 4.1. Implementation Types 4.2. Heap and Relocatable Areas 4.3. The Garbage Collector 4.4. Allocation Functions 4.5. Storage Information Chapter 5. Debugging Facilities 5.1. The Tracer 5.2. The Stepper 5.3. Errors 5.4. The Break Loop 5.5. Describe and Inspect Chapter 6. The Compiler Chapter 7. Declarations 7.1. Declaration Specifiers 7.2. Significant Type Specifiers 7.3. Treatment of Type Declarations 7.3.1. Variable Allocations 7.3.2. Built-in Functions that Operate on Raw Data Directly 7.3.3. Arguments/Values Passing Chapter 8. Operating System Interface Chapter 9. Macros 9.1. System Macros 9.2. Defmacro Lambda-Lists Chapter 10. The C Language Interface Chapter 11. The Editor Appendix A. KCL Summary Appendix B. An Overview of Kyoto Common Lisp Appendix C. Kyoto Common Lisp Installation Guide C.1. Installation of KCL/AOS C.2. Installation of KCL/VAX C.3. Installation of KCL/SUN C.4. Installation of KCL/UST Chapter 1. How to Start and End a KCL Session KCL on Unix is invoked by the Shell command kcl. % kcl KCL (Kyoto Common Lisp) July 1, 1987 ---------------------- Note to KCL/AOS users ---------------------- KCL/AOS is invoked by the CLI command KCL. ) KCL KCL (Kyoto Common Lisp) July 1, 1987 --------------------------- End of Note ---------------------------- When invoked, KCL will print the banner and initialize the system. The date in the KCL banner identifies the revision of KCL. "July 1, 1987" is the value of the function lisp-implementation-version. If there exists a file named init.lsp in the current working directory, KCL successively evaluates the forms in the file, immediately after the system initialization. The user may set up his or her own KCL environment (e.g., the memory configuration) with init.lsp. After the initialization, KCL enters the top-level loop and prints the prompt '>'. > The prompt indicates that KCL is now ready to receive a form from the terminal and to evaluate it. Usually, the current package (i.e., the value of *package*) is the user package, and the prompt appears as above. If, however, the current package is other than the user package, then the prompt will be prefixed by the package name. package-name> To exit from KCL, call the function bye (or by). >(bye) Bye. % ---------------------- Note to KCL/AOS users ---------------------- In this report, we sometimes assume that KCL is invoked from the Unix Shell. In particular, we use the standard prompt of the Unix Shell '%' in most examples. -------------------------- End of Note ---------------------------- Alternatively, you may type ^D (control-D), i.e., press the key D while pressing down the CNTL key. >^DBye. % The top-level loop of KCL is almost the same as that defined in Section 20.2 of the Common Lisp Reference Manual. Since the input from the terminal is in line mode, each top-level form should be followed by a newline. If more than one value is returned by the evaluation of the top-level form, the values will be printed successively. If no value is returned, then nothing will be printed. >(values 1 2) 1 2 >(values) > When an error is signalled, control will enter the break loop. >(defun foo (x) (bar x)) foo >(defun bar (y) (bee y y)) bar >(foo 'lish) Error: The function BEE is undefined. Error signalled by BAR. Broken at BAR. >> '>>' in the last line is the prompt of the break loop. Like in the top-level loop, the prompt will be prefixed by the current package name, if the current package is other than the user package. To go back to the top-level loop, type :q. >>:q Top level. > See Section 5.4 for the details of the break loop. In KCL on Unix, the terminal interrupt (usually caused by typing ^C (control-C) or by typing DELETE) is a kind of error. It breaks the running program and calls the break level loop. Example: >(defun foo () (do () (nil))) foo >(foo) ^C Correctable error: Console interrupt. Signalled by DO. Broken at FOO. >> ---------------------- Note to KCL/AOS users---------------------- In KCL/AOS, the console interrupt caused by typing ^C (control-C) followed by ^A (control-A) is a kind of error. Typing ^C and ^A breaks the running program and calls the break loop. On the other hand, the console interrupt caused by ^C and ^B (control-B) will immediately terminate KCL. Example: >(defun foo () (do () (nil))) foo >(foo) ^C^A Correctable error: Console interrupt. Signalled by DO. Broken at FOO. >>(foo) ^C^B *ABORT* CONSOLE INTERRUPT ERROR: FROM PROGRAM LEVEL 1 x,kcl ) ---------------------------End of Note---------------------------- Chapter 2. Data Types KCL supports all Common Lisp data types exactly as defined in the Common Lisp Reference Manual. This chapter simply complements Chapter 2 of the Common Lisp Reference Manual, by describing implementation dependent features of Common Lisp data types. Each section in this chapter corresponds to the section in Chapter 2 of the Common Lisp Reference Manual, with the same section title. 2.1. Numbers 2.1.1. Integers Fixnums in KCL are those integers in the range -(2 to the power of 31) to (2 to the power of 31)-1, inclusive. Other integers are bignums. Thus 25 factorial (25!) 15511210043330985984000000 is certainly a bignum in KCL. Common Lisp constants related to integers have the following values in KCL. most-positive-fixnum = 2147483647 = (2 to the power of 31)-1 most-negative-fixnum = -2147483648 = -(2 to the power of 31) boole-1 = 3 boole-2 = 5 boole-and = 1 boole-andc1 = 4 boole-andc2 = 2 boole-c1 = 12 boole-c2 = 10 boole-clr = 0 boole-eqv = 9 boole-ior = 7 boole-nand = 14 boole-nor = 8 boole-orc1 = 13 boole-orc2 = 11 boole-set = 15 boole-xor = 6 See Chapter 12 of the Common Lisp Reference Manual for their meanings. 2.1.2. Ratios There are no implementation-dependent features for ratios. 2.1.3. Floating-Point Numbers KCL provides two distinct internal floating-point formats. One format is short; the other is single and serves also as double and long. The data types single-float, double-float, and long-float are considered to be identical, but short-float is distinct. An expression such as (eql 1.0s0 1.0d0) is false, but (eql 1.0f0 1.0d0) is true. Similarly, (typep 1.0L0 'short-float) is false, but (typep 1.0L0 'single-float) is true. For output purposes all floating-point numbers are assumed to be of short or single format. The floating-point precisions are: Format KCL/AOS KCL/VAX KCL/SUN KCL/UST ---------------------------------------------------------------- Short 24 bits 23 bits 24 bits 24 bits Single 56 bits 55 bits 53 bits 53 bits Double 56 bits 55 bits 53 bits 53 bits Long 56 bits 55 bits 53 bits 53 bits The floating-point exponent sizes are: Format KCL/AOS KCL/VAX KCL/SUN KCL/UST ---------------------------------------------------------------- Short 7 bits 8 bits 8 bits 8 bits Single 7 bits 8 bits 11 bits 11 bits Double 7 bits 8 bits 11 bits 11 bits Long 7 bits 8 bits 11 bits 11 bits There is no "minus zero." (eql 0.0 -0.0) is true. Common Lisp constants related to floating-point numbers have the following values in KCL. most-positive-short-float = - most-negative-short-float = 7.237005s75 (KCL/AOS) 1.701412s38 (KCL/VAX) 3.402823s38 (KCL/SUN and KCL/UST) least-positive-short-float = - least-negative-short-float = 5.397605s-79 (KCL/AOS) 2.938736s-39 (KCL/VAX) 1.401298s-45 (KCL/SUN and KCL/UST) most-positive-long-float = most-positive-double-float = most-positive-single-float = - most-negative-long-float = - most-negative-double-float = - most-negative-single-float = 7.237005577332264f75 (KCL/AOS) 1.701411834604692f38 (KCL/VAX) 1.797693134862315f308 (KCL/SUN and KCL/UST) least-positive-long-float = least-positive-double-float = least-positive-single-float = - least-negative-long-float = - least-negative-double-flo = - least-negative-single-float = 5.397605346934027f-79 (KCL/AOS) 2.938735877055719f-39 (KCL/VAX) 4.940656458412469f-324 (KCL/SUN and KCL/UST) short-float-epsilon = 4.468372s-7 (KCL/AOS) 6.938894s-18 (KCL/VAX) 2.980232s-8 (KCL/SUN and KCL/UST) short-float-negative-epsilon = 2.980232s-8 (KCL/AOS) 6.938894s-18 (KCL/VAX) 2.980232s-8 (KCL/SUN and KCL/UST) long-float-epsilon = double-float-epsilon = single-float-epsilon = 1.110223024625157f-16 (KCL/AOS) 6.938893903907228f-18 (KCL/VAX) 5.5511151231257827f-17 (KCL/SUN and KCL/UST) long-float-negative-epsilon = double-float-negative-epsilon = single-float-negative-epsilon = 6.938893903907228f-18 (KCL/AOS) 6.938893903907228f-18 (KCL/VAX) 5.5511151231257827f-17 (KCL/SUN and KCL/UST) pi = 3.141592653589793 See Chapter 12 of the Common Lisp Reference Manual for their meanings. 2.1.4. Complex Numbers There are no implementation-dependent features for complex numbers. 2.2. Characters 2.2.1. Standard Characters KCL supports all standard and semi-standard characters listed in Section 2.2.1 of the Common Lisp Reference Manual. Non-printing characters have the following character codes. Character Code (in octal) -------------------------------- #\Space 040 #\Newline 012 #\Backspace 010 #\Tab 011 #\Linefeed 012 #\Page 014 #\Return 015 #\Rubout 177 Note that #\Linefeed is synonymous with #\Newline and thus is a member of standard-char. Other semi-standard characters are not members of standard-char. ---------------------- Note to KCL/AOS users---------------------- KCL/AOS uses 025 (in octal) as the character code of #\Backspace. ---------------------------End of Note---------------------------- 2.2.2. Line Divisions Since KCL represents the #\Newline character by a single code 12, problems with line divisions discussed in Section 2.2.2 of the Common Lisp Reference Manual cause no problem in KCL. 2.2.3. Non-standard Characters KCL supports no additional non-standard characters. 2.2.4. Character Attributes The bit and font fields of KCL characters are always 0. Common Lisp constants related to characters have the following values in KCL. char-bits-limit = 1 char-code-limit = 256 char-control-bit = 0 char-font-limit = 1 char-hyper-bit = 0 char-meta-bit = 0 char-super-bit = 0 See Chapter 13 of the Common Lisp Reference Manual for their meanings. 2.2.5. String Characters Since the bit and font fields of KCL characters are always 0, string-char is considered to be identical to character. 2.3. Symbols The print name of a symbol may consist of up to 16777216 (i.e., the value of array-total-size-limit) characters. However, when a symbol is read, the number of characters (not counting escape characters) in the print name is limited to 2048. 2.4. Lists and Conses There are no implementation-dependent features for lists and conses. 2.5. Arrays KCL arrays can have up to 64 ranks. When the value of the Common Lisp variable *print-array* (see Section 22.1.6 of the Common Lisp Reference Manual) is nil, then bit-vectors are printed as #, other vectors are printed as #, and other arrays are printed as #. Common Lisp constants related to arrays have the following values in KCL. array-dimension-limit = 16777216 array-rank-limit = 64 array-total-size-limit = 16777216 See Section 17.1 of the Common Lisp Reference Manual for their meanings. 2.5.1. Vectors In KCL, array elements are represented in one of six ways depending on the type of the array. Array Type Element Representation --------------------------------------------------------------- (array t) and (vector t) a cell pointer (array fixnum) and (vector fixnum) 32 bit signed integer (array string-char) and string 8 bit code (array short-float) and (vector short-float) 32 bit floating point (array long-float) and (vector long-float) 64 bit floating point (array bit) and bit-vector 1 bit bit 2.5.2. Strings A string may consists of up to 16777216 (i.e., the value of array-total-size-limit) characters. However, when a string is read, the number of characters (not counting escape characters) in the string is limited to 2048. 2.5.3. Bit-Vectors There are no implementation-dependent features for bit-vectors. 2.6. Hash Tables All hash tables are printed as #. 2.7. Readtables All readtables are printed as #. 2.8. Packages The following packages are built into KCL. lisp user keyword system compiler The compiler package contains symbols used by the KCL compiler. Other packages are described in Section 11.6 of the Common Lisp Reference Manual. The system package has two nicknames sys and si; system:symbol may be written as sys:symbol or si:symbol. Other packages have no nicknames. Packages are printed as #. 2.9. Pathnames KCL provides a # macro #" that reads a pathname: #"string" is equivalent to (pathname "string"). For example, #"foo.lsp" is equivalent to (pathname "foo.lsp"). The same format is used when a pathname is printed. The initial value of the Common Lisp variable *default-pathname-defaults* is #"" (or, equivalently, (pathname "")). A pathname in the file system of Common Lisp consists of the following six elements: host device directory name type version Among these elements, KCL does not use host, device, and version. That is, when converting a namestring into a pathname, KCL turns these three elements into nil. Conversely, when converting a pathname into a namestring, KCL ignores these three elements. In the sequel, we explain how KCL converts a namestring into a pathname. If a namestring contains one or more periods '.', the last period separates the namestring into the file name and the filetype. "foo.lsp" name: "foo" type: "lsp" "a.b.c" name: "a.b" type: "c" If a namestring ends with a period, the filetype becomes the null string. "foo." name: "foo" type: "" (null string) If a namestring begins with a period, the file name becomes nil. ".lsp" name: nil type: "lsp" If a namestring contains no period, the filetype is nil. "foo" name: "foo" type: nil In a pathname, the file directory is represented as a list. "common/demo/foo.lsp" directory: ("common" "demo") name: "foo" type: "lsp" If a namestring does not contain a directory, the directory component of the pathname is nil. "foo.lsp" directory: nil name: "foo" type: "lsp" In a pathname, the root directory is represented by the keyword :root. "/usr/common/foo.lsp" directory: (:root "usr" "common") name: "foo" type: "lsp" The abbreviation symbols '.' and '..' may be used in a namestring. "./demo/queen.lsp" directory: (:current "demo") name: "queen" type: "lsp" "../../demo/queen.lsp" directory: (:parent :parent "demo") name: "queen" type: "lsp" :current and :parent represent the current directory and the parent directory, respectively. The part of a namestring after the last slash '/' is always regarded as representing the file name and the filetype. In order to represent a pathname with both the name and the filetype nil, end the pathname with a slash. "/usr/common/" directory: (:root "usr" "common") name: nil type: nil "/usr/common/.lsp" directory: (:root "usr" "common") name: nil type: "lsp" '*' in the place of file name or filetype becomes :wild. "*.lsp" name: :wild type: "lsp" "foo.*" name: "foo" type: :wild ----------------------Note to KCL/AOS users---------------------- In KCL/AOS, all the lower-case letters are turned into upper-case letters by pathname conversions. Thus, for example, "foo.lsp" name: "FOO" type: "LSP" KCL/AOS follows the convention of the AOS/VS file system: The symbols '/', '.', '..', and '*' in the examples above should be replaced by ':', '=', '^', and '-', respectively, in KCL/AOS. ---------------------------End of Note---------------------------- 2.10. Streams Streams are printed in the following formats. # An input stream from the file file-name. # An output stream to the file file-name. # An input stream generated by (make-string-input-stream string). # An output stream generated by the function make-string-output-stream # A stream generated by the function make-two-way-stream. # A bidirectional stream generated by the function make-echo-stream. # The stream generated by (make-synonym-stream symbol) # An input stream generated by the function make-concatenated-stream. # An output stream generated by the function make-broadcast-stream. 2.11. Random-States KCL provides a # macro '#$' that reads a random state. #$integer is equivalent to (make-random-state integer). The same format is used when a random state is printed. 2.12. Structures There are no implementation-dependent features for structures. 2.13. Functions An interpreted function (including macro expansion functions) is represented in one of the following formats. (lambda lambda-list . body) A lambda-expression with null lexical environment and with no implicit block around it. This type of function typically appears when '(lambda lambda-list . body) is evaluated. (lambda-block block-name lambda-list . body) A lambda-expression with null lexical environment but with an implicit block around it. This type of function typically appears when (defun function-name lambda-list . body) is evaluated. In this case, block-name is identical to function-name. (lambda-closure env1 env2 env3 lambda-list . body) A lambda-expression with lexical environments but with no implicit block around it. This type of function typically appears when #'(lambda lambda-list) . body) (or, equivalently, (function (lambda lambda-list . body)) ) is evaluated. env1, env2, and env3 represent the variable bindings, the local function/macro definitions, and the tag/block-name establishments, respectively, at the time the closure was created. (lambda-block-closure env1 env2 env3 block-name lambda-list . body) A lambda-expression with lexical environments and with an implicit block around it. Local functions and local macros are represented in this format. env1, env2, and env3 represent the variable bindings, the local function/macro bindings, and the tag/block-name establishments, respectively, at the time the local function/macro was created by flet, labels, or macrolet. The block-name is identical to the local function/macro name. Compiled functions (including compiled macro-expansion functions) are printed in the following formats. # or # Incidentally, the value of (symbol-function special-form-name) is a list, (special . address) if special-form-name names a special form. Common Lisp constants related to functions have the following values in KCL. call-arguments-limit = 64 lambda-list-keywords = (&optional &rest &key &allow-other-keys &aux &whole &environment &body) lambda-parameters-limit = 64 multiple-values-limit = 32 Refer to the Common Lisp Reference Manual for their meanings. 2.14. Unreadable Data Objects There are no implementation-dependent features for unreadable data objects. 2.15. Overlap, Inclusion, and Disjointness of Types In KCL, the types number and array are certainly subtypes of common, since KCL does not extend the set of objects of these types. Chapter 3. Input and Output 3.1. Read Macros The following # macros are introduced in KCL. #" #"string" reads a pathname. #"string" is equivalent to (pathname "string"). #$ #$integer reads a random state. #$integer is equivalent to (make-random-state integer). The # macro '#,' works as described in the Common Lisp Reference Manual, only if it is included in a constant object. The forms immediately after '#,' below will be evaluated when the compiled code is loaded. '#,x '(a b c (d #,e f) g) #(1 2 3 #,(+ a b c) 5 6) #C(0.0 #,(exp 1)) Otherwise, the effect of using '#,' is unpredictable. Note that, when interpreted code is loaded, '#,' has the same effect as the # macro '#.'. 3.2. Input and Output Functions The input and output functions of KCL almost follow the definitions in Chapter 22 of the Common Lisp Reference Manual. Most of the differences come from the fact that, in KCL, input from the terminal is always in line mode and binary I/O is not supported. In KCL, *terminal-io* is a two-way stream from the standard input and to the standard output. The echoing to the terminal is performed by the underlying operating system. In particular, when a disk file is assigned to the standard output, nothing will be echoed at the terminal. Those functions that deviate from the definitions in the Common Lisp Reference Manual are listed below. load pathname &key :print :verbose :if-does-not-exist [Function] If pathname does not specify the filetype of the input file, then load first tries to load a file with the filetype .o, i.e., the fasl file (see Chapter 6). If it fails, then load tries to load a file with the filetype .lsp. KCL assumes that .lsp is the standard filetype for source files. If it fails again, then load will load the specified file with no filetype. load recognizes a file as a fasl file if and only if the filetype of the file is .o. Other files are assumed to be source files. ----------------------Note to KCL/AOS users---------------------- In KCL/AOS, the filetype of fasl files is .fasl (see Chapter 6). Therefore, if the pathname argument does not explicitly specify the filetype, load first tries to load a file with the filetype .fasl. In addition, load recognizes a file as a fasl file if and only if the filetype of the file is .fasl. ---------------------------End of Note---------------------------- open [Function] The argument to the keyword variable :element-type is ignored and :element-type is always bound to the value string-char. close [Function] The keyword variable :abort is always ignored. listen [Function] listen always returns t. read-char-no-hang [Function] read-char-no-hang is equivalent to read-char. clear-input [Function] clear-output [Function] clear-input and clear-output simply return nil without doing anything. read-byte [Function] write-byte [Function] These functions may operate on any stream. They read or write a byte (8 bits) at a time. princ [Function] write-char [Function] write-byte [Function] These functions do not always flush the stream. The stream is flushed when 1. a newline character is written, or 2. the input from the terminal is requested in the case that these functions operate on *terminal-io*. Chapter 4. Memory Management 4.1. Implementation Types Each KCL object belongs to one of the 22 implementation types. The implementation types are shown in Table 4-1 with the corresponding Common Lisp data types. In the table, the compiled functions are divided into two implementation types; cfun is the type of compiled functions without environment, and cclosure is the type of compiled functions with environment (i.e., the type of compiled closures). spice is the type of internal data used by KCL, and does not correspond to any Common Lisp data type. Table 4-1 Implementation Types Implementation Type Common Lisp Data Type ---------------------------------------------------------------- cons cons fixnum fixnum bignum bignum ratio ratio short-float short-float long-float long-float (= double-float = single-float) complex complex character character symbol symbol package package hash-table hash-table array (and array (not vector)) vector (and vector (not string) (not bit-vector)) string string bit-vector bit-vector structure structure stream stream random-state random-state readtable readtable cfun compiled-function without environment cclosure compiled-function with environment spice none Each object is represented by a cell allocated in the heap area of the interpreter. The size of the cell is determined by the implementation type of the object. The implementation types are classified according to the size of the cells for the objects of the type, as shown in Table 4-2. The size of the cells in the same type class is the same. Table 4-2 Classification of Implementation Types Class Implementation Types ---------------------------------------------------------------- 1 cons bignum ratio long-float complex 2 fixnum short-float character random-state readtable spice 3 symbol package 4 array hash-table vector bit-vector stream pathname cclosure 5 string cfun 6 structure For objects of the (implementation) types readtable, symbol, package, array, hash-table, vector, bit-vector, stream, cclosure, string, cfun, and structure, the cell is simply a header of the object. The body of the object is allocated separately from the cell and is managed in a different manner. The memory space occupied by the body of such an object is called a block. A block is either contiguous or relocatable depending on the area in which it is allocated. The difference between the two areas will be explained below. Table 4-3 lists these types, along with the contents of the body and the kind of the block. Table 4-3 Types with Bodies Type Body Block ----------------------------------------------------------- readtable read table contiguous symbol symbol name relocatable package hash table contiguous array array body relocatable or contiguous hash-table hash table relocatable vector vector body relocatable or contiguous bit-vector bit-vector body relocatable or contiguous stream I/O buffer contiguous cclosure code contiguous string string body relocatable or contiguous cfun code contiguous structure structure body relocatable Usually, the body of an array, a vector, a bit-vector, or a string is allocated as a relocatable block. In KCL, the function make-array takes an extra keyword argument :static. If the :static argument is supplied with a non-nil value, then the body of the array is allocated as a contiguous block. 4.2. Heap and Relocatable Areas The memory space of KCL is divided into two parts: the heap area and the relocatable area. Both areas occupy a contiguous space in the memory. Cells of KCL objects are allocated in the heap. KCL divides the heap into pages (1 page = 2048 bytes), and each page consists of cells in the same type class (see Table 4-2). Cells in different type classes are allocated in different pages. Some blocks are also allocated in the heap: They are called contiguous blocks. The pages for contiguous blocks contain only contiguous blocks. Thus each page in the heap is either a page for cells in a particular type class, or a page for contiguous blocks. Blocks not in the heap are called relocatable blocks and are allocated in the relocatable area. The user may specify the maximum number of pages that can be allocated for each type class by calling the KCL specific function allocate. There is also a limit on the number of pages for contiguous blocks; the limit can be altered by calling the KCL specific function allocate-contiguous-pages. The size of the relocatable area is specified by the KCL specific function allocate-relocatable-pages. See Section 4.4 for these functions. In some installations of KCL, the total amount of memory that KCL can use is limited. In such cases, the entire memory may become exhausted before the maximum number of pages for each type class, for contiguous blocks, or for the relocatable area have been allocated. The heap lies in a part of memory with lower address than the relocatable area and there is a "hole" between the two areas (see Figure 4-1). On request for a new page of heap, the page with the lowest address in the hole is used. When the hole is exhausted, the relocatable area is shifted toward the higher address space and a new hole of an appropriate size is created between the two areas. Figure 1 Heap and Relocatable Area lower address higher address ---------------------- - - - 2------------------- | heap | hole | relocatable area | 7--------------------- - - - 8------------------9 4.3. The Garbage Collector The garbage collector of KCL has three levels according to what it collects: 1. cells 2. cells and relocatable blocks 3. cells, relocatable blocks and contiguous blocks. In levels 2 and 3, the relocatable area is shifted to the higher address space to reserve an appropriate number of pages in the hole. For each type class, KCL keeps a free list of unused cells, and when the free list is exhausted, a new page is allocated, or the garbage collector is invoked, depending on whether the maximum number of pages for that class have been allocated or not. The garbage collector does not compactify the heap. That is, cells and contiguous blocks are never moved to another place. Moreover, once a page is allocated for a particular type class or for contiguous blocks, that page will never be freed for other classes, even if the entire page becomes garbage. On the other hand, the relocatable area is compactified during level 2 and level 3 of garbage collection. A relocatable block is really relocatable. The garbage collector is automatically invoked in one of the following situations. The number in the parentheses indicates the level of garbage collection that is performed. * The free list of a certain type class is exhausted after the maximum number of pages have been allocated for that type class (1). * The hole is exhausted (2). * The relocatable area is exhausted after the maximum number of pages have been allocated for the relocatable area (2). * The contiguous blocks are exhausted after the maximum number of pages have been allocated for contiguous blocks (3). The garbage collector is also invoked by the following KCL specific function. gbc x [Function] The garbage collector is invoked with the level specified by x. If x is nil, the garbage collector is invoked for level 1 garbage collection. If x is t, it is invoked for level 3 garbage collection. Otherwise, it is invoked for level 2 garbage collection. 4.4. Allocation Functions The following functions are used to set or inspect the (maximum) number of pages for each type class, for contiguous blocks, or for relocatable blocks. allocate type number [Function] Sets the maximum number of pages for the type class of the implementation type type to number. If more than number pages have already been allocated, an error is signalled. allocated-pages type [Function] Returns the number of pages currently allocated for the type class of the implementation type type. maximum-allocatable-pages type [Function] Returns the current maximum number of pages for type class of the implementation type type . allocate-contiguous-pages number [Function] Sets the maximum number of pages for contiguous blocks to number. allocated-contiguous-pages [Function] Returns the number of pages allocated for contiguous blocks. maximum-contiguous-pages [Function] Returns the current maximum number of pages for contiguous blocks. allocate-relocatable-pages number [Function] Sets the maximum number of pages for relocatable blocks to number. The relocatable area is expanded to number pages immediately. Therefore, "the current maximum number" and "the number of pages allocated" have the same meanings for relocatable blocks. allocated-relocatable-pages [Function] Returns the number of pages allocated for relocatable blocks. If the pages for a particular type class are exhausted after the maximum number of pages for that class have been allocated, and if there remain no free cells (actually, if there remain very few cells), KCL behaves as directed by the value of the KCL specific variable *ignore-maximum-pages*. If the value is nil, then KCL signals a correctable error and enters the break loop. The user can reset the maximum number by calling allocate and then continue the execution of the program by typing :r. Example: >(make-list 100000) Correctable error: The storage for CONS is exhausted. Currently, 531 pages are allocated. Use ALLOCATE to expand the space. Signalled by MAKE-LIST. Broken at FUNCALL. >>(ALLOCATE 'CONS 1000) t >>:r (nil nil nil nil nil nil nil nil nil nil ............ The user can also reset the maximum number of pages for relocatable blocks and for contiguous blocks in a similar manner. On the other hand, if the value of *ignore-maximum-pages* is non-nil, then KCL automatically increments the maximum number of pages for the class by 50 percent. The initial value of *ignore-maximum-pages* is t. 4.5. Storage Information room &optional x [Function] The function room prints the storage information. The argument x is simply ignored and the output of room is always in the same format. room prints the following information: * for each type class * the number of pages so-far allocated for the type class * the maximum number of pages for the type class * the percentage of used cells to cells so-far allocated * the number of times the garbage collector has been called to collect cells of the type class * the implementation types that belong to the type class * the number of pages actually allocated for contiguous blocks * the maximum number of pages for contiguous blocks * the number of times the garbage collector has been called to collect contiguous blocks * the number of pages in the hole * the maximum number of pages for relocatable blocks * the number of times the garbage collector has been called to collect relocatable blocks * the total number of pages allocated for cells * the total number of pages allocated * the number of available pages * the number of pages KCL can use. The number of times the garbage collector has been called is not shown, if the number is zero. In the following example, the maximum of 531 pages have already been allocated for the type class to which cons belongs, but only 16.9 percent of the cells are actually used. The garbage collector was once invoked to collect cells in this type class. >(room) 531/531 16.9% 1 cons bignum ratio long-float complex 3/52 10.4% fixnum short-float character random-state readtable spice 47/65 73.6% symbol package 3/71 32.4% array hash-table vector bit-vector stream pathname cclosure 46/96 98.8% string cfun 1/32 2.3% structure 17/512 contiguous (3 blocks) 14 hole 50 47.4% 2 relocatable 631 pages for cells 712 total pages 14840 pages available 16384 maximum pages > Chapter 5. Debugging Facilities 5.1. The Tracer The Tracer causes selected functions to be traced. When such a traced function is invoked, it prints level > (name arg1...argn) On return from a traced function, it prints < level (name value1... valuen) name is the name of the traced function, args are the arguments, and values are the return values. level is a number which is incremented each time a traced function is invoked and is decremented at the completion of the invocation. Trace print-outs are indented according to the level. In the current version of KCL, macros and special forms cannot be traced. trace {function-name}* [Macro] Causes one or more functions to be traced. function-names must be symbols and they are not evaluated. If a function is called from a compiled function, the call may not produce trace print-outs. If this is the case, the simplest way to get trace print-outs is to recompile the caller with a notinline declaration for the called function (see Chapter 7). trace returns a name list of those functions that were traced by the call to trace. If no function-name is given, trace simply returnsa name list of all the currently traced functions. untrace {function-name}* [Macro] Causes the specified functions to be not traced any more. function-names must be symbols and they are not evaluated. untrace returns a name list of those functions that were untraced by the call to untrace. If no function-name is given, untrace will untraceall the currently traced functions and will return a list of their names. 5.2. The Stepper step form [Macro] Starts evaluating the form in the single-step mode. In this mode, before any form is evaluated, the Stepper will print the form and prompt the user for a Stepper command. The Stepper binds the two variables *print-level* and *print-length* both to 2, so that the current form may not occupy too much space on the screen. A Stepper command will be executed when the user types the single character for the command followed by the required arguments, if any, and presses the newline key. If the user presses the newline key without having typed any character, then the Stepper will assume that the Stepper command n was abbreviated. The Stepper commands are: n Next. Evaluates the current form in the single-step mode. s Skip. Evaluates the current form in the ordinary mode. The single-step mode will be resumed at completion of the evaluation. p Print. Pretty-prints the current form and then prompts again. f fn Function. Evaluates the current form in the ordinary mode until the specified function fn is invoked. If the specified function is not invoked at all, then this command has the same effects as the q command below. q Quit. Evaluates the current form and any other forms in the ordinary mode. e form Eval. Evaluates the specified form in the ordinary mode and prints the resulting values. Then prompts again with the same current form. ? Help. Lists the Stepper commands. 5.3. Errors *break-enable* [Variable] This variable is used to determine whether to enter the break loop (see Section 5.4) when an error occurs. Even the function break checks this variable. Initially, this variable is set to t, and thus an error will invoke the break loop. If the value is nil, functions that cause fatal errors, such as error, will just print an error message and control will return to the top-level loop (or to the current break loop, if already in the break loop). Functions that cause correctable errors, such as cerror, will print an error message and a "continue message", and control will return to the next form. In KCL, backtrace is not part of an error message, but a break loop command will print backtrace. Therefore, if *break-enable* is nil, no backtrace appears on the screen. When the break loop is entered, *break-enable*will be bound to nil. 5.4. The Break Loop The break loop is a read-eval-print loop similar to the top-level loop. In addition to ordinary Lisp forms, the break loop accepts various commands with which the user can inspect and modify the state of the program execution. Each break loop command is identified with a keyword (i.e., a symbol in the keyword package). A break loop command is executed when the user inputs a list whose first element is the keyword that identifies the command. The rest of the list is the arguments to the command. They are evaluated before being passed to the command. If the command needs no arguments, then the user may input only the keyword. It is an error if the given keyword does not identify any command. Any other input to the break loop is regarded as an ordinary Lisp form; the form will be evaluated and the resulting values will be printed on the terminal. There can be several instances of the break loop at the same time, and each such instance is identified by a level number. When the break loop is entered during execution in the top-level loop, the break loop instance is given the level number 1. The break loop instance that is entered from the level n break loop is given the level number n+1. The prompt of the level n break loop is n+1 consecutive >'s, occasionally prefixed with the name of the current package. The break loop keeps track of the invocation sequence of functions (including special forms and macro expansion functions), which led up to the break loop from the previous break loop (or from the top-level loop, if the current break loop is level 1). The invocation sequence is maintained in a pushdown stack of events. An event consists of an event function and an event environment. An event function is: 1. an interpreted (i.e., not compiled) function (global function, local function, lambda-expression, or closure), 2. a special form within an interpreted function, 3. a macro expansion function called from an interpreted function, 4. a compiled function called from an interpreted function, or 5. a compiled function called from another compiled function which was compiled while the safety optimize level is 3 or with a notinline declaration for the called function (see Chapter 7). An event is pushed on the event stack when execution of its event function begins, and is poped away at the completion of the execution. An event environment is the 'environment' of the event function at the time the next event is pushed. Actually, an event environment is a pointer to the main stack of KCL. For each interpreted event function (i.e., event function in classes 1, 2, and 3), the pointer points to the first entry of the three contiguous main stack entries that hold the lexical environment of the event function. For each compiled event function (i.e., event function in classes 4 and 5), the pointer is set to the first entry of the main stack area that is used locally by the compiled code. In most cases, the first argument to the compiled function is saved in the first entry, the second argument in the second entry, and so on. The local variables of the function are allocated in the entries following the arguments. However, this is not always the case. Refer to Section 7.3 for variable allocations in compiled functions. By break level commands, the user can choose one of the events as the current event. If the current event function is an interpreted event function, then the break loop evaluates Lisp forms in the lexical environment retrieved from the event environment. In particular, local variables may be referenced by the variable names, local functions and local macros may be invoked as usual, established blocks may be exited from, and tags may be used as the destination of go. If the current function is a compiled function, Lisp forms are evaluated in the null environment. Within the break loop, each event is represented by the event symbol. The :backtrace command, for example, lists events in terms of their event symbols. If the event function is a named function (global or local) or a macro expansion function, then the function or macro name is used as the event symbol. If the event function is a special form, then the name of the special form is used. If the event function is a lambda-expression (or a closure), then the symbol lambda (or lambda-closure) is used. To suppress unnecessary information, the user can hide (or make invisible) some of the events. Invisible events do not appear in the backtrace, for example. Initially, only those events are invisible whose event symbols belong to the system internal package system. When the break loop is entered, the last visible event becomes the current event. The break loop commands are described below. Some of the commands allow abbreviation in the keywords that identify them. For example, the user may abbreviate :current as :c. The break loop commands return no values at all. :current [Break Loop Command] :c [Abbreviated Break Loop Command] Prints the event symbol of the current event. :previous &optional n [Break Loop Command] :p &optional [Abbreviated Break Loop Command] Makes the n-th previous visible event the new current event. Invisible events are not counted. If there are less than n previous events, then the first visible event in the invocation sequence becomes the new current event. n must be a positive integer and the default is 1. :next &optional n [Break Loop Command] :n &optional n [Abbreviated Break Loop Command] Makes the n-th next visible event the new current event. If there are less than n next events, then the last visible event in the invocation sequence becomes the new current event. n must be a positive integer and the default is 1. :backtrace [Break Loop Command] :b [Abbreviated Break Loop Command] Prints the event symbols of all visible events in order. The symbol of the current event is printedin upper-case letters and the event symbols of other events are in lower-case. :help [Break Loop Command] :h [Abbreviated Break Loop Command] Lists the break loop commands. :quit &optional n [Break Loop Command] :q &optional n [Abbreviated Break Loop Command] Returns control to the level n break loop. If n is 0 or if n is omitted, then control will return to the top-level loop. n must be a non-negative integer smaller than the current break level. :resume [Break Loop Command] :r [Abbreviated Break Loop Command] Returns control to the caller of the break loop. If the break loop has been entered from cerror, cerror returns nil as its value and control will resume at that point. Otherwise, this command returns control to the previous break loop (or to the top-level loop, if the current break level is 1). :variables [Break Loop Command] :v [Abbreviated Break Loop Command] Prints the names of the bound variables in the current environment. To see the value of a bound variable, just type the variable name. :functions [Break Loop Command] Prints the names of the local functions and local macros in the current environment. To see the definition of a local function or macro, use the function special form in the usual way. That is, (function name) will return the definition of the local function or macro whose name is name. Local functions and local macros may be invoked as usual. :blocks [Break Loop Command] Prints the names of the blocks established in the current environment. If a block block is established, then the return-from form (return-from block value) works as usual. That is, the block form that established block will return value as its value and control will resume at that point. :tags [Break Loop Command] Prints the tags established in the current environment. If a tag tag is established, then the go form (go tag) works as usual. That is, control will resume at the position of tag in the surrounding tagbody. :local &optional n [Break Loop Command] :l &optional n [Abbreviated Break Loop Command] If n is 0 or if it is omitted, then this command prints the value stored in the main stack entry that is pointed to by the current event environment. n is an offset from that entry. If n is positive, then the value of the n-th next (i.e., toward the top of the main stack) entry is printed. If n is negative, then the value of the | n |-th previous (i.e., toward the bottom of the main stack) entry is printed. n must be an integer. It is an error if the specified entry does not lie between the bottom and the top of the stack. :hide symbol [Break Loop Command] Hides all events whose event symbol is symbol. In particular, by (:hide 'lambda) and (:hide 'lambda-closure), all events become invisible whose event functions are lambda-expressions and closures, respectively. If the event symbol of the current event happens to be symbol, then the last previous visible event will become the new current event. symbol must be a symbol. Events of eval and evalhook may never become invisible and attempts to hide them are simply ignored. It is always the case that the first event function is either evalor evalhook. Keeping both of them visible is the simplest way to avoid the silly attempts of the user to hide all events. :hide-package package [Break Loop Command] Hides all events whose event symbol belongs to the package package. package may be any object that represents a package, i.e., a package object, a symbol, or a string. If the event symbol of the current event happens to belong to the package package, then the last previous visible event will become the new current event. Even if lisp package was specified as package, events of eval and evalhook do not become invisible. See the description of :hide above. :unhide symbol [Break Loop Command] :unhide is the inverse command of :hide. If, however, symbol belongs to one of the :hide-package'd packages, events of symbol become visible only after the package is :unhide-package'd. symbol must be a symbol. :unhide-package package[Break Loop Command] :unhide-package is the inverse command of :hide-package. However, an event whose event symbol belongs to package becomes visible only after the symbol is :unhide'd, if the symbol was :hide'd before. package may be any object that represents a package, i.e., a package object, a symbol, or a string. Example: >(defun fact (x) (if (= x 0) one (* x (fact (1- x))))) fact ;;; Wrong definition for fact, the factorial. >(fact 6) ;;; Tries to calculate factorial 6. Error: The variable ONE is unbound. Error signalled by IF. Broken at IF. ;;; Enters the break-loop. >>:h ;;; Help. :c(urrent) Shows the current function. :p(revious) To the previous function. :n(ext) To the next function. :b(acktrace) Prints backtrace. :h(elp) Help. :q(uit) Returns to top-level. :r(esume) Returns to the caller of break-level. :l(ocal) Shows the n-th local value on the stack. :v(ariables) Shows local variables. :functions Shows local functions. :blocks Shows block names. :tags Shows tags. :(un)hide(-package) (Un)hide a function (or a package). >>:b ;;; Backtrace. Backtrace: eval > fact > if > fact > if > fact > if > fact > if > fact > if > fact > if > fact > IF >>:p ;;; Moves to the previous event. Broken at FACT. >>:b ;;; Now inside of fact but outside of if. Backtrace: eval > fact > if > fact > if > fact > if > fact > if > fact > if > fact > if > FACT > if >>:v ;;; Shows local variables. Local variables: x. >>x ;;; The value of x is 0. 0 >>:blocks ;;; Shows blocks. Block names: fact. >>(return-from fact 1) ;;; Returns from the fact block with value 1. 720 ;;; Now the correct answer. > ;;; Top-level. 5.5. Describe and Inspect describe object [Function] Prints the information about object to the stream that is the value of *standard-output*. The description of an object consists of several fields, each of which is described in a recursive manner. For example, a symbol may have fields such as home package, variable documentation, value, function documentation, function binding, type documentation, deftype definition, properties. inspect object [Function] Prints the information about object in an interactive manner. The output of inspect is similar to that of describe, but after printing the label and the value of a field (the value itself is not describe'd), it prompts the user to input a one-character command. The input to inspect is taken from the stream that is the value of *query-io*. Normally, the inspection of object terminates after all of its fields have been inspected. The following commands are supported: n Next. Goes to the next level; the field is inspected recursively. s Skip. Skips the inspection of the field. inspect proceeds to the next field. p Print. Pretty-prints the field and prompts again. u form Update. The form is evaluated and the field is replaced by the resulting value. If the field cannot be updated, the message Not updated. will be printed. a Abort. Aborts the inspection of the current object. The field and the rest of the fields are not inspected. e form Eval. Evaluates the specified form in the null environment and prints the resulting values. Then prompts again with the same field. q Quit. Aborts the entire inspection. ? Help. Lists the inspect commands. Chapter 6. The Compiler The KCL compiler translates a Lisp program stored in a source file into a C-language program, invokes the C-language compiler to compile the C-language program, and then generates an object file, called fasl file (or o-file because of the actual filetype). The compiled program in a fasl file is loaded by the function load. Ordinarily, the object program generated by the KCL compiler scarcely does runtime error-checking for runtime efficiency. In addition, Lisp functions in the same source file are linked together and some system functions are open-coded in-line. To control runtime error checking, supply appropriate optimize declarations (see Section 7.1). The KCL compiler processes the eval-when special form exactly as specified in the Common Lisp Reference Manual. However, all top-level forms in the source file are normally processed in compile-time-too mode, not in not-compile-time mode (see Section 5.3.3 of the Common Lisp Reference Manual). That is, each top-level form top-level-form is processed as if it were surrounded by the eval-when special form with the situations compile, load, and eval. (eval-when (compile load eval) top-level-form) There is no exception for this rule. Thus, for instance, in the example of set-macro-character form in Section 5.3.3 of the Common Lisp Reference Manual, the surrounding eval-when form is unnecessary in KCL. If it is desired that each top-level form be processed in not-compile-time mode, change the value of the KCL specific variable *eval-when-compile* as described below. The KCL compiler is invoked by the functions compile-file, compile, and disassemble described below. In addition, the KCL compiler may be invoked directly by the Shell commands lc or lc1. These commands require the file name of the source file as their argument. Both lc and lc1 simply add ".lsp" to the file name argument to obtain the full name of the source file. % lc filename has the same effect as the compiler invocation (compile-file "filename") from within KCL, and % lc1 filename has the same effects as (compile-file "filename" :o-file t :c-file t :h-file t :data-file t). compile-file input-pathname [Function] &key :output-file :o-file :c-file :h-file :data-file compile-file compiles the Lisp program stored in the file specified by input-pathname, and generates a fasl file. Also compile-file generates the following temporary files. Temporary File Contents ------------------------------------------------ c-file C version of the Lisp program h-file The include file referenced in the c-file data-file The Lisp data to be used at load time If files of these names already exist, the old files will be deleted first. Usually, these intermediate files are automatically deleted after execution of compile-file. The input-file is determined in the usual manner (see Section 2.9), except that, if the filetype is not specified, then the default filetype .lsp will be used. The keyword parameter :output-file defines the default directory and the default name to be applied to the output files (i.e., the fasl file and the temporary files). :output-file itself defaults to input-pathname. That is, if :output-file is not supplied, then the directory and the name of the input file will be used as the default directory and the default name for the output files. The filetypes of the output files are fixed as follows. Output File Filetype ---------------------- fasl file .o c-file .c h-file .h data-file .data Each output file can be specified by the corresponding keyword parameter. If the value of the keyword parameter is nil, then the output file will be deleted after execution of compile-file. If the value of the keyword parameter is t, then the output file will be left in the default directory under the default name. Otherwise, the output file will be left in the directory under the name specified by the keyword parameter. The default value of :o-file is t, and the default values of :c-file, :h-file, and :data-file are all nil. Example: (compile-file 'foo) The source file is "FOO.lsp" and the fasl file is "FOO.o" both in the current directory. (compile-file 'foo.lish) The source file is "FOO.LISH" and the fasl file is "FOO.o". (compile-file "/usr/mas/foo" :output-file "/usr/tai/baa") The source file is "foo.lsp" in the directory "/usr/mas", and the fasl file is "baa.o" in the directory "/usr/tai". ----------------------Note to KCL/AOS users---------------------- The compiler of KCL/AOS generates the following output files. Output File Filetype Contents ------------------------------------------------------------ fasl file .fasl The fasl file c-file .c C version of the Lisp program h-file .h The include file referenced in the c-file ob-file .ob The object file generated by the C compiler data-file .data The Lisp data to be used at load time Note that the filetype of the fasl file is .fasl in KCL/AOS. Also note that the compiler of KCL/AOS generates an additional file ob-file. Accordingly, the function compile-file has a slightly different definition: compile-file input-pathname [Function] &key :output-file :fasl-file :c-file :h-file :ob-file :data-file The keyword parameter :fasl-file corresponds to the keyword parameter :o-file in KCL on Unix. In particular, the default value of :fasl-file is t and the default values of :c-file, :h-file, :ob-file, and :data-file are all nil. In KCL/AOS, ) lc1 filename has the same effects as (compile-file "filename" :fasl-file t :c-file t :h-file t :ob-file t :data-file t). Because KCL/AOS follows the convention of the AOS/VS file system, the last example above should be replaced as: (compile-file ":udd:mas:foo" :output-file ":udd:tai:baa") The source file is "FOO.LSP" in the directory ":UDD:MAS", and the fasl file is "BAA.FASL" in the directory ":UDD:TAI". ---------------------------End of Note---------------------------- compile name &optional definition [Function] If definition is not supplied, name should be the name of a not-yet-compiled function. In this case, compile compiles the function, replaces the previous definition of name with the compiled function, and returns name. If definition is supplied, it should be a lambda-expression to be compiled and name should be a symbol. If name is a non-nil symbol, then compile installs the compiled function as the function definition of name and returns name. If name is nil, then compile simply returns the compiled function. The KCL compiler is essentially a file compiler, and forms to be compiled are supposed to be stored in a file. Thus compile actually creates a source file which contains the form designated by the arguments. Then compile calls compile-file to get a fasl file, which is then loaded into KCL. The source file and the fasl file are given the names gazonk.lsp and gazonk.fasl, respectively. These files are not deleted automatically after the execution of compile. disassemble &optional thing &key :h-file :data-file [Function] This function does not actually disassemble. It always calls the KCL compiler and prints the contents of the c-file, i.e., the C-language code, generated by the KCL compiler. If thing is not supplied, or if it is nil, then the previously compiled form by disassemble will be compiled again. If thing is a symbol other than nil, then it must be the name of a not-yet-compiled function, whose definition is to be compiled. In this case, it is an error if the name is associated with a special form or a macro. If thing is a lambda-expression (lambda lambda-list . body), then disassemble first creates a function definition (defun gazonk lambda-list . body) and this definition is compiled. (The function name gazonk has no special meanings. Indeed, the displayed code is essentially independent of the function name.) Otherwise, thing itself will be compiled as a top-level form. In any case, disassemble does not install the compiled function. disassemble returns no value. No intermediate h-file is created if the keyword parameter :h-file is nil or if :h-file is not supplied. Otherwise, an intermediate h-file is created under the name specified by :h-file. Similarly, the intermediate data-file is specified by the keyword parameter :data-file. *eval-when-compile* [Variable] The compiler processes each top-level form in not-compile-time mode if the value of this variable is nil, and in compile-time-too mode, otherwise. See Section 5.3.3 of Common Lisp Reference Manual for these two modes. The initial value of this variable is t. Chapter 7. Declarations KCL supports all kinds of declarations described in the Common Lisp Reference Manual. Any valid declaration will affect the KCL environment in some way or another, although information obtained by declarations, other than special declarations, is mainly used by the KCL compiler. As described in the Common Lisp Reference Manual, Common Lisp declarations are divided into two classes: proclamations and others. A proclamation is a global declaration given by the function proclaim, the top-level macro defvar, or the top-level macro defparameter. Once given, a proclamation remains effective during the KCL session unless it is shadowed by a local declaration or is canceled by another proclamation. Any other declaration is a local declaration and is given only by the special form declare. A local declaration remains in effect only within the body of the construct that surrounds the declaration. In the following nonsensical example borrowed from Chapter 9 of the Common Lisp Reference Manual, (defun nonsense (k x z) (foo z x) (let ((j (foo k x)) (x (* k k))) (declare (inline foo) (special x z)) (foo x j z))) the inline and the special declarations both remain in effect within the surrounding let form. In this case, we say that the let form is the surrounding construct of these declarations. proclamation decl-spec [Function] This function is introduced to KCL so that the user can see currently effective proclamations. The argument decl-spec specifies the proclamation to be checked. It may be any declaration specification that can be a valid argument to the function proclaim. The function proclamation returns t if the specified proclamation is still in effect. Otherwise, it returns nil. For example, >(proclaim '(special *x*)) ;;; The variable *x* is nil ;;; proclaimed to be globally special. >(proclamation '(special *x*)) t >(defvar *y*) ;;; Another way to proclaim a variable nil ;;; to be globally special. >(proclamation '(special *y*)) t the value-type form [Special Form] The KCL interpreter does actually check whether the value of the form conforms to the data type specified by value-type and signals an error if the value does not. The type checking is performed by the function typep. For example, (the fixnum (foo)) is equivalent to (let ((values (multiple-value-list (foo)))) (cond ((endp values) (error "Too few return values.")) ((not (endp (cdr values))) (error "Too many return values.")) ((typep (car values) 'fixnum) (car values)) (t (error "~s is not of type fixnum." (car values))))) On the other hand, the KCL compiler uses the the special form to obtain type information for compiled code optimization. No code for runtime type-checking is embedded in the compiled code. 7.1. Declaration Specifiers KCL recognizes all declaration specifiers defined in the Common Lisp Reference Manual. The syntax of each such declaration specifier is exactly the same as defined in the Common Lisp Reference Manual. In addition, KCL recognizes the object declaration specifier which is specific to KCL. special { variable-name }* [Declaration Specifier] The interpreter and the compiler of KCL both treat special declarations exactly as described in the Common Lisp Reference Manual. type type { variable-name }* [Declaration Specifier] A type proclamation (type type var1 var2 ...) specifies that the dynamic values of the named variables are of the type type. A local type declaration specifies that the variables mentioned are bound by the surrounding construct and have values of the type type during execution of the surrounding construct. The compiler issues a warning if one of the named variables is not bound by the surrounding construct. The information given by type declarations is used by the compiler to optimize the compiled code. The behavior of the compiled code is unpredictable if a wrong type declaration is supplied. The compiler detects certain wrong type declarations at compile time. For example, >(defun foo (x y) (declare (fixnum x) (character y)) (setq x y) ...)) foo >(compile 'foo) ; (defun foo ...) is being compiled. ;; Warning: Type mismatches between x and y. See Section 7.3 for further information on type declarations. type { variable-name }* [Declaration Specifier] (type var1 var2 ...) is equivalent to (type type var1 var2 ...), provided that type is one of the symbols in Table 4-1 of the Common Lisp Reference Manual, other than function. Declaration specifications that begin with function are regarded as function declarations (see below). function function-name argument-types . return-types [Declaration Specifier] A function declaration is used to obtain type information for function call forms. That is, a function declaration specifies the argument and the return types of each form that calls the named function. (defun foo () (declare (function bar (character) fixnum)) (+ (bar (atcholi1)) (bar (atcholi2)))) In this example, the function declaration specifies that the two functions atcholi1 and atcholi2 both return character objects when called within the body of foo, and that the function bar returns fixnum objects when called within the body of foo. The type information given by function declarations is used by the compiler to optimize the compiled code. The behavior of the compiled code is unpredictable if a wrong function declaration is supplied. The compiler detects certain wrong function declarations at compile time. For example, >(defun foo (x) (declare (fixnum x) (function bar (character) fixnum)) (bar x)) foo >(compile 'foo) ; (defun foo ...) is being compiled. ;; Warning: The type of the form x is not character. However, the compiler does not check the number of arguments, and thus, the following function definition will be compiled successfully without any warnings. (defun foo () (declare (function bar (character character) fixnum)) (+ (bar (atcholi1)) (bar (atcholi2) (atcholi3) (atcholi4)))) For this definition, the compiler assumes that the three functions atcholi1, atcholi2, and atcholi3 will return fixnum objects. The return type of atcholi4 is unknown at compile time. The complete syntax of a function declaration is: (function function-name ( { type }* [ { &optional | &rest | &key } { thing }* ] ) { (values { type }* ) | { type }* } ) Although &optional, &rest, and &key markers may appear in the list of argument types, only those types are recognized that appear before any such markers and the rest of the list is simply ignored. Note that functions with &optional, &rest, or &key parameters may still be declared by function declarations because of the use of function declarations mentioned above. The values construct in the specification of return types is almost useless: (function function-name argument-types (values type1 type2 ...)) is equivalent to (function function-name argment-types type1 type2 ...). We, the implementors of KCL wonder why the value construct was introduced in Common Lisp. See Section 7.3 for further information on function declarations. ftype function-type { function-name }* [Declaration Specifier] function-type must be a list whose first element is the symbol function. (ftype (function . rest) function-name-1 ... function-name-n) is equivalent to n consecutive function declarations (function function-name-1 . rest) ... (function function-name-n . rest). notinline { function-name }* [Declaration Specifier] (notinline function1 function2 ...) specifies that the compiler should not compile the named functions in-line. Calls to the named functions can be traced and an event (see Section 5.4) is pushed on the event stack when any one of the named functions is invoked. inline { function-name }* [Declaration Specifier] An inline proclamation cancels currently effective notinline proclamations, and a local inline declaration locally shadows currently effective notinline declarations. >(defun foo (x) (cons (car x) (locally (declare (inline car)) (car x)))) foo >(defun bar (x) (cons (car x) (locally (declare (inline car)) (car x)))) foo >(proclaim '(notinline car)) nil >(compile 'foo) ... >(proclaim '(inline car)) nil >(compile 'bar) ... Usually, primitive functions such as car are compiled in-line. Therefore, in this example, only the first call to car within foo is compiled not in-line, In general, the KCL compiler compiles functions in-line whenever possible. Thus an inline declaration (inline function1 function2 ...) is worthless if none of the named functions have previously been declared to be notinline. ignore { variable-name }* [Declaration Specifier] Usually, the compiler issues a warning if a lexical variable is never referred to. (ignore var1 ... varn) causes the compiler not to issue a warning even if the named variables are never referred to. The compiler issues a warning if one of the named variables is not bound by the surrounding construct, or if a named variable is actually referred to. ignore proclamations are simply ignored. optimize { { (quality value) | quality } }* [Declaration Specifier] KCL supports the four optimize qualities listed in the Common Lisp Reference Manual. speed and compilation-speed are used to set up the optimization switch of the C language compiler which is invoked to compile the C-language code generated by the KCL compiler (see Chapter 6). (optimize (speed n)) and (optimize (compilation-speed m)) are equivalent, where n and m are integers between 0 and 3, and m is equal to 3-n. When a KCL session is started, the speed quality is set to 3. That is, by default, the compiler generates the fastest code in the longest compilation time. The space quality specifies whether the code size is important or not: The compiled code is a little bit larger and faster when compiled with the space quality 0, than when compiled with the space quality 1, 2, or 3. When a KCL session is started, the space quality is set to 0. The safety quality determines how much runtime error checking code should be embedded in the compiled code. If the safety quality is 0, the compiled code scarcely does runtime error checking. If the safety quality is 1, then the compiled code for a function will check the number of arguments to the function at runtime. If the safety quality is 2 or 3, then the compiled code does full runtime error checking. In addition, the highest quality value 3 causes the compiler to treat all functions as if they were declared to be notinline. When a KCL session is started, the safety quality is set to 0. declaration ) { name }* [Declaration Specifier] A declaration declaration is used exactly as specified in the Common Lisp Reference Manual. object { variable-name }* [Declaration Specifier] This is the only declaration specifier that is specific to KCL. (object var1 ... varn) affects only variable bindings and specifies that the named variables can be allocated in the C stack (see Section 7.3). The compiler issues a warning if one of the named variables is not bound by the surrounding construct. object proclamations are simply ignored. 7.2. Significant Type Specifiers Whenever a declaration is encountered, each type specifier (if any) in the declaration is converted to one of the following type specifiers, which are collectively called the significant type specifiers. ------------ fixnum | ------------ character | ------------ short-float | ------------ long-float | t ---- (array t) ------------ (vector t) | -- (array fixnum) ------- (vector fixnum) | -- (array string-char) -- string | -- (array short-float) -- (vector short-float) | -- (array long-float) --- (vector long-float) | -- (array bit) ---------- bit-vector Here, the lines indicate subtype relations; the right type is a subtype of the left type. For instance, (vector t) is a subtype of (array t) and t, and (array t) itself is a subtype of t. However, (array t) and (array string-char) are disjoint types. The function subtypep is used for the conversion to significant type specifiers: If the first value of (subtypep raw-type type) is t for one of the significant type specifiers type, then the type specifier raw-type in the declaration is converted to type. If there are more than one such significant type specifiers, then the type specifier that is a subtype of other specifiers is selected. For example, type specifiers fixnum, (mod 3), and (member 0 1) are all converted to fixnum, though they are also subtypes of t. Because of this type specifier conversion, KCL may sometimes regard two seemingly distinct declarations as the same. For example, the following type declarations are completely equivalent, internally in KCL. (declare (type fixnum x)) (declare (type (mod 3) x)) (declare (type (member 0 1) x)) Type specifiers in declaration specifications passed to the KCL specific function proclamation are also converted to significant type specifiers. Thus, for example, >(proclaim '(function foo (fixnum) fixnum)) nil >(proclamation '(function foo ((mod 3)) (member 0 1))) t >(proclamation '(function foo (number) character)) nil The first call to proclamation returns t because both (mod 3) and (member 0 1) are converted to fixnum before the function type of foo is checked. 7.3. Treatment of Type Declarations KCL has several runtime stacks. One of them is called the value stack which is the "main stack" of KCL: Arguments to functions and resulting values of functions are usually passed via the value stack, lexical variables in compiled code are usually allocated on the value stack, and temporary values during evaluation of nested expressions are usually saved on the value stack. However, if appropriate declarations are supplied to the compiler, the compiled code will use another stack called the C stack, which can be accessed more efficiently than the value stack. In addition, arguments and resulting values passed via the C stack, values of lexical variables allocated on the C stack, and temporary values saved on the C stack may sometimes be represented as raw data instead of pointers to heap-allocated cells. In KCL, even a fixnum object is usually represented as a pointer to a fixnum cell in which the raw datum (i.e., the 32-bit signed integer) for the fixnum is stored. Accessing such raw data on the C stack results in faster compiled code, partly because no pointer deferencing operation is necessary, and partly because no cell is newly allocated on the heap when a new object is created. In contrast, any object on the value stack is represented as a pointer to a heap-allocated cell. One of the deficiencies of the use of the C stack is that raw data on the C stack may sometimes need to be reallocated on the heap. Suppose, in the following example, that the lexical variable x is allocated on the C stack and has always a fixnum raw datum as its value. (The situations in which this occurs will be explained later.) (defun foo () (let ((x 0)) .... (bar x) .... )) Also suppose that the function bar expects its argument to be passed via the value stack rather than via the C stack. (This situation typically occurs when foo and bar are defined in separate source files. See below.) On call to bar, the compiled code of foo will allocate a fixnum cell on the heap and push the pointer to this cell on the value stack as the argument to bar. Another deficiency is that it is sometimes dangerous to allocate a cell pointer onto the C stack. (This occurs when object) declarations are supplied. See below.) The garbage collector of KCL never takes care of cell pointers on the C stack and thus a heap-allocated cell pointed to only from the C stack may be recycled for further use, while the data in the cell is still in use. This is why KCL usually uses the less efficient value stack. In contrast, objects on the value stack are automatically protected against garbage collection. Note that raw data on the C stack need not be protected against garbage collection because they remain alive until the C stack is popped. 7.3.1. Variable Allocations If a lexical variable is declared to be of fixnum, character, short-float, long-float, or their subtypes, then it is allocated on the C stack rather than on the value stack. In addition, the variable always has a raw datum as its value: 32 bit signed integer for fixnums, 8 bit character code with 24 bit padding for characters (remember that the font and bit fields of KCL characters are always 0), 32 bit floating point representation for short-floats, and 64 bit floating point representation for long-floats. Similarly, if a lexical variable is named in an object declaration (see Section 7.1), then it is allocated on the C stack but, in this case, the variable always has a cell pointer as its value. The user is strongly recommended to make sure that objects stored in such an object variable may never be garbage collected unexpectedly. For example, (do ((x (foo) (cdr x))) ((endp x)) (let ((y (car x))) (declare (object y)) (bar y))) this object declaration is completely safe because the value of the variable y is always a substructure of the value of x, which in turn is protected against garbage collection. Incidentally, loop variables of dolist may always be declared as object variables, since the dolist form has essentially the same control structure as the do form above. On the other hand, the result of evaluation of the following form is unpredictable, because the cons cell pointed to from the object variable z may be garbage collected before bar is called. (let ((z (cons x y))) (declare (object z)) (foo (cons x y)) (bar z)) Lexical variables that are not declared to be of fixnum, character, short-float, long-float, or their subtypes, and that are not named in object declarations are usually allocated on the value stack, but may possibly be allocated on the C stack automatically by the compiler. 7.3.2. Built-in Functions that Operate on Raw Data Directly Some built-in Common Lisp functions can directly operate on raw data, if appropriate declarations are supplied. The addition function + is among such functions. (let ((x 1)) (declare (fixnum x)) .... (setq x (+ x 2)) .... ) In the compiled code for this let form, the raw fixnum datum (i.e., the 32 bit signed integer) stored in x is simply incremented by 2 and the resulting 32 bit signed integer is stored back into x. The compiler is sure that the addition for 32 bit signed integers will be performed on the call to +, because the arguments are both fixnums and the return value must be also a fixnum since the value is to be assigned to the fixnum variable. The knowledge of both the argument types and the return type is necessary for this decision: Addition of two fixnums may possibly produce a bignum and addition of two bignums may happen to produce a fixnum value. If either the argument type or the return type were not known to the compiler, the general addition function would be called to handle the general case. In the following form, for example, the compiler cannot be sure that the return value of the multiplication is a fixnum or that the arguments of the addition are fixnums. (setq x (+ (* x 3) 2)) In order to obtain the optimal code, a the special form should surround the multiplication. (setq x (+ (the fixnum (* x 3)) 2)) Built-in Common Lisp functions that can directly operate on raw data are: 1. arithmetic functions such as +, -, 1+, 1-, *, floor, mod, /, and expt. 2. predicates such as eq, eql, equal, zerop, plusp, minusp, =, /=, <, <=, >, >=, char=, char/, char<, char<=, char>, and char>=. 3. sequence processing functions that receive or return one or more fixnum values, such as nth, nthcdr, length, and elt. 4. array access function such as svref, char, schar, and aref (see below). 5. system-internal functions for array update (see below). 6. type-specific functions such as char-code, code-char, and float. As mentioned in Section 2.5.1, array elements are represented in one of the six ways depending on the type of the array. By supplying appropriate array type declarations, array access and update operations can handle raw data stored in arrays. For example, (let ((a (make-array n :element-type 'fixnum)) (sum O)) (declare (type (array fixnum) a) (fixnum sum)) (dotimes (i n) ;;; Array initialization. (declare (fixnum i)) (setf (aref a i) i)) .... (dotimes (i n) ;;;Summing up the elements. (declare (fixnum i)) (setq sum (+ (aref a i) sum ))) .... ) The setf form replaces the i-th element of the array a by the raw fixnum value of i. The aref form retrieves the raw fixnum datum stored in a. This raw datum is then added to the raw fixnum value of the fixnum variable sum, producing the raw fixnum datum to be stored in sum. The similar raw data handling is possible for arrays of types (array fixnum), (vector fixnum), (array string-char), and (vector long-float). 7.3.3.Arguments/Values Passing Function proclamations (function funtion-name (arg-type1 arg-type2...) return-type ) or its equivalents give the compiler the chance to generate the compiled code so that arguments to the named functions and resulted values of the named function be passed via the C stack, thus increasing the efficiency of calls to these functions. Such arguments/values passing via the C stack is possible only if the called function is also defined in the same source file. This is because the code for the called function must have two entries: One entry for arguments/values passing via the C stack and another for arguments/values passing via the value stack. (An ordinary function has only the latter entry.) When the latter entry is used, the arguments on the value stack are pushed onto the C stack and then the former entry is used to execute the body of the function. On return from the function, the resulted value on the C stack is pushed onto the value stack. This means that ordinary calls to these functions are slower than calls to ordinary functions. One of the merits of arguments/values passing via the C stack is that raw data stored on C-stack-allocated variables can be passed directly to other functions and raw data returned from functions may be directly saved in C-stack-allocated variables or may directly be used as arguments to another function. A good example of this follows: (eval-when (compile) (proclaim '(function tak (fixnum fixnum fixnum) fixnum))) (defun tak (x y z) (declare (fixnum x y z)) (if (not (< y x)) z (tak (tak (1- x) y z) (tak (1- y) z x) (tak (1- z) x y)))) ;;; Call (tak 18 12 6). When tak is called with the arguments 18, 12, and 6, the raw fixnum data of the arguments are set to the parameters x, y, z which are allocated on the C stack. After that, only raw data on the C stack are used to perform the execution: No cell pointers are newly allocated nor even referenced. Arguments and resulted values for recursive calls to tak are passed via the C stack, and the built-in functions < and 1- directly operate on the raw data. Only at the return from the top-level call of tak, the resulted raw data value (which happens to be 7) is reallocated on the heap. Note that both the functions proclamation and the local fixnum declaration are necessary to obtain the optimal code. The function proclamation is necessary for arguments/values passing via the C stack and the fixnum declarations is necessary to allocate the parameters onto the C stack. Chapter 8. Operating System Interface KCL provides the following facilities that are not defined in the Common Lisp Reference Manual. save filename [Function] save saves the current memory image into a program file filename. After saving the memory image, the KCL process terminates immediately. To execute the saved program file, specify the full pathname of the file, as indicated in the example below. ---------------------------Note to KCL/AOS Users----------------------------- In KCL/AOS, if the filename does not contain the filetype .pr, then the program file is given the name filename.pr. Also save saves a symbol table file with the filetype .st. When the program file is executed, execution begins at the top-level of KCL. Even if there were streams that were open at the call of save, these streams are not effective when the program file is executed. The function save of KCL/AOS does no terminate the KCL process. -------------------------End of Note------------------------------------ Example: >(defun plus (x y) (+x y)) plus >(save "savefile") % %pwd /usr/hagiya/savefile >(plus 2 3) 5 >(bye) Bye. % -------------------Note to KCL/AOS users-------------------------- Here is the example of save in KCL/AOS. >(defun plus (x y) (+x y)) plus >(save "savefile") t >(bye) Bye. ) ) X SAVEFILE >(plus 2 3) 5 >(bye) Bye. ) ----------------------------End of Note------------------------------- system string [Function] Executes a Shell command as if string is an input to the Shell. On return from the Shell command, system returns the exit code of the command as an integer. ----------------------Note to KCL/AOS Users----------------------- This function is not suppported in KCL/AOS. Use instead those functions specific to KCL/AOS described below. -------------------------End of Note-------------------------------- bye &optional exit-code [Function] by &optional exit-code [Function] Terminates KCL and returns the exit-code to the parent process. exit-code must be an integer and its default value is O. -----------------------Note to KCL/AOS Users-------------------------- The functions bye and by of KCL/AOS accept a string instead of an exit-code. If string is supplied, these functions return the string to the father as the termination message. ---------------------------End of Note----------------------------- The following functions process, termination-message, and last-termination-message are specific to KCL/AOS and are not supported in KCL on Unix. process progname &optional ipc-message [Function] &key :block :console :debug :dir :input :output :username :list :data :ioc This function is defined only in KCL/AOS. process creates a process in the way as specified by its arguments. progname The name of the process to create. Must be a string ipc-message The IPC message passed to the process. Must be a string. Arguments in the message must be separated with commas `,'. :block If non-nil, Kcl blocks its execution while the son executes. Defaults to t. :console The name of the file to be associated to @console. Must be a string. No file is associated if :console is not specified and if the :ioc argument (see below) is specified with a non-nil value. :console supercedes :ioc. :debug If non-nil, the son runs in the debug mode. :input The name of the file to be associated to @input. Must be string. No file is associated if :input is not specified and if the :ioc argument (see below) is specified with a non-nil value. :input supercedes :ioc. :output The name of the file to be associated to @output. Must be a string. No file is associated if :output is not specified and if the :ioc argument (see below) is specified with a non-nil value. :output supercedes :ioc. :username The user-name of sub-process. Must be a string. If not specfied, the current user-name is used. :list If a string, the name of the file to be associated to @list is used. If t, the file currently associated to @list is used. If nil, or if not specified, no list file is passed to the son. :data If a string, the name of the file to be associated to @data. If t, the file currently associated to @list is used. If nil, or if not specified, no list file is passed to the son. :ioc If non-nil, current @input, @output, and @console files are passed to the son. If not specified, these files are not passed unless specified by the :console, :input, or :output arguments. Example: >(process ":cli.pr") AOS/VS CLI Rev 03f.03.00.00 01-July-87 12:00:00 )by AOS/VS CLI TERMINATING 01-July-87 12:00:00 t > termination-message [Function] This function is defined only in KCL/AOS. termination-message retruns a string consisting of the termination message of a son. Used in connection with the function process. last-termination-message [Function] This function is defined only in KCL/AOS. last-termination-message flushes all the messages currently spooled and returns the last termination message. Chapter 9. Macros 9.1. System Macros The KCL interpreter implements the following system macros as if they were special forms. That is, macro forms of the following macros are directly evaluated without being macro-expanded. and case cond decf defmacro defun do do* dolist dotimes incf locally loop multiple-value-bind multiple-value-list multiple-value-setq or pop prog prog* prog1 prog2 psetq push return setf unless when For these macro forms, the functions macro-function and special-form-p both return non-nil values: macro-function returns the macro expansion function and special-form-p returns t. Of course, functions such as macroexpand and macroexpand-1 will successfully expand macro forms for these system macros. 9.2. Defmacro Lambda-Lists A defmacro lambda-list is a lambda-list-like construct that is used as the third element in the defmacro form, (defmacro name defmacro-lambda-list {declaration | doc-string}* {form}* ) The description of defmacro lambda-lists in the Common Lisp Reference Manual is quite ambiguous. KCL employs the following syntax. The complete syntax of a defmacro lambda-list is: ( [ &whole var ] [ &environment var ] { pseudo-var }* [ &optional { var | ( pseudo-var [ initform [ pseudo-var ] ] ) }* ] { [ { &rest | &body } pseudo-var ] [ &key { var | ( { var | ( keyword pseudo-var ) } [ initform [ pseudo-var ] ] ) }* [ &allow-other-keys ] ] [ &aux { var | ( pseudo-var [ initform ] ) }* ] | . var } ) where pseudo-var is either a symbol or a list of the following form: ( { pseudo-var }* [ &optional { var | ( pseudo-var [ initform [ pseudo-var ] ] ) }* ] { [ { &rest | &body } pseudo-var ] [ &key { var | ( { var | ( keyword pseudo-var ) } [ initform [ pseudo-var ] ] ) }* [ &allow-other-keys ] ] [ &aux { var | ( pseudo-var [ initform ] ) }* ] | . var } ) The defmacro lambda-list keyword &whole may appear only at the top-level, first in the defmacro lambda-list. It is not allowed within pseudo-var. Use of the &whole keyword does not affect the processing of the rest of the defmacro lambda-list: (defmacro foo (&whole w x y) ... ) and (defmacro foo (x y) ... ) both bind the variables x and y to the second and the third elements, respectively, of macro forms of foo. The defmacro lambda-list keyword &environment may appear only at the top-level, first in the defmacro lambda-list if &whole is not supplied, or immediately after the variable that follows &whole, if &whole is supplied. &environment is not allowed within pseudo-var. Like &whole, use of &environment does not affect the processing of the rest of the defmacro lambda-list. If an &environment parameter is supplied and if this parameter is not used at all, then the KCL compiler will issue a warning. To suppress the warning, just remove the parameter from the defmacro lambda-list, or add an ignore declaration. The defmacro lambda-list keyword &body is completely equivalent to the &rest keyword. KCL takes no special action for &body parameters. Although useless, KCL allows supplied-p parameters to be destructured. This is useless because supplied-p parameters can never be bound to a non-empty list. Our intention is to stick to the specification in the Common Lisp Reference Manual as far as possible, even if it is silly to do so. Like for ordinary lambda-lists, the interpreter detects invalid arguments to macro expansion functions. When a parameter is destructured, the structure of the corresponding argument is also checked. Such runtime argument checking may or may not be embedded in compiled code, depending on the environment when the code was generated. If the code was generated while the safety optimize level is zero (that is, while the value of (proclamation '(optimize (safety 0))) is t), then the generated code does not perform argument checking at all. Otherwise, the compiled code does check the validity of arguments. Chapter 10. The C Language Interface This chapter describes the facility of KCL to interface the C language and KCL. With this facility, the user can arrange his or her C-language programs so that they can be invoked from KCL. In addition, the user can write Lisp function definitions in the C language to increase runtime efficiency. The basic idea of interfacing the C language is this: As mentioned in Chapter 6, the KCL compiler, given a Lisp source file, creates an intermediate C-language program file, called c-file, which is then compiled by the C-language compiler to obtain the final fasl-file. Usually, the c-file consists of C-language function definitions. The first C-language function in the c-file is the "initializer", which is executed when the fasl file is loaded, and the other C-language functions are the C versions of the Lisp functions (including macro expansion functions) defined in the source file. By using the top-level macros Clines and defCfun described below, the user can direct the compiler to insert his or her own C-language function definitions and/or C-language preprocessor macros such as #define and #include into the c-file. In order that such C-language functions be invoked from KCL, another top-level macro defentry is used. This macro defines a Lisp function whose body consists of the calling sequence to the specified C-language function. The C-language function definitions are placed in the c-file in the order of the corresponding Lisp functions defined in the source file. That is, the C code for the first Lisp function comes first, the C code for the second Lisp function comes second, and so on. If a Clines or defCfun macro form appears between two Lisp function definitions in the source file, then the C code specified by the macro is placed in between the C code for the Lisp functions. We define some terminology here which is used throughout this Chapter. A C-id is either a Lisp string consisting of a valid C-language identifier, or a Lisp symbol whose print-name, with all its alphabetic characters turned into lower case, is a valid C identifier. Thus the symbol foo is equivalent to the string "foo" when used as a C-id. Similarly, a C-expr is a string or a symbol that may be regarded as a C-language expression. A C-type is one of the Lisp symbols int, char, float, double, and object. Each corresponds to a data type in the C language; object is the type of Lisp object and other C-types are primitive data types in the C language. Clines {string}* [Macro] When the KCL compiler encounters a macro form (Clines string1 ... stringn), it simply outputs the strings into the c-file. The arguments are not evaluated and each argument must be a string. Each string may consist of any number of lines, and separate lines in the string are placed in separate lines in the c-file. In addition, each string opens a fresh line in the c-file, i.e., the first character in the string is placed at the first column of a line. Therefore, C-language preprocessor commands such as #define and #include will be recognized as such by the C compiler, if the '#' sign appears as the first character of the string or as the first character of a line within the string. In order to clearly distinguish C code from other parts of Lisp programs, we, the implementors of KCL, make it our rule to start each C code line with a percent sign '%'. We define % as a read macro which returns the rest of the line as a string. For example, ;;; C version of TAK. (Clines % int tak(x, y, z) % int x, y, z; % { if (y >= x) return(z); % else return(tak(tak(x-1, y, z), % tak(y-1, z, x), % tak(z-1, x, y))); % } ) Of course, the user may instead enclose each C code line or the whole C code with double quotes, but we recommend the use of the percent sign read macro. Since the percent sign read macro is not a standard read macro, the users must define this read macro by themselves. We use the following definition. (set-macro-character #\% #'(lambda (stream char) (values (read-line stream))))) Here, the lambda-expression returns the first value of read-line by using values as a filter. When interpreted, a Clines macro form expands to nil. defentry function parameter-list C-function [Macro] defentry defines a Lisp function whose body consists of the calling sequence to a C-language function. function is the name of the Lisp function to be defined, and C-function specifies the C function to be invoked. C-function must be either a list (type C-id) or C-id, where type and C-id are the type and the name of the C function. type must be a C-type or the symbol void which means that the C function returns no value. (object C-id) may be abbreviated as C-id. parameter-list is a list of C-types for the parameters of the C function. For example, the following defentry form defines a Lisp function tak from which the C function tak above is called. (defentry tak (int int int) (int tak)) The Lisp function tak defined by this defentry form requires three arguments. The arguments are converted to int values before they are passed to the C function. On return from the C function, the returned int value is converted to a Lisp integer (actually a fixnum) and this fixnum will be returned as the value of the Lisp function. See below for type conversion between Lisp and the C language. A defentry form is treated in the above way only when it appears as a top-level form of a Lisp source file. Otherwise, a defentry form expands to nil. defla name lambda-list {declaration | doc-string}* {form}* [Macro] When interpreted, defla is exactly the same as defun. That is, (defla name lambda-list . body) expands to (defun name lambda-list . body). However, defla forms are completely ignored by the compiler; no C-language code will be generated for defla forms. The primary use of defla is to define a Lisp function in two ways within a single Lisp source file; one in the C language and the other in Lisp. defla is short for DEFine Lisp Alternative. Suppose you have a Lisp source file whose contents are: ;;; C version of TAK. (Clines % int tak(x, y, z) % int x, y, z; % { if (y >= x) return(z); % else return(tak(tak(x-1, y, z), % tak(y-1, z, x), % tak(z-1, x, y))); % } ) ;;; TAK calls the C function tak defined above. (defentry tak (int int int) (int tak)) ;;; The alternative Lisp definition of TAK. (defla tak (x y z) (if (>= y x) z (tak (tak (1- x) y z) (tak (1- y) z x) (tak (1- z) x y)))) When this file is loaded into KCL, the interpreter uses the Lisp version of the tak definition. Once this file has been compiled, and when the generated fasl file is loaded into KCL, a function call to tak is actually the call to the C version of tak. defCfun header n {element}* [Macro] defCfun defines a C-language function which calls Lisp functions and/or which handles Lisp objects. header is a string consisting of the C code for the optional type-specifier of the C function, the function-declarator of the C function, and the type-decl-list of the parameters to the C function. (For the C-language terminology, refer to The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie.) The rest of the C function definition, i.e., the function-statement, is given by elements. Each element may be a string, in which case the string is treated in the same way as the arguments to the Clines macro. Or else, the element is a list ((name arg1 ... argn) place1 ... placem). The compiler translates this list into a calling sequence to the Lisp function whose name is name. As will be mentioned later, name may be quote, but name may not be the name of any other special form or a macro. The args specify the arguments to the function and the places specify where the values should go. Thus the list-formed element could be regarded as something like the Lisp form: (multiple-value-setq (place1 ... placem) (name arg1 ... argn)). Each arg is a list (C-type C-expr), where C-expr is any C-language expression of the type C-type. If type is object, then arg may be written simply as C-expr. Similarly, each place is a list (C-type C-expr), or it may be abbreviated as C-expr if C-type is object. The C-expr in this case is any lvalue (in the terminology of the C language), i.e., it may be any valid C-language code that can be written at the left side of an assignment. The function call is performed as follows. The args are evaluated, and the values are sent to the specified Lisp function after type conversion from C to Lisp. On return from the called Lisp function, each returned value is assigned to the corresponding place, i.e., the first returned value goes to place1, the second to place2, and so on. If there are more places than the values returned, extra values of nil are assigned to the remaining places. If there are more values than places, the excess values are simply discarded. If necessary, Lisp-to-C type conversion may take place before each returned value is assigned. If the Lisp function is called just for side-effects, then the list-formed element may be abbreviated as a one-level list (name arg1 ... argn). As a special case, if a list-formed element is of the form ((quote value) place), the Lisp object value is assigned to place. Here value may be any Lisp object. The following defCfun form defines the C function silly which adds 100 to the value of the parameter x and prints the result in three different ways. The second argument to defCfun will be described later, and the user may ignore it. (defCfun "silly(x) int x;" 0 % int y; ((+ (int x) (int "100")) (int y)) % printf("\\n%d", y); % y = x+100; (print (int y)) (print (int "x+100")) ) When a C function handles Lisp objects (i.e., data of type object), the user should be careful enough so that the objects may not be garbage-collected. This is because the garbage collector of KCL does not take care of Lisp objects used in the C function. See the following C function which is assumed to return a two-element list consisting of its two arguments. (defCfun "object list2(x,y) object x,y;" 0 % object z; ('nil z) ((cons y z) z) ((cons x z) z) % return(z); ) When invoked, list2 first sets nil to the variable z, conses y to z, and then conses x. Each time cons is called, a new cons cell is allocated and the pointer to this cell is stored in z. However, there is no way to inform the garbage collector that the cells are referenced from the C variable z. Suppose that the cons cell allocated by the first cons is the last cons cell available at that time. Then, during execution of the second call to cons, the garbage collector begins to run and, unfortunately, the cons cell in z will be destroyed so that the cell can be recycled for further use. To prevent a Lisp object from being unexpectedly garbage collected, the user must save the object in some place that is recognized by the garbage collector. The second parameter n to defCfun is used to reserve n such places for each call to the C function. In the body of the C function, these reserved places are referenced as vs[0], ..., vs[n-1]. The function list2 above, therefore, should be revised as follows. (defCfun "object list2(x,y) object x,y;" 1 ('nil "vs[0]") ((cons y "vs[0]") "vs[0]") ((cons x "vs[0]") "vs[0]") % Creturn(vs[0]); ) Notice that return is replaced by Creturn. Creturn is similar to return except that Creturn releases the reserved places on return from the function. In the C code within a defCfun form, write "Creturn(value);" instead of "return(value);", and write "Cexit;" instead of "return;". Again, a defCfun form has the above meaning only when it appears as a top-level form in a Lisp source file. Otherwise, the form expands to nil. KCL converts a Lisp object into a C-language data by using the Common Lisp function coerce: For the C-type int (or char), the object is first coerced to a Lisp integer and the least significant 32-bit (or 8-bit) field is used as the C int (or char). For the C-type float (or double), the object is coerced to a short-float (or a long-float) and this value is used as the C float (or double). Conversion from a C data into a Lisp object is obvious: C char, int, float, and double become the equivalent Lisp character, fixnum, short-float, and long-float, respectively. Here we list the complete syntax of Clines, defentry, and defCfun macro forms. Clines-form: (Clines { string }* ) defentry-form: (defentry function-symbol ( { C-type }* ) C-function-name | ( { C-type | void } C-function-name ) } ) defCfun-form: (defCfun string non-negative-integer { string | (function-symbol { value }* ) | ((function-symbol { value }* ) { place }* ) } ) value: place: { C-expr | (C-type C-expr) } C-function-name: C-expr: { string | symbol } C-type: { object | int | char | float | double } Chapter 11. The Editor KCL/AOS is equipped with a screen editor FeCl2 (Full-screen Editor as a Common Lisp TOOl). FeCl2 is an EMACS-like editor with facilities for Lisp coding. FeCl2 is invoked from KCL by the function ed and the result of editing can be passed to KCL directly. For the details of FeCl2 refer to The FeCl2 Editor Reference Manual. ed &optional filename [Function] ed invokes FeCl2 and sets the edit file of FeCl2 to filename. If the filetype of the file is not explicitly specified, then the filename is first merged into #".lsp". The FeCl2 editor is not supported by other versions of KCL. The function ed of KCL/VAX, KCL/SUN, and KCL/UST calls the vi editor. If you hate vi, define your own ed function using the function system described in Chapter 8. Appendix A. KCL Summary The following table lists all symbols defined in KCL. Each line has the following form. symbol [kind] remark where kind is Function, Macro, Special (i.e., Special form name), Variable, Constant, Symbol, or Keyword. In the table, some symbols are labeled both as a macro and a special form name. This means that, although these symbols are defined to be a macro name in the Common Lisp Reference Manual, KCL treats them as if they were special forms (see Section 9.1). * [Function] * [Variable] ** [Variable] *** [Variable] + [Function] + [Variable] ++ [Variable] +++ [Variable] - [Function] - [Variable] / [Function] / [Variable] // [Variable] /// [Variable] /= [Function] 1+ [Function] 1- [Function] < [Function] <= [Function] = [Function] > [Function] >= [Function] :abort [Keyword] abs [Function] acons [Function] acos [Function] acosh [Function] adjoin [Function] adjust-array [Function] :adjustable [Keyword] adjustable-array-p [Function] allocate [Function] Added. allocate-contiguous-pages [Function] Added. allocated-contiguous-pages [Function] Added. allocated-pages [Function] Added. allocated-relocatable-pages [Function] Added. allocate-relocatable-pages [Function] Added. alpha-char-p [Function] alphanumericp [Function] and [Special, Macro] append [Function] :append [Keyword] apply [Function] applyhook [Function] *applyhook* [Variable] apropos [Function] apropos-list [Function] aref [Function] :array [Keyword] array-dimension [Function] array-dimension-limit [Constant] array-dimensions [Function] array-element-type [Function] array-has-fill-pointer-p [Function] array-in-bounds-p [Function] array-rank [Function] array-rank-limit [Constant] array-row-major-index [Function] array-total-size [Function] array-total-size-limit [Constant] arrayp [Function] ash [Function] asin [Function] asinh [Function] assert [Macro] assoc [Function] assoc-if [Function] assoc-if-not [Function] atan [Function] atanh [Function] atom [Function] :b [Keyword] Abbreviate Break Loop Command. :backtrace [Keyword] Break Loop Command. :base [Keyword] bit [Function] bit-and [Function] bit-andc1 [Function] bit-andc2 [Function] bit-eqv [Function] bit-ior [Function] bit-nand [Function] bit-nor [Function] bit-not [Function] bit-orc1 [Function] bit-orc2 [Function] bit-vector-p [Function] bit-xor [Function] block [Special] :block [Keyword] Added. :blocks [Keyword] Break Loop Command. boole [Function] boole-1 [Constant] boole-2 [Constant] boole-and [Constant] boole-andc1 [Constant] boole-andc2 [Constant] boole-c1 [Constant] boole-c2 [Constant] boole-clr [Constant] boole-eqv [Constant] boole-ior [Constant] boole-nand [Constant] boole-nor [Constant] boole-orc1 [Constant] boole-orc2 [Constant] boole-set [Constant] boole-xor [Constant] both-case-p [Function] boundp [Function] break [Function] *break-on-warnings* [Variable] *break-enable* [Variable] Added. butlast [Function] by [Function] Added. bye [Function] Added. byte [Function] byte-position [Function] byte-size [Function] :c [Keyword] Abbreviated Break Loop Command. caaaar [Function] caaadr [Function] caaar [Function] caadar [Function] caaddr [Function] caadr [Function] caar [Function] cadaar [Function] cadadr [Function] cadar [Function] caddar [Function] cadddr [Function] caddr [Function] cadr [Function] call-arguments-limit [Constant] car [Function] :case [Keyword] case [Special, Macro] catch [Special] ccase [Macro] cdaaar [Function] cdaadr [Function] cdaar [Function] cdadar [Function] cdaddr [Function] cdadr [Function] cdar [Function] cddaar [Function] cddadr [Function] cddar [Function] cdddar [Function] cddddr [Function] cdddr [Function] cddr [Function] cdr [Function] ceiling [Function] cerror [Function] :c-file [Keyword] Added. char [Function] char-bit [Function] char-bits [Function] char-bits-limit [Constant] char-code [Function] char-code-limit [Constant] char-control-bit [Constant] char-downcase [Function] char-equal [Function] char-font [Function] char-font-limit [Constant] char-greaterp [Function] char-hyper-bit [Constant] char-int [Function] char-lessp [Function] char-meta-bit [Constant] char-name [Function] char-not-equal [Function] char-not-greaterp [Function] char-not-lessp [Function] char-super-bit [Constant] char-upcase [Function] char/= [Function] char< [Function] char<= [Function] char= [Function] char> [Function] char>= [Function] character [Function] characterp [Function] check-type [Macro] :circle [Keyword] cis [Function] clear-input [Function] Different. clear-output [Function] Different. clines [Macro] Added. close [Function] Different. clrhash [Function] code-char [Function] coerce [Function] commonp [Function] compilation-speed [Symbol] Optimize Quality. compile [Function] compile-file [Function] compiled-function-p [Function] compiler-let [Special] complex [Function] complexp [Function] :conc-name [Keyword] concatenate [Function] cond [Special, Macro] conjugate [Function] cons [Function] :console [Keyword] Added. consp [Function] constantp [Function] :constructor [Keyword] :copier [Keyword] copy-alist [Function] copy-list [Function] copy-readtable [Function] copy-seq [Function] copy-symbol [Function] copy-tree [Function] cos [Function] cosh [Function] count [Function] :count [Keyword] count-if [Function] count-if-not [Function] :create [Keyword] ctypecase [Macro] :current [Keyword] Break Loop Command. :data [Keyword] Added. :data-file [Keyword] Added. :debug [Keyword] Added. *debug-io* [Variable] decf [Special, Macro] declaration [Symbol] Declaration Specifier. declare [Special] decode-float [Function] decode-universal-time [Function] :default [Keyword] *default-pathname-defaults* [Variable] :defaults [Keyword] defautoload [Macro] Added. defcfun [Macro] Added. defconstant [Macro] defentry [Macro] Added. define-modify-macro [Macro] define-setf-method [Macro] defla [Macro] Added. defmacro [Special, Macro] defparameter [Macro] defsetf [Macro] defstruct [Macro] deftype [Macro] defun [Special, Macro] defvar [Macro] delete [Function] delete-duplicates [Function] delete-file [Function] delete-if [Function] delete-if-not [Function] denominator [Function] deposit-field [Function] describe [Function] :device [Keyword] digit-char [Function] digit-char-p [Function] :dir [Keyword] Added. :direction [Keyword] directory [Function] :directory [Keyword] directory-namestring [Function] disassemble [Function] Different. :displaced-index-offset [Keyword] :displaced-to [Keyword] do [Special, Macro] do* [Special, Macro] do-all-symbols [Macro] do-external-symbols [Macro] do-symbols [Macro] documentation [Function] dolist [Special, Macro] dotimes [Special, Macro] double-float-epsilon [Constant] double-float-negative-epsilon [Constant] dpb [Function] dribble [Function] ecase [Macro] ed [Function] Different. eighth [Function] :element-type [Keyword] elt [Function] encode-universal-time [Function] :end [Keyword] :end1 [Keyword] :end2 [Keyword] endp [Function] enough-namestring [Function] &environment [Symbol] Defmacro-lambda Keyword. eq [Function] eql [Function] equal [Function] equalp [Function] error [Function] :error [Keyword] *error-output* [Variable] :escape [Keyword] etypecase [Macro] eval [Function] evalhook [Function] *evalhook* [Variable] eval-when [Macro] *eval-when-compile* [Variable] Added. evenp [Function] every [Function] exp [Function] export [Function] expt [Function] :external [Keyword] :fasl-file [Keyword] Added. fboundp [Function] fceiling [Function] *features* [Variable] ffloor [Function] fifth [Function] file-author [Function] file-length [Function] file-namestring [Function] file-position [Function] file-write-date [Function] fill [Function] fill-pointer [Function] :fill-pointer [Keyword] find [Function] find-all-symbols [Function] find-if [Function] find-if-not [Function] find-package [Function] find-symbol [Function] finish-output [Function] first [Function] flet [Special] float [Function] float-digits [Function] float-precision [Function] float-radix [Function] float-sign [Function] floatp [Function] floor [Function] fmakunbound [Function] force-output [Function] format [Function] fourth [Function] fresh-line [Function] :from-end [Keyword] fround [Function] ftruncate [Function] ftype [Symbol] Declaration Specifier. funcall [Function] function [Special] Also Declaration Specifier. functionp [Function] :functions [Keyword] Break Loop Command. gbc [Function] Added. gcd [Function] gensym [Function] :gensym [Keyword] gentemp [Function] get [Function] get-decoded-time [Function] get-dispatch-macro-character [Function] get-internal-real-time [Function] get-internal-run-time [Function] get-macro-character [Function] get-output-stream-string [Function] get-properties [Function] get-setf-method [Function] get-setf-method-multiple-value [Function] get-universal-time [Function] getf [Function] gethash [Function] go [Special] graphic-char-p [Function] hash-table-count [Function] hash-table-p [Function] :h [Keyword] Abbreviated Break Loop Command. :help [Keyword] Break Loop Command. :h-file [Keyword] Added. :hide [Keyword] Break Loop Command. :hide-package [Keyword] Break Loop Command. :host [Keyword] host-namestring [Function] identity [Function] if [Special] :if-does-not-exist [Keyword] :if-exists [Keyword] ignore [Symbol] Declaration Specifier. *ignore-maximum-pages* [Variable] Added. imagpart [Function] import [Function] in-package [Function] incf [Special, Macro] :include [Keyword] :index [Keyword] :inherited [Keyword] :initial-contents [Keyword] :initial-element [Keyword] :initial-offset [Keyword] :initial-value [Keyword] inline [Symbol] Declaration Specifier. :input [Keyword] input-stream-p [Function] inspect [Function] int-char [Function] integer-decode-float [Function] integer-length [Function] integerp [Function] intern [Function] :intern [Keyword] internal-time-units-per-second [Constant] intersection [Function] :io [Keyword] :ioc [Keyword] Added. isqrt [Function] :junk-allowed [Keyword] :key [Keyword] keywordp [Function] :l [Keyword] Abbreviated Break Loop Command. labels [Special] lambda-list-keywords [Constant] lambda-parameters-limit [Constant] last [Function] last-termination-message [Function] Added. lcm [Function] ldb [Function] ldb-test [Function] ldiff [Function] least-negative-double-float [Constant] least-negative-long-float [Constant] least-negative-short-float [Constant] least-negative-single-float [Constant] least-positive-double-float [Constant] least-positive-long-float [Constant] least-positive-short-float [Constant] least-positive-single-float [Constant] length [Function] :length [Keyword] let [Special] let* [Special] :level [Keyword] lisp-implementation-type [Function] lisp-implementation-version [Function] list [Function] :list [Keyword] Added. list* [Function] list-all-packages [Function] list-length [Function] listen [Function] Different. listp [Function] load [Function] *load-verbose* [Variable] :local [Keyword] Break Loop Command. locally [Special, Macro] log [Function] logand [Function] logandc1 [Function] logandc2 [Function] logbitp [Function] logcount [Function] logeqv [Function] logior [Function] lognand [Function] lognor [Function] lognot [Function] logorc1 [Function] logorc2 [Function] logtest [Function] logxor [Function] long-float-epsilon [Constant] long-float-negative-epsilon [Constant] long-site-name [Function] loop [Special, Macro] lower-case-p [Function] machine-instance [Function] machine-type [Function] machine-version [Function] macro-function [Function] macroexpand [Function] macroexpand-1 [Function] *macroexpand-hook* [Variable] macrolet [Special] make-array [Function] make-broadcast-stream [Function] make-char [Function] make-concatenated-stream [Function] make-dispatch-macro-character [Function] make-echo-stream [Function] make-hash-table [Function] make-list [Function] make-package [Function] make-pathname [Function] make-random-state [Function] make-sequence [Function] make-string [Function] make-string-input-stream [Function] make-string-output-stream [Function] make-symbol [Function] make-synonym-stream [Function] make-two-way-stream [Function] makunbound [Function] map [Function] mapc [Function] mapcan [Function] mapcar [Function] mapcon [Function] maphash [Function] mapl [Function] maplist [Function] mask-field [Function] max [Function] maximum-allocatable-pages [Function] Added. maximum-contiguous-pages [Function] Added. member [Function] member-if [Function] member-if-not [Function] merge [Function] merge-pathnames [Function] min [Function] minusp [Function] mismatch [Function] mod [Function] *modules* [Variable] most-negative-double-float [Constant] most-negative-fixnum [Constant] most-negative-long-float [Constant] most-negative-short-float [Constant] most-negative-single-float [Constant] most-positive-double-float [Constant] most-positive-fixnum [Constant] most-positive-long-float [Constant] most-positive-short-float [Constant] most-positive-single-float [Constant] multiple-value-bind [Special, Macro] multiple-value-call [Special] multiple-value-list [Special, Macro] multiple-value-prog1 [Special] multiple-value-setq [Special, Macro] multiple-values-limit [Constant] :n [Keyword] Abbreviated Break Loop Command. :name [Keyword] name-char [Function] :named [Keyword] namestring [Function] nbutlast [Function] nconc [Function] :new-version [Keyword] :next [Keyword] Break Loop Command. nil [Constant] nintersection [Function] ninth [Function] not [Function] notany [Function] notevery [Function] notinline [Symbol] Declaration Specifier. nreconc [Function] nreverse [Function] nset-difference [Function] nset-exclusive-or [Function] nstring-capitalize [Function] nstring-downcase [Function] nstring-upcase [Function] nsublis [Function] nsubst [Function] nsubst-if [Function] nsubst-if-not [Function] nsubstitute [Function] nsubstitute-if [Function] nsubstitute-if-not [Function] nth [Function] nthcdr [Function] null [Function] numberp [Function] numerator [Function] nunion [Function] :ob-file [Keyword] Added. object [Symbol] Declaration Specifier. Added. oddp [Function] :o-file [Keyword] Added. open [Function] Different. optimize [Symbol] Declaration Specifier. or [Special, Macro] :output [Keyword] :output-file [Keyword] output-stream-p [Function] :overwrite [Keyword] *package* [Variable] package-name [Function] package-nicknames [Function] package-shadowing-symbols [Function] package-use-list [Function] package-used-by-list [Function] packagep [Function] pairlis [Function] :parent [Keyword] Added. parse-integer [Function] parse-namestring [Function] pathname [Function] pathname-device [Function] pathname-directory [Function] pathname-host [Function] pathname-name [Function] pathname-type [Function] pathname-version [Function] pathnamep [Function] peek-char [Function] phase [Function] pi [Constant] plusp [Function] pop [Macro] position [Function] position-if [Function] position-if-not [Function] pprint [Function] :p [Keyword] Abbreviate Break Loop Command. :predicate [Keyword] :preserve-whitespace [Keyword] :pretty [Keyword] :previous [Keyword] Break Loop Command. prin1 [Function] prin1-to-string [Function] princ [Function] princ-to-string [Function] print [Function] :print [Keyword] *print-array* [Variable] *print-base* [Variable] *print-case* [Variable] *print-circle* [Variable] *print-escape* [Variable] :print-function [Keyword] *print-gensym* [Variable] *print-length* [Variable] *print-level* [Variable] *print-pretty* [Variable] *print-radix* [Variable] :probe [Keyword] probe-file [Function] process [Function] Added. proclaim [Function] proclamation [Function] Added. prog [Special, Macro] prog* [Special, Macro] prog1 [Special, Macro] prog2 [Special, Macro] progn [Special] progv [Special] provide [Function] psetf [Macro] psetq [Special, Macro] push [Special, Macro] pushnew [Macro] :q [Keyword] Abbreviated Break Loop Command. *query-io* [Variable] :quit [Keyword] Break Loop Command. quote [Special] :r [Keyword] Abbreviated Break Loop Command. :radix [Keyword] random [Function] *random-state* [Variable] random-state-p [Function] rassoc [Function] rassoc-if [Function] rassoc-if-not [Function] rational [Function] rationalize [Function] rationalp [Function] read [Function] *read-base* [Variable] read-byte [Function] Different. read-char [Function] read-char-no-hang [Function] Different. *read-default-float-format* [Variable] read-delimited-list [Function] read-from-string [Function] read-line [Function] :read-only [Keyword] read-preserving-whitespace [Function] *read-suppress* [Variable] *readtable* [Variable] readtablep [Function] realpart [Function] reduce [Function] :rehash-size [Keyword] :rehash-threshold [Keyword] rem [Function] remf [Macro] remhash [Function] remove [Function] remove-duplicates [Function] remove-if [Function] remove-if-not [Function] remprop [Function] :rename [Keyword] :rename-and-delete [Keyword] rename-file [Function] rename-package [Function] replace [Function] require [Function] :resume [Keyword] Break Loop Command. rest [Function] return [Special, Macro] return-from [Special] revappend [Function] reverse [Function] room [Function] :root [Function] Added. rotatef [Macro] round [Function] rplaca [Function] rplacd [Function] safety [Symbol] Optimize Quality. save [Function] Added. sbit [Function] scale-float [Function] schar [Function] search [Function] second [Function] set [Function] set-char-bit [Function] set-difference [Function] set-dispatch-macro-character [Function] set-exclusive-or [Function] set-macro-character [Function] set-syntax-from-char [Function] setf [Special, Macro] setq [Special] seventh [Function] shadow [Function] shadowing-import [Function] shiftf [Macro] short-float-epsilon [Constant] short-float-negative-epsilon [Constant] short-site-name [Function] signum [Function] simple-bit-vector-p [Function] simple-string-p [Function] simple-vector-p [Function] sin [Function] single-float-epsilon [Constant] single-float-negative-epsilon [Constant] sinh [Function] sixth [Function] :size [Keyword] sleep [Function] software-type [Function] software-version [Function] some [Function] sort [Function] space [Symbol] Optimize Quality. special [Symbol] Declaration Specifier. special-form-p [Function] speed [Symbol] Optimize Quality. sqrt [Function] stable-sort [Function] standard-char-p [Function] *standard-input* [Variable] *standard-output* [Variable] :start [Keyword] :start1 [Keyword] :start2 [Keyword] :static [Keyword] Added. step [Macro] :stream [Keyword] stream-element-type [Function] streamp [Function] string [Function] string-capitalize [Function] string-char-p [Function] string-downcase [Function] string-equal [Function] string-greaterp [Function] string-left-trim [Function] string-lessp [Function] string-not-equal [Function] string-not-greaterp [Function] string-not-lessp [Function] string-right-trim [Function] string-trim [Function] string-upcase [Function] string/= [Function] string< [Function] string<= [Function] string= [Function] string> [Function] string>= [Function] stringp [Function] sublis [Function] subseq [Function] subsetp [Function] subst [Function] subst-if [Function] subst-if-not [Function] substitute [Function] substitute-if [Function] substitute-if-not [Function] subtypep [Function] :supersede [Keyword] svref [Function] sxhash [Function] symbol-function [Function] symbol-name [Function] symbol-package [Function] symbol-plist [Function] symbol-value [Function] symbolp [Function] system [Function] Added. t [Constant] :tags [Keyword] Break Loop Command. tagbody [Special] tailp [Function] tan [Function] tanh [Function] tenth [Function] *terminal-io* [Variable] Different. termination-message [Function] Added. terpri [Function] :test [Keyword] :test-not [Keyword] the [Special] third [Function] throw [Special] time [Macro] trace [Macro] *trace-output* [Variable] tree-equal [Function] truename [Function] truncate [Function] type [Symbol] Declaration Specifier. :type [Keyword] type-of [Function] typecase [Macro] typep [Function] unexport [Function] unintern [Function] union [Function] :unhide [Keyword] Break Loop Command. :unhide-package [Keyword] Break Loop Command. unless [Special, Macro] unread-char [Function] untrace [Macro] unuse-package [Function] unwind-protect [Special] upper-case-p [Function] use-package [Function] user-homedir-pathname [Function] :username [Keyword] Added. :v [Keyword] Abbreviated Break Loop Command. values [Function] values-list [Function] :variables [Keyword] Break Loop Command. vector [Function] vector-pop [Function] vector-push [Function] vector-push-extend [Function] vectorp [Function] :verbose [Keyword] :version [Keyword] warn [Function] when [Special, Macro] &whole [Symbol] Defmacro-lambda Keyword. :wild [Keyword] Added. with-input-from-string [Macro] with-open-file [Macro] with-open-stream [Macro] with-output-to-string [Macro] write [Function] write-byte [Function] Different. write-char [Function] write-line [Function] write-string [Function] write-to-string [Function] y-or-n-p [Function] yes-or-no-p [Function] zerop [Function] Appendix B. An Overview of Kyoto Common Lisp Kyoto Common Lisp (KCL for short) is a full implementation of the Common Lisp language. KCL is a highly portable Common Lisp system intended for several classes of machines, from mini/micro to mainframe. The key idea behind the portability is the use of the C language and its standard libraries as the interface with the underlying machines and operating systems: The kernel of the system is written in C and the rest of the system is written in Common Lisp. Even the compiler generates intermediate code in C. KCL is also an efficient and compact system: KCL regards the runtime efficiency of interpreted code as important as the efficiency of compiled code. The small size of the KCL system makes KCL suitable for the current computer technology, such as the use of virtual memory and cache memory. This document reports the current status of KCL, its implementation, and system performance. This document is a draft: the description is still incomplete and informal, and some technical terms are used without definition or explanation. A full paper on the KCL implementation is in preparation. KCL is a full Common Lisp system. KCL is a full implementation of the Common Lisp language described in the Common Lisp Reference Manual: Common Lisp: The Language. by Guy L. Steele et al. Digital Press, 1984 KCL supports all Common Lisp functions, macros, and special forms defined in the Common Lisp Reference Manual. All Common Lisp variables and constants are defined in KCL exactly as described in the Common Lisp Reference Manual. KCL is available on several machines already. Currently, there are four major versions of KCL: 1. KCL/AOS Machine: Data General's Eclipse MV series super-minicomputers (MV10000, MV8000, MV6000, and MV4000) Operating System: Data General's original AOS/VS (Advanced Operating System / Virtual Storage) 2. KCL/VAX Machine: Digital Equipment Corporation's VAX 11 series machines (VAX 11/780 and VAX 11/750) Operating System: UNIX 4.2 bsd 3. KCL/SUN Machine: Sun Microsystems' Sun Workstation (MC68000 base) Operating System: UNIX 4.2 bsd 4. KCL/UST Machine: Sumitomo Electric Industries and Digital Computer Laboratory's personal workstation Ustation E15 (MC68000 base) Operating System: UNIX V (Uniplus' version) KCL/AOS is the original version of KCL, which was developed at Research Institute for Mathematical Sciences (RIMS), Kyoto University, with the cooperation of Nippon Data General Corporation. Other versions are ported from KCL/AOS at RIMS. All four versions share most of the source files of KCL. Improvements and error corrections are performed on the common source files, and the most recent revisions are brought to each machine from time to time. Ports to other machines and other operating systems are being undertaken or are in preparation at other organizations. KCL is expected to become available on the following machines in the near future. * IBM (and IBM-compatible) M series machines * Apollo Domain * Perkins Elmer * VAX 11 (running VMS) * VAX 11 (running Eunice, the Unix emulator) * Eclipse MV (running DGUX, Data General's native Unix) KCL is written in C and Lisp The kernel of KCL is written in C, including: * memory management and garbage collection * the evaluator (or interpreter) * Common Lisp special forms The KCL compiler is entirely written in Common Lisp. Each Common Lisp function or macro is written either in C or in Lisp. in C: 418 Common Lisp functions 11 Common Lisp macros in Lisp: 133 Common Lisp functions 59 Common Lisp macros The size of the source code is: C code 705 Kbytes Common Lisp functions and macros written in Lisp 173 Kbytes The compiler 264 Kbytes ------------------------- total 1142 Kbytes Three routines in the kernel are partly written in assembly language. These routines are: * bignum multiplication * bignum division * bit table manipulation of the garbage collector The total size of assembly code is 20 to 30 lines, depending on the version of KCL. KCL/AOS is built up by old-fashioned bootstrapping When KCL/AOS, the original version of KCL, was born, the following steps were taken to build it up. 1. Compile all C code with the C compiler and link them all. A subset of KCL is ready to run at this moment. 2. Load all Lisp code into KCL. Now the full system is ready to run, although the compiler and some Common Lisp functions and macros run interpretively. 3. Compile the source files of the KCL compiler with the (interpreted) KCL compiler itself. Load each Fasl-file (i.e., the file created by the KCL compiler) immediately after it is generated. The compilation process becomes faster toward the end of this step. Finally, the whole KCL compiler is ready to run by itself. 4. Compile the Common Lisp functions and macros written in Lisp, with the compiled KCL compiler. Load the Fasl-files. This completes the generation of the full system. The same steps are taken whenever drastic changes are made to the kernel. On the other hand, the procedure to port KCL or to revise the ported versions of KCL is much simpler, because all Lisp code has been cross-compiled by the compiler of KCL/AOS beforehand. Objects are represented by cells. KCL does not support the so-called immediate data. Any KCL object is represented as (a pointer to) a cell that is allocated on the heap. Each cell consists of several words (1 word = 32 bit) whose first word is in the format common to all data types: half of the word is the type indicator and the other half is used as the mark by the garbage collector. For instance, a cons cell consists of three words: ------------------------ | 'CONS' | mark-bit | ------------------------ | car-pointer | ------------------------ | cdr-pointer | ------------------------ and a fixnum cell consists of two words: ------------------------ | 'FIXNUM' | mark-bit | ------------------------ | fixnum-value | ------------------------ Array headers and compiled-function headers are represented in this way, and array elements and compiled code are placed elsewhere. Internally in compiled functions, certain Lisp objects may be represented simply by their values. For example, a fixnum object may be represented by its fixnum value, and a character object may be represented by its character code. Cells of small fixnums ranging from -1024 to 1023 and cells of characters are pre-allocated in fixed locations. Thus, for example, (eq 1023 1023) yields t, whereas (eq 1024 1024) yields nil. The heap is divided into pages. The whole heap of KCL is divided into pages (1 page = 2048 bytes). Each page falls in one of the following classes: * pages that contain cells consisting of the same number of words * pages that contain binary data such as compiled function code * pages that contain relocatable data such as array elements Free cells (i.e., those cells that are not used any more) consisting of the same number of words are linked together to form a free list. When a new cell is requested, the first cell in the free list (if it is not empty) is used and is removed from the list. If the free list is empty, then the garbage collector begins to run to collect unused cells. If the new free list is too short after the garbage collection, then new pages are allocated dynamically. Free binary data are also linked together in the order of the size so that, when a binary datum is being allocated on the heap, the smallest free area that is large enough to hold the binary datum will be used. Cell pages are never compactified. Once a page is allocated for cells with n words, the page is used for cells with n words only, even after all the cells in the page become garbage. The same rule holds for binary pages. In contrast, relocatable pages are sometimes compactified. That is, each relocatable datum may be moved to another place. The actual configuration of the KCL heap is: lower address higher address ---------------------------------------------------------------- | cell pages and binary pages | hole | relocatable pages | ---------------------------------------------------------------- There is a "hole" between the area for cell/binary pages and the area for relocatable pages. New pages are allocated in the hole for cell/binary pages, whereas new relocatable pages are allocated by expanding the heap to the higher address, i.e., to the right in this figure. When the hole becomes empty, the area for relocatable pages are shifted to the right to reserve a certain number of pages as the hole. During this process, the relocatable data in the relocatable pages are compactified. No free list is maintained for relocatable data. Symbol print names and string bodies are usually allocated in relocatable pages. However, when the KCL system is created, i.e., when the object module of KCL is created, such relocatable data are moved towards the area for cell/binary pages and then the pages for relocatable data are marked "static". The garbage collector never tries to sweep static pages. Thus, within the object module of KCL, the heap looks like: lower address higher address ---------------------------------------- | cell/binary pages and static pages | ---------------------------------------- Notice that the hole is not included in the object module; it is allocated only when the KCL system is started. This saves secondary storage a little bit. The maximum size of the hole is about 100 pages (= 200 Kbytes). KCL uses five stacks. KCL uses the following stacks. * Value Stack, for arguments/values passing lexical variables allocation temporary values saving * Frame Stack, consisting of catch, block, tagbody frames * Bind Stack, for shallow binding of dynamic variables * Invocation History Stack, maintaining information for debugging * C Language Control Stack, sometimes used in compiled functions for: arguments/values passing typed lexical variables allocation temporary values saving, in addition to the obvious use such as function invocation Arguments/values are passed via the value stack. To show the argument/value passing mechanism, here we list the actual code for the Common Lisp function cons. Lcons() { object x; check_arg(2); x = alloc_object(t_cons); x->c.c_car = vs_base[0]; x->c.c_cdr = vs_base[1]; vs_base[0] = x; vs_pop; } We adopted the convention that the name of a function that implements a Common Lisp function begins with 'L', followed by the name of the Common Lisp function. (Strictly speaking, '-' and '*' in the Common Lisp function name are replaced by '_' and 'A', respectively, to obey the syntax of C.) Arguments to functions are pushed on the value stack. The stack pointer vs_base (value stack base) points to the first argument and another pointer vs_top points to the stack location next to the last argument. Thus, for example, when cons is called with the first argument 1 and the second argument 2, the value stack looks like: 4---------6 vs_top ->| | ----------- | 2 | ----------- vs_base ->| 1 | ----------- | | : : | | bottom ----------- value stack check_arg(2) in the code of Lcons checks if exactly two arguments are supplied to cons. That is, it checks whether the difference of vs_top and vs_base is 2, and if not, it causes an error. allocate_object(t_cons) allocates a cons cell in the heap and returns the pointer to the cell. After the car and the cdr fields of the cell are set, the cell pointer is put onto the value stack. The two stack pointers are used also on return from a function call. vs_base points to the first returned value and vs_top points to the stack location next to the last returned value. vs_pop in the code above decrements vs_top by one. 4---------6 | | ----------- vs_top ->| | ----------- vs_base ->| (1 . 2) | ----------- | | : : | | bottom ----------- value stack Because the same stack pointers are used both for argument passing and for return value passing, the Common Lisp function values does almost nothing. On the call of (values 1 2) On return from (values 1 2) ----------- ----------- vs_top ->| | vs_top ->| | ----------- ----------- | 2 | | 2 | ----------- ----------- vs_base ->| 1 | vs_base ->| 1 | ----------- ----------- | | | | : : : : | | | | bottom ----------- bottom ----------- value stack value stack In most cases, the caller of a function uses only the first returned value which is pointed to by vs_base. This is not the case, however, when the called function returns no value at all. In order to avoid the check whether this is the case, each KCL function, on return from its call, sets nil to the stack entry which is pointed to by vs_base, whenever it returns no value at all. Thus, for instance, the actual code for the Common Lisp function values is: Lvalues() { vs_top[0] = Cnil; } where Cnil is a global variable that always contains the pointer to nil. See why this works. The interpreter uses A-lists. The KCL interpreter uses three A-lists (Association lists) to represent lexical environments. * One for variable bindings * One for local function/macro definitions * One for tag/block bindings When a function closure is created, the current three A-lists are saved in the closure along with the lambda expression. Later, when the closure is invoked, the saved A-lists are used to recover the lexical environment. The invocation history stack is used for debugging. The invocation history stack consists of two kinds of elements. Each element may be either a pair of a Lisp form and a pointer to lexical environment: --------------------------------------------- | form | environment-pointer | --------------------------------------------- or a pair of a function name and a pointer to the value stack: --------------------------------------------- | function-name | value-stack-pointer | --------------------------------------------- The former is pushed on the invocation history stack when an interpreted code is evaluated. The form is the interpreted code itself and the environment-pointer points to the three consecutive memory words each of which holds the A-list that represents the lexical environment. The latter is pushed when a compiled function is invoked. The function-name is the name of the called function and the value-stack-pointer points to the value stack location which is pointed to by vs_base when the function is called. For both kinds, the element on the invocation history stack is poped at the end of the evaluation. Let us see how the invocation history stack is used for debugging. >(defun fact (x) ;;; Wrong definition of the (if (= x 0) ;;; factorial function. one ;;; one should be 1. (* x (fact (1- x))))) fact >(fact 3) ;;; Tries 3! Error: The variable ONE is unbound. Error signalled by IF. Broken at IF. >>:b ;;; Backtrace. Backtrace: eval > fact > if > fact > if > fact > if > fact > IF ;;; Currently at the last if. >>:h ;;; Help. :c(urrent) Show current function. :p(revious) Move to previous function. :n(ext) Move to next function. :b(acktrace) Backtrace. :h(elp) Help. :q(uit) Return to top-level. :r(esume) Return to the caller :l(ocal) Show n-th local value. :v(ariables) Show local variables. :functions Show local functions. :blocks Show block names. :tags Show tags. :hide Hide a function :hide-package Hide a package. :unhide Unhide a function :unhide-package Unhide a package. >>:p ;;; Move to the last call of fact. Broken at FACT. >>:b Backtrace: eval > fact > if > fact > if > fact > if > FACT > if ;;; Now at the last fact. >>:v ;;; The environment at the last call Local variables: x. ;;; to fact is recovered. ;;; x is the only bound variable. >>x 0 ;;; The value of x is 0. >>:blocks Block names: fact. ;;; The block fact is established. >>(return-from fact 1) ;;; Return from the last call of 6 ;;; fact with value of 0. ;;; The execution is resumed and > ;;; the value 6 is returned. ;;; Again at the top-level loop. The KCL compiler generates intermediate code in C. The KCL compiler is essentially a translator from Common Lisp to C. Given a Lisp source file, the compiler first generates three intermediate files: * a C-file which consists of the C version of the Lisp program * an H-file which consists of declarations referenced in the C-file * a Data-file which consists of Lisp data to be used at load time The KCL compiler then invokes the C compiler to compile the C-file into an object file. Finally, the contents of the Data-file is appended to the object file to make a Fasl-file. The generated Fasl-file can be loaded into the KCL system by the Common Lisp function load. By default, the three intermediate files are deleted after the compilation, but, if asked, the compiler leaves them. The merits of the use of C as the intermediate language are: * The KCL compiler is highly portable. Indeed the four versions of KCL share the same compiler. Only the calling sequence of the C compiler and the handling of the intermediate files are different in these versions. * Cross compilation is possible, because the contents of the intermediate files are common to all versions of KCL. For example, one can compile his or her Lisp program by the KCL compiler on Eclipse, bring the intermediate files to SUN, compile the C-file with the C compiler on SUN, and then append the Data-file to the object file. This procedure generates the Fasl-file for the KCL system on SUN. This kind of cross compilation makes it easier to port KCL. * Hardware-dependent optimizations such as register allocations are done by the C compiler. The demerits are: * At those sites where no C compiler is available, the users cannot compile their Lisp programs. * The compilation time is long. 70% to 80% of the compilation time is used by the C compiler. The KCL compiler is perhaps the slowest compiler in the Lisp world. The compiler mimics human C programmer. The format of the intermediate C code generated by the KCL compiler is the same as the hand-coded C code of the KCL source programs. For example, supposing that the Lisp source file contains the following function definition: (defun add1 (x) (1+ x)) The compiler generates the following intermediate C code. init_code(start,size,data)char *start;int size;object data; { register object *base=vs_top; register object *sup=base+VM2; vs_check; Cstart=start;Csize=size;Cdata=data; set_VV(VV,VM1,data); MF(VV[0],L1,start,size,data); vs_top=vs_base=base; } /* function definition for ADD1 */ static L1() { register object *base=vs_base; register object *sup=base+VM3; vs_reserve(VM3); check_arg(1); vs_top=sup; base[1]=one_plus(base[0]); vs_top=(vs_base=base+1)+1; return; } The C function L1 implements the Lisp function add1. This relation is established by MF in the initialization function init_code, which is invoked at load time. There, the vector VV consists of Lisp objects; VV[0] in this example holds the Lisp symbol add1. VM3 in the definition of L1 is a C macro declared in the corresponding H-file. The actual value of VM3 is the number of value stack locations used by L1, i.e., 2 in this example. Thus the following macro definition is found in the H-file. #define VM3 2 When the compiled add1 is called, the value stack looks like: On the call of (add1 1) On return from (add1 1) ----------- ----------- | | vs_top ->| | ----------- ----------- vs_top ->| | vs_base ->| 2 | ----------- ----------- vs_base ->| 1 | | 1 | ----------- ----------- | | | | : : : : | | | | bottom ----------- bottom ----------- value stack value stack Note that the two value stack pointers need not be moved in this example. This shows that the KCL compiler still has room for improvement. Lexical environment of compiled closures is represented by a list. The KCL compiler takes two passes before it invokes the C compiler. The major role of the first pass is to detect function closures and to detect, for each function closure, those lexical objects (i.e., lexical variable, local function definitions, tas, and block-names) to be enclosed within the closure. This check must be done before the C code generation in the second pass, because lexical objects to be enclosed in function closures are treated in a different way from those not enclosed. Ordinarily, lexical variables in a compiled function f are allocated on the value stack. However, if a lexical variable is to be enclosed in function closures, it is allocated on a list, called the "environment list", which is local to f. In addition, one entity is reserved on the value stack, in which the pointer to the variable's location (within the environment list) is stored, so that the variable may be accessed by indexing rather than by list traversal. The environment list is a pushdown list: It is empty when f is called. An element is pushed on the environment list when a variable to be enclosed in closures is bound, and is popped when the binding is no more in effect. That is, at any moment during execution of f, the environment list contains those lexical variables whose binding is still in effect and which should be enclosed in closures. When a compiled closure is created during execution of f, the compiled code for the closure is coupled with the environment list at that moment to form the compiled closure. Later, when the compiled closure is invoked, as many entities as the elements in the environment list is reserved on the value stack, each of which points to a lexical object in the environment list, so that, again, each object may be referenced by indexing. Let us see an example. Suppose the following function has been compiled. (defun foo (x) (let ((a #'(lambda () (incf x))) (y x)) (values a #'(lambda () (incf x y))))) foo returns two compiled closures. The first closure increments x by one, whereas the second closure increments x by the initial value of x. Both closures return the incremented value of x. >(multiple-value-setq (f g) (foo 10)) # >(funcall f) 11 >(funcall g) 21 > After this, the two compiled closures look like: second closure y: x: ---------------- ---------------- --------------- | ** | -------->| 10 | -------->| 21 | nil | ---------------- ---------------- --------------- ^ first closure | ---------------- | | * | -------------- ---------------- * : address of the compiled code for #'(lambda () (incf x)) ** : address of the compiled code for #'(lambda () (incf x y)) Declarations increase code efficiency. Declarations, especially type and function declarations, increase the efficiency of the compiled code. For example, for the following Lisp source file, with two Common Lisp declarations added, (eval-when (compile) (proclaim '(function tak (fixnum fixnum fixnum) fixnum))) (defun tak (x y z) (declare (fixnum x y z)) (if (not (< y x)) z (tak (tak (1- x) y z) (tak (1- y) z x) (tak (1- z) x y)))) the compiler generates the following C code. /* local entry for function TAK */ static int LI2(V4,V5,V6) int V4,V5,V6; { VMB3 VMS3 VMV3 if((V5)<(V4)){ goto T4;} VMR3(V6) T4:; {int V7=LI2((V4)-1,V5,V6); {int V8=LI2((V5)-1,V6,V4); VMR3(LI2(V7,V8,LI2((V6)-1,V4,V5)))}} } /* global entry for the function TAK */ static L2() { register object *base=vs_base; base[0]=make_fixnum(LI2(fix(base[0]), fix(base[1]), fix(base[2]))); vs_base=base; vs_top=base+1; } The main part of the tak function is LI2. If redundant parentheses are removed, macros are expanded, and identifiers are renamed, we obtain the following code equivalent to LI2. /* local entry for function TAK */ static int tak(x,y,z) int x,y,z; { if(y(defun add1 (x) (1+ x)) add1 >(disassemble 'add1) init_code(start,size,data)char *start;int size;object data; { register object *base=vs_top; register object *sup=base+VM2; vs_check; Cstart=start;Csize=size;Cdata=data;set_VV(VV,VM1,data); MF(VV[0],L1,start,size,data); vs_top=vs_base=base; } /* function definition for ADD1 */ static L1() { register object *base=vs_base; register object *sup=base+VM3; vs_check; vs_top=sup; base[1]=one_plus(base[0]); vs_top=(vs_base=base+1)+1; return; } > KCL/AOS has its own screen editor. KCL/AOS has an embedded full-screen editor which resembles EMACS. The editor is called FeCl2 as the acronym of Full-screen Editor as a Common Lisp TOOl. It is invoked by the Common Lisp function ed. Unfortunately, FeCl2 is not supported by other versions of KCL, simply because we are too lazy to port it (it is written in C). For these versions, ed invokes the vi editor of Unix. KCL has C language interface. The user can embed his or her own C code into Lisp source code. The idea is very simple: The specified C code is inserted in the intermediate C code that is generated by the KCL compiler. In the following example, Clines and defentry are top-level macros specific to KCL. The Clines macro form specifies the C code to be embedded, in terms of strings, and the defentry form defines an entry of the specified C function from KCL. (Clines " int tak(x, y, z) " " int x, y, z; " " { if (y >= x) return(z); " " else return(tak(tak(x-1, y, z), " " tak(y-1, z, x), " " tak(z-1, x, y))); " " } " ) (defentry tak (int int int) (int "tak")) Port to VAX took three days. Although KCL is made to be highly portable, certain minor changes had to be done, when it was ported to VAX Unix 4.2 bsd. These changes include: 1. The compiler top-level was slightly changed, because of the differences of the calling sequence of the C compiler and of the handling of object files. 2. File system interface was changed to fit Unix 4.2 bsd. 3. The following system parameters were redefined because Vax's representation of floating point numbers differs from that of Eclipse. most-positive-short-float most-negative-short-float least-positive-short-float least-negative-short-float most-positive-long-float most-positive-double-float most-positive-single-float most-negative-long-float most-negative-double-float most-negative-single-float least-positive-long-float least-positive-double-float least-positive-single-float least-negative-long-float least-negative-double-float least-negative-single-float short-float-epsilon short-float-negative-epsilon long-float-epsilon double-float-epsilon single-float-epsilon long-float-negative-epsilon double-float-negative-epsilon single-float-negative-epsilon 4. For the same reason as above, the following machine-dependent Common Lisp functions were rewritten. decode-float scale-float float-radix float-digits float-precision integer-decode-float 5. The three assembler routines were rewritten. 6. The in-core loader that loads Fasl-files into the KCL memory was changed. This was a simple job because we used the standard linkage editor ld of Unix. 7. The memory dump routine was rewritten. The whole job of poring KCL to VAX Unix 4.2 bsd took three days. Later, we spent some more days, to fix bugs in the ported version of KCL. Port to SUN took three evenings. The port to the SUN Workstation was much easier than the port to the VAX, mainly because the operating system is the same for both VAX and SUN. 1. The compiler top-level of KCL/VAX was used without changes. 2. The file system of KCL/VAX was used without changes. 3. The system parameters that depend on the representation of floating point numbers were rewritten. 4. The Common Lisp functions that depend on the representation of floating point numbers were redefined. 5. The three assembler routines were rewritten. 6. The in-core loader of KCL/VAX was used without changes. 7. The memory dump routines of KCL/VAX was used without changes. The whole job of poring KCL to SUN took three evenings. Most of the time was spent for the three assembler routines, because we did not know anything about the MC68000 assembler at first. Port to Ustation took one week. The port to the Ustation was relatively a hard job. It took almost a week. The major difficulity was that the C compiler of Unix V on the Ustation recognized identifiers only by the first seven characters. As already mentioned, we used the convention that the C function that implements the Common Lisp function function-name is given the name Lfunction-name. Thus, for example, the Common Lisp functions on packages such as package-name package-nickname package-shadowing-symbols package-use-list package-used-by-list packagep are implemented by the C functions whose names all begin with Lpackage. These C functions are regarded as having the same name by the C compiler. This problem was solved by preparing a preprocessor program which maps long identifiers into smaller ones. This program is now used by the KCL compiler on Ustation before the C compiler is called. KCL is relatively compact. The size of the object module of the whole KCL system (including the Compiler) is: KCL/AOS 1.78 Mbytes KCL/VAX 1.45 Mbytes KCL/SUN 1.56 Mbytes KCL/UST 1.56 Mbytes Since all system initialization (such as loading the database of the KCL compiler) has been done when the object module is created, the object module size roughly corresponds to the initial size of the KCL process when a KCL session is started, minus the initial size of the hole in the heap (about 200 Kbytes). Gabriel's benchmark. The following table shows the results of Richard Gabriel's Lisp benchmark tests with the four versions of KCL. The results with five other Common Lisp systems are also listed for comparison. Each number represents the CPU time (in seconds) for the compiled program. '*' indicates that the time includes garbage-collection time. The data of S-1 Lisp and Spice Lisp are found in: Performance and Evaluation of Lisp Systems by Richard P. Gabriel Computer Systems Ser. Research Reports, MIT Press, 1985 We received the data of Symbolics, DEC Common Lisp, and DG Common Lisp directly from Dr. Richard Gabriel in April 1985. We measured the data for KCL in July 1985. For the details of the benchmark tests, refer to the book above. Benchmark | Boyer | Browse | Destruct | Traverse | Traverse | Test | | | |Initialize| Run | ------------------------------------------------------------------- | | | | | | Kyoto CL | 11.02 | 18.09 | 3.15 | 5.75 | 44.16 | MV10000 | | | | | | | | | | | | Kyoto CL | 43.73 | 68.15* | 8.00 | 14.42 | 151.20 | VAX 780 | | | | | | | | | | | | Kyoto CL | 43.60* | 73.08* | 10.23 | 20.38 | 118.60 | E15 | | | | | | | | | | | | Kyoto CL | 47.00 | 81.37 | 14.10 | 26.30 | 160.58 | SUN | | | | | | | | | | | | Symbolics | 11.99 | 30.8 | 3.03 | 8.62 | 49.95 | 3600 | | | | | | | | | | | | S-1 CL | 10.03 | 10.2 | 0.91 | 1.93 | 30.1 | Mark IIA | | | | | | | | | | | | Spice | 134.79 | 359.63 | 17.78 | 41.75 | 490.6 | Perq | | | | | | | | | | | | DEC CL | 46.79 | 118.51 | 6.38 | 20.76 | 161.68 | VAX 780 | | | | | | | | | | | | DG CL | 29.3 | 59.91 | 6.95 | 27.77 | 45.86 | MV10000 | | | | | | Benchmark | Tak | Stak | Ctak | Takl | Takr | Test | | | | | | ------------------------------------------------------------------- | | | | | | Kyoto CL | 0.42 | 1.90 | 4.35 | 5.13 | 0.54 | MV10000 | | | | | | | | | | | | Kyoto CL | 1.45 | 6.03 | 14.02 | 19.97 | 1.75 | VAX 780 | | | | | | | | | | | | Kyoto CL | 1.17 | 7.63 | 9.58 | 16.10 | 1.38 | E15 | | | | | | | | | | | | Kyoto CL | 1.48 | 11.02 | 16.88 | 23.35 | 1.67 | SUN | | | | | | | | | | | | Symbolics | 0.6 | 2.58 | 7.65 | 6.44 | 0.6 | 3600 | | | | | | | | | | | | S-1 CL | 0.29 | 4.31 | 0.82 | 2.92 | 0.58 | Mark IIA | | | | | | | | | | | | Spice | 4.7 | 13.5 | 8.4 | 24.0 | 7.7 | Perq | | | | | | | | | | | | DEC CL | 1.83 | 4.11 | 8.09 | 7.34 | 3.42 | VAX 780 | | | | | | | | | | | | DG CL | 0.89 | 3.09 | 1.79 | 5.52 | 1.21 | MV10000 | | | | | | Benchmark | Deriv | DDeriv | Div2 | Div2 | FFT | Test | | | Iterative| Recursive| | ------------------------------------------------------------------- | | | | | | Kyoto CL | 4.85 | 5.93 | 1.99 | 2.73 | 1.55 | MV10000 | | | | | | | | | | | | Kyoto CL | 18.98 | 23.07 | 7.48 | 11.25 | 9.07 | VAX 780 | | | | | | | | | | | | Kyoto CL | 22.07* | 25.38* | 9.95* | 12.60* | 74.62 | E15 | | | | | | | | | | | | Kyoto CL | 20.72 | 24.77 | 9.32 | 12.30 | 94.07 | SUN | | | | | | | | | | | | Symbolics | 5.12 | 5.24 | 1.85 | 2.89 | 4.75 | 3600 | | | | | | | | | | | | S-1 CL | 4.99 | 3.27 | 0.82 | 1.49 | 1.44 | Mark IIA | | | | | | | | | | | | Spice | 71.8 | 77.7 | 28.15 | 40.69 | 59.0 | Perq | | | | | | | | | | | | DEC CL | 13.76 | --- | 5.0 | 9.84 | 32.69 | VAX 780 | | | | | | | | | | | | DG CL | 5.6 | 8.11 | 2.86 | 4.48 | 62.78 | MV10000 | | | | | | Benchmark | Puzzle | Triang | Fprint | Fread | Tprint | Test | | | | | | ------------------------------------------------------------------- | | | | | | Kyoto CL | 6.76 | 104.85 | 1.98 | 2.45 | 1.74 | MV10000 | | | | | | | | | | | | Kyoto CL | 20.57 | 366.12 | 5.73 | 5.77 | 6.55 | VAX 780 | | | | | | | | | | | | Kyoto CL | 41.30 | 341.23* | 9.83 | 6.07 | 11.58 | E15 | | | | | | | | | | | | Kyoto CL | 49.13 | 499.68 | 10.05 | 7.62 | 8.50 | SUN | | | | | | | | | | | | Symbolics | 13.89 | 151.7 | 2.6 | 4.6 | 4.9 | 3600 | | | | | | | | | | | | S-1 CL | 1.82 | 62.06 | --- | --- | --- | Mark IIA | | | | | | | | | | | | Spice | 75.14 | 1488.85 | 20.0 | 26.0 | 22.6 | Perq | | | | | | | | | | | | DEC CL | 47.48 | 360.85 | 3.94 | 7.24 | 2.85 | VAX 780 | | | | | | | | | | | | DG CL | 138.2 | 151.2 | 2.35 | 4.65 | 2.83 | MV10000 | | | | | | Appendix C. Kyoto Common Lisp Installation Guide This appendix explains how to install the KCL system, separately for each version of KCL. C.1. Installation of KCL/AOS 1. Prepare a directory (hereafter called KCL directory) for Kyoto Common Lisp. In the following examples, we suppose that the KCL directory is :UDD:KCL. 2. Load the distribution tape to the KCL directory. ) DIR :UDD:KCL ) LOAD You will find that the subdirectory PORT has been created. The PORT subdirectory contains everything that is needed to run KCL. Files in this directory are: Documents: README this file Executable files: KCL.PR the KCL interpreter and compiler KCL.ST BUILD_FASL.PR the fasl-file builder FECL2.PR the FeCl2 editor Command files: KCL.CLI to invoke KCL LC.CLI to invoke the KCL compiler LC1.CLI to invoke the KCL compiler FECL2.CLI to invoke the FeCl2 editor Header file: CMPINCLUDE.H the header file for the KCL compiler Miscellaneous: FECL2.CMD FeCl2 editor command table 3. Customize the command files. The command file KCL.CLI consists of the following command lines to invoke the KCL interpreter. push;prom pop sea :usr:dgc [!sea] x :udd:[!user]:port:%0-% :udd:[!user]:port: pop Replace the two occurrences of "[!user]" with the name of the KCL directory (i.e., KCL in our example). push;prom pop sea :usr:dgc [!sea] x :udd:KCL:port:%0-% :udd:KCL:port: pop And move this file to an appropriate command directory, say :UTIL, so that all KCL users can access it. If the name of the directory that includes DG's C compiler is not :USR:DGC, you should replace it with the appropriate directory name, so that the KCL compiler can access the C compiler by CC.PR. You can use the commands LC.CLI and LC1.CLI to invoke the compiler directly from the CLI. The content of LC.CLI is: push prompt pop level sea :usr:dgc [!sea] WRITE Compiling %1%.LSP. proc/def/ioc/block/pri=3 & :udd:[!user]:port:kcl :udd:[!user]:port: %1% %1% U10000 pop Customize these command files in the same way as for the KCL.CLI command file above. 4. Install the header file Copy the header file CMPINCLUDE.H to the standard directory for C include files, say :USR:DGC. C.2. Installation of KCL/VAX 1. Prepare a directory (hereafter called KCL directory) for Kyoto Common Lisp. In the following examples, we suppose that the KCL directory is /usr/kcl. 2. Load the distribution tape to the KCL directory. % pwd /usr/kcl % tar x You will find that the subdirectory unixport has been created. The unixport subdirectory contains everything that is needed to run KCL and the KCL compiler. Files in this directory are: Documents: readme this file Executable files: saved_kcl the KCL interpreter and compiler Command files: kcl to invoke KCL lc to invoke the KCL compiler lc1 to invoke the KCL compiler Header file: cmpinclude.h the header file for the KCL compiler 3. Customize the command files. The command file kcl consists of a single line command to invoke the KCL interpreter. # ~/unixport/saved_kcl ~/unixport/ Replace two '~'s with the pathname of the KCL directory (i.e., /usr/kcl in our example). # /usr/kcl/unixport/saved_kcl /usr/kcl/unixport/ And move this file to an appropriate command directory, say /usr/bin, so that all KCL users can access it. You can use the commands lc and lc1 to invoke the compiler directly from the shell. The content of lc is: # echo Compiling $1.lsp ~/unixport/saved_kcl ~/unixport/ $1 $1 U1000 Customize these command files in the same way as for the kcl command file above. 4. Install the header file Copy the header file cmpinclude.h to the standard directory for C include files, say /usr/include. C.3. Installation of KCL/SUN 1. Prepare a directory (hereafter called KCL directory) for Kyoto Common Lisp. In the following examples, we suppose that the KCL directory is /usr/kcl. 2. Load the distribution tape to the KCL directory. % pwd /usr/kcl % tar x You will find that the subdirectory unixport has been created. The unixport subdirectory contains everything that is needed to run KCL and the KCL compiler. Files in this directory are: Documents: readme this file Executable files: saved_kcl the KCL interpreter and compiler Command files: kcl to invoke KCL lc to invoke the KCL compiler lc1 to invoke the KCL compiler Header file: cmpinclude.h the header file for the KCL compiler 3. Customize the command files. The command file kcl consists of a single line command to invoke the KCL interpreter. # ~/unixport/saved_kcl ~/unixport/ Replace two '~'s with the pathname of the KCL directory (i.e., /usr/kcl in our example). # /usr/kcl/unixport/saved_kcl /usr/kcl/unixport/ And move this file to an appropriate command directory, say /usr/bin, so that all KCL users can access it. You can use the commands lc and lc1 to invoke the compiler directly from the shell. The content of lc is: # echo Compiling $1.lsp ~/unixport/saved_kcl ~/unixport/ $1 $1 U1000 Customize these command files in the same way as for the kcl command file above. 4. Install the header file Copy the header file cmpinclude.h to the standard directory for C include files, say /usr/include. C.4. Installation of KCL/UST 1. Prepare a directory (hereafter called KCL directory) for Kyoto Common Lisp. In the following examples, we suppose that the KCL directory is /usr/kcl. 2. Three floppy disks are used for the distribution. Load the floppy disks to the KCL directory by the multi-volume option of the tar command. (Insert the first disk to the drive and issue the tar command. Then, you will be prompted to change the disks.) % pwd /usr/kcl % tar xvfBM /dev/rdy0g 1976 You will find that the subdirectory unixport has been created. The unixport subdirectory contains everything that is needed to run KCL and the KCL compiler. Files in this directory are: Documents: readme this file Executable files: saved_kcl the KCL interpreter and compiler ild incremental loader trans translator from Unix 4.2 to Unix V Command Source files: kcl.c to invoke KCL lc.c to invoke the KCL compiler lc1.c to invoke the KCL compiler Header file: cmpinclude.h the header file for the KCL compiler 3. Customize the command files. The source file kcl.c consists of a C-language program to invoke the KCL interpreter. Replace all /usr/ukcl in this file with the pathname of the KCL directory (i.e., /usr/kcl in our example), and compile this file. % cc -o kcl kcl.c And move the object file to an appropriate command directory, say /usr/bin, so that all KCL users can access it. You can use the source files lc.c and lc1.c to invoke the compiler directly from the shell. Customize these source files in the same way as for the kcl command file above. 4. Install the header file Copy the header file cmpinclude.h to the standard directory for C include files, say /usr/include. Addendum, 1986 KCL on UNIX: Problems and Future Improvement * Core Dump We can consider several situations in which KCL dumps core. 1. The KCL compiler, by default, produces efficient but very dangerous code. The code seldom detects erraneous situations such as extracting the car of a fixnum, which, in bad cases, cause "Segmentation violation" or "Bus error" on UNIX. I think this is the reason for most of the complaints you have been reported so far. To avoid this, one should tell the compiler to produce rather inefficient but safe code using the appropriate proclamation such as (proclaim '(optimize (safety 2))). The safety level greater than or equal to 2 guarantees that the code detects every runtime error. 2. KCL keeps several stacks. Whenever an item is pushed on a stack, KCL checks whether the stack limit is violated or not, except for the value stack and the C stack. The limit for the value stack is not checked if the code was compiled with the safety level 0; i.e., the limit is always checked in the code compiled with the safety level greater than 0, and in the interpreted code. 3. The limit for the C stack is not checked in the compiled code. We can insert the code to check the C stack limit at the beginning of each compiled function. However, we don't think it is feasible. 4. GC of KCL uses the C stack in the marking phase. Currently, the C stack overflow in the marking phase is not detected. We will insert the code to check the stack limit in the next revision. However, we can't signal a Lisp error in GC. The C stack overflow in GC will result in a fatal error. Note: Big lists extending to the direction of car consume more stack area than those extending to cdr. * C Stack Limit The C stack limit used by KCL is smaller than the actual limit. Currently, its value is fixed and independent of the actual limit. On BSD, as you may know, the actual limit for the C stack can be changed by the limit command of csh. In the next revision, we will set the C stack limit of KCL from the value obtained by the getrlimit system call. Therefore, for those applications that use much stack area, one can invoke KCL in the following way: % limit stacksize 1024 # 1024K bytes = 1M bytes % kcl We can even change KCL so that it dynamically increments its C stack limit by the setrlimit system call. But we don't think it's feasible, either. Note: Currently, the C stack limit of KCL is set 15000 words = 60K bytes for all the versions of KCL. Its value is defined as the C macro CSSIZE in "h/eval.h". Note: The actual stack limit is 512K by default on SUN-III. Note: In the revision of KCL you have, the C stack overflow will never signal a Lisp error; it always results in a fatal error and KCL terminates immediately. This is a BUG. I found it while I was checking the behavior of KCL for the C stack overflow. I've already fixed it, so in the next revision, the C stack overflow will signal a Lisp error except in GC. * Process Size Since KCL keeps a table which records the type of each page in the process space, the process size of KCL is limited by the size of the table. Its size is determined by the MAXPAGE macro defined on the cc command line used for compiling each C source file of KCL. Currently, MAXPAGE = 16384 = 32M bytes. I think the size is reasonable now. On BSD, the size of the KCL process is also limited by the resource limit set by the limit command. KCL doesn't change the limit by the setrlimit system call. Note: Even if the resource limit is 1G, you can't use that much unless MAXPAGE is large enough. Note: For SUN-III, the limit is nearly 256M bytes by default. Note: Even if the resource limit is bigger than MAXPAGE, you can't use MAXPAGE pages because of the limitation of the swap space of the operating system. In SUN3/75M, which I am using now, I can't allocate more than 16M. If there are many other processes running, I can only allocate far less than 16M. * Explicit Expansion of Process Space Usually, KCL expands its process space incrementally, i.e., it only allocates memory after it has failed in collecting enough space by GC. In order to expands the process space of KCL explicitly, we changed the function ALLOCATE and ALLOCATE-CONTIGUOUS-PAGES so that they take one optional argument. When a non-NIL value is supplied for the optional argument, these functions acutally allocate the maximum number of pages for the specified type or for the contiguous blocks. Therefore, one can begin with 1M bytes for conses (500 pages = 1M bytes) as follows: % kcl KCL (Kyoto Common Lisp) ... >(allocate 'cons 500 t) t > If one extends the hole size by SI:SET-HOLE-SIZE and allocates memory as above, while consuming the current hole, KCL will surely make the hole of the specified size. Therefore, if one begins KCL in the following way, one will never invoke GC. % kcl KCL (Kyoto Common Lisp) ... >(si:set-hole-size 8000) ; 16M 8000 >(allocate 'cons 500 t) ; Actually allocates 1M. ; The hole will be 16M. t >(allocate 'cons 8000) ; Set the maximum. t ... ... >(allocate 'fixnum 8000) t >(allocate-contiguous-pages 8000) t >(allocate-relocatable-pages 3000) ; 6M t Note: In the above example, KCL allocates 16M for cells and 6M for relocatable blocks. Since KCL uses two spaces for the relocatable area, 16M + 2*6M < 32M. We are not prepared for the critical case, say 16M+2*8M = 32M. Note: The above example will not work on SUN-III in general, unless you reinstall the operating system so that it has MUCH swap space. Please make a test with smaller parameters than above, after you have recieved the next revision of KCL. Note: One should first check the size of the swap space before complaining about KCL. * Notification of GC We defined a new system-internal variable SI:*NOTIFY-GBC*. When its value is non-NIL, GC will print GBC invoked when it is invoked, and will print GBC finished when it returns. It's much neater than SI:*GBC-MESSAGE*. Note: The message is directly written on the standard output of the C library and is not written on a Lisp stream. Therefore, when one DRIBBLEs the KCL session, the message from GC won't be written out on the specified file. This is because writing on a stream has the danger of consuming memory. * Faslink We made the loader which can load the object file while linking other object files and/or libraries. It is defined as a function SI:FASLINK and used as follows: (si:faslink "foo.o" "bar.o boo.o -lpixrect") "foo.o" should be an object file produced by compiling a Lisp source file. The Lisp file, in general, consists of DEFENTRY definitions that call functions in the object files and/or the libraries specified in the second argument. The first argument should be a pathname, a string or a symbol, and the second argument should be a string that can be accpted by the UNIX linkage editor. If there are more than one arguments, they should be separated by a space as above. Note: The second argument is passed to "ld" as it is. Note: SI:FASLINK is only defined in the BSD versions of KCL. * valloc The SunView library uses the "valloc" function of C. To use the SunView library with KCL, one should redefine "valloc" as follows: #define PAGSIZ ... char * valloc(size) { int p; p = (int)malloc(size+PAGSIZ); return((p+PAGSIZ-1)&(~PAGSIZ)); return((char *)p); } Note: In my SunView interface, all the libraries are linked with KCL from the beginning. I haven't checked that SI:FASLINK will work for SunView. But, it is necessary (perhaps, not sufficient) to redefine "valloc" as above. * init.lsp If there exists a file with the name "init.lsp" in the current directory, KCL loads the file before entering into the top-level loop. The user of KCL is expected to make his own environment using this facility. It is similar to ".chsrc" for csh, ".profile" for sh, ".newsrc" for readnews, although the name doesn't begin with ".". If you want to invoke your favorate editor from KCL, please define the interface in "init.lsp". * Big C Code The C compiler sometimes complains that the code produced by KCL is too big and cannot compute jump addresses. I bet this is a bug of the UNIX assembler. To avoid this, one should supply the assembler with the -J option. I'm not sure that the cc command will pass the -J option to the assembler, since it passes those arguments it can't interpret to the linkage editor in general. To avoid the problem, you should compile the Lisp file by >(compile-file "foo.lsp" :c-file t :h-file t :data-file t :o-file nil) and compile the C file with the -S option % cc -S foo.c and then assemble it with the -J option. % as -J foo.s -o foo.o Finally, on BSD, concatenate the data file at the end. % cat foo.data >> foo.o Note: The above recipe is totally dependent on the version of UNIX. I hope you will report what C compilers (and assemblers) have failed in compiling the C code produced by the KCL compiler.