\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename slib.info @settitle slib @include version.txi @setchapternewpage on @c Choices for setchapternewpage are {on,off,odd}. @paragraphindent 2 @defcodeindex ft @syncodeindex ft cp @syncodeindex tp cp @c %**end of header @copying @noindent This manual is for SLIB (version @value{SLIBVERSION}, @value{SLIBDATE}), the portable Scheme library. @noindent @c Copyright (C) 1993 Todd R. Eigenschink@* Copyright @copyright{} 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation @end copying @dircategory The Algorithmic Language Scheme @direntry * SLIB: (slib). Scheme Library @end direntry @iftex @finalout @c DL: lose the egregious vertical whitespace, esp. around examples @c but paras in @defun-like things don't have parindent @parskip 4pt plus 1pt @end iftex @titlepage @title SLIB @subtitle The Portable Scheme Library @subtitle Version @value{SLIBVERSION}, @value{SLIBDATE} @author Aubrey Jaffer @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, The Library System, (dir), (dir) @top SLIB @insertcopying @menu * The Library System:: How to use and customize. * Universal SLIB Procedures:: Provided for all implementations. * Scheme Syntax Extension Packages:: * Textual Conversion Packages:: * Mathematical Packages:: * Database Packages:: * Other Packages:: * About SLIB:: Install, etc. * Index:: @end menu @end ifnottex @node The Library System, Universal SLIB Procedures, Top, Top @chapter The Library System @noindent @dfn{SLIB} is a portable library for the programming language @dfn{Scheme}. It provides a platform independent framework for using @dfn{packages} of Scheme procedures and syntax. As distributed, SLIB contains useful packages for all Scheme implementations. Its catalog can be transparently extended to accomodate packages specific to a site, implementation, user, or directory. @menu * Feature:: SLIB names. * Require:: * Library Catalogs:: * Catalog Creation:: * Catalog Vicinities:: * Compiling Scheme:: @end menu @node Feature, Require, The Library System, The Library System @section Feature @noindent @cindex feature SLIB denotes @dfn{features} by symbols. SLIB maintains a list of features supported by a Scheme @dfn{session}. The set of features @cindex session provided by a session may change during that session. Some features are properties of the Scheme implementation being used. The following @cindex intrinsic feature @dfn{intrinsic feature}s detail what sort of numbers are available from an implementation: @ftindex inexact @ftindex rational @ftindex real @ftindex complex @ftindex bignum @itemize @bullet @item 'inexact @item 'rational @item 'real @item 'complex @item 'bignum @end itemize @noindent SLIB initialization (in @file{require.scm}) tests and @dfn{provide}s any of these numeric features which are appropriate. @noindent Other features correspond to the presence of packages of Scheme procedures or syntax (macros). @defun provided? feature Returns @code{#t} if @var{feature} is present in the current Scheme session; otherwise @code{#f}. More specifically, @code{provided?} returns @code{#t} if the symbol @var{feature} is the @code{software-type}, the @code{scheme-implementation-type} @footnote{scheme-implementation-type is the name symbol of the running Scheme implementation (RScheme, |STk|, Bigloo, chez, Elk, gambit, guile, JScheme, kawa, MacScheme, MITScheme, Pocket-Scheme, Scheme48, Scheme->C, Scheme48, Scsh, SISC, T, umb-scheme, or Vscm). Dependence on scheme-implementation-type is almost always the wrong way to do things.}, or if @var{feature} has been provided by a module already loaded; and @code{#f} otherwise. In some implementations @code{provided?} tests whether a module has been @code{require}d by any module or in any thread; other implementations will have @code{provided?} reflect only the modules @code{require}d by that particular session or thread. To work portably in both scenarios, use @code{provided?} only to test whether intrinsic properties (like those above) are present. The @var{feature} argument can also be an expression calling @code{and}, @code{or}, and @code{not} of features. The boolean result of the logical question asked by @var{feature} is returned. @end defun @noindent The generalization of @code{provided?} for arbitrary features and catalog is @code{feature-eval}: @defun feature-eval expression provided? Evaluates @code{and}, @code{or}, and @code{not} forms in @var{expression}, using the values returned by calling @var{provided?} on the leaf symbols. @code{feature-eval} returns the boolean result of the logical combinations. @end defun @deffn {Procedure} provide feature Informs SLIB that @var{feature} is supported in this session. @end deffn @example (provided? 'foo) @result{} #f (provide 'foo) (provided? 'foo) @result{} #t @end example @c @defvar slib:features @c Is a list of symbols denoting features present in this implementation. @c @var{slib:features} can grow as modules are @code{require}d. @c @footnote{The variables @var{*modules*} and @var{slib:features} were @c originally modeled on variables of the same names in common-lisp. But @c the distinction between features native to an implementation versus @c those provided by loading files was not useful. The symbols in @c @var{slib:features} now indicate the presence of a capability regardless @c of how it was provided.} @c @end defvar @node Require, Library Catalogs, Feature, The Library System @section Require @noindent @cindex catalog SLIB creates and maintains a @dfn{catalog} mapping features to locations of files introducing procedures and syntax denoted by those features. @defvar *catalog* Is an association list of features (symbols) and pathnames which will supply those features. The pathname can be either a string or a pair. If pathname is a pair then the first element should be a macro feature symbol, @code{source}, @code{compiled}, or one of the other cases described in @ref{Library Catalogs}. The cdr of the pathname should be either a string or a list. @end defvar @noindent At the beginning of each section of this manual, there is a line like @code{(require '@var{feature})}. @ftindex feature The Scheme files comprising SLIB are cataloged so that these feature names map to the corresponding files. @noindent SLIB provides a form, @code{require}, which loads the files providing the requested feature. @deffn {Procedure} require feature @itemize @bullet @item If @code{(provided? @var{feature})} is true, then @code{require} just returns. @item Otherwise, if @var{feature} is found in the catalog, then the corresponding files will be loaded and @code{(provided? @var{feature})} will henceforth return @code{#t}. That @var{feature} is thereafter @code{provided}. @item Otherwise (@var{feature} not found in the catalog), an error is signaled. @end itemize @end deffn @noindent There is a related form @code{require-if}, used primarily for enabling compilers to statically include modules which would be dynamically loaded by interpreters. @deffn {Procedure} require-if condition feature Requires @var{feature} if @var{condition} is true. @end deffn @noindent The @code{random} module uses @code{require-if} to flag @code{object->string} as a (dynamic) required module. @example (require 'byte) (require 'logical) (require-if 'compiling 'object->string) @end example @noindent The @code{batch} module uses @code{require-if} to flag @code{posix-time} as a module to load if the implementation supports large precision exact integers. @example (require-if '(and bignum compiling) 'posix-time) @end example @noindent The catalog can also be queried using @code{slib:in-catalog?}. @defun slib:in-catalog? feature Returns a @code{CDR} of the catalog entry if one was found for the symbol @var{feature} in the alist @code{*catalog*} (and transitively through any symbol aliases encountered). Otherwise, returns @code{#f}. The format of catalog entries is explained in @ref{Library Catalogs}. @end defun @node Library Catalogs, Catalog Creation, Require, The Library System @section Library Catalogs @noindent Catalog files consist of one or more @dfn{association list}s. @cindex Catalog File In the circumstance where a feature symbol appears in more than one list, the latter list's association is retrieved. Here are the supported formats for elements of catalog lists: @table @code @item (@var{feature} . @i{}) Redirects to the feature named @i{}. @item (@var{feature} . "@i{}") Loads file @i{}. @item (@var{feature} source "@i{"}) @cindex source @code{slib:load}s the Scheme source file @i{}. @item (@var{feature} compiled "@i{"} @dots{}) @cindex compiled @code{slib:load-compiled}s the files @i{} @dots{}. @item (@var{feature} aggregate @i{} @dots{}) @cindex aggregate @code{require}s the features @i{} @dots{}. @end table @noindent The various macro styles first @code{require} the named macro package, then just load @i{} or load-and-macro-expand @i{} as appropriate for the implementation. @table @code @item (@var{feature} defmacro "@i{"}) @cindex defmacro @code{defmacro:load}s the Scheme source file @i{}. @item (@var{feature} macro-by-example "@i{"}) @cindex macro-by-example @code{defmacro:load}s the Scheme source file @i{}. @end table @table @code @item (@var{feature} macro "@i{"}) @cindex macro @code{macro:load}s the Scheme source file @i{}. @item (@var{feature} macros-that-work "@i{"}) @cindex macros-that-work @code{macro:load}s the Scheme source file @i{}. @item (@var{feature} syntax-case "@i{"}) @cindex syntax-case @code{macro:load}s the Scheme source file @i{}. @item (@var{feature} syntactic-closures "@i{"}) @cindex syntactic-closures @code{macro:load}s the Scheme source file @i{}. @end table @node Catalog Creation, Catalog Vicinities, Library Catalogs, The Library System @section Catalog Creation @noindent At the start of an interactive session no catalog is present, but is created with the first catalog inquiry (such as @code{(require 'random)}). Several sources of catalog information are combined to produce the catalog: @itemize @bullet @item standard SLIB packages. @item additional packages of interest to this site. @item packages specifically for the variety of Scheme which this session is running. @item packages this user wants to always have available. This catalog is the file @file{homecat} in the user's @dfn{HOME} directory. @cindex HOME @item packages germane to working in this (current working) directory. This catalog is the file @file{usercat} in the directory to which it applies. One would typically @code{cd} to this directory before starting the Scheme session. @item packages which are part of an application program. @end itemize @noindent SLIB combines the catalog information which doesn't vary per user into the file @file{slibcat} in the implementation-vicinity. Therefore @file{slibcat} needs change only when new software is installed or compiled. Because the actual pathnames of files can differ from installation to installation, SLIB builds a separate catalog for each implementation it is used with. @noindent The definition of @code{*slib-version*} in SLIB file @file{require.scm} is checked against the catalog association of @code{*slib-version*} to ascertain when versions have changed. It is a reasonable practice to change the definition of @code{*slib-version*} whenever the library is changed. If multiple implementations of Scheme use SLIB, remember that recompiling one @file{slibcat} will update only that implementation's catalog. @noindent The compilation scripts of Scheme implementations which work with SLIB can automatically trigger catalog compilation by deleting @file{slibcat} or by invoking @code{require} of a special feature: @deffn {Procedure} require @r{'new-catalog} @cindex new-catalog This will load @file{mklibcat}, which compiles and writes a new @file{slibcat}. @end deffn @noindent Another special feature of @code{require} erases SLIB's catalog, forcing it to be reloaded the next time the catalog is queried. @deffn {Procedure} require @r{#f} Removes SLIB's catalog information. This should be done before saving an executable image so that, when restored, its catalog will be loaded afresh. @end deffn @node Catalog Vicinities, Compiling Scheme, Catalog Creation, The Library System @section Catalog Vicinities @noindent Each file in the table below is descibed in terms of its file-system independent @dfn{vicinity} (@pxref{Vicinity}). The entries of a catalog in the table override those of catalogs above it in the table. @table @asis @item @code{implementation-vicinity} @file{slibcat} @cindex slibcat This file contains the associations for the packages comprising SLIB, the @file{implcat} and the @file{sitecat}s. The associations in the other catalogs override those of the standard catalog. @item @code{library-vicinity} @file{mklibcat.scm} @cindex mklibcat.scm creates @file{slibcat}. @item @code{library-vicinity} @file{sitecat} @cindex sitecat This file contains the associations specific to an SLIB installation. @item @code{implementation-vicinity} @file{implcat} @cindex implcat This file contains the associations specific to an implementation of Scheme. Different implementations of Scheme should have different @code{implementation-vicinity}. @item @code{implementation-vicinity} @file{mkimpcat.scm} @cindex mkimpcat.scm if present, creates @file{implcat}. @item @code{implementation-vicinity} @file{sitecat} @cindex sitecat This file contains the associations specific to a Scheme implementation installation. @item @code{home-vicinity} @file{homecat} @cindex homecat This file contains the associations specific to an SLIB user. @item @code{user-vicinity} @file{usercat} @cindex usercat This file contains associations affecting only those sessions whose @dfn{working directory} is @code{user-vicinity}. @end table @noindent Here is an example of a @file{usercat} catalog. A program in this directory can invoke the @samp{run} feature with @code{(require 'run)}. @example ;;; "usercat": SLIB catalog additions for SIMSYNCH. -*-scheme-*- ( (simsynch . "../synch/simsynch.scm") (run . "../synch/run.scm") (schlep . "schlep.scm") ) @end example @noindent Copying @file{usercat} to many directories is inconvenient. Application programs which aren't always run in specially prepared directories can nonetheless register their features during initialization. @deffn {Procedure} catalog:read vicinity catalog Reads file named by string @var{catalog} in @var{vicinity}, resolving all paths relative to @var{vicinity}, and adds those feature associations to @var{*catalog*}. @code{catalog:read} would typically be used by an application program having dynamically loadable modules. For instance, to register factoring and other modules in @var{*catalog*}, JACAL does: @example (catalog:read (program-vicinity) "jacalcat") @end example @end deffn @noindent For an application program there are three appropriate venues for registering its catalog associations: @itemize @bullet @item in a @file{usercat} file in the directory where the program runs; or @item in an @file{implcat} file in the @code{implementation-vicinity}; or @item in an application program directory; loaded by calling @code{catalog:read}. @end itemize @node Compiling Scheme, , Catalog Vicinities, The Library System @section Compiling Scheme To use Scheme compilers effectively with SLIB the compiler needs to know which SLIB modules are to be compiled and which symbols are exported from those modules. The procedures in this section automate the extraction of this information from SLIB modules. They are guaranteed to work on SLIB modules; to use them on other sources, those sources should follow SLIB conventions. @menu * Module Conventions:: * Module Manifests:: * Module Semantics:: * Top-level Variable References:: * Module Analysis:: @end menu @node Module Conventions, Module Manifests, Compiling Scheme, Compiling Scheme @subsection Module Conventions @itemize @bullet @item All the top-level @code{require} commands have one quoted argument and are positioned before other Scheme definitions and expressions in the file. @item Any conditionally @code{require}d SLIB modules @footnote{There are some functions with internal @code{require} calls to delay loading modules until they are needed. While this reduces startup latency for interpreters, it can produce headaches for compilers.} also appear at the beginning of their files conditioned on the feature @cindex compiling @code{compiling} using @code{require-if} (@pxref{Require, require-if}). @example (require 'logical) (require 'multiarg/and-) (require-if 'compiling 'sort) (require-if 'compiling 'ciexyz) @end example @item Schmooz-style comments preceding a definition, identify that definition as an exported identifier (@pxref{Schmooz}). For non-schmooz files, putting @samp{;@@} at the beginning of the line immediately preceding the definition (@code{define}, @code{define-syntax}, or @code{defmacro}) suffices. @example ;@@ (define (identity ) ) @end example @item Syntax (macro) definitions are grouped at the end of a module file. @item Modules defining macros do not invoke those macros. SLIB macro implementations are exempt from this rule. An example of how to expand macro invocations is: @example (require 'macros-that-work) (require 'yasos) (require 'pprint-file) (pprint-filter-file "collect.scm" macwork:expand) @end example @end itemize @node Module Manifests, Module Semantics, Module Conventions, Compiling Scheme @subsection Module Manifests @include manifest.txi @node Module Semantics, Top-level Variable References, Module Manifests, Compiling Scheme @subsection Module Semantics For the purpose of compiling Scheme code, each top-level @code{require} makes the identifiers exported by its feature's module @code{defined} (or defmacroed or defined-syntaxed) within the file (being compiled) headed with those requires. Top-level occurrences of @code{require-if} make defined the exports from the module named by the second argument @emph{if} the @var{feature-expression} first argument is true in the target environment. The target feature @code{compiling} should be provided during this phase of compilation. Non-top-level SLIB occurences of @code{require} and @code{require-if} of quoted features can be ignored by compilers. The SLIB modules will all have top-level constructs for those features. @cindex aggregate Note that aggregate catalog entries import more than one module. Implementations of @code{require} may or may @emph{not} be transitive; code which uses module exports without requiring the providing module is in error. In the SLIB modules @code{modular}, @code{batch}, @code{hash}, @code{common-lisp-time}, @code{commutative-ring}, @code{charplot}, @code{logical}, @code{common-list-functions}, @code{coerce} and @code{break} there is code conditional on features being @code{provided?}. Most are testing for the presence of features which are intrinsic to implementations (inexacts, bignums, ...). In all cases these @code{provided?} tests can be evaluated at compile-time using @code{feature-eval} (@pxref{Feature, feature-eval}). The simplest way to compile these constructs may be to treat @code{provided?} as a macro. @node Top-level Variable References, Module Analysis, Module Semantics, Compiling Scheme @subsection Top-level Variable References @include top-refs.txi @node Module Analysis, , Top-level Variable References, Compiling Scheme @subsection Module Analysis @include vet.txi @node Universal SLIB Procedures, Scheme Syntax Extension Packages, The Library System, Top @chapter Universal SLIB Procedures @noindent The procedures described in these sections are supported by all implementations as part of the @samp{*.init} files or by @file{require.scm}. @menu * Vicinity:: Pathname Management * Configuration:: Characteristics of Scheme Implementation * Input/Output:: Things not provided by the Scheme specs. * System:: LOADing, EVALing, ERRORing, and EXITing * Miscellany:: @end menu @node Vicinity, Configuration, Universal SLIB Procedures, Universal SLIB Procedures @section Vicinity @noindent A vicinity is a descriptor for a place in the file system. Vicinities hide from the programmer the concepts of host, volume, directory, and version. Vicinities express only the concept of a file environment where a file name can be resolved to a file in a system independent manner. Vicinities can even be used on @dfn{flat} file systems (which have no directory structure) by having the vicinity express constraints on the file name. All of these procedures are file-system dependent. Use of these vicinity procedures can make programs file-system @emph{in}dependent. @noindent These procedures are provided by all implementations. On most systems a vicinity is a string. @defun make-vicinity dirpath Returns @var{dirpath} as a vicinity for use as first argument to @code{in-vicinity}. @end defun @defun pathname->vicinity path Returns the vicinity containing @var{path}. @example (pathname->vicinity "/usr/local/lib/scm/Link.scm") @result{} "/usr/local/lib/scm/" @end example @end defun @defun program-vicinity Returns the vicinity of the currently loading Scheme code. For an interpreter this would be the directory containing source code. For a compiled system (with multiple files) this would be the directory where the object or executable files are. If no file is currently loading, then the result is undefined. @strong{Warning:} @code{program-vicinity} can return incorrect values if your program escapes back into a @code{load} continuation. @end defun @defun library-vicinity Returns the vicinity of the shared Scheme library. @end defun @defun implementation-vicinity Returns the vicinity of the underlying Scheme implementation. This vicinity will likely contain startup code and messages and a compiler. @end defun @defun user-vicinity Returns the vicinity of the current directory of the user. On most systems this is @file{""} (the empty string). @end defun @defun home-vicinity Returns the vicinity of the user's @dfn{HOME} directory, the directory @cindex HOME which typically contains files which customize a computer environment for a user. If scheme is running without a user (eg. a daemon) or if this concept is meaningless for the platform, then @code{home-vicinity} returns @code{#f}. @end defun @c @defun scheme-file-suffix @c Returns the default filename suffix for scheme source files. On most @c systems this is @samp{.scm}. @c @end defun @defun vicinity:suffix? chr Returns the @samp{#t} if @var{chr} is a vicinity suffix character; and @code{#f} otherwise. Typical vicinity suffixes are @samp{/}, @samp{:}, and @samp{\}, @end defun @defun in-vicinity vicinity filename Returns a filename suitable for use by @code{slib:load}, @code{slib:load-source}, @code{slib:load-compiled}, @code{open-input-file}, @code{open-output-file}, etc. The returned filename is @var{filename} in @var{vicinity}. @code{in-vicinity} should allow @var{filename} to override @var{vicinity} when @var{filename} is an absolute pathname and @var{vicinity} is equal to the value of @code{(user-vicinity)}. The behavior of @code{in-vicinity} when @var{filename} is absolute and @var{vicinity} is not equal to the value of @code{(user-vicinity)} is unspecified. For most systems @code{in-vicinity} can be @code{string-append}. @end defun @defun sub-vicinity vicinity name Returns the vicinity of @var{vicinity} restricted to @var{name}. This is used for large systems where names of files in subsystems could conflict. On systems with directory structure @code{sub-vicinity} will return a pathname of the subdirectory @var{name} of @var{vicinity}. @end defun @defun with-load-pathname path thunk @var{path} should be a string naming a file being read or loaded. @code{with-load-pathname} evaluates @var{thunk} in a dynamic scope where an internal variable is bound to @var{path}; the internal variable is used for messages and @code{program-vicinity}. @code{with-load-pathname} returns the value returned by @var{thunk}. @end defun @node Configuration, Input/Output, Vicinity, Universal SLIB Procedures @section Configuration @noindent These constants and procedures describe characteristics of the Scheme and underlying operating system. They are provided by all implementations. @defvr Constant char-code-limit An integer 1 larger that the largest value which can be returned by @code{char->integer}. @end defvr @defvr Constant most-positive-fixnum In implementations which support integers of practically unlimited size, @var{most-positive-fixnum} is a large exact integer within the range of exact integers that may result from computing the length of a list, vector, or string. In implementations which do not support integers of practically unlimited size, @var{most-positive-fixnum} is the largest exact integer that may result from computing the length of a list, vector, or string. @end defvr @defvr Constant slib:tab The tab character. @end defvr @defvr Constant slib:form-feed The form-feed character. @end defvr @defun software-type Returns a symbol denoting the generic operating system type. For instance, @code{unix}, @code{vms}, @code{macos}, @code{amiga}, or @code{ms-dos}. @end defun @defun slib:report-version Displays the versions of SLIB and the underlying Scheme implementation and the name of the operating system. An unspecified value is returned. @example (slib:report-version) @result{} slib "@value{SLIBVERSION}" on scm "5b1" on unix @end example @end defun @defun slib:report Displays the information of @code{(slib:report-version)} followed by almost all the information neccessary for submitting a problem report. An unspecified value is returned. @defunx slib:report #t provides a more verbose listing. @defunx slib:report filename Writes the report to file @file{filename}. @example (slib:report) @result{} slib "@value{SLIBVERSION}" on scm "5b1" on unix (implementation-vicinity) is "/usr/local/lib/scm/" (library-vicinity) is "/usr/local/lib/slib/" (scheme-file-suffix) is ".scm" loaded slib:features : trace alist qp sort common-list-functions macro values getopt compiled implementation slib:features : bignum complex real rational inexact vicinity ed getenv tmpnam abort transcript with-file ieee-p1178 r4rs rev4-optional-procedures hash object-hash delay eval dynamic-wind multiarg-apply multiarg/and- logical defmacro string-port source current-time record rev3-procedures rev2-procedures sun-dl string-case array dump char-ready? full-continuation system implementation *catalog* : (i/o-extensions compiled "/usr/local/lib/scm/ioext.so") ... @end example @end defun @node Input/Output, System, Configuration, Universal SLIB Procedures @section Input/Output @noindent These procedures are provided by all implementations. @defun file-exists? filename Returns @code{#t} if the specified file exists. Otherwise, returns @code{#f}. If the underlying implementation does not support this feature then @code{#f} is always returned. @end defun @defun delete-file filename Deletes the file specified by @var{filename}. If @var{filename} can not be deleted, @code{#f} is returned. Otherwise, @code{#t} is returned. @end defun @defun open-file filename modes @var{filename} should be a string naming a file. @code{open-file} returns a port depending on the symbol @var{modes}: @table @r @item r an input port capable of delivering characters from the file. @item rb a @emph{binary} input port capable of delivering characters from the file. @item w an output port capable of writing characters to a new file by that name. @item wb a @emph{binary} output port capable of writing characters to a new file by that name. @end table If an implementation does not distinguish between binary and non-binary files, then it must treat @r{rb} as @r{r} and @r{wb} as @r{w}. If the file cannot be opened, either #f is returned or an error is signalled. For output, if a file with the given name already exists, the effect is unspecified. @end defun @defun port? obj Returns @t{#t} if @var{obj} is an input or output port, otherwise returns @t{#f}. @end defun @deffn {Procedure} close-port port Closes the file associated with @var{port}, rendering the @var{port} incapable of delivering or accepting characters. @code{close-file} has no effect if the file has already been closed. The value returned is unspecified. @end deffn @defun call-with-open-ports proc ports @dots{} @defunx call-with-open-ports ports @dots{} proc @var{Proc} should be a procedure that accepts as many arguments as there are @var{ports} passed to @code{call-with-open-ports}. @code{call-with-open-ports} calls @var{proc} with @var{ports} @dots{}. If @var{proc} returns, then the ports are closed automatically and the value yielded by the @var{proc} is returned. If @var{proc} does not return, then the ports will not be closed automatically unless it is possible to prove that the ports will never again be used for a read or write operation. @end defun @defun tmpnam Returns a pathname for a file which will likely not be used by any other process. Successive calls to @code{(tmpnam)} will return different pathnames. @end defun @defun current-error-port Returns the current port to which diagnostic and error output is directed. @end defun @deffn {Procedure} force-output @deffnx {Procedure} force-output port Forces any pending output on @var{port} to be delivered to the output device and returns an unspecified value. The @var{port} argument may be omitted, in which case it defaults to the value returned by @code{(current-output-port)}. @end deffn @defun file-position port @defunx file-position port #f @var{port} must be open to a file. @code{file-position} returns the current position of the character in @var{port} which will next be read or written. If the implementation does not support file-position, then @code{#f} is returned. @defunx file-position port k @var{port} must be open to a file. @code{file-position} sets the current position in @var{port} which will next be read or written. If successful, @code{#f} is returned; otherwise @code{file-position} returns @code{#f}. @end defun @defun output-port-width @defunx output-port-width port Returns the width of @var{port}, which defaults to @code{(current-output-port)} if absent. If the width cannot be determined 79 is returned. @end defun @defun output-port-height @defunx output-port-height port Returns the height of @var{port}, which defaults to @code{(current-output-port)} if absent. If the height cannot be determined 24 is returned. @end defun @node System, Miscellany, Input/Output, Universal SLIB Procedures @section System @noindent These procedures are provided by all implementations. @deffn {Procedure} slib:load-source name Loads a file of Scheme source code from @var{name} with the default filename extension used in SLIB. For instance if the filename extension used in SLIB is @file{.scm} then @code{(slib:load-source "foo")} will load from file @file{foo.scm}. @end deffn @deffn {Procedure} slib:load-compiled name On implementations which support separtely loadable compiled modules, loads a file of compiled code from @var{name} with the implementation's filename extension for compiled code appended. @end deffn @deffn {Procedure} slib:load name Loads a file of Scheme source or compiled code from @var{name} with the appropriate suffixes appended. If both source and compiled code are present with the appropriate names then the implementation will load just one. It is up to the implementation to choose which one will be loaded. If an implementation does not support compiled code then @code{slib:load} will be identical to @code{slib:load-source}. @end deffn @deffn {Procedure} slib:eval obj @code{eval} returns the value of @var{obj} evaluated in the current top level environment. @ref{Eval} provides a more general evaluation facility. @end deffn @deffn {Procedure} slib:eval-load filename eval @var{filename} should be a string. If filename names an existing file, the Scheme source code expressions and definitions are read from the file and @var{eval} called with them sequentially. The @code{slib:eval-load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end deffn @deffn {Procedure} slib:warn arg1 arg2 @dots{} Outputs a warning message containing the arguments. @end deffn @deffn {Procedure} slib:error arg1 arg2 @dots{} Outputs an error message containing the arguments, aborts evaluation of the current form and responds in a system dependent way to the error. Typical responses are to abort the program or to enter a read-eval-print loop. @end deffn @deffn {Procedure} slib:exit n @deffnx {Procedure} slib:exit Exits from the Scheme session returning status @var{n} to the system. If @var{n} is omitted or @code{#t}, a success status is returned to the system (if possible). If @var{n} is @code{#f} a failure is returned to the system (if possible). If @var{n} is an integer, then @var{n} is returned to the system (if possible). If the Scheme session cannot exit, then an unspecified value is returned from @code{slib:exit}. @end deffn @defun browse-url url Web browsers have become so ubiquitous that programming languagues should support a uniform interface to them. If a browser is running, @code{browse-url} causes the browser to display the page specified by string @var{url} and returns @code{#t}. If the browser is not running, @code{browse-url} starts a browser displaying the argument @var{url}. If the browser starts as a background job, @code{browse-url} returns @code{#t} immediately; if the browser starts as a foreground job, then @code{browse-url} returns @code{#t} when the browser exits; otherwise (if no browser) it returns @code{#f}. @end defun @node Miscellany, , System, Universal SLIB Procedures @section Miscellany These procedures are provided by all implementations. @defun identity x @var{identity} returns its argument. Example: @lisp (identity 3) @result{} 3 (identity '(foo bar)) @result{} (foo bar) (map identity @var{lst}) @equiv{} (copy-list @var{lst}) @end lisp @end defun @subsection Mutual Exclusion @noindent An @dfn{exchanger} is a procedure of one argument regulating mutually @cindex exchanger exclusive access to a resource. When a exchanger is called, its current content is returned, while being replaced by its argument in an atomic operation. @defun make-exchanger obj Returns a new exchanger with the argument @var{obj} as its initial content. @example (define queue (make-exchanger (list a))) @end example A queue implemented as an exchanger holding a list can be protected from reentrant execution thus: @example (define (pop queue) (let ((lst #f)) (dynamic-wind (lambda () (set! lst (queue #f))) (lambda () (and lst (not (null? lst)) (let ((ret (car lst))) (set! lst (cdr lst)) ret))) (lambda () (and lst (queue lst)))))) (pop queue) @result{} a (pop queue) @result{} #f @end example @end defun @subsection Legacy @noindent The following procedures were present in Scheme until R4RS (@pxref{Notes, , Language changes ,r4rs, Revised(4) Scheme}). They are provided by all SLIB implementations. @defvr Constant t Defined as @code{#t}. @end defvr @defvr Constant nil Defined as @code{#f}. @end defvr @defun last-pair l Returns the last pair in the list @var{l}. Example: @lisp (last-pair (cons 1 2)) @result{} (1 . 2) (last-pair '(1 2)) @result{} (2) @equiv{} (cons 2 '()) @end lisp @end defun @node Scheme Syntax Extension Packages, Textual Conversion Packages, Universal SLIB Procedures, Top @chapter Scheme Syntax Extension Packages @menu * Defmacro:: Supported by all implementations * R4RS Macros:: 'macro * Macro by Example:: 'macro-by-example * Macros That Work:: 'macros-that-work * Syntactic Closures:: 'syntactic-closures * Syntax-Case Macros:: 'syntax-case Syntax extensions (macros) included with SLIB. * Define-Structure:: 'structure * Define-Record-Type:: 'define-record-type, 'srfi-9 * Fluid-Let:: 'fluid-let * Binding to multiple values:: 'receive, 'srfi-8 * Guarded LET* special form:: 'and-let*, 'srfi-2 * Guarded COND Clause:: 'guarded-cond-clause, 'srfi-61 * Yasos:: 'yasos, 'oop, 'collect @end menu @node Defmacro, R4RS Macros, Scheme Syntax Extension Packages, Scheme Syntax Extension Packages @section Defmacro Defmacros are supported by all implementations. @c See also @code{gentemp}, in @ref{Macros}. @defun gentemp Returns a new (interned) symbol each time it is called. The symbol names are implementation-dependent @lisp (gentemp) @result{} scm:G0 (gentemp) @result{} scm:G1 @end lisp @end defun @defun defmacro:eval e Returns the @code{slib:eval} of expanding all defmacros in scheme expression @var{e}. @end defun @defun defmacro:load filename @var{filename} should be a string. If filename names an existing file, the @code{defmacro:load} procedure reads Scheme source code expressions and definitions from the file and evaluates them sequentially. These source code expressions and definitions may contain defmacro definitions. The @code{macro:load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end defun @defun defmacro? sym Returns @code{#t} if @var{sym} has been defined by @code{defmacro}, @code{#f} otherwise. @end defun @defun macroexpand-1 form @defunx macroexpand form If @var{form} is a macro call, @code{macroexpand-1} will expand the macro call once and return it. A @var{form} is considered to be a macro call only if it is a cons whose @code{car} is a symbol for which a @code{defmacro} has been defined. @code{macroexpand} is similar to @code{macroexpand-1}, but repeatedly expands @var{form} until it is no longer a macro call. @end defun @defmac defmacro name lambda-list form @dots{} When encountered by @code{defmacro:eval}, @code{defmacro:macroexpand*}, or @code{defmacro:load} defines a new macro which will henceforth be expanded when encountered by @code{defmacro:eval}, @code{defmacro:macroexpand*}, or @code{defmacro:load}. @end defmac @subsection Defmacroexpand @code{(require 'defmacroexpand)} @ftindex defmacroexpand @defun defmacro:expand* e Returns the result of expanding all defmacros in scheme expression @var{e}. @end defun @node R4RS Macros, Macro by Example, Defmacro, Scheme Syntax Extension Packages @section R4RS Macros @code{(require 'macro)} is the appropriate call if you want R4RS @ftindex macro high-level macros but don't care about the low level implementation. If an SLIB R4RS macro implementation is already loaded it will be used. Otherwise, one of the R4RS macros implemetations is loaded. The SLIB R4RS macro implementations support the following uniform interface: @defun macro:expand sexpression Takes an R4RS expression, macro-expands it, and returns the result of the macro expansion. @end defun @defun macro:eval sexpression Takes an R4RS expression, macro-expands it, evals the result of the macro expansion, and returns the result of the evaluation. @end defun @deffn {Procedure} macro:load filename @var{filename} should be a string. If filename names an existing file, the @code{macro:load} procedure reads Scheme source code expressions and definitions from the file and evaluates them sequentially. These source code expressions and definitions may contain macro definitions. The @code{macro:load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end deffn @node Macro by Example, Macros That Work, R4RS Macros, Scheme Syntax Extension Packages @section Macro by Example @code{(require 'macro-by-example)} @ftindex macro-by-example A vanilla implementation of @cite{Macro by Example} (Eugene Kohlbecker, R4RS) by Dorai Sitaram, (dorai @@ cs.rice.edu) using @code{defmacro}. @itemize @bullet @item generating hygienic global @code{define-syntax} Macro-by-Example macros @strong{cheaply}. @item can define macros which use @code{...}. @item needn't worry about a lexical variable in a macro definition clashing with a variable from the macro use context @item don't suffer the overhead of redefining the repl if @code{defmacro} natively supported (most implementations) @end itemize @subsection Caveat These macros are not referentially transparent (@pxref{Macros, , ,r4rs, Revised(4) Scheme}). Lexically scoped macros (i.e., @code{let-syntax} and @code{letrec-syntax}) are not supported. In any case, the problem of referential transparency gains poignancy only when @code{let-syntax} and @code{letrec-syntax} are used. So you will not be courting large-scale disaster unless you're using system-function names as local variables with unintuitive bindings that the macro can't use. However, if you must have the full @cite{r4rs} macro functionality, look to the more featureful (but also more expensive) versions of syntax-rules available in slib @ref{Macros That Work}, @ref{Syntactic Closures}, and @ref{Syntax-Case Macros}. @defmac define-syntax keyword transformer-spec The @var{keyword} is an identifier, and the @var{transformer-spec} should be an instance of @code{syntax-rules}. The top-level syntactic environment is extended by binding the @var{keyword} to the specified transformer. @example (define-syntax let* (syntax-rules () ((let* () body1 body2 ...) (let () body1 body2 ...)) ((let* ((name1 val1) (name2 val2) ...) body1 body2 ...) (let ((name1 val1)) (let* (( name2 val2) ...) body1 body2 ...))))) @end example @end defmac @defmac syntax-rules literals syntax-rule @dots{} @var{literals} is a list of identifiers, and each @var{syntax-rule} should be of the form @code{(@var{pattern} @var{template})} where the @var{pattern} and @var{template} are as in the grammar above. An instance of @code{syntax-rules} produces a new macro transformer by specifying a sequence of hygienic rewrite rules. A use of a macro whose keyword is associated with a transformer specified by @code{syntax-rules} is matched against the patterns contained in the @var{syntax-rule}s, beginning with the leftmost @var{syntax-rule}. When a match is found, the macro use is trancribed hygienically according to the template. Each pattern begins with the keyword for the macro. This keyword is not involved in the matching and is not considered a pattern variable or literal identifier. @end defmac @node Macros That Work, Syntactic Closures, Macro by Example, Scheme Syntax Extension Packages @section Macros That Work @code{(require 'macros-that-work)} @ftindex macros-that-work @cite{Macros That Work} differs from the other R4RS macro implementations in that it does not expand derived expression types to primitive expression types. @defun macro:expand expression @defunx macwork:expand expression Takes an R4RS expression, macro-expands it, and returns the result of the macro expansion. @end defun @defun macro:eval expression @defunx macwork:eval expression @code{macro:eval} returns the value of @var{expression} in the current top level environment. @var{expression} can contain macro definitions. Side effects of @var{expression} will affect the top level environment. @end defun @deffn {Procedure} macro:load filename @deffnx {Procedure} macwork:load filename @var{filename} should be a string. If filename names an existing file, the @code{macro:load} procedure reads Scheme source code expressions and definitions from the file and evaluates them sequentially. These source code expressions and definitions may contain macro definitions. The @code{macro:load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end deffn References: The @cite{Revised^4 Report on the Algorithmic Language Scheme} Clinger and Rees [editors]. To appear in LISP Pointers. Also available as a technical report from the University of Oregon, MIT AI Lab, and Cornell. @center Macros That Work. Clinger and Rees. POPL '91. The supported syntax differs from the R4RS in that vectors are allowed as patterns and as templates and are not allowed as pattern or template data. @example transformer spec @expansion{} (syntax-rules literals rules) rules @expansion{} () | (rule . rules) rule @expansion{} (pattern template) pattern @expansion{} pattern_var ; a symbol not in literals | symbol ; a symbol in literals | () | (pattern . pattern) | (ellipsis_pattern) | #(pattern*) ; extends R4RS | #(pattern* ellipsis_pattern) ; extends R4RS | pattern_datum template @expansion{} pattern_var | symbol | () | (template2 . template2) | #(template*) ; extends R4RS | pattern_datum template2 @expansion{} template | ellipsis_template pattern_datum @expansion{} string ; no vector | character | boolean | number ellipsis_pattern @expansion{} pattern ... ellipsis_template @expansion{} template ... pattern_var @expansion{} symbol ; not in literals literals @expansion{} () | (symbol . literals) @end example @subsection Definitions @table @asis @item Scope of an ellipsis Within a pattern or template, the scope of an ellipsis (@code{...}) is the pattern or template that appears to its left. @item Rank of a pattern variable The rank of a pattern variable is the number of ellipses within whose scope it appears in the pattern. @item Rank of a subtemplate The rank of a subtemplate is the number of ellipses within whose scope it appears in the template. @item Template rank of an occurrence of a pattern variable The template rank of an occurrence of a pattern variable within a template is the rank of that occurrence, viewed as a subtemplate. @item Variables bound by a pattern The variables bound by a pattern are the pattern variables that appear within it. @item Referenced variables of a subtemplate The referenced variables of a subtemplate are the pattern variables that appear within it. @item Variables opened by an ellipsis template The variables opened by an ellipsis template are the referenced pattern variables whose rank is greater than the rank of the ellipsis template. @end table @subsection Restrictions No pattern variable appears more than once within a pattern. For every occurrence of a pattern variable within a template, the template rank of the occurrence must be greater than or equal to the pattern variable's rank. Every ellipsis template must open at least one variable. For every ellipsis template, the variables opened by an ellipsis template must all be bound to sequences of the same length. The compiled form of a @var{rule} is @example rule @expansion{} (pattern template inserted) pattern @expansion{} pattern_var | symbol | () | (pattern . pattern) | ellipsis_pattern | #(pattern) | pattern_datum template @expansion{} pattern_var | symbol | () | (template2 . template2) | #(pattern) | pattern_datum template2 @expansion{} template | ellipsis_template pattern_datum @expansion{} string | character | boolean | number pattern_var @expansion{} #(V symbol rank) ellipsis_pattern @expansion{} #(E pattern pattern_vars) ellipsis_template @expansion{} #(E template pattern_vars) inserted @expansion{} () | (symbol . inserted) pattern_vars @expansion{} () | (pattern_var . pattern_vars) rank @expansion{} exact non-negative integer @end example where V and E are unforgeable values. The pattern variables associated with an ellipsis pattern are the variables bound by the pattern, and the pattern variables associated with an ellipsis template are the variables opened by the ellipsis template. If the template contains a big chunk that contains no pattern variables or inserted identifiers, then the big chunk will be copied unnecessarily. That shouldn't matter very often. @node Syntactic Closures, Syntax-Case Macros, Macros That Work, Scheme Syntax Extension Packages @section Syntactic Closures @code{(require 'syntactic-closures)} @ftindex syntactic-closures @defun macro:expand expression @defunx synclo:expand expression Returns scheme code with the macros and derived expression types of @var{expression} expanded to primitive expression types. @end defun @defun macro:eval expression @defunx synclo:eval expression @code{macro:eval} returns the value of @var{expression} in the current top level environment. @var{expression} can contain macro definitions. Side effects of @var{expression} will affect the top level environment. @end defun @deffn {Procedure} macro:load filename @deffnx {Procedure} synclo:load filename @var{filename} should be a string. If filename names an existing file, the @code{macro:load} procedure reads Scheme source code expressions and definitions from the file and evaluates them sequentially. These source code expressions and definitions may contain macro definitions. The @code{macro:load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end deffn @subsection Syntactic Closure Macro Facility @center A Syntactic Closures Macro Facility @center by Chris Hanson @center 9 November 1991 This document describes @dfn{syntactic closures}, a low-level macro facility for the Scheme programming language. The facility is an alternative to the low-level macro facility described in the @cite{Revised^4 Report on Scheme.} This document is an addendum to that report. The syntactic closures facility extends the BNF rule for @var{transformer spec} to allow a new keyword that introduces a low-level macro transformer: @example @var{transformer spec} := (transformer @var{expression}) @end example Additionally, the following procedures are added: @lisp make-syntactic-closure capture-syntactic-environment identifier? identifier=? @end lisp The description of the facility is divided into three parts. The first part defines basic terminology. The second part describes how macro transformers are defined. The third part describes the use of @dfn{identifiers}, which extend the syntactic closure mechanism to be compatible with @code{syntax-rules}. @subsubsection Terminology This section defines the concepts and data types used by the syntactic closures facility. @itemize @bullet @item @dfn{Forms} are the syntactic entities out of which programs are recursively constructed. A form is any expression, any definition, any syntactic keyword, or any syntactic closure. The variable name that appears in a @code{set!} special form is also a form. Examples of forms: @lisp 17 #t car (+ x 4) (lambda (x) x) (define pi 3.14159) if define @end lisp @item An @dfn{alias} is an alternate name for a given symbol. It can appear anywhere in a form that the symbol could be used, and when quoted it is replaced by the symbol; however, it does not satisfy the predicate @code{symbol?}. Macro transformers rarely distinguish symbols from aliases, referring to both as identifiers. @item A @dfn{syntactic} environment maps identifiers to their meanings. More precisely, it determines whether an identifier is a syntactic keyword or a variable. If it is a keyword, the meaning is an interpretation for the form in which that keyword appears. If it is a variable, the meaning identifies which binding of that variable is referenced. In short, syntactic environments contain all of the contextual information necessary for interpreting the meaning of a particular form. @item A @dfn{syntactic closure} consists of a form, a syntactic environment, and a list of identifiers. All identifiers in the form take their meaning from the syntactic environment, except those in the given list. The identifiers in the list are to have their meanings determined later. A syntactic closure may be used in any context in which its form could have been used. Since a syntactic closure is also a form, it may not be used in contexts where a form would be illegal. For example, a form may not appear as a clause in the cond special form. A syntactic closure appearing in a quoted structure is replaced by its form. @end itemize @subsubsection Transformer Definition This section describes the @code{transformer} special form and the procedures @code{make-syntactic-closure} and @code{capture-syntactic-environment}. @deffn Syntax transformer expression Syntax: It is an error if this syntax occurs except as a @var{transformer spec}. Semantics: The @var{expression} is evaluated in the standard transformer environment to yield a macro transformer as described below. This macro transformer is bound to a macro keyword by the special form in which the @code{transformer} expression appears (for example, @code{let-syntax}). A @dfn{macro transformer} is a procedure that takes two arguments, a form and a syntactic environment, and returns a new form. The first argument, the @dfn{input form}, is the form in which the macro keyword occurred. The second argument, the @dfn{usage environment}, is the syntactic environment in which the input form occurred. The result of the transformer, the @dfn{output form}, is automatically closed in the @dfn{transformer environment}, which is the syntactic environment in which the @code{transformer} expression occurred. For example, here is a definition of a push macro using @code{syntax-rules}: @lisp (define-syntax push (syntax-rules () ((push item list) (set! list (cons item list))))) @end lisp Here is an equivalent definition using @code{transformer}: @lisp (define-syntax push (transformer (lambda (exp env) (let ((item (make-syntactic-closure env '() (cadr exp))) (list (make-syntactic-closure env '() (caddr exp)))) `(set! ,list (cons ,item ,list)))))) @end lisp In this example, the identifiers @code{set!} and @code{cons} are closed in the transformer environment, and thus will not be affected by the meanings of those identifiers in the usage environment @code{env}. Some macros may be non-hygienic by design. For example, the following defines a loop macro that implicitly binds @code{exit} to an escape procedure. The binding of @code{exit} is intended to capture free references to @code{exit} in the body of the loop, so @code{exit} must be left free when the body is closed: @lisp (define-syntax loop (transformer (lambda (exp env) (let ((body (cdr exp))) `(call-with-current-continuation (lambda (exit) (let f () ,@@(map (lambda (exp) (make-syntactic-closure env '(exit) exp)) body) (f)))))))) @end lisp To assign meanings to the identifiers in a form, use @code{make-syntactic-closure} to close the form in a syntactic environment. @end deffn @defun make-syntactic-closure environment free-names form @var{environment} must be a syntactic environment, @var{free-names} must be a list of identifiers, and @var{form} must be a form. @code{make-syntactic-closure} constructs and returns a syntactic closure of @var{form} in @var{environment}, which can be used anywhere that @var{form} could have been used. All the identifiers used in @var{form}, except those explicitly excepted by @var{free-names}, obtain their meanings from @var{environment}. Here is an example where @var{free-names} is something other than the empty list. It is instructive to compare the use of @var{free-names} in this example with its use in the @code{loop} example above: the examples are similar except for the source of the identifier being left free. @lisp (define-syntax let1 (transformer (lambda (exp env) (let ((id (cadr exp)) (init (caddr exp)) (exp (cadddr exp))) `((lambda (,id) ,(make-syntactic-closure env (list id) exp)) ,(make-syntactic-closure env '() init)))))) @end lisp @code{let1} is a simplified version of @code{let} that only binds a single identifier, and whose body consists of a single expression. When the body expression is syntactically closed in its original syntactic environment, the identifier that is to be bound by @code{let1} must be left free, so that it can be properly captured by the @code{lambda} in the output form. To obtain a syntactic environment other than the usage environment, use @code{capture-syntactic-environment}. @end defun @defun capture-syntactic-environment procedure @code{capture-syntactic-environment} returns a form that will, when transformed, call @var{procedure} on the current syntactic environment. @var{procedure} should compute and return a new form to be transformed, in that same syntactic environment, in place of the form. An example will make this clear. Suppose we wanted to define a simple @code{loop-until} keyword equivalent to @lisp (define-syntax loop-until (syntax-rules () ((loop-until id init test return step) (letrec ((loop (lambda (id) (if test return (loop step))))) (loop init))))) @end lisp The following attempt at defining @code{loop-until} has a subtle bug: @lisp (define-syntax loop-until (transformer (lambda (exp env) (let ((id (cadr exp)) (init (caddr exp)) (test (cadddr exp)) (return (cadddr (cdr exp))) (step (cadddr (cddr exp))) (close (lambda (exp free) (make-syntactic-closure env free exp)))) `(letrec ((loop (lambda (,id) (if ,(close test (list id)) ,(close return (list id)) (loop ,(close step (list id))))))) (loop ,(close init '()))))))) @end lisp This definition appears to take all of the proper precautions to prevent unintended captures. It carefully closes the subexpressions in their original syntactic environment and it leaves the @code{id} identifier free in the @code{test}, @code{return}, and @code{step} expressions, so that it will be captured by the binding introduced by the @code{lambda} expression. Unfortunately it uses the identifiers @code{if} and @code{loop} within that @code{lambda} expression, so if the user of @code{loop-until} just happens to use, say, @code{if} for the identifier, it will be inadvertently captured. The syntactic environment that @code{if} and @code{loop} want to be exposed to is the one just outside the @code{lambda} expression: before the user's identifier is added to the syntactic environment, but after the identifier loop has been added. @code{capture-syntactic-environment} captures exactly that environment as follows: @lisp (define-syntax loop-until (transformer (lambda (exp env) (let ((id (cadr exp)) (init (caddr exp)) (test (cadddr exp)) (return (cadddr (cdr exp))) (step (cadddr (cddr exp))) (close (lambda (exp free) (make-syntactic-closure env free exp)))) `(letrec ((loop ,(capture-syntactic-environment (lambda (env) `(lambda (,id) (,(make-syntactic-closure env '() `if) ,(close test (list id)) ,(close return (list id)) (,(make-syntactic-closure env '() `loop) ,(close step (list id))))))))) (loop ,(close init '()))))))) @end lisp In this case, having captured the desired syntactic environment, it is convenient to construct syntactic closures of the identifiers @code{if} and the @code{loop} and use them in the body of the @code{lambda}. A common use of @code{capture-syntactic-environment} is to get the transformer environment of a macro transformer: @lisp (transformer (lambda (exp env) (capture-syntactic-environment (lambda (transformer-env) ...)))) @end lisp @end defun @subsubsection Identifiers This section describes the procedures that create and manipulate identifiers. Previous syntactic closure proposals did not have an identifier data type -- they just used symbols. The identifier data type extends the syntactic closures facility to be compatible with the high-level @code{syntax-rules} facility. As discussed earlier, an identifier is either a symbol or an @dfn{alias}. An alias is implemented as a syntactic closure whose @dfn{form} is an identifier: @lisp (make-syntactic-closure env '() 'a) @result{} an @dfn{alias} @end lisp Aliases are implemented as syntactic closures because they behave just like syntactic closures most of the time. The difference is that an alias may be bound to a new value (for example by @code{lambda} or @code{let-syntax}); other syntactic closures may not be used this way. If an alias is bound, then within the scope of that binding it is looked up in the syntactic environment just like any other identifier. Aliases are used in the implementation of the high-level facility @code{syntax-rules}. A macro transformer created by @code{syntax-rules} uses a template to generate its output form, substituting subforms of the input form into the template. In a syntactic closures implementation, all of the symbols in the template are replaced by aliases closed in the transformer environment, while the output form itself is closed in the usage environment. This guarantees that the macro transformation is hygienic, without requiring the transformer to know the syntactic roles of the substituted input subforms. @defun identifier? object Returns @code{#t} if @var{object} is an identifier, otherwise returns @code{#f}. Examples: @lisp (identifier? 'a) @result{} #t (identifier? (make-syntactic-closure env '() 'a)) @result{} #t (identifier? "a") @result{} #f (identifier? #\a) @result{} #f (identifier? 97) @result{} #f (identifier? #f) @result{} #f (identifier? '(a)) @result{} #f (identifier? '#(a)) @result{} #f @end lisp The predicate @code{eq?} is used to determine if two identifers are ``the same''. Thus @code{eq?} can be used to compare identifiers exactly as it would be used to compare symbols. Often, though, it is useful to know whether two identifiers ``mean the same thing''. For example, the @code{cond} macro uses the symbol @code{else} to identify the final clause in the conditional. A macro transformer for @code{cond} cannot just look for the symbol @code{else}, because the @code{cond} form might be the output of another macro transformer that replaced the symbol @code{else} with an alias. Instead the transformer must look for an identifier that ``means the same thing'' in the usage environment as the symbol @code{else} means in the transformer environment. @end defun @defun identifier=? environment1 identifier1 environment2 identifier2 @var{environment1} and @var{environment2} must be syntactic environments, and @var{identifier1} and @var{identifier2} must be identifiers. @code{identifier=?} returns @code{#t} if the meaning of @var{identifier1} in @var{environment1} is the same as that of @var{identifier2} in @var{environment2}, otherwise it returns @code{#f}. Examples: @lisp (let-syntax ((foo (transformer (lambda (form env) (capture-syntactic-environment (lambda (transformer-env) (identifier=? transformer-env 'x env 'x))))))) (list (foo) (let ((x 3)) (foo)))) @result{} (#t #f) @end lisp @lisp (let-syntax ((bar foo)) (let-syntax ((foo (transformer (lambda (form env) (capture-syntactic-environment (lambda (transformer-env) (identifier=? transformer-env 'foo env (cadr form)))))))) (list (foo foo) (foobar)))) @result{} (#f #t) @end lisp @end defun @subsubsection Acknowledgements The syntactic closures facility was invented by Alan Bawden and Jonathan Rees. The use of aliases to implement @code{syntax-rules} was invented by Alan Bawden (who prefers to call them @dfn{synthetic names}). Much of this proposal is derived from an earlier proposal by Alan Bawden. @node Syntax-Case Macros, Define-Structure, Syntactic Closures, Scheme Syntax Extension Packages @section Syntax-Case Macros @code{(require 'syntax-case)} @ftindex syntax-case @defun macro:expand expression @defunx syncase:expand expression Returns scheme code with the macros and derived expression types of @var{expression} expanded to primitive expression types. @end defun @defun macro:eval expression @defunx syncase:eval expression @code{macro:eval} returns the value of @var{expression} in the current top level environment. @var{expression} can contain macro definitions. Side effects of @var{expression} will affect the top level environment. @end defun @deffn {Procedure} macro:load filename @deffnx {Procedure} syncase:load filename @var{filename} should be a string. If filename names an existing file, the @code{macro:load} procedure reads Scheme source code expressions and definitions from the file and evaluates them sequentially. These source code expressions and definitions may contain macro definitions. The @code{macro:load} procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end deffn This is version 2.1 of @code{syntax-case}, the low-level macro facility proposed and implemented by Robert Hieb and R. Kent Dybvig. This version is further adapted by Harald Hanche-Olsen to make it compatible with, and easily usable with, SLIB. Mainly, these adaptations consisted of: @itemize @bullet @item Removing white space from @file{expand.pp} to save space in the distribution. This file is not meant for human readers anyway@dots{} @item Removed a couple of Chez scheme dependencies. @item Renamed global variables used to minimize the possibility of name conflicts. @item Adding an SLIB-specific initialization file. @item Removing a couple extra files, most notably the documentation (but see below). @end itemize If you wish, you can see exactly what changes were done by reading the shell script in the file @file{syncase.sh}. The two PostScript files were omitted in order to not burden the SLIB distribution with them. If you do intend to use @code{syntax-case}, however, you should get these files and print them out on a PostScript printer. They are available with the original @code{syntax-case} distribution by anonymous FTP in @file{cs.indiana.edu:/pub/scheme/syntax-case}. In order to use syntax-case from an interactive top level, execute: @lisp (require 'syntax-case) @ftindex syntax-case (require 'repl) @ftindex repl (repl:top-level macro:eval) @end lisp See the section Repl (@pxref{Repl}) for more information. To check operation of syntax-case get @file{cs.indiana.edu:/pub/scheme/syntax-case}, and type @lisp (require 'syntax-case) @ftindex syntax-case @findex syncase:sanity-check (syncase:sanity-check) @end lisp Beware that @code{syntax-case} takes a long time to load -- about 20s on a SPARCstation SLC (with SCM) and about 90s on a Macintosh SE/30 (with Gambit). @subsection Notes All R4RS syntactic forms are defined, including @code{delay}. Along with @code{delay} are simple definitions for @code{make-promise} (into which @code{delay} expressions expand) and @code{force}. @code{syntax-rules} and @code{with-syntax} (described in @cite{TR356}) are defined. @code{syntax-case} is actually defined as a macro that expands into calls to the procedure @code{syntax-dispatch} and the core form @code{syntax-lambda}; do not redefine these names. Several other top-level bindings not documented in TR356 are created: @itemize @bullet @item the ``hooks'' in @file{hooks.ss} @item the @code{build-} procedures in @file{output.ss} @item @code{expand-syntax} (the expander) @end itemize The syntax of define has been extended to allow @code{(define @var{id})}, which assigns @var{id} to some unspecified value. We have attempted to maintain R4RS compatibility where possible. The incompatibilities should be confined to @file{hooks.ss}. Please let us know if there is some incompatibility that is not flagged as such. Send bug reports, comments, suggestions, and questions to Kent Dybvig (dyb @@ iuvax.cs.indiana.edu). @node Define-Structure, Define-Record-Type, Syntax-Case Macros, Scheme Syntax Extension Packages @section Define-Structure @code{(require 'structure)} @noindent Included with the @code{syntax-case} files was @file{structure.scm} which defines a macro @code{define-structure}. Here is its documentation from Gambit 4.0: @deffn {special form} define-structure @var{name} @var{field}@dots{} Record data types similar to Pascal records and C @code{struct} types can be defined using the @code{define-structure} special form. The identifier @var{name} specifies the name of the new data type. The structure name is followed by @var{k} identifiers naming each field of the record. The @code{define-structure} expands into a set of definitions of the following procedures: @itemize @bullet{} @item `@t{make-}@var{name}' -- A @var{k} argument procedure which constructs a new record from the value of its @var{k} fields. @item `@var{name}@t{?}' -- A procedure which tests if its single argument is of the given record type. @item `@var{name}@t{-}@var{field}' -- For each field, a procedure taking as its single argument a value of the given record type and returning the content of the corresponding field of the record. @item `@var{name}@t{-}@var{field}@t{-set!}' -- For each field, a two argument procedure taking as its first argument a value of the given record type. The second argument gets assigned to the corresponding field of the record and the void object is returned. @end itemize Gambit record data types have a printed representation that includes the name of the type and the name and value of each field. For example: @smallexample > @b{(define-structure point x y color)} > @b{(define p (make-point 3 5 'red))} > @b{p} # > @b{(point-x p)} 3 > @b{(point-color p)} red > @b{(point-color-set! p 'black)} > @b{p} # @end smallexample @end deffn @node Define-Record-Type, Fluid-Let, Define-Structure, Scheme Syntax Extension Packages @section Define-Record-Type @code{(require 'define-record-type)} or @code{(require 'srfi-9)} @ftindex srfi-9 @ftindex define-record-type @url{http://srfi.schemers.org/srfi-9/srfi-9.html} @defspec define-record-type ( ...) ... Where @lisp @equiv{} ( ) @equiv{} ( ) @end lisp @code{define-record-type} is a syntax wrapper for the SLIB @code{record} module. @end defspec @node Fluid-Let, Binding to multiple values, Define-Record-Type, Scheme Syntax Extension Packages @section Fluid-Let @code{(require 'fluid-let)} @ftindex fluid-let @deffn Syntax fluid-let @code{(@var{bindings} @dots{})} @var{forms}@dots{} @end deffn @lisp (fluid-let ((@var{variable} @var{init}) @dots{}) @var{expression} @var{expression} @dots{}) @end lisp The @var{init}s are evaluated in the current environment (in some unspecified order), the current values of the @var{variable}s are saved, the results are assigned to the @var{variable}s, the @var{expression}s are evaluated sequentially in the current environment, the @var{variable}s are restored to their original values, and the value of the last @var{expression} is returned. The syntax of this special form is similar to that of @code{let}, but @code{fluid-let} temporarily rebinds existing @var{variable}s. Unlike @code{let}, @code{fluid-let} creates no new bindings; instead it @emph{assigns} the values of each @var{init} to the binding (determined by the rules of lexical scoping) of its corresponding @var{variable}. @node Binding to multiple values, Guarded LET* special form, Fluid-Let, Scheme Syntax Extension Packages @section Binding to multiple values @code{(require 'receive)} or @code{(require 'srfi-8)} @ftindex srfi-8 @ftindex receive @defspec receive formals expression body @dots{} @url{http://srfi.schemers.org/srfi-8/srfi-8.html} @end defspec @code{(require 'let-values)} or @code{(require 'srfi-11)} @ftindex srfi-11 @ftindex let-values @defspec let-values ((formals expression) ...) body @dots{} @defspecx let-values* ((formals expression) ...) body @dots{} @url{http://srfi.schemers.org/srfi-11/srfi-11.html} @end defspec @node Guarded LET* special form, Guarded COND Clause, Binding to multiple values, Scheme Syntax Extension Packages @section Guarded LET* special form @code{(require 'and-let*)} or @code{(require 'srfi-2)} @ftindex srfi-2 @ftindex and-let* @defmac and-let* claws body @dots{} @url{http://srfi.schemers.org/srfi-2/srfi-2.html} @end defmac @node Guarded COND Clause, Yasos, Guarded LET* special form, Scheme Syntax Extension Packages @section Guarded COND Clause @code{(require 'guarded-cond-clause)} or @code{(require 'srfi-61)} @ftindex srfi-61 @ftindex guarded-cond-clause @url{http://srfi.schemers.org/srfi-61/srfi-61.html} @deffn {library syntax} cond @dots{} @emph{Syntax:} Each @r{} should be of the form @format @t{(@r{} @r{} @dots{}) } @end format where @r{} is any expression. Alternatively, a @r{} may be of the form @format @t{(@r{} => @r{}) } @end format The @r{} production in the formal syntax of Scheme as written by R5RS in section 7.1.3 is extended with a new option: @cindex @w{=>} @format @t{@r{} => (@r{} @r{} => @r{}) } @end format where @r{}, @r{}, & @r{} are all @r{}s. @quotation Clauses of this form have the following semantics: @r{} is evaluated. It may return arbitrarily many values. @r{} is applied to an argument list containing the values in order that @r{} returned. If @r{} returns a true value for that argument list, @r{} is applied with an equivalent argument list. If @r{} returns a false value, however, the clause is abandoned and the next one is tried. @end quotation The last @r{} may be an ``else clause,'' which has the form @format @t{(else @r{} @r{} @dots{})@r{.} } @end format @end deffn @noindent This @code{port->char-list} procedure accepts an input port and returns a list of all the characters it produces until the end. @example (define (port->char-list port) (cond ((read-char port) char? => (lambda (c) (cons c (port->char-list port)))) (else '()))) (call-with-input-string "foo" port->char-list) ==> (#\f #\o #\o) @end example @node Yasos, , Guarded COND Clause, Scheme Syntax Extension Packages @section Yasos @c Much of the documentation in this section was written by Dave Love @c (d.love@dl.ac.uk) -- don't blame Ken Dickey for its faults. @c but we can blame him for not writing it! @code{(require 'oop)} or @code{(require 'yasos)} @ftindex oop @ftindex yasos `Yet Another Scheme Object System' is a simple object system for Scheme based on the paper by Norman Adams and Jonathan Rees: @cite{Object Oriented Programming in Scheme}, Proceedings of the 1988 ACM Conference on LISP and Functional Programming, July 1988 [ACM #552880]. Another reference is: Ken Dickey. @ifset html @end ifset Scheming with Objects @ifset html @end ifset @cite{AI Expert} Volume 7, Number 10 (October 1992), pp. 24-33. @menu * Yasos terms:: Definitions and disclaimer. * Yasos interface:: The Yasos macros and procedures. * Setters:: Dylan-like setters in Yasos. * Yasos examples:: Usage of Yasos and setters. @end menu @node Yasos terms, Yasos interface, Yasos, Yasos @subsection Terms @table @asis @item @dfn{Object} Any Scheme data object. @item @dfn{Instance} An instance of the OO system; an @dfn{object}. @item @dfn{Operation} A @var{method}. @end table @table @emph @item Notes: The object system supports multiple inheritance. An instance can inherit from 0 or more ancestors. In the case of multiple inherited operations with the same identity, the operation used is that from the first ancestor which contains it (in the ancestor @code{let}). An operation may be applied to any Scheme data object---not just instances. As code which creates instances is just code, there are no @dfn{classes} and no meta-@var{anything}. Method dispatch is by a procedure call a la CLOS rather than by @code{send} syntax a la Smalltalk. @item Disclaimer: There are a number of optimizations which can be made. This implementation is expository (although performance should be quite reasonable). See the L&FP paper for some suggestions. @end table @node Yasos interface, Setters, Yasos terms, Yasos @subsection Interface @deffn Syntax define-operation @code{(}opname self arg @dots{}@code{)} @var{default-body} Defines a default behavior for data objects which don't handle the operation @var{opname}. The default behavior (for an empty @var{default-body}) is to generate an error. @end deffn @deffn Syntax define-predicate opname? Defines a predicate @var{opname?}, usually used for determining the @dfn{type} of an object, such that @code{(@var{opname?} @var{object})} returns @code{#t} if @var{object} has an operation @var{opname?} and @code{#f} otherwise. @end deffn @deffn Syntax object @code{((@var{name} @var{self} @var{arg} @dots{}) @var{body})} @dots{} Returns an object (an instance of the object system) with operations. Invoking @code{(@var{name} @var{object} @var{arg} @dots{}} executes the @var{body} of the @var{object} with @var{self} bound to @var{object} and with argument(s) @var{arg}@dots{}. @end deffn @deffn Syntax object-with-ancestors @code{((}ancestor1 init1@code{)} @dots{}@code{)} operation @dots{} A @code{let}-like form of @code{object} for multiple inheritance. It returns an object inheriting the behaviour of @var{ancestor1} etc. An operation will be invoked in an ancestor if the object itself does not provide such a method. In the case of multiple inherited operations with the same identity, the operation used is the one found in the first ancestor in the ancestor list. @end deffn @deffn Syntax operate-as component operation self arg @dots{} Used in an operation definition (of @var{self}) to invoke the @var{operation} in an ancestor @var{component} but maintain the object's identity. Also known as ``send-to-super''. @end deffn @deffn {Procedure} print obj port A default @code{print} operation is provided which is just @code{(format @var{port} @var{obj})} (@pxref{Format}) for non-instances and prints @var{obj} preceded by @samp{#} for instances. @end deffn @defun size obj The default method returns the number of elements in @var{obj} if it is a vector, string or list, @code{2} for a pair, @code{1} for a character and by default id an error otherwise. Objects such as collections (@pxref{Collections}) may override the default in an obvious way. @end defun @node Setters, Yasos examples, Yasos interface, Yasos @subsection Setters @dfn{Setters} implement @dfn{generalized locations} for objects associated with some sort of mutable state. A @dfn{getter} operation retrieves a value from a generalized location and the corresponding setter operation stores a value into the location. Only the getter is named -- the setter is specified by a procedure call as below. (Dylan uses special syntax.) Typically, but not necessarily, getters are access operations to extract values from Yasos objects (@pxref{Yasos}). Several setters are predefined, corresponding to getters @code{car}, @code{cdr}, @code{string-ref} and @code{vector-ref} e.g., @code{(setter car)} is equivalent to @code{set-car!}. This implementation of setters is similar to that in Dylan(TM) (@cite{Dylan: An object-oriented dynamic language}, Apple Computer Eastern Research and Technology). Common LISP provides similar facilities through @code{setf}. @defun setter getter Returns the setter for the procedure @var{getter}. E.g., since @code{string-ref} is the getter corresponding to a setter which is actually @code{string-set!}: @example (define foo "foo") ((setter string-ref) foo 0 #\F) ; set element 0 of foo foo @result{} "Foo" @end example @end defun @deffn Syntax set place new-value If @var{place} is a variable name, @code{set} is equivalent to @code{set!}. Otherwise, @var{place} must have the form of a procedure call, where the procedure name refers to a getter and the call indicates an accessible generalized location, i.e., the call would return a value. The return value of @code{set} is usually unspecified unless used with a setter whose definition guarantees to return a useful value. @example (set (string-ref foo 2) #\O) ; generalized location with getter foo @result{} "FoO" (set foo "foo") ; like set! foo @result{} "foo" @end example @end deffn @deffn {Procedure} add-setter getter setter Add procedures @var{getter} and @var{setter} to the (inaccessible) list of valid setter/getter pairs. @var{setter} implements the store operation corresponding to the @var{getter} access operation for the relevant state. The return value is unspecified. @end deffn @deffn {Procedure} remove-setter-for getter Removes the setter corresponding to the specified @var{getter} from the list of valid setters. The return value is unspecified. @end deffn @deffn Syntax define-access-operation getter-name Shorthand for a Yasos @code{define-operation} defining an operation @var{getter-name} that objects may support to return the value of some mutable state. The default operation is to signal an error. The return value is unspecified. @end deffn @node Yasos examples, , Setters, Yasos @subsection Examples @lisp ;;; These definitions for PRINT and SIZE are ;;; already supplied by (require 'yasos) (define-operation (print obj port) (format port (if (instance? obj) "#" "~s") obj)) (define-operation (size obj) (cond ((vector? obj) (vector-length obj)) ((list? obj) (length obj)) ((pair? obj) 2) ((string? obj) (string-length obj)) ((char? obj) 1) (else (slib:error "Operation not supported: size" obj)))) (define-predicate cell?) (define-operation (fetch obj)) (define-operation (store! obj newValue)) (define (make-cell value) (object ((cell? self) #t) ((fetch self) value) ((store! self newValue) (set! value newValue) newValue) ((size self) 1) ((print self port) (format port "#" (fetch self))))) (define-operation (discard obj value) (format #t "Discarding ~s~%" value)) (define (make-filtered-cell value filter) (object-with-ancestors ((cell (make-cell value))) ((store! self newValue) (if (filter newValue) (store! cell newValue) (discard self newValue))))) (define-predicate array?) (define-operation (array-ref array index)) (define-operation (array-set! array index value)) (define (make-array num-slots) (let ((anArray (make-vector num-slots))) (object ((array? self) #t) ((size self) num-slots) ((array-ref self index) (vector-ref anArray index)) ((array-set! self index newValue) (vector-set! anArray index newValue)) ((print self port) (format port "#" (size self)))))) (define-operation (position obj)) (define-operation (discarded-value obj)) (define (make-cell-with-history value filter size) (let ((pos 0) (most-recent-discard #f)) (object-with-ancestors ((cell (make-filtered-call value filter)) (sequence (make-array size))) ((array? self) #f) ((position self) pos) ((store! self newValue) (operate-as cell store! self newValue) (array-set! self pos newValue) (set! pos (+ pos 1))) ((discard self value) (set! most-recent-discard value)) ((discarded-value self) most-recent-discard) ((print self port) (format port "#" (fetch self)))))) (define-access-operation fetch) (add-setter fetch store!) (define foo (make-cell 1)) (print foo #f) @result{} "#" (set (fetch foo) 2) @result{} (print foo #f) @result{} "#" (fetch foo) @result{} 2 @end lisp @node Textual Conversion Packages, Mathematical Packages, Scheme Syntax Extension Packages, Top @chapter Textual Conversion Packages @menu * Precedence Parsing:: * Format:: Common-Lisp Format * Standard Formatted I/O:: Posix printf and scanf * Programs and Arguments:: * HTML:: Generating * HTML Tables:: Databases meet HTML * HTTP and CGI:: Serve WWW sites * Parsing HTML:: 'html-for-each * URI:: Uniform Resource Identifier * Parsing XML:: 'parse-xml or 'ssax * Printing Scheme:: Nicely * Time and Date:: * NCBI-DNA:: DNA and protein sequences * Schmooz:: Documentation markup for Scheme programs @end menu @node Precedence Parsing, Format, Textual Conversion Packages, Textual Conversion Packages @section Precedence Parsing @code{(require 'precedence-parse)} or @code{(require 'parse)} @ftindex parse @ftindex precedence @noindent This package implements: @itemize @bullet @item a Pratt style precedence parser; @item a @dfn{tokenizer} which congeals tokens according to assigned classes of constituent characters; @item procedures giving direct control of parser rulesets; @item procedures for higher level specification of rulesets. @end itemize @menu * Precedence Parsing Overview:: * Rule Types:: * Ruleset Definition and Use:: * Token definition:: * Nud and Led Definition:: * Grammar Rule Definition:: @end menu @node Precedence Parsing Overview, Rule Types, Precedence Parsing, Precedence Parsing @subsection Precedence Parsing Overview @noindent This package offers improvements over previous parsers. @itemize @bullet @item Common computer language constructs are concisely specified. @item Grammars can be changed dynamically. Operators can be assigned different meanings within a lexical context. @item Rulesets don't need compilation. Grammars can be changed incrementally. @item Operator precedence is specified by integers. @item All possibilities of bad input are handled @footnote{How do I know this? I parsed 250kbyte of random input (an e-mail file) with a non-trivial grammar utilizing all constructs.} and return as much structure as was parsed when the error occured; The symbol @code{?} is substituted for missing input. @end itemize @noindent @cindex binding power The notion of @dfn{binding power} may be unfamiliar to those accustomed to BNF grammars. @noindent When two consecutive objects are parsed, the first might be the prefix to the second, or the second might be a suffix of the first. Comparing the left and right binding powers of the two objects decides which way to interpret them. @noindent Objects at each level of syntactic grouping have binding powers. @noindent @cindex syntax tree A syntax tree is not built unless the rules explicitly do so. The call graph of grammar rules effectively instantiate the sytnax tree. @noindent The JACAL symbolic math system (@url{http://swiss.csail.mit.edu/~jaffer/JACAL}) uses @t{precedence-parse}. Its grammar definitions in the file @file{jacal/English.scm} can serve as examples of use. @node Rule Types, Ruleset Definition and Use, Precedence Parsing Overview, Precedence Parsing @subsection Rule Types @noindent Here are the higher-level syntax types and an example of each. Precedence considerations are omitted for clarity. See @ref{Grammar Rule Definition} for full details. @deftp Grammar nofix bye exit @example bye @end example calls the function @code{exit} with no arguments. @end deftp @deftp Grammar prefix - negate @example - 42 @end example Calls the function @code{negate} with the argument @code{42}. @end deftp @deftp Grammar infix - difference @example x - y @end example Calls the function @code{difference} with arguments @code{x} and @code{y}. @end deftp @deftp Grammar nary + sum @example x + y + z @end example Calls the function @code{sum} with arguments @code{x}, @code{y}, and @code{y}. @end deftp @deftp Grammar postfix ! factorial @example 5 ! @end example Calls the function @code{factorial} with the argument @code{5}. @end deftp @deftp Grammar prestfix set set! @example set foo bar @end example Calls the function @code{set!} with the arguments @code{foo} and @code{bar}. @end deftp @deftp Grammar commentfix /* */ @example /* almost any text here */ @end example Ignores the comment delimited by @code{/*} and @code{*/}. @end deftp @deftp Grammar matchfix @{ list @} @example @{0, 1, 2@} @end example Calls the function @code{list} with the arguments @code{0}, @code{1}, and @code{2}. @end deftp @deftp Grammar inmatchfix ( funcall ) @example f(x, y) @end example Calls the function @code{funcall} with the arguments @code{f}, @code{x}, and @code{y}. @end deftp @deftp Grammar delim ; @example set foo bar; @end example delimits the extent of the restfix operator @code{set}. @end deftp @node Ruleset Definition and Use, Token definition, Rule Types, Precedence Parsing @subsection Ruleset Definition and Use @defvar *syn-defs* A grammar is built by one or more calls to @code{prec:define-grammar}. The rules are appended to @var{*syn-defs*}. The value of @var{*syn-defs*} is the grammar suitable for passing as an argument to @code{prec:parse}. @end defvar @defvr Constant *syn-ignore-whitespace* Is a nearly empty grammar with whitespace characters set to group 0, which means they will not be made into tokens. Most rulesets will want to start with @code{*syn-ignore-whitespace*} @end defvr @noindent In order to start defining a grammar, either @example (set! *syn-defs* '()) @end example @noindent or @example (set! *syn-defs* *syn-ignore-whitespace*) @end example @defun prec:define-grammar rule1 @dots{} Appends @var{rule1} @dots{} to @var{*syn-defs*}. @code{prec:define-grammar} is used to define both the character classes and rules for tokens. @end defun @noindent Once your grammar is defined, save the value of @code{*syn-defs*} in a variable (for use when calling @code{prec:parse}). @example (define my-ruleset *syn-defs*) @end example @defun prec:parse ruleset delim @defunx prec:parse ruleset delim port The @var{ruleset} argument must be a list of rules as constructed by @code{prec:define-grammar} and extracted from @var{*syn-defs*}. The token @var{delim} may be a character, symbol, or string. A character @var{delim} argument will match only a character token; i.e. a character for which no token-group is assigned. A symbol or string will match only a token string; i.e. a token resulting from a token group. @code{prec:parse} reads a @var{ruleset} grammar expression delimited by @var{delim} from the given input @var{port}. @code{prec:parse} returns the next object parsable from the given input @var{port}, updating @var{port} to point to the first character past the end of the external representation of the object. If an end of file is encountered in the input before any characters are found that can begin an object, then an end of file object is returned. If a delimiter (such as @var{delim}) is found before any characters are found that can begin an object, then @code{#f} is returned. The @var{port} argument may be omitted, in which case it defaults to the value returned by @code{current-input-port}. It is an error to parse from a closed port. @findex current-input-port @end defun @node Token definition, Nud and Led Definition, Ruleset Definition and Use, Precedence Parsing @subsection Token definition @defun tok:char-group group chars chars-proc The argument @var{chars} may be a single character, a list of characters, or a string. Each character in @var{chars} is treated as though @code{tok:char-group} was called with that character alone. The argument @var{chars-proc} must be a procedure of one argument, a list of characters. After @code{tokenize} has finished accumulating the characters for a token, it calls @var{chars-proc} with the list of characters. The value returned is the token which @code{tokenize} returns. The argument @var{group} may be an exact integer or a procedure of one character argument. The following discussion concerns the treatment which the tokenizing routine, @code{tokenize}, will accord to characters on the basis of their groups. When @var{group} is a non-zero integer, characters whose group number is equal to or exactly one less than @var{group} will continue to accumulate. Any other character causes the accumulation to stop (until a new token is to be read). The @var{group} of zero is special. These characters are ignored when parsed pending a token, and stop the accumulation of token characters when the accumulation has already begun. Whitespace characters are usually put in group 0. If @var{group} is a procedure, then, when triggerd by the occurence of an initial (no accumulation) @var{chars} character, this procedure will be repeatedly called with each successive character from the input stream until the @var{group} procedure returns a non-false value. @end defun @noindent The following convenient constants are provided for use with @code{tok:char-group}. @defvr Constant tok:decimal-digits Is the string @code{"0123456789"}. @end defvr @defvr Constant tok:upper-case Is the string consisting of all upper-case letters ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"). @end defvr @defvr Constant tok:lower-case Is the string consisting of all lower-case letters ("abcdefghijklmnopqrstuvwxyz"). @end defvr @defvr Constant tok:whitespaces Is the string consisting of all characters between 0 and 255 for which @code{char-whitespace?} returns true. @end defvr @noindent For the purpose of reporting problems in error messages, this package keeps track of the @dfn{current column}. When the column does not simply track input characters, @code{tok:bump-column} can be used to adjust the current-column. @defun tok:bump-column pos port Adds @var{pos} to the current-column for input-port @var{port}. @end defun @node Nud and Led Definition, Grammar Rule Definition, Token definition, Precedence Parsing @subsection Nud and Led Definition This section describes advanced features. You can skip this section on first reading. @noindent The @dfn{Null Denotation} (or @dfn{nud}) @cindex Null Denotation, nud of a token is the procedure and arguments applying for that token when @dfn{Left}, an unclaimed parsed expression is not extant. @noindent The @dfn{Left Denotation} (or @dfn{led}) @cindex Left Denotation, led of a token is the procedure, arguments, and lbp applying for that token when there is a @dfn{Left}, an unclaimed parsed expression. @noindent In his paper, @quotation Pratt, V. R. Top Down Operator Precendence. @cite{SIGACT/SIGPLAN Symposium on Principles of Programming Languages}, Boston, 1973, pages 41-51 @end quotation the @dfn{left binding power} (or @dfn{lbp}) was an independent property of tokens. I think this was done in order to allow tokens with NUDs but not LEDs to also be used as delimiters, which was a problem for statically defined syntaxes. It turns out that @emph{dynamically binding} NUDs and LEDs allows them independence. @noindent For the rule-defining procedures that follow, the variable @var{tk} may be a character, string, or symbol, or a list composed of characters, strings, and symbols. Each element of @var{tk} is treated as though the procedure were called for each element. @noindent Character @var{tk} arguments will match only character tokens; i.e. characters for which no token-group is assigned. Symbols and strings will both match token strings; i.e. tokens resulting from token groups. @defun prec:make-nud tk sop arg1 @dots{} Returns a rule specifying that @var{sop} be called when @var{tk} is parsed. If @var{sop} is a procedure, it is called with @var{tk} and @var{arg1} @dots{} as its arguments; the resulting value is incorporated into the expression being built. Otherwise, @code{(list @var{sop} @var{arg1} @dots{})} is incorporated. @end defun @noindent If no NUD has been defined for a token; then if that token is a string, it is converted to a symbol and returned; if not a string, the token is returned. @defun prec:make-led tk sop arg1 @dots{} Returns a rule specifying that @var{sop} be called when @var{tk} is parsed and @var{left} has an unclaimed parsed expression. If @var{sop} is a procedure, it is called with @var{left}, @var{tk}, and @var{arg1} @dots{} as its arguments; the resulting value is incorporated into the expression being built. Otherwise, @var{left} is incorporated. @end defun @noindent If no LED has been defined for a token, and @var{left} is set, the parser issues a warning. @node Grammar Rule Definition, , Nud and Led Definition, Precedence Parsing @subsection Grammar Rule Definition @noindent Here are procedures for defining rules for the syntax types introduced in @ref{Precedence Parsing Overview}. @noindent For the rule-defining procedures that follow, the variable @var{tk} may be a character, string, or symbol, or a list composed of characters, strings, and symbols. Each element of @var{tk} is treated as though the procedure were called for each element. @noindent For procedures prec:delim, @dots{}, prec:prestfix, if the @var{sop} argument is @code{#f}, then the token which triggered this rule is converted to a symbol and returned. A false @var{sop} argument to the procedures prec:commentfix, prec:matchfix, or prec:inmatchfix has a different meaning. @noindent Character @var{tk} arguments will match only character tokens; i.e. characters for which no token-group is assigned. Symbols and strings will both match token strings; i.e. tokens resulting from token groups. @defun prec:delim tk Returns a rule specifying that @var{tk} should not be returned from parsing; i.e. @var{tk}'s function is purely syntactic. The end-of-file is always treated as a delimiter. @end defun @defun prec:nofix tk sop Returns a rule specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item If @var{sop} is a procedure, it is called with no arguments; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop} is incorporated. @end itemize @end defun @defun prec:prefix tk sop bp rule1 @dots{} Returns a rule specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item @code{prec:parse1} is called with binding-power @var{bp}. @item If @var{sop} is a procedure, it is called with the expression returned from @code{prec:parse1}; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop} and the expression returned from @code{prec:parse1} is incorporated. @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize @end defun @defun prec:infix tk sop lbp bp rule1 @dots{} Returns a rule declaring the left-binding-precedence of the token @var{tk} is @var{lbp} and specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item One expression is parsed with binding-power @var{lbp}. If instead a delimiter is encountered, a warning is issued. @item If @var{sop} is a procedure, it is applied to the list of @var{left} and the parsed expression; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop}, the @var{left} expression, and the parsed expression is incorporated. @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize @end defun @defun prec:nary tk sop bp Returns a rule declaring the left-binding-precedence of the token @var{tk} is @var{bp} and specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item Expressions are parsed with binding-power @var{bp} as far as they are interleaved with the token @var{tk}. @item If @var{sop} is a procedure, it is applied to the list of @var{left} and the parsed expressions; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop}, the @var{left} expression, and the parsed expressions is incorporated. @end itemize @end defun @defun prec:postfix tk sop lbp Returns a rule declaring the left-binding-precedence of the token @var{tk} is @var{lbp} and specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item If @var{sop} is a procedure, it is called with the @var{left} expression; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop} and the @var{left} expression is incorporated. @end itemize @end defun @defun prec:prestfix tk sop bp rule1 @dots{} Returns a rule specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item Expressions are parsed with binding-power @var{bp} until a delimiter is reached. @item If @var{sop} is a procedure, it is applied to the list of parsed expressions; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop} and the parsed expressions is incorporated. @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize @end defun @defun prec:commentfix tk stp match rule1 @dots{} Returns rules specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item Characters are read until and end-of-file or a sequence of characters is read which matches the @emph{string} @var{match}. @item If @var{stp} is a procedure, it is called with the string of all that was read between the @var{tk} and @var{match} (exclusive). @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize Parsing of commentfix syntax differs from the others in several ways. It reads directly from input without tokenizing; It calls @var{stp} but does not return its value; nay any value. I added the @var{stp} argument so that comment text could be echoed. @end defun @defun prec:matchfix tk sop sep match rule1 @dots{} Returns a rule specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item A rule declaring the token @var{match} a delimiter takes effect. @item Expressions are parsed with binding-power @code{0} until the token @var{match} is reached. If the token @var{sep} does not appear between each pair of expressions parsed, a warning is issued. @item If @var{sop} is a procedure, it is applied to the list of parsed expressions; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop} and the parsed expressions is incorporated. @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize @end defun @defun prec:inmatchfix tk sop sep match lbp rule1 @dots{} Returns a rule declaring the left-binding-precedence of the token @var{tk} is @var{lbp} and specifying the following actions take place when @var{tk} is parsed: @itemize @bullet @item The rules @var{rule1} @dots{} augment and, in case of conflict, override rules currently in effect. @item A rule declaring the token @var{match} a delimiter takes effect. @item Expressions are parsed with binding-power @code{0} until the token @var{match} is reached. If the token @var{sep} does not appear between each pair of expressions parsed, a warning is issued. @item If @var{sop} is a procedure, it is applied to the list of @var{left} and the parsed expressions; the resulting value is incorporated into the expression being built. Otherwise, the list of @var{sop}, the @var{left} expression, and the parsed expressions is incorporated. @item The ruleset in effect before @var{tk} was parsed is restored; @var{rule1} @dots{} are forgotten. @end itemize @end defun @node Format, Standard Formatted I/O, Precedence Parsing, Textual Conversion Packages @section Format (version 3.1) @ifset html @end ifset @code{(require 'format)} or @code{(require 'srfi-28)} @ftindex format @c The @file{format.scm} package was removed because it was not @c reentrant. @url{http://swiss.csail.mit.edu/~jaffer/SLIB.FAQ} explains @c more about FORMAT's woes. @include format.texi @node Standard Formatted I/O, Programs and Arguments, Format, Textual Conversion Packages @section Standard Formatted I/O @menu * Standard Formatted Output:: 'printf * Standard Formatted Input:: 'scanf @end menu @subsection stdio @code{(require 'stdio)} @ftindex stdio @code{require}s @code{printf} and @code{scanf} and additionally defines the symbols: @defvar stdin Defined to be @code{(current-input-port)}. @end defvar @defvar stdout Defined to be @code{(current-output-port)}. @end defvar @defvar stderr Defined to be @code{(current-error-port)}. @end defvar @node Standard Formatted Output, Standard Formatted Input, Standard Formatted I/O, Standard Formatted I/O @subsection Standard Formatted Output @ifset html @end ifset @code{(require 'printf)} @ftindex printf @deffn {Procedure} printf format arg1 @dots{} @deffnx {Procedure} fprintf port format arg1 @dots{} @deffnx {Procedure} sprintf str format arg1 @dots{} @deffnx {Procedure} sprintf #f format arg1 @dots{} @deffnx {Procedure} sprintf k format arg1 @dots{} Each function converts, formats, and outputs its @var{arg1} @dots{} arguments according to the control string @var{format} argument and returns the number of characters output. @code{printf} sends its output to the port @code{(current-output-port)}. @code{fprintf} sends its output to the port @var{port}. @code{sprintf} @code{string-set!}s locations of the non-constant string argument @var{str} to the output characters. Two extensions of @code{sprintf} return new strings. If the first argument is @code{#f}, then the returned string's length is as many characters as specified by the @var{format} and data; if the first argument is a non-negative integer @var{k}, then the length of the returned string is also bounded by @var{k}. The string @var{format} contains plain characters which are copied to the output stream, and conversion specifications, each of which results in fetching zero or more of the arguments @var{arg1} @dots{}. The results are undefined if there are an insufficient number of arguments for the format. If @var{format} is exhausted while some of the @var{arg1} @dots{} arguments remain unused, the excess @var{arg1} @dots{} arguments are ignored. The conversion specifications in a format string have the form: @example % @r{[} @var{flags} @r{]} @r{[} @var{width} @r{]} @r{[} . @var{precision} @r{]} @r{[} @var{type} @r{]} @var{conversion} @end example An output conversion specifications consist of an initial @samp{%} character followed in sequence by: @itemize @bullet @item Zero or more @dfn{flag characters} that modify the normal behavior of the conversion specification. @table @asis @item @samp{-} Left-justify the result in the field. Normally the result is right-justified. @item @samp{+} For the signed @samp{%d} and @samp{%i} conversions and all inexact conversions, prefix a plus sign if the value is positive. @item @samp{ } For the signed @samp{%d} and @samp{%i} conversions, if the result doesn't start with a plus or minus sign, prefix it with a space character instead. Since the @samp{+} flag ensures that the result includes a sign, this flag is ignored if both are specified. @item @samp{#} For inexact conversions, @samp{#} specifies that the result should always include a decimal point, even if no digits follow it. For the @samp{%g} and @samp{%G} conversions, this also forces trailing zeros after the decimal point to be printed where they would otherwise be elided. For the @samp{%o} conversion, force the leading digit to be @samp{0}, as if by increasing the precision. For @samp{%x} or @samp{%X}, prefix a leading @samp{0x} or @samp{0X} (respectively) to the result. This doesn't do anything useful for the @samp{%d}, @samp{%i}, or @samp{%u} conversions. Using this flag produces output which can be parsed by the @code{scanf} functions with the @samp{%i} conversion (@pxref{Standard Formatted Input}). @item @samp{0} Pad the field with zeros instead of spaces. The zeros are placed after any indication of sign or base. This flag is ignored if the @samp{-} flag is also specified, or if a precision is specified for an exact converson. @end table @item An optional decimal integer specifying the @dfn{minimum field width}. If the normal conversion produces fewer characters than this, the field is padded (with spaces or zeros per the @samp{0} flag) to the specified width. This is a @emph{minimum} width; if the normal conversion produces more characters than this, the field is @emph{not} truncated. @cindex minimum field width (@code{printf}) Alternatively, if the field width is @samp{*}, the next argument in the argument list (before the actual value to be printed) is used as the field width. The width value must be an integer. If the value is negative it is as though the @samp{-} flag is set (see above) and the absolute value is used as the field width. @item An optional @dfn{precision} to specify the number of digits to be written for numeric conversions and the maximum field width for string conversions. The precision is specified by a period (@samp{.}) followed optionally by a decimal integer (which defaults to zero if omitted). @cindex precision (@code{printf}) Alternatively, if the precision is @samp{.*}, the next argument in the argument list (before the actual value to be printed) is used as the precision. The value must be an integer, and is ignored if negative. If you specify @samp{*} for both the field width and precision, the field width argument precedes the precision argument. The @samp{.*} precision is an enhancement. C library versions may not accept this syntax. For the @samp{%f}, @samp{%e}, and @samp{%E} conversions, the precision specifies how many digits follow the decimal-point character. The default precision is @code{6}. If the precision is explicitly @code{0}, the decimal point character is suppressed. For the @samp{%g} and @samp{%G} conversions, the precision specifies how many significant digits to print. Significant digits are the first digit before the decimal point, and all the digits after it. If the precision is @code{0} or not specified for @samp{%g} or @samp{%G}, it is treated like a value of @code{1}. If the value being printed cannot be expressed accurately in the specified number of digits, the value is rounded to the nearest number that fits. For exact conversions, if a precision is supplied it specifies the minimum number of digits to appear; leading zeros are produced if necessary. If a precision is not supplied, the number is printed with as many digits as necessary. Converting an exact @samp{0} with an explicit precision of zero produces no characters. @item An optional one of @samp{l}, @samp{h} or @samp{L}, which is ignored for numeric conversions. It is an error to specify these modifiers for non-numeric conversions. @item A character that specifies the conversion to be applied. @end itemize @subsubsection Exact Conversions @table @asis @item @samp{b}, @samp{B} Print an integer as an unsigned binary number. @emph{Note:} @samp{%b} and @samp{%B} are SLIB extensions. @item @samp{d}, @samp{i} Print an integer as a signed decimal number. @samp{%d} and @samp{%i} are synonymous for output, but are different when used with @code{scanf} for input (@pxref{Standard Formatted Input}). @item @samp{o} Print an integer as an unsigned octal number. @item @samp{u} Print an integer as an unsigned decimal number. @item @samp{x}, @samp{X} Print an integer as an unsigned hexadecimal number. @samp{%x} prints using the digits @samp{0123456789abcdef}. @samp{%X} prints using the digits @samp{0123456789ABCDEF}. @end table @subsubsection Inexact Conversions @table @asis @item @samp{f} Print a floating-point number in fixed-point notation. @item @samp{e}, @samp{E} Print a floating-point number in exponential notation. @samp{%e} prints @samp{e} between mantissa and exponont. @samp{%E} prints @samp{E} between mantissa and exponont. @item @samp{g}, @samp{G} Print a floating-point number in either fixed or exponential notation, whichever is more appropriate for its magnitude. Unless an @samp{#} flag has been supplied, trailing zeros after a decimal point will be stripped off. @samp{%g} prints @samp{e} between mantissa and exponont. @samp{%G} prints @samp{E} between mantissa and exponent. @item @samp{k}, @samp{K} Print a number like @samp{%g}, except that an SI prefix is output after the number, which is scaled accordingly. @samp{%K} outputs a dot between number and prefix, @samp{%k} does not. @end table @subsubsection Other Conversions @table @asis @item @samp{c} Print a single character. The @samp{-} flag is the only one which can be specified. It is an error to specify a precision. @item @samp{s} Print a string. The @samp{-} flag is the only one which can be specified. A precision specifies the maximum number of characters to output; otherwise all characters in the string are output. @item @samp{a}, @samp{A} Print a scheme expression. The @samp{-} flag left-justifies the output. The @samp{#} flag specifies that strings and characters should be quoted as by @code{write} (which can be read using @code{read}); otherwise, output is as @code{display} prints. A precision specifies the maximum number of characters to output; otherwise as many characters as needed are output. @emph{Note:} @samp{%a} and @samp{%A} are SLIB extensions. @c @item @samp{p} @c Print the value of a pointer. @c @item @samp{n} @c Get the number of characters printed so far. See @ref{Other Output Conversions}. @c Note that this conversion specification never produces any output. @c @item @samp{m} @c Print the string corresponding to the value of @code{errno}. @c (This is a GNU extension.) @c @xref{Other Output Conversions}. @item @samp{%} Print a literal @samp{%} character. No argument is consumed. It is an error to specify flags, field width, precision, or type modifiers with @samp{%%}. @end table @end deffn @node Standard Formatted Input, , Standard Formatted Output, Standard Formatted I/O @subsection Standard Formatted Input @code{(require 'scanf)} @ftindex scanf @deffn Function scanf-read-list format @deffnx Function scanf-read-list format port @deffnx Function scanf-read-list format string @end deffn @defmac scanf format arg1 @dots{} @defmacx fscanf port format arg1 @dots{} @defmacx sscanf str format arg1 @dots{} Each function reads characters, interpreting them according to the control string @var{format} argument. @code{scanf-read-list} returns a list of the items specified as far as the input matches @var{format}. @code{scanf}, @code{fscanf}, and @code{sscanf} return the number of items successfully matched and stored. @code{scanf}, @code{fscanf}, and @code{sscanf} also set the location corresponding to @var{arg1} @dots{} using the methods: @table @asis @item symbol @code{set!} @item car expression @code{set-car!} @item cdr expression @code{set-cdr!} @item vector-ref expression @code{vector-set!} @item substring expression @code{substring-move-left!} @end table The argument to a @code{substring} expression in @var{arg1} @dots{} must be a non-constant string. Characters will be stored starting at the position specified by the second argument to @code{substring}. The number of characters stored will be limited by either the position specified by the third argument to @code{substring} or the length of the matched string, whichever is less. The control string, @var{format}, contains conversion specifications and other characters used to direct interpretation of input sequences. The control string contains: @itemize @bullet @item White-space characters (blanks, tabs, newlines, or formfeeds) that cause input to be read (and discarded) up to the next non-white-space character. @item An ordinary character (not @samp{%}) that must match the next character of the input stream. @item Conversion specifications, consisting of the character @samp{%}, an optional assignment suppressing character @samp{*}, an optional numerical maximum-field width, an optional @samp{l}, @samp{h} or @samp{L} which is ignored, and a conversion code. @c @item The conversion specification can alternatively be prefixed by @c the character sequence @samp{%n$} instead of the character @samp{%}, @c where @var{n} is a decimal integer in the range. The @samp{%n$} @c construction indicates that the value of the next input field should be @c placed in the @var{n}th place in the return list, rather than to the next @c unused one. The two forms of introducing a conversion specification, @c @samp{%} and @samp{%n$}, must not be mixed within a single format string @c with the following exception: Skip fields (see below) can be designated @c as @samp{%*} or @samp{%n$*}. In the latter case, @var{n} is ignored. @end itemize Unless the specification contains the @samp{n} conversion character (described below), a conversion specification directs the conversion of the next input field. The result of a conversion specification is returned in the position of the corresponding argument points, unless @samp{*} indicates assignment suppression. Assignment suppression provides a way to describe an input field to be skipped. An input field is defined as a string of characters; it extends to the next inappropriate character or until the field width, if specified, is exhausted. @quotation @emph{Note:} This specification of format strings differs from the @cite{ANSI C} and @cite{POSIX} specifications. In SLIB, white space before an input field is not skipped unless white space appears before the conversion specification in the format string. In order to write format strings which work identically with @cite{ANSI C} and SLIB, prepend whitespace to all conversion specifications except @samp{[} and @samp{c}. @end quotation The conversion code indicates the interpretation of the input field; For a suppressed field, no value is returned. The following conversion codes are legal: @table @asis @item @samp{%} A single % is expected in the input at this point; no value is returned. @item @samp{d}, @samp{D} A decimal integer is expected. @item @samp{u}, @samp{U} An unsigned decimal integer is expected. @item @samp{o}, @samp{O} An octal integer is expected. @item @samp{x}, @samp{X} A hexadecimal integer is expected. @item @samp{i} An integer is expected. Returns the value of the next input item, interpreted according to C conventions; a leading @samp{0} implies octal, a leading @samp{0x} implies hexadecimal; otherwise, decimal is assumed. @item @samp{n} Returns the total number of bytes (including white space) read by @code{scanf}. No input is consumed by @code{%n}. @item @samp{f}, @samp{F}, @samp{e}, @samp{E}, @samp{g}, @samp{G} A floating-point number is expected. The input format for floating-point numbers is an optionally signed string of digits, possibly containing a radix character @samp{.}, followed by an optional exponent field consisting of an @samp{E} or an @samp{e}, followed by an optional @samp{+}, @samp{-}, or space, followed by an integer. @item @samp{c}, @samp{C} @var{Width} characters are expected. The normal skip-over-white-space is suppressed in this case; to read the next non-space character, use @samp{%1s}. If a field width is given, a string is returned; up to the indicated number of characters is read. @item @samp{s}, @samp{S} A character string is expected The input field is terminated by a white-space character. @code{scanf} cannot read a null string. @item @samp{[} Indicates string data and the normal skip-over-leading-white-space is suppressed. The left bracket is followed by a set of characters, called the scanset, and a right bracket; the input field is the maximal sequence of input characters consisting entirely of characters in the scanset. @samp{^}, when it appears as the first character in the scanset, serves as a complement operator and redefines the scanset as the set of all characters not contained in the remainder of the scanset string. Construction of the scanset follows certain conventions. A range of characters may be represented by the construct first-last, enabling @samp{[0123456789]} to be expressed @samp{[0-9]}. Using this convention, first must be lexically less than or equal to last; otherwise, the dash stands for itself. The dash also stands for itself when it is the first or the last character in the scanset. To include the right square bracket as an element of the scanset, it must appear as the first character (possibly preceded by a @samp{^}) of the scanset, in which case it will not be interpreted syntactically as the closing bracket. At least one character must match for this conversion to succeed. @end table The @code{scanf} functions terminate their conversions at end-of-file, at the end of the control string, or when an input character conflicts with the control string. In the latter case, the offending character is left unread in the input stream. @end defmac @node Programs and Arguments, HTML, Standard Formatted I/O, Textual Conversion Packages @section Program and Arguments @menu * Getopt:: Command Line option parsing * Command Line:: A command line reader for Scheme shells * Parameter lists:: 'parameters * Getopt Parameter lists:: 'getopt-parameters * Filenames:: 'filename * Batch:: 'batch @end menu @node Getopt, Command Line, Programs and Arguments, Programs and Arguments @subsection Getopt @code{(require 'getopt)} @ftindex getopt This routine implements Posix command line argument parsing. Notice that returning values through global variables means that @code{getopt} is @emph{not} reentrant. Obedience to Posix format for the @code{getopt} calls sows confusion. Passing @var{argc} and @var{argv} as arguments while referencing @var{optind} as a global variable leads to strange behavior, especially when the calls to @code{getopt} are buried in other procedures. Even in C, @var{argc} can be derived from @var{argv}; what purpose does it serve beyond providing an opportunity for @var{argv}/@var{argc} mismatch? Just such a mismatch existed for years in a SLIB @code{getopt--} example. I have removed the @var{argc} and @var{argv} arguments to getopt procedures; and replaced them with a global variable: @defvar *argv* Define @var{*argv*} with a list of arguments before calling getopt procedures. If you don't want the first (0th) element to be ignored, set @var{*optind*} to 0 (after requiring getopt). @end defvar @defvar *optind* Is the index of the current element of the command line. It is initially one. In order to parse a new command line or reparse an old one, @var{*optind*} must be reset. @end defvar @defvar *optarg* Is set by getopt to the (string) option-argument of the current option. @end defvar @defun getopt optstring Returns the next option letter in @var{*argv*} (starting from @code{(vector-ref argv *optind*)}) that matches a letter in @var{optstring}. @var{*argv*} is a vector or list of strings, the 0th of which getopt usually ignores. @var{optstring} is a string of recognized option characters; if a character is followed by a colon, the option takes an argument which may be immediately following it in the string or in the next element of @var{*argv*}. @var{*optind*} is the index of the next element of the @var{*argv*} vector to be processed. It is initialized to 1 by @file{getopt.scm}, and @code{getopt} updates it when it finishes with each element of @var{*argv*}. @code{getopt} returns the next option character from @var{*argv*} that matches a character in @var{optstring}, if there is one that matches. If the option takes an argument, @code{getopt} sets the variable @var{*optarg*} to the option-argument as follows: @itemize @bullet @item If the option was the last character in the string pointed to by an element of @var{*argv*}, then @var{*optarg*} contains the next element of @var{*argv*}, and @var{*optind*} is incremented by 2. If the resulting value of @var{*optind*} is greater than or equal to @code{(length @var{*argv*})}, this indicates a missing option argument, and @code{getopt} returns an error indication. @item Otherwise, @var{*optarg*} is set to the string following the option character in that element of @var{*argv*}, and @var{*optind*} is incremented by 1. @end itemize If, when @code{getopt} is called, the string @code{(vector-ref argv *optind*)} either does not begin with the character @code{#\-} or is just @code{"-"}, @code{getopt} returns @code{#f} without changing @var{*optind*}. If @code{(vector-ref argv *optind*)} is the string @code{"--"}, @code{getopt} returns @code{#f} after incrementing @var{*optind*}. If @code{getopt} encounters an option character that is not contained in @var{optstring}, it returns the question-mark @code{#\?} character. If it detects a missing option argument, it returns the colon character @code{#\:} if the first character of @var{optstring} was a colon, or a question-mark character otherwise. In either case, @code{getopt} sets the variable @var{getopt:opt} to the option character that caused the error. The special option @code{"--"} can be used to delimit the end of the options; @code{#f} is returned, and @code{"--"} is skipped. RETURN VALUE @code{getopt} returns the next option character specified on the command line. A colon @code{#\:} is returned if @code{getopt} detects a missing argument and the first character of @var{optstring} was a colon @code{#\:}. A question-mark @code{#\?} is returned if @code{getopt} encounters an option character not in @var{optstring} or detects a missing argument and the first character of @var{optstring} was not a colon @code{#\:}. Otherwise, @code{getopt} returns @code{#f} when all command line options have been parsed. Example: @lisp #! /usr/local/bin/scm (require 'program-arguments) (require 'getopt) (define argv (program-arguments)) @ftindex getopt @ftindex program-arguments (define opts ":a:b:cd") (let loop ((opt (getopt (length argv) argv opts))) (case opt ((#\a) (print "option a: " *optarg*)) ((#\b) (print "option b: " *optarg*)) ((#\c) (print "option c")) ((#\d) (print "option d")) ((#\?) (print "error" getopt:opt)) ((#\:) (print "missing arg" getopt:opt)) ((#f) (if (< *optind* (length argv)) (print "argv[" *optind* "]=" (list-ref argv *optind*))) (set! *optind* (+ *optind* 1)))) (if (< *optind* (length argv)) (loop (getopt (length argv) argv opts)))) (slib:exit) @end lisp @end defun @subsection Getopt--- @defun @code{getopt--} optstring The procedure @code{getopt--} is an extended version of @code{getopt} which parses @dfn{long option names} of the form @samp{--hold-the-onions} and @samp{--verbosity-level=extreme}. @w{@code{Getopt--}} behaves as @code{getopt} except for non-empty options beginning with @samp{--}. Options beginning with @samp{--} are returned as strings rather than characters. If a value is assigned (using @samp{=}) to a long option, @code{*optarg*} is set to the value. The @samp{=} and value are not returned as part of the option string. No information is passed to @code{getopt--} concerning which long options should be accepted or whether such options can take arguments. If a long option did not have an argument, @code{*optarg*} will be set to @code{#f}. The caller is responsible for detecting and reporting errors. @example (define opts ":-:b:") (define *argv* '("foo" "-b9" "--f1" "--2=" "--g3=35234.342" "--")) (define *optind* 1) (define *optarg* #f) (require 'qp) @ftindex qp (do ((i 5 (+ -1 i))) ((zero? i)) (let ((opt (getopt-- opts))) (print *optind* opt *optarg*))) @print{} 2 #\b "9" 3 "f1" #f 4 "2" "" 5 "g3" "35234.342" 5 #f "35234.342" @end example @end defun @node Command Line, Parameter lists, Getopt, Programs and Arguments @subsection Command Line @include comparse.txi @node Parameter lists, Getopt Parameter lists, Command Line, Programs and Arguments @subsection Parameter lists @code{(require 'parameters)} @ftindex parameters @noindent Arguments to procedures in scheme are distinguished from each other by their position in the procedure call. This can be confusing when a procedure takes many arguments, many of which are not often used. @noindent A @dfn{parameter-list} is a way of passing named information to a procedure. Procedures are also defined to set unused parameters to default values, check parameters, and combine parameter lists. @noindent A @var{parameter} has the form @code{(@r{parameter-name} @r{value1} @dots{})}. This format allows for more than one value per parameter-name. @noindent A @var{parameter-list} is a list of @var{parameter}s, each with a different @var{parameter-name}. @deffn Function make-parameter-list parameter-names Returns an empty parameter-list with slots for @var{parameter-names}. @end deffn @deffn Function parameter-list-ref parameter-list parameter-name @var{parameter-name} must name a valid slot of @var{parameter-list}. @code{parameter-list-ref} returns the value of parameter @var{parameter-name} of @var{parameter-list}. @end deffn @deffn Function remove-parameter parameter-name parameter-list Removes the parameter @var{parameter-name} from @var{parameter-list}. @code{remove-parameter} does not alter the argument @var{parameter-list}. If there are more than one @var{parameter-name} parameters, an error is signaled. @end deffn @deffn {Procedure} adjoin-parameters! parameter-list parameter1 @dots{} Returns @var{parameter-list} with @var{parameter1} @dots{} merged in. @end deffn @deffn {Procedure} parameter-list-expand expanders parameter-list @var{expanders} is a list of procedures whose order matches the order of the @var{parameter-name}s in the call to @code{make-parameter-list} which created @var{parameter-list}. For each non-false element of @var{expanders} that procedure is mapped over the corresponding parameter value and the returned parameter lists are merged into @var{parameter-list}. This process is repeated until @var{parameter-list} stops growing. The value returned from @code{parameter-list-expand} is unspecified. @end deffn @deffn Function fill-empty-parameters defaulters parameter-list @var{defaulters} is a list of procedures whose order matches the order of the @var{parameter-name}s in the call to @code{make-parameter-list} which created @var{parameter-list}. @code{fill-empty-parameters} returns a new parameter-list with each empty parameter replaced with the list returned by calling the corresponding @var{defaulter} with @var{parameter-list} as its argument. @end deffn @deffn Function check-parameters checks parameter-list @var{checks} is a list of procedures whose order matches the order of the @var{parameter-name}s in the call to @code{make-parameter-list} which created @var{parameter-list}. @code{check-parameters} returns @var{parameter-list} if each @var{check} of the corresponding @var{parameter-list} returns non-false. If some @var{check} returns @code{#f} a warning is signaled. @end deffn @noindent In the following procedures @var{arities} is a list of symbols. The elements of @code{arities} can be: @table @code @item single Requires a single parameter. @item optional A single parameter or no parameter is acceptable. @item boolean A single boolean parameter or zero parameters is acceptable. @item nary Any number of parameters are acceptable. @item nary1 One or more of parameters are acceptable. @end table @deffn Function parameter-list->arglist positions arities parameter-list Returns @var{parameter-list} converted to an argument list. Parameters of @var{arity} type @code{single} and @code{boolean} are converted to the single value associated with them. The other @var{arity} types are converted to lists of the value(s). @var{positions} is a list of positive integers whose order matches the order of the @var{parameter-name}s in the call to @code{make-parameter-list} which created @var{parameter-list}. The integers specify in which argument position the corresponding parameter should appear. @end deffn @node Getopt Parameter lists, Filenames, Parameter lists, Programs and Arguments @subsection Getopt Parameter lists @include getparam.txi @node Filenames, Batch, Getopt Parameter lists, Programs and Arguments @subsection Filenames @ftindex glob @include glob.txi @node Batch, , Filenames, Programs and Arguments @subsection Batch @code{(require 'batch)} @ftindex batch @noindent The batch procedures provide a way to write and execute portable scripts for a variety of operating systems. Each @code{batch:} procedure takes as its first argument a parameter-list (@pxref{Parameter lists}). This parameter-list argument @var{parms} contains named associations. Batch currently uses 2 of these: @table @code @item batch-port The port on which to write lines of the batch file. @item batch-dialect The syntax of batch file to generate. Currently supported are: @itemize @bullet @item unix @item dos @item vms @item amigaos @item system @item *unknown* @end itemize @end table @noindent The @samp{batch} module uses 2 enhanced relational tables (@pxref{Using Databases}) to store information linking the names of @code{operating-system}s to @code{batch-dialect}es. @defun batch:initialize! database Defines @code{operating-system} and @code{batch-dialect} tables and adds the domain @code{operating-system} to the enhanced relational database @var{database}. @end defun @defvar *operating-system* Is batch's best guess as to which operating-system it is running under. @code{*operating-system*} is set to @code{(software-type)} (@pxref{Configuration}) unless @code{(software-type)} is @code{unix}, in which case finer distinctions are made. @end defvar @defun batch:call-with-output-script parms file proc @var{proc} should be a procedure of one argument. If @var{file} is an output-port, @code{batch:call-with-output-script} writes an appropriate header to @var{file} and then calls @var{proc} with @var{file} as the only argument. If @var{file} is a string, @code{batch:call-with-output-script} opens a output-file of name @var{file}, writes an appropriate header to @var{file}, and then calls @var{proc} with the newly opened port as the only argument. Otherwise, @code{batch:call-with-output-script} acts as if it was called with the result of @code{(current-output-port)} as its third argument. @end defun @noindent The rest of the @code{batch:} procedures write (or execute if @code{batch-dialect} is @code{system}) commands to the batch port which has been added to @var{parms} or @code{(copy-tree @var{parms})} by the code: @example (adjoin-parameters! @var{parms} (list 'batch-port @var{port})) @end example @defun batch:command parms string1 string2 @dots{} Calls @code{batch:try-command} (below) with arguments, but signals an error if @code{batch:try-command} returns @code{#f}. @end defun @noindent These functions return a non-false value if the command was successfully translated into the batch dialect and @code{#f} if not. In the case of the @code{system} dialect, the value is non-false if the operation suceeded. @defun batch:try-command parms string1 string2 @dots{} Writes a command to the @code{batch-port} in @var{parms} which executes the program named @var{string1} with arguments @var{string2} @dots{}. @end defun @defun batch:try-chopped-command parms arg1 arg2 @dots{} list breaks the last argument @var{list} into chunks small enough so that the command: @example @var{arg1} @var{arg2} @dots{} @var{chunk} @end example fits withing the platform's maximum command-line length. @code{batch:try-chopped-command} calls @code{batch:try-command} with the command and returns non-false only if the commands all fit and @code{batch:try-command} of each command line returned non-false. @end defun @defun batch:run-script parms string1 string2 @dots{} Writes a command to the @code{batch-port} in @var{parms} which executes the batch script named @var{string1} with arguments @var{string2} @dots{}. @emph{Note:} @code{batch:run-script} and @code{batch:try-command} are not the same for some operating systems (VMS). @end defun @defun batch:comment parms line1 @dots{} Writes comment lines @var{line1} @dots{} to the @code{batch-port} in @var{parms}. @end defun @defun batch:lines->file parms file line1 @dots{} Writes commands to the @code{batch-port} in @var{parms} which create a file named @var{file} with contents @var{line1} @dots{}. @end defun @defun batch:delete-file parms file Writes a command to the @code{batch-port} in @var{parms} which deletes the file named @var{file}. @end defun @defun batch:rename-file parms old-name new-name Writes a command to the @code{batch-port} in @var{parms} which renames the file @var{old-name} to @var{new-name}. @end defun @noindent In addition, batch provides some small utilities very useful for writing scripts: @defun truncate-up-to path char @defunx truncate-up-to path string @defunx truncate-up-to path charlist @var{path} can be a string or a list of strings. Returns @var{path} sans any prefixes ending with a character of the second argument. This can be used to derive a filename moved locally from elsewhere. @example (truncate-up-to "/usr/local/lib/slib/batch.scm" "/") @result{} "batch.scm" @end example @end defun @defun string-join joiner string1 @dots{} Returns a new string consisting of all the strings @var{string1} @dots{} in order appended together with the string @var{joiner} between each adjacent pair. @end defun @defun must-be-first list1 list2 Returns a new list consisting of the elements of @var{list2} ordered so that if some elements of @var{list1} are @code{equal?} to elements of @var{list2}, then those elements will appear first and in the order of @var{list1}. @end defun @defun must-be-last list1 list2 Returns a new list consisting of the elements of @var{list1} ordered so that if some elements of @var{list2} are @code{equal?} to elements of @var{list1}, then those elements will appear last and in the order of @var{list2}. @end defun @defun os->batch-dialect osname Returns its best guess for the @code{batch-dialect} to be used for the operating-system named @var{osname}. @code{os->batch-dialect} uses the tables added to @var{database} by @code{batch:initialize!}. @end defun @noindent Here is an example of the use of most of batch's procedures: @example (require 'databases) @ftindex databases (require 'parameters) @ftindex parameters (require 'batch) @ftindex batch (require 'filename) @ftindex filename (define batch (create-database #f 'alist-table)) (batch:initialize! batch) (define my-parameters (list (list 'batch-dialect (os->batch-dialect *operating-system*)) (list 'operating-system *operating-system*) (list 'batch-port (current-output-port)))) ;gets filled in later (batch:call-with-output-script my-parameters "my-batch" (lambda (batch-port) (adjoin-parameters! my-parameters (list 'batch-port batch-port)) (and (batch:comment my-parameters "================ Write file with C program.") (batch:rename-file my-parameters "hello.c" "hello.c~") (batch:lines->file my-parameters "hello.c" "#include " "int main(int argc, char **argv)" "@{" " printf(\"hello world\\n\");" " return 0;" "@}" ) (batch:command my-parameters "cc" "-c" "hello.c") (batch:command my-parameters "cc" "-o" "hello" (replace-suffix "hello.c" ".c" ".o")) (batch:command my-parameters "hello") (batch:delete-file my-parameters "hello") (batch:delete-file my-parameters "hello.c") (batch:delete-file my-parameters "hello.o") (batch:delete-file my-parameters "my-batch") ))) @end example @noindent Produces the file @file{my-batch}: @example #! /bin/sh # "my-batch" script created by SLIB/batch Sun Oct 31 18:24:10 1999 # ================ Write file with C program. mv -f hello.c hello.c~ rm -f hello.c echo '#include '>>hello.c echo 'int main(int argc, char **argv)'>>hello.c echo '@{'>>hello.c echo ' printf("hello world\n");'>>hello.c echo ' return 0;'>>hello.c echo '@}'>>hello.c cc -c hello.c cc -o hello hello.o hello rm -f hello rm -f hello.c rm -f hello.o rm -f my-batch @end example @noindent When run, @file{my-batch} prints: @example bash$ my-batch mv: hello.c: No such file or directory hello world @end example @node HTML, HTML Tables, Programs and Arguments, Textual Conversion Packages @section HTML @include htmlform.txi @node HTML Tables, HTTP and CGI, HTML, Textual Conversion Packages @section HTML Tables @include db2html.txi @node HTTP and CGI, Parsing HTML, HTML Tables, Textual Conversion Packages @section HTTP and CGI @include http-cgi.txi @node Parsing HTML, URI, HTTP and CGI, Textual Conversion Packages @section Parsing HTML @include html4each.txi @node URI, Parsing XML, Parsing HTML, Textual Conversion Packages @section URI @include uri.txi @node Parsing XML, Printing Scheme, URI, Textual Conversion Packages @section Parsing XML @include xml-parse.txi @node Printing Scheme, Time and Date, Parsing XML, Textual Conversion Packages @section Printing Scheme @menu * Generic-Write:: 'generic-write * Object-To-String:: 'object->string * Pretty-Print:: 'pretty-print, 'pprint-file @end menu @node Generic-Write, Object-To-String, Printing Scheme, Printing Scheme @subsection Generic-Write @code{(require 'generic-write)} @ftindex generic-write @code{generic-write} is a procedure that transforms a Scheme data value (or Scheme program expression) into its textual representation and prints it. The interface to the procedure is sufficiently general to easily implement other useful formatting procedures such as pretty printing, output to a string and truncated output. @deffn {Procedure} generic-write obj display? width output @table @var @item obj Scheme data value to transform. @item display? Boolean, controls whether characters and strings are quoted. @item width Extended boolean, selects format: @table @asis @item #f single line format @item integer > 0 pretty-print (value = max nb of chars per line) @end table @item output Procedure of 1 argument of string type, called repeatedly with successive substrings of the textual representation. This procedure can return @code{#f} to stop the transformation. @end table The value returned by @code{generic-write} is undefined. Examples: @lisp (write obj) @equiv{} (generic-write obj #f #f @var{display-string}) (display obj) @equiv{} (generic-write obj #t #f @var{display-string}) @end lisp @noindent where @lisp @var{display-string} @equiv{} (lambda (s) (for-each write-char (string->list s)) #t) @end lisp @end deffn @node Object-To-String, Pretty-Print, Generic-Write, Printing Scheme @subsection Object-To-String @code{(require 'object->string)} @ftindex object->string @include obj2str.txi @node Pretty-Print, , Object-To-String, Printing Scheme @subsection Pretty-Print @code{(require 'pretty-print)} @ftindex pretty-print @deffn {Procedure} pretty-print obj @deffnx {Procedure} pretty-print obj port @code{pretty-print}s @var{obj} on @var{port}. If @var{port} is not specified, @code{current-output-port} is used. Example: @example @group (pretty-print '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) (16 17 18 19 20) (21 22 23 24 25))) @print{} ((1 2 3 4 5) @print{} (6 7 8 9 10) @print{} (11 12 13 14 15) @print{} (16 17 18 19 20) @print{} (21 22 23 24 25)) @end group @end example @end deffn @deffn {Procedure} pretty-print->string obj @deffnx {Procedure} pretty-print->string obj width Returns the string of @var{obj} @code{pretty-print}ed in @var{width} columns. If @var{width} is not specified, @code{(output-port-width)} is used. Example: @example @group (pretty-print->string '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) (16 17 18 19 20) (21 22 23 24 25))) @result{} "((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) (16 17 18 19 20) (21 22 23 24 25)) " @end group @group (pretty-print->string '((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) (16 17 18 19 20) (21 22 23 24 25)) 16) @result{} "((1 2 3 4 5) (6 7 8 9 10) (11 12 13 14 15) (16 17 18 19 20) (21 22 23 24 25)) " @end group @end example @end deffn @code{(require 'pprint-file)} @ftindex pprint-file @deffn {Procedure} pprint-file infile @deffnx {Procedure} pprint-file infile outfile Pretty-prints all the code in @var{infile}. If @var{outfile} is specified, the output goes to @var{outfile}, otherwise it goes to @code{(current-output-port)}. @end deffn @defun pprint-filter-file infile proc outfile @defunx pprint-filter-file infile proc @var{infile} is a port or a string naming an existing file. Scheme source code expressions and definitions are read from the port (or file) and @var{proc} is applied to them sequentially. @var{outfile} is a port or a string. If no @var{outfile} is specified then @code{current-output-port} is assumed. These expanded expressions are then @code{pretty-print}ed to this port. Whitepsace and comments (introduced by @code{;}) which are not part of scheme expressions are reproduced in the output. This procedure does not affect the values returned by @code{current-input-port} and @code{current-output-port}. @end defun @code{pprint-filter-file} can be used to pre-compile macro-expansion and thus can reduce loading time. The following will write into @file{exp-code.scm} the result of expanding all defmacros in @file{code.scm}. @lisp (require 'pprint-file) @ftindex pprint-file (require 'defmacroexpand) @ftindex defmacroexpand (defmacro:load "my-macros.scm") (pprint-filter-file "code.scm" defmacro:expand* "exp-code.scm") @end lisp @node Time and Date, NCBI-DNA, Printing Scheme, Textual Conversion Packages @section Time and Date @menu * Time Zone:: * Posix Time:: 'posix-time * Common-Lisp Time:: 'common-lisp-time * Time Infrastructure:: @end menu @noindent If @code{(provided? 'current-time)}: @noindent The procedures @code{current-time}, @code{difftime}, and @code{offset-time} deal with a @dfn{calendar time} datatype @cindex time @cindex calendar time which may or may not be disjoint from other Scheme datatypes. @defun current-time Returns the time since 00:00:00 GMT, January 1, 1970, measured in seconds. Note that the reference time is different from the reference time for @code{get-universal-time} in @ref{Common-Lisp Time}. @end defun @defun difftime caltime1 caltime0 Returns the difference (number of seconds) between twe calendar times: @var{caltime1} - @var{caltime0}. @var{caltime0} may also be a number. @end defun @defun offset-time caltime offset Returns the calendar time of @var{caltime} offset by @var{offset} number of seconds @code{(+ caltime offset)}. @end defun @node Time Zone, Posix Time, Time and Date, Time and Date @subsection Time Zone (require 'time-zone) @deftp {Data Format} TZ-string POSIX standards specify several formats for encoding time-zone rules. @table @t @item :@i{} If the first character of @i{} is @samp{/}, then @i{} specifies the absolute pathname of a tzfile(5) format time-zone file. Otherwise, @i{} is interpreted as a pathname within @var{tzfile:vicinity} (/usr/lib/zoneinfo/) naming a tzfile(5) format time-zone file. @item @i{}@i{} The string @i{} consists of 3 or more alphabetic characters. @i{} specifies the time difference from GMT. The @i{} is positive if the local time zone is west of the Prime Meridian and negative if it is east. @i{} can be the number of hours or hours and minutes (and optionally seconds) separated by @samp{:}. For example, @code{-4:30}. @item @i{}@i{}@i{} @i{} is the at least 3 alphabetic characters naming the local daylight-savings-time. @item @i{}@i{}@i{}@i{} @i{} specifies the offset from the Prime Meridian when daylight-savings-time is in effect. @end table The non-tzfile formats can optionally be followed by transition times specifying the day and time when a zone changes from standard to daylight-savings and back again. @table @t @item ,@i{}/@i{