1 ;;; ebnf-otz.el --- syntactic chart OpTimiZer
3 ;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
5 ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
6 ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
7 ;; Keywords: wp, ebnf, PostScript
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
28 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;; This is part of ebnf2ps package.
33 ;; This package defines an optimizer for ebnf2ps.
35 ;; See ebnf2ps.el for documentation.
42 ;; *To be implemented*:
44 ;; A = B | A C B | A C D. ==> A = B {C (B | D)}*.
47 ;; A = B | C A. ==> A = {C}* B.
48 ;; A = B | D | C A | E A. ==> A = { C | E }* ( B | D ).
51 ;; A = B | C B. ==> A = [C] B.
52 ;; A = B | B C. ==> A = B [C].
53 ;; A = D | B D | B C D. ==> A = [B [C]] D.
56 ;; *Already implemented*:
58 ;; A = B | A C. ==> A = B {C}*.
59 ;; A = B | A B. ==> A = {B}+.
60 ;; A = | A B. ==> A = {B}*.
61 ;; A = B | A C B. ==> A = {B || C}+.
62 ;; A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
65 ;; A = B | . ==> A = [B].
66 ;; A = | B . ==> A = [B].
69 ;; A = B C | B D. ==> A = B (C | D).
70 ;; A = C B | D B. ==> A = (C | D) B.
71 ;; A = B C E | B D E. ==> A = B (C | D) E.
74 ;; A = B | C | . ==> A = B | C | .
75 ;; A = B | C A D. ==> A = B | C A D.
78 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
89 (defvar ebnf-empty-rule-list nil
90 "List of empty rule name.")
93 (defun ebnf-add-empty-rule-list (rule)
94 "Add empty RULE in `ebnf-empty-rule-list'."
95 (and ebnf-ignore-empty-rule
96 (eq (ebnf-node-kind (ebnf-node-production rule
))
98 (setq ebnf-empty-rule-list
(cons (ebnf-node-name rule
)
99 ebnf-empty-rule-list
))))
102 (defun ebnf-otz-initialize ()
103 "Initialize optimizer."
104 (setq ebnf-empty-rule-list nil
))
107 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
108 ;; Eliminate empty rules
111 (defun ebnf-eliminate-empty-rules (syntax-list)
112 "Eliminate empty rules."
113 (while ebnf-empty-rule-list
114 (let ((ebnf-total (length syntax-list
))
116 (prod-list syntax-list
)
119 (ebnf-message-info "Eliminating empty rules")
120 (let ((rule (car prod-list
)))
121 ;; if any non-terminal pertains to ebnf-empty-rule-list
122 ;; then eliminate non-terminal from rule
123 (if (ebnf-eliminate-empty rule
)
124 (setq before prod-list
)
125 ;; eliminate empty rule from syntax-list
126 (setq new-list
(cons (ebnf-node-name rule
) new-list
))
128 (setcdr before
(cdr prod-list
))
129 (setq syntax-list
(cdr syntax-list
)))))
130 (setq prod-list
(cdr prod-list
)))
131 (setq ebnf-empty-rule-list new-list
)))
135 ;; [production width-func entry height width name production action]
136 ;; [sequence width-func entry height width list]
137 ;; [alternative width-func entry height width list]
138 ;; [non-terminal width-func entry height width name default]
139 ;; [empty width-func entry height width]
140 ;; [terminal width-func entry height width name default]
141 ;; [special width-func entry height width name default]
143 (defun ebnf-eliminate-empty (rule)
144 (let ((kind (ebnf-node-kind rule
)))
147 ((eq kind
'ebnf-generate-non-terminal
)
148 (if (member (ebnf-node-name rule
) ebnf-empty-rule-list
)
152 ((eq kind
'ebnf-generate-sequence
)
153 (let ((seq (ebnf-node-list rule
))
154 (header (ebnf-node-list rule
))
158 (if (ebnf-eliminate-empty elt
)
161 (setcdr before
(cdr seq
))
162 (setq header
(cdr header
))))
163 (setq seq
(cdr seq
)))
165 (ebnf-node-list rule header
)
168 ((eq kind
'ebnf-generate-alternative
)
169 (let ((seq (ebnf-node-list rule
))
170 (header (ebnf-node-list rule
))
174 (if (ebnf-eliminate-empty elt
)
177 (setcdr before
(cdr seq
))
178 (setq header
(cdr header
))))
179 (setq seq
(cdr seq
)))
181 (if (= (length header
) 1)
183 (ebnf-node-list rule header
)
186 ((eq kind
'ebnf-generate-production
)
187 (let ((prod (ebnf-eliminate-empty (ebnf-node-production rule
))))
189 (ebnf-node-production rule prod
)
191 ;; terminal, special and empty
197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 ;; *To be implemented*:
203 ;; A = B | A C B | A C D. ==> A = B {C (B | D)}*.
206 ;; A = B | C A. ==> A = {C}* B.
207 ;; A = B | D | C A | E A. ==> A = { C | E }* ( B | D ).
210 ;; A = B | C B. ==> A = [C] B.
211 ;; A = B | B C. ==> A = B [C].
212 ;; A = D | B D | B C D. ==> A = [B [C]] D.
215 ;; *Already implemented*:
217 ;; A = B | A C. ==> A = B {C}*.
218 ;; A = B | A B. ==> A = {B}+.
219 ;; A = | A B. ==> A = {B}*.
220 ;; A = B | A C B. ==> A = {B || C}+.
221 ;; A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
224 ;; A = B | . ==> A = [B].
225 ;; A = | B . ==> A = [B].
228 ;; A = B C | B D. ==> A = B (C | D).
229 ;; A = C B | D B. ==> A = (C | D) B.
230 ;; A = B C E | B D E. ==> A = B (C | D) E.
233 ;; A = B | C | . ==> A = B | C | .
234 ;; A = B | C A D. ==> A = B | C A D.
236 (defun ebnf-optimize (syntax-list)
237 "Syntactic chart optimizer."
238 (if (not ebnf-optimize
)
240 (let ((ebnf-total (length syntax-list
))
244 (setq new
(cons (ebnf-optimize1 (car syntax-list
)) new
)
245 syntax-list
(cdr syntax-list
)))
250 ;; 1. A = B | A C. ==> A = B {C}*.
251 ;; 2. A = B | A B. ==> A = {B}+.
252 ;; 3. A = | A B. ==> A = {B}*.
253 ;; 4. A = B | A C B. ==> A = {B || C}+.
254 ;; 5. A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
257 ;; 6. A = B | . ==> A = [B].
258 ;; 7. A = | B . ==> A = [B].
261 ;; 8. A = B C | B D. ==> A = B (C | D).
262 ;; 9. A = C B | D B. ==> A = (C | D) B.
263 ;; 10. A = B C E | B D E. ==> A = B (C | D) E.
265 (defun ebnf-optimize1 (prod)
266 (ebnf-message-info "Optimizing syntactic chart")
267 (let ((production (ebnf-node-production prod
)))
268 (and (eq (ebnf-node-kind production
) 'ebnf-generate-alternative
)
269 (let* ((hlist (ebnf-split-header-prefix
270 (ebnf-node-list production
)
271 (ebnf-node-name prod
)))
274 (elist (ebnf-split-header-suffix nlist zlist
)))
275 (ebnf-node-production
282 (setq elist
(or (ebnf-prefix-suffix elist
)
284 (let* ((nl (ebnf-extract-empty nlist
))
285 (el (or (ebnf-prefix-suffix (cdr nl
))
286 (ebnf-create-alternative (cdr nl
)))))
288 (ebnf-make-zero-or-more el elist
)
289 (ebnf-make-one-or-more el elist
))))
292 (let* ((xlist (cdr (ebnf-extract-empty zlist
)))
293 (znode (ebnf-make-zero-or-more
294 (or (ebnf-prefix-suffix xlist
)
295 (ebnf-create-alternative xlist
))))
296 (nnode (ebnf-map-list-to-optional nlist
)))
298 (setq nlist
(list nnode
)))
300 (and (= (length nlist
) 1)
301 (eq (ebnf-node-kind (car nlist
))
302 'ebnf-generate-empty
)))
305 (list (or (ebnf-prefix-suffix nlist
)
306 (ebnf-create-alternative nlist
))
309 ((ebnf-map-node-to-optional production
)
312 ((ebnf-prefix-suffix nlist
)
321 (defun ebnf-split-header-prefix (node-list header
)
322 (let* ((hlist (ebnf-split-header-prefix1 node-list header
))
325 (while (setq hlist
(cdr hlist
))
326 (let ((elt (car hlist
)))
327 (if (eq (ebnf-node-kind elt
) 'ebnf-generate-sequence
)
329 (let ((seq (cdr (ebnf-node-list elt
))))
330 (if (= (length seq
) 1)
332 (ebnf-node-list elt seq
)
337 (setq zlist
(cons (ebnf-make-empty)
339 (cons nlist
(nreverse zlist
))))
342 (defun ebnf-split-header-prefix1 (node-list header
)
345 (if (ebnf-node-equal-header (car node-list
) header
)
346 (setq hlist
(cons (car node-list
) hlist
))
347 (setq nlist
(cons (car node-list
) nlist
)))
348 (setq node-list
(cdr node-list
)))
349 (cons (nreverse nlist
) (nreverse hlist
))))
352 (defun ebnf-node-equal-header (node header
)
353 (let ((kind (ebnf-node-kind node
)))
355 ((eq kind
'ebnf-generate-sequence
)
356 (ebnf-node-equal-header (car (ebnf-node-list node
)) header
))
357 ((eq kind
'ebnf-generate-non-terminal
)
358 (string= (ebnf-node-name node
) header
))
364 (defun ebnf-map-node-to-optional (node)
365 (and (eq (ebnf-node-kind node
) 'ebnf-generate-alternative
)
366 (ebnf-map-list-to-optional (ebnf-node-list node
))))
369 (defun ebnf-map-list-to-optional (nlist)
370 (and (= (length nlist
) 2)
371 (let ((first (nth 0 nlist
))
372 (second (nth 1 nlist
)))
375 ((eq (ebnf-node-kind first
) 'ebnf-generate-empty
)
376 (ebnf-make-optional second
))
378 ((eq (ebnf-node-kind second
) 'ebnf-generate-empty
)
379 (ebnf-make-optional first
))
386 (defun ebnf-extract-empty (elist)
390 (if (not (eq (ebnf-node-kind (car now
)) 'ebnf-generate-empty
))
394 (setcdr before
(cdr now
))
395 (setq elist
(cdr elist
))))
396 (setq now
(cdr now
)))
397 (cons empty-p elist
)))
400 (defun ebnf-split-header-suffix (nlist zlist
)
403 ((= (length nlist
) 1)
406 (while (and ok zlist
)
407 (setq ok
(ebnf-split-header-suffix1 elt
(car zlist
))
411 (setq new
(cons ok new
))))
413 ((= (length nlist
) (length zlist
))
415 (while (and ok zlist
)
416 (setq ok
(ebnf-split-header-suffix1 (car nlist
) (car zlist
))
421 (setq new
(cons ok new
))))
426 (let* ((lis (ebnf-unique-list new
))
434 (ebnf-make-optional lis
)
438 (setq lis
(cons (ebnf-make-empty) lis
)))
439 (ebnf-create-alternative (nreverse lis
)))
443 (defun ebnf-split-header-suffix1 (ne ze
)
445 ((eq (ebnf-node-kind ne
) 'ebnf-generate-sequence
)
446 (and (eq (ebnf-node-kind ze
) 'ebnf-generate-sequence
)
447 (let ((nl (ebnf-node-list ne
))
448 (zl (ebnf-node-list ze
))
450 (and (>= (length zl
) (length nl
))
452 (setq len
(- (length zl
) (length nl
))
455 (setq ok
(ebnf-node-equal (car z
) (car nl
))
461 (setcdr (nthcdr (1- len
) zl
) nil
)
463 ((eq (ebnf-node-kind ze
) 'ebnf-generate-sequence
)
464 (let* ((zl (ebnf-node-list ze
))
466 (and (ebnf-node-equal ne
(car (nthcdr (1- len
) zl
)))
473 (setcdr (nthcdr (- len
2) zl
) nil
)
477 (ebnf-node-equal ne ze
))
481 (defun ebnf-prefix-suffix (lis)
483 (let* ((prefix (ebnf-split-prefix lis
))
484 (suffix (ebnf-split-suffix (cdr prefix
)))
485 (middle (cdr suffix
)))
486 (setq prefix
(car prefix
)
488 (and (or prefix suffix
)
492 (list (or (ebnf-map-list-to-optional middle
)
493 (ebnf-create-alternative middle
))))
497 (defun ebnf-split-prefix (lis)
498 (let* ((len (length lis
))
500 (head (if (eq (ebnf-node-kind (car lis
)) 'ebnf-generate-sequence
)
501 (ebnf-node-list (car lis
))
504 ;; determine prefix length
505 (while (and (> ipre
0) (setq tail
(cdr tail
)))
507 (this (if (eq (ebnf-node-kind (car tail
)) 'ebnf-generate-sequence
)
508 (ebnf-node-list (car tail
))
512 (ebnf-node-equal (car cur
) (car this
)))
516 (setq ipre
(min ipre i
))))
517 (if (or (zerop ipre
) (> ipre len
))
520 (let* ((tail (nthcdr ipre head
))
524 (setcdr (nthcdr (1- ipre
) head
) nil
))
527 ;; adjust first element
528 (if (or (not (eq (ebnf-node-kind (car lis
)) 'ebnf-generate-sequence
))
533 (if (= (length tail
) 1)
534 (setcar lis
(car tail
))
535 (ebnf-node-list (car lis
) tail
))
536 (setq tail
(cdr lis
)))
537 ;; eliminate prefix from lis based on ipre
539 (let ((elt (car tail
))
541 (if (and (eq (ebnf-node-kind elt
) 'ebnf-generate-sequence
)
542 (setq rest
(nthcdr ipre
(ebnf-node-list elt
))))
544 (if (= (length rest
) 1)
545 (setcar tail
(car rest
))
546 (ebnf-node-list elt rest
))
550 (setcdr before
(cdr tail
))
551 (setq lis
(cdr lis
))))
552 (setq tail
(cdr tail
))))
553 (cons prefix
(ebnf-unique-list
555 (nconc lis
(list (ebnf-make-empty)))
559 (defun ebnf-split-suffix (lis)
560 (let* ((len (length lis
))
563 (if (eq (ebnf-node-kind (car lis
)) 'ebnf-generate-sequence
)
564 (ebnf-node-list (car lis
))
567 ;; determine suffix length
568 (while (and (> isuf
0) (setq tail
(cdr tail
)))
571 (if (eq (ebnf-node-kind (car tail
)) 'ebnf-generate-sequence
)
572 (ebnf-node-list (car tail
))
577 (ebnf-node-equal (car cur
) (car this
)))
582 (setq isuf
(min isuf i
))))
583 (setq head
(nreverse head
))
584 (if (or (zerop isuf
) (> isuf len
))
587 (let* ((n (- (length head
) isuf
))
589 (suffix (nthcdr n head
))
592 (setcdr (nthcdr (1- n
) head
) nil
)
595 ;; adjust first element
596 (if (or (not (eq (ebnf-node-kind (car lis
)) 'ebnf-generate-sequence
))
601 (if (= (length tail
) 1)
602 (setcar lis
(car tail
))
603 (ebnf-node-list (car lis
) tail
))
604 (setq tail
(cdr lis
)))
605 ;; eliminate suffix from lis based on isuf
607 (let ((elt (car tail
))
609 (if (and (eq (ebnf-node-kind elt
) 'ebnf-generate-sequence
)
610 (setq rest
(ebnf-node-list elt
)
611 n
(- (length rest
) isuf
))
615 (setcar tail
(car rest
))
616 (setcdr (nthcdr (1- n
) rest
) nil
)
617 (ebnf-node-list elt rest
))
621 (setcdr before
(cdr tail
))
622 (setq lis
(cdr lis
))))
623 (setq tail
(cdr tail
))))
624 (cons suffix
(ebnf-unique-list
626 (nconc lis
(list (ebnf-make-empty)))
630 (defun ebnf-unique-list (nlist)
631 (let ((current nlist
)
634 (let ((tail (cdr current
))
638 (if (not (ebnf-node-equal head
(car tail
)))
639 (setq tail
(cdr tail
))
643 (setcdr before
(cdr current
))
644 (setq nlist
(cdr nlist
)))))
646 (setq before current
))
647 (setq current
(cdr current
))))
651 (defun ebnf-node-equal (A B
)
652 (let ((kindA (ebnf-node-kind A
))
653 (kindB (ebnf-node-kind B
)))
654 (and (eq kindA kindB
)
657 ((eq kindA
'ebnf-generate-empty
)
659 ;; non-terminal, terminal, special
660 ((memq kindA
'(ebnf-generate-non-terminal
661 ebnf-generate-terminal
662 ebnf-generate-special
))
663 (string= (ebnf-node-name A
) (ebnf-node-name B
)))
664 ;; alternative, sequence
665 ((memq kindA
'(ebnf-generate-alternative ; any order
666 ebnf-generate-sequence
)) ; order is important
667 (let ((listA (ebnf-node-list A
))
668 (listB (ebnf-node-list B
)))
669 (and (= (length listA
) (length listB
))
671 (while (and ok listA
)
672 (setq ok
(ebnf-node-equal (car listA
) (car listB
))
677 ((eq kindA
'ebnf-generate-production
)
678 (and (string= (ebnf-node-name A
) (ebnf-node-name B
))
679 (ebnf-node-equal (ebnf-node-production A
)
680 (ebnf-node-production B
))))
687 (defun ebnf-create-alternative (alt)
688 (if (> (length alt
) 1)
689 (ebnf-make-alternative alt
)
693 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
699 ;;; ebnf-otz.el ends here