{Begin SubSec Block Compiling} {Title Block Compiling} {Text {Tag BlockCompiler} {Tag BlockCompiling} {index *PRIMARY* Block compiling} {note should put in some warnings about TCOMPLing and BCOMPLing and BRECOMPILEing the same file. Apparently, you can wind up with garbage if you don't do one thing consistantly} In Interlisp-10, block compiling provides a way of compiling several functions into a single block. Function calls between the component functions of the block are very fast. Thus, compiling a block consisting of just a single recursive function may be yield great savings if the function calls itself many times. The output of a block compilation is a single, usually large, function. Calls from within the block to functions outside of the block look like regular function calls. A block can be entered via several different functions, called entries.{index *PRIMARY* Entries to a block} These must be specified when the block is compiled. In Interlisp-D, block compiling is handled somewhat differently; block compiling provides a mechanism for hiding function names internal to a block, but it does not provide a performance improvement. Block compiling in Interlisp-D works by automatically renaming the block functions with special names, and calling these functions with the normal function-calling mechanisms. Specifically, a function {arg FN} is renamed to {lisp \{arg BLOCK-NAME}/{arg FN}}. For example, function {lisp FOO} in block {lisp BAR} is renamed to "{lisp \BAR/FOO}". Note that it is possible with this scheme to break functions internal to a block. {Begin SubSec Block Declarations} {Title Block Declarations} {Text {Tag BlockDeclarations} {index *PRIMARY* Block declarations} Block compiling a file frequently involves giving the compiler a lot of information about the nature and structure of the compilation, e.g., block functions, entries, specvars, etc. To help with this, there is the {filecom BLOCKS} file package command{index BLOCKS FileCom} ({PageRef FileCom BLOCKS}), which has the form: {lispcode (BLOCKS {arg BLOCK{sub 1}} {arg BLOCK{sub 2}} {ellipsis} {arg BLOCK{sub N}})} where each {arg BLOCK{sub i}} is a block declaration. The {index BLOCKS FileCom}{filecom BLOCKS} command outputs a {index DECLARE: filecom}{filecom DECLARE:} expression, which is noticed by {fn BCOMPL} and {fn BRECOMPILE}. {index BCOMPL FN}{fn BCOMPL} and {index BRECOMPILE FN}{fn BRECOMPILE} are sensitive to these declarations and take the appropriate action. Note: Masterscope ({PageRef Tag Masterscope}) includes a facility for checking the block declarations of a file or files for various anomalous conditions, e.g. functions in block declarations which aren't on the file(s), functions in {lisp ENTRIES} not in the block, variables that may not need to be {lisp SPECVARS} because they are not used freely below the places they are bound, etc. A block declaration is a list of the form: {lispcode ({arg BLKNAME} {arg BLKFN{sub 1}} {ellipsis} {arg BLKFN{sub M}} ({arg VAR{sub 1}} . {arg VALUE{sub 1}}) {ellipsis} ({arg VAR{sub N}} . {arg VALUE{sub N}}))} {arg BLKNAME} is the name of a block. {lisp {arg BLKFN{sub 1}} {ellipsis} {arg BLKFN{sub M}}} are the functions in the block and correspond to {arg BLKFNS} in the call to {index BLOCKCOMPILE FN}{fn BLOCKCOMPILE}. The ({arg VAR{sub i}} . {arg VALUE{sub i}}) expressions indicate the settings for variables affecting the compilation of that block. If {arg VALUE{sub i}} is atomic, then {arg VAR{sub i}} is set to {arg VALUE{sub i}}, otherwise {arg VAR{sub i}} is set to the {fn UNION} ({PageRef Fn UNION}) of {arg VALUE{sub i}} and the current value of the variable {arg VAR{sub i}}. Also, expressions of the form {lisp ({arg VAR} * {arg FORM})} will cause {arg FORM} to be evaluated and the resulting list used as described above (e.g. {lisp (GLOBALVARS * MYGLOBALVARS)}). For example, consider the block declaration below. The block name is {lisp EDITBLOCK}, it includes a number of functions ({lisp EDITL0}, {lisp EDITL1}, {ellipsis} {lisp EDITH}), and it sets the variables {lisp ENTRIES}, {lisp SPECVARS}, {lisp RETFNS}, and {lisp GLOBALVARS}. {lispcode (EDITBLOCK EDITL0 EDITL1 UNDOEDITL EDITCOM EDITCOMA EDITMAC EDITCOMS EDIT]UNDO UNDOEDITCOM EDITH (ENTRIES EDITL0 ## UNDOEDITL) (SPECVARS L COM LCFLG #1 #2 #3 LISPXBUFS) (RETFNS EDITL0) (GLOBALVARS EDITCOMSA EDITCOMSL EDITOPS))} Whenever {fn BCOMPL} or {fn BRECOMPILE} encounter a block declaration, they rebind {index RETFNS Var}{var RETFNS}, {index SPECVARS Var}{var SPECVARS}, {index GLOBALVARS Var}{var GLOBALVARS}, {index BLKLIBRARY Var}{var BLKLIBRARY}, and {var DONTCOMPILEFNS}{index DONTCOMPILEFNS Var} to their top level values, bind {index BLKAPPLYFNS Var}{var BLKAPPLYFNS} and {index ENTRIES Var}{var ENTRIES} to {lisp NIL}, and bind {var BLKNAME}{index BLKNAME Var} to the first element of the declaration. They then scan the rest of the declaration, setting these variables as described above. When the declaration is exhausted, the block compiler is called and given {var BLKNAME}, the list of block functions, and {var ENTRIES}. If a function appears in a block declaration, but is not defined in one of the files, then if it has an in-core definition, this definition is used and a message printed {index NOT ON FILE, COMPILING IN CORE DEFINITION Error}{lisp NOT ON FILE, COMPILING IN CORE DEFINITION}. Otherwise, the message {index NOT COMPILEABLE Error}{lisp NOT COMPILEABLE}, is printed and the block declaration processed as though the function were not on it, i.e. calls to the function will be compiled as external function calls. Note that since all compiler variables are rebound for each block declaration, the declaration only has to set those variables it wants {it changed}. Furthermore, setting a variable in one declaration has no effect on the variable's value for another declaration. After finishing all blocks, {index BCOMPL FN}{fn BCOMPL} and {index BRECOMPILE FN}{fn BRECOMPILE} treat any functions in the file that did not appear in a block declaration in the same way as do {index TCOMPL FN}{fn TCOMPL} and {index RECOMPILE FN}{fn RECOMPILE}. If the user wishes a function compiled separately as well as in a block, or if he wishes to compile some functions (not blockcompile), with some compiler variables changed, he can use a special pseudo-block declaration of the form {index NIL (in block declarations)} {lispcode (NIL {arg BLKFN{sub 1}} {ellipsis} {arg BLKFN{sub M}} ({arg VAR{sub 1}} . {arg VALUE{sub 1}}) {ellipsis} ({arg VAR{sub N}} . {arg VALUE{sub N}}))} which means that {arg BLKFN{sub 1}} {ellipsis} {arg BLKFN{sub M}} should be compiled after first setting {arg VAR{sub 1}} {ellipsis} {arg VAR{sub N}} as described above. The following variables control other aspects of compiling a block: {VarDef {Name RETFNS} {Text Value is a list of internal block functions whose names must appear on the stack, e.g., if the function is to be returned from {fn RETFROM}, {fn RETTO}, {fn RETEVAL}, etc. Usually, internal calls between functions in a block are not put on the stack. }} {VarDef {Name BLKAPPLYFNS} {Text Value is a list of internal block functions called by other functions in the same block using {fn BLKAPPLY} or {fn BLKAPPLY*} for efficiency reasons. Normally, a call to {fn APPLY} from inside a block would be the same as a call to any other function outside of the block. If the first argument to {fn APPLY} turned out to be one of the entries to the block, the block would have to be reentered. {var BLKAPPLYFNS} enables a program to compute the name of a function in the block to be called next, without the overhead of leaving the block and reentering it. This is done by including on the list {var BLKAPPLYFNS} those functions which will be called in this fashion, and by using {index BLKAPPLY FN}{fn BLKAPPLY} in place of {index APPLY FN}{fn APPLY}, and {index BLKAPPLY* FN}{fn BLKAPPLY*} in place of {index APPLY* FN}{fn APPLY*}. If {fn BLKAPPLY} or {fn BLKAPPLY*} is given a function not on {var BLKAPPLYFNS}, the effect is the same as a call to {fn APPLY} or {fn APPLY*} and no error is generated. Note however, that {var BLKAPPLYFNS} must be set at {it compile} time, not run time, and furthermore, that all functions on {var BLKAPPLYFNS} must be in the block, or an error is generated (at compile time), {lisp NOT ON BLKFNS}.{index NOT ON BLKFNS Error} }} {VarDef {Name BLKAPPLYFNS} {Text Value is a list of functions that are considered to be in the "block library"{index *PRIMARY* Block library} of functions that should automatically be included in the block if they are called within the block. Compiling a function open via a macro provides a way of eliminating a function call. For block compiling, the same effect can be achieved by including the function in the block. A further advantage is that the code for this function will appear only once in the block, whereas when a function is compiled open, its code appears at each place where it is called. The block library feature provides a convenient way of including functions in a block. It is just a convenience since the user can always achieve the same effect by specifying the function(s) in question as one of the block functions, provided it has an expr definition at compile time. The block library feature simply eliminates the burden of supplying this definition. To use the block library feature, place the names of the functions of interest on the list {index *PRIMARY* BLKLIBRARY Var}{var BLKLIBRARY}, and their expr definitions on the property list of the functions under the property {index *PRIMARY* BLKLIBRARYDEF Prop}{prop BLKLIBRARYDEF}. When the block compiler compiles a form, it first checks to see if the function being called is one of the block functions. If not, and the function is on {var BLKLIBRARY}, its definition is obtained from the property value of {prop BLKLIBRARYDEF}, and it is automatically included as part of the block. }} }{End SubSec Block Declarations} {Begin SubSec Block Compiling Functions} {Title Block Compiling Functions} {Text {index *PRIMARY* Block compiling functions} {index Compiler functions} There are three user level functions for block compiling, {fn BLOCKCOMPILE}, {fn BCOMPL}, and {fn BRECOMPILE}, corresponding to {fn COMPILE}, {fn TCOMPL}, and {fn RECOMPILE}. Note that all of the remarks on macros, globalvars, compiler messages, etc., all apply equally for block compiling. Using block declarations, the user can intermix in a single file functions compiled normally and block compiled functions. {FnDef {FnName BLOCKCOMPILE} {FnArgs BLKNAME BLKFNS ENTRIES FLG} {Text {arg BLKNAME} is the name of a block, {arg BLKFNS} is a list of the functions comprising the block, and {arg ENTRIES} a list of entries to the block.{index Entries to a block} Each of the entries must also be on {arg BLKFNS} or an error is generated, {lisp NOT ON BLKFNS}.{index NOT ON BLKFNS Error} If only one entry is specified, the block name can also be one of the {arg BLKFNS}, e.g., {lisp (BLOCKCOMPILE 'FOO '(FOO FIE FUM) '(FOO))}. However, if more than one entry is specified, an error will be generated, {lisp CAN'T BE BOTH AN ENTRY AND THE BLOCK NAME}.{index CAN'T BE BOTH AN ENTRY AND THE BLOCK NAME Error} If {arg ENTRIES} is {lisp NIL}, {lisp (LIST {arg BLKNAME})} is used, e.g., {lisp (BLOCKCOMPILE 'COUNT '(COUNT COUNT1))} If {arg BLKFNS} is {lisp NIL}, {lisp (LIST {arg BLKNAME})} is used, e.g., {lisp (BLOCKCOMPILE 'EQUAL)} {fn BLOCKCOMPILE} asks the standard compiler questions ({PageRef Tag CompilerQuestions}), and then begins compiling. As with {fn COMPILE}, if the compiled code is being written to a file, the file is closed unless {arg FLG}={lisp T}. The value of {fn BLOCKCOMPILE} is a list of the {index Entries to a block}entries, or if {arg ENTRIES}={lisp NIL}, the value is {arg BLKNAME}. The output of a call to {fn BLOCKCOMPILE} is one function definition for {arg BLKNAME}, plus definitions for each of the functions on {arg ENTRIES} if any. These entry functions are very short functions which immediately call {arg BLKNAME}. }} {index Compiling files} {FnDef {FnName BCOMPL} {FnArgs FILES CFILE {anonarg} {anonarg}} {Text {arg FILES} is a list of symbolic files (if atomic, {lisp (LIST {arg FILES})} is used). {fn BCOMPL} differs from {index TCOMPL FN}{fn TCOMPL} in that it compiles all of the files at once, instead of one at a time, in order to permit one block to contain functions in several files. (If you have several files to be {fn BCOMPL}ed {it separately}, you must make several calls to {fn BCOMPL}.) Output is to {arg CFILE} if given, otherwise to a file whose name is {lisp (CAR {arg FILES})} suffixed with {index DCOM (file name extension)}{lisp DCOM}. For example, {lisp (BCOMPL '(EDIT WEDIT))} produces one file, {lisp EDIT.DCOM}. {fn BCOMPL} asks the standard compiler questions ({PageRef Tag CompilerQuestions}), except for "{lisp OUTPUT FILE:}", then processes each file exactly the same as {fn TCOMPL} ({PageRef Fn TCOMPL}). {fn BCOMPL} next processes the block declarations as described above. Finally, it compiles those functions not mentioned in one of the block declarations, and then writes out all other expressions. If {it any} of the files have property {prop FILETYPE} with value {lisp CLISP}, or a list containing {lisp CLISP}, then {index DWIMIFYCOMPFLG Var}{var DWIMIFYCOMPFLG} is rebound to {lisp T} for {it all} of the files. See {PageRef Tag CompilingCLISP}. The value of {fn BCOMPL} is the output file (the new compiled file). If the compilation is aborted due to an error or control-D, all files are closed and the (partially complete) output file is deleted. Note that it is permissible to {index TCOMPL FN}{fn TCOMPL} files set up for {fn BCOMPL}; the block declarations will simply have no effect. Similarly, you can {index BCOMPL FN}{fn BCOMPL} a file that does not contain any block declarations and the result will be the same as having {fn TCOMPL}ed it. }} {Begin Note} Date: 6 DEC 1979 2107-PST From: TEITELMAN i fixed errortypelst so that if a file wont open error occurs when no version was specified, it will try the next higher version. this will fix the problem of having a compilatin going in a higher fork, doing an exec and trying to compile something and getting a file wont open error on bcompl.scratch. i also fixed bcompl so that it does not save undo informaton when it is actually compiling (since it is compiling from the file anyway). this should save some space when compiling large files with lots of clisp. {End Note} {FnDef {FnName BRECOMPILE} {FnArgs FILES CFILE FNS {anonarg}} {Text {fn BRECOMPILE} plays the same role for {fn BCOMPL} that {fn RECOMPILE} plays for {fn TCOMPL}. Its purpose is to allow the user to update a compiled file without requiring an entire {fn BCOMPL}. {arg FILES} is a list of symbolic files (if atomic, {lisp (LIST {arg FILES})} is used). {arg CFILE} is the compiled file produced by {fn BCOMPL} or a previous {fn BRECOMPILE} that contains compiled definitions that may be copied. The interpretation of {arg FNS} is the same as with {fn RECOMPILE}. {fn BRECOMPILE} asks the standard compiler questions ({PageRef Tag CompilerQuestions}), except for "{lisp OUTPUT FILE:}". As with {fn BCOMPL}, output automatically goes to {lisp {arg FILE}.DCOM}, where {arg FILE} is the first file in {arg FILES}. {fn BRECOMPILE} processes each file the same as {fn RECOMPILE} ({PageRef Fn RECOMPILE}), then processes each block declaration. If {it any} of the functions in the block are to be recompiled, the entire block must be (is) recompiled. Otherwise, the block is copied from {arg CFILE} as with {fn RECOMPILE}. For pseudo-block declarations of the form {lisp (NIL {arg FN1} {ellipsis})}, all variable assignments are made, but only those functions indicated by {arg FNS} are recompiled. After completing the block declarations, {fn BRECOMPILE} processes all functions that do not appear in a block declaration, recompiling those dictated by {arg FNS}, and copying the compiled definitions of the remaining from {arg CFILE}. Finally, {fn BRECOMPILE} writes onto the output file the "other expressions" collected in the initial scan of {arg FILES}. The value of {fn BRECOMPILE} is the output file (the new compiled file). If the compilation is aborted due to an error or control-D, all files are closed and the (partially complete) output file is deleted. If {arg CFILE}={lisp NIL}, the old version of {lisp {arg FILE}.DCOM} is used, as with {fn RECOMPILE}. In addition, if {arg FNS} and {arg CFILE} are both {lisp NIL}, {arg FNS} is set to the value of {index RECOMPILEDEFAULT Var}{var RECOMPILEDEFAULT}, initially {lisp CHANGES}. }} }{End SubSec Block Compiling Functions} }{End SubSec Block Compiling}