Mercurial > hg > xemacs-beta
comparison lisp/psgml/psgml-dtd.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;;; psgml-dtd.el --- DTD parser for SGML-editing mode with parsing support | |
2 ;; $Id: psgml-dtd.el,v 1.1.1.1 1996/12/18 03:35:19 steve Exp $ | |
3 | |
4 ;; Copyright (C) 1994 Lennart Staflin | |
5 | |
6 ;; Author: Lennart Staflin <lenst@lysator.liu.se> | |
7 | |
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. | |
12 ;; | |
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. | |
17 ;; | |
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. | |
21 | |
22 | |
23 ;;;; Commentary: | |
24 | |
25 ;; Part of major mode for editing the SGML document-markup language. | |
26 | |
27 | |
28 ;;;; Code: | |
29 | |
30 (provide 'psgml-dtd) | |
31 (require 'psgml) | |
32 (require 'psgml-parse) | |
33 | |
34 | |
35 ;;;; Variables | |
36 | |
37 ;; Variables used during doctype parsing and loading | |
38 (defvar sgml-used-pcdata nil | |
39 "True if model group built is mixed") | |
40 | |
41 | |
42 ;;;; Constructing basic | |
43 | |
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))) | |
47 (while l | |
48 (sgml-add-opt-move s2 | |
49 (sgml-move-token (car l)) | |
50 (sgml-move-dest (car l))) | |
51 (setq l (cdr l))) | |
52 (setq l (sgml-state-reqs s1)) | |
53 (while l | |
54 (sgml-add-req-move s2 | |
55 (sgml-move-token (car l)) | |
56 (sgml-move-dest (car l))) | |
57 (setq l (cdr l))))) | |
58 | |
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))) | |
62 (while l | |
63 (sgml-add-opt-move s2 | |
64 (sgml-move-token (car l)) | |
65 (sgml-move-dest (car l))) | |
66 (setq l (cdr l))) | |
67 (setq l (sgml-state-reqs s1)) | |
68 (while l | |
69 (sgml-add-opt-move s2 | |
70 (sgml-move-token (car l)) | |
71 (sgml-move-dest (car l))) | |
72 (setq l (cdr l))))) | |
73 | |
74 | |
75 (defun sgml-some-states-of (state) | |
76 ;; List of some states reachable from STATE, includes all final states | |
77 (let* ((states (list state)) | |
78 (l states) | |
79 s ms m) | |
80 (while l | |
81 (setq s (car l) | |
82 ms (append (sgml-state-opts s) (sgml-state-reqs s))) | |
83 (while ms | |
84 (setq m (sgml-move-dest (car ms)) | |
85 ms (cdr ms)) | |
86 (unless (sgml-normal-state-p m) | |
87 (setq m (sgml-&node-next m))) | |
88 (unless (memq m states) | |
89 (nconc states (list m)))) | |
90 (setq l (cdr l))) | |
91 states)) | |
92 | |
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))) | |
97 (, s)) | |
98 (while L-states | |
99 (when (sgml-state-final-p (setq (, s) (car L-states))) | |
100 (,@ forms)) | |
101 (setq L-states (cdr L-states)))))) | |
102 | |
103 (put 'sgml-for-all-final-states 'lisp-indent-hook 2) | |
104 (put 'sgml-for-all-final-states 'edebug-form-hook '(symbolp &rest form)) | |
105 | |
106 | |
107 ;;;; Optimization for the dfa building | |
108 | |
109 (defsubst sgml-empty-state-p (s) | |
110 ;; True if S hase no outgoing moves | |
111 (and (sgml-normal-state-p s) | |
112 (null (sgml-state-reqs s)) | |
113 (null (sgml-state-opts s))) ) | |
114 | |
115 (defun sgml-one-final-state (s) | |
116 ;; Collaps 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))) | |
121 (let ((final nil) | |
122 dest) | |
123 (loop for m in (append (sgml-state-reqs s) | |
124 (sgml-state-opts s)) | |
125 do | |
126 (setq dest (sgml-move-dest m)) | |
127 (when (sgml-empty-state-p dest) | |
128 (cond ((null final) | |
129 (setq final dest)) | |
130 (t | |
131 (setf (sgml-move-dest m) final))))))) | |
132 | |
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) | |
139 always | |
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) | |
144 always | |
145 (eq (sgml-move-dest m) | |
146 (sgml-move-dest (sgml-moves-lookup (sgml-move-token m) | |
147 (sgml-state-reqs s2))))))) | |
148 | |
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))) | |
155 (let ((yes nil) | |
156 (no (list s)) | |
157 (l (sgml-state-reqs s)) | |
158 (nl (sgml-state-opts s)) | |
159 (res s) | |
160 dest) | |
161 (while (or l (setq l (prog1 nl (setq nl nil)))) | |
162 (cond | |
163 ((not (sgml-normal-state-p (setq dest (sgml-move-dest (car l)))))) | |
164 ((memq dest no)) | |
165 ((memq dest yes)) | |
166 ((sgml-states-equal s dest) | |
167 (progn (push dest yes)))) | |
168 (setq l (cdr l))) | |
169 (setq l (sgml-state-opts s) | |
170 nl (sgml-state-reqs s)) | |
171 (when yes | |
172 (sgml-debug "OPT redundant-1: sucess %s" (length yes)) | |
173 (while (or l (setq l (prog1 nl (setq nl nil)))) | |
174 (cond ((memq (sgml-move-dest (car l)) yes) | |
175 (setf (sgml-move-dest (car l)) s))) | |
176 (setq l (cdr l)))))) | |
177 | |
178 | |
179 | |
180 ;;;; Constructing | |
181 | |
182 (defun sgml-make-opt (s1) | |
183 (when (sgml-state-reqs s1) | |
184 (setf (sgml-state-opts s1) | |
185 (nconc (sgml-state-opts s1) | |
186 (sgml-state-reqs s1))) | |
187 (setf (sgml-state-reqs s1) nil)) | |
188 s1) | |
189 | |
190 (defun sgml-make-* (s1) | |
191 (setq s1 (sgml-make-+ s1)) | |
192 (when (sgml-state-reqs s1) | |
193 (sgml-make-opt s1)) | |
194 (sgml-remove-redundant-states-1 s1) | |
195 s1) | |
196 | |
197 (defun sgml-make-+ (s1) | |
198 (sgml-for-all-final-states s s1 | |
199 (sgml-copy-moves-to-opt s1 s)) | |
200 (sgml-remove-redundant-states-1 s1) ; optimize | |
201 s1) | |
202 | |
203 (defun sgml-make-conc (s1 s2) | |
204 (let ((moves (append (sgml-state-reqs s1) (sgml-state-opts s1)))) | |
205 (cond | |
206 (;; optimize the case where all moves from s1 goes to empty states | |
207 (loop for m in moves | |
208 always (sgml-empty-state-p (sgml-move-dest m))) | |
209 (loop for m in moves do (setf (sgml-move-dest m) s2)) | |
210 (when (sgml-state-final-p s1) | |
211 (sgml-copy-moves s2 s1))) | |
212 (t ; general case | |
213 (sgml-for-all-final-states s s1 | |
214 (sgml-copy-moves s2 s) | |
215 (sgml-remove-redundant-states-1 s))))) | |
216 s1) | |
217 | |
218 (defun sgml-make-pcdata () | |
219 (sgml-make-* (sgml-make-primitive-content-token sgml-pcdata-token))) | |
220 | |
221 (defun sgml-reduce-, (l) | |
222 (while (cdr l) | |
223 (setcar (cdr l) | |
224 (sgml-make-conc (car l) (cadr l))) | |
225 (setq l (cdr l))) | |
226 (car l)) | |
227 | |
228 (defun sgml-reduce-| (l) | |
229 (while (cdr l) ; apply the binary make-alt | |
230 (cond ((or (sgml-state-final-p (car l)) ; is result optional | |
231 (sgml-state-final-p (cadr l))) | |
232 (sgml-make-opt (car l)) | |
233 (sgml-copy-moves-to-opt (cadr l) (car l))) | |
234 (t | |
235 (sgml-copy-moves (cadr l) (car l)))) | |
236 (setcdr l (cddr l))) | |
237 (sgml-one-final-state (car l)) ; optimization | |
238 (car l)) | |
239 | |
240 (defun sgml-make-& (dfas) | |
241 (let ((&n (sgml-make-&node dfas (sgml-make-state))) | |
242 (s (sgml-make-state)) | |
243 (l dfas)) | |
244 (while l ; For each si: | |
245 ;; For m in opts(si): add optional move from s to &n on token(m). | |
246 (loop for m in (sgml-state-opts (car l)) | |
247 do (sgml-add-opt-move s (sgml-move-token m) &n)) | |
248 ;; For m in reqs(si): add required move from s to &n on token(m). | |
249 (loop for m in (sgml-state-reqs (car l)) | |
250 do (sgml-add-req-move s (sgml-move-token m) &n)) | |
251 (setq l (cdr l))) | |
252 ;; Return s. | |
253 s)) | |
254 | |
255 | |
256 | |
257 ;(sgml-make-conc (sgml-make-primitive-content-token 'para) (sgml-make-primitive-content-token 'list)) | |
258 ;(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 | |
260 ;(setq x (sgml-some-states-of (sgml-make-primitive-content-token 'para))) | |
261 ;(sgml-state-final-p (car x) ) | |
262 ;(sgml-state-final-p (cadr x)) | |
263 | |
264 | |
265 ;;;; Parse doctype: General | |
266 | |
267 (defun sgml-skip-ts () | |
268 ;; Skip over ts* | |
269 ;;70 ts = 5 s | EE | 60+ parameter entity reference | |
270 ;;For simplicity I use ps* | |
271 ;;65 ps = 5 s | EE | 60+ parameter entity reference | 92 comment | |
272 ;;*** some comments are accepted that shouldn't | |
273 (sgml-skip-ps)) | |
274 | |
275 (defun sgml-parse-character-reference (&optional dofunchar) | |
276 ;; *** Actually only numerical character references | |
277 ;; I don't know how to handel the function character references. | |
278 ;; For the shortrefs let's give them numeric values. | |
279 (if (if dofunchar | |
280 (sgml-parse-delim "CRO" (digit nmstart)) | |
281 (sgml-parse-delim "CRO" (digit))) | |
282 (prog1 (if (sgml-is-delim "NULL" digit) | |
283 (string-to-int (sgml-check-nametoken)) | |
284 (let ((spec (sgml-check-name))) | |
285 (or (cdr (assoc spec '(("re" . 10) | |
286 ("rs" . 1) | |
287 ("tab" . 9) | |
288 ("space" . 32)))) | |
289 ;; *** What to do with other names? | |
290 127))) | |
291 (or (sgml-parse-delim "REFC") | |
292 (sgml-parse-RE))))) | |
293 | |
294 (defun sgml-parse-parameter-literal (&optional dofunchar) | |
295 (let* (lita ; flag if lita | |
296 (value ; accumulates literals value | |
297 "") | |
298 (original-buffer ; Buffer (entity) where lit started | |
299 (current-buffer)) | |
300 temp | |
301 ) | |
302 (cond | |
303 ((or (sgml-parse-delim "LIT") | |
304 (setq lita (sgml-parse-delim "LITA"))) | |
305 (while (not (and (eq (current-buffer) original-buffer) | |
306 (if lita | |
307 (sgml-parse-delim "LITA") | |
308 (sgml-parse-delim "LIT")))) | |
309 (cond ((eobp) | |
310 (or (sgml-pop-entity) | |
311 (sgml-error "Parameter literal unterminated"))) | |
312 ((sgml-parse-parameter-entity-ref)) | |
313 ((setq temp (sgml-parse-character-reference dofunchar)) | |
314 (setq value (concat value (format "%c" temp)))) | |
315 (t | |
316 (setq value | |
317 (concat value | |
318 (buffer-substring | |
319 (point) | |
320 (progn (forward-char 1) | |
321 (if lita | |
322 (sgml-skip-upto ("LITA" "PERO" "CRO")) | |
323 (sgml-skip-upto ("LIT" "PERO" "CRO"))) | |
324 (point))))))) | |
325 ) | |
326 value)))) | |
327 | |
328 (defun sgml-check-parameter-literal () | |
329 (or (sgml-parse-parameter-literal) | |
330 (sgml-parse-error "Parameter literal expected"))) | |
331 | |
332 (defsubst sgml-parse-connector () | |
333 (sgml-skip-ps) | |
334 (cond ((sgml-parse-delim "SEQ") | |
335 (function sgml-reduce-,)) | |
336 ((sgml-parse-delim "OR") | |
337 (function sgml-reduce-|)) | |
338 ((sgml-parse-delim "AND") | |
339 (function sgml-make-&)))) | |
340 | |
341 (defun sgml-parse-name-group () | |
342 "Parse a single name or a name group (general name case) . | |
343 Returns a list of strings or nil." | |
344 (let (names) | |
345 (cond | |
346 ((sgml-parse-delim "GRPO") | |
347 (sgml-skip-ps) | |
348 (setq names (sgml-parse-name-group)) ; *** Allows more than it should | |
349 (while (sgml-parse-connector) | |
350 (sgml-skip-ps) | |
351 (nconc names (sgml-parse-name-group))) | |
352 (sgml-check-delim "GRPC") | |
353 names) | |
354 ((setq names (sgml-parse-name)) | |
355 (list names))))) | |
356 | |
357 (defun sgml-check-name-group () | |
358 (or (sgml-parse-name-group) | |
359 (sgml-parse-error "Expecting a name or a name group"))) | |
360 | |
361 (defun sgml-check-nametoken-group () | |
362 "Parse a name token group, return a list of strings. | |
363 Case transformed for general names." | |
364 (sgml-skip-ps) | |
365 (let ((names nil)) | |
366 (cond | |
367 ((sgml-parse-delim GRPO) | |
368 (while (progn | |
369 (sgml-skip-ps) | |
370 (push (sgml-general-case (sgml-check-nametoken)) names) | |
371 (sgml-parse-connector))) | |
372 (sgml-check-delim GRPC) | |
373 (nreverse names)) ; store in same order as declared | |
374 (t | |
375 (list (sgml-general-case (sgml-check-nametoken))))))) | |
376 | |
377 (defun sgml-check-element-type () | |
378 "Parse and check an element type, returns list of strings." | |
379 ;;; 117 element type = [[30 generic identifier]] | |
380 ;;; | [[69 name group]] | |
381 ;;; | [[118 ranked element]] | |
382 ;;; | [[119 ranked group]] | |
383 (cond | |
384 ((sgml-parse-delim GRPO) | |
385 (sgml-skip-ts) | |
386 (let ((names (list (sgml-check-name)))) | |
387 (while (progn (sgml-skip-ts) | |
388 (sgml-parse-connector)) | |
389 (sgml-skip-ts) | |
390 (nconc names (list (sgml-check-name)))) | |
391 (sgml-check-delim GRPC) | |
392 ;; A ranked group will have a rank suffix here | |
393 (sgml-skip-ps) | |
394 (if (sgml-is-delim "NULL" digit) | |
395 (let ((suffix (sgml-parse-nametoken))) | |
396 (loop for n in names | |
397 collect (concat n suffix))) | |
398 names))) | |
399 (t ; gi/ranked element | |
400 (let ((name (sgml-check-name))) | |
401 (sgml-skip-ps) | |
402 (list (if (sgml-is-delim "NULL" digit) | |
403 (concat name (sgml-check-nametoken)) | |
404 name)))))) | |
405 | |
406 | |
407 (defun sgml-check-external () | |
408 (or (sgml-parse-external) | |
409 (sgml-parse-error "Expecting a PUBLIC or SYSTEM"))) | |
410 | |
411 ;;;; Parse doctype: notation | |
412 | |
413 (defun sgml-declare-notation () | |
414 ;;148 notation declaration = MDO, "NOTATION", | |
415 ;; 65 ps+, 41 notation name, | |
416 ;; 65 ps+, 149 notation identifier, | |
417 ;; 65 ps*, MDC | |
418 ;;41 notation name = 55 name | |
419 ;;149 notation identifier = 73 external identifier | |
420 (sgml-skip-ps) | |
421 (sgml-check-name) | |
422 (sgml-skip-ps) | |
423 (sgml-check-external)) | |
424 | |
425 | |
426 ;;;; Parse doctype: Element | |
427 | |
428 (defun sgml-parse-opt () | |
429 (sgml-skip-ps) | |
430 (cond ((or (sgml-parse-char ?o) | |
431 (sgml-parse-char ?O)) | |
432 t) | |
433 ((sgml-parse-char ?-) | |
434 nil))) | |
435 | |
436 (defun sgml-parse-modifier () | |
437 (cond ((sgml-parse-delim PLUS) | |
438 (function sgml-make-+)) | |
439 ((sgml-parse-delim REP) | |
440 (function sgml-make-*)) | |
441 ((sgml-parse-delim OPT) | |
442 (function sgml-make-opt)))) | |
443 | |
444 (defun sgml-check-primitive-content-token () | |
445 (sgml-make-primitive-content-token | |
446 (sgml-eltype-token | |
447 (sgml-lookup-eltype | |
448 (sgml-check-name))))) | |
449 | |
450 (defun sgml-check-model-group () | |
451 (sgml-skip-ps) | |
452 (let (el mod) | |
453 (cond | |
454 ((sgml-parse-delim "GRPO") | |
455 (let ((subs (list (sgml-check-model-group))) | |
456 (con1 nil) | |
457 (con2 nil)) | |
458 (while (setq con2 (sgml-parse-connector)) | |
459 (cond ((and con1 | |
460 (not (eq con1 con2))) | |
461 (sgml-parse-error "Mixed connectors"))) | |
462 (setq con1 con2) | |
463 (setq subs (nconc subs (list (sgml-check-model-group))))) | |
464 (sgml-check-delim "GRPC") | |
465 (setq el (if con1 | |
466 (funcall con1 subs) | |
467 (car subs))))) | |
468 ((sgml-parse-rni "pcdata") ; #PCDATA | |
469 (setq sgml-used-pcdata t) | |
470 (setq el (sgml-make-pcdata))) | |
471 ((sgml-parse-delim "DTGO") ; data tag group | |
472 (sgml-skip-ts) | |
473 (let ((tok (sgml-check-primitive-content-token))) | |
474 (sgml-skip-ts) (sgml-check-delim "SEQ") | |
475 (sgml-skip-ts) (sgml-check-data-tag-pattern) | |
476 (sgml-skip-ts) (sgml-check-delim "DTGC") | |
477 (setq el (sgml-make-conc tok (sgml-make-pcdata))) | |
478 (setq sgml-used-pcdata t))) | |
479 (t | |
480 (setq el (sgml-check-primitive-content-token)))) | |
481 (setq mod (sgml-parse-modifier)) | |
482 (if mod | |
483 (funcall mod el) | |
484 el))) | |
485 | |
486 (defun sgml-check-data-tag-pattern () | |
487 ;; 134 data tag pattern | |
488 ;; template | template group | |
489 (cond ((sgml-parse-delim GRPO) | |
490 (sgml-skip-ts) | |
491 (sgml-check-parameter-literal) ; data tag template, | |
492 (while (progn (sgml-skip-ts) | |
493 (sgml-parse-delim OR)) | |
494 (sgml-skip-ts) | |
495 (sgml-check-parameter-literal)) ; data tag template | |
496 (sgml-skip-ts) | |
497 (sgml-check-delim GRPC)) | |
498 (t | |
499 (sgml-check-parameter-literal))) ; data tag template | |
500 (sgml-skip-ts) | |
501 (when (sgml-parse-delim SEQ) | |
502 (sgml-check-parameter-literal))) ; data tag padding template | |
503 | |
504 (defun sgml-check-content-model () | |
505 (sgml-check-model-group)) | |
506 | |
507 (defun sgml-check-content () | |
508 (sgml-skip-ps) | |
509 (cond ((sgml-is-delim GRPO) | |
510 (sgml-check-content-model)) | |
511 (t | |
512 ;; ANY, CDATA, RCDATA or EMPTY | |
513 (let ((dc (intern (upcase (sgml-check-name))))) | |
514 (when (eq dc 'ANY) | |
515 (setq sgml-used-pcdata t)) | |
516 dc)))) | |
517 | |
518 (defun sgml-parse-exeption (type) | |
519 (sgml-skip-ps) | |
520 (if (sgml-parse-char type) | |
521 (mapcar (function sgml-lookup-eltype) | |
522 (sgml-check-name-group)))) | |
523 | |
524 (defun sgml-before-eltype-modification () | |
525 ;;; (let ((merged (sgml-dtd-merged sgml-dtd-info))) | |
526 ;;; (when (and merged | |
527 ;;; (eq (sgml-dtd-eltypes sgml-dtd-info) | |
528 ;;; (sgml-dtd-eltypes (cdr merged)))) | |
529 ;;; (setf (sgml-dtd-eltypes sgml-dtd-info) | |
530 ;;; (sgml-merge-eltypes (sgml-make-eltypes-table) | |
531 ;;; (sgml-dtd-eltypes sgml-dtd-info))))) | |
532 ) | |
533 | |
534 (defun sgml-declare-element () | |
535 (let* ((names (sgml-check-element-type)) | |
536 (stag-opt (sgml-parse-opt)) | |
537 (etag-opt (sgml-parse-opt)) | |
538 (sgml-used-pcdata nil) | |
539 (model (sgml-check-content)) | |
540 (exclusions (sgml-parse-exeption ?-)) | |
541 (inclusions (sgml-parse-exeption ?+))) | |
542 (sgml-before-eltype-modification) | |
543 (while names | |
544 (sgml-debug "Defining element %s" (car names)) | |
545 (let ((et (sgml-lookup-eltype (car names)))) | |
546 (setf (sgml-eltype-stag-optional et) stag-opt | |
547 (sgml-eltype-etag-optional et) etag-opt | |
548 (sgml-eltype-model et) model | |
549 (sgml-eltype-mixed et) sgml-used-pcdata | |
550 (sgml-eltype-excludes et) exclusions | |
551 (sgml-eltype-includes et) inclusions)) | |
552 (setq names (cdr names))) | |
553 (sgml-lazy-message "Parsing doctype (%s elements)..." | |
554 (incf sgml-no-elements)))) | |
555 | |
556 ;;;; Parse doctype: Entity | |
557 | |
558 (defun sgml-declare-entity () | |
559 (let (name ; Name of entity | |
560 dest ; Entity table | |
561 (type 'text) ; Type of entity | |
562 text ; Text of entity | |
563 extid ; External id | |
564 ) | |
565 (cond | |
566 ((sgml-parse-delim "PERO") ; parameter entity declaration | |
567 (sgml-skip-ps) | |
568 (setq name (sgml-check-name t)) | |
569 (setq dest (sgml-dtd-parameters sgml-dtd-info))) | |
570 (t ; normal entity declaration | |
571 (or (sgml-parse-rni "default") | |
572 (setq name (sgml-check-name t))) | |
573 (setq dest (sgml-dtd-entities sgml-dtd-info)))) | |
574 (sgml-skip-ps) | |
575 ;;105 entity text = 66 parameter literal | |
576 ;; | 106 data text | |
577 ;; | 107 bracketed text | |
578 ;; | 108 external entity specification | |
579 (setq extid (sgml-parse-external)) | |
580 (setq text | |
581 (cond | |
582 (extid ; external entity specification = | |
583 ; 73 external identifier, | |
584 ; (65 ps+, 109+ entity type)? | |
585 (sgml-skip-ps) | |
586 (setq type (or (sgml-parse-entity-type) 'text)) | |
587 extid) | |
588 ((sgml-startnm-char-next) | |
589 (let ((token (intern (sgml-check-name)))) | |
590 (sgml-skip-ps) | |
591 (cond | |
592 ((memq token '(cdata sdata)) ; data text *** | |
593 (setq type token) | |
594 (sgml-check-parameter-literal)) | |
595 ((eq token 'pi) | |
596 (concat "<?" (sgml-check-parameter-literal) ">")) | |
597 ((eq token 'starttag) | |
598 (sgml-start-tag-of (sgml-check-parameter-literal))) | |
599 ((eq token 'endtag) | |
600 (sgml-end-tag-of (sgml-check-parameter-literal))) | |
601 ((eq token 'ms) ; marked section | |
602 (concat "<![" (sgml-check-parameter-literal) "]]>")) | |
603 ((eq token 'md) ; Markup declaration | |
604 (concat "<!" (sgml-check-parameter-literal) ">"))))) | |
605 ((sgml-check-parameter-literal)))) | |
606 (when dest | |
607 (sgml-entity-declare name dest type text)))) | |
608 | |
609 | |
610 (defun sgml-parse-entity-type () | |
611 ;;109+ entity type = "SUBDOC" | |
612 ;; | (("CDATA" | "NDATA" | "SDATA"), | |
613 ;; 65 ps+, | |
614 ;; 41 notation name, | |
615 ;; 149.2+ data attribute specification?) | |
616 (let ((type (sgml-parse-name))) | |
617 (when type | |
618 (setq type (intern (downcase type))) | |
619 (cond ((eq type 'subdoc)) | |
620 ((memq type '(cdata ndata sdata)) | |
621 (sgml-skip-ps) | |
622 (sgml-check-name) | |
623 ;;149.2+ data attribute specification | |
624 ;; = 65 ps+, DSO, | |
625 ;; 31 attribute specification list, | |
626 ;; 5 s*, DSC | |
627 (sgml-skip-ps) | |
628 (when (sgml-parse-delim DSO) | |
629 (sgml-parse-attribute-specification-list) | |
630 (sgml-parse-s) | |
631 (sgml-check-delim DSC))) | |
632 (t (sgml-error "Illegal entity type: %s" type)))) | |
633 type)) | |
634 | |
635 | |
636 ;;;; Parse doctype: Attlist | |
637 | |
638 (defun sgml-declare-attlist () | |
639 (let* ((assnot (cond ((sgml-parse-rni "notation") | |
640 (sgml-skip-ps) | |
641 t))) | |
642 (assel (sgml-check-name-group)) | |
643 (attlist nil) ; the list | |
644 (attdef nil)) | |
645 (while (setq attdef (sgml-parse-attribute-definition)) | |
646 (push attdef attlist)) | |
647 (setq attlist (nreverse attlist)) | |
648 (unless assnot | |
649 (sgml-before-eltype-modification) | |
650 (loop for elname in assel do | |
651 (setf (sgml-eltype-attlist (sgml-lookup-eltype elname)) | |
652 attlist))))) | |
653 | |
654 (defun sgml-parse-attribute-definition () | |
655 (sgml-skip-ps) | |
656 (if (sgml-is-delim MDC) ; End of attlist? | |
657 nil | |
658 (sgml-make-attdecl (sgml-check-name) | |
659 (sgml-check-declared-value) | |
660 (sgml-check-default-value)))) | |
661 | |
662 (defun sgml-check-declared-value () | |
663 (sgml-skip-ps) | |
664 (let ((type 'name-token-group) | |
665 (names nil)) | |
666 (unless (eq (following-char) ?\() | |
667 (setq type (intern (sgml-check-name))) | |
668 (sgml-skip-ps)) | |
669 (when (memq type '(name-token-group notation)) | |
670 (setq names (sgml-check-nametoken-group))) | |
671 (sgml-make-declared-value type names))) | |
672 | |
673 (defun sgml-check-default-value () | |
674 (sgml-skip-ps) | |
675 (let* ((rni (sgml-parse-rni)) | |
676 (key (if rni (intern (sgml-check-name))))) | |
677 (sgml-skip-ps) | |
678 (sgml-make-default-value | |
679 key | |
680 (if (or (not rni) (eq key 'fixed)) | |
681 (sgml-check-attribute-value-specification))))) | |
682 | |
683 | |
684 ;;;; Parse doctype: Shortref | |
685 | |
686 ;;;150 short reference mapping declaration = MDO, "SHORTREF", | |
687 ;;; [[65 ps]]+, [[151 map name]], | |
688 ;;; ([[65 ps]]+, [[66 parameter literal]], | |
689 ;;; [[65 ps]]+, [[55 name]])+, | |
690 ;;; [[65 ps]]*, MDC | |
691 | |
692 (defun sgml-declare-shortref () | |
693 (let ((mapname (sgml-check-name)) | |
694 mappings literal name) | |
695 (while (progn | |
696 (sgml-skip-ps) | |
697 (setq literal (sgml-parse-parameter-literal 'dofunchar))) | |
698 (sgml-skip-ps) | |
699 (setq name (sgml-check-name t)) | |
700 (push (cons literal name) mappings)) | |
701 (sgml-add-shortref-map | |
702 (sgml-dtd-shortmaps sgml-dtd-info) | |
703 mapname | |
704 (sgml-make-shortmap mappings)))) | |
705 | |
706 ;;;152 short reference use declaration = MDO, "USEMAP", | |
707 ;;; [[65 ps]]+, [[153 map specification]], | |
708 ;;; ([[65 ps]]+, [[72 associated element type]])?, | |
709 ;;; [[65 ps]]*, MDC | |
710 | |
711 (defun sgml-do-usemap-element (mapname) | |
712 ;; This is called from sgml-do-usemap with the mapname | |
713 (sgml-before-eltype-modification) | |
714 (loop for e in (sgml-parse-name-group) do | |
715 (setf (sgml-eltype-shortmap (sgml-lookup-eltype e sgml-dtd-info)) | |
716 (if (null mapname) | |
717 'empty | |
718 mapname)))) | |
719 | |
720 | |
721 ;;;; Parse doctype | |
722 | |
723 (defun sgml-check-dtd-subset () | |
724 (let ((sgml-parsing-dtd t) | |
725 (eref sgml-current-eref)) | |
726 (while | |
727 (progn | |
728 (setq sgml-markup-start (point)) | |
729 (cond | |
730 ((and (eobp) (eq sgml-current-eref eref)) | |
731 nil) | |
732 ((sgml-parse-ds)) | |
733 ((sgml-parse-markup-declaration 'dtd)) | |
734 ((sgml-parse-delim "MS-END"))))))) | |
735 | |
736 | |
737 ;;;; Save DTD: compute translation | |
738 | |
739 (defvar sgml-translate-table nil) | |
740 | |
741 (defun sgml-translate-node (node) | |
742 (assert (not (numberp node))) | |
743 (let ((tp (assq node sgml-translate-table))) | |
744 (unless tp | |
745 (setq tp (cons node (length sgml-translate-table))) | |
746 (nconc sgml-translate-table (list tp))) | |
747 (cdr tp))) | |
748 | |
749 (defun sgml-translate-moves (moves) | |
750 (while moves | |
751 (sgml-translate-node (sgml-move-dest (car moves))) | |
752 (setq moves (cdr moves)))) | |
753 | |
754 (defun sgml-translate-model (model) | |
755 (let* ((sgml-translate-table (list (cons model 0))) | |
756 (p sgml-translate-table)) | |
757 (while p | |
758 (cond ((sgml-normal-state-p (caar p)) | |
759 (sgml-translate-moves (sgml-state-opts (caar p))) | |
760 (sgml-translate-moves (sgml-state-reqs (caar p)))) | |
761 (t | |
762 (sgml-translate-node (sgml-&node-next (caar p))))) | |
763 (setq p (cdr p))) | |
764 sgml-translate-table)) | |
765 | |
766 ;;;; Save DTD: binary coding | |
767 | |
768 (defvar sgml-code-token-numbers nil) | |
769 (defvar sgml-code-xlate nil) | |
770 | |
771 (defsubst sgml-code-xlate (node) | |
772 ;;(let ((x (cdr (assq node sgml-code-xlate)))) (assert x) x) | |
773 (cdr (assq node sgml-code-xlate))) | |
774 | |
775 (defun sgml-code-number (num) | |
776 (if (> num sgml-max-single-octet-number) | |
777 (insert (+ (lsh (- num sgml-max-single-octet-number) -8) | |
778 sgml-max-single-octet-number 1) | |
779 (logand (- num sgml-max-single-octet-number) 255)) | |
780 (insert num))) | |
781 | |
782 (defun sgml-code-token-number (token) | |
783 (let ((bp (assq token sgml-code-token-numbers))) | |
784 (unless bp | |
785 (setq sgml-code-token-numbers | |
786 (nconc sgml-code-token-numbers | |
787 (list (setq bp (cons token | |
788 (length sgml-code-token-numbers))))))) | |
789 (cdr bp))) | |
790 | |
791 (defun sgml-code-token (token) | |
792 (sgml-code-number (sgml-code-token-number token))) | |
793 | |
794 (defmacro sgml-code-sequence (loop-c &rest body) | |
795 "Produce the binary coding of a counted sequence from a list. | |
796 Syntax: (var seq) &body forms | |
797 FORMS should produce the binary coding of element in VAR." | |
798 (let ((var (car loop-c)) | |
799 (seq (cadr loop-c))) | |
800 (` (let ((seq (, seq))) | |
801 (sgml-code-number (length seq)) | |
802 (loop for (, var) in seq | |
803 do (,@ body)))))) | |
804 | |
805 (put 'sgml-code-sequence 'lisp-indent-hook 1) | |
806 (put 'sgml-code-sequence 'edbug-forms-hook '(sexp &rest form)) | |
807 | |
808 (defun sgml-code-sexp (sexp) | |
809 (let ((standard-output (current-buffer))) | |
810 (prin1 sexp) | |
811 (terpri))) | |
812 | |
813 (defun sgml-code-tokens (l) | |
814 (sgml-code-sequence (x l) | |
815 (sgml-code-token x))) | |
816 | |
817 (defsubst sgml-code-move (m) | |
818 (sgml-code-token (sgml-move-token m)) | |
819 (insert (sgml-code-xlate (sgml-move-dest m)))) | |
820 | |
821 (defun sgml-code-model (m) | |
822 (let ((sgml-code-xlate (sgml-translate-model m))) | |
823 (sgml-code-sequence (s sgml-code-xlate) ; s is (node . number) | |
824 (setq s (car s)) ; s is node | |
825 (cond | |
826 ((sgml-normal-state-p s) | |
827 (assert (and (< (length (sgml-state-opts s)) 255) | |
828 (< (length (sgml-state-reqs s)) 256))) | |
829 (sgml-code-sequence (x (sgml-state-opts s)) | |
830 (sgml-code-move x)) | |
831 (sgml-code-sequence (x (sgml-state-reqs s)) | |
832 (sgml-code-move x))) | |
833 (t ; s is a &-node | |
834 (insert 255) ; Tag &-node | |
835 (insert (sgml-code-xlate (sgml-&node-next s))) | |
836 (sgml-code-sequence (m (sgml-&node-dfas s)) | |
837 (sgml-code-model m))))))) | |
838 | |
839 (defun sgml-code-element (et) | |
840 (sgml-code-sexp (sgml-eltype-all-miscdata et)) | |
841 (cond | |
842 ((not (sgml-eltype-defined et)) | |
843 (insert 128)) | |
844 (t | |
845 (insert (sgml-eltype-flags et)) | |
846 (let ((c (sgml-eltype-model et))) | |
847 (cond ((eq c sgml-cdata) (insert 0)) | |
848 ((eq c sgml-rcdata) (insert 1)) | |
849 ((eq c sgml-empty) (insert 2)) | |
850 ((eq c sgml-any) (insert 3)) | |
851 ((null c) (insert 4)) | |
852 (t | |
853 (assert (sgml-model-group-p c)) | |
854 (insert 128) | |
855 (sgml-code-model c)))) | |
856 (sgml-code-tokens (sgml-eltype-includes et)) | |
857 (sgml-code-tokens (sgml-eltype-excludes et))))) | |
858 | |
859 | |
860 (defun sgml-code-dtd (dtd) | |
861 "Produce the binary coding of the current DTD into the current buffer." | |
862 (sgml-code-sexp (sgml-dtd-dependencies dtd)) | |
863 (sgml-code-sexp (sgml-dtd-parameters dtd)) | |
864 (sgml-code-sexp (sgml-dtd-doctype dtd)) | |
865 (let ((done 0) ; count written elements | |
866 tot) | |
867 (setq sgml-code-token-numbers nil) | |
868 (sgml-code-token-number sgml-pcdata-token) ; Make #PCDATA token 0 | |
869 (sgml-map-eltypes ; Assign numbers to all tokens | |
870 (function (lambda (et) | |
871 (sgml-code-token-number (sgml-eltype-token et)))) | |
872 dtd nil t) | |
873 (setq tot (length sgml-code-token-numbers)) | |
874 ;; Produce the counted sequence of element type names | |
875 (sgml-code-sequence (pair (cdr sgml-code-token-numbers)) | |
876 (sgml-code-sexp (sgml-eltype-name (car pair)))) | |
877 ;; Produce the counted sequence of element types | |
878 (sgml-code-sequence (pair (cdr sgml-code-token-numbers)) | |
879 (setq done (1+ done)) | |
880 (sgml-code-element (car pair)) | |
881 (sgml-lazy-message "Saving DTD %d%% done" (/ (* 100 done) tot))) | |
882 (sgml-code-sexp (sgml-dtd-entities dtd)) | |
883 (sgml-code-sexp (sgml-dtd-shortmaps dtd)) | |
884 (sgml-code-sexp (sgml-dtd-notations dtd)))) | |
885 | |
886 | |
887 ;;;; Save DTD | |
888 | |
889 (defun sgml-save-dtd (file) | |
890 "Save the parsed dtd on FILE." | |
891 (interactive | |
892 (let* ((tem (expand-file-name | |
893 (or sgml-default-dtd-file | |
894 (sgml-default-dtd-file)))) | |
895 (dir (file-name-directory tem)) | |
896 (nam (file-name-nondirectory tem))) | |
897 (list | |
898 (read-file-name "Save DTD in: " dir tem nil nam)))) | |
899 (setq file (expand-file-name file)) | |
900 (when (equal file (buffer-file-name)) | |
901 (error "Would clobber current file")) | |
902 (sgml-need-dtd) | |
903 (sgml-push-to-entity (sgml-make-entity "#SAVE" nil "")) | |
904 (sgml-write-dtd sgml-dtd-info file) | |
905 (sgml-pop-entity) | |
906 (setq sgml-default-dtd-file | |
907 (if (equal (expand-file-name default-directory) | |
908 (file-name-directory file)) | |
909 (file-name-nondirectory file) | |
910 file)) | |
911 (setq sgml-loaded-dtd file)) | |
912 | |
913 (defun sgml-write-dtd (dtd file) | |
914 "Save the parsed dtd on FILE. | |
915 Construct the binary coded DTD (bdtd) in the current buffer." | |
916 (insert | |
917 ";;; This file was created by psgml on " (current-time-string) "\n" | |
918 "(sgml-saved-dtd-version 6)\n") | |
919 (sgml-code-dtd dtd) | |
920 (setq file-type 1) | |
921 (write-region (point-min) (point-max) file)) | |
922 | |
923 | |
924 ;;; psgml-dtd.el ends here |