|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 8373 (0x20b5) Types: TextFile Names: »cross.doc«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/cross.doc«
This is a preliminary document on the use of the Scheme Cross syntaxer. This documentation is not all inclusive and the cross syntaxer is subject to change without notice. As a matter of fact, there is a much better one which will be installed in rel5. The scheme interpreter does not run the code that you type at it. The code that we call scheme code such as: (define (fact n) (if (< n 2) 1 (* n (fact (-1+ n))))) is transformed into SCode. SCode is an abstract code representation that is somewhat simpler than scheme code. The process of translating scheme code into scode is called syntaxing. As an example, the fragment (< n 2) is syntaxed into an scode object called a combination. A combination has two parts, the operator, which in this case is the variable <, and the list of the operands, which in the case is the list of the variable n and the number 2. Since programs are run in their scode representation, if the scode is optimized, the program will run faster. The cross syntaxer performs this optimization. It is called cross syntaxer rather than SCode optimizer for historical reasons (it was originally written in PDP10 scheme to generate the initial load for the implementation which ran on 68000s). The normal use for the cross syntaxer is to call the function SF (which stands for "syntax-file"). SF takes one required argument which is the name of the source file of scheme code that you want to cross syntax. This argument could also be a list of file names. These names are strings. The cross syntaxer reads the source file, syntaxes and optimizes the scode, dumps the scode into a binary file (with file extension ".bin") and dumps some human readable information about the code into a specification file (with file extension ".spc"). When the cross syntaxer is about to process a file it prints out: (SYNTAX-FILE {source-file} {scode-output-file} {spec-output-file}) For example, suppose we start out will the following code in the file "fact.scm". ;;; File fact.scm (define (fact n) (if (< n 2) 1 (* n (fact (-1+ n))))) ;;; end of file fact.scm If we then typed the following at scheme: ]=> (sf "fact.scm") The cross syntaxer would print out the following: (SYNTAX-FILE "fact.scm" "fact.bin" "fact.spc") It will then process the file "fact.scm", output the binary form of the scode in "fact.bin", and output the spec file in "fact.spc". If we wanted to cross syntax several files we could put the file names into a list. For instance, if we wanted to cross syntax both fact.scm and another file "fib.scm", we could type the following at scheme: ]=> (sf (list "fact.scm" "fib.scm")) The cross syntaxer would then print out as above: (SYNTAX-FILE "fact.scm" "fact.bin" "fact.spc") Once it had finished processing this first file it would then print out the following and process this next file: (SYNTAX-FILE "fib.scm" "fib.bin" "fib.spc") If we wanted the bin and spc files to go into another directory, we could say: ]=> (sf "fact.scm" "mydirectory/") It would then print out: (SYNTAX-FILE "fact.scm" "mydirectory/fact.bin" "mydirectory/fact.spc") Also we could specify different directories for the bin and spec file: ]=> (sf "fact.scm" "bindirectory/" "spcdirectory/") This would cause the cross syntaxer to print: (SYNTAX-FILE "fact.scm" "bindirectory/fact.bin" "spcdirectory/fact.spc") The specification of the output files will also work if the first argument is a list of filenames. Once a file is cross syntaxed and dumped into a bin file, the scode in the bin file can be loaded into scheme via the normal load command. Hence, after cross syntaxing "fact.scm", we could then say: ]=> (load "fact.bin") When scheme loads binary scode, it will print out a message similar to the following: FASLoading file fact.bin Since it is loading binary scode and doesn't have to parse the text of the source file, this loading will take less time then loading the source text. Hence the loading will be fast, which explains the strange word FASLoading, which stands for "fast loading". One of the optimizations that the cross syntaxer makes is to put actual primitives in the scode in place of a variable to look up the value of the primitive. This process is called primitive integration or in-lining. for instance, in the combination (-1+ n), if the primitive -1+ were in the operator part of the combination instead of the variable which causes the interpreter to look up the value of -1+, this combination could be evaluated more quickly as the expense of the lookup would be avoided. several things must be noted. first, the cross syntaxer must be told to do this optimization with primitives. it does not do it automatically. second, if this optimization is performed and the primitive -1+ is integrated into the combination, redefining -1+ to be something else has no effect on the evaluation of the combination as the variable -1+ is never looked up to find it's value. the way to tell the cross syntaxer to integrate a primitive is to have the following declaration at the top of the file of source code: (declare (compilable-primitive-functions {primitive-name} . . )) this tells the cross syntaxer to integrate all the primitives listed after compilable-primitive-functions. hence, to optimize our factorial program, we could cross syntax the source file with the following at the top: (declare (compilable-primitive-functions -1+)) Another declaration that is useful is to put a two element list after compilable-primitive-functions instead of a primitive name. This tells the cross syntaxer to integrate the second item in the list whenever it sees an occurance of the first item of the list. For instance, if we declared: (declare (compilable-primitive-functions (decrement -1+))) and our combination was written as (decrement n), the primitive -1+ would be integrated in place of decrement. An important thing to note is that integrations are not always performed if the cross syntaxer deems them to be unsafe. For instance, suppose the file fact contained the follwing: ;;; File fact.scm that defeats the declarations (declare (compilable-primitive-functions -1+)) (define (-1+ n) (- n 1)) (define (fact n) (if (< n 2) 1 (* n (fact (-1+ n))))) ;;; end of file fact.scm In this case, -1+ would not be integrated, because -1+ is defined in the file and it is unclear whether fact should use the primitive or call the compound procedure defined as -1+. Another important thing to note is that only primitives can be integrated. To find out whether a procedure is a primitive or not, simply type the name of the procedure at the interpreter and see what the interpreter returns. For example: ]=> -1+ #[PRIMITIVE-PROCEDURE -1+] ;; this is a primitive ]=> < #[COMPOUND-PROCEDURE <] ;; this is not ]=> * #[COMPOUND-PROCEDURE *] ;; neither is this We could futher optimize fact if we could use the primitive versions of two compound procedures above. In fact, if we pretty-printed the two compound procedures, we would see that they use the primitives &< and &*. These two primitives always take two arguments, unlike the compound procedures < and *. Hence to further optimize our factorial program, we could change the source file as follows and cross syntax: ;;; Greatly optimized file fact.scm (declare (compilable-primitive-functions -1+ &* &<)) (define (fact n) (if (&< n 2) 1 (&* n (fact (-1+ n))))) ;;; end of file fact.scm Once cross syntaxed, this version of fact would run relatively efficiently because as written, it never needs to look up any free variables. The primitives are all in-lined, and the only variables needed to look up are n which is local to fact because it is an argument, and fact, which it knows to be itself. (declare (usual-integrations)) Tells the cross-syntaxer to integrate all the common primitives (eq?, cons, etc.) Note that no renames are performed by this, so the variable argument arithmetic functions are not affected by this declaration. Note that the student system makes the cross-syntaxer available only after invoking ENABLE-LANGUAGE-FEATURES. The development system always makes the cross-syntaxer available. The cross-syntaxer is generated by loading the file xbuild.bin, and thi sis done in the installation process.