Hello all
I want to write an interpreter (sort of) in lisp for a
TeX-like language. I'm not sure yet how what I will do with
the output (either store it in a list, or display it as the
data is parsed); I simply want to read in a subset of TeX.
Basically, my language will be as follows:
1. atom : prints the atom itself
e.g. Hello World
will merely print "Hello World"
2. {atoms} : prints each atom, same as #1
e.g. {Hello World}
will print "Hello World"
3. \key{atoms} : prints the atoms in the manner specified
by the key.
e.g. \bold{Hello World}
will print out a bolded "Hello World"
4. \key[options]{atoms} : same as #3, with options controlling
a few variables associated with that key.
e.g. \paragraph[In the beginning] {
Once upon a time, in a land far far
away, there lived the deranged developer.
}
will result in the above paragraph with the
title "In the beginning".
I can possibly do this with a state machine, but I was wondering
if there is a better way. I'm guessing that a modification to the
readtable might make it possible to read in a file of TeX and
have each "\key" be a function call, with optional arguments
represented with "[...]" and a rest argument being represented
with "{...}" so that when the reader encounters
\paragraph[Welcome]{
\textbf{Hello to the \textit{entire} World}
}
it will read it in as
(paragraph :option "Welcome"
(textbf "Hello to the " (textit "entire") " World"))
and then I can just write the functions (paragraph ...),
(textbf ...) etc, but I don't know enough about the readtable
to even know where to begin, never mind what the changes should
be.
Is this possible by just changing the reader syntax? Is it
difficult enough that I should rather just write a state-machine
instead? The only problem I see with the above is that free-
standing atoms would get ignored.
Thanks in advance
goose
(ps. I actually *am* intending to read in TeX, and display
(as faithfully as possible, anyway) the rendered TeX).
goose wrote:
> Hello all
>
> I want to write an interpreter (sort of) in lisp for a
> TeX-like language. I'm not sure yet how what I will do with
> the output (either store it in a list, or display it as the
> data is parsed); I simply want to read in a subset of TeX.
>
Hi,
you mean like this ? Sorry for the spare commented src but it's just a
quick hack. However, any comments are highly appreciated.
Please note that \paragraph{ foo bar } will become (paragraph (foo
bar)). I make this because there might be a limit on the number of
arguments given to a function.
Regards
AHz
(defun read-list-if-character (char stream terminator)
(let ((next-char (read-char stream))) ; TODO: Eat whitespaces
(if (char= next-char char)
(read-delimited-list terminator stream t)
(unread-char next-char stream))))
(defun tex-reader-function (stream char)
(declare (ignore char))
(let ((*readtable* (copy-readtable)))
(no-char-fct (get-macro-character #\A)))
(set-macro-character #\[ no-char-fct)
(set-macro-character #\] no-char-fct)
(let* ((function (list (read stream)))
(options (read-list-if-character #\[ stream #\]))
(value (read-list-if-character #\{ stream #\})))
(when value
(push value function))
(when options
(push :options function)
(push options function))
(reverse function))))
(defun tex-read-list (stream char)
(declare (ignore char))
(read-delimited-list #\} stream t))
(defconstant +macro-characters+ '(#\# #\, #\` #\' #\( #\) ))
(defconstant +terminating-characters+ '(#\. #\, #\? #\! ))
(defun tex-read (&optional input-stream eof-error-p eof-value recursive-p)
"Read input from a tex-like file"
(let ((*readtable* (copy-readtable))
(start-list (get-macro-character #\( ))
(end-list (get-macro-character #\) ))
(no-char-fct (get-macro-character #\A)))
(dolist (c +macro-characters+) ; Kill default macro chars
(set-syntax-from-char c #\A))
(dolist (c +terminating-characters+) ; make new terminating chars
(set-macro-character c no-char-fct))
(set-macro-character #\\ #'tex-reader-function)
(set-macro-character #\{ #'tex-read-list)
(set-macro-character #\} end-list)
(setf (readtable-case *readtable*) :preserve)
(read input-stream eof-error-p eof-value recursive-p)))
;; some spare tests
(prin1 (tex-read (make-string-input-stream "foo")))
(prin1 (tex-read (make-string-input-stream "{foo bar}")))
(prin1 (tex-read (make-string-input-stream "\\foo bar")))
(prin1 (tex-read (make-string-input-stream "\\foo{ bar }")))
(prin1 (tex-read (make-string-input-stream "\\foo[what ever you want]{
bar }")))
(prin1 (tex-read (make-string-input-stream "\\paragraph[In the beginning]{
Once upon a time, in a land far far
away, there lived the deranged developer.
}")))
Hello
this:
> (dolist (c +terminating-characters+) ; make new terminating chars
> (set-macro-character c no-char-fct))
gives the following error in clisp:
*** - SET-MACRO-CHARACTER: undefined function NIL
A similar complaint is raised by cmucl. I don't really
understand readtables, so I cannot figure out what it
is supposed to be doing at that point (I'm not even
sure why set-macro-character wants a function).
I am slowing working my way through this function
to try and figure out how it accomplishes what it does.
HAND,
goose