1 ;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: SGML; -*-
2 ;;; ---------------------------------------------------------------------------
3 ;;; Title: A very first approach to parse DTD's directly
4 ;;; Created: 1997-10-14
5 ;;; Author: Gilbert Baumann <gilbert@base-engineering.com>
6 ;;; License: MIT style (see below)
7 ;;; ---------------------------------------------------------------------------
8 ;;; (c) copyright 1997-2001 by Gilbert Baumann
10 ;;; Permission is hereby granted, free of charge, to any person obtaining
11 ;;; a copy of this software and associated documentation files (the
12 ;;; "Software"), to deal in the Software without restriction, including
13 ;;; without limitation the rights to use, copy, modify, merge, publish,
14 ;;; distribute, sublicense, and/or sell copies of the Software, and to
15 ;;; permit persons to whom the Software is furnished to do so, subject to
16 ;;; the following conditions:
18 ;;; The above copyright notice and this permission notice shall be
19 ;;; included in all copies or substantial portions of the Software.
21 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 ;;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 ;;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 ;;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 ;;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 name
;the name (a SYMBOL)
33 include
;set of included elements (a list)
34 exclude
;set of excluded elements (a list)
35 obegin?
;optional start tag? (boolean)
36 oend?
;optional end tag? (boolean)
39 (defstruct (dtd (:print-function print-dtd
))
41 elements
;EQ-hashtable mapping from SYMBOLs to ELEMENTs
42 entities
;a simple alist mapping from entity names to entity values
43 resolve-info
;a EQUAL-hashtable
47 (defun print-dtd (self sink depth
)
48 (declare (ignore depth
))
49 (cond (*print-readably
*
53 :elements
(dtd-elements self
))
56 (format sink
"#<~S ~S>" (type-of self
) (dtd-name self
)))))
58 ;;;; ------------------------------------------------------------------------------------------
65 (defun find-entity (name)
66 (cdr (assoc name
*entities
* :test
#'string
=)))
68 (defun add-entity (name value
)
69 (setf *entities
* (nconc *entities
* (list (cons name value
)))))
71 (defun new-entities ()
72 (setf *entities
* nil
))
75 (defun find-entity (name)
76 (gethash name
*entities
*))
78 (defun add-entity (name value
)
79 (if (> (length value
) 60)
80 (format T
"~&;; % ~A <- '~A [...]' "
81 name
(substitute #\space
#\newline
(subseq value
0 60)))
82 (format T
"~&;; % ~A <- '~A' " name
(substitute #\space
#\newline value
)))
83 (unless (gethash name
*entities
*)
84 (setf (gethash name
*entities
*) value
)))
86 (defun new-entities ()
87 (setf *entities
* (make-hash-table :test
#'equal
)))
90 ((alpha (or (range "a" "z") (range "A" "Z")))
91 (digit (range "0" "9"))
92 (white (or #\space
#\newline
#\tab
#\page
))
94 (name-char (or alpha digit
"." "-" "_"))
96 (string-char (or white
(range #\space
#\
!) (range #\
# #\
&) (range #\
( #\~
)))
98 (name (and name-start
(* name-char
)))
99 (any (or white
(range #\space
#\~
))) )
101 ;;slurp away white spaces
103 ;; slurp away comments
104 ("--" (clex:begin
'comment
))
105 ((clex::in comment
"--") (clex:begin
'clex
:initial
))
106 ((clex::in comment any
))
109 ;;this is a defined entity
110 (let ((looked (find-entity (subseq clex
:bag
1 (- (length clex
:bag
) 1)))))
114 (do ((i (- (length looked
) 1) (- i
1)))
116 (clex:backup
(char looked i
))))
117 ((error "Entity ~A is not defined." clex
:bag
)) )))
119 ;;this is a defined entity
120 (let ((looked (find-entity (subseq clex
:bag
1))))
122 (do ((i (- (length looked
) 1) (- i
1)))
124 (clex:backup
(char looked i
))))
125 ((error "Entity ~A is not defined." clex
:bag
)) )))
133 ("ENTITY" (return :entity
))
134 ("ATTLIST" (return :attlist
))
135 ("ELEMENT" (return :element
))
136 ("SYSTEM" (return :system
))
137 ("PUBLIC" (return :public
))
138 ("CDATA" (return :cdata
))
139 ("IGNORE" (return :ignore
))
140 ("INCLUDE" (return :include
))
141 ("#REQUIRED" (return :required
))
142 ("#IMPLIED" (return :implied
))
143 ("#PCDATA" (return :pcdata
))
144 ("#FIXED" (return :fixed
))
145 (name (return (list :name clex
:bag
)))
147 ("+(" (clex:backup
#\
() (return :plus-prefix
))
148 ("-(" (clex:backup
#\
() (return :minus-prefix
))
151 (return (list :number
(parse-integer clex
:bag
))))
155 (return (char clex
:bag
0)))
157 ((and #\" (* (or string-char
#\')) #\")
158 (return (list :string
(subseq clex
:bag
1 (- (length clex
:bag
) 1)))))
159 ((and #\' (* (or string-char
#\")) #\')
160 (return (list :string
(subseq clex
:bag
1 (- (length clex
:bag
) 1))))) )
162 ;;;; ------------------------------------------------------------------------------------------
168 (defmacro action
(&rest body
)
169 (let ((args (gensym)))
170 `#'(lambda (&rest
,args
)
171 (declare (ignorable ,args
))
172 (symbol-macrolet (($
1 (nth 0 ,args
))
181 (lalr:define-grammar dtd-parser
(:open
:close
:entity
:attlist
:element
:name
182 #\%
#\
( #\
) #\|
#\
+ #\-
#\
* #\? #\
, #\
&
184 :plus-prefix
:minus-prefix
186 :required
:implied
:number
:pcdata
:cdata
187 :public
:system
:ignore
:include
#\
[ #\
])
188 (start --
> <definitions
> (action nil
))
190 (<definitions
> --
> <one-def
> :close
<definitions
> (action nil
))
191 (<definitions
> --
> #'(lambda () nil
))
193 (<one-def
> --
> definition
(action (cond ((eq (car $
1) 'def-my-entity
)
194 (add-entity (second $
1) (third $
1)))
197 ((defelement defattlist
) (princ #\.
) (finish-output *standard-output
*)))
198 (process-dtd-def *dtd
* $
1)))))
200 (<ignored-definitions
> --
> ignored-definition
:close
<ignored-definitions
> (action nil
))
201 (<ignored-definitions
> --
> (action nil
))
203 (ignored-definition --
> definition
(action nil
))
205 (definition --
> :open
(action nil
))
206 (definition --
> :open
:ENTITY
#\%
:name
:string
(action (list 'DEF-MY-ENTITY $
4 $
5)))
207 (definition --
> :open
:ENTITY
#\%
:name
<sgml-resource
> (action (list 'DEF-MY-ENTITY $
4 (sgml-resource-as-string $
5))))
208 (definition --
> :open
:ENTITY
:name
<sgml-resource
> (action (list 'DEF-ENTITY $
3 (sgml-resource-as-string $
4))))
209 (definition --
> :open
:ATTLIST production attliste
(action (list 'DEFATTLIST $
3 $
4)))
210 (definition --
> :open
:ELEMENT production odef odef production maybe-pm
(action (list 'DEFELEMENT $
3 $
4 $
5 $
6 $
7)))
212 (definition --
> :open
#\
[ :ignore
#\
[ <ignored-definitions
> #\
] #\
]
213 #'(lambda (&rest i
) i nil
))
214 (definition --
> :open
#\
[ :include
#\
[ <definitions
> #\
] #\
]
215 #'(lambda (&rest i
) i nil
))
217 (attliste --
> #'(lambda () nil
))
218 (attliste --
> att-def attliste
#'cons
)
220 (att-def --
> ident production value
#'list
)
221 (att-def --
> ident production
:fixed value
#'(lambda (n p i v
) i
(list n p v
)))
223 (maybe-pm --
> #'(lambda () nil
))
224 (maybe-pm --
> :plus-prefix production
#'(lambda (i p
) i
(list '+ p
)))
225 (maybe-pm --
> :minus-prefix production
#'(lambda (i p
) i
(list '- p
)))
227 (odef --
> #\-
#'(lambda (i) i
'-
))
228 (odef --
> ident
#'identity
)
229 (production --
> p1
#'identity
)
231 (p1 --
> p2
#\| p1
#'(lambda (a b c
) b
(as-cons 'or a c
)))
232 (p1 --
> p2
#'identity
)
233 (p2 --
> p3
#\
, p2
#'(lambda (a b c
) b
(as-cons 'and a c
)))
234 (p2 --
> p3
#\
& p2
#'(lambda (a b c
) b
(as-cons 'amp a c
)))
235 (p2 --
> p3
#'identity
)
236 (p3 --
> p4
#\
* #'(lambda (a b
) b
(list '* a
)))
237 (p3 --
> p4
#\
+ #'(lambda (a b
) b
(list '+ a
)))
238 (p3 --
> p4
#\? #'(lambda (a b
) b
(list '? a
)))
239 (p3 --
> p4
#'identity
)
240 (p4 --
> #\
( production
#\
) #'(lambda (a b c
) a c b
))
241 (p4 --
> ident
#'identity
)
242 (p4 --
> :pcdata
#'identity
)
243 (p4 --
> :cdata
#'identity
)
244 (p4 --
> :number
#'(lambda (x) (princ-to-string x
)))
246 (value --
> :implied
#'(lambda (a) a
:implied
))
247 (value --
> :required
#'(lambda (a) a
:required
))
248 (value --
> ident
#'identity
)
249 (value --
> :string
#'identity
)
250 (value --
> :number
#'identity
)
253 #'(lambda (x) (intern (string-upcase x
) :keyword
)))
255 ( <sgml-resource
> --
> :cdata
:string
#'list
)
256 ( <sgml-resource
> --
> :public
:string
#'list
)
257 ( <sgml-resource
> --
> :public
:string
:string
#'list
)
260 (defun parse-dtd (res-name &optional
(top-elment :html
))
261 (let ((dtd (make-dtd :name res-name
:elements
(make-hash-table :test
#'eq
))))
262 (with-open-stream (input (apply #'open-sgml-resource res-name
))
265 (lexer (make-dtd-lexer input
)))
267 (labels ((next-input ()
268 (let ((x (funcall lexer
)))
269 (cond ((eq x
:eof
) (values :eof
:eof
))
270 ((atom x
) (values x x
))
271 (t (values (first x
) (second x
))))))
274 (error "Parse-Error! at pos = ~D" (ignore-errors (file-position input
)))))
275 (dtd-parser #'next-input
#'parse-error
))))
276 (setf (gethash :pcdata
(dtd-elements dtd
))
277 (make-element :name
:pcdata
280 (calculate-resolve-info dtd top-elment
)
283 ;;;; ------------------------------------------------------------------------------------------
285 (defun as-cons (op x y
)
286 (cond ((and (consp y
) (eq (car y
) op
))
287 (list* op x
(cdr y
)))
290 (defun find-element (dtd name
&optional
(intern? nil
) (error? t
))
291 (or (gethash name
(dtd-elements dtd
))
293 (let ((new (make-element :name name
)))
294 (setf (gethash name
(dtd-elements dtd
)) new
)
296 (and error?
(error "Element ~S is not defined." name
))))
298 (defun find-element-attlist (dtd name
)
299 (let ((x (find-element dtd name nil nil
)))
300 (and x
(element-attlist x
))))
302 (defun canon-optional-tag-definition (x)
303 (cond ((eq x
'-
) nil
)
306 (error "Optionalilty definition must be either '-' or 'O' - ~S. " x
))))
308 (defun production->name-list
(prod)
309 (cond ((atom prod
) (list prod
))
311 (mapcan #'production-
>name-list
(cdr prod
)))
313 (error "Bogus production - ~S" prod
))))
315 (defun production->name-list
/2 (prod)
316 (cond ((atom prod
) (list prod
))
317 ((member (car prod
) '(or and amp
+ * ?
))
318 (mapcan #'production-
>name-list
/2 (cdr prod
)))
320 (error "Bogus production - ~S" prod
))))
322 (defun process-def-element (dtd name odef cdef production additional
)
324 (dolist (name (production->name-list name
))
325 (process-def-element dtd name odef cdef production additional
)))
326 ((let ((obegin?
(canon-optional-tag-definition odef
))
327 (oend?
(canon-optional-tag-definition cdef
))
328 (incl (subst :pcdata
:cdata
;xxx hack here
329 (production->name-list
/2 production
)))
331 (cond ((and (consp additional
) (eq (car additional
) '+))
332 (setf incl
(union incl
(production->name-list
/2 (cadr additional
)))))
333 ((and (consp additional
) (eq (car additional
) '-
))
334 (setf excl
(production->name-list
/2 (cadr additional
))))
337 (error "Bogus extra inclusion/exclusion - ~S" additional
)))
338 (let ((elm (find-element dtd name t
)))
339 (setf (element-include elm
) (if (equal incl
'(:empty
)) nil incl
)
340 (element-exclude elm
) excl
341 (element-obegin? elm
) obegin?
342 (element-oend? elm
) oend?
))))))
344 (defun process-attribute (name type value
)
345 (declare (ignore value
))
346 (setq type
(production->name-list type
))
347 (cond ((and (= (length type
) 1)
348 (member (car type
) '(:cdata
)))
349 (list (intern (symbol-name name
) :keyword
) 't
))
350 ((and (= (length type
) 1)
351 (member (car type
) '(:number
:name
:id
)))
352 (list name
(car type
)))
353 ((list (intern (symbol-name name
) :keyword
) type
)) ))
355 (defun process-def-attlist (dtd name attlist
)
357 (dolist (name (production->name-list name
))
358 (process-def-attlist dtd name attlist
)))
360 (setf (element-attlist (find-element dtd name t
))
361 (mapcar #'(lambda (x)
362 (process-attribute (first x
) (second x
) (third x
)))
365 (defun process-dtd-def (dtd def
)
367 ((eq (car def
) 'def-entity
)
368 (push (cons (second def
)
369 (resolve-entities-in-string
370 (string-rod (third def
))
373 ((eq (car def
) 'defelement
)
374 (process-def-element dtd
375 (second def
) (third def
) (fourth def
) (fifth def
) (sixth def
)))
376 ((eq (car def
) 'defattlist
)
377 (process-def-attlist dtd
(second def
) (third def
)))
379 (error "Bogus dtd-def-form ~S" def
))))
381 ;;; Uhu! CDATA seems also to been a defined content element. E.g. upon
382 ;;; STYLE in the HTML-4.0 DTD.
385 ;;;; ------------------------------------------------------------------------------------------
386 ;;;; SGML resources (how is this called in reality?)
389 (defvar *simple-catalog
* nil
)
391 (defun open-sgml-resource (name-space &rest more
)
393 (:system
(apply #'open-system-resource more
))
394 (:public
(apply #'open-public-resource more
))
395 (:cdata
(apply #'make-string-input-stream more
)) ))
397 (defun open-system-resource (filename)
398 (open filename
:direction
:input
))
400 (defun open-public-resource (name &optional system-fallback
)
401 (open-sgml-resource :system
402 (cdr (or (assoc name
*simple-catalog
* :test
#'string-equal
)
404 (error "I do not know where to fetch PUBLIC \"~A\"." name
)))))
407 (defun slurp-catalog (catalog-url)
408 ;; Really dirty implementation
409 (setf *simple-catalog
* nil
)
410 (multiple-value-bind (io header
) (netlib::open-document-2 catalog-url
)
411 (declare (ignore header
))
413 (let ((str (html-glisp::gstream-as-string io
)))
414 (with-input-from-string (input str
)
415 (do ((x (read input nil nil
) (read input nil nil
)))
417 (assert (equal (symbol-name x
) "PUBLIC"))
418 (let ((name (read input
))
420 (assert (stringp name
))
421 (assert (stringp file
))
422 (push (cons name
(url:merge-url
(url:parse-url file
) catalog-url
))
423 *simple-catalog
*)))))
426 ;;;; ------------------------------------------------------------------------------------------
428 #+(OR) ;seems to be buggy
429 (defun sgml-resource-as-string (name)
430 (with-open-stream (in (apply #'open-sgml-resource name
))
431 (let ((buffer (g/make-string
32 :adjustable t
)))
433 (j (html-glisp:read-char-sequence buffer in
:start
0 :end
32)
434 (html-glisp:read-char-sequence buffer in
:start i
:end
(+ i
4000)) ))
435 ((= j i
) (subseq buffer
0 j
))
436 (princ "%") (finish-output)
437 (adjust-array buffer
(list (+ j
4000))) ))))
439 (defun sgml-resource-as-string (name)
440 (with-output-to-string (bag)
441 (with-open-stream (in (apply #'open-sgml-resource name
))
442 (do ((x (read-char in nil nil
) (read-char in nil nil
)))
444 (write-char x bag
)))))
448 ;;;; ------------------------------------------------------------------------------------------
449 ;;;; Calculating the resolve information
457 (defstruct (tag (:include token
))
460 (defstruct (start-tag (:include tag
) (:print-function print-start-tag
))
463 (defstruct (end-tag (:include tag
) (:print-function print-end-tag
)))
465 (defstruct (comment-token (:include token
))
469 (defstruct (empty-tag
471 (:print-function print-empty-tag
))
475 (defun print-start-tag (self sink depth
)
476 (declare (ignore depth
))
477 (cond (*print-readably
*
478 (format sink
"#.~S" `(MAKE-START-TAG :NAME
,(tag-name self
)
479 :ATTS
,(start-tag-atts self
))))
481 (format sink
"<~A>" (tag-name self
)))))
483 (defun print-end-tag (self sink depth
)
484 (declare (ignore depth
))
485 (cond (*print-readably
*
486 (format sink
"#.~S" `(MAKE-END-TAG :NAME
,(tag-name self
))))
488 (format sink
"</~A>" (tag-name self
)))))
492 (defun elm-stag (elm)
493 (make-start-tag :name elm
))
495 (defun elm-etag (elm)
496 (make-end-tag :name elm
))
498 (defun find-dtd-top-elements (dtd)
499 (or (dtd-root-elements dtd
)
500 (setf (dtd-root-elements dtd
)
503 (maphash (lambda (key val
)
505 (dolist (k (element-include val
))
506 (pushnew k includes
)))
508 (set-difference tags includes
)))))
510 (defun elm-inclusion (dtd x
)
512 (find-dtd-top-elements dtd
)) ;;'(:html))
514 (element-include (find-element dtd x
)))))
516 (defun elm-oend?
(dtd x
)
522 (element-oend?
(find-element dtd x
)))))
524 (defun elm-ostart?
(dtd x
)
527 (element-obegin?
(find-element dtd x
))))
529 (defun all-elms (dtd)
531 (maphash (lambda (n i
)
537 (defun elm-surclusion (dtd e
)
538 "For a given element 'e' calculate the surclusion, that is the set of all
539 elements, which may contain `e' as direct child."
540 (or (gethash e
(dtd-elm-surclusion-cache dtd
))
541 (setf (gethash e
(dtd-elm-surclusion-cache dtd
))
545 (loop for k in
(all-elms dtd
)
546 when
(member e
(elm-inclusion dtd k
))
549 (defun legal-in-p (dtd s x
)
550 (cond ((start-tag-p x
)
551 (member (tag-name x
) (elm-inclusion dtd s
)))
553 (eq s
(tag-name x
))) ))
555 ;;; Actual calculation of resolve information
557 (defun raux (dtd s x yet
)
559 (cond ((member s yet
)
561 ((legal-in-p dtd s x
)
565 (dolist (a (elm-inclusion dtd s
))
566 (when (and (elm-ostart? dtd a
)
567 (setq q
(raux dtd a x
(cons s yet
))))
568 (cond ((and (end-tag-p (car q
))
569 (eql (tag-name (car q
)) a
))
570 '(warn "RAUX: s=~S x=~S yet=~S -> a=~S" s x yet a
))
572 (pushnew (elm-stag a
) res
:key
#'tag-name
)))))
573 (when (elm-oend? dtd s
)
574 (dolist (z (elm-surclusion dtd s
))
575 (when (raux dtd z x
(cons s yet
))
576 (pushnew (elm-etag s
) res
:key
#'tag-name
))))
579 (defun resolve-key (state token
)
580 (cond ((start-tag-p token
)
581 (list state
:start
(tag-name token
)))
583 (list state
:end
(tag-name token
)))
585 (error "oops in resolve-key ~S ~S" state token
))))
587 (defun calculate-resolve-info (dtd &optional
(top-elment :html
))
588 (setf (dtd-resolve-info dtd
)
589 (make-hash-table :test
#'equal
))
590 (setf (dtd-elm-surclusion-cache dtd
) (make-hash-table :test
#'eq
))
592 (labels ((puta (a b r
)
595 (setf (gethash (resolve-key a b
) (dtd-resolve-info dtd
)) (car r
)))
597 (warn "Ambiguous : ~S ~S." a b
)))))
598 (dolist (a (cons ':%top
(all-elms dtd
)))
599 (princ "*") (finish-output)
600 (dolist (b (cons ':%top
(all-elms dtd
)))
601 (let ((bs (elm-stag b
))
603 (unless (legal-in-p dtd a bs
)
604 (puta a bs
(raux dtd a bs nil
)))
605 (unless (legal-in-p dtd a be
)
606 (puta a be
(raux dtd a be nil
)))))))) )
608 (defun resolve (dtd state token
)
609 (gethash (resolve-key state token
) (dtd-resolve-info dtd
)))
611 ;;; -------------------------------------------------------------------------------------------
613 (defun set-equal (x y
&rest options
)
614 (null (apply #'set-exclusive-or x y options
)))
616 (defun elms-eqv (dtd x y
)
617 ;; zwei elms sind genau dann aequivalent, wenn inclusion und surclusion gleich sind.
618 (and (set-equal (elm-inclusion dtd x
) (elm-inclusion dtd y
))
619 (set-equal (elm-surclusion dtd x
) (elm-surclusion dtd y
))
620 (equal (elm-oend? dtd x
) (elm-oend? dtd x
))
621 (equal (elm-ostart? dtd x
) (elm-ostart? dtd x
))))
623 (defun eqv-classes (dtd)
625 (dolist (k (all-elms dtd
))
626 (do ((q classes
(cdr q
)))
628 (push (list k
) classes
))
629 (when (elms-eqv dtd k
(caar q
))
630 (setf (car q
) (cons k
(car q
)))
634 ;;;; ----------------------------------------------------------------------------------------------------
638 ;; Since parsing and 'compiling' DTDs is slow, I'll provide for a way
639 ;; to (un)dump compiled DTD to stream.
641 (defun dump-dtd (dtd sink
)
642 (let ((*print-pretty
* nil
)
647 `(MAKE-DTD :NAME
',(dtd-name dtd
)
648 :ELEMENTS
(LET ((R (MAKE-HASH-TABLE :TEST
#'EQ
)))
649 (SETF ,@(let ((q nil
))
650 (maphash (lambda (key value
)
652 (push `(GETHASH ',key R
) q
))
656 :ENTITIES
',(dtd-entities dtd
)
657 :RESOLVE-INFO
(LET ((R (MAKE-HASH-TABLE :TEST
#'EQUAL
)))
658 (SETF ,@(let ((q nil
))
659 (maphash (lambda (key value
)
661 (push `(GETHASH ',key R
) q
))
662 (dtd-resolve-info dtd
))
665 ;; XXX surclusion-cache fehlt
670 (defun save-html-dtd ()
671 (with-open-file (sink "html-dtd.lisp" :direction
:output
:if-exists
:new-version
)
672 (print `(in-package :sgml
) sink
)
673 (let ((*package
* (find-package :sgml
)))
674 (princ "(SETQ " sink
)
675 (prin1 'cl-user
::*html-dtd
* sink
)
677 (dump-dtd cl-user
::*html-dtd
* sink
)
680 ;;; --------------------------------------------------------------------------------
684 (defun dump-dtd (dtd filename
)
686 (declare (special *foo
*))
687 (with-open-file (sink (merge-pathnames filename
"*.lisp")
689 :if-exists
:new-version
)
690 (format sink
"(in-package :sgml)(locally (declare (special *foo*))(setq *foo* '#.*foo*))"))
691 (compile-file (merge-pathnames filename
"*.lisp"))))
693 (defun undump-dtd (filename)
695 (declare (special *foo
*))
696 (load (compile-file-pathname (merge-pathnames filename
"*.lisp"))
701 (defmethod make-load-form ((self dtd
) &optional env
)
702 (declare (ignore env
))
703 `(make-dtd :name
',(dtd-name self
)
704 :elements
',(dtd-elements self
)
705 :entities
',(dtd-entities self
)
706 :resolve-info
',(dtd-resolve-info self
)
707 :elm-surclusion-cache
',(dtd-elm-surclusion-cache self
)
708 :root-elements
',(dtd-root-elements self
)))
710 (defmethod make-load-form ((self element
) &optional env
)
711 (declare (ignore env
))
713 :name
',(element-name self
)
714 :include
',(element-include self
)
715 :exclude
',(element-exclude self
)
716 :obegin?
',(element-obegin? self
)
717 :oend?
',(element-oend? self
)
718 :attlist
',(element-attlist self
)))
720 (defmethod make-load-form ((self tag
) &optional env
)
721 (declare (ignore env
))
722 `(make-tag :name
',(tag-name self
)))
724 (defmethod make-load-form ((self start-tag
) &optional env
)
725 (declare (ignore env
))
726 `(make-start-tag :name
',(tag-name self
)
727 :atts
',(start-tag-atts self
)))
729 (defmethod make-load-form ((self end-tag
) &optional env
)
730 (declare (ignore env
))
731 `(make-end-tag :name
',(tag-name self
)))
733 (defmethod make-load-form ((self comment-token
) &optional env
)
734 (declare (ignore env
))
735 `(make-comment-token :data
',(comment-token-data self
)))
739 (defmethod my-make-load-form ((self dtd
))
740 (declare (ignore env
))
741 `(make-dtd :name
,(my-make-load-form (dtd-name self
))
742 :elements
,(my-make-load-form (dtd-elements self
))
743 :entities
,(my-make-load-form (dtd-entities self
))
744 :resolve-info
,(my-make-load-form (dtd-resolve-info self
))
745 :elm-surclusion-cache
,(my-make-load-form (dtd-elm-surclusion-cache self
))
746 :root-elements
,(my-make-load-form (dtd-root-elements self
))))
748 (defmethod my-make-load-form ((self element
))
749 (declare (ignore env
))
751 :name
,(my-make-load-form (element-name self
))
752 :include
,(my-make-load-form (element-include self
))
753 :exclude
,(my-make-load-form (element-exclude self
))
754 :obegin?
,(my-make-load-form (element-obegin? self
))
755 :oend?
,(my-make-load-form (element-oend? self
))
756 :attlist
,(my-make-load-form (element-attlist self
))))
758 (defmethod my-make-load-form ((self tag
))
759 (declare (ignore env
))
760 `(make-tag :name
,(my-make-load-form (tag-name self
))))
762 (defmethod my-make-load-form ((self start-tag
))
763 (declare (ignore env
))
764 `(make-start-tag :name
,(my-make-load-form (tag-name self
))
765 :atts
,(my-make-load-form (start-tag-atts self
))))
767 (defmethod my-make-load-form ((self end-tag
))
768 (declare (ignore env
))
769 `(make-end-tag :name
,(my-make-load-form (tag-name self
))))
771 (defmethod my-make-load-form ((self comment-token
))
772 (declare (ignore env
))
773 `(make-comment-token :data
,(my-make-load-form (comment-token-data self
))))
775 (defmethod my-make-load-form ((object cons
))
777 (do ((q object
(cdr q
)))
780 `(list ,@(reverse yet
))
781 `(list* ,@(reverse yet
) ,(my-make-load-form q
))))
782 (push (my-make-load-form (car q
)) yet
))))
784 (defmethod my-make-load-form ((object string
))
787 (defmethod my-make-load-form ((object vector
))
788 `(make-array ,(length object
)
789 :element-type
',(array-element-type object
)
790 :initial-contents
,(my-make-load-form (coerce object
'list
))))
792 (defmethod my-make-load-form ((object symbol
))
793 (cond ((keywordp object
) object
)
794 ((eq object nil
) nil
)
797 (defmethod my-make-load-form ((object number
))
800 (defmethod my-make-load-form ((object hash-table
))
801 `(let ((res (make-hash-table :test
',(hash-table-test object
))))
803 (maphash (lambda (key value
)
804 (push `(gethash ,(my-make-load-form key
) res
) todo
)
805 (push (my-make-load-form value
) todo
))
810 (defun dump-dtd (dtd filename
)
811 (with-open-file (sink filename
813 :if-exists
:new-version
)
814 (with-standard-io-syntax
815 (let ((*package
* (find-package :cl
)))
816 (print (my-make-load-form dtd
) sink
))))
823 (defun dump-dtd (dtd filename
)
824 (with-open-file (sink filename
826 :if-exists
:new-version
827 :element-type
'(unsigned-byte 8))
828 (with-standard-io-syntax
829 (let ((*package
* (find-package :cl
)))
830 (excl:fasl-write dtd sink
))))
833 (defun undump-dtd (filename)
834 (first (excl:fasl-read
(open filename
:element-type
'(unsigned-byte 8)))))