{Begin SubSec Global Variables} {Title Global Variables} {Text {Tag GLOBALVARS} Variables that appear on the list {index *PRIMARY* GLOBALVARS Var}{var GLOBALVARS}, or have the property {prop GLOBALVAR}{index *PRIMARY* GLOBALVAR Prop} with value {lisp T}, or are declared with the {filecom GLOBALVARS} file package command ({PageRef FileCom GLOBALVARS}), are called global variables. Such variables are always accessed through their top level value when they are used freely in a compiled function. In other words, a reference to the value of this variable is equivalent to {lisp (GETTOPVAL (QUOTE {arg VARIABLE}))}, regardless of whether or not it is bound in the current access chain. Similarly, {lisp (SETQ {arg VARIABLE} {arg VALUE})} will compile as {lisp (SETTOPVAL (QUOTE {arg VARIABLE}) {arg VALUE})}. All system parameters, unless otherwise specified, are declared as global variables. Thus, {it rebinding} these variables in a deep bound system (like Interlisp-D) will not affect the behavior of the system: instead, the variables must be {it reset} to their new values, and if they are to be restored to their original values, reset again. For example, the user might write {Lispcode (SETQ {arg GLOBALVARIABLE} {arg NEWVALUE}) {arg FORM} (SETQ {arg GLOBALVARIABLE} {arg OLDVALUE})} {note should more clearly explain difference between rebinding and resetting} Note that in this case, if an error occurred during the evaluation of {arg FORM}, or a {index control-D}control-D was typed, the global variable would not be restored to its original value. The function {index RESETVAR FN}{fn RESETVAR} ({PageRef Fn RESETVAR}) provides a convenient way of resetting global variables{index global variables} in such a way that their values are restored even if an error occurred or {index control-D}control-D is typed. Note: Interlisp-10 employs a {index shallow binding}shallow binding scheme as described on {PageRef Tag Stack}. There is no distinction between global variables and other types of variables: all variable references are to the variable's value cell. Thus, the cost of {it accessing} a variable is small and independent of the depth of computation, whereas in a deep bound system, it can be expensive to search the stack for the most recent binding of a variable, hence the need for a mechanism like global variables. Note however that in a shallow bound system, the cost of rebinding a variable is somewhat higher than in a deep bound system (except when the variable is a {lisp LOCALVAR}). For the purposes of compilation, global variables are treated the same as {lisp SPECVARS}, i.e. their names are always visible on the stack when they are rebound. }{End SubSec Global Variables} {Begin SubSec LOCALVARS and SPECVARS} {Title LOCALVARS and SPECVARS} {Text {Tag LOCALVARS} {Tag SPECVARS} In normal compiled and interpreted code, all variable bindings are accessible by lower level functions because the variable's name is associated with its value. We call such variables {it special} variables, or specvars. As mentioned earlier, the block compiler normally does {it not} associate names with variable values. Such unnamed variables are not accessible from outside the function which binds them and are therefore {it local} to that function. We call such unnamed variables local variables, or localvars. The time economies of local variables can be achieved without block compiling by use of declarations. Using local variables will increase the speed of compiled code; the price is the work of writing the necessary specvar declarations for those variables which need to be accessed from outside the block. {var LOCALVARS}{index *PRIMARY* LOCALVARS Var} and {var SPECVARS}{index *PRIMARY* SPECVARS Var} are variables that affect compilation. During regular compilation, {var SPECVARS} is normally {lisp T}, and {var LOCALVARS} is {lisp NIL} or a list. This configuration causes all variables bound in the functions being compiled to be treated as special {it except} those that appear on {var LOCALVARS}. During block compilation, {var LOCALVARS} is normally {lisp T} and {var SPECVARS} is {lisp NIL} or a list. All variables are then treated as local {it except} those that appear on {var SPECVARS}. Declarations to set {var LOCALVARS} and {var SPECVARS} to other values, and therefore affect how variables are treated, may be used at several levels in the compilation process with varying scope. (1) The declarations may be included in the filecoms of a file, by using the {filecom LOCALVARS} and {filecom SPECVARS} file package commands ({PageRef FileCom LOCALVARS}). The scope of the declaration is then the entire file: {lispcode {ellipsis} (LOCALVARS . T) (SPECVARS X Y) {ellipsis}} (2) The declarations may be included in block declarations; the scope is then the block, e.g., {lispcode (BLOCKS ((FOOBLOCK FOO FIE (SPECVARS . T) (LOCALVARS X)))} (3) The declarations may also appear in individual functions, or in {fn PROG}'s or {lisp LAMBDA}'s within a function, using the {fn DECLARE}{index *PRIMARY* DECLARE Fn} function. In this case, the scope of the declaration is the function or the {fn PROG} or {lisp LAMBDA} in which it appears. {var LOCALVARS} and {var SPECVARS} declarations must appear immediately after the variable list in the function, {fn PROG}, or {lisp LAMBDA}, but intervening comments are permitted. For example: {lispcode (DEFINEQ ((FOO (LAMBDA (X Y) (DECLARE (LOCALVARS Y)) (PROG (X Y Z) (DECLARE (LOCALVARS X)) ... ]} If the above function is compiled (non-block), the outer {lisp X} will be special, the {lisp X} bound in the {fn PROG} will be local, and both bindings of {lisp Y} will be local. Declarations for {var LOCALVARS} and {var SPECVARS} can be used in two ways: either to cause variables to be treated the same whether the function(s) are block compiled or compiled normally, or to affect one compilation mode while not affecting the default in the other mode. For example: {lispcode (LAMBDA (X Y) (DECLARE (SPECVARS . T)) (PROG (Z) ... ]} will cause {lisp X}, {lisp Y}, and {lisp Z} to be specvars for both block and normal compilation while {lispcode (LAMBDA (X Y) (DECLARE (SPECVARS X)) ... ]} will make {lisp X} a specvar when block compiling, but when regular compiling the declaration will have no effect, because the default value of specvars would be {lisp T}, and therefore {it both} {lisp X} and {lisp Y} will be specvars by default. Although {var LOCALVARS} and {var SPECVARS} declarations have the same form as other components of block declarations such as {lisp (LINKFNS . T)}, their operation is somewhat different because the two variables are not independent. {lisp (SPECVARS . T)} will cause {var SPECVARS} to be set to {lisp T}, and {var LOCALVARS} to be set to {lisp NIL}. {lisp (SPECVARS V1 V2 ...)} will have {it no} effect if the value of {var SPECVARS} is {lisp T}, but if it is a list (or {lisp NIL}), {var SPECVARS} will be set to the union of its prior value and {lisp (V1 V2 ...)}. The operation of {var LOCALVARS} is analogous. Thus, to affect both modes of compilation one of the two ({var LOCALVARS} or {var SPECVARS}) must be declared {lisp T} before specifying a list for the other. }{End SubSec LOCALVARS and SPECVARS} {Begin SubSec Constants} {Title Constants} {Text {index constants in compiled code} Interlisp allows the expression of constructions which are intended to be description of their constant values. The function {fn CONSTANT}{index *PRIMARY* CONSTANT Fn} enables the user to define certain expressions as descriptions of their "constant" values. For example, if a user program needed a list of 30 {lisp NIL}s, the user could specify {lisp (CONSTANT (to 30 collect NIL))} instead of {lisp (QUOTE (NIL NIL {ellipsis}))}. The former is more concise and displays the important parameter much more directly than the latter. {fn CONSTANT} can also be used to denote values that cannot be quoted directly, such as {lisp (CONSTANT (PACK NIL))}, {lisp (CONSTANT (ARRAY 10))}. It is also useful to parameterize quantities that are constant at run time but may differ at compile time, e.g., {lisp (CONSTANT BITSPERWORD)} in a program is exactly equivalent to 36, if the variable {lisp BITSPERWORD} is bound to 36 when the {fn CONSTANT} expression is evaluated at compile time. When interpreted, the expression occuring as the argument to {fn CONSTANT} is evaluted each time it is encountered. If the {fn CONSTANT} form is compiled, however, the expression will be evaluated only once: If the value of the expression has a readable print-name, then it will be evaluated at compile-time, and the value will be saved as a literal in the compiled function's definition, as if {lisp (QUOTE {arg VALUE-OF-EXPRESSION})} had appeared instead of {lisp (CONSTANT {arg EXPRESSION})}. If the value does not have a readable printname (e.g. the {lisp PACK} and {lisp ARRAY} examples above), then the expression itself will be saved with the function, and it will be evaluated when the function is first loaded. The value will then be stored in the function's literals, and will be retrieved on future references. Whereas the function {fn CONSTANT} attempts to evaluate the expression as soon as possible (compile-time, load-time, or first-run-time), other options are available. The special form {fn LOADTIMECONSTANT}{index *PRIMARY* LOADTIMECONSTANT Fn} specifies a special form whose execution is to be deferred until the compiled code for the containing function is loaded in. (If a {lisp LOADTIMECONSTANT} form is interpreted, it merely returns its argument. For example, {lisp (LOADTIMECONSTANT (DATE))} will return the date the code was loaded. The function {fn DEFERREDCONSTANT}{index *PRIMARY* DEFERREDCONSTANT Fn} will always defer the evaluation until first running. This is useful when the storage for the constant is excessive so that it shouldn't be allocated until (unless) the function is actually invoked. Note: The function {fn SELECTC} ({PageRef Fn SELECTC}) provides a mechanism for conparing a value to a number of constants. {FnDef {Name CONSTANTS} {Args VAR{sub 1} VAR{sub 2} {ellipsis} VAR{sub N}} {Type NOSPREAD NLAMBDA} {Text Defines {arg VAR{sub 1}}, {ellipsis} {arg VAR{sub N}} (unevaluated) to be compile-time constants. Whenever the compiler encounters a (free) reference to one of these constants, it will compile the form {lisp (CONSTANT {arg VAR{sub i}})} instead. If {arg VAR{sub i}} is a list of the form {lisp ({arg VAR} {arg FORM})}, a free reference to the variable will compile as {lisp (CONSTANT {arg FORM})}. Constants can be saved using the {filecom CONSTANTS} file package command ({PageRef FileCom CONSTANTS}). }} }{End SubSec Constants} {Begin SubSec Compiling Function Calls} {Title Compiling Function Calls} {Text {Tag CompilingNLAMBDAs} {index *BEGIN* compiling function calls} When compiling the call to a function, the compiler must know the type of the function, to determine how the arguments should be prepared (evaluated/unevaluated, spread/nospread). There are three seperate cases: lambda, nlambda spread, and nlambda nospread functions. To determine which of these three cases is appropriate, the compiler will first look for a definition among the functions in the file that is being compiled. The function can be defined anywhere in any of the files given as arguments to {fn BCOMPL}, {fn TCOMPL}, {fn BRECOMPILE} or {fn RECOMPILE}.{note even in later files (if more than one compiled)?} If the function is not contained in the file, the compiler will look for other information in the variables {var NLAMA}, {var NLAML}, and {var LAMS}, which can be set by the user: {VarDef {Name NLAMA} {Text (for {lisp NLAM}bda {lisp A}toms) A list of functions to be treated as nlambda nospread functions by the compiler. }} {VarDef {Name NLAML} {Text (for {lisp NLAM}bda {lisp L}ist) A list of functions to be treated as nlambda spread functions by the compiler. }} {VarDef {Name LAMS} {Text A list of functions to be treated as lambda functions by the compiler. Note that including functions on {var LAMS} is only necessary to override in-core nlambda definitions, since in the absence of other information, the compiler assumes the function is a lambda. }} If the function is not contained in a file, or on the lists {var NLAMA}, {var NLAML}, or {var LAMS}, the compiler will look for a current definition in the Interlisp system, and use its type. If there is no current definition, next {var COMPILEUSERFN} is called: {VarDef {Name COMPILEUSERFN} {Text When compiling a function call, if the function type cannot be found by looking in files, the variables {var NLAMA}, {var NLAML}, or {var LAMS}, or at a current definition, then if the value of {index *PRIMARY* COMPILEUSERFN Var}{var COMPILEUSERFN} is not {lisp NIL}, the compiler calls (the value of) {var COMPILEUSERFN} giving it as arguments {fn CDR} of the form and the form itself, i.e., the compiler does {lisp (APPLY* COMPILEUSERFN (CDR {arg FORM}) {arg FORM})}. If a non-{lisp NIL} value is returned, it is compiled instead of {arg FORM}. If {lisp NIL} is returned, the compiler compiles the original expression as a call to a lambda spread that is not yet defined. Note that {var COMPILEUSERFN} is only called when the compiler encounters a {it list} {fn CAR} of which is not the name of a defined function. The user can instruct the compiler about how to compile other data types via {var COMPILETYPELST},{index COMPILETYPELST Var} {PageRef Var COMPILETYPELST}. {index CLISP and compiler}{index compiling CLISP}CLISP uses {var COMPILEUSERFN} to tell the compiler how to compile iterative statements, {lisp IF-THEN-ELSE} statements, and pattern match constructs (See {PageRef Tag CompilingCLISP}). }} {note how can COMPILEUSERFN be of any use, If it is defined by CLISP? Can/should users advise it??} If the compiler cannot determine the function type by any of the means above, it assumes that the function is a lambda function, and its arguments are to be evaluated. The function is also added to the value of {var ALAMS}: {VarDef {Name ALAMS} {Text (for {lisp A}ssumed {lisp LAM}bda{lisp S}) A list of functions to that the compiler has assumed to be lambda functions. {var ALAMS} is not used by the compiler; it is maintained for the user's benefit so that the user can check to see whether any incorrect assumptions were made. }} If there are nlambda functions called from the functions being compiled, and they are only defined in a separate file, they must be included on {var NLAMA} or {var NLAML}, or the compiler will incorrectly assume that their arguments are to be evaluated, and compile the calling function correspondingly. Note that this is only necessary if the compiler does not "know" about the function. If the function is defined at compile time, or is handled via a macro, or is contained in the same group of files as the functions that call it, the compiler will automatically handle calls to that function correctly. {index *END* compiling function calls} }{End SubSec Compiling Function Calls} {Begin SubSec FUNCTION and Functional Arguments} {Title FUNCTION and Functional Arguments} {Text {Tag CompilingFUNCTION} {index compiling FUNCTION} {index functional arguments} Compiling the function {fn FUNCTION} ({PageRef Fn FUNCTION}) may involve creating and compiling a seperate "auxiliary function", which will be called at run time. An auxiliary function is named by attaching a {fn GENSYM} ({PageRef Fn GENSYM}) to the end of the name of the function in which they appear, e.g., {lisp FOOA0003}. For example, suppose {lisp FOO} is defined as {lisp (LAMBDA (X) {ellipsis} (FOO1 X (FUNCTION {ellipsis})) {ellipsis})} and compiled. When {lisp FOO} is run, {lisp FOO1} will be called with two arguments, {lisp X}, and {lisp FOOA000{arg N}} and {lisp FOO1} will call {lisp FOOA000{arg N}} each time it uses its functional argument. Compiling {fn FUNCTION} will {it not} create an auxiliary function if it is a functional argument to a function that compiles open, such as most of the mapping functions ({fn MAPCAR}, {fn MAPLIST}, etc.). Note that a considerable savings in time could be achieved by making {lisp FOO1} compile open via a computed macro ({PageRef Tag Macros}), e.g. {lispcode (Z (LIST (SUBST (CADADR Z) (QUOTE FN) {arg DEF}) (CAR Z)))} {arg DEF} is the definition of {lisp FOO1} as a function of just its first argument, and {lisp FN} is the name used for its functional argument in its definition. In this case, {lisp (FOO1 X (FUNCTION {ellipsis}))} would compile as an expression, containing the argument to {fn FUNCTION} as an open {lisp LAMBDA} expression. Thus you save not only the function call to {lisp FOO1}, but also each of the function calls to its functional argument. For example, if {lisp FOO1} operates on a list of length ten, eleven function calls will be saved. Of course, this savings in time costs space, and the user must decide which is more important. {note won't code be generated for every time the fn is called in FOO1 ???} }{End SubSec FUNCTION and Functional Arguments} {Begin SubSec Open Functions} {Title Open Functions} {Text {index *BEGIN* open functions} When a function is called from a compiled function, a system routine is invoked that sets up the parameter and control push lists as necessary for variable bindings and return information. If the amount of time spent {it inside} the function is small, this function calling time will be a significant percentage of the total time required to use the function. Therefore, many "small" functions, e.g., {fn CAR}, {fn CDR}, {fn EQ}, {fn NOT}, {fn CONS} are always compiled "open", i.e., they do not result in a function call. Other larger functions such as {fn PROG}, {fn SELECTQ}, {fn MAPC}, etc. are compiled open because they are frequently used. The user can make other functions compile open via {index MACRO Prop}{prop MACRO} definitions (see {PageRef Tag Macros}). The user can also affect the compiled code via {index COMPILEUSERFN Var}{var COMPILEUSERFN} ({PageRef Var COMPILEUSERFN}) and {var COMPILETYPELST} ({PageRef Var COMPILETYPELST}). {note list of open functions commented out --- do we really need this list here? does anyone ever use it? How can we be sure this list is correct? ---mjs} {Begin Comment} note: is it really necessary to have this list?? isn't there some way for people to find out whether a given function compiles open?? In Interlisp-D, aren't all open-compiled fns done with macros (except for a few special ones (like COND) that the compiler treats specially) ?? How about in Interlisp-10?? Frankly, I wonder if anyone has ever looked at this list! ---------- It is useful to know exactly which functions are compiled open in order to determine where a program is spending its time. Therefore below is a list of those functions which when compiled do not result in function calls. The following functions compile open{foot Some of these compile in-line via macro expansions and some compile so as to use a {lisp PUSHJ} to jump into system code. The important point from the user's standpoint is that all of them do not require a function call. }{comment endfootnote} in Interlisp-10: {lisp AC}, {lisp ADD1}, {lisp AND}, {lisp APPLY*}, {lisp ARG},{foot when the {lisp ARG} variable is bound locally. }{comment endfootnote} {lisp ARRAYP}, {lisp ASSEMBLE}, {lisp ATOM}, {lisp BLKAPPLY}, {lisp BLKAPPLY*}, {lisp BOUNDP}, {lisp CAR}, {lisp CDR}, {lisp CAAR}, {ellipsis} {lisp CDDDAR}, {lisp CDDDDR}, {lisp CLOSER}, {lisp COND}, {lisp CONS}, {lisp CONSTANT}, {lisp COROUTINE}, {lisp DOCOLLECT}, {lisp ENDCOLLECT}, {lisp EQ}, {lisp EQMEMB}, {lisp ERSETQ}, {lisp EVALV},{foot when given only one argument. }{comment endfootnote} {lisp EVERY}, {lisp EVQ}, {lisp FASSOC}, {lisp FCHARACTER}, {lisp FDIFFERENCE}, {lisp FGETD}, {lisp FGREATERP}, {lisp FIX}, {lisp FIXP}, {lisp FLAST}, {lisp FLENGTH}, {lisp FLOAT}, {lisp FLOATP}, {lisp FMEMB}, {lisp FMINUS}, {lisp FNTH}, {lisp FPLUS}, {lisp FQUOTIENT}, {lisp FRPLACA}, {lisp FRPLACD}, {lisp FRPLNODE}, {lisp FRPLNODE2}, {lisp FRPTQ}, {lisp FTIMES}, {lisp FUNCTION}, {lisp GENERATOR}, {lisp GEQ},{foot i.e., compiles open as a call to {lisp LESSP}. However, there is still this function call associated with the {lisp GEQ} expression. }{comment endfootnote} {lisp GETATOMVAL}, {lisp GETFILEPTR}, {lisp GETHASH}, {lisp GETPROPLIST}, {lisp GO}, {lisp IDIFFERENCE}, {lisp IEQP}, {lisp IGEQ}, {lisp IGREATERP}, {lisp ILEQ}, {lisp ILESSP}, {lisp IMINUS}, {lisp INTERRUPTABLE}, {lisp IPLUS}, {lisp IQUOTIENT}, {lisp IREMAINDER}, {lisp ITIMES}, {lisp JSYS},{foot When the jsys number is itself a small integer, and {lisp RESULTAC} is either a small number or {lisp NIL}, e.g. {lisp (JSYS 51Q)} but not {lisp (JSYS N)}. }{comment endfootnote} {lisp KWOTE}, {lisp LEQ},{foot See footnote to {lisp GEQ} above. }{comment endfootnote} {lisp LISPXWATCH}, {lisp LIST}, {lisp LISTP}, {lisp LITATOM}, {lisp LLSH}, {lisp LOC}, {lisp LOGAND}, {lisp LOGOR}, {lisp LOGXOR}, {lisp LRSH}, {lisp LSH}, {lisp MAP}, {lisp MAPC}, {lisp MAPCAR}, {lisp MAPCON}, {lisp MAPCONC}, {lisp MAPLIST}, {lisp MINUSP}, {lisp MKLIST}, {lisp NCONC1}, {lisp NEQ}, {lisp NLISTP}, {lisp NLSETQ}, {lisp NOT}, {lisp NOTEVERY}, {lisp NOTANY}, {lisp NTYP}, {lisp NULL}, {lisp NUMBERP}, {lisp OPENR}, {lisp OR}, {lisp POSSIBILITIES}, {lisp PROG}, {lisp PROG1}, {lisp PROGN}, {lisp RESETFORM}, {lisp RESETLST}, {lisp RESETSAVE}, {lisp RESETVAR}, {lisp RESETVARS}, {lisp RETURN}, {lisp RPTQ}, {lisp RSH}, {lisp SELECTQ}, {lisp SET}, {lisp SETARG}, {lisp SETATOMVAL}, {lisp SETN}, {lisp SETPROPLIST}, {lisp SETQ}, {lisp SETQQ}, {lisp SMALLP}, {lisp SOME}, {lisp STACKP}, {lisp STRINGP}, {lisp SUB1}, {lisp SUBSET}, {lisp SYNTAXP},{foot when class is quoted, e.g. {lisp (SYNTAXP X (QUOTE BREAK))}. }{comment endfootnote} {lisp SYSTEMTYPE}, {lisp TRYNEXT}, {lisp TYPENAMEP}, {lisp TYPEP}, {lisp UNDONLSETQ}, {lisp VAG}, {lisp ZEROP}. {End Comment} {index *END* open functions} }{End SubSec Open Functions} {Begin SubSec COMPILETYPELST} {Title COMPILETYPELST} {Text {index COMPILETYPELST Var} {index compiling by datatype} Most of the compiler's mechanism deals with how to handle forms (lists) and variables (literal atoms). The user can affect the compiler's behaviour with respect to lists and literal atoms in a number of ways, e.g. macros, declarations, {var COMPILEUSERFN} ({PageRef Var COMPILEUSERFN}), etc. {var COMPILETYPELST} allows the user to tell the compiler what to do when it encounters a data type {it other} than a list or an atom. It is the facility in the compiler that corresponds to {fn DEFEVAL} ({PageRef Fn DEFEVAL}) for the interpreter. {VarDef {Name COMPILETYPELST} {Text A list of elements of the form {lisp ({arg TYPENAME} . {arg FUNCTION})}. Whenever the compiler encounters a datum that is not a list and not an atom (or a number) in a context where the datum is being evaluated, the type name of the datum is looked up on {var COMPILETYPELST}. If an entry appears {fn CAR} of which is equal to the type name, {fn CDR} of that entry is applied to the datum. If the value returned by this application is {it not} {fn EQ} to the datum, then that value is compiled instead. If the value {it is} {fn EQ} to the datum, or if there is no entry on {var COMPILETYPELST} for this type name, the compiler simply compiles the datum as {lisp (QUOTE {arg DATUM})}. }} }{End SubSec COMPILETYPELST} {Begin SubSec Compiling CLISP} {Title Compiling CLISP} {Text {Tag CompilingCLISP} {index *PRIMARY* compiling CLISP} Since the compiler does not know about CLISP, in order to compile functions containing CLISP constructs, the definitions must first be {fn DWIMIFY}ed ({PageRef Fn DWIMIFY}). The user can automate this process in several ways: (1) If the variable {index DWIMIFYCOMPFLG Var}{var DWIMIFYCOMPFLG} is {lisp T}, the compiler will always {fn DWIMIFY} expressions before compiling them. {var DWIMIFYCOMPFLG} is initially {lisp NIL}. (2) If a file has the property {index FILETYPE Prop}{prop FILETYPE} with value {lisp CLISP} on its property list, {fn TCOMPL}, {fn BCOMPL}, {fn RECOMPILE}, and {fn BRECOMPILE} will operate as though {var DWIMIFYCOMPFLG} is {lisp T} and {fn DWIMIFY} all expressions before compiling. (3) If the function definition has a local {lisp CLISP} declaration (see {PageRef Tag CLISPLocalDeclarations}), including a null declaration, i.e., just {lisp (CLISP:)}, the definition will be automatically {fn DWIMIFY}ed before compiling. Note: {var COMPILEUSERFN}{index COMPILEUSERFN FN} ({PageRef Var COMPILEUSERFN}) is defined to call {fn DWIMIFY} on iterative statements, {lisp IF}-{lisp THEN} statements, and {lisp fetch}, {lisp replace}, and {lisp match} expressions, i.e., any CLISP construct which can be recognized by its {fn CAR} of form. Thus, if the only CLISP constructs in a function appear inside of iterative statements, {lisp IF} statements, etc., the function does not have to be dwimified before compiling. If {fn DWIMIFY}{index dwimify (Printed by DWIM)} is ever unsuccessful in processing a {lisp CLISP} expression, it will print the error message {index UNABLE TO DWIMIFY Error}{lisp UNABLE TO DWIMIFY} followed by the expression, and go into a break.{foot unless {var DWIMESSGAG}{index DWIMESSGAG Var}={lisp T}. In this case, the expression is just compiled as is, i.e. as though clisp had not been enabled. }{comment endfootnote} The user can exit the break in several different ways: (1) type {lisp OK} to the break, which will cause the compiler to try again, e.g. the user could define some missing records while in the break, and then continue; or (2) type {lisp ↑}, which will cause the compiler to simply compile the expression as is, i.e. as though CLISP had not been enabled in the first place; or (3) return an expression to be compiled in its place by using the {breakcom RETURN} break command ({PageRef BreakCom RETURN}). Note: {fn TCOMPL}, {fn BCOMPL}, {fn RECOMPILE}, and {fn BRECOMPILE} all scan the entire file before doing any compiling, and take note of the names of all functions that are defined in the file as well as the names of all variables that are set by adding them to {index NOFIXFNSLST Var}{var NOFIXFNSLST} and {index NOFIXVARSLST Var}{var NOFIXVARSLST}, respectively. Thus, if a function is not currently defined, but {it is} defined in the file being compiled, when {fn DWIMIFY} is called before compiling, it will not attempt to interpret the function name as CLISP when it appears as {fn CAR} of a form. {fn DWIMIFY} also takes into account variables that have been declared to be {lisp LOCALVARS}, or {lisp SPECVARS}, either via block declarations or {lisp DECLARE} expressions in the function being compiled, and does not attempt spelling correction on these variables. The declaration {index USEDFREE (CLISP declaration)}{lisp USEDFREE} may also be used to declare variables simply used freely in a function. These variables will also be left alone by {fn DWIMIFY}. Finally, {var NOSPELLFLG} ({PageRef Var NOSPELLFLG}) is reset to {lisp T} when compiling functions from a file (as opposed to from their in-core definition) so as to suppress spelling correction. }{End SubSec Compiling CLISP}