ramsdell@LINUS.MITRE.ORG (10/27/89)
I got so many requests for SchemeTeX I decided to send it to the news group. Since my last message, I modified the Scheme source to SchemeTeX so that it contains no TAB characters for you Mac users. Please update to this version even if you recently received a version by mail from me. John #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Makefile # astyped.sty # schemeTeX.l # st.sh # st.scm # st.tex # reader.st # This archive created: Fri Oct 27 11:35:30 1989 export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' @(#)README 1.1 89/10/25 SchemeTeX---Simple support for literate programming in Lisp. SchemeTeX is a Unix filter that translates schemeTeX source into LaTeX source. Originally developed for the Scheme dialect of Lisp, it can easily be used with most other dialects. Installation: 1) Processes the file "st.tex" with LaTeX and read that one page document. 2) Decide if you plan to use your Lisp system's standard LOAD procedure or a modified one. I recommend you start by using your Lisp system's LOAD, which means all text lines must begin with ";". 3) Assuming you do use the standard LOAD, edit "st.sh" so that it contains the correct extension, i.e. ".scm", ".lisp", or ".clisp". Otherwise do not modify "st.sh". 4) Edit "Makefile" to reflect the correct destination of the executables(DEST) and the correct destination of the style file(TEXDEST). 5) The command "make install" installs schemeTeX. 6) If you plan to modify your Lisp system's standard LOAD, follow the model given in "reader.st", a reader of schemeTeX source for the R4RS dialect of Scheme. SHAR_EOF fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # schemeTeX Makefile @(#)Makefile 1.4 89/10/25. SRCS = README Makefile astyped.sty schemeTeX.l st.sh\ st.scm st.tex reader.st CMDS = st schemeTeX DOCS = st.dvi reader.dvi TEXSTY = astyped.sty #DEST = /usr/local/bin DEST = $(HOME)/bin #TEXDEST = /usr/local/lib/tex/inputs TEXDEST = $(HOME)/doc/inputs # Generic rules .SUFFIXES: .dvi .tex .st .st.dvi: make $*.tex && make $*.dvi .st.tex: st $* .tex.dvi: latex $* # Generic commands. all: $(CMDS) doc: $(DOCS) $(CMDS) install: $(CMDS) $(TEXSTY) mv $(CMDS) $(DEST) cp $(TEXSTY) $(TEXDEST) clean: -rm $(CMDS) dist: schemeTeX.sh # Specific commands. schemeTeX: schemeTeX.l lex -t $? > schemeTeX.c cc -O -o $@ schemeTeX.c -ll rm schemeTeX.c st: st.sh cp $? $@ chmod +x $@ schemeTeX.sh: $(SRCS) shar $(SRCS) > $@ SHAR_EOF fi # end of overwriting check if test -f 'astyped.sty' then echo shar: will not over-write existing file "'astyped.sty'" else cat << \SHAR_EOF > 'astyped.sty' %%%%%%%%%%%%%%%%%%%%%% @(#)astyped.sty 1.3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ASTYPED DOCUMENT-STYLE OPTION - released 88/06/30 % for LaTeX version 2.09 % Based on Leslie Lamport's verbatim environment in latex.tex. % Defines the `astyped' environment, which is like the `verbatim' % environment except most of the special characters have their usual meanings. % Space, ^K, and ^A are the only specials changed. \def\astyped{\trivlist \item[]\if@minipage\else\vskip\parskip\fi \leftskip\@totalleftmargin\rightskip\z@ \parindent\z@\parfillskip\@flushglue\parskip\z@ \@tempswafalse \def\par{\if@tempswa\hbox{}\fi\@tempswatrue\@@par} \obeylines \tt \catcode``=13 \@noligs \let\do\@makeother \do\ \do\^^K\do\^^A \frenchspacing\@vobeyspaces} \let\endastyped=\endtrivlist % Used inside astyped environments for normal formatting of a line. % I wish I could give space its normal catcode within \notastyped. \def\notastyped#1{\mbox{\rm #1}} SHAR_EOF fi # end of overwriting check if test -f 'schemeTeX.l' then echo shar: will not over-write existing file "'schemeTeX.l'" else cat << \SHAR_EOF > 'schemeTeX.l' %{ /* schemeTeX -- Scheme to TeX. John D. Ramsdell. * Simple support for literate programming in Scheme. * Usage: schemeTeX < {Scheme TeX file} > {TeX file} */ #if !defined lint static char ID[] = "@(#)schemeTeX.l 1.3 88/06/30"; static char copyright[] = "Copyright 1988 by The MITRE Corporation."; /* Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. The MITRE Corporation makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. */ #endif /* SchemeTeX defines a new source file format in which source lines are divided into text and code. Lines of code start with a line beginning with '(', and continue until the line that contains the matching ')'. The text lines remain, and they are treated as comments. If the first character of a text line is ';', it is stripped from the output. This is provided for those who want to use an unmodified version of their Scheme system's LOAD. When producing a document, both the text lines and the code lines are copied into the document source file, but the code lines are surrounded by a pair of formatting commands, as is comments beginning with ';' within code lines. SchemeTeX is currently set up for use with LaTeX. */ /* Define STRIP if you want to remove all comments in a Scheme TeX file. */ /* Modify the following for use with something other than LaTeX. Also see tex_verbatim_echo. */ #define BEGIN_COMMENT "\\notastyped{" #define BEGIN_CODE "\\begin{astyped}" #define END_CODE "\\end{astyped}" #define TEX_ECHO tex_verbatim_echo(yytext, stdout) /* Lex is used for identifying code in an Scheme TeX file. */ int parens; /* Used to balance parenthesis. */ /* All input occurs in the following routines so that TAB characters can be expanded. TeX treats TAB characters as a space--not what is wanted. */ #undef getc() #define getc(STREAM) expanding_getc(STREAM) int spaces = 0; /* Spaces left to print a TAB. */ int column = 0; /* Current input column. */ int expanding_getc(stream) FILE *stream; { int c; if (spaces > 0) { spaces--; return ' '; } switch (c = fgetc(stream)) { case '\t': spaces = 8 - (7&column); column += spaces; return expanding_getc(stream); case '\n': column = 0; return c; default: column++; return c; } } %} %% #\\\( { #if defined STRIP ECHO; #else TEX_ECHO; #endif } #\\\) { #if defined STRIP ECHO; #else TEX_ECHO; #endif } \( { ECHO; parens++; } \) { ECHO; parens--; if (parens == 0) { /* End of code. */ char c; /* Check that nothing follows. */ while ((c = input()) == ' ') output(c); if (c == '\000') return 0; /* EOF */ if (c != '\n' && c != ';') return -1; unput(c); } } \"[^"]*\" { if ((yyleng > 1) && (yytext[yyleng-2] == '\\')) yymore(); else #if defined STRIP ECHO; #else TEX_ECHO; #endif } ;[^\n]*$ { #if defined STRIP ; #else fputs(BEGIN_COMMENT, stdout); ECHO; fputs("}", stdout); #endif } \n { ECHO; if (parens <= 0) return 0; } . { #if defined STRIP ECHO; #else TEX_ECHO; #endif } %% fatal (s) char *s; { fprintf(stderr, "On line %d, %s\n", yylineno, s); exit(1); } tex_verbatim_echo (s, f) char *s; FILE *f; { for (; *s != '\000'; s++) switch (*s) { case '\\': case '{': case '}': case '$': case '&': case '#': case '^': case '_': case '%': case '~': fputs("\\verb-", f); putc(*s, f); putc('-', f); break; default: putc(*s, f); } } main() { char c; do { /* TeX mode and saw newline */ c = input(); if (c == '(') { /* TeX mode changed to code mode. */ unput(c); #if !defined STRIP fputs(BEGIN_CODE,stdout); putc('\n', stdout); #endif do { /* Copy out code using yylex. */ parens = 0; if (0 != yylex()) fatal("Bad code section."); if (parens != 0) fatal("Premature EOF."); c = input(); unput(c); /* Repeat when there is code */ } while (c == '('); /* immediately after copied code. */ #if !defined STRIP fputs(END_CODE, stdout); putc('\n', stdout); #endif } else { /* Found a text line. */ if (c == ';') c = input(); /* For those who want to use bare load. */ while (c != '\n') { if (c == '\000') exit(0); /* EOF. */ #if !defined STRIP output(c); #endif c = input(); } #if !defined STRIP output(c); #endif } } while (1); } SHAR_EOF fi # end of overwriting check if test -f 'st.sh' then echo shar: will not over-write existing file "'st.sh'" else cat << \SHAR_EOF > 'st.sh' #! /bin/sh # schemeTeX @(#)st.sh 1.3 88/06/30 EXT=.st DIR=`dirname $1` BASE=`basename $1 ${EXT}` case $# in 0) schemeTeX ;; 1) schemeTeX < ${DIR}/${BASE}${EXT} > ${DIR}/${BASE}.tex ;; 2) schemeTeX < $1 > $2 ;; *) echo "usage: $0 file-name"; exit 1;; esac SHAR_EOF fi # end of overwriting check if test -f 'st.scm' then echo shar: will not over-write existing file "'st.scm'" else cat << \SHAR_EOF > 'st.scm' ;;; @(#)st.scm 1.2 89/10/27 ;;; SchemeTeX --- Simple support for literate programming in Scheme. ;;; October 1989, John D. Ramsdell. ;;; ;;; Copyright 1989 by The MITRE Corporation. ;;; Permission to use, copy, modify, and distribute this ;;; software and its documentation for any purpose and without ;;; fee is hereby granted, provided that the above copyright ;;; notice appear in all copies. The MITRE Corporation ;;; makes no representations about the suitability of this ;;; software for any purpose. It is provided "as is" without ;;; express or implied warranty. ;;; ;;; SchemeTeX ;;; defines a new source file format in which source lines are divided ;;; into text and code. Lines of code start with a line beginning with ;;; '(', and continue until the line that contains the matching ')'. The ;;; text lines remain, and they are treated as comments. When producing ;;; a document, both the text lines and the code lines are copied into ;;; the document source file, but the code lines are surrounded by a pair ;;; of formatting commands. The formatting commands are in begin-code ;;; and end-code. SchemeTeX is currently set up for use with LaTeX. ;;; ;;; Exports: tangle and weave. ;;; (tangle st-file scheme-file) Makes scheme file from schemeTeX source. ;;; (weave st-file tex-file) Makes LaTeX file from schemeTeX source. (define (tangle st-filename scheme-filename) ; => scheme-filename or false. (if (call-with-input-file st-filename (lambda (st-port) (call-with-output-file scheme-filename (lambda (scheme-port) (tangle-port st-port scheme-port))))) scheme-filename (begin ; Put a call to error here. (display "tangle failed.") (newline) '#f))) (define (weave st-filename tex-filename) ; => tex-filename or false. (if (call-with-input-file st-filename (lambda (st-port) (call-with-output-file tex-filename (lambda (tex-port) (weave-port st-port tex-port))))) tex-filename (begin ; Put a call to error here. (display "weave failed.") (newline) '#f))) (define (tangle-port st-port scheme-port) ; => false on failure. (letrec ((tex-mode-and-saw-newline ; Decide if input is code (lambda () (let ((ch (peek-char st-port))) ; or tex source. (cond ((eof-object? ch) '#t) ((char=? ch #\() (scheme-mode)) (else (tex-mode-within-a-line)))))) (tex-mode-within-a-line ; Strip comments. (lambda () (let ((ch (read-char st-port))) (cond ((eof-object? ch) '#t) ((char=? ch #\newline) (tex-mode-and-saw-newline)) (else (tex-mode-within-a-line)))))) (scheme-mode ; This routine should use (lambda () (write (read st-port) scheme-port) (newline scheme-port) ; read-refusing-eof if (tex-mode-within-a-line)))) ; available. (tex-mode-and-saw-newline))) (define begin-code "\\begin{astyped}") ; TeX code surrounding (define end-code "\\end{astyped}") ; code and comments (define begin-comment "\\notastyped{") ; within code. (define (weave-port st-port tex-port) (let ((spaces 0) ; Used in get-char and get-line during (hpos 0) ; the expansion of tabs into spaces. (ch-buf '#f)) ; One char buffer. (letrec ((get-char (lambda () ; Get-char expands tabs into spaces, (cond (ch-buf ; and implements a one character (let ((ch ch-buf)) ; buffer. (set! ch-buf '#f) ch)) ((> spaces 0) (set! spaces (- spaces 1)) #\space) (else (let ((ch (read-char st-port))) (cond ((eof-object? ch) ch) ((char=? ch #\tab) ; Expand tabs here. (set! spaces (- 8 (modulo hpos 8))) (set! hpos (+ hpos spaces)) (get-char)) ((char=? ch #\newline) (set! hpos 0) ch) (else (set! hpos (+ hpos 1)) ch))))))) (unget-char (lambda (ch) (set! ch-buf ch))) (copy-line-saw-eof (lambda () (let ((ch (get-char))) (cond ((eof-object? ch) '#t) ((char=? ch #\newline) '#f) (else (write-char ch tex-port) (copy-line-saw-eof)))))) (tex-write-char (lambda (ch) ; Write to TeX file (if (or (char=? ch #\\) ; escaping TeX's special (char=? ch #\{) ; characters. (char=? ch #\}) (char=? ch #\$) (char=? ch #\&) (char=? ch #\#) (char=? ch #\^) (char=? ch #\_) (char=? ch #\%) (char=? ch #\~)) (begin (display "\\verb-" tex-port) (write-char ch tex-port) (write-char #\- tex-port)) (write-char ch tex-port)))) ;; TeX mode (tex-mode-and-saw-newline ; State at which it is (lambda () ; decided whether to go (let ((ch (get-char))) ; into Scheme code mode (cond ((eof-object? ch) '#t) ; or stay in TeX mode. ((char=? ch #\() (scheme-mode)) (else ;; Strip leading semicolon for those who ;; want to use regular load. (if (not (char=? ch #\;)) (write-char ch tex-port)) (if (char=? ch #\newline) (tex-mode-and-saw-newline) (tex-mode-within-a-line))))))) (tex-mode-within-a-line ; Copy out TeX line. (lambda () (let ((saw-eof (copy-line-saw-eof))) (newline tex-port) (or saw-eof (tex-mode-and-saw-newline))))) ;; Scheme mode (scheme-mode ; Change from TeX mode (lambda () ; to scheme code mode. (display begin-code tex-port) (newline tex-port) (write-char #\( tex-port) (sexpr 1))) (sexpr ; parens is used to watch (lambda (parens) ; for the closing paren (let ((ch (get-char))) ; used to detect the end (cond ((eof-object? ch) '#f) ; of scheme code mode. ((char=? ch #\;) (copy-comment-within-sexpr parens)) (else (sexpr-write-char parens ch)))))) (copy-comment-within-sexpr (lambda (parens) ; Handle comment. (display begin-comment tex-port) (write-char #\; tex-port) (let ((saw-eof (copy-line-saw-eof))) (write-char #\} tex-port) (newline tex-port) (and (not saw-eof) (sexpr parens))))) (sexpr-write-char (lambda (parens ch) ; Write a char and (tex-write-char ch) ; figure out what to (cond ((char=? ch #\() ; do next. (sexpr (+ parens 1))) ((char=? ch #\)) (if (= 1 parens) ; Done reading sexpr. (scheme-mode-after-sexpr) (sexpr (- parens 1)))) ((char=? ch #\") (copy-out-string parens)) ((char=? ch #\#) ; Worrying about #\( and #\). (maybe-char-syntax parens)) (else (sexpr parens))))) (copy-out-string (lambda (parens) (let ((ch (get-char))) (and (not (eof-object? ch)) (begin (tex-write-char ch) (cond ((char=? ch #\\) (let ((ch (get-char))) (and (not (eof-object? ch)) (begin (tex-write-char ch) (copy-out-string parens))))) ((char=? ch #\") (sexpr parens)) (else (copy-out-string parens)))))))) (maybe-char-syntax ; What out for (lambda (parens) ; #\( and #\). (let ((ch (get-char))) (cond ((eof-object? ch) '#f) ((char=? ch #\\) (tex-write-char ch) (let ((ch (get-char))) (and (not (eof-object? ch)) (begin (tex-write-char ch) (sexpr parens))))) (else (unget-char st-port) (sexpr parens)))))) (scheme-mode-after-sexpr (lambda () (let ((ch (get-char))) (cond ((eof-object? ch) '#t) ((char=? ch #\;) (copy-comment-after-sexpr)) ((char=? ch #\newline) (newline tex-port) (scheme-mode-merge)) ((char=? ch #\space) (tex-write-char ch) (scheme-mode-after-sexpr)) (else '#f))))) ; Call to error should go here. (copy-comment-after-sexpr (lambda () ; Handle trailing comment. (display begin-comment tex-port) (write-char #\; tex-port) (let ((saw-eof (copy-line-saw-eof))) (write-char #\} tex-port) (newline tex-port) (and (not saw-eof) (scheme-mode-merge))))) (scheme-mode-merge ; Don't change mode if next (lambda () ; line is code. (let ((ch (get-char))) (cond ((eof-object? ch) '#t) ((char=? ch #\() ; Stay in scheme mode. (write-char ch tex-port) (sexpr 1)) (else ; Enter tex mode. (display end-code tex-port) (newline tex-port) (write-char ch tex-port) (if (char=? ch #\newline) (tex-mode-and-saw-newline) (tex-mode-within-a-line)))))))) (tex-mode-and-saw-newline)))) SHAR_EOF fi # end of overwriting check if test -f 'st.tex' then echo shar: will not over-write existing file "'st.tex'" else cat << \SHAR_EOF > 'st.tex' \documentstyle[proc]{article} % @(#)st.tex 1.4 89/10/25 \title{Scheme\TeX{}} \author{John D. Ramsdell} \date{ 89/10/25 } \begin{document} \maketitle Scheme\TeX{} provides simple support for literate programming in any dialect of Lisp. Originally created for use with Scheme, it defines a new source file format which may be used to produce \LaTeX{} input or Lisp code. Scheme\TeX{} source lines are divided into text and code. Lines of code start with a line beginning with ``('', and continue until the line containing the matching ``)''. The remaining lines are text lines, and they are treated as comments. When producing a \LaTeX{} document, both the text lines and the code lines are copied into the document source file, but the code lines are surrounded by a pair of formatting commands (\verb-\begin{astyped}- and \verb-\end{astyped}-). This \LaTeX{} environment formats the code as written, in typewriter font. A Lisp comment within a code line is formatted in an \verb-\mbox- in Roman font. A Scheme\TeX{} style command should include the \verb-astyped- style option, so that the \verb-astyped- environment is available. An example: \begin{center} \verb-\documentstyle[astyped]{article}- \end{center} Scheme\TeX{} was designed under the constraint that code lines must be unmodified Lisp code, and text lines must be unmodified \LaTeX{} code. Text editors with support for Lisp and \LaTeX{}, such as Emacs, may be used for Scheme\TeX{} code much as they are used for Lisp code and \LaTeX{} code. For those who prefer not to modify the reader used by their Lisp system's loader and compiler, the rule that text lines must be unmodified \LaTeX{} code has been relaxed. Text lines that begin with ``;'' are copied without the initial ``;''. \section*{Usage in Scheme} The file \verb;st.scm; contains programs used to obtain code or \LaTeX{} from a Scheme\TeX{} source file. The Scheme expression \begin{center} \verb;(TANGLE; {\it st-filespec Scheme-filespec\/}{\tt )} \end{center} creates Scheme source from a Scheme\TeX{} file, and the expression \begin{center} \verb;(WEAVE; {\it st-filespec \LaTeX{}-filespec\/}{\tt )} \end{center} creates LaTeX{} source. The file \verb-reader.st- contains a Scheme\TeX{} reader in R$^4$R Scheme. Use that reader with your Scheme system's loader and compiler to avoid running \verb-TANGLE- and creating a temporary file. \section*{Usage in a Unix shell} The extension for Scheme\TeX{} files is ``\verb;.st;''. A \LaTeX{} file is produced from Scheme\TeX{} source using the Unix shell command \begin{center} {\tt st} {\it file-name} \end{center} It will produce a file with the ``\verb;.tex;'' extension. The obvious make file is in Figure~\ref{makefile}. \begin{figure} \begin{verbatim} .SUFFIXES: .dvi .tex .st .st.dvi: make $*.tex && make $*.dvi .st.tex: st $* .tex.dvi: latex $* \end{verbatim} \caption{A Scheme\TeX{} Makefile}\label{makefile} \end{figure} \end{document} SHAR_EOF fi # end of overwriting check if test -f 'reader.st' then echo shar: will not over-write existing file "'reader.st'" else cat << \SHAR_EOF > 'reader.st' \documentstyle[astyped]{article} % @(#)reader.st 1.4 89/10/25 \title{{\tt read-st}} \author{John D. Ramsdell} \date{ 89/10/25 } \begin{document} \maketitle \verb;read-st; converts Scheme\TeX{} representations of Scheme objects into the objects themselves much as \verb;read; does. (define (read-st . rest) ; Returns what \verb;read; returns. (let ((port (if (pair? rest) ; \verb;read-st; arguments are (car rest) ; the same as \verb;read;'s. (current-input-port)))) (letrec ((text-mode-and-saw-newline ; Lines of a Scheme\TeX{} file (lambda () ; beginning with ``{\tt(}'', (let ((ch (peek-char port))) ; start a code section. (cond ((eof-object? ch) ch) ((char=? ch #\() ; If code section, then use (got-code (read port))) ; \verb;read; to get code, (else ; else skip this line as it (text-mode-within-a-line)))))) ; is a comment. (text-mode-within-a-line (lambda () ; Ignore comments. (let ((ch (read-char port))) (cond ((eof-object? ch) ch) ((char=? ch #\newline) (text-mode-and-saw-newline)) (else (text-mode-within-a-line)))))) (got-code (lambda (code) ; Ignore the remainder of the (let ((ch (read-char port))) ; last code line and return (cond ((eof-object? ch) code) ; the results of \verb;read;. ((char=? ch #\newline) code) (else (got-code code))))))) (text-mode-and-saw-newline) ; Start by looking ))) ; for a code line. \end{document} SHAR_EOF fi # end of overwriting check # End of shell archive exit 0