1 ;;;; psgml-dtd.el --- DTD parser for SGML-editing mode with parsing support
2 ;; $Id: psgml-dtd.el,v 2.30 2003/03/25 19:46:09 lenst Exp $
4 ;; Copyright (C) 1994 Lennart Staflin
6 ;; Author: Lennart Staflin <lenst@lysator.liu.se>
8 ;; This program is free software; you can redistribute it and/or
9 ;; modify it under the terms of the GNU General Public License
10 ;; as published by the Free Software Foundation; either version 2
11 ;; of the License, or (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 ;; Part of major mode for editing the SGML document-markup language.
32 (require 'psgml-parse)
33 (eval-when-compile (require 'cl))
37 ;; Variables used during doctype parsing and loading
38 (defvar sgml-used-pcdata nil
39 "True if model group built is mixed.")
42 ;;;; Constructing basic
44 (defun sgml-copy-moves (s1 s2)
45 "Copy all moves from S1 to S2, keeping their status."
46 (let ((l (sgml-state-opts s1)))
49 (sgml-move-token (car l))
50 (sgml-move-dest (car l)))
52 (setq l (sgml-state-reqs s1))
55 (sgml-move-token (car l))
56 (sgml-move-dest (car l)))
59 (defun sgml-copy-moves-to-opt (s1 s2)
60 "Copy all moves from S1 to S2 as optional moves."
61 (let ((l (sgml-state-opts s1)))
64 (sgml-move-token (car l))
65 (sgml-move-dest (car l)))
67 (setq l (sgml-state-reqs s1))
70 (sgml-move-token (car l))
71 (sgml-move-dest (car l)))
75 (defun sgml-some-states-of (state)
76 ;; List of some states reachable from STATE, includes all final states
77 (let* ((states (list state))
82 ms (append (sgml-state-opts s) (sgml-state-reqs s)))
84 (setq m (sgml-move-dest (car ms))
86 (unless (sgml-normal-state-p m)
87 (setq m (sgml-and-node-next m)))
88 (unless (memq m states)
89 (nconc states (list m))))
93 (defmacro sgml-for-all-final-states (s dfa &rest forms)
94 "For all final states S in DFA do FORMS.
95 Syntax: var dfa-expr &body forms"
96 (` (let ((L-states (sgml-some-states-of (, dfa)))
99 (when (sgml-state-final-p (setq (, s) (car L-states)))
101 (setq L-states (cdr L-states))))))
103 (put 'sgml-for-all-final-states 'lisp-indent-hook 2)
104 (put 'sgml-for-all-final-states 'edebug-form-hook '(symbolp &rest form))
107 ;;;; Optimization for the dfa building
109 (defsubst sgml-empty-state-p (s)
110 "True if S has no outgoing moves."
111 (and (sgml-normal-state-p s)
112 (null (sgml-state-reqs s))
113 (null (sgml-state-opts s))) )
115 (defun sgml-one-final-state (s)
116 "Collapse all states that have no moves.
117 This is a safe optimization, useful for (..|..|..)."
118 (sgml-debug "OPT one final: reqs %d opts %d"
119 (length (sgml-state-reqs s))
120 (length (sgml-state-opts s)))
123 (loop for m in (append (sgml-state-reqs s)
126 (setq dest (sgml-move-dest m))
127 (when (sgml-empty-state-p dest)
131 (setf (sgml-move-dest m) final)))))))
133 (defun sgml-states-equal (s1 s2)
134 (and (= (length (sgml-state-opts s1))
135 (length (sgml-state-opts s2)))
136 (= (length (sgml-state-reqs s1))
137 (length (sgml-state-reqs s2)))
138 (loop for m in (sgml-state-opts s1)
140 (eq (sgml-move-dest m)
141 (sgml-move-dest (sgml-moves-lookup (sgml-move-token m)
142 (sgml-state-opts s2)))))
143 (loop for m in (sgml-state-reqs s1)
145 (eq (sgml-move-dest m)
146 (sgml-move-dest (sgml-moves-lookup (sgml-move-token m)
147 (sgml-state-reqs s2)))))))
149 (defun sgml-remove-redundant-states-1 (s)
150 ;; Remove states accessible from s with one move and equivalent to s,
151 ;; by changing the moves from s.
152 (sgml-debug "OPT redundant-1: reqs %d opts %d"
153 (length (sgml-state-reqs s))
154 (length (sgml-state-opts s)))
157 (l (sgml-state-reqs s))
158 (nl (sgml-state-opts s))
160 (while (or l (setq l (prog1 nl (setq nl nil))))
162 ((not (sgml-normal-state-p (setq dest (sgml-move-dest (car l))))))
165 ((sgml-states-equal s dest)
166 (progn (push dest yes))))
168 (setq l (sgml-state-opts s)
169 nl (sgml-state-reqs s))
171 (sgml-debug "OPT redundant-1: success %s" (length yes))
172 (while (or l (setq l (prog1 nl (setq nl nil))))
173 (cond ((memq (sgml-move-dest (car l)) yes)
174 (setf (sgml-move-dest (car l)) s)))
181 (defun sgml-make-opt (s1)
182 (when (sgml-state-reqs s1)
183 (setf (sgml-state-opts s1)
184 (nconc (sgml-state-opts s1)
185 (sgml-state-reqs s1)))
186 (setf (sgml-state-reqs s1) nil))
189 (defun sgml-make-* (s1)
190 (setq s1 (sgml-make-+ s1))
191 (when (sgml-state-reqs s1)
193 (sgml-remove-redundant-states-1 s1)
196 (defun sgml-make-+ (s1)
197 (sgml-for-all-final-states s s1
198 (sgml-copy-moves-to-opt s1 s))
199 (sgml-remove-redundant-states-1 s1) ; optimize
202 (defun sgml-make-conc (s1 s2)
203 (let ((moves (append (sgml-state-reqs s1) (sgml-state-opts s1))))
205 (;; optimize the case where all moves from s1 goes to empty states
207 always (sgml-empty-state-p (sgml-move-dest m)))
208 (loop for m in moves do (setf (sgml-move-dest m) s2))
209 (when (sgml-state-final-p s1)
210 (sgml-copy-moves s2 s1)))
212 (sgml-for-all-final-states s s1
213 (sgml-copy-moves s2 s)
214 (sgml-remove-redundant-states-1 s)))))
217 (defun sgml-make-pcdata ()
218 (sgml-make-* (sgml-make-primitive-content-token sgml-pcdata-token)))
220 (defun sgml-reduce-, (l)
223 (sgml-make-conc (car l) (cadr l)))
227 (defun sgml-reduce-| (l)
228 (while (cdr l) ; apply the binary make-alt
229 (cond ((or (sgml-state-final-p (car l)) ; is result optional
230 (sgml-state-final-p (cadr l)))
231 (sgml-make-opt (car l))
232 (sgml-copy-moves-to-opt (cadr l) (car l)))
234 (sgml-copy-moves (cadr l) (car l))))
236 (sgml-one-final-state (car l)) ; optimization
239 (defun sgml-make-& (dfas)
240 (let ((&n (sgml-make-and-node dfas (sgml-make-state)))
241 (s (sgml-make-state))
243 (while l ; For each si:
244 ;; For m in opts(si): add optional move from s to &n on token(m).
245 (loop for m in (sgml-state-opts (car l))
246 do (sgml-add-opt-move s (sgml-move-token m) &n))
247 ;; For m in reqs(si): add required move from s to &n on token(m).
248 (loop for m in (sgml-state-reqs (car l))
249 do (sgml-add-req-move s (sgml-move-token m) &n))
256 ;(sgml-make-conc (sgml-make-primitive-content-token 'para) (sgml-make-primitive-content-token 'list))
257 ;(sgml-make-conc (sgml-make-& (list (sgml-make-primitive-content-token 'para) (sgml-make-primitive-content-token 'list))) (sgml-make-primitive-content-token 'foo))
259 ;(setq x (sgml-some-states-of (sgml-make-primitive-content-token 'para)))
260 ;(sgml-state-final-p (car x) )
261 ;(sgml-state-final-p (cadr x))
264 ;;;; Parse doctype: General
266 (defun sgml-skip-ts ()
268 ;;70 ts = 5 s | EE | 60+ parameter entity reference
269 ;;For simplicity I use ps*
270 ;;65 ps = 5 s | EE | 60+ parameter entity reference | 92 comment
271 ;;*** some comments are accepted that shouldn't
274 (defun sgml-parse-character-reference (&optional dofunchar)
275 ;; *** Actually only numerical character references
276 ;; I don't know how to handel the function character references.
277 ;; For the shortrefs let's give them numeric values.
279 (sgml-parse-delim "CRO" (digit nmstart))
280 (sgml-parse-delim "CRO" (digit)))
281 (prog1 (if (sgml-is-delim "NULL" digit)
282 (string-to-int (sgml-check-nametoken))
283 (let ((spec (sgml-check-name)))
284 (or (cdr (assoc spec '(("RE" . 10)
288 ;; *** What to do with other names?
290 (or (sgml-parse-delim "REFC")
293 (defun sgml-parse-parameter-literal (&optional dofunchar)
294 (let* (lita ; flag if lita
295 (value ; accumulates literals value
297 (original-buffer ; Buffer (entity) where lit started
301 ((or (sgml-parse-delim "LIT")
302 (setq lita (sgml-parse-delim "LITA")))
303 (while (not (and (eq (current-buffer) original-buffer)
305 (sgml-parse-delim "LITA")
306 (sgml-parse-delim "LIT"))))
308 (or (sgml-pop-entity)
309 (sgml-error "Parameter literal unterminated")))
310 ((sgml-parse-parameter-entity-ref))
311 ((setq temp (sgml-parse-character-reference dofunchar))
315 ;; XEmacs: test if bound
317 (boundp 'enable-multibyte-characters)
318 enable-multibyte-characters
319 (fboundp 'unibyte-char-to-multibyte))
320 (setq temp (unibyte-char-to-multibyte temp)))
323 (format "&#%d;" temp))))))
327 (buffer-substring-no-properties
329 (progn (forward-char 1)
331 (sgml-skip-upto ("LITA" "PERO" "CRO"))
332 (sgml-skip-upto ("LIT" "PERO" "CRO")))
336 (defun sgml-check-parameter-literal ()
337 (or (sgml-parse-parameter-literal)
338 (sgml-parse-error "Parameter literal expected")))
340 (defsubst sgml-parse-connector ()
342 (cond ((sgml-parse-delim "SEQ")
343 (function sgml-reduce-,))
344 ((sgml-parse-delim "OR")
345 (function sgml-reduce-|))
346 ((sgml-parse-delim "AND")
348 (sgml-error "XML forbids AND connector")
349 (function sgml-make-&)))))
351 (defun sgml-parse-name-group ()
352 "Parse a single name or a name group (general name case) .
353 Returns a list of strings or nil."
356 ((sgml-parse-delim "GRPO")
358 (setq names (sgml-parse-name-group)) ; *** Allows more than it should
359 (while (sgml-parse-connector)
361 (nconc names (sgml-parse-name-group)))
362 (sgml-check-delim "GRPC")
364 ((setq names (sgml-parse-name))
367 (defun sgml-check-name-group ()
368 (or (sgml-parse-name-group)
369 (sgml-parse-error "Expecting a name or a name group")))
371 (defun sgml-check-nametoken-group ()
372 "Parse a name token group, return a list of strings.
373 Case transformed for general names."
377 ((sgml-parse-delim GRPO)
380 (push (sgml-general-case (sgml-check-nametoken)) names)
381 (sgml-parse-connector)))
382 (sgml-check-delim GRPC)
383 (nreverse names)) ; store in same order as declared
385 (list (sgml-general-case (sgml-check-nametoken)))))))
387 (defun sgml-check-element-type ()
388 "Parse and check an element type, return list of strings."
389 ;;; 117 element type = [[30 generic identifier]]
390 ;;; | [[69 name group]]
391 ;;; | [[118 ranked element]]
392 ;;; | [[119 ranked group]]
394 ((sgml-parse-delim GRPO)
396 (sgml-error "XML forbids name groups for the element type"))
398 (let ((names (list (sgml-check-name))))
399 (while (progn (sgml-skip-ts)
400 (sgml-parse-connector))
402 (nconc names (list (sgml-check-name))))
403 (sgml-check-delim GRPC)
404 ;; A ranked group will have a rank suffix here
406 (if (sgml-is-delim "NULL" digit)
407 (let ((suffix (sgml-parse-nametoken)))
409 collect (concat n suffix)))
411 (t ; gi/ranked element
412 (let ((name (sgml-check-name)))
414 (list (if (sgml-is-delim "NULL" digit)
415 (concat name (sgml-check-nametoken))
419 (defun sgml-check-external (&optional pubid-ok)
420 (or (sgml-parse-external pubid-ok)
421 (sgml-parse-error "Expecting a PUBLIC or SYSTEM")))
423 ;;;; Parse doctype: notation
425 (defun sgml-declare-notation ()
426 ;;148 notation declaration = MDO, "NOTATION",
427 ;; 65 ps+, 41 notation name,
428 ;; 65 ps+, 149 notation identifier,
430 ;;41 notation name = 55 name
431 ;;149 notation identifier = 73 external identifier
435 (sgml-check-external t))
438 ;;;; Parse doctype: Element
440 (defun sgml-parse-opt ()
442 (cond ((or (sgml-parse-char ?o)
443 (sgml-parse-char ?O))
445 (sgml-error "XML forbids omitted tag minimization.")
447 ((sgml-parse-char ?-)
449 (sgml-error "XML forbids omitted tag minimization")
452 (defun sgml-parse-modifier ()
453 (cond ((sgml-parse-delim "PLUS")
454 (function sgml-make-+))
455 ((sgml-parse-delim "REP")
456 (function sgml-make-*))
457 ((sgml-parse-delim "OPT")
458 (function sgml-make-opt))))
460 (defun sgml-check-primitive-content-token ()
461 (sgml-make-primitive-content-token
464 (sgml-check-name)))))
466 (defun sgml-check-model-group ()
470 ((sgml-parse-delim "GRPO")
471 (let ((subs (list (sgml-check-model-group)))
474 (while (setq con2 (sgml-parse-connector))
476 (not (eq con1 con2)))
477 (sgml-parse-error "Mixed connectors")))
479 (setq subs (nconc subs (list (sgml-check-model-group)))))
480 (sgml-check-delim "GRPC")
484 ((sgml-parse-rni "PCDATA") ; #PCDATA (FIXME: when changing case)
485 (setq sgml-used-pcdata t)
486 (setq el (sgml-make-pcdata)))
487 ((sgml-parse-delim "DTGO") ; data tag group
489 (sgml-error "XML forbids DATATAG"))
491 (let ((tok (sgml-check-primitive-content-token)))
492 (sgml-skip-ts) (sgml-check-delim "SEQ")
493 (sgml-skip-ts) (sgml-check-data-tag-pattern)
494 (sgml-skip-ts) (sgml-check-delim "DTGC")
495 (setq el (sgml-make-conc tok (sgml-make-pcdata)))
496 (setq sgml-used-pcdata t)))
498 (setq el (sgml-check-primitive-content-token))))
499 (setq mod (sgml-parse-modifier))
504 (defun sgml-check-data-tag-pattern ()
505 ;; 134 data tag pattern
506 ;; template | template group
507 (cond ((sgml-parse-delim GRPO)
509 (sgml-check-parameter-literal) ; data tag template,
510 (while (progn (sgml-skip-ts)
511 (sgml-parse-delim OR))
513 (sgml-check-parameter-literal)) ; data tag template
515 (sgml-check-delim GRPC))
517 (sgml-check-parameter-literal))) ; data tag template
519 (when (sgml-parse-delim SEQ)
520 (sgml-check-parameter-literal))) ; data tag padding template
522 (defun sgml-check-content-model ()
523 (sgml-check-model-group))
525 (defun sgml-check-content ()
527 (cond ((sgml-is-delim GRPO)
528 (sgml-check-content-model))
530 ;; ANY, CDATA, RCDATA or EMPTY
531 (let ((dc (intern (sgml-check-case (sgml-check-name)))))
533 (setq sgml-used-pcdata t))
536 (sgml-error "XML forbids CDATA declared content")))
539 (sgml-error "XML forbids RCDATA declared content")))
542 (sgml-error "Exptected content model group or one of %s"
545 "ANY, CDATA, RCDATA or EMPTY"))))
548 (defun sgml-parse-exception (type)
550 (if (sgml-parse-char type)
552 (sgml-error "XML forbids inclusion and exclusion exceptions")
553 (mapcar (function sgml-lookup-eltype)
554 (sgml-check-name-group)))))
556 (defun sgml-before-eltype-modification ()
557 ;;; (let ((merged (sgml-dtd-merged sgml-dtd-info)))
558 ;;; (when (and merged
559 ;;; (eq (sgml-dtd-eltypes sgml-dtd-info)
560 ;;; (sgml-dtd-eltypes (cdr merged))))
561 ;;; (setf (sgml-dtd-eltypes sgml-dtd-info)
562 ;;; (sgml-merge-eltypes (sgml-make-eltypes-table)
563 ;;; (sgml-dtd-eltypes sgml-dtd-info)))))
566 (defun sgml-declare-element ()
567 (let* ((names (sgml-check-element-type))
568 (stag-opt (sgml-parse-opt))
569 (etag-opt (sgml-parse-opt))
570 (sgml-used-pcdata nil)
571 (model (sgml-check-content))
572 (exclusions (sgml-parse-exception ?-))
573 (inclusions (sgml-parse-exception ?+)))
574 (sgml-before-eltype-modification)
576 (sgml-debug "Defining element %s" (car names))
577 (let ((et (sgml-lookup-eltype (car names))))
578 (setf (sgml-eltype-stag-optional et) stag-opt
579 (sgml-eltype-etag-optional et) etag-opt
580 (sgml-eltype-model et) model
581 (sgml-eltype-mixed et) sgml-used-pcdata
582 (sgml-eltype-excludes et) exclusions
583 (sgml-eltype-includes et) inclusions))
584 (setq names (cdr names)))
585 (sgml-lazy-message "Parsing doctype (%s elements)..."
586 (incf sgml-no-elements))))
588 ;;;; Parse doctype: Entity
590 (defun sgml-declare-entity ()
591 (let (name ; Name of entity
593 (type 'text) ; Type of entity
594 (notation nil) ; Notation of entity
595 text ; Text of entity
599 ((sgml-parse-delim "PERO") ; parameter entity declaration
601 (setq name (sgml-check-name t))
602 (setq dest (sgml-dtd-parameters sgml-dtd-info)))
603 (t ; normal entity declaration
604 (or (sgml-parse-rni "DEFAULT")
605 (setq name (sgml-check-name t)))
606 (setq dest (sgml-dtd-entities sgml-dtd-info))))
608 ;;105 entity text = 66 parameter literal
610 ;; | 107 bracketed text
611 ;; | 108 external entity specification
612 (setq extid (sgml-parse-external))
615 (extid ; external entity specification =
616 ; 73 external identifier,
617 ; (65 ps+, 109+ entity type)?
619 (let ((tn (sgml-parse-entity-type)))
620 (setq type (or (car tn) 'text))
621 (unless (eq (cdr tn) "")
622 (setq notation (cdr tn))))
624 ((sgml-startnm-char-next)
625 (let ((token (intern (sgml-check-case (sgml-check-name)))))
627 (when (and sgml-xml-p
628 (memq token '(CDATA SDATA PI STARTTAG ENDTAG MS MD)))
629 (sgml-error "XML forbids %s entities"
630 (upcase (symbol-name token))))
632 ((memq token '(CDATA SDATA)) ; data text ***
634 (sgml-check-parameter-literal))
636 (concat "<?" (sgml-check-parameter-literal) ">"))
637 ((eq token 'STARTTAG)
638 (sgml-start-tag-of (sgml-check-parameter-literal)))
640 (sgml-end-tag-of (sgml-check-parameter-literal)))
641 ((eq token 'MS) ; marked section
642 (concat "<![" (sgml-check-parameter-literal) "]]>"))
643 ((eq token 'MD) ; Markup declaration
644 (concat "<!" (sgml-check-parameter-literal) ">")))))
645 ((sgml-check-parameter-literal))))
647 (sgml-entity-declare name dest type text notation))))
650 (defun sgml-parse-entity-type ()
651 ;;109+ entity type = "SUBDOC"
652 ;; | (("CDATA" | "NDATA" | "SDATA"),
655 ;; 149.2+ data attribute specification?)
656 (let ((type (sgml-parse-name))
659 (setq type (intern (sgml-check-case type)))
660 (when (and sgml-xml-p (memq type '(SUBDOC CDATA SDATA)))
661 (sgml-error "XML forbids %s entities"
662 (upcase (symbol-name type))))
663 (cond ((eq type 'SUBDOC))
664 ((memq type '(CDATA NDATA SDATA))
666 (setq notation (sgml-parse-name))
667 ;;149.2+ data attribute specification
669 ;; 31 attribute specification list,
672 (when (sgml-parse-delim DSO)
673 (sgml-parse-attribute-specification-list)
675 (sgml-check-delim DSC)))
676 (t (sgml-error "Illegal entity type: %s" type))))
677 (cons type notation)))
680 ;;;; Parse doctype: Attlist
682 (defun sgml-declare-attlist ()
683 (let* ((assnot (cond ((sgml-parse-rni "NOTATION")
685 (sgml-error "XML forbids data attribute declarations"))
688 (assel (sgml-check-name-group))
691 (when (and sgml-xml-p (> (length assel) 1))
692 (sgml-error "XML forbids name groups for an associated element type"))
693 (while (setq attdef (sgml-parse-attribute-definition))
694 (push attdef attlist))
695 (setq attlist (nreverse attlist))
697 (sgml-before-eltype-modification)
698 (loop for elname in assel do
699 (setf (sgml-eltype-attlist (sgml-lookup-eltype elname))
702 (sgml-lookup-eltype elname))
705 (defun sgml-merge-attlists (old new)
706 (setq old (nreverse (copy-sequence old)))
707 (loop for att in new do
708 (unless (assoc (car att) old)
709 (setq old (cons att old))))
712 (defun sgml-parse-attribute-definition ()
714 (if (sgml-is-delim "MDC") ; End of attlist?
716 (sgml-make-attdecl (sgml-check-name)
717 (sgml-check-declared-value)
718 (sgml-check-default-value))))
720 (defun sgml-check-declared-value ()
722 (let ((type 'name-token-group)
724 (unless (eq (following-char) ?\()
725 (setq type (intern (sgml-check-case (sgml-check-name))))
726 (sgml-validate-declared-value type)
728 (when (memq type '(name-token-group NOTATION))
729 (setq names (sgml-check-nametoken-group)))
730 (sgml-make-declared-value type names)))
732 (defun sgml-validate-declared-value (type)
749 (sgml-error "Invalid attribute declared value: %s" type))
750 (when (and sgml-xml-p (memq type
751 '(NAME NAMES NUMBER NUMBERS NUTOKEN NUTOKENS)))
752 (sgml-error "XML forbids %s attributes" (upcase (symbol-name type)))))
754 (defun sgml-check-default-value ()
756 (let* ((rni (sgml-parse-rni))
757 (key (if rni (intern (sgml-check-case (sgml-check-name))))))
758 (if rni (sgml-validate-default-value-rn key))
760 (sgml-make-default-value
762 (if (or (not rni) (eq key 'FIXED))
763 (sgml-check-attribute-value-specification)))))
765 (defun sgml-validate-default-value-rn (rn)
766 (unless (memq rn '(REQUIRED FIXED CURRENT CONREF IMPLIED))
767 (sgml-error "Unknown reserved name: %s"
768 (upcase (symbol-name rn))))
769 (when (and sgml-xml-p (memq rn '(CURRENT CONREF)))
770 (sgml-error "XML forbids #%s attributes"
771 (upcase (symbol-name rn)))))
775 ;;;; Parse doctype: Shortref
777 ;;;150 short reference mapping declaration = MDO, "SHORTREF",
778 ;;; [[65 ps]]+, [[151 map name]],
779 ;;; ([[65 ps]]+, [[66 parameter literal]],
780 ;;; [[65 ps]]+, [[55 name]])+,
783 (defun sgml-declare-shortref ()
784 (let ((mapname (sgml-check-name))
785 mappings literal name)
788 (setq literal (sgml-parse-parameter-literal 'dofunchar)))
790 (setq name (sgml-check-name t))
791 (push (cons literal name) mappings))
792 (sgml-add-shortref-map
793 (sgml-dtd-shortmaps sgml-dtd-info)
795 (sgml-make-shortmap mappings))))
797 ;;;152 short reference use declaration = MDO, "USEMAP",
798 ;;; [[65 ps]]+, [[153 map specification]],
799 ;;; ([[65 ps]]+, [[72 associated element type]])?,
802 (defun sgml-do-usemap-element (mapname)
803 ;; This is called from sgml-do-usemap with the mapname
804 (sgml-before-eltype-modification)
805 (loop for e in (sgml-parse-name-group) do
806 (setf (sgml-eltype-shortmap (sgml-lookup-eltype e sgml-dtd-info))
814 (defun sgml-check-dtd-subset ()
815 (let ((sgml-parsing-dtd t)
816 (eref sgml-current-eref))
819 (setq sgml-markup-start (point))
821 ((and (eobp) (eq sgml-current-eref eref))
824 ((sgml-parse-markup-declaration 'dtd))
825 ((sgml-parse-delim "MS-END")))))))
828 ;;;; Save DTD: compute translation
830 (defvar sgml-translate-table nil)
832 (defun sgml-translate-node (node)
833 (assert (not (numberp node)))
834 (let ((tp (assq node sgml-translate-table)))
836 (setq tp (cons node (length sgml-translate-table)))
837 (nconc sgml-translate-table (list tp)))
840 (defun sgml-translate-moves (moves)
842 (sgml-translate-node (sgml-move-dest (car moves)))
843 (setq moves (cdr moves))))
845 (defun sgml-translate-model (model)
846 (let* ((sgml-translate-table (list (cons model 0)))
847 (p sgml-translate-table))
849 (cond ((sgml-normal-state-p (caar p))
850 (sgml-translate-moves (sgml-state-opts (caar p)))
851 (sgml-translate-moves (sgml-state-reqs (caar p))))
853 (sgml-translate-node (sgml-and-node-next (caar p)))))
855 sgml-translate-table))
857 ;;;; Save DTD: binary coding
859 (defvar sgml-code-token-numbers nil)
860 (defvar sgml-code-xlate nil)
862 (defsubst sgml-code-xlate (node)
863 ;;(let ((x (cdr (assq node sgml-code-xlate)))) (assert x) x)
864 (cdr (assq node sgml-code-xlate)))
866 (defun sgml-code-number (num)
867 (if (> num sgml-max-single-octet-number)
868 (insert (+ (lsh (- num sgml-max-single-octet-number) -8)
869 sgml-max-single-octet-number 1)
870 (logand (- num sgml-max-single-octet-number) 255))
873 (defun sgml-code-token-number (token)
874 (let ((bp (assq token sgml-code-token-numbers)))
876 (setq sgml-code-token-numbers
877 (nconc sgml-code-token-numbers
878 (list (setq bp (cons token
879 (length sgml-code-token-numbers)))))))
882 (defun sgml-code-token (token)
883 (sgml-code-number (sgml-code-token-number token)))
885 (defmacro sgml-code-sequence (loop-c &rest body)
886 "Produce the binary coding of a counted sequence from a list.
887 Syntax: (var seq) &body forms
888 FORMS should produce the binary coding of element in VAR."
889 (let ((var (car loop-c))
891 (` (let ((seq (, seq)))
892 (sgml-code-number (length seq))
893 (loop for (, var) in seq
896 (put 'sgml-code-sequence 'lisp-indent-hook 1)
897 (put 'sgml-code-sequence 'edbug-forms-hook '(sexp &rest form))
899 (defun sgml-code-sexp (sexp)
900 (let ((standard-output (current-buffer)))
904 (defun sgml-code-tokens (l)
905 (sgml-code-sequence (x l)
906 (sgml-code-token x)))
908 (defsubst sgml-code-move (m)
909 (sgml-code-token (sgml-move-token m))
910 (insert (sgml-code-xlate (sgml-move-dest m))))
912 (defun sgml-code-model (m)
913 (let ((sgml-code-xlate (sgml-translate-model m)))
914 (sgml-code-sequence (s sgml-code-xlate) ; s is (node . number)
915 (setq s (car s)) ; s is node
917 ((sgml-normal-state-p s)
918 (assert (and (< (length (sgml-state-opts s)) 255)
919 (< (length (sgml-state-reqs s)) 256)))
920 (sgml-code-sequence (x (sgml-state-opts s))
922 (sgml-code-sequence (x (sgml-state-reqs s))
925 (insert 255) ; Tag &-node
926 (insert (sgml-code-xlate (sgml-and-node-next s)))
927 (sgml-code-sequence (m (sgml-and-node-dfas s))
928 (sgml-code-model m)))))))
930 (defun sgml-code-element (et)
931 (sgml-code-sexp (sgml-eltype-all-miscdata et))
933 ((not (sgml-eltype-defined et))
936 (insert (sgml-eltype-flags et))
937 (let ((c (sgml-eltype-model et)))
938 (cond ((eq c sgml-cdata) (insert 0))
939 ((eq c sgml-rcdata) (insert 1))
940 ((eq c sgml-empty) (insert 2))
941 ((eq c sgml-any) (insert 3))
942 ((null c) (insert 4))
944 (assert (sgml-model-group-p c))
946 (sgml-code-model c))))
947 (sgml-code-tokens (sgml-eltype-includes et))
948 (sgml-code-tokens (sgml-eltype-excludes et)))))
951 (defun sgml-code-dtd (dtd)
952 "Produce the binary coding of the current DTD into the current buffer."
953 (sgml-code-sexp (sgml-dtd-dependencies dtd))
954 (sgml-code-sexp (sgml-dtd-parameters dtd))
955 (sgml-code-sexp (sgml-dtd-doctype dtd))
956 (let ((done 0) ; count written elements
958 (setq sgml-code-token-numbers nil)
959 (sgml-code-token-number sgml-pcdata-token) ; Make #PCDATA token 0
960 (sgml-map-eltypes ; Assign numbers to all tokens
961 (function (lambda (et)
962 (sgml-code-token-number (sgml-eltype-token et))))
964 (setq tot (length sgml-code-token-numbers))
965 ;; Produce the counted sequence of element type names
966 (sgml-code-sequence (pair (cdr sgml-code-token-numbers))
967 (sgml-code-sexp (sgml-eltype-name (car pair))))
968 ;; Produce the counted sequence of element types
969 (sgml-code-sequence (pair (cdr sgml-code-token-numbers))
970 (setq done (1+ done))
971 (sgml-code-element (car pair))
972 (sgml-lazy-message "Saving DTD %d%% done" (/ (* 100 done) tot)))
973 (sgml-code-sexp (sgml-dtd-entities dtd))
974 (sgml-code-sexp (sgml-dtd-shortmaps dtd))
975 (sgml-code-sexp (sgml-dtd-notations dtd))))
980 (defun sgml-save-dtd (file)
981 "Save the parsed dtd on FILE."
983 (let* ((tem (expand-file-name
984 (or sgml-default-dtd-file
985 (sgml-default-dtd-file))))
986 (dir (file-name-directory tem))
987 (nam (file-name-nondirectory tem)))
989 (read-file-name "Save DTD in: " dir tem nil nam))))
990 (setq file (expand-file-name file))
991 (when (equal file (buffer-file-name))
992 (error "Would clobber current file"))
994 (sgml-push-to-entity (sgml-make-entity "#SAVE" nil ""))
995 (sgml-write-dtd sgml-dtd-info file)
997 (setq sgml-default-dtd-file
998 (if (equal (expand-file-name default-directory)
999 (file-name-directory file))
1000 (file-name-nondirectory file)
1002 (setq sgml-loaded-dtd file))
1004 (defun sgml-write-dtd (dtd file)
1005 "Save the parsed DTD in FILE.
1006 Construct the binary coded DTD (bdtd) in the current buffer."
1007 (sgml-set-buffer-multibyte nil)
1009 ";;; This file was created by psgml on " (current-time-string)
1010 " -*-coding:binary-*-\n"
1011 "(sgml-saved-dtd-version 7)\n")
1012 (let ((print-escape-multibyte t))
1013 (sgml-code-dtd dtd))
1015 (let ((coding-system-for-write 'no-conversion))
1016 (write-region (point-min) (point-max) file)))
1019 ;;; psgml-dtd.el ends here