;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: The Basic Operations of the Compiler =Text: 3THE BASIC OPERATIONS OF THE COMPILER* The purpose of the Lisp compiler is to convert Lisp functions into programs in the Lisp Machine's instruction set, so that they run more quickly and take up less storage. Compiled functions are represented in Lisp by FEFs (Function Entry Frames), which contain machine code as well as various other information. The printed representation of a FEF is 3#* If you want to understand the output of the compiler, refer to 4(ASSEMBLER-0)How to Read Assembly Language*. There are three ways to invoke the compiler from the Lisp Machine. First, you may have an interpreted function in the Lisp environment that you would like to compile. The function 2compile* is used to do this. Second, you may have code in an editor buffer that you would like to compile. The Zmacs editor has commands to read code into Lisp and compile it. Third, you may have a program (a group of function definitions and other forms) written in a file on the file system. The function 2compile-file* can translate this file into a 1QFASL* file that describes the compiled functions and associated data. The QFASL file format is capable of representing an arbitrary collection of Lisp objects, including shared structure. The name derives from `Q', a prefix once used to mean ``for the Lisp Machine, not for Maclisp'', and `FASL', an abbreviation for ``fast loading''. =Node: How to Invoke the Compiler =Text: 3HOW TO INVOKE THE COMPILER compile* 1function-spec* &optional 1definition* Compiles an individual interpreted function definition. If 1definition* is supplied, it is the definition to be compiled. Otherwise, the current definition of 1function-spec* is used. If 1function-spec* is non-2nil*, the compiled function is stored as the definition of 1function-spec*, and 1function-spec* is returned. Otherwise, the compiled function object itself is returned. (However, it is preferable to use 2compile-lambda* if your wish is to create a compiled function object without storing it anywhere.) The compiled function object created by 2compile* records the interpreted definition it was made from on its debugging info alist (see 4(FUNCTIONS-2)How Programs Examine Functions*). This is useful in two ways: the function 2uncompile* can be used to reinstall the interpreted definition, and 2compile* invoked again on the same 1function-spec* can find the interpreted definition used before and compile it again. The latter is useful if you have changed some macros or subst functions which the definition refers to. 3uncompile* 1function-spec* If 1function-spec* is defined as a compiled function that records the original definition that was compiled, then 1function-spec* is redefined with that original definition. This undoes the effect of calling 2compile* on 1function-spec*. 3compile-lambda* 1lambda-exp* 1function-spec* Returns a compiled function object produced by compiling 1lambda-exp*. The function name recorded by the compiled function object is 1function-spec*, but that function spec is not defined by 2compile-lambda*. This function is preferable to 2compile* with first argument 2nil* in that it allows you to specify the name for the function to record internally. 3compile-encapsulations* 1function-spec* Compiles all encapsulations that 2function-spec* currently has. Encapsulations (see 4(FUNCTIONS-2)Encapsulations*) include tracing, breakons and advice. Compiling tracing or breakons makes it possible (or at least more possible) to trace or breakon certain functions that are used in the evaluator. Compiling advice makes it less costly to advise functions that are used frequently. Any encapsulation that is changed will cease to be compiled; thus, if you add or remove advice, you must do 2compile-encapsulations* again if you wish the advice to be compiled again. 3compile-encapsulations-flag* 1Variable* If this is non-2nil*, all encapsulations that are created are compiled automatically. 3compile-file* 1input-file* &key 1output-file* 1set-default-pathname* 1package* Compiles the file specified by 1input-file*, a pathname or namestring. The format for files input to the compiler is described on 4(COMPILER-1)Input to the Compiler*. If 1output-file* is specified, it is a pathname used for the compiled file. Otherwise, the ouptut file name is computed from the input file name by specifying 2:qfasl* as the type component. 1package*, if non-2nil* specifies the package in which compilation should be performed. Normally the system knows, or asks interactively, and you need not supply this argument. 1set-default-pathname*, if non-2nil*, means that the defaults should be set to the input file's name. 1set-default-pathname* defaults to 2t*. 3qc-file* 1filename* &optional 1output-file* 1load-flag* 1in-core-flag* 1package* 1file-local-declarations* 1dont-set-default-p* 1read-then-process-flag* An older, obsolete way of invoking the compiler on a file. 1file-local-declarations* is for compiling multiple files as if they were one. 1dont-set-default-p* suppresses the changing of the default file name to 1filename* that normally occurs. The 1load-flag* and 1in-core-flag* arguments were not fully implemented and should not be used. 1read-then-process-flag* causes the entire file to be read and then the entire file to be compiled; this is no longer advantageous now that there is enough memory to avoid thrashing when forms are read and compiled one by one, and it prevents compile-time reader-macros defined in the file from working properly. 3qc-file-load* 1filename* &optional 1output-file* 1load-flag* 1in-core-flag* 1package* 1functions-defined* 1file-local-declarations* 1dont-set-default-p* 1read-then-process-flag* Compiles a file and then loads in the resulting QFASL file. 3compiler:compiler-verbose* 1Variable* If this variable is non-2nil*, the compiler prints the name of each function that it is about to compile. 3compiler:peep-enable* 1Variable* The peephole optimizer is used if this variable is non-2nil*. The only reason to set it to 2nil* is if there is a suspicion of a bug in the optimizer. See also the 2disassemble* function (4(MISCELL-1)Poking Around in the Lisp World*), which lists the instructions of a compiled function in symbolic form. =Node: Input to the Compiler =Text: 3INPUT TO THE COMPILER* The purpose of 2compile-file* is to take a file and produce a translated version which does the same thing as the original except that the functions are compiled. 2compile-file* reads through the input file, processing the forms in it one by one. For each form, suitable binary output is sent to the QFASL file so that when the QFASL file is loaded the effect of that source form will be reproduced. The differences between source files and QFASL files are that QFASL files are in a compressed binary form, which reads much faster but cannot be edited, and that function definitions in QFASL files have been translated from Lisp forms to FEFs. So, if the source contains a 2(defun ...)* form at top level, then when the QFASL file is loaded the function will be defined as a compiled function. If the source file contains a form that is not of a type known specially to the compiler, then that form (encoded in QFASL format) is output ``directly'' into the QFASL file, so that when the QFASL file is loaded that form will be evaluated. Thus, if the source file contains 2(princ "Hello")* at top level, then the compiler puts in the QFASL file instructions to create the list 2(princ "Hello")* and then evaluate it. The Lisp Machine editor Zmacs assumes that source files are formatted so that an open parenthesis at the left margin (that is, in column zero) indicates the beginning of a function definition or other top level list (with a few standard exceptions). The compiler assumes that you follow this indentation convention, enabling it to tell when a close-parenthesis is missing from one function as soon as the beginning of the next function is reached. If the compiler finds an open parenthesis in column zero in the middle of a list, it invents enough close parentheses to close off the list that is in progress. A compiler warning is produced instead of an error. After that list has been processed, the open parenthesis is read again. The compilation of the list that was forcefully closed off is probably useless, but the compilation of the rest of the file is usually correct. You can read the source file into the editor to fix and recompile the function that was unbalanced. A similar thing happens on end of file in the middle of a list, so that you get to see any warnings for the function that was unbalanced. Certain special forms including 2eval-when*, 2progn*, 2local-declare*, 2declare-flavor-instance-variables*, and 2comment* are customarily used around lists that start in column zero. These symbols have a non-2nil* 2si:may-surround-defun* property that makes the compiler permit this. You can add such properties to other symbols if you want. 3compiler:qc-file-check-indentation* 1Variable* If 2nil*, inhibits the compiler from checking for open-parentheses in column zero. Whan a macro definition (2macro* and 2defmacro* forms) is encountered at top level in the file being compiled, the macro definition is recorded for the rest of the compilation so that the macro thus defined can be used in the same file following its definition. This is in addition to writing the compiled macro definition into the QFASL file. Flavor definitions (2defflavor* forms, see 4(FLAVOR-2)Flavor Functions*) and global 2special* declarations (made with 2proclaim*, 4(EVAL-4)Declarations*, or with 2defvar*, 4(EVAL-1)Defining Global Variables*) are likewise recorded for the rest of the compilation, as well as written into the QFASL file so that they will be recorded permanently when the file is loaded. 3sys:file-local-declarations* 1Variable* During file-to-file compilation, the value of this variable is a list of all declarations that are in effect for the rest of the file. Macro definitions, 2defdecl*'s, 2proclaim*'s and special declarations that come from 2defvar*s are all recorded on this list. Package-defining and altering functions such as 2defpackage*, 2in-package*, 2export* and 2use-package* are executed by the compiler in the ordinary, permanent fashion. They are also written in the QFASL file so that the form is executed just the same when the file is loaded. If you load the file later in the same session, the package altering form is executed twice. This is normally harmless. 2require* receives the same treatment. You can control explicitly whether a form is evaluated by the compiler, and whether it is written into the QFASL file to be executed when the file is loaded, using the 2eval-when* construct. You might want a form to be: 2Put into the QFASL file (compiled, of course), or not.* 2Evaluated within the compiler, or not.* 2Evaluated if the source file loaded, or not.* An 2eval-when* form looks like 3(eval-when 1times-list** 3 1form1* 1form2* ...)* The 1times-list* may contain one or more of the symbols 2load*, 2compile*, or 2eval*. If 2load* is present, the 1forms* are written into the QFASL file to be evaluated when the QFASL file is loaded (except that 2defun* forms put the compiled definition into the QFASL file instead). If 2compile* is present, the 1forms* are evaluated in the compiler. If 2eval* is present, the 1forms* are evaluated when read into Lisp; this is because 2eval-when* is defined as a special form in Lisp. (The compiler ignores 2eval* in the 1times-list*.) For example, 3(eval-when (compile eval) (macro foo (x) (cadr x)))* would define 2foo* as a macro in the compiler and when the file is read in interpreted, but not when the QFASL file is fasloaded. 3eval-when* 1(time...)* 1body...* 1Special Form* When seen by the interpreter, if one of the 1times* is the symbol 2eval* then the 1body* forms are evaluated; otherwise 2eval-when* does nothing. But when seen by the compiler, this special form does the special things described above. Nested use of 2eval-when* is permitted but its meaning is tricky. If an inner 2eval-when* form appears in an ordinary context where a general form would be written into the QFASL file but not executed at compile time, then it behaves in the usual fashion: the 1body* forms are written into the QFASL file if 2load* is one of the 1times*, and they are evaluated at compile time if 2compile* is one of the 1times*. If the inner 2eval-when* form appears in a context which says to evaluate at compile time only, then the 1body* forms are evaluated if 2eval* is one of the 1times*. If the inner 2eval-when* appears in a context which says to write into the QFASL file and evaluate at compile time, the the 1body* forms are written into the QFASL file if 2load* is one of the 1times*, and they are evaluated at compile time if either 2compile* or 2eval* is one of the 1times*. For the rest of this section, we will use lists such as are given to 2eval-when*, e.g. 2(load eval)*, 2(load compile)*, etc., to describe when forms are evaluated. If a form is not enclosed in an 2eval-when*, then the times at which it is evaluated depend on the form. The following table summarizes at what times evaluation takes place for any given form seen at top level by the compiler. 2(eval-when 1times-list* 1form* ...)* 1times-list* specifies when the 1form*... should be performed. 2(declare (special ...)) or (declare (unspecial ...))* The 2special* or 2unspecial* is performed at 2(load compile)* time. 2(declare 1anything-else*)* 1anything-else* is performed only at 2(compile)* time. 2(proclaim ...)* is performed at 2(load compile eval)* time. 2(special ...) or (unspecial ...)* 2(load compile eval) (macro ...) or (defmacro ...) or (defsubst ...)* 2or (defflavor ...) or (defstruct ...)(load eval)*. However, during file to file compilation, the definition is recorded temporarily and used for expanding calls to the macro, or macros defined by the 2defstruct* for the rest of the file. 2(comment ...)* Ignored at all times. 2(compiler-let ((1var val*) ...) 1body*...)* Processes the 1body* in its normal fashion, but with the indicated variable bindings in effect. These variables will typically affect the operation of the compiler or of macros. See 4(MACROS-2)Nesting Macros*. 2(local-declare (1decl decl ...*) 1body*...)* Processes the 1body* in its normal fashion, with the indicated declarations added to the front of the list which is the value of 2local-declarations*. 2(defun ...) or (defmethod ...) or (defselect ...)* 2(load eval)*, but at load time what is processed is not this form itself, but the result of compiling it. 2(require ...) or (in-package ...)* 2or various other package functions(load compile eval) 1anything-else** 2(load eval)* Sometimes a macro wants to return more than one form for the compiler top level to see (and to be evaluated). The following facility is provided for such macros. If a form 3(progn 1form1* 1form2* ...)* is seen at the compiler top level, all of the 1forms* are processed as if they had been at compiler top level. (Of course, in the interpreter they are all evaluated.) To prevent an expression from being optimized by the compiler, surround it with a call to 2dont-optimize*. 3dont-optimize* 1form* 1Special Form* In execution, this is equivalent to simply 1form*. However, any source-level optimizations that the compiler would normally perform on the top level of 1form* are not done. Examples: 3(dont-optimize (apply 'foo (list 'a 'b)))* actually makes a list and calls 3apply*, rather than doing 3(foo 'a 'b)* 3(dont-optimize (si:flavor-method-table flav))* actually calls 2si:flavor-method-table* as a function, rather than substituting the definition of that 2defsubst*. 2dont-optimize* can even be used around a 2defsubst* inside of 2setf* or 2locf*, to prevent open-coding of the 2defsubst*. In this case, a function will be created at load time to do the setting or return the location. 3(setf (dont-optimize (zwei:buffer-package buffer)) * 3 (pkg-find-package "foo"))* Subforms of 1form*, such as arguments, are still optimized or open coded, unless additional 2dont-optimize*'s appear around them. =Node: Compile-Time Properties of Symbols =Text: 3COMPILE-TIME PROPERTIES OF SYMBOLS* When symbol properties are referred to during macro expansion, it is desirable for properties defined in a file to be ``in effect'' for the the rest of the file if the file is compiled. This does not happen if 2get* and 2defprop* are used, because the 2defprop* will not be executed until the QFASL file is loaded. Instead, you can use 2getdecl* and 2defdecl*. These are normally the same as 2get* and 2defprop*, but during file-to-file compilation they also refer to and create declarations. 3getdecl* 1symbol* 1property* This is a version of 2get* that allows the properties of the 1symbol* to be overridden by declarations. If a declaration of the form 2(1property* 1symbol* 1value*)* is in effect, 2getdecl* returns 1value*. Otherwise, 2getdecl* returns the result of 2(get 1symbol* 1property*)*. If you intend to create such declarations with 2proclaim* or local use of 2declare*, you must make sure that a 2declaration* declaration is in effect for 1property*. You can do this with 2(proclaim* 2'(declaration 1property*))*. 2getdecl* is typically used in macro definitions. For example, the 2setf* macro uses 2getdecl* to get the properties which say how to store in the specified place. See 4(MACROS-2)Nesting Macros* for an example of a macro that uses 2getdecl*. 3putdecl* 1symbol* 1property* 1value* Causes 2(getdecl 1symbol* 1property*)* to return 1value*. 2putdecl* usually simply does a 2putprop*. But if executed at compile time during file-to-file compilation, it instead makes an entry on 2file-local-declarations* of the form 2(1property* 1symbol** 1value2)**. In either case, this stores 1value* where 2getdecl* can find it; but if 2putdecl* is done during compilation, it affects only the rest of that compilation. 3defdecl* 1symbol* 1property* 1value* 1Special Form* When executed, this is like 2putdecl* except that the arguments are not evaluated. It is usually the same as 2defprop* except for the order of the arguments. Unlike 2defprop*, when 2defdecl* is encountered during file-to-file compilation, a declaration is recorded which remains in effect for the rest of the compilation. (The 2defdecl* form also goes into the QFASL file to be executed when the file is loaded). 2defprop* would have no effect whatever at compile time. 2defdecl* is often useful as a part of the expansion of a macro. It is also useful as a top-level expression in a source file. Example: 3(defdecl foo locf foo-location)* in a source file would allow 2(locf (foo 1args*...))* to be used in the rest of that source file; and, once the file was loaded, by anyone. Simple use 2defsetf* expands into a 2defdecl*. =Node: Using Compiler Warnings =Text: 3USING COMPILER WARNINGS* When the compiler prints warnings, it also records them in a data base, organized by file and by function within file. Old warnings for previous compilations of the same function are thrown away, so the data base contains only warnings that are still applicable. This data base can be used to visit, in the editor, the functions that got warnings. You can also save the data base and restore it later. There are three editor commands that you can use to begin visiting the sites of the recorded warnings. They differ only in how they decide which files to look through: 2Meta-X Edit Warnings* For each file that has any warnings, asks whether to edit the warnings for that file. 2Meta-X Edit File Warnings* Reads the name of a file and then edits the warnings for that file. 2Meta-X Edit System Warnings* Reads the name of a system and then edits the warnings for all files in that system (see 2defsystem*, 4(SYSTEMS-1)Defining a System*). While the warnings are being edited, the warnings themselves appear in a small window at the top of the editor frame, and the code appears in a large window which occupies the rest of the editor frame. As soon as you have finished specifying the file(s) or system to process, the editor proceeds to visit the code for the first warning. From then on, to move to the next warning, use the command 2Control-Shift-W*. To move to the previous warning, use 2Meta-Shift-W*. You can also switch to the warnings window with 2Control-X O* or with the mouse, and move around in that buffer. When you use 2Control-Shift-W* and there are no more warnings after the cursor, you return to single-window mode. You can also insert the text of the warnings into any editor buffer: 2Meta-X Insert File Warnings* Reads the name of a file and inserts into the buffer after point the text for that file's warnings. The mark is left after the warnings, but the region is not turned on. 2Meta-X Insert Warnings* Inserts into the buffer after point the text for the warnings of all files that have warnings. The mark is left after the warnings, but the region is not turned on. You can also dump the warnings data base into a file and reload it later. Then you can do 2Meta-X Edit Warnings* again in the later session. You dump the warnings with 2si:dump-warnings* and load the file again with 2load*. In addition, 2make-system* with the 2:batch* option writes all the warnings into a file in this way. 3si:dump-warnings* 1output-file-pathname* &rest 1warnings-file-pathnames* Writes the warnings for the files named in 1warnings-file-pathnames* (a list of pathnames or strings) into a file named 1output-file-pathname*. 3compiler:warn-on-errors* 1Variable* If this variable is non-2nil*, errors in reading code to be compiled, and errors in macro expansion within the compiler, produce only warnings; they do not enter the debugger. The variable is normally 2t*. The default setting is useful when you do not anticipate errors during compilation, because it allows the compilation to proceed past such errors. If you have walked away from the machine, you do not come back to find that your compilation stopped in the first file and did not finish. If you find an inexplicable error in reading or macroexpansion, and wish to use the debugger to localize it, set 2compiler:warn-on-errors* to 2nil* and recompile. =Node: Controlling Compiler Warnings =Text: 3CONTROLLING COMPILER WARNINGS* By controlling the compile-time values of the variables 2run-in-maclisp-switch*, 2obsolete-function-warning-switch*, and 2inhibit-style-warning-switch* (explained above), you can enable or disable some of the warning messages of the compiler. The following special form is also useful: 3inhibit-style-warnings* 1form* 1Macro* Prevents the compiler from performing style-checking on the top level of 1form*. Style-checking is still done on the arguments of 1form*. Both obsolete function warnings and won't-run-in-Maclisp warnings are done by means of the style-checking mechanism, so, for example, 3(setq bar (inhibit-style-warnings (value-cell-location foo)))* does not warn that 2value-cell-location* will not work in Maclisp, but 3(inhibit-style-warnings (setq bar (value-cell-location foo)))* does warn, since 2inhibit-style-warnings* applies only to the top level of the form inside it (in this case, to the 2setq*). Sometimes functions take arguments that they deliberately do not use. Normally the compiler warns you if your program binds a variable that it never references. In order to disable this warning for variables that you know you are not going to use, there are three things you can do. .vindex ignore The first thing is to name the variables 2ignore* or 2ignored*. The compiler does not complain if a variable by one of these names is not used. Furthermore, by special dispensation, it is all right to have more than one variable in a lambda-list that has one of these names. Another thing you can do is write an 2ignore* declaration. Example: 3(defun the-function (list fraz-name fraz-size)* 3 (declare (ignore fraz-size)))* This has the advantage that 2arglist* (see 4(FUNCTIONS-2)How Programs Examine Functions*) will return a more meaningful argument list for the function, rather than returning something with 2ignore*'s in it. Finally, you can simply use the variable for effect (ignoring its value) at the front of the function. Example: 3(defun the-function (list fraz-name fraz-size)* 3 fraz-size ; This argument is not used.* 3 ...)* The following function is useful for requesting compiler warnings in certain esoteric cases. Normally, the compiler notices whenever any function 1x* uses (calls) any other function 1y*; it makes notes of all these uses, and then warns you at the end of the compilation if the function 1y* got called but no definition of it has been seen. This usually does what you want, but sometimes there is no way the compiler can tell that a certain function is being used. Suppose that instead of 1x*'s containing any forms that call 1y*, 1x* simply stores 1y* away in a data structure somewhere, and someplace else in the program that data structure is accessed and 2funcall* is done on it. There is no way that the compiler can see that this is going to happen, and so it can't notice the function usage, and so it can't create a warning message. In order to make such warnings happen, you can explicitly call the following function at compile-time. 3compiler:function-referenced* 1what* 1by* 1what* is a symbol that is being used as a function. 1by* may be any function spec. 2compiler:function-referenced* must be called at compile-time while a compilation is in progress. It tells the compiler that the function 1what* is referenced by 1by*. When the compilation is finished, if the function 1what* has not been defined, the compiler issues a warning to the effect that 1by* referred to the function 1what*, which was never defined. You can also tell the compiler about any function it should consider ``defined'': 3compiler:compilation-define* 1function-spec* 1function-spec* is marked as ``defined'' for the sake of the compiler; future calls to this function will not produce warnings. 3compiler:make-obsolete* 1function* 1reason* 1Macro* This special form declares a function to be obsolete; code that calls it will get a compiler warning, under the control of 2obsolete-function-warning-switch*. This is used by the compiler to mark as obsolete some Maclisp functions which exist in Zetalisp but should not be used in new programs. It can also be useful when maintaining a large system, as a reminder that a function has become obsolete and usage of it should be phased out. An example of an obsolete-function declaration is: 3(compiler:make-obsolete create-mumblefrotz* 3 "use MUMBLIFY with the :FROTZ option instead")* =Node: Recording Warnings =Text: 3RECORDING WARNINGS* The warnings data base is not just for compilation. It can record operations for any number of different operations on files or parts of files. Compilation is merely the only operation in the system that uses it. Each operation about which warnings can be recorded should have a name, preferably in the keyword package. This symbol should have four properties that tell the system how to print out the operation name as various parts of speech. For compilation, the operation name is 2:compile* and the properties are defined as follows: 3(defprop :compile "compilation" si:name-as-action)* 3(defprop :compile "compiling" si:name-as-present-participle)* 3(defprop :compile "compiled" si:name-as-past-participle)* 3(defprop :compile "compiler" si:name-as-agent)* The warnings system considers that these operations are normally performed on files that are composed of named objects. Each warning is associated with a filename and then with an object within the file. It is also possible to record warnings about objects that are not within any file. To tell the warnings system that you are starting to process all or part of a file, use the macro 2si:file-operation-with-warnings*. 3sys:file-operation-with-warnings* 1(generic-pathname* 1operation-name* 1whole-file-p)* 1body...Macro* 1body* is executed within a context set up so that warnings can be recorded for operation 1operation-name* about the file specified by 1generic-pathname* (see ). In the case of compilation, this is done at the level of 2compile-file* (actually, it is done in 2compiler:compile-stream*). 1whole-file-p* should be non-2nil* if the entire contents of the file are to be processed inside the 1body* if it finishes; this implies that any warnings left over from previous iterations of this operation on this file should be thrown away on exit. This is only relevant to objects that are not found in the file this time; the assumption is that the objects must have been deleted from the file and their warnings are no longer appropriate. All three of the special arguments are specified as expressions that are evaluated. Within the processing of a file, you must also announce when you are beginning to process an object: 3sys:object-operation-with-warnings* 1(object-name* 1location-function)* 1body...* 1Macro* Executes 1body* in a context set up so that warnings are recorded for the object named 1object-name*, which can be a symbol or a list. Object names are compared with 2equal*. In the case of compilation, this macro goes around the processing of a single function. 1location-function* is either 2nil* or a function that the editor uses to find the text of the object. Refer to the file 2SYS: ZWEI; POSS LISP* for more details on this. 1object-name* and 1location-function* are specified with expressions that are evaluated. You can enter this macro recursively. If the inner invocation is for the same object as the outer one, it has no effect. Otherwise, warnings recorded in the inner invocation apply to the object specified therein. Finally, when you detect exceptions, you must make the actual warnings: 3sys:record-warning* 1type* 1severity* 1location-info* 1format-string* &rest 1args* Records one warning for the object and file currently being processed. The text of the warning is specified by 1format-string*and 1args*, which are suitable arguments for 2format*, but the warning is 1not* printed when you call this function. Those arguments will be used to reprint the warning later. 3sys:record-and-print-warning* 1type* 1severity* 1location-info* 1format-string* &rest 1args* Records a warning and also prints it. 1type* is a symbol that identifies the specific cause of the warning. Types have meaning only as defined by a particular operation, and at present nothing makes much use of them. The system defines one type: 2si:premature-warnings-marker*. 1severity* measures how important a warning this is, and the general causal classification. It should be a symbol in the keyword package. Several severities are defined, and should be used when appropriate, but nothing looks at them: 2:implausible* This warning is about something that is not intrinsically wrong but is probably due to a mistake of some sort. 2:impossible* This warning is about something that cannot have a meaning even if circumstances outside the text being processed are changed. 2:probable-error* This is used to indicate something that is certainly an error but can be made correct by a change somewhere else; for example, calling a function with the wrong number of arguments. 2:missing-declaration* This is used for warnings about free variables not declared special, and such. It means that the text was not actually incorrect, but something else that is supposed to accompany it was missing. 2:obsolete* This warning is about something that you shouldn't use any more, but which still does work. 2:very-obsolete* This is about something that doesn't even work any more. 2:maclisp* This is for something that doesn't work in Maclisp. 2:fatal* This indicates a problem so severe that no sense can be made of the object at all. It indicates that the presence or absence of other warnings is not significant. 2:error* There was a Lisp error in processing the object. 1location-info* is intended to be used to inform the editor of the precise location in the text of the cause of this warning. It is not defined as yet, and you should use 2nil*. If a warning is encountered while processing data that doesn't really have a name (such as forms in a source file that are not function definitions), you can record a warning even though you are not inside an invocation of 2sys:object-operation-with-warnings*. This warning is known as a 1premature warning* and it will be recorded with the next object that is processed; a message will be added so that the user can tell which warnings were premature. Refer to the file 2SYS: SYS; QNEW LISP* for more information on the warnings data base.