aboutsummaryrefslogtreecommitdiff
path: root/src/interp/util.lisp.pamphlet
diff options
context:
space:
mode:
authordos-reis <gdr@axiomatics.org>2007-08-14 05:14:52 +0000
committerdos-reis <gdr@axiomatics.org>2007-08-14 05:14:52 +0000
commitab8cc85adde879fb963c94d15675783f2cf4b183 (patch)
treec202482327f474583b750b2c45dedfc4e4312b1d /src/interp/util.lisp.pamphlet
downloadopen-axiom-ab8cc85adde879fb963c94d15675783f2cf4b183.tar.gz
Initial population.
Diffstat (limited to 'src/interp/util.lisp.pamphlet')
-rw-r--r--src/interp/util.lisp.pamphlet1683
1 files changed, 1683 insertions, 0 deletions
diff --git a/src/interp/util.lisp.pamphlet b/src/interp/util.lisp.pamphlet
new file mode 100644
index 00000000..ec9f4ad1
--- /dev/null
+++ b/src/interp/util.lisp.pamphlet
@@ -0,0 +1,1683 @@
+% Oh Emacs, this is a -*- Lisp -*- file, despite appearance.
+\documentclass{article}
+\usepackage{axiom}
+
+\title{\$SPAD/src/interp util.lisp}
+\author{Timothy Daly}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+
+
+\section{util.lisp}
+
+This file is a collection of utility functions that are useful
+for system level work. A couple of the functions, {\bf build-depsys}
+and {\bf build-interpsys} interface to the src/interp/Makefile.
+
+A second group of related functions allows us to rebuild portions
+of the system from the command prompt. This varies from rebuilding
+individual files to whole directories. The most complex functions
+like {\bf makespad} can rebuild the whole algebra tree.
+
+A third group of related functions are used to set up the
+{\bf autoload} mechanism. These enable whole subsystems to
+be kept out of memory until they are used.
+
+A fourth group of related functions are used to construct and
+search Emacs TAGS files.
+
+A fifth group of related functions are some translated boot
+functions we need to define here so they work and are available
+at load time.
+
+\subsection{Building Depsys (build-depsys)}
+
+The {\bf depsys} image is one of the two images we build from
+the src/interp subdirectory (the other is {\bf interpsys}). We
+use {\bf depsys} as a compile-time image as it contains all of
+the necessary functions and macros to compile any file. The
+{\bf depsys} image is almost the same as an {\bf interpsys}
+image but it does not have any autoload triggers or databases
+loaded.
+<<build-depsys>>=
+(defun build-depsys (load-files spad)
+#+:CCL
+ (setq *package* (find-package "BOOT"))
+#+:AKCL
+ (in-package "BOOT")
+ (mapcar #'load load-files)
+ (initroot spad)
+ #+:AKCL
+ (init-memory-config :cons 1000 :fixnum 400 :symbol 1000 :package 16
+ :array 800 :string 1000 :cfun 200 :cpages 2000
+ :rpages 2000 :hole 4000) )
+;; (init-memory-config :cons 500 :fixnum 200 :symbol 500 :package 8
+;; :array 400 :string 500 :cfun 100 :cpages 1000
+;; :rpages 1000 :hole 2000) )
+
+@
+
+\subsection{Building Interpsys (build-interpsys)}
+\begin{verbatim}
+;############################################################################
+;# autoload dependencies
+;#
+;# if you are adding a file which is to be autoloaded the following step
+;# information is useful:
+;# there are 2 cases:
+;# 1) adding files to currently autoloaded parts
+;# (as of 2/92: browser old parser and old compiler)
+;# 2) adding new files
+;# case 1:
+;# a) you have to add the file to the list of files currently there
+;# (e.g. see BROBJS above)
+;# b) add an autolaod rule
+;# (e.g. ${AUTO}/parsing.${O}: ${OUT}/parsing.${O})
+;# c) edit util.lisp to add the 'external' function (those that
+;# should trigger the autoload
+;# case 2:
+;# build-interpsys (in util.lisp) needs an extra argument for the
+;# new autoload things and several functions in util.lisp need hacking.
+;############################################################################
+\end{verbatim}
+The {\bf build-interpsys} function takes a list of files to load
+into the image ({\bf load-files}). It also takes several lists of files,
+one for each subsystem which will be autoloaded. Autoloading is explained
+below. Next it takes a set of shell variables, the most important of
+which is the {\bf spad} variable. This is normally set to be the same
+as the final build location. This function is called in the
+src/interp/Makefile.
+
+This function calls {\bf initroot} to set up pathnames we need. Next
+it sets up the lisp system memory (at present only for AKCL/GCL). Next
+it loads all of the named files, resets a few global state variables,
+loads the databases, sets up autoload triggers and clears out hash tables.
+After this function is called the image is clean and can be saved.
+<<build-interpsys>>=
+(defun build-interpsys (load-files parse-files comp-files browse-files
+ translate-files nagbr-files asauto-files spad)
+ (initroot spad)
+ #+:AKCL
+ (init-memory-config :cons 500 :fixnum 200 :symbol 500 :package 8
+ :array 400 :string 500 :cfun 100 :cpages 1000
+ :rpages 1000 :hole 2000)
+ <<compiler-notes>>
+ (mapcar #'|AxiomCore|::|importModule| load-files)
+ (|resetWorkspaceVariables|)
+ (|initHist|)
+ (|initNewWorld|)
+ (compressopen)
+ (interpopen)
+ (create-initializers)
+ (|start| :fin)
+#+:CCL
+ (resethashtables)
+ (setq *load-verbose* nil)
+ (|setBootAutloadProperties| comp-functions comp-files)
+ (|setBootAutloadProperties| parse-functions parse-files)
+ (|setBootAutloadProperties| browse-functions browse-files)
+ (|setBootAutloadProperties| translate-functions translate-files)
+ (|setNAGBootAutloadProperties| nagbr-functions nagbr-files)
+ (|setBootAutloadProperties| asauto-functions asauto-files)
+ (setf (symbol-function 'boot::|addConsDB|) #'identity)
+ (resethashtables) ; the databases into core, then close the streams
+ )
+
+@
+
+\subsubsection{GCL porting changes}
+
+GCL likes to output lines of the form:
+\begin{verbatim}
+;; Note: Tail-recursive call of |matSuperList1| was replaced by iteration.
+\end{verbatim}
+which is pointless and should be removed. Bill Schelter added this while
+he was debugging tail-recursive replacement and it never was removed.
+<<compiler-notes>>=
+ #+:AKCL
+ (setq compiler::*suppress-compiler-notes* t)
+@
+
+
+\subsection{The variables}
+
+Various lisps use different ``extensions'' on the filename to indicate
+that a file has been compiled. We set this variable correctly depending
+on the system we are using.
+<<bin-path>>=
+(defvar *bin-path*
+ #+kcl "o"
+ #+lucid "bbin"
+ #+symbolics "bin"
+ #+cmulisp "fasl"
+ #+:ccl "not done this way at all")
+
+@
+
+\subsubsection{directory-list}
+
+This is the system-wide list of directories to search.
+It is set up in the {\bf reroot} function.
+<<directory-list>>=
+(defvar $directory-list ())
+
+@
+
+
+\subsubsection{relative-directory-list}
+
+The relative directory list specifies a search path for files
+for the current directory structure. It has been changed from the
+NAG distribution back to the original form.
+<<relative-directory-list>>=
+(defvar $relative-directory-list
+ '("/../../src/input/"
+ "/share/msgs/"
+ "/../../src/algebra/"
+ "/../../src/interp/" ; for boot and lisp files (helps fd)
+ "/doc/spadhelp/" ))
+
+@
+
+
+\subsubsection{library-directory-list}
+
+This is the system-wide search path for library files.
+It is set up in the {\bf reroot} function.
+<<library-directory-list>>=
+(defvar $library-directory-list ())
+
+@
+
+\subsubsection{relative-library-directory-list}
+
+The relative directory list specifies how to find the algebra
+directory from the current {\bf AXIOM} shell variable.
+<<relative-library-directory-list>>=
+(defvar $relative-library-directory-list '("/algebra/"))
+
+@
+
+
+\subsection{The autoload list}
+
+There are several subsystems within {\bf AXIOM} that are not normally
+loaded into a running system. They will be loaded only if you invoke
+one of the functions listed here. Each of these listed functions will
+have their definitions replaced by a special ``autoloader'' function.
+The first time a function named here is called it will trigger a
+load of the associated subsystem, the autoloader functions will get
+overwritten, the function call is retried and now succeeds. Files
+containing functions listed here are assumed to exist in the
+{\bf autoload} subdirectory. The list of files to load is defined
+in the src/interp/Makefile.
+
+\subsubsection{setBootAutloadProperties}
+
+This function is called by {\bf build-interpsys}. It takes two lists.
+The first is a list of functions that need to be used as
+``autoload triggers''. The second is a list of files to load if one
+of the trigger functions is called. At system build time each of the
+functions in the first list is set up to load every file in the second
+list. In this way we will automatically load a whole subsystem if we
+touch any function in that subsystem. We call a helper function
+called {\bf setBootAutoLoadProperty} to set up the autoload trigger.
+This helper function is listed below.
+<<setBootAutloadProperties>>=
+(defun |setBootAutloadProperties| (fun-list file-list)
+#+:AKCL
+ (mapc #'(lambda (fun) (|setBootAutoLoadProperty| fun file-list)) fun-list)
+#+:CCL
+ (mapc #'(lambda (fun) (lisp::set-autoload fun file-list)) fun-list)
+)
+
+@
+
+\subsubsection{setBootAutoLoadProperty}
+
+This is a helper function to set up the autoload trigger. It sets
+the function cell of each symbol to {\bf mkBootAutoLoad} which is
+listed below.
+<<setBootAutoLoadProperty>>=
+(defun |setBootAutoLoadProperty| (func file-list)
+ (setf (symbol-function func) (|mkBootAutoLoad| func file-list)) )
+
+@
+
+\subsubsection{mkBootAutoLoad}
+
+This is how the autoload magic happens. Every function named in the
+autoload lists is actually just another name for this function. When
+the named function is called we call {\bf boot-load} on all of the
+files in the subsystem. This overwrites all of the autoload triggers.
+We then look up the new (real) function definition and call it again
+with the real arguments. Thus the subsystem loads and the original
+call succeeds.
+<<mkBootAutoLoad>>=
+(defun |mkBootAutoLoad| (fn file-list)
+ (function (lambda (&rest args)
+ (mapc #'boot-load file-list)
+ (unless (string= (subseq (string fn) 0 4) "LOAD")
+ (apply (symbol-function fn) args)))))
+
+@
+
+\subsubsection{boot-load}
+
+This function knows where the {\bf autoload} subdirectory lives.
+It is called by {\bf mkBootAutoLoad} above to find the necessary
+files.
+<<boot-load>>=
+(defun boot-load (file)
+ (let ((name (concat $SPADROOT "/autoload/" (pathname-name file))))
+ (if |$printLoadMsgs|
+ (format t " Loading ~A.~%" name))
+ (load name)))
+
+@
+
+\subsubsection{setNAGBootAutloadProperties}
+
+This is a further refinement of the autoload scheme. Since the
+Numerical Algorithms Group (NAG) fortran library contains many
+functions we subdivide the NAG library subsystem into chapters.
+We use a different helper function {\bf get-NAG-chapter} to decide
+which files to load.
+<<setNAGBootAutloadProperties>>=
+(defun |setNAGBootAutloadProperties| (function-list file-list)
+ (mapcar
+ #'(lambda (f)
+ (|setBootAutloadProperties|
+ (get-NAG-chapter (chapter-name f) function-list)
+ (nag-files f file-list)))
+ file-list))
+
+@
+
+\subsubsection{get-NAG-chapter}
+
+This function is used to find the names of the files to load.
+On solaris 9 under GCL the original implementation will fail because
+the max number of arguments is 63. We rewrite it to get around this
+problem. It originally read:
+\begin{verbatim}
+(defun get-NAG-chapter (chapter function-list)
+ (apply 'append
+ (mapcar
+ #'(lambda (f)
+ (cond
+ ((equalp chapter (subseq (string f) 0 (length chapter))) (list f ))))
+ function-list)))
+
+\end{verbatim}
+<<get-NAG-chapter>>=
+(defun get-NAG-chapter (chapter function-list)
+ (let ((l (length chapter)) r)
+ (dolist (f function-list)
+ (when (equalp chapter (subseq (string f) 0 l))
+ (push f r)))
+ (nreverse r)))
+
+@
+
+\subsubsection{nag-files}
+
+We analyze the function names to decide which chapter we are in.
+We load files based on the chapter.
+<<nag-files>>=
+(defun nag-files (filename filelist)
+ (apply 'append (mapcar
+ #'(lambda (f)
+ (cond ((equalp (chapter-name filename) (chapter-name f)) (list f))) )
+ filelist)))
+
+@
+
+\subsubsection{chapter-name}
+
+The library names follow a convention that allows us to extract
+the chapter name.
+<<chapter-name>>=
+(defun chapter-name (f)
+#+:AKCL
+ (apply
+ #'(lambda (s)
+ (cond ((equalp (aref s 0) #\s) "s") (T (reverse (subseq s 0 3)))))
+ (list (string-left-trim "a.o" (reverse f) )) )
+#+:CCL
+ (subseq (string-downcase (string f)) 4 (length (string f)))
+)
+
+@
+
+\subsubsection{parse-functions}
+
+This is the {\bf boot parser} subsystem. It is only needed by
+developers who translate boot code to Common Lisp.
+<<parse-functions>>=
+(setq parse-functions
+ '(
+;; loadparser
+ |oldParserAutoloadOnceTrigger|
+ |PARSE-Expression|
+ boot-parse-1
+ BOOT
+ SPAD
+ init-boot/spad-reader))
+
+@
+
+\subsubsection{comp-functions}
+
+This is the {\bf spad compiler} subsystem. It is only needed by
+developers who write or modify algebra code.
+<<comp-functions>>=
+(setq comp-functions
+ '(
+;; loadcompiler
+ |oldCompilerAutoloadOnceTrigger|
+ |compileSpad2Cmd|
+ |convertSpadToAsFile|
+ |compilerDoit|
+ |compilerDoitWithScreenedLisplib|
+ |mkCategory|
+ |cons5|
+ |sublisV|))
+
+@
+
+\subsubsection{browse-functions}
+
+This is the {\bf browser} subsystem. It will get autoloaded only
+if you use the browse function of the {\bf hypertex} system.
+<<browse-functions>>=
+(setq browse-functions
+ '(
+;; loadbrowse
+ |browserAutoloadOnceTrigger|
+ |parentsOf| ;interop.boot
+ |getParentsFor| ;old compiler
+ |folks| ;for astran
+ |extendLocalLibdb| ;)lib needs this
+ |oSearch|
+ |aokSearch|
+ |kSearch|
+ |aSearch|
+ |genSearch|
+ |docSearch|
+ |abSearch|
+ |detailedSearch|
+ |ancestorsOf|
+ |aPage|
+ |dbGetOrigin|
+ |dbGetParams|
+ |dbGetKindString|
+ |dbGetOrigin|
+ |dbComments|
+ |grepConstruct|
+ |buildLibdb|
+ |bcDefiniteIntegrate|
+ |bcDifferentiate|
+ |bcDraw|
+ |bcExpand|
+ |bcIndefiniteIntegrate|
+ |bcLimit|
+ |bcMatrix|
+ |bcProduct|
+ |bcSeries|
+ |bcSolve|
+ |bcSum|
+ |cSearch|
+ |conPage|
+ |dbName|
+ |dbPart|
+ |extendLocalLibdb|
+ |form2HtString|
+ |htGloss|
+ |htGreekSearch|
+ |htHistory|
+ |htSystemCommands|
+ |htSystemVariables|
+ |htTextSearch|
+ |htTutorialSearch|
+ |htUserVariables|
+ |htsv|
+ |oPage|
+ |oPageFrom|
+ |spadSys|
+ |spadType|
+ |syscomPage|
+ |unescapeStringsInForm|))
+
+@
+
+\subsubsection{translate-functions}
+
+This is a little used subsystem to generate {\bf ALDOR} code
+from {\bf Spad} code. Frankly, I'd be amazed if it worked.
+<<translate-functions>>=
+(setq translate-functions '(
+;; .spad to .as translator, in particular
+;; loadtranslate
+ |spad2AsTranslatorAutoloadOnceTrigger|
+ ))
+
+@
+
+\subsubsection{asauto-functions}
+
+This is part of the {\bf ALDOR subsystem}. These will be loaded
+if you compile a {\bf .as} file rather than a {\bf .spad} file.
+{\bf ALDOR} is an external compiler that gets automatically called
+if the file extension is {\bf .as}.
+<<asauto-functions>>=
+(setq asauto-functions '(
+ loadas
+;; |as| ;; now in as.boot
+;; |astran| ;; now in as.boot
+ |spad2AxTranslatorAutoloadOnceTrigger|
+ |sourceFilesToAxcliqueAxFile|
+ |sourceFilesToAxFile|
+ |setExtendedDomains|
+ |makeAxFile|
+ |makeAxcliqueAxFile|
+ |nrlibsToAxFile|
+ |attributesToAxFile| ))
+
+@
+
+\subsubsection{debug-functions}
+
+These are some {\bf debugging} functions that I use. I can't imagine
+why you might autoload them but they don't need to be in a running
+system.
+<<debug-functions>>=
+(setq debug-functions '(
+ loaddebug
+ |showSummary|
+ |showPredicates|
+ |showAttributes|
+ |showFrom|
+ |showImp|))
+
+@
+
+\subsubsection{anna-functions}
+
+The {\bf ANNA} subsystem, invoked thru {\bf hypertex}, is an
+expert system that understands the Numerical Algorithms Group (NAG)
+fortran library.
+<<anna-functions>>=
+(setq anna-functions '(
+ |annaInt|
+ |annaMInt|
+ |annaOde|
+ |annaOpt|
+ |annaOpt2|
+ |annaPDESolve|
+ |annaOptDefaultSolve1|
+ |annaOptDefaultSolve2|
+ |annaOptDefaultSolve3|
+ |annaOptDefaultSolve4|
+ |annaOptDefaultSolve5|
+ |annaOpt2DefaultSolve|
+ |annaFoo|
+ |annaBar|
+ |annaJoe|
+ |annaSue|
+ |annaAnn|
+ |annaBab|
+ |annaFnar|
+ |annaDan|
+ |annaBlah|
+ |annaTub|
+ |annaRats|
+ |annaMInt|
+ |annaOdeDefaultSolve1|
+ |annaOdeDefaultSolve2|))
+
+@
+
+\subsubsection{nagbr-functions}
+
+The Numerical Algorithms Group (NAG) fortran library has a set
+of cover functions. These functions need to be loaded if you use
+the NAG library.
+<<nagbr-functions>>=
+(setq nagbr-functions '(
+ loadnag
+ |c02aff| |c02agf|
+ |c05adf| |c05nbf| |c05pbf|
+ |c06eaf| |c06ebf| |c06ecf| |c06ekf| |c06fpf| |c06fqf| |c06frf|
+ |c06fuf| |c06gbf| |c06gcf| |c06gqf| |c06gsf|
+ |d01ajf| |d01akf| |d01alf| |d01amf| |d01anf| |d01apf| |d01aqf|
+ |d01asf| |d01bbf| |d01fcf| |d01gaf| |d01gbf|
+ |d02bbf| |d02bhf| |d02cjf| |d02ejf| |d02gaf| |d02gbf| |d02kef|
+ |d02raf|
+ |d03edf| |d03eef| |d03faf|
+ |e01baf| |e01bef| |e01bff| |e01bgf| |e01bhf| |e01daf| |e01saf|
+ |e01sbf| |e01sef|
+ |e02adf| |e02aef| |e02agf| |e02ahf| |e02ajf| |e02akf| |e02baf|
+ |e02bbf| |e02bcf| |e02bdf| |e02bef| |e02daf| |e02dcf|
+ |e02ddf| |e02def| |e02dff| |e02gaf| |e02zaf|
+ |e04dgf| |e04fdf| |e04gcf| |e04jaf| |e04mbf| |e04naf| |e04ucf|
+ |e04ycf|
+ |f01brf| |f01bsf| |f01maf| |f01mcf| |f01qcf| |f01qdf| |f01qef|
+ |f01rcf| |f01rdf| |f01ref|
+ |f02aaf| |f02abf| |f02adf| |f02aef| |f02aff| |f02agf| |f02ajf|
+ |f02akf| |f02awf| |f02axf| |f02bbf| |f02bjf| |f02fjf|
+ |f02wef| |f02xef|
+ |f04adf| |f04arf| |f04asf| |f04atf| |f04axf| |f04faf| |f04jgf|
+ |f04maf| |f04mbf| |f04mcf| |f04qaf|
+ |f07adf| |f07aef| |f07fdf| |f07fef|
+ |s01eaf| |s13aaf| |s13acf| |s13adf| |s14aaf| |s14abf| |s14baf|
+ |s15adf| |s15aef| |s17acf| |s17adf| |s17aef| |s17aff|
+ |s17agf| |s17ahf| |s17ajf| |s17akf| |s17dcf| |s17def|
+ |s17dgf| |s17dhf| |s17dlf| |s18acf| |s18adf| |s18aef|
+ |s18aff| |s18dcf| |s18def| |s19aaf| |s19abf| |s19acf|
+ |s19adf| |s20acf| |s20adf| |s21baf| |s21bbf| |s21bcf|
+ |s21bdf|
+ ))
+
+@
+
+
+\subsection{The command-line build functions}
+
+\subsubsection{translist}
+
+Translate a list of boot files to common lisp.
+<<translist>>=
+(defun translist (fns)
+ (mapcar #'(lambda (f) (format t "translating ~a~%" (concat f ".boot"))
+ (translate f))
+ fns))
+
+@
+
+\subsubsection{translate}
+
+Translate a single boot file to common lisp
+<<translate>>=
+(defun translate (file) ;; translates a single boot file
+#+:CCL
+ (setq *package* (find-package "BOOT"))
+#+:AKCL
+ (in-package "BOOT")
+ (let (*print-level* *print-length* (fn (pathname-name file))
+ (bootfile (merge-pathnames file (concat $spadroot "nboot/.boot"))))
+ (declare (special *print-level* *print-length*))
+ (boot bootfile (make-pathname :type "lisp" :defaults bootfile))))
+
+@
+
+\subsubsection{compile-boot-file}
+
+Translate a single boot file to common lisp, compile it
+and load it.
+<<compile-boot-file>>=
+(defun compile-boot-file (file)
+ "compile and load a boot file"
+ (boot (concat file ".boot") (concat file ".lisp"))
+#+:AKCL
+ (compile-file (concat file ".lisp"))
+#+:AKCL
+ (load (concat file "." *bin-path*))
+#+:CCL
+ (load (concat file ".lisp"))
+)
+
+@
+
+\subsubsection{retranslate-file-if-necessary}
+
+Retranslate a single boot file if it has been changed.
+<<retranslate-file-if-necessary>>=
+(defun retranslate-file-if-necessary (bootfile)
+ (let* ((lfile (make-pathname :type "lisp" :defaults bootfile))
+ (ldate (our-write-date lfile))
+ (binfile (make-pathname :type *bin-path* :defaults bootfile))
+ (bindate (our-write-date binfile))
+ (bootdate (our-write-date bootfile)))
+ (if (and ldate bootdate (> ldate bootdate)) nil
+ (if (and bindate bootdate (> bindate bootdate)) nil
+ (progn (format t "translating ~a~%" bootfile)
+ (boot bootfile lfile) (list bootfile))))))
+
+@
+
+\subsubsection{retranslate-directory}
+
+Translate a directory of boot code to common lisp if the boot code
+is newer.
+<<retranslate-directory>>=
+(defun retranslate-directory (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "boot"))
+ (files (directory pattern)))
+ (mapcan #'retranslate-file-if-necessary files)))
+
+@
+
+\subsubsection{recompile-NRLIB-if-necessary}
+
+Recompile a single library's lisp file if it is out of date.
+The {\bf recompile-lib-file-if-necessary} is defined in nlib.lisp.
+<<recompile-NRLIB-if-necessary>>=
+(defun recompile-NRLIB-if-necessary (lib)
+ (recompile-lib-file-if-necessary (concat (namestring lib) "/code.lsp"))
+ (lift-NRLIB-name (namestring lib)))
+
+@
+
+\subsubsection{lift-NRLIB-name}
+
+We used to use FOO.NRLIB/code.o files for algebra. However there
+was no need for this additional level of indirection since the rest
+of the information in an NRLIB is now kept in the daase files. Thus
+we lift the FOO.NRLIB/code.o to FOO.o in the final system.
+<<lift-NRLIB-name>>=
+(defun lift-NRLIB-name (f)
+ (obey (concat "cp " f "/code.o " (subseq f 0 (position #\. f)) ".o"))
+ nil)
+
+@
+
+\subsubsection{recompile-lib-directory}
+
+Recompile library lisp code if necessary.
+<<recompile-lib-directory>>=
+(defun recompile-lib-directory (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "NRLIB"))
+ (files (directory pattern)))
+ (mapcan #'recompile-NRLIB-if-necessary files)))
+
+@
+
+\subsubsection{recompile-all-files}
+
+Force recompilation of all lisp files in a directory.
+<<recompile-all-files>>=
+(defun recompile-all-files (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "lisp"))
+ (files (directory pattern)))
+ (mapcar #'compile-file files)))
+
+@
+
+\subsubsection{recompile-directory}
+
+This function will compile any lisp code that has changed in a directory.
+<<recompile-directory>>=
+(defun recompile-directory (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "lisp"))
+ (files (directory pattern)))
+ (mapcan #'recompile-file-if-necessary files)))
+
+@
+
+\subsubsection{recompile-file-if-necessary}
+
+This is a helper function that checks the time stamp between
+the given file and its compiled binary. If the file has changed
+since it was last compiled this function will recompile it.
+<<recompile-file-if-necessary>>=
+(defun recompile-file-if-necessary (lfile)
+ (let* ((bfile (make-pathname :type *bin-path* :defaults lfile))
+ (bdate (our-write-date bfile))
+ (ldate (our-write-date lfile)))
+ (if (and bdate ldate (> bdate ldate)) nil
+ (progn
+ (format t "compiling ~a~%" lfile)
+ (compile-file lfile)
+ (list bfile)))))
+
+@
+
+\subsubsection{our-write-date}
+
+Get the write date of a file. In GCL we need to check that it
+exists first. This is a simple helper function.
+<<our-write-date>>=
+(defun our-write-date (file) (and #+kcl (probe-file file)
+ (file-write-date file)))
+
+@
+
+\subsubsection{fe}
+
+I'm unsure what this does but I believe it is related to an interpreter
+command. Invoking ``)fe'' in the interpreter tries to get at the
+src/interp/TAGS file.
+<<fe>>=
+(defun fe (function file &optional (compflag nil) &aux (fn (pathname-name file)))
+ (let ((tbootfile (concat "/tmp/" fn ".boot"))
+ (tlispfile (concat "/tmp/" fn ".lisp")))
+ (system::run-aix-program "fc"
+ :arguments (list (string function)
+ (namestring
+ (merge-pathnames file (concat $SPADROOT "nboot/.boot"))))
+ :if-output-exists :supersede :output tbootfile)
+ (boot tbootfile tlispfile)
+ (if compflag (progn (compile-file tlispfile)
+ (load (make-pathname :type *bin-path* :defaults tlispfile)))
+ (load tlispfile))))
+@
+
+\subsubsection{fc}
+
+I'm unsure what this does but I believe it is related to an interpreter
+command. Invoking ``)fc'' in the interpreter tries to get at the
+src/interp/TAGS file.
+<<fc>>=
+(defun fc (function file) (fe function file t))
+
+@
+
+\subsubsection{compspadfiles}
+
+The {\bf compspadfiles} function will recompile a list of {\bf spad} files.
+The filelist should be a file containing names of files to compile.
+<<compspadfiles>>=
+(defun compspadfiles (filelist ;; should be a file containing files to compile
+ &optional (*default-pathname-defaults*
+ (pathname (concat $SPADROOT "nalgebra/"))))
+ (with-open-file (stream filelist)
+ (do ((fname (read-line stream nil nil) (read-line stream nil nil)))
+ ((null fname) 'done)
+ (setq fname (string-right-trim " *" fname))
+ (when (not (equal (elt fname 0) #\*))
+ (spad fname (concat (pathname-name fname) ".out"))))))
+
+@
+
+\subsubsection{load-directory}
+
+Load a whole subdirectory of compiled files
+<<load-directory>>=
+(defun load-directory (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type *bin-path*))
+ (files (directory pattern)))
+ (mapcar #'load files)))
+
+@
+
+\subsubsection{interp-make-directory}
+
+This is used by the ")cd" system command.
+<<interp-make-directory>>=
+(defun interp-make-directory (direc)
+ (setq direc (namestring direc))
+ (if (string= direc "") $current-directory
+ (if (or (memq :unix *features*)
+ (memq 'unix *features*))
+ (progn
+ (if (char/= (char $current-directory (1-(length $current-directory))) #\/)
+ (setq $current-directory (concat $current-directory "/")))
+ (if (char/= (char direc 0) #\/)
+ (setq direc (concat $current-directory direc)))
+ (if (char/= (char direc (1- (length direc))) #\/)
+ (setq direc (concat direc "/")))
+ direc)
+ (progn ;; Assume Windows conventions
+ (if (not (or (char= (char $current-directory (1- (length $current-directory))) #\/)
+ (char= (char $current-directory (1- (length $current-directory))) #\\ )))
+ (setq $current-directory (concat $current-directory "\\")))
+ (if (not (or (char= (char direc 0) #\/)
+ (char= (char direc 0) #\\)
+ (find #\: direc)))
+ (setq direc (concat $current-directory direc)))
+ (if (not (or (char= (char direc (1- (length direc))) #\/)
+ (char= (char direc (1- (length direc))) #\\ )))
+ (setq direc (concat direc "\\")))
+ direc))))
+
+@
+
+\subsubsection{make-directory}
+
+Make a directory relative to the {\bf \$spadroot} variable.
+<<make-directory>>=
+(defun make-directory (direc)
+ (setq direc (namestring direc))
+ (if (string= direc "") $SPADROOT
+ (if (or (memq :unix *features*)
+ (memq 'unix *features*))
+ (progn
+ (if (char/= (char direc 0) #\/)
+ (setq direc (concat $SPADROOT "/" direc)))
+ (if (char/= (char direc (1- (length direc))) #\/)
+ (setq direc (concat direc "/")))
+ direc)
+ (progn ;; Assume Windows conventions
+ (if (not (or (char= (char direc 0) #\/)
+ (char= (char direc 0) #\\)
+ (find #\: direc)))
+ (setq direc (concat $SPADROOT "\\" direc)))
+ (if (not (or (char= (char direc (1- (length direc))) #\/)
+ (char= (char direc (1- (length direc))) #\\ )))
+ (setq direc (concat direc "\\")))
+ direc))))
+
+@
+
+\subsubsection{recompile-all-libs}
+
+Occasionally it will be necessary to iterate over all of the NRLIB
+directories and compile each of the code.lsp files in every NRLIB.
+This function will do that. A correct call looks like:
+\begin{verbatim}
+(in-package "BOOT")
+(recompile-all-libs "/spad/mnt/${SYS}/algebra")
+\end{verbatim}
+where the [[${SYS}]] variable is same as the one set at build time.
+<<recompile-all-libs>>=
+(defun recompile-all-libs (dir)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "NRLIB"))
+ (files (directory pattern)))
+ (mapcar
+ #'(lambda (lib) (compile-lib-file (concat (namestring lib) "/code.lsp")))
+ files)))
+
+@
+
+\subsubsection{recompile-all-algebra-files}
+
+We occasionally need to completely rebuild the algebra from the spad
+files. This function will iterate across a directory containing all
+of the spad files and attempt to recompile them. A correct call looks
+like:
+\begin{verbatim}
+(in-package "BOOT")
+(recompile-all-algebra-files "nalg")
+\end{verbatim}
+Note that it will build a pathname from the current {\bf AXIOM}
+shell variable. So if the {\bf AXIOM} shell variable had the value
+\begin{verbatim}
+/spad/mnt/${SYS}
+\end{verbatim}
+(where the [[${SYS}]] variable is the same one set at build time)
+then the wildcard expands to
+\begin{verbatim}
+/spad/mnt/${SYS}/nalg/*.spad
+\end{verbatim}
+and all of the matching files would be recompiled.
+<<recompile-all-algebra-files>>=
+(defun recompile-all-algebra-files (dir) ;; a desperation measure
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type "spad"))
+ (files (directory pattern))
+ (*default-pathname-defaults* (pathname direc)))
+ (mapcar
+ #'(lambda (fname) (spad fname (concat (pathname-name fname) ".out")))
+ files)))
+
+@
+
+\subsubsection{boottocl}
+
+The {\bf boottocl} function is the workhorse function that translates
+{\bf .boot} files to {\bf Common Lisp}. It basically wraps the actual
+{\bf boot} function call to ensure that we don't truncate lines
+because of {\bf *print-level*} or {\bf *print-length*}.
+<<boottocl>>=
+(in-package "OLD-BOOT")
+
+(defun boot (file) ;; translates a single boot file
+#+:CCL
+ (setq *package* (find-package "BOOT"))
+#+:AKCL
+ (in-package "BOOT")
+ (let (*print-level*
+ *print-length*
+ (fn (pathname-name file))
+ (*print-pretty* t))
+ (declare (special *print-level* *print-length*))
+ (boot::boot
+ file
+ (merge-pathnames (make-pathname :type "clisp") file))))
+
+@
+
+\subsubsection{yearweek}
+
+We need a way of distinguishing different versions of the system.
+There used to be a way to touch the src/timestamp file whenever
+you checked in a change to the change control subsystem.
+During make PART=interp (the default for make) we set timestamp
+to the filename of this timestamp file. This function converts it
+to a luser readable string and sets the *yearweek* variable.
+
+The result of this function is a string that is printed as a banner
+when Axiom starts. The actual printing is done by the function
+[[spadStartUpMsgs]] in [[src/interp/msgdb.boot]]. It uses a
+format string from the file [[src/doc/msgs/s2-us.msgs]].
+<<yearweek>>=
+(defun yearweek ()
+ "set *yearweek* to the current time string for the version banner"
+ (declare (special timestamp) (special *yearweek*))
+ (if (and (boundp 'timestamp) (probe-file timestamp))
+ (let (sec min hour date month year day dayvec monvec)
+ (setq dayvec '("Monday" "Tuesday" "Wednesday" "Thursday"
+ "Friday" "Saturday" "Sunday"))
+ (setq monvec '("January" "February" "March" "April" "May" "June"
+ "July" "August" "September" "October" "November"
+ "December"))
+ (multiple-value-setq (sec min hour date month year day)
+ (decode-universal-time
+ (file-write-date timestamp)))
+ (setq *yearweek*
+ (copy-seq
+ (format nil "~a ~a ~d, ~d at ~2,'0d:~2,'0d:~2,'0d "
+ (elt dayvec day)
+ (elt monvec (1- month)) date year hour min sec))))
+ (setq *yearweek* "no timestamp")))
+
+@
+
+\subsubsection{makelib}
+
+Make will not compare dates across directories.
+Rather than copy all of the code.lsp files to the MNT directory
+we run this function to compile the files that are out of date
+this function assumes that the shell variables INT and MNT are set.
+
+Also of note: on the rt some files (those in the nooptimize list)
+need to be compiled without optimize due to compiler bugs
+<<makelib>>=
+(defun makelib (mid out stype btype)
+ "iterate over the NRLIBs, compiling ones that are out of date.
+ mid is the directory containing code.lsp
+ out is the directory containing code.o"
+ (let (libs lspdate odate nooptimize (alphabet #\space))
+#+(and :akcl :rt)
+ (setq nooptimize '("FFCAT-.NRLIB" "CHVAR.NRLIB" "PFO.NRLIB" "SUP.NRLIB"
+ "INTG0.NRLIB" "FSPRMELT.NRLIB" "VECTOR.NRLIB"
+ "EUCDOM-.NRLIB"))
+ (if (and mid out)
+ (format t "doing directory on ~s...~%" (concatenate 'string mid "/*"))
+ (error "makelib:MID=~a OUT=~a~% these are not set properly~%" mid out))
+#+:akcl (compiler::emit-fn nil)
+#+:akcl (si::chdir mid)
+#-:akcl (vmlisp::obey (concatenate 'string "cd " mid))
+ (setq libs (directory "*.NRLIB"))
+ (unless libs
+ (format t "makelib:directory of ~a returned NIL~%" mid)
+ (bye -1))
+ (princ "checking ")
+ (dolist (lib libs)
+ (unless (char= (schar (pathname-name lib) 0) alphabet)
+ (setq alphabet (schar (pathname-name lib) 0))
+ (princ alphabet)
+ (finish-output))
+ (let (dotlsp doto mntlib intkaf mntkaf intkafdate mntkafdate)
+ (setq dotlsp
+ (concatenate 'string mid "/" (file-namestring lib) "/code." stype))
+ (setq doto
+ (concatenate 'string out "/" (pathname-name lib) ".NRLIB/code." btype))
+ (setq mntlib
+ (concatenate 'string out "/" (pathname-name lib) ".NRLIB"))
+ (setq intkaf
+ (concatenate 'string mid "/" (file-namestring lib) "/index.KAF*"))
+ (setq mntkaf
+ (concatenate 'string out "/" (pathname-name lib) ".NRLIB/index.KAF*"))
+ (unless (probe-file mntlib)
+ (format t "creating directory ~a~%" mntlib)
+ (vmlisp::obey (concatenate 'string "cp -pr " (namestring lib) " " out))
+ (when (probe-file (concatenate 'string mntlib "/code." stype))
+ (delete-file (concatenate 'string mntlib "/code." stype))))
+ (setq intkafdate (and (probe-file intkaf) (file-write-date intkaf)))
+ (setq mntkafdate (and (probe-file mntkaf) (file-write-date mntkaf)))
+ (when intkafdate
+ (unless (and mntkafdate (> mntkafdate intkafdate))
+ (format t "~&copying ~s to ~s" intkaf mntkaf)
+ (vmlisp::obey
+ (concatenate 'string "cp "
+ (namestring intkaf) " " (namestring mntkaf)))))
+ (setq lspdate (and (probe-file dotlsp) (file-write-date dotlsp)))
+ (setq odate (and (probe-file doto) (file-write-date doto)))
+ (when lspdate
+ (unless (and odate (> odate lspdate))
+#+(and :akcl :rt)
+ (if (member (file-namestring lib) nooptimize :test #'string=)
+ (setq compiler::*speed* 0)
+ (setq compiler::*speed* 3))
+ (compile-lib-file dotlsp :output-file doto)))))))
+
+@
+
+\subsubsection{makespad}
+
+Make will not compare dates across directories.
+In particular, it cannot compare the algebra files because there
+is a one-to-many correspondence. This function will walk over
+all of the algebra NRLIB files and find all of the spad files
+that are out of date and need to be recompiled. This function
+creates a file "/tmp/compile.input" to be used later in the
+makefile.
+
+Note that the file /tmp/compile.input is not currently used
+as algebra source recompiles are not necessarily something
+we want done automatically. Nevertheless, in the quest for
+quality we check anyway.
+<<makespad>>=
+(defun makespad (src mid stype)
+ "iterate over the spad files, compiling ones that are out of date.
+ src is the directory containing .spad
+ mid is the directory containing code.lsp
+ out is the directory containing code.o"
+ (let (mntlibs spadwork (alphabet #\space))
+ (labels (
+ (findsrc (mid libname)
+ "return a string name of the source file given the library file
+ name (eg PI) as a string"
+ (let (kaffile index alist)
+ (setq kaffile
+ (concatenate 'string mid "/" libname ".NRLIB/index.KAF*"))
+ (with-open-file (kaf kaffile)
+ (setq index (read kaf))
+ (file-position kaf index)
+ (setq alist (read kaf))
+ (setq index (third (assoc "sourceFile" alist :test #'string=)))
+ (file-position kaf index)
+ (pathname-name (pathname (read kaf index)))))))
+ (format t "makespad:src=~s mid=~s stype=~s~%" src mid stype)
+ (if (and src mid)
+ (format t "doing directory on ~s...~%" (concatenate 'string src "/*"))
+ (error "makespad:SRC=~a MID=~a not set properly~%" src mid))
+#+:akcl (si::chdir mid)
+#-:akcl (vmlisp::obey (concatenate 'string "cd " mid))
+ (setq mntlibs (directory "*.NRLIB"))
+ (unless mntlibs
+ (format t "makespad:directory of ~a returned NIL~%" src)
+ (bye 1))
+ (princ "checking ")
+ (dolist (lib mntlibs)
+ (unless (char= (schar (pathname-name lib) 0) alphabet)
+ (setq alphabet (schar (pathname-name lib) 0))
+ (princ alphabet)
+ (finish-output))
+ (let (spad spaddate lsp lspdate)
+ (setq spad
+ (concatenate 'string src "/" (findsrc mid (pathname-name lib)) ".spad"))
+ (setq spaddate
+ (and (probe-file spad) (file-write-date spad)))
+ (setq lsp
+ (concatenate 'string mid "/" (pathname-name lib) ".NRLIB/code." stype))
+ (setq lspdate
+ (and (probe-file lsp) (file-write-date lsp)))
+ (cond
+ ((and spaddate lspdate (<= spaddate lspdate)))
+ ((and spaddate lspdate (> spaddate lspdate))
+ (setq spadwork (adjoin spad spadwork :test #'string=)))
+ ((and spaddate (not lspdate))
+ (setq spadwork (adjoin spad spadwork :test #'string=)))
+ ((and (not spaddate) lspdate)
+ (format t "makespad:missing spad file ~a for lisp file ~a~%" spad lsp))
+ ((and (not spaddate) (not lspdate))
+ (format t "makespad:NRLIB ~a exist but is spad ~a and lsp ~a don't~%"
+ lib spad lsp)))))
+ (with-open-file (tmp "/tmp/compile.input" :direction :output)
+ (dolist (spad spadwork)
+ (format t "~a is out of date~%" spad)
+ (format tmp ")co ~a~%" spad))))))
+
+@
+
+\subsubsection{libcheck}
+
+We need to ensure that the INTERP.EXPOSED list, which is a list
+of the exposed constructors, is consistent with the actual libraries.
+<<libcheck>>=
+(defun libcheck (int)
+ "check that INTERP.EXPOSED and NRLIBs are consistent"
+ (let (interp nrlibs)
+ (labels (
+ (CONSTRUCTORNAME (nrlib)
+ "find the long name of a constructor given an abbreviation string"
+ (let (file sourcefile name)
+ (setq file (findsrc nrlib))
+ (setq sourcefile
+ (concatenate 'string int "/" file ".spad"))
+ (when (and file (probe-file sourcefile))
+ (setq name (searchsource sourcefile nrlib)))))
+ (NOCAT (longnames)
+ "remove the categories from the list of long names"
+ (remove-if
+ #'(lambda (x)
+ (let ((c (schar x (1- (length x)))))
+ (or (char= c #\&) (char= c #\-)))) longnames))
+ (FINDSRC (libname)
+ "return a string name of the source file given the library file
+ name (eg PI) as a string"
+ (let (kaffile index alist result)
+ (setq kaffile
+ (concatenate 'string int "/" libname ".NRLIB/index.KAF*"))
+ (if (probe-file kaffile)
+ (with-open-file (kaf kaffile)
+ (setq index (read kaf))
+ (file-position kaf index)
+ (setq alist (read kaf))
+ (setq index (third (assoc "sourceFile" alist :test #'string=)))
+ (file-position kaf index)
+ (setq result (pathname-name (pathname (read kaf index))))))
+ (format t "~a does not exist~%" kaffile)
+ result))
+ (READINTERP ()
+ "read INTERP.EXPOSED and return a sorted abbreviation list"
+ (let (expr names longnames)
+ (with-open-file (in (concatenate 'string int "/INTERP.EXPOSED"))
+ (catch 'eof
+ (loop
+ (setq expr (read-line in nil 'eof))
+ (when (eq expr 'eof) (throw 'eof nil))
+ (when
+ (and
+ (> (length expr) 58)
+ (char= (schar expr 0) #\space)
+ (not (char= (schar expr 8) #\space)))
+ (push (string-trim '(#\space) (subseq expr 8 57)) longnames)
+ (push (string-right-trim '(#\space) (subseq expr 58)) names)))))
+ (setq longnames (sort longnames #'string<))
+ (setq names (sort names #'string<))
+ (values names longnames)))
+ (READLIBS (algebra)
+ "read the NRLIB directory and return a sorted abbreviation list"
+ (let (libs nrlibs)
+#+:akcl (si::chdir algebra)
+#-:akcl (vmlisp::obey (concatenate 'string "cd " algebra))
+ (setq nrlibs (directory "*.NRLIB"))
+ (unless nrlibs
+ (error "libcheck: (directory ~s) returned NIL~%"
+ (concatenate 'string algebra "/*.NRLIB")))
+ (dolist (lib nrlibs)
+ (push (pathname-name lib) libs))
+ (sort libs #'string<)))
+ (SEARCHSOURCE (sourcefile nrlib)
+ "search a sourcefile for the long constructor name of the nrlib string"
+ (let (in expr start)
+ (setq nrlib (concatenate 'string " " nrlib " "))
+ (catch 'done
+ (with-open-file (in sourcefile)
+ (loop
+ (setq expr (read-line in nil 'done))
+ (when (eq expr 'done) (throw 'done nil))
+ (when (and (> (length expr) 4)
+ (string= ")abb" (subseq expr 0 4))
+ (search nrlib expr :test #'string=)
+ (setq start (position #\space expr :from-end t :test #'char=)))
+ (throw 'done (string-trim '(#\space) (subseq expr start)))))))))
+ (SRCABBREVS (sourcefile)
+ (let (in expr start end names longnames)
+ (catch 'done
+ (with-open-file (in sourcefile)
+ (loop
+ (setq expr (read-line in nil 'done))
+ (when (eq expr 'done) (throw 'done nil))
+ (when (and (> (length expr) 4)
+ (string= ")abb" (subseq expr 0 4)))
+ (setq point (position #\space expr :from-end t :test #'char=))
+ (push (string-trim '(#\space) (subseq expr point)) longnames)
+ (setq mark
+ (position #\space
+ (string-right-trim '(#\space)
+ (subseq expr 0 (1- point))) :from-end t))
+ (push (string-trim '(#\space) (subseq expr mark point)) names)))))
+ (values names longnames)))
+ (SRCSCAN ()
+ (let (longnames names)
+#+:gcl (system::chdir int)
+#-:gcl (vmlisp::obey (concatenate 'string "cd " int))
+ (setq spads (directory "*.spad"))
+ (dolist (spad spads)
+ (multiple-value-setq (short long) (srcabbrevs spad))
+ (setq names (nconc names short))
+ (setq longnames (nconc longnames long)))
+ (setq names (sort names #'string<))
+ (setq longnames (sort longnames #'string<))
+ (values names longnames))))
+ (multiple-value-setq (abbrevs constructors) (readinterp))
+ (setq nrlibs (readlibs int))
+ (dolist (lib (set-difference nrlibs abbrevs :test #'string=))
+ (format t "libcheck:~a/~a.NRLIB is not in INTERP.EXPOSED~%" int lib))
+ (dolist (expose (set-difference abbrevs nrlibs :test #'string=))
+ (format t "libcheck:~a is in INTERP.EXPOSED with no NRLIB~%" expose))
+ (multiple-value-setq (srcabbrevs srcconstructors) (srcscan))
+ (setq abbrevs (nocat abbrevs))
+ (setq constructors (nocat constructors))
+ (dolist (item (set-difference srcabbrevs abbrevs :test #'string=))
+ (format t "libcheck:~a is in ~a but not in INTERP.EXPOSED~%" item
+ (findsrc item)))
+ (dolist (item (set-difference abbrevs srcabbrevs :test #'string=))
+ (format t "libcheck:~a is in INTERP.EXPOSED but has no spad sourcfile~%"
+ item))
+ (dolist (item (set-difference srcconstructors constructors :test #'string=))
+ (format t "libcheck:~a is not in INTERP.EXPOSED~%" item))
+ (dolist (item (set-difference constructors srcconstructors :test #'string=))
+ (format t "libcheck:~a has no spad source file~%" item)))))
+
+@
+
+
+\subsection{Constructing TAGS}
+
+TAGS are useful for finding functions if you run Emacs. We have a
+set of functions that construct TAGS files for Axiom.
+\subsubsection{make-tags-file}
+Run the etags command on all of the lisp code. Then run the
+{\bf spadtags-from-directory} function on the boot code. The
+final TAGS file is constructed in the {\bf tmp} directory.
+<<make-tags-file>>=
+(defun make-tags-file ()
+#+:gcl (system:chdir "/tmp")
+#-:gcl (vmlisp::obey (concatenate 'string "cd " "/tmp"))
+ (obey (concat "etags " (make-absolute-filename "../../src/interp/*.lisp")))
+ (spadtags-from-directory "../../src/interp" "boot")
+ (obey "cat /tmp/boot.TAGS >> /tmp/TAGS"))
+
+@
+
+\subsubsection{spadtags-from-directory}
+
+This function will walk across a directory and call
+{\bf spadtags-from-file} on each file.
+<<spadtags-from-directory>>=
+(defun spadtags-from-directory (dir type)
+ (let* ((direc (make-directory dir))
+ (pattern (make-pathname :directory (pathname-directory direc)
+ :name :wild :type type))
+ (files (directory pattern)))
+ (with-open-file
+ (tagstream (concatenate 'string "/tmp/" type ".TAGS") :direction :output
+ :if-exists :supersede :if-does-not-exist :create)
+ (dolist (file files (namestring tagstream))
+ (print (list "processing:" file))
+ (write-char #\page tagstream)
+ (terpri tagstream)
+ (write-string (namestring file) tagstream)
+ (write-char #\, tagstream)
+ (princ (spadtags-from-file file) tagstream)
+ (terpri tagstream)
+ (with-open-file (stream "/tmp/*TAGS")
+ (do ((line (read-line stream nil nil)
+ (read-line stream nil nil)))
+ ((null line) nil)
+ (write-line line tagstream)))))))
+
+@
+
+\subsubsection{spadtags-from-file}
+
+This function knows how to find function names in {\bf boot} code
+so we can add them to the TAGS file using standard etags format.
+<<spadtags-from-file>>=
+(defun spadtags-from-file (spadfile)
+ (with-open-file (tagstream "/tmp/*TAGS" :direction :output
+ :if-exists :supersede :if-does-not-exist :create)
+ (with-open-file (stream spadfile)
+ (do ((char-count 0 (file-position stream))
+ (line (read-line stream nil nil) (read-line stream nil nil))
+ (line-count 1 (1+ line-count)))
+ ((null line) (file-length tagstream))
+ (if (/= (length line) 0)
+ (let ((firstchar (elt line 0)) (end nil)
+ (len (length line)))
+ (cond ((member firstchar '(#\space #\{ #\} #\tab )
+ :test #'char= ) "skip")
+ ((string= line ")abb" :end1 (min 4 len))
+ (setq end (position #\space line :from-end t
+ :test-not #'eql)
+ end (and end (position #\space line :from-end t
+ :end end)))
+ (write-tag-line line tagstream end
+ line-count char-count))
+ ((char= firstchar #\)) "skip")
+ ((and (> len 1) (string= line "--" :end1 2)) "skip")
+ ((and (> len 1) (string= line "++" :end1 2)) "skip")
+ ((search "==>" line) "skip")
+ ((and (setq end (position #\space line)
+ end (or (position #\( line :end end) end)
+ end (or (position #\: line :end end) end)
+ end (or (position #\[ line :end end) end))
+ (equal end 0)) "skip")
+ ((position #\] line :end end) "skip")
+ ((string= line "SETANDFILEQ" :end1 end) "skip")
+ ((string= line "EVALANDFILEACTQ" :end1 end) "skip")
+ (t (write-tag-line line tagstream
+ (if (numberp end) (+ end 1) end)
+ line-count char-count)) )))))))
+
+@
+
+\subsubsection{write-tag-line}
+
+This function knows how to write a single line into a TAGS file
+using the etags file format.
+<<write-tag-line>>=
+(defun write-tag-line (line tagstream endcol line-count char-count)
+ (write-string line tagstream :end endcol)
+ (write-char #\rubout tagstream)
+ (princ line-count tagstream)
+ (write-char #\, tagstream)
+ (princ char-count tagstream)
+ (terpri tagstream))
+
+@
+
+\subsubsection{blankcharp}
+
+This is a trivial predicate for calls to {\bf position-if-not} in the
+{\bf findtag} function.
+<<blankcharp>>=
+(defun blankcharp (c) (char= c #\Space))
+
+@
+
+\subsubsection{findtag}
+
+The {\bf findtag} function is a user-level function to figure out
+which file contains a given tag. This is sometimes useful if Emacs
+is not around or TAGS are not loaded.
+<<findtag>>=
+(defun findtag (tag &optional (tagfile (concat $spadroot "/../../src/interp/TAGS")) )
+ ;; tag is an identifier
+ (with-open-file (tagstream tagfile)
+ (do ((tagline (read-line tagstream nil nil)
+ (read-line tagstream nil nil))
+ (*package* (symbol-package tag))
+ (sourcefile)
+ (stringtag (string tag))
+ (pos)
+ (tpos)
+ (type))
+ ((null tagline) ())
+ (cond ((char= (char tagline 0) #\Page)
+ (setq tagline (read-line tagstream nil nil))
+ (setq sourcefile (subseq tagline 0
+ (position #\, tagline)))
+ (setq type (pathname-type sourcefile)))
+ ((string= type "lisp")
+ (if (match-lisp-tag tag tagline)
+ (return (cons sourcefile tagline))))
+ ((> (mismatch ")abb" tagline) 3)
+ (setq pos (position #\Space tagline :start 3))
+ (setq pos (position-if-not #'blankcharp tagline
+ :start pos))
+ (setq pos (position #\Space tagline :start pos))
+ (setq pos (position-if-not #'blankcharp tagline
+ :start pos))
+ (setq tpos (mismatch stringtag tagline :start2 pos))
+ (if (and (= tpos (length (string tag)))
+ (member (char tagline (+ pos tpos)) '(#\Space #\Rubout)))
+ (return (cons sourcefile tagline))))
+ ((setq pos (mismatch stringtag tagline))
+ (if (and (= pos (length stringtag))
+ (> (length tagline) pos)
+ (member (char tagline pos)
+ '( #\Space #\( #\:) ))
+ (return (cons sourcefile tagline))))))))
+
+@
+
+\subsubsection{match-lisp-tag}
+
+The {\bf match-lisp-tag} function is used by {\bf findtag}. This
+function assumes that \\ can only appear as first character of name.
+<<match-lisp-tag>>=
+(defun match-lisp-tag (tag tagline &optional (prefix nil)
+ &aux (stringtag (string tag)) pos tpos)
+ (when (and (if prefix
+ (= (mismatch prefix tagline :test #'char-equal)
+ (length prefix))
+ t)
+ (numberp (setq pos (position #\Space tagline)))
+ (numberp (setq pos (position-if-not #'blankcharp tagline
+ :start pos))))
+ (if (char= (char tagline pos) #\') (incf pos))
+ (if (member (char tagline pos) '( #\\ #\|))
+ (setq tpos (1+ pos))
+ (setq tpos pos))
+ (and (= (mismatch stringtag tagline :start2 tpos :test #'char-equal)
+ (length stringtag))
+ (eq tag (read-from-string tagline nil nil :start pos))) ))
+
+@
+
+
+\subsection{Translated Boot functions}
+
+\subsubsection{string2BootTree}
+
+<<string2BootTree>>=
+(DEFUN |string2BootTree| (S)
+ (init-boot/spad-reader)
+ (LET* ((BOOT-LINE-STACK (LIST (CONS 1 S)))
+ ($BOOT T)
+ ($SPAD NIL)
+ (XTOKENREADER 'GET-BOOT-TOKEN)
+ (LINE-HANDLER 'NEXT-BOOT-LINE)
+ (PARSEOUT (PROGN (|PARSE-Expression|) (POP-STACK-1))))
+ (DECLARE (SPECIAL BOOT-LINE-STACK $BOOT $SPAD XTOKENREADER LINE-HANDLER))
+ (DEF-RENAME (|new2OldLisp| PARSEOUT))))
+
+@
+
+\subsubsection{string2SpadTree}
+
+<<string2SpadTree>>=
+(DEFUN |string2SpadTree| (LINE)
+ (DECLARE (SPECIAL LINE))
+ (if (and (> (LENGTH LINE) 0) (EQ (CHAR LINE 0) #\) ))
+ (|processSynonyms|))
+ (ioclear)
+ (LET* ((BOOT-LINE-STACK (LIST (CONS 1 LINE)))
+ ($BOOT NIL)
+ ($SPAD T)
+ (XTOKENREADER 'GET-BOOT-TOKEN)
+ (LINE-HANDLER 'NEXT-BOOT-LINE)
+ (PARSEOUT (PROG2 (|PARSE-NewExpr|) (POP-STACK-1))))
+ (DECLARE (SPECIAL BOOT-LINE-STACK $BOOT $SPAD XTOKENREADER LINE-HANDLER))
+ PARSEOUT))
+
+@
+
+\subsubsection{processSynonyms}
+
+;;--------------------> NEW DEFINITION (see i-syscmd.boot.pamphlet)
+<<processSynonyms>>=
+(defun |processSynonyms| () nil) ;;dummy def for depsys, redefined later
+
+@
+
+
+\section{License}
+
+<<license>>=
+;; Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are
+;; met:
+;;
+;; - Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;;
+;; - Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in
+;; the documentation and/or other materials provided with the
+;; distribution.
+;;
+;; - Neither the name of The Numerical ALgorithms Group Ltd. nor the
+;; names of its contributors may be used to endorse or promote products
+;; derived from this software without specific prior written permission.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+;; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+;; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+;; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+@
+<<*>>=
+<<license>>
+
+#-:common-lisp (IMPORT-MODULE "vmlisp")
+
+(in-package "BOOT")
+(export '($spadroot $directory-list $current-directory reroot
+ make-absolute-filename |$msgDatabaseName| |$defaultMsgDatabaseName|))
+
+<<our-write-date>>
+<<make-directory>>
+<<interp-make-directory>>
+<<bin-path>>
+<<load-directory>>
+<<compspadfiles>>
+<<recompile-all-algebra-files>>
+<<fe>>
+<<fc>>
+<<recompile-directory>>
+<<recompile-file-if-necessary>>
+<<recompile-all-files>>
+<<recompile-lib-directory>>
+<<recompile-all-libs>>
+<<recompile-NRLIB-if-necessary>>
+<<lift-NRLIB-name>>
+<<retranslate-directory>>
+<<retranslate-file-if-necessary>>
+<<make-tags-file>>
+<<spadtags-from-directory>>
+<<spadtags-from-file>>
+<<write-tag-line>>
+<<blankcharp>>
+<<findtag>>
+<<match-lisp-tag>>
+<<compile-boot-file>>
+<<translate>>
+<<translist>>
+<<relative-directory-list>>
+<<relative-library-directory-list>>
+<<directory-list>>
+<<library-directory-list>>
+<<boottocl>>
+
+(in-package "BOOT")
+
+<<parse-functions>>
+<<comp-functions>>
+<<browse-functions>>
+<<translate-functions>>
+<<asauto-functions>>
+<<debug-functions>>
+<<anna-functions>>
+<<nagbr-functions>>
+<<setBootAutloadProperties>>
+<<boot-load>>
+<<setBootAutoLoadProperty>>
+<<mkBootAutoLoad>>
+<<build-interpsys>>
+<<setNAGBootAutloadProperties>>
+<<get-NAG-chapter>>
+<<nag-files>>
+<<chapter-name>>
+<<build-depsys>>
+
+<<string2BootTree>>
+<<string2SpadTree>>
+<<processSynonyms>>
+
+;; the following are for conditional reading
+#+:ieee-floating-point (setq $ieee t)
+#-:ieee-floating-point (setq $ieee nil)
+(setq |$opSysName| '"shell")
+#+:CCL (defun machine-type () "unknown")
+(setq |$machineType| (machine-type))
+; spad-clear-input patches around fact that akcl clear-input leaves newlines chars
+(defun spad-clear-input (st) (clear-input st) (if (listen st) (read-char st)))
+
+<<yearweek>>
+(defun sourcepath (f)
+ "find the sourcefile in the system directories"
+ (let (axiom algebra naglink)
+ (setq axiom (|getEnv| "AXIOM"))
+ (setq algebra (concatenate 'string axiom "/../../src/algebra/" f ".spad"))
+ (setq naglink (concatenate 'string axiom "/../../src/naglink/" f ".spad"))
+ (cond
+ ((probe-file algebra) algebra)
+ ((probe-file naglink) naglink)
+ ('else nil))))
+
+(defun srcabbrevs (sourcefile)
+ "read spad source files and return the constructor names and abbrevs"
+ (let (expr point mark names longnames)
+ (catch 'done
+ (with-open-file (in sourcefile)
+ (loop
+ (setq expr (read-line in nil 'done))
+ (when (eq expr 'done) (throw 'done nil))
+ (when (and (> (length expr) 4) (string= ")abb" (subseq expr 0 4)))
+ (setq expr (string-right-trim '(#\space #\tab) expr))
+ (setq point (position #\space expr :from-end t :test #'char=))
+ (push (subseq expr (1+ point)) longnames)
+ (setq expr (string-right-trim '(#\space #\tab)
+ (subseq expr 0 point)))
+ (setq mark (position #\space expr :from-end t))
+ (push (subseq expr (1+ mark)) names)))))
+ (values longnames names)))
+
+
+#+(and :AKCL (not (or :dos :win32)))
+(in-package "COMPILER")
+#+(and :AKCL (not (or :dos :win32)))
+(defun gazonk-name ( &aux tem)
+ "return the name of the intermediate compiler file"
+ (dotimes (i 1000)
+ (setq tem (merge-pathnames (format nil "/tmp/gazonk~d.lsp" i)))
+ (unless (probe-file tem)
+ (return-from gazonk-name (pathname tem))))
+ (error "1000 gazonk names used already!"))
+
+(in-package "BOOT")
+
+(defun |tr| (fn)
+ (|oldCompilerAutoloadOnceTrigger|)
+ (|browserAutoloadOnceTrigger|)
+ (|spad2AsTranslatorAutoloadOnceTrigger|)
+ (|convertSpadFile| fn) )
+
+<<makelib>>
+<<makespad>>
+<<libcheck>>
+
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}